Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
7edc337f
Commit
7edc337f
authored
Apr 05, 2018
by
Kushal Pandya
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update layout for Geo nodes admin page
parent
2c84eb5c
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
186 additions
and
671 deletions
+186
-671
ee/app/assets/javascripts/geo_nodes/components/app.vue
ee/app/assets/javascripts/geo_nodes/components/app.vue
+13
-20
ee/app/assets/javascripts/geo_nodes/components/geo_node_detail_item.vue
...javascripts/geo_nodes/components/geo_node_detail_item.vue
+9
-12
ee/app/assets/javascripts/geo_nodes/components/geo_node_details.vue
...ets/javascripts/geo_nodes/components/geo_node_details.vue
+39
-237
ee/app/assets/javascripts/geo_nodes/components/geo_node_event_status.vue
...avascripts/geo_nodes/components/geo_node_event_status.vue
+16
-1
ee/app/assets/javascripts/geo_nodes/components/geo_node_health_status.vue
...vascripts/geo_nodes/components/geo_node_health_status.vue
+17
-12
ee/app/assets/javascripts/geo_nodes/components/geo_node_item.vue
...assets/javascripts/geo_nodes/components/geo_node_item.vue
+15
-91
ee/app/assets/javascripts/geo_nodes/components/geo_node_sync_settings.vue
...vascripts/geo_nodes/components/geo_node_sync_settings.vue
+1
-1
ee/app/assets/javascripts/geo_nodes/components/geo_nodes_list.vue
...ssets/javascripts/geo_nodes/components/geo_nodes_list.vue
+2
-2
spec/javascripts/geo_nodes/components/app_spec.js
spec/javascripts/geo_nodes/components/app_spec.js
+5
-34
spec/javascripts/geo_nodes/components/geo_node_detail_item_spec.js
...scripts/geo_nodes/components/geo_node_detail_item_spec.js
+0
-10
spec/javascripts/geo_nodes/components/geo_node_details_spec.js
...javascripts/geo_nodes/components/geo_node_details_spec.js
+15
-145
spec/javascripts/geo_nodes/components/geo_node_event_status_spec.js
...cripts/geo_nodes/components/geo_node_event_status_spec.js
+21
-4
spec/javascripts/geo_nodes/components/geo_node_health_status_spec.js
...ripts/geo_nodes/components/geo_node_health_status_spec.js
+7
-4
spec/javascripts/geo_nodes/components/geo_node_item_spec.js
spec/javascripts/geo_nodes/components/geo_node_item_spec.js
+14
-97
spec/javascripts/geo_nodes/components/geo_nodes_list_spec.js
spec/javascripts/geo_nodes/components/geo_nodes_list_spec.js
+1
-1
spec/javascripts/geo_nodes/mock_data.js
spec/javascripts/geo_nodes/mock_data.js
+11
-0
No files found.
ee/app/assets/javascripts/geo_nodes/components/app.vue
View file @
7edc337f
...
...
@@ -10,13 +10,13 @@ import eventHub from '../event_hub';
import
{
NODE_ACTIONS
}
from
'
../constants
'
;
import
geoNodesList
from
'
./geo_nodes_list
.vue
'
;
import
GeoNodeItem
from
'
./geo_node_item
.vue
'
;
export
default
{
components
:
{
loadingIcon
,
DeprecatedModal
,
geoNodesList
,
GeoNodeItem
,
},
props
:
{
store
:
{
...
...
@@ -46,7 +46,6 @@ export default {
modalKind
:
'
warning
'
,
modalMessage
:
''
,
modalActionLabel
:
''
,
errorMessage
:
''
,
};
},
computed
:
{
...
...
@@ -85,7 +84,6 @@ export default {
});
},
fetchGeoNodes
()
{
this
.
hasError
=
false
;
this
.
service
.
getGeoNodes
()
.
then
(
res
=>
res
.
data
)
...
...
@@ -93,9 +91,11 @@ export default {
this
.
store
.
setNodes
(
nodes
);
this
.
isLoading
=
false
;
})
.
catch
(
err
=>
{
this
.
hasError
=
true
;
this
.
errorMessage
=
err
;
.
catch
(()
=>
{
this
.
isLoading
=
false
;
Flash
(
s__
(
'
GeoNodes|Something went wrong while fetching nodes
'
),
);
});
},
fetchNodeDetails
(
node
)
{
...
...
@@ -217,28 +217,21 @@ export default {
</
script
>
<
template
>
<div
class=
"panel panel-default"
>
<div
class=
"panel-heading"
>
Geo nodes (
{{
nodes
.
length
}}
)
</div>
<div
class=
"geo-nodes-container"
>
<loading-icon
class=
"loading-animation prepend-top-20 append-bottom-20"
size=
"2"
v-if=
"isLoading"
:label=
"s__('GeoNodes|Loading nodes')"
/>
<geo-nodes-list
v-if=
"!isLoading"
:nodes=
"nodes"
<geo-node-item
v-for=
"(node, index) in nodes"
:key=
"index"
:node=
"node"
:primary-node=
"node.primary"
:node-actions-allowed=
"nodeActionsAllowed"
:node-edit-allowed=
"nodeEditAllowed"
/>
<p
class=
"health-message prepend-left-15 append-right-15"
v-if=
"hasError"
>
{{
errorMessage
}}
</p>
<deprecated-modal
v-show=
"showModal"
:title=
"__('Are you sure?')"
...
...
ee/app/assets/javascripts/geo_nodes/components/geo_node_detail_item.vue
View file @
7edc337f
...
...
@@ -4,14 +4,12 @@
import
{
VALUE_TYPE
,
CUSTOM_TYPE
}
from
'
../constants
'
;
import
geoNodeHealthStatus
from
'
./geo_node_health_status.vue
'
;
import
geoNodeSyncSettings
from
'
./geo_node_sync_settings.vue
'
;
import
geoNodeEventStatus
from
'
./geo_node_event_status.vue
'
;
export
default
{
components
:
{
stackedProgressBar
,
geoNodeHealthStatus
,
geoNodeSyncSettings
,
geoNodeEventStatus
,
},
...
...
@@ -53,6 +51,11 @@
required
:
false
,
default
:
''
,
},
eventTypeLogStatus
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
computed
:
{
isValueTypePlain
()
{
...
...
@@ -64,9 +67,6 @@
isValueTypeCustom
()
{
return
this
.
itemValueType
===
VALUE_TYPE
.
CUSTOM
;
},
isCustomTypeStatus
()
{
return
this
.
customType
===
CUSTOM_TYPE
.
STATUS
;
},
isCustomTypeSync
()
{
return
this
.
customType
===
CUSTOM_TYPE
.
SYNC
;
},
...
...
@@ -75,7 +75,7 @@
</
script
>
<
template
>
<
li
class=
"row node-detail-item
"
>
<
div
class=
"node-detail-item prepend-top-15 prepend-left-10
"
>
<div
class=
"node-detail-title"
>
{{
itemTitle
}}
</div>
...
...
@@ -100,12 +100,8 @@
/>
</div>
<template
v-if=
"isValueTypeCustom"
>
<geo-node-health-status
v-if=
"isCustomTypeStatus"
:status=
"itemValue"
/>
<geo-node-sync-settings
v-
else-
if=
"isCustomTypeSync"
v-if=
"isCustomTypeSync"
:sync-status-unavailable=
"itemValue.syncStatusUnavailable"
:selective-sync-type=
"itemValue.selectiveSyncType"
:last-event=
"itemValue.lastEvent"
...
...
@@ -115,7 +111,8 @@
v-else
:event-id=
"itemValue.eventId"
:event-time-stamp=
"itemValue.eventTimeStamp"
:event-type-log-status=
"eventTypeLogStatus"
/>
</
template
>
</
li
>
</
div
>
</template>
ee/app/assets/javascripts/geo_nodes/components/geo_node_details.vue
View file @
7edc337f
<
script
>
/* eslint-disable vue/no-side-effects-in-computed-properties */
import
{
s__
,
__
}
from
'
~/locale
'
;
import
{
parseSeconds
,
stringifyTime
}
from
'
~/lib/utils/pretty_time
'
;
import
{
numberToHumanSize
}
from
'
~/lib/utils/number_utils
'
;
import
icon
from
'
~/vue_shared/components/icon.vue
'
;
import
{
s__
}
from
'
~/locale
'
;
import
{
VALUE_TYPE
,
CUSTOM_TYPE
}
from
'
../constants
'
;
import
geoNodeDetailItem
from
'
./geo_node_detail_item.vue
'
;
import
NodeDetailsSectionMain
from
'
./node_detail_sections/node_details_section_main.vue
'
;
import
NodeDetailsSectionSync
from
'
./node_detail_sections/node_details_section_sync.vue
'
;
import
NodeDetailsSectionVerification
from
'
./node_detail_sections/node_details_section_verification.vue
'
;
import
NodeDetailsSectionOther
from
'
./node_detail_sections/node_details_section_other.vue
'
;
export
default
{
components
:
{
icon
,
geoNodeDetailItem
,
NodeDetailsSectionMain
,
NodeDetailsSectionSync
,
NodeDetailsSectionVerification
,
NodeDetailsSectionOther
,
},
props
:
{
node
:
{
...
...
@@ -23,56 +23,19 @@
type
:
Object
,
required
:
true
,
},
nodeActionsAllowed
:
{
type
:
Boolean
,
required
:
true
,
},
nodeEditAllowed
:
{
type
:
Boolean
,
required
:
true
,
},
},
data
()
{
return
{
showAdvanceItems
:
false
,
errorMessage
:
''
,
nodeDetailItems
:
[
{
itemTitle
:
s__
(
'
GeoNodes|Storage config:
'
),
itemValue
:
this
.
storageShardsStatus
(),
itemValueType
:
VALUE_TYPE
.
PLAIN
,
cssClass
:
this
.
plainValueCssClass
(
!
this
.
nodeDetails
.
storageShardsMatch
),
},
{
itemTitle
:
s__
(
'
GeoNodes|Health status:
'
),
itemValue
:
this
.
nodeHealthStatus
(),
itemValueType
:
VALUE_TYPE
.
CUSTOM
,
customType
:
CUSTOM_TYPE
.
STATUS
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Repositories:
'
),
itemValue
:
this
.
nodeDetails
.
repositories
,
itemValueType
:
VALUE_TYPE
.
GRAPH
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Wikis:
'
),
itemValue
:
this
.
nodeDetails
.
wikis
,
itemValueType
:
VALUE_TYPE
.
GRAPH
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Local LFS objects:
'
),
itemValue
:
this
.
nodeDetails
.
lfs
,
itemValueType
:
VALUE_TYPE
.
GRAPH
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Local job artifacts:
'
),
itemValue
:
this
.
nodeDetails
.
jobArtifacts
,
itemValueType
:
VALUE_TYPE
.
GRAPH
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Local Attachments:
'
),
itemValue
:
this
.
nodeDetails
.
attachments
,
itemValueType
:
VALUE_TYPE
.
GRAPH
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Sync settings:
'
),
itemValue
:
this
.
syncSettings
(),
itemValueType
:
VALUE_TYPE
.
CUSTOM
,
customType
:
CUSTOM_TYPE
.
SYNC
,
},
],
};
},
computed
:
{
...
...
@@ -90,197 +53,36 @@
}
return
false
;
},
versionCssClass
()
{
return
this
.
plainValueCssClass
(
this
.
hasVersionMismatch
);
},
advanceButtonIcon
()
{
return
this
.
showAdvanceItems
?
'
angle-up
'
:
'
angle-down
'
;
},
nodeVersion
()
{
if
(
this
.
nodeDetails
.
version
==
null
&&
this
.
nodeDetails
.
revision
==
null
)
{
return
__
(
'
Unknown
'
);
}
return
`
${
this
.
nodeDetails
.
version
}
(
${
this
.
nodeDetails
.
revision
}
)`
;
},
replicationSlotWAL
()
{
return
numberToHumanSize
(
this
.
nodeDetails
.
replicationSlotWAL
);
},
dbReplicationLag
()
{
// Replication lag can be nil if the secondary isn't actually streaming
if
(
this
.
nodeDetails
.
dbReplicationLag
!==
null
&&
this
.
nodeDetails
.
dbReplicationLag
>=
0
)
{
const
parsedTime
=
parseSeconds
(
this
.
nodeDetails
.
dbReplicationLag
,
{
hoursPerDay
:
24
,
daysPerWeek
:
7
,
});
return
stringifyTime
(
parsedTime
);
}
return
__
(
'
Unknown
'
);
},
lastEventStatus
()
{
return
{
eventId
:
this
.
nodeDetails
.
lastEvent
.
id
,
eventTimeStamp
:
this
.
nodeDetails
.
lastEvent
.
timeStamp
,
};
},
cursorLastEventStatus
()
{
return
{
eventId
:
this
.
nodeDetails
.
cursorLastEvent
.
id
,
eventTimeStamp
:
this
.
nodeDetails
.
cursorLastEvent
.
timeStamp
,
};
},
valueType
()
{
return
VALUE_TYPE
;
},
customType
()
{
return
CUSTOM_TYPE
;
},
},
methods
:
{
nodeHealthStatus
()
{
return
this
.
nodeDetails
.
healthy
?
this
.
nodeDetails
.
health
:
this
.
nodeDetails
.
healthStatus
;
},
storageShardsStatus
()
{
if
(
this
.
nodeDetails
.
storageShardsMatch
==
null
)
{
return
__
(
'
Unknown
'
);
}
return
this
.
nodeDetails
.
storageShardsMatch
?
__
(
'
OK
'
)
:
s__
(
'
GeoNodes|Does not match the primary storage configuration
'
);
},
plainValueCssClass
(
value
)
{
const
cssClass
=
'
node-detail-value-bold
'
;
return
value
?
`
${
cssClass
}
node-detail-value-error`
:
cssClass
;
},
syncSettings
()
{
return
{
syncStatusUnavailable
:
this
.
nodeDetails
.
syncStatusUnavailable
,
selectiveSyncType
:
this
.
nodeDetails
.
selectiveSyncType
,
lastEvent
:
this
.
nodeDetails
.
lastEvent
,
cursorLastEvent
:
this
.
nodeDetails
.
cursorLastEvent
,
};
},
onClickShowAdvance
()
{
this
.
showAdvanceItems
=
!
this
.
showAdvanceItems
;
},
},
};
</
script
>
<
template
>
<div
class=
"row"
>
<ul
class=
"col-md-8 list-unstyled node-details-list"
>
<geo-node-detail-item
:item-title=
"s__('GeoNodes|GitLab version:')"
:css-class=
"versionCssClass"
:item-value=
"nodeVersion"
:item-value-type=
"valueType.PLAIN"
/>
<template
v-if=
"!node.primary"
>
<geo-node-detail-item
v-for=
"(nodeDetailItem, index) in nodeDetailItems"
:key=
"index"
:css-class=
"nodeDetailItem.cssClass"
:item-title=
"nodeDetailItem.itemTitle"
:item-value=
"nodeDetailItem.itemValue"
:item-value-type=
"nodeDetailItem.itemValueType"
:custom-type=
"nodeDetailItem.customType"
/>
</
template
>
<li
class=
"prepend-top-5 node-detail-item"
>
<button
class=
"btn-link btn-show-advanced"
type=
"button"
@
click=
"onClickShowAdvance"
>
<span>
{{ __('Advanced') }}
</span>
<icon
:size=
"12"
:name=
"advanceButtonIcon"
/>
</button>
</li>
<
template
v-if=
"showAdvanceItems"
>
<template
v-if=
"node.primary"
>
<geo-node-detail-item
v-if=
"nodeDetails.repositoryVerificationEnabled"
:item-title=
"s__('GeoNodes|Repositories checksummed:')"
:success-label=
"s__('GeoNodes|Checksummed')"
:neutral-label=
"s__('GeoNodes|Not checksummed')"
:failure-label=
"s__('GeoNodes|Failed')"
:item-value=
"nodeDetails.verifiedRepositories"
:item-value-type=
"valueType.GRAPH"
/>
<geo-node-detail-item
v-if=
"nodeDetails.repositoryVerificationEnabled"
:item-title=
"s__('GeoNodes|Wikis checksummed:')"
:success-label=
"s__('GeoNodes|Checksummed')"
:neutral-label=
"s__('GeoNodes|Not checksummed')"
:failure-label=
"s__('GeoNodes|Failed')"
:item-value=
"nodeDetails.verifiedWikis"
:item-value-type=
"valueType.GRAPH"
/>
<geo-node-detail-item
:item-title=
"s__('GeoNodes|Replication slots:')"
:success-label=
"s__('GeoNodes|Used slots')"
:neutral-label=
"s__('GeoNodes|Unused slots')"
:item-value=
"nodeDetails.replicationSlots"
:item-value-type=
"valueType.GRAPH"
/>
<geo-node-detail-item
v-if=
"nodeDetails.replicationSlots.totalCount"
css-class=
"node-detail-value-bold"
:item-title=
"s__('GeoNodes|Replication slot WAL:')"
:item-value=
"replicationSlotWAL"
:item-value-type=
"valueType.PLAIN"
/>
</
template
>
<
template
v-else
>
<geo-node-detail-item
v-if=
"nodeDetails.repositoryVerificationEnabled"
:item-title=
"s__('GeoNodes|Repository checksums verified:')"
:success-label=
"s__('GeoNodes|Verified')"
:neutral-label=
"s__('GeoNodes|Unverified')"
:failure-label=
"s__('GeoNodes|Failed')"
:item-value=
"nodeDetails.verifiedRepositories"
:item-value-type=
"valueType.GRAPH"
/>
<geo-node-detail-item
v-if=
"nodeDetails.repositoryVerificationEnabled"
:item-title=
"s__('GeoNodes|Wiki checksums verified:')"
:success-label=
"s__('GeoNodes|Verified')"
:neutral-label=
"s__('GeoNodes|Unverified')"
:failure-label=
"s__('GeoNodes|Failed')"
:item-value=
"nodeDetails.verifiedWikis"
:item-value-type=
"valueType.GRAPH"
/>
<geo-node-detail-item
css-class=
"node-detail-value-bold"
:item-title=
"s__('GeoNodes|Database replication lag:')"
:item-value=
"dbReplicationLag"
:item-value-type=
"valueType.PLAIN"
/>
<geo-node-detail-item
:item-title=
"s__('GeoNodes|Last event ID seen from primary:')"
:item-value=
"lastEventStatus"
:item-value-type=
"valueType.CUSTOM"
:custom-type=
"customType.EVENT"
/>
<geo-node-detail-item
:item-title=
"s__('GeoNodes|Last event ID processed by cursor:')"
:item-value=
"cursorLastEventStatus"
:item-value-type=
"valueType.CUSTOM"
:custom-type=
"customType.EVENT"
/>
</
template
>
</template>
</ul>
<div
class=
"panel-body"
>
<node-details-section-main
:node=
"node"
:node-details=
"nodeDetails"
:node-actions-allowed=
"nodeActionsAllowed"
:node-edit-allowed=
"nodeEditAllowed"
:version-mismatch=
"hasVersionMismatch"
/>
<node-details-section-sync
v-if=
"!node.primary"
:node-details=
"nodeDetails"
/>
<node-details-section-verification
:node-details=
"nodeDetails"
:node-type-primary=
"node.primary"
/>
<node-details-section-other
v-if=
"!node.primary"
:node-details=
"nodeDetails"
/>
<div
v-if=
"hasError || hasVersionMismatch"
class=
"
col-md-12 prepend-top-10
"
class=
"
node-health-message-container
"
>
<p
class=
"health-message"
>
<p
class=
"
node-
health-message"
>
{{
errorMessage
}}
</p>
</div>
...
...
ee/app/assets/javascripts/geo_nodes/components/geo_node_event_status.vue
View file @
7edc337f
<
script
>
import
{
s__
,
sprintf
}
from
'
~/locale
'
;
import
{
formatDate
}
from
'
~/lib/utils/datetime_utility
'
;
import
timeAgoMixin
from
'
~/vue_shared/mixins/timeago
'
;
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
...
...
@@ -18,6 +19,12 @@
eventTimeStamp
:
{
type
:
Number
,
required
:
true
,
default
:
0
,
},
eventTypeLogStatus
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
computed
:
{
...
...
@@ -27,6 +34,14 @@
timeStampString
()
{
return
formatDate
(
this
.
timeStamp
);
},
eventString
()
{
if
(
this
.
eventTypeLogStatus
)
{
return
sprintf
(
s__
(
'
GeoNodes|%{eventId} events behind
'
),
{
eventId
:
this
.
eventId
,
});
}
return
this
.
eventId
;
},
},
};
</
script
>
...
...
@@ -37,7 +52,7 @@
>
<template
v-if=
"eventTimeStamp"
>
<strong>
{{
event
Id
}}
{{
event
String
}}
</strong>
<span
v-tooltip
...
...
ee/app/assets/javascripts/geo_nodes/components/geo_node_health_status.vue
View file @
7edc337f
...
...
@@ -24,18 +24,23 @@
</
script
>
<
template
>
<div
class=
"node-detail-value node-health-status"
:class=
"healthCssClass"
>
<icon
:size=
"16"
:name=
"statusIconName"
/>
<span
class=
"status-text prepend-left-5"
<div
class=
"prepend-top-15 detail-section-item"
>
<div
class=
"node-detail-title"
>
{{
s__
(
'
GeoNodes|Health status:
'
)
}}
</div>
<div
class=
"node-detail-value node-health-status"
:class=
"healthCssClass"
>
{{
status
}}
</span>
<icon
:size=
"16"
:name=
"statusIconName"
/>
<span
class=
"status-text prepend-left-5"
>
{{
status
}}
</span>
</div>
</div>
</
template
>
ee/app/assets/javascripts/geo_nodes/components/geo_node_item.vue
View file @
7edc337f
<
script
>
import
{
s__
}
from
'
~/locale
'
;
import
icon
from
'
~/vue_shared/components/icon.vue
'
;
import
loadingIcon
from
'
~/vue_shared/components/loading_icon.vue
'
;
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
import
eventHub
from
'
../event_hub
'
;
import
geoNodeActions
from
'
./geo_node_actions
.vue
'
;
import
g
eoNodeDetails
from
'
./geo_node_details.vue
'
;
import
GeoNodeHeader
from
'
./geo_node_header
.vue
'
;
import
G
eoNodeDetails
from
'
./geo_node_details.vue
'
;
export
default
{
components
:
{
icon
,
loadingIcon
,
geoNodeActions
,
geoNodeDetails
,
},
directives
:
{
tooltip
,
GeoNodeHeader
,
GeoNodeDetails
,
},
props
:
{
node
:
{
...
...
@@ -47,41 +37,12 @@ export default {
};
},
computed
:
{
isNodeNonHTTPS
()
{
return
this
.
node
.
url
.
startsWith
(
'
http://
'
);
},
showNodeStatusIcon
()
{
if
(
this
.
isNodeDetailsLoading
)
{
return
false
;
}
return
this
.
isNodeNonHTTPS
||
this
.
isNodeDetailsFailed
;
},
showNodeDetails
()
{
if
(
!
this
.
isNodeDetailsLoading
)
{
return
!
this
.
isNodeDetailsFailed
;
}
return
false
;
},
nodeStatusIconClass
()
{
const
iconClasses
=
'
prepend-left-10 pull-left
'
;
if
(
this
.
isNodeDetailsFailed
)
{
return
`
${
iconClasses
}
node-status-icon-failure`
;
}
return
`
${
iconClasses
}
node-status-icon-warning`
;
},
nodeStatusIconName
()
{
if
(
this
.
isNodeDetailsFailed
)
{
return
'
status_failed_borderless
'
;
}
return
'
warning
'
;
},
nodeStatusIconTooltip
()
{
if
(
this
.
isNodeDetailsFailed
)
{
return
''
;
}
return
s__
(
'
GeoNodes|You have configured Geo nodes using an insecure HTTP connection. We recommend the use of HTTPS.
'
);
},
},
created
()
{
eventHub
.
$on
(
'
nodeDetailsLoaded
'
,
this
.
handleNodeDetails
);
...
...
@@ -119,59 +80,22 @@ export default {
</
script
>
<
template
>
<li
<div
class=
"panel panel-default geo-node-item"
:class=
"
{ 'node-action-active': node.nodeActionActive }"
>
<div
class=
"row"
>
<div
class=
"col-md-8"
>
<div
class=
"row"
>
<div
class=
"col-md-8 clearfix"
>
<strong
class=
"node-url inline pull-left"
>
{{
node
.
url
}}
</strong>
<loading-icon
v-if=
"isNodeDetailsLoading || node.nodeActionActive"
class=
"node-details-loading prepend-left-10 pull-left inline"
size=
"1"
/>
<icon
v-tooltip
v-if=
"showNodeStatusIcon"
data-container=
"body"
data-placement=
"bottom"
:name=
"nodeStatusIconName"
:size=
"18"
:css-classes=
"nodeStatusIconClass"
:title=
"nodeStatusIconTooltip"
/>
<span
class=
"inline pull-left prepend-left-10"
>
<span
class=
"node-badge current-node"
v-if=
"node.current"
>
{{
s__
(
'
Current node
'
)
}}
</span>
<span
class=
"node-badge primary-node"
v-if=
"node.primary"
>
{{
s__
(
'
Primary
'
)
}}
</span>
</span>
</div>
</div>
</div>
<geo-node-actions
v-if=
"showNodeDetails && nodeActionsAllowed"
:node=
"node"
:node-edit-allowed=
"nodeEditAllowed"
:node-missing-oauth=
"nodeDetails.missingOAuthApplication"
/>
</div>
<geo-node-header
:node=
"node"
:node-details=
"nodeDetails"
:node-details-loading=
"isNodeDetailsLoading"
:node-details-failed=
"isNodeDetailsFailed"
/>
<geo-node-details
v-if=
"showNodeDetails"
:node=
"node"
:node-details=
"nodeDetails"
:node-edit-allowed=
"nodeEditAllowed"
:node-actions-allowed=
"nodeActionsAllowed"
/>
<div
v-if=
"isNodeDetailsFailed"
...
...
@@ -181,5 +105,5 @@ export default {
{{
errorMessage
}}
</p>
</div>
</
li
>
</
div
>
</
template
>
ee/app/assets/javascripts/geo_nodes/components/geo_node_sync_settings.vue
View file @
7edc337f
...
...
@@ -118,7 +118,7 @@
<span
v-else
v-tooltip
class=
"node-sync-settings
inline
"
class=
"node-sync-settings"
data-placement=
"bottom"
:title=
"syncStatusTooltip"
>
...
...
ee/app/assets/javascripts/geo_nodes/components/geo_nodes_list.vue
View file @
7edc337f
...
...
@@ -23,7 +23,7 @@ export default {
</
script
>
<
template
>
<
ul
class=
"well-list geo-nodes
"
>
<
div
class=
"panel panel-default
"
>
<geo-node-item
v-for=
"(node, index) in nodes"
:key=
"index"
...
...
@@ -32,5 +32,5 @@ export default {
:node-actions-allowed=
"nodeActionsAllowed"
:node-edit-allowed=
"nodeEditAllowed"
/>
</
ul
>
</
div
>
</
template
>
spec/javascripts/geo_nodes/components/app_spec.js
View file @
7edc337f
...
...
@@ -56,7 +56,6 @@ describe('AppComponent', () => {
expect
(
vm
.
modalKind
).
toBe
(
'
warning
'
);
expect
(
vm
.
modalMessage
).
toBe
(
''
);
expect
(
vm
.
modalActionLabel
).
toBe
(
''
);
expect
(
vm
.
errorMessage
).
toBe
(
''
);
});
});
...
...
@@ -91,10 +90,9 @@ describe('AppComponent', () => {
spyOn
(
vm
.
store
,
'
setNodes
'
);
vm
.
fetchGeoNodes
();
expect
(
vm
.
hasError
).
toBeFalsy
();
setTimeout
(()
=>
{
expect
(
vm
.
store
.
setNodes
).
toHaveBeenCalledWith
(
mockNodes
);
expect
(
vm
.
isLoading
).
toBe
Falsy
(
);
expect
(
vm
.
isLoading
).
toBe
(
false
);
done
();
},
0
);
});
...
...
@@ -104,10 +102,9 @@ describe('AppComponent', () => {
statusCode
=
500
;
vm
.
fetchGeoNodes
();
expect
(
vm
.
hasError
).
toBeFalsy
();
setTimeout
(()
=>
{
expect
(
vm
.
hasError
).
toBeTruthy
(
);
expect
(
vm
.
errorMessage
.
response
.
data
).
toBe
(
response
);
expect
(
vm
.
isLoading
).
toBe
(
false
);
expect
(
document
.
querySelector
(
'
.flash-text
'
).
innerText
.
trim
()).
toBe
(
'
Something went wrong while fetching nodes
'
);
done
();
},
0
);
});
...
...
@@ -380,39 +377,13 @@ describe('AppComponent', () => {
});
describe
(
'
template
'
,
()
=>
{
it
(
'
renders container elements correctly
'
,
()
=>
{
expect
(
vm
.
$el
.
classList
.
contains
(
'
panel
'
,
'
panel-default
'
)).
toBeTruthy
();
expect
(
vm
.
$el
.
querySelectorAll
(
'
.panel-heading
'
).
length
).
not
.
toBe
(
0
);
expect
(
vm
.
$el
.
querySelector
(
'
.panel-heading
'
).
innerText
.
trim
()).
toBe
(
'
Geo nodes (0)
'
);
it
(
'
renders container element with class `geo-nodes-container`
'
,
()
=>
{
expect
(
vm
.
$el
.
classList
.
contains
(
'
geo-nodes-container
'
)).
toBe
(
true
);
});
it
(
'
renders loading animation when `isLoading` is true
'
,
()
=>
{
vm
.
isLoading
=
true
;
expect
(
vm
.
$el
.
querySelectorAll
(
'
.loading-animation.prepend-top-20.append-bottom-20
'
).
length
).
not
.
toBe
(
0
);
});
it
(
'
renders list of nodes
'
,
(
done
)
=>
{
vm
.
store
.
setNodes
(
mockNodes
);
vm
.
isLoading
=
false
;
Vue
.
nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelectorAll
(
'
.loading-animation.prepend-top-20.append-bottom-20
'
).
length
).
toBe
(
0
);
expect
(
vm
.
$el
.
querySelectorAll
(
'
ul.geo-nodes
'
).
length
).
not
.
toBe
(
0
);
done
();
});
});
it
(
'
renders error message
'
,
(
done
)
=>
{
vm
.
hasError
=
true
;
vm
.
isLoading
=
false
;
vm
.
errorMessage
=
'
Something went wrong.
'
;
Vue
.
nextTick
(()
=>
{
const
errEl
=
'
p.health-message.prepend-left-15.append-right-15
'
;
expect
(
vm
.
$el
.
querySelectorAll
(
errEl
).
length
).
not
.
toBe
(
0
);
expect
(
vm
.
$el
.
querySelector
(
errEl
).
innerText
.
trim
()).
toBe
(
vm
.
errorMessage
);
done
();
});
});
});
});
spec/javascripts/geo_nodes/components/geo_node_detail_item_spec.js
View file @
7edc337f
...
...
@@ -46,16 +46,6 @@ describe('GeoNodeDetailItemComponent', () => {
vm
.
$destroy
();
});
it
(
'
renders health status item value
'
,
()
=>
{
const
vm
=
createComponent
({
itemValueType
:
VALUE_TYPE
.
CUSTOM
,
customType
:
CUSTOM_TYPE
.
STATUS
,
itemValue
:
rawMockNodeDetails
.
health
,
});
expect
(
vm
.
$el
.
querySelectorAll
(
'
.node-health-status
'
).
length
).
not
.
toBe
(
0
);
vm
.
$destroy
();
});
it
(
'
renders sync settings item value
'
,
()
=>
{
const
vm
=
createComponent
({
itemValueType
:
VALUE_TYPE
.
CUSTOM
,
...
...
spec/javascripts/geo_nodes/components/geo_node_details_spec.js
View file @
7edc337f
...
...
@@ -2,14 +2,21 @@ import Vue from 'vue';
import
geoNodeDetailsComponent
from
'
ee/geo_nodes/components/geo_node_details.vue
'
;
import
mountComponent
from
'
spec/helpers/vue_mount_component_helper
'
;
import
{
mockNodes
,
mockNodeDetails
}
from
'
../mock_data
'
;
const
createComponent
=
(
nodeDetails
=
mockNodeDetails
)
=>
{
import
{
mockNode
,
mockNodeDetails
}
from
'
../mock_data
'
;
const
createComponent
=
({
node
=
mockNode
,
nodeDetails
=
mockNodeDetails
,
nodeActionsAllowed
=
true
,
nodeEditAllowed
=
true
,
})
=>
{
const
Component
=
Vue
.
extend
(
geoNodeDetailsComponent
);
return
mountComponent
(
Component
,
{
node
,
nodeDetails
,
node
:
mockNodes
[
1
],
nodeActionsAllowed
,
nodeEditAllowed
,
});
};
...
...
@@ -17,7 +24,7 @@ describe('GeoNodeDetailsComponent', () => {
let
vm
;
beforeEach
(()
=>
{
vm
=
createComponent
();
vm
=
createComponent
(
{}
);
});
afterEach
(()
=>
{
...
...
@@ -28,7 +35,6 @@ describe('GeoNodeDetailsComponent', () => {
it
(
'
returns default data props
'
,
()
=>
{
expect
(
vm
.
showAdvanceItems
).
toBeFalsy
();
expect
(
vm
.
errorMessage
).
toBe
(
''
);
expect
(
Array
.
isArray
(
vm
.
nodeDetailItems
)).
toBeTruthy
();
});
});
...
...
@@ -40,7 +46,7 @@ describe('GeoNodeDetailsComponent', () => {
health
:
'
Something went wrong.
'
,
healthy
:
false
,
});
const
vmX
=
createComponent
(
nodeDetails
);
const
vmX
=
createComponent
(
{
nodeDetails
}
);
expect
(
vmX
.
errorMessage
).
toBe
(
'
Something went wrong.
'
);
expect
(
vmX
.
hasError
).
toBeTruthy
();
vmX
.
$destroy
();
...
...
@@ -57,7 +63,7 @@ describe('GeoNodeDetailsComponent', () => {
primaryVersion
:
'
10.3.0-pre
'
,
primaryRevision
:
'
b93c51850b
'
,
});
const
vmX
=
createComponent
(
nodeDetails
);
const
vmX
=
createComponent
(
{
nodeDetails
}
);
expect
(
vmX
.
errorMessage
).
toBe
(
'
GitLab version does not match the primary node version
'
);
expect
(
vmX
.
hasVersionMismatch
).
toBeTruthy
();
vmX
.
$destroy
();
...
...
@@ -66,147 +72,11 @@ describe('GeoNodeDetailsComponent', () => {
expect
(
vm
.
hasVersionMismatch
).
toBeFalsy
();
});
});
describe
(
'
advanceButtonIcon
'
,
()
=>
{
it
(
'
returns button icon name
'
,
()
=>
{
vm
.
showAdvanceItems
=
true
;
expect
(
vm
.
advanceButtonIcon
).
toBe
(
'
angle-up
'
);
vm
.
showAdvanceItems
=
false
;
expect
(
vm
.
advanceButtonIcon
).
toBe
(
'
angle-down
'
);
});
});
describe
(
'
nodeVersion
'
,
()
=>
{
it
(
'
returns `Unknown` when `version` and `revision` are null
'
,
()
=>
{
const
nodeDetailsVersionNull
=
Object
.
assign
({},
mockNodeDetails
,
{
version
:
null
,
revision
:
null
,
});
const
vmVersionNull
=
createComponent
(
nodeDetailsVersionNull
);
expect
(
vmVersionNull
.
nodeVersion
).
toBe
(
'
Unknown
'
);
vmVersionNull
.
$destroy
();
});
it
(
'
returns version string
'
,
()
=>
{
expect
(
vm
.
nodeVersion
).
toBe
(
'
10.4.0-pre (b93c51849b)
'
);
});
});
describe
(
'
replicationSlotWAL
'
,
()
=>
{
it
(
'
returns replication slot WAL in Megabytes
'
,
()
=>
{
expect
(
vm
.
replicationSlotWAL
).
toBe
(
'
479.37 MiB
'
);
});
});
describe
(
'
dbReplicationLag
'
,
()
=>
{
it
(
'
returns DB replication lag time duration
'
,
()
=>
{
expect
(
vm
.
dbReplicationLag
).
toBe
(
'
0m
'
);
});
it
(
'
returns `Unknown` when `dbReplicationLag` is null
'
,
()
=>
{
const
nodeDetailsLagNull
=
Object
.
assign
({},
mockNodeDetails
,
{
dbReplicationLag
:
null
,
});
const
vmLagNull
=
createComponent
(
nodeDetailsLagNull
);
expect
(
vmLagNull
.
dbReplicationLag
).
toBe
(
'
Unknown
'
);
vmLagNull
.
$destroy
();
});
});
describe
(
'
lastEventStatus
'
,
()
=>
{
it
(
'
returns event status object
'
,
()
=>
{
expect
(
vm
.
lastEventStatus
.
eventId
).
toBe
(
mockNodeDetails
.
lastEvent
.
id
);
expect
(
vm
.
lastEventStatus
.
eventTimeStamp
).
toBe
(
mockNodeDetails
.
lastEvent
.
timeStamp
);
});
});
describe
(
'
cursorLastEventStatus
'
,
()
=>
{
it
(
'
returns event status object
'
,
()
=>
{
expect
(
vm
.
cursorLastEventStatus
.
eventId
).
toBe
(
mockNodeDetails
.
cursorLastEvent
.
id
);
expect
(
vm
.
cursorLastEventStatus
.
eventTimeStamp
)
.
toBe
(
mockNodeDetails
.
cursorLastEvent
.
timeStamp
);
});
});
});
describe
(
'
methods
'
,
()
=>
{
describe
(
'
nodeHealthStatus
'
,
()
=>
{
it
(
'
returns health status string
'
,
()
=>
{
// With altered mock data for Unhealthy status
const
nodeDetails
=
Object
.
assign
({},
mockNodeDetails
,
{
healthStatus
:
'
Unhealthy
'
,
healthy
:
false
,
});
const
vmX
=
createComponent
(
nodeDetails
);
expect
(
vmX
.
nodeHealthStatus
()).
toBe
(
'
Unhealthy
'
);
vmX
.
$destroy
();
// With default mock data
expect
(
vm
.
nodeHealthStatus
()).
toBe
(
'
Healthy
'
);
});
});
describe
(
'
storageShardsStatus
'
,
()
=>
{
it
(
'
returns storage shard status string
'
,
()
=>
{
// With altered mock data for Unhealthy status
let
nodeDetails
=
Object
.
assign
({},
mockNodeDetails
,
{
storageShardsMatch
:
null
,
});
let
vmX
=
createComponent
(
nodeDetails
);
expect
(
vmX
.
storageShardsStatus
()).
toBe
(
'
Unknown
'
);
vmX
.
$destroy
();
nodeDetails
=
Object
.
assign
({},
mockNodeDetails
,
{
storageShardsMatch
:
true
,
});
vmX
=
createComponent
(
nodeDetails
);
expect
(
vmX
.
storageShardsStatus
()).
toBe
(
'
OK
'
);
vmX
.
$destroy
();
// With default mock data
expect
(
vm
.
storageShardsStatus
()).
toBe
(
'
Does not match the primary storage configuration
'
);
});
});
describe
(
'
plainValueCssClass
'
,
()
=>
{
it
(
'
returns CSS class for plain value item
'
,
()
=>
{
expect
(
vm
.
plainValueCssClass
()).
toBe
(
'
node-detail-value-bold
'
);
expect
(
vm
.
plainValueCssClass
(
true
)).
toBe
(
'
node-detail-value-bold node-detail-value-error
'
);
});
});
describe
(
'
syncSettings
'
,
()
=>
{
it
(
'
returns sync settings object
'
,
()
=>
{
const
nodeDetailsUnknownSync
=
Object
.
assign
({},
mockNodeDetails
,
{
syncStatusUnavailable
:
true
,
});
const
vmUnknownSync
=
createComponent
(
nodeDetailsUnknownSync
);
const
syncSettings
=
vmUnknownSync
.
syncSettings
();
expect
(
syncSettings
.
syncStatusUnavailable
).
toBe
(
true
);
expect
(
syncSettings
.
namespaces
).
toBe
(
mockNodeDetails
.
namespaces
);
expect
(
syncSettings
.
lastEvent
).
toBe
(
mockNodeDetails
.
lastEvent
);
expect
(
syncSettings
.
cursorLastEvent
).
toBe
(
mockNodeDetails
.
cursorLastEvent
);
vmUnknownSync
.
$destroy
();
});
});
describe
(
'
onClickShowAdvance
'
,
()
=>
{
it
(
'
toggles `showAdvanceItems` prop
'
,
()
=>
{
vm
.
showAdvanceItems
=
true
;
vm
.
onClickShowAdvance
();
expect
(
vm
.
showAdvanceItems
).
toBeFalsy
();
vm
.
showAdvanceItems
=
false
;
vm
.
onClickShowAdvance
();
expect
(
vm
.
showAdvanceItems
).
toBeTruthy
();
});
});
});
describe
(
'
template
'
,
()
=>
{
it
(
'
renders container elements correctly
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelectorAll
(
'
.node-details-list
'
).
length
).
not
.
toBe
(
0
);
expect
(
vm
.
$el
.
querySelectorAll
(
'
.btn-show-advanced
'
).
length
).
not
.
toBe
(
0
);
expect
(
vm
.
$el
.
classList
.
contains
(
'
panel-body
'
)).
toBe
(
true
);
});
});
});
spec/javascripts/geo_nodes/components/geo_node_event_status_spec.js
View file @
7edc337f
...
...
@@ -4,15 +4,17 @@ import geoNodeEventStatusComponent from 'ee/geo_nodes/components/geo_node_event_
import
mountComponent
from
'
spec/helpers/vue_mount_component_helper
'
;
import
{
mockNodeDetails
}
from
'
../mock_data
'
;
const
createComponent
=
(
const
createComponent
=
(
{
eventId
=
mockNodeDetails
.
lastEvent
.
id
,
eventTimeStamp
=
mockNodeDetails
.
lastEvent
.
timeStamp
,
)
=>
{
eventTypeLogStatus
=
false
,
})
=>
{
const
Component
=
Vue
.
extend
(
geoNodeEventStatusComponent
);
return
mountComponent
(
Component
,
{
eventId
,
eventTimeStamp
,
eventTypeLogStatus
,
});
};
...
...
@@ -20,7 +22,7 @@ describe('GeoNodeEventStatus', () => {
let
vm
;
beforeEach
(()
=>
{
vm
=
createComponent
();
vm
=
createComponent
(
{}
);
});
afterEach
(()
=>
{
...
...
@@ -39,6 +41,18 @@ describe('GeoNodeEventStatus', () => {
expect
(
vm
.
timeStampString
).
toContain
(
'
Nov 21, 2017
'
);
});
});
describe
(
'
eventString
'
,
()
=>
{
it
(
'
returns computed event string when `eventTypeLogStatus` prop is true
'
,
()
=>
{
const
vmWithLogStatus
=
createComponent
({
eventTypeLogStatus
:
true
});
expect
(
vmWithLogStatus
.
eventString
).
toBe
(
`
${
mockNodeDetails
.
lastEvent
.
id
}
events behind`
);
vmWithLogStatus
.
$destroy
();
});
it
(
'
returns event ID as it is when `eventTypeLogStatus` prop is false
'
,
()
=>
{
expect
(
vm
.
eventString
).
toBe
(
mockNodeDetails
.
lastEvent
.
id
);
});
});
});
describe
(
'
template
'
,
()
=>
{
...
...
@@ -50,7 +64,10 @@ describe('GeoNodeEventStatus', () => {
});
it
(
'
renders empty state when timestamp is not present
'
,
()
=>
{
const
vmWithoutTimestamp
=
createComponent
(
0
,
0
);
const
vmWithoutTimestamp
=
createComponent
({
eventId
:
0
,
eventTimeStamp
:
0
,
});
expect
(
vmWithoutTimestamp
.
$el
.
querySelectorAll
(
'
strong
'
).
length
).
not
.
toBe
(
0
);
expect
(
vmWithoutTimestamp
.
$el
.
querySelectorAll
(
'
.event-status-timestamp
'
).
length
).
toBe
(
0
);
expect
(
vmWithoutTimestamp
.
$el
.
querySelector
(
'
strong
'
).
innerText
.
trim
()).
toBe
(
'
Not available
'
);
...
...
spec/javascripts/geo_nodes/components/geo_node_health_status_spec.js
View file @
7edc337f
...
...
@@ -50,10 +50,13 @@ describe('GeoNodeHealthStatusComponent', () => {
describe
(
'
template
'
,
()
=>
{
it
(
'
renders container elements correctly
'
,
()
=>
{
const
vm
=
createComponent
(
'
Healthy
'
);
expect
(
vm
.
$el
.
classList
.
contains
(
'
node-detail-value
'
,
'
node-health-status
'
,
'
geo-node-healthy
'
)).
toBeTruthy
();
expect
(
vm
.
$el
.
querySelectorAll
(
'
svg
'
).
length
).
not
.
toBe
(
0
);
expect
(
vm
.
$el
.
querySelector
(
'
svg use
'
).
getAttribute
(
'
xlink:href
'
)).
toContain
(
'
#status_success
'
);
expect
(
vm
.
$el
.
querySelector
(
'
.status-text
'
).
innerText
.
trim
()).
toBe
(
'
Healthy
'
);
expect
(
vm
.
$el
.
classList
.
contains
(
'
detail-section-item
'
)).
toBe
(
true
);
expect
(
vm
.
$el
.
querySelector
(
'
.node-detail-title
'
).
innerText
.
trim
()).
toBe
(
'
Health status:
'
);
const
iconContainerEl
=
vm
.
$el
.
querySelector
(
'
.node-detail-value.node-health-status
'
);
expect
(
iconContainerEl
).
not
.
toBeNull
();
expect
(
iconContainerEl
.
querySelector
(
'
svg use
'
).
getAttribute
(
'
xlink:href
'
)).
toContain
(
'
#status_success
'
);
expect
(
iconContainerEl
.
querySelector
(
'
.status-text
'
).
innerText
.
trim
()).
toBe
(
'
Healthy
'
);
vm
.
$destroy
();
});
});
...
...
spec/javascripts/geo_nodes/components/geo_node_item_spec.js
View file @
7edc337f
...
...
@@ -3,9 +3,9 @@ import Vue from 'vue';
import
geoNodeItemComponent
from
'
ee/geo_nodes/components/geo_node_item.vue
'
;
import
eventHub
from
'
ee/geo_nodes/event_hub
'
;
import
mountComponent
from
'
spec/helpers/vue_mount_component_helper
'
;
import
{
mockNode
s
,
mockNodeDetails
}
from
'
../mock_data
'
;
import
{
mockNode
,
mockNodeDetails
}
from
'
../mock_data
'
;
const
createComponent
=
(
node
=
mockNode
s
[
0
]
)
=>
{
const
createComponent
=
(
node
=
mockNode
)
=>
{
const
Component
=
Vue
.
extend
(
geoNodeItemComponent
);
return
mountComponent
(
Component
,
{
...
...
@@ -29,8 +29,8 @@ describe('GeoNodeItemComponent', () => {
describe
(
'
data
'
,
()
=>
{
it
(
'
returns default data props
'
,
()
=>
{
expect
(
vm
.
isNodeDetailsLoading
).
toBe
Truthy
(
);
expect
(
vm
.
isNodeDetailsFailed
).
toBe
Falsy
(
);
expect
(
vm
.
isNodeDetailsLoading
).
toBe
(
true
);
expect
(
vm
.
isNodeDetailsFailed
).
toBe
(
false
);
expect
(
vm
.
nodeHealthStatus
).
toBe
(
''
);
expect
(
vm
.
errorMessage
).
toBe
(
''
);
expect
(
typeof
vm
.
nodeDetails
).
toBe
(
'
object
'
);
...
...
@@ -39,57 +39,20 @@ describe('GeoNodeItemComponent', () => {
describe
(
'
computed
'
,
()
=>
{
let
vmHttps
;
let
mock
Node
;
let
https
Node
;
beforeEach
(()
=>
{
// Altered mock data for secure URL
mockNode
=
Object
.
assign
({},
mockNodes
[
0
]
,
{
httpsNode
=
Object
.
assign
({},
mockNode
,
{
url
:
'
https://127.0.0.1:3001/
'
,
});
vmHttps
=
createComponent
(
mock
Node
);
vmHttps
=
createComponent
(
https
Node
);
});
afterEach
(()
=>
{
vmHttps
.
$destroy
();
});
describe
(
'
isNodeNonHTTPS
'
,
()
=>
{
it
(
'
returns `true` if Node URL protocol is non-HTTPS
'
,
()
=>
{
// With default mock data
expect
(
vm
.
isNodeNonHTTPS
).
toBeTruthy
();
});
it
(
'
returns `false` is Node URL protocol is HTTPS
'
,
()
=>
{
// With altered mock data
expect
(
vmHttps
.
isNodeNonHTTPS
).
toBeFalsy
();
});
});
describe
(
'
showNodeStatusIcon
'
,
()
=>
{
it
(
'
returns `false` if Node details are still loading
'
,
()
=>
{
vm
.
isNodeDetailsLoading
=
true
;
expect
(
vm
.
showNodeStatusIcon
).
toBeFalsy
();
});
it
(
'
returns `true` if Node details failed to load
'
,
()
=>
{
vm
.
isNodeDetailsLoading
=
false
;
vm
.
isNodeDetailsFailed
=
true
;
expect
(
vm
.
showNodeStatusIcon
).
toBeTruthy
();
});
it
(
'
returns `true` if Node details loaded and Node URL is non-HTTPS
'
,
()
=>
{
vm
.
isNodeDetailsLoading
=
false
;
vm
.
isNodeDetailsFailed
=
false
;
expect
(
vm
.
showNodeStatusIcon
).
toBeTruthy
();
});
it
(
'
returns `false` if Node details loaded and Node URL is HTTPS
'
,
()
=>
{
vmHttps
.
isNodeDetailsLoading
=
false
;
vmHttps
.
isNodeDetailsFailed
=
false
;
expect
(
vmHttps
.
showNodeStatusIcon
).
toBeFalsy
();
});
});
describe
(
'
showNodeDetails
'
,
()
=>
{
it
(
'
returns `false` if Node details are still loading
'
,
()
=>
{
vm
.
isNodeDetailsLoading
=
true
;
...
...
@@ -108,50 +71,17 @@ describe('GeoNodeItemComponent', () => {
expect
(
vm
.
showNodeDetails
).
toBeTruthy
();
});
});
describe
(
'
nodeStatusIconClass
'
,
()
=>
{
it
(
'
returns `node-status-icon-failure` along with default classes if Node details failed to load
'
,
()
=>
{
vm
.
isNodeDetailsFailed
=
true
;
expect
(
vm
.
nodeStatusIconClass
).
toBe
(
'
prepend-left-10 pull-left node-status-icon-failure
'
);
});
it
(
'
returns `node-status-icon-warning` along with default classes if Node details loaded and Node URL is non-HTTPS
'
,
()
=>
{
vm
.
isNodeDetailsFailed
=
false
;
expect
(
vm
.
nodeStatusIconClass
).
toBe
(
'
prepend-left-10 pull-left node-status-icon-warning
'
);
});
});
describe
(
'
nodeStatusIconName
'
,
()
=>
{
it
(
'
returns `warning` if Node details loaded and Node URL is non-HTTPS
'
,
()
=>
{
vm
.
isNodeDetailsFailed
=
false
;
expect
(
vm
.
nodeStatusIconName
).
toBe
(
'
warning
'
);
});
it
(
'
returns `status_failed_borderless` if Node details failed to load
'
,
()
=>
{
vm
.
isNodeDetailsFailed
=
true
;
expect
(
vm
.
nodeStatusIconName
).
toBe
(
'
status_failed_borderless
'
);
});
});
describe
(
'
nodeStatusIconTooltip
'
,
()
=>
{
it
(
'
returns empty string if Node details failed to load
'
,
()
=>
{
vm
.
isNodeDetailsFailed
=
true
;
expect
(
vm
.
nodeStatusIconTooltip
).
toBe
(
''
);
});
it
(
'
returns tooltip string if Node details loaded and Node URL is non-HTTPS
'
,
()
=>
{
vm
.
isNodeDetailsFailed
=
false
;
expect
(
vm
.
nodeStatusIconTooltip
).
toBe
(
'
You have configured Geo nodes using an insecure HTTP connection. We recommend the use of HTTPS.
'
);
});
});
});
describe
(
'
methods
'
,
()
=>
{
describe
(
'
handleNodeDetails
'
,
()
=>
{
it
(
'
intializes props based on provided `nodeDetails`
'
,
()
=>
{
// With altered mock data with matching ID
const
mockNode
=
Object
.
assign
({},
mockNodes
[
1
]);
const
vmNodePrimary
=
createComponent
(
mockNode
);
const
mockNodeSecondary
=
Object
.
assign
({},
mockNode
,
{
id
:
mockNodeDetails
.
id
,
primary
:
false
,
});
const
vmNodePrimary
=
createComponent
(
mockNodeSecondary
);
vmNodePrimary
.
handleNodeDetails
(
mockNodeDetails
);
expect
(
vmNodePrimary
.
isNodeDetailsLoading
).
toBeFalsy
();
...
...
@@ -212,21 +142,8 @@ describe('GeoNodeItemComponent', () => {
});
describe
(
'
template
'
,
()
=>
{
it
(
'
renders node URL
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelectorAll
(
'
.node-url
'
).
length
).
not
.
toBe
(
0
);
});
it
(
'
renders node details loading animation
'
,
()
=>
{
vm
.
isNodeDetailsLoading
=
true
;
expect
(
vm
.
$el
.
querySelectorAll
(
'
.node-details-loading
'
).
length
).
not
.
toBe
(
0
);
});
it
(
'
renders node badge `Current node`
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelectorAll
(
'
.node-badge.current-node
'
).
length
).
not
.
toBe
(
0
);
});
it
(
'
renders node badge `Primary`
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelectorAll
(
'
.node-badge.primary-node
'
).
length
).
not
.
toBe
(
0
);
it
(
'
renders container element
'
,
()
=>
{
expect
(
vm
.
$el
.
classList
.
contains
(
'
panel
'
,
'
panel-default
'
,
'
geo-node-item
'
)).
toBe
(
true
);
});
it
(
'
renders node error message
'
,
(
done
)
=>
{
...
...
spec/javascripts/geo_nodes/components/geo_nodes_list_spec.js
View file @
7edc337f
...
...
@@ -18,7 +18,7 @@ describe('GeoNodesListComponent', () => {
describe
(
'
template
'
,
()
=>
{
it
(
'
renders container element correctly
'
,
()
=>
{
const
vm
=
createComponent
();
expect
(
vm
.
$el
.
classList
.
contains
(
'
well-list
'
,
'
geo-nodes
'
)).
toBeTruthy
(
);
expect
(
vm
.
$el
.
classList
.
contains
(
'
panel
'
,
'
panel-default
'
)).
toBe
(
true
);
vm
.
$destroy
();
});
});
...
...
spec/javascripts/geo_nodes/mock_data.js
View file @
7edc337f
...
...
@@ -145,6 +145,7 @@ export const mockNodeDetails = {
replicationSlotWAL
:
502658737
,
missingOAuthApplication
:
false
,
storageShardsMatch
:
false
,
repositoryVerificationEnabled
:
true
,
replicationSlots
:
{
totalCount
:
null
,
successCount
:
null
,
...
...
@@ -175,6 +176,16 @@ export const mockNodeDetails = {
successCount
:
0
,
failureCount
:
0
,
},
verifiedRepositories
:
{
totalCount
:
0
,
successCount
:
0
,
failureCount
:
0
,
},
verifiedWikis
:
{
totalCount
:
0
,
successCount
:
0
,
failureCount
:
0
,
},
lastEvent
:
{
id
:
3
,
timeStamp
:
1511255200
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment