Skip to content

Commit

Permalink
fix(ui): limit clone/move app to eligible nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
andre8244 committed Dec 17, 2024
1 parent 3904ffb commit 0b21903
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 44 deletions.
6 changes: 5 additions & 1 deletion core/ui/public/i18n/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -945,7 +945,11 @@
"reason_max_per_node_limit": "Limit of {param} instance reached | Limit of {param} instances reached",
"reason_min_core_requirement": "Core version is lower than {param}",
"search_core_apps": "Search core apps",
"cannot_install_app_on_node": "Cannot install {app} {version} on {node}"
"cannot_install_app_on_node": "Cannot install {app} {version} on {node}",
"no_node_eligible_for_app_installation": "No node is eligible for app installation",
"no_node_eligible_for_instance_cloning": "No node is eligible for instance cloning",
"no_node_eligible_for_instance_migration": "No node is eligible for instance migration"

},
"system_logs": {
"title": "System logs",
Expand Down
66 changes: 27 additions & 39 deletions core/ui/src/components/nodes/NodeSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,33 @@
-->
<template>
<div class="node-selector">
<cv-grid class="mg-bottom-md no-padding">
<cv-row>
<cv-column
v-for="(node, index) in internalNodes"
:key="index"
:md="4"
:max="4"
>
<NsTile
:light="true"
kind="selectable"
v-model="node.selected"
value="nodeValue"
:footerIcon="Chip20"
@click="deselectOtherNodes(node)"
class="min-height-card"
:disabled="disabledNodes.includes(node.id)"
>
<h6>
<span v-if="node.ui_name">
{{ node.ui_name }} ({{ $t("common.node") }} {{ node.id }})
</span>
<span v-else> {{ $t("common.node") }} {{ node.id }} </span>
</h6>
<div v-if="$slots[`node-${node.id}`]" class="mg-top-md">
<slot :name="`node-${node.id}`"></slot>
</div>
</NsTile>
</cv-column>
</cv-row>
</cv-grid>
<!-- card grid -->
<div
class="card-grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 3xl:grid-cols-4"
>
<NsTile
v-for="node in internalNodes"
:key="node.id"
:light="true"
kind="selectable"
v-model="node.selected"
value="nodeValue"
:footerIcon="Chip20"
@click="deselectOtherNodes(node)"
class="min-height-card"
:disabled="disabledNodes.includes(node.id)"
>
<h6>
<span v-if="node.ui_name">
{{ node.ui_name }} ({{ $t("common.node") }} {{ node.id }})
</span>
<span v-else> {{ $t("common.node") }} {{ node.id }} </span>
</h6>
<div v-if="$slots[`node-${node.id}`]" class="mg-top-md">
<slot :name="`node-${node.id}`"></slot>
</div>
</NsTile>
</div>
</div>
</template>

Expand All @@ -47,14 +43,6 @@ export default {
name: "NodeSelector",
mixins: [UtilService, IconService],
props: {
extraInfoNode: {
type: Number,
default: 0,
},
extraInfoLabel: {
type: String,
default: "",
},
disabledNodes: {
type: Array,
default: () => [],
Expand Down
105 changes: 101 additions & 4 deletions core/ui/src/components/software-center/CloneOrMoveAppModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,32 @@
: $t("software_center.move_app_description", { instanceLabel })
}}
</div>
<div>{{ $t("software_center.select_destination_node") }}</div>
<div>{{ $t("software_center.select_destination_node") }}:</div>
<NsInlineNotification
v-if="clusterNodes.length == disabledNodes.length"
kind="info"
:title="
isClone
? $t('software_center.no_node_eligible_for_instance_cloning')
: $t('software_center.no_node_eligible_for_instance_migration')
"
:showCloseButton="false"
/>
<NodeSelector
class="mg-top-xlg"
@selectNode="onSelectNode"
:disabledNodes="isClone ? [] : [installationNode]"
:disabledNodes="disabledNodes"
>
<template :slot="`node-${installationNode}`">
<div>{{ $t("software_center.current_node") }}</div>
<template v-for="(nodeMessages, nodeId) in nodesInfo">
<template :slot="`node-${nodeId}`">
<div
v-for="(nodeMessage, index) in nodeMessages"
:key="index"
class="node-message"
>
{{ nodeMessage }}
</div>
</template>
</template>
</NodeSelector>
<NsInlineNotification
Expand Down Expand Up @@ -83,6 +101,10 @@ export default {
type: Number,
required: true,
},
app: {
type: Object,
default: null,
},
},
data() {
return {
Expand All @@ -104,6 +126,73 @@ export default {
return this.instanceId;
}
},
nodesInfo() {
if (!this.app) {
return {};
}
const nodesInfo = {};

if (this.app) {
for (const nodeInfo of this.app.install_destinations) {
const nodeMessages = [];

if (nodeInfo.node_id === this.installationNode) {
// show "Current node"
nodeMessages.push(this.$t("software_center.current_node"));
}

if (!nodeInfo.eligible) {
// show reason why node is not eligible
const rejectReason = nodeInfo.reject_reason;

if (rejectReason.message === "max_per_node_limit") {
const numMaxInstances = rejectReason.parameter;
nodeMessages.push(
this.$tc(
`software_center.reason_${rejectReason.message}`,
numMaxInstances,
{ param: numMaxInstances }
)
);
} else {
nodeMessages.push(
this.$t(`software_center.reason_${rejectReason.message}`, {
param: rejectReason.parameter,
})
);
}
} else if (nodeInfo.instances) {
// show number of instances installed
nodeMessages.push(
this.$tc(
"software_center.num_instances_installed",
nodeInfo.instances,
{ num: nodeInfo.instances }
)
);
}
nodesInfo[nodeInfo.node_id] = nodeMessages;
}
}
return nodesInfo;
},
disabledNodes() {
if (!this.app) {
return [];
}

const ineligibleNodes = this.app.install_destinations
.filter((nodeInfo) => !nodeInfo.eligible)
.map((nodeInfo) => nodeInfo.node_id);

if (this.isClone) {
// cloning app
return ineligibleNodes;
} else {
// moving app: add current node to ineligible nodes and remove possible duplicates
return [...new Set(ineligibleNodes.concat(this.installationNode))];
}
},
},
methods: {
async cloneOrMove() {
Expand Down Expand Up @@ -214,4 +303,12 @@ export default {

<style scoped lang="scss">
@import "../../styles/carbon-utils";

.node-message {
margin-bottom: $spacing-05;
}

.node-message:last-child {
margin-bottom: 0;
}
</style>
6 changes: 6 additions & 0 deletions core/ui/src/components/software-center/InstallAppModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@
})
}}
</div>
<NsInlineNotification
v-if="clusterNodes.length == disabledNodes.length"
kind="info"
:title="$t('software_center.no_node_eligible_for_app_installation')"
:showCloseButton="false"
/>
<NodeSelector
@selectNode="onSelectNode"
:disabledNodes="disabledNodes"
Expand Down
1 change: 1 addition & 0 deletions core/ui/src/views/SoftwareCenterAppInstances.vue
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@
:instanceId="cloneOrMove.instanceId"
:instanceUiName="cloneOrMove.instanceUiName"
:installationNode="cloneOrMove.installationNode"
:app="app"
@hide="cloneOrMove.isModalShown = false"
@cloneOrMoveCompleted="onCloneOrMoveCompleted"
/>
Expand Down

0 comments on commit 0b21903

Please sign in to comment.