66 <NsModal
77 size =" default"
88 :visible =" isShown"
9- @modal-hidden =" $emit('hide') "
9+ @modal-hidden =" onModalHidden "
1010 @primary-click =" cloneOrMove"
11+ @modal-shown =" onModalShown"
1112 :primary-button-disabled ="
1213 !selectedNode ||
1314 (!isClone && installationNode == selectedNode.id) ||
14- loading.cloneModule
15+ loading.cloneModule ||
16+ loading.getClusterStatus ||
17+ clusterStatus.length == disabledNodes.length
1518 "
1619 >
1720 <template slot="title">{{
2730 : $t("software_center.move_app_description", { instanceLabel })
2831 }}
2932 </div >
33+ <NsInlineNotification
34+ v-if =" error.getClusterStatus"
35+ kind =" error"
36+ :title =" $t('action.get-cluster-status')"
37+ :description =" error.getClusterStatus"
38+ :showCloseButton =" false"
39+ />
3040 <div >{{ $t("software_center.select_destination_node") }}:</div >
3141 <NsInlineNotification
32- v-if =" clusterNodes.length == disabledNodes.length"
42+ v-if ="
43+ clusterStatus.length == disabledNodes.length &&
44+ !loading.getClusterStatus
45+ "
3346 kind =" info"
3447 :title ="
3548 isClone
4255 class =" mg-top-xlg"
4356 @selectNode =" onSelectNode"
4457 :disabledNodes =" disabledNodes"
58+ :loading =" loading.getClusterStatus"
4559 >
4660 <template v-for =" (nodeMessages , nodeId ) in nodesInfo " >
4761 <template :slot =" ` node-${nodeId } ` " >
@@ -109,11 +123,14 @@ export default {
109123 data () {
110124 return {
111125 selectedNode: null ,
126+ clusterStatus: [],
112127 loading: {
113128 cloneModule: false ,
129+ getClusterStatus: true ,
114130 },
115131 error: {
116132 cloneModule: " " ,
133+ getClusterStatus: " " ,
117134 },
118135 };
119136 },
@@ -173,6 +190,15 @@ export default {
173190 }
174191 nodesInfo[nodeInfo .node_id ] = nodeMessages;
175192 }
193+ // Add offline nodes message
194+ for (const node of this .clusterStatus ) {
195+ if (! node .online ) {
196+ if (! nodesInfo[node .id ]) {
197+ nodesInfo[node .id ] = [];
198+ }
199+ nodesInfo[node .id ].push (this .$t (" software_center.node_offline" ));
200+ }
201+ }
176202 }
177203 return nodesInfo;
178204 },
@@ -181,20 +207,92 @@ export default {
181207 return [];
182208 }
183209
210+ // Get non-eligible nodes from install_destinations
184211 const ineligibleNodes = this .app .install_destinations
185212 .filter ((nodeInfo ) => ! nodeInfo .eligible )
186213 .map ((nodeInfo ) => nodeInfo .node_id );
187214
215+ // Get offline nodes from clusterStatus
216+ const offlineNodeIds = this .clusterStatus
217+ .filter ((node ) => ! node .online )
218+ .map ((node ) => node .id );
219+
188220 if (this .isClone ) {
189- // cloning app
190- return ineligibleNodes;
221+ // cloning app: combine ineligible and offline nodes
222+ return [ ... new Set ([ ... ineligibleNodes, ... offlineNodeIds])] ;
191223 } else {
192- // moving app: add current node to ineligible nodes and remove possible duplicates
193- return [... new Set (ineligibleNodes .concat (this .installationNode ))];
224+ // moving app: add current node to ineligible/offline nodes and remove possible duplicates
225+ return [
226+ ... new Set ([
227+ ... ineligibleNodes .concat (this .installationNode ),
228+ ... offlineNodeIds,
229+ ]),
230+ ];
194231 }
195232 },
196233 },
197234 methods: {
235+ onModalShown () {
236+ // reset state before showing modal
237+ // Force selection to node 1 if only available
238+ if (this .clusterNodes .length == 1 ) {
239+ this .selectedNode = this .clusterNodes [0 ];
240+ this .clusterNodes [0 ].selected = true ;
241+ } else {
242+ this .selectedNode = null ;
243+ }
244+ this .clusterStatus = [];
245+ this .getClusterStatus ();
246+ },
247+ onModalHidden () {
248+ // reset state
249+ this .$emit (" hide" );
250+ this .clearErrors ();
251+ this .selectedNode = null ;
252+ this .clusterStatus = [];
253+ this .loading .getClusterStatus = true ;
254+ },
255+ async getClusterStatus () {
256+ this .error .getClusterStatus = " " ;
257+ const taskAction = " get-cluster-status" ;
258+
259+ // register to task error
260+ this .$root .$off (taskAction + " -aborted" );
261+ this .$root .$once (taskAction + " -aborted" , this .getClusterStatusAborted );
262+
263+ // register to task completion
264+ this .$root .$off (taskAction + " -completed" );
265+ this .$root .$once (
266+ taskAction + " -completed" ,
267+ this .getClusterStatusCompleted
268+ );
269+
270+ const res = await to (
271+ this .createClusterTask ({
272+ action: taskAction,
273+ extra: {
274+ title: this .$t (" action." + taskAction),
275+ isNotificationHidden: true ,
276+ },
277+ })
278+ );
279+ const err = res[0 ];
280+
281+ if (err) {
282+ console .error (` error creating task ${ taskAction} ` , err);
283+ this .error .getClusterStatus = this .getErrorMessage (err);
284+ return ;
285+ }
286+ },
287+ getClusterStatusAborted (taskResult , taskContext ) {
288+ console .error (` ${ taskContext .action } aborted` , taskResult);
289+ this .error .getClusterStatus = this .$t (" error.generic_error" );
290+ this .loading .getClusterStatus = false ;
291+ },
292+ getClusterStatusCompleted (taskContext , taskResult ) {
293+ this .clusterStatus = taskResult .output .nodes ;
294+ this .loading .getClusterStatus = false ;
295+ },
198296 async cloneOrMove () {
199297 this .loading .cloneModule = true ;
200298 const taskAction = " clone-module" ;
0 commit comments