feat: show notification if there is VM pending restart (#700)

* feat: show notification if there is VM pending restart

Signed-off-by: Andy Lee <andy.lee@suse.com>

* refactor: update based on comments

Signed-off-by: Andy Lee <andy.lee@suse.com>

* refactor: calculate count from vm names

Signed-off-by: Andy Lee <andy.lee@suse.com>

---------

Signed-off-by: Andy Lee <andy.lee@suse.com>
This commit is contained in:
Andy Lee 2026-02-03 16:21:20 +08:00 committed by GitHub
parent 8b9b5b41b7
commit 2db7ee7397
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 64 additions and 7 deletions

View File

@ -190,12 +190,16 @@ harvester:
title: Restart Virtual Machine title: Restart Virtual Machine
tip: Restart the virtual machine for configuration changes to take effect. tip: Restart the virtual machine for configuration changes to take effect.
cancel: Save cancel: Save
notification: notification:
title: title:
succeed: Succeed succeed: Succeed
info: Info info: Info
warning: Warning warning: Warning
error: Error error: Error
restartRequired:
title: '{count} {count, plural, =1 {Virtual Machine is} other {Virtual Machines are}} Pending Restart'
message: 'Please restart { vmNames } to apply updated configurations'
action: action:
createVM: Create Virtual Machine createVM: Create Virtual Machine
start: Start start: Start

View File

@ -115,6 +115,7 @@ export default {
allVMIs: [], allVMIs: [],
allNodeNetworks: [], allNodeNetworks: [],
allClusterNetworks: [], allClusterNetworks: [],
restartNotificationDisplayed: false,
HCI HCI
}; };
}, },
@ -174,6 +175,48 @@ export default {
this['allVMIs'] = vmis; this['allVMIs'] = vmis;
}, },
beforeUnmount() {
// clear restart message before component unmount
this.$store.dispatch('growl/clear');
},
watch: {
allVMs: {
handler(neu) {
const vmNames = [];
neu.forEach((vm) => {
if (vm.isRestartRequired) {
vmNames.push(vm.metadata.name);
}
});
const count = vmNames.length;
if ( count === 0 && this.restartNotificationDisplayed) {
this.restartNotificationDisplayed = false;
return;
}
if (count > 0) {
// clear old notification before showing new one
if (this.restartNotificationDisplayed) {
this.$store.dispatch('growl/clear');
}
}
if (count > 0 && vmNames.length > 0) {
this.$store.dispatch('growl/warning', {
title: this.t('harvester.notification.restartRequired.title', { count }),
message: this.t('harvester.notification.restartRequired.message', { vmNames: vmNames.join(', ') }),
timeout: 10000,
}, { root: true });
this.restartNotificationDisplayed = true;
}
},
deep: true,
}
},
methods: { methods: {
lockIconTooltipMessage(row) { lockIconTooltipMessage(row) {
const message = ''; const message = '';
@ -243,6 +286,12 @@ export default {
</div> </div>
</template> </template>
<style lang="scss">
.growl-container {
z-index: 56 !important; // set to be lower than the vm action menu (z-index: 57)
}
</style>
<style lang="scss" scoped> <style lang="scss" scoped>
.state { .state {
display: flex; display: flex;

View File

@ -1180,11 +1180,15 @@ export default class VirtVm extends HarvesterResource {
); );
} }
get stateDescription() { get isRestartRequired() {
const conditions = get(this, 'status.conditions'); const conditions = get(this, 'status.conditions');
const restartRequired = findBy(conditions, 'type', 'RestartRequired'); const restartRequired = findBy(conditions, 'type', 'RestartRequired');
if (restartRequired && restartRequired.status === 'True') { return restartRequired && restartRequired.status === 'True';
}
get stateDescription() {
if (this.isRestartRequired) {
return this.t('harvester.virtualMachine.hotplug.restartVMMessage'); return this.t('harvester.virtualMachine.hotplug.restartVMMessage');
} }