diff options
| author | Nishant Tiwari <tiwari.nishant@ibm.com> | 2026-07-16 11:27:11 +0300 |
|---|---|---|
| committer | Nishant Tiwari <tiwari.nishant@ibm.com> | 2026-09-28 13:42:29 +0300 |
| commit | 85248e05cf5c44fc2a77135f829ae33b0d485e2f (patch) | |
| tree | 16378e768cfd50a88578c36ad28e6d9275dd8907 | |
| parent | 4628f24b336ea30b288a4b50d42c0e50d8d62869 (diff) | |
| download | webui-vue-master.tar.xz | |
Implemented the ability to view and edit the system asset tag directly
from the Overview page, including a modal dialog for editing, Vuex store
action for saving, and truncation in the app header.
Changes:
- Added ModalAssetTag.vue component with:
- Form input for editing the asset tag value
- Vuelidate validation requiring a non-empty tag
- Updated OverviewServer.vue to:
- Display asset tag in the system information section
- Add inline edit button using Carbon edit icon
- Dispatch saveAssetTag store action with toast feedback
- Refresh global system info after a successful save
- Added saveAssetTag action to SystemStore.js using PATCH
against the system path endpoint
- Updated AppHeader.vue to truncate asset tags longer than
30 characters with an ellipsis, preserving full value in
the title attribute for accessibility
- Added translation keys for asset tag label, modal title,
and success/error toast messages in en-US, ka-GE, and
ru-RU locale files
Testing:
- Verified asset tag displays correctly in system info section
- Verified modal opens, validates, and submits correctly
- Verified PATCH request updates asset tag on the server
- Validated success and error toast notifications display
- Confirmed long asset tags are truncated in the header
Change-Id: I6ac51dfc24b9d40986b74e9220cff955b029d659
Signed-off-by: Nishant Tiwari <tiwari.nishant@ibm.com>
| -rw-r--r-- | src/components/AppHeader/AppHeader.vue | 10 | ||||
| -rw-r--r-- | src/locales/en-US.json | 10 | ||||
| -rw-r--r-- | src/locales/ka-GE.json | 10 | ||||
| -rw-r--r-- | src/locales/ru-RU.json | 10 | ||||
| -rw-r--r-- | src/store/modules/HardwareStatus/SystemStore.js | 11 | ||||
| -rw-r--r-- | src/views/Overview/ModalAssetTag.vue | 126 | ||||
| -rw-r--r-- | src/views/Overview/OverviewServer.vue | 40 |
7 files changed, 212 insertions, 5 deletions
diff --git a/src/components/AppHeader/AppHeader.vue b/src/components/AppHeader/AppHeader.vue index 79e5c167b..0773cbe3d 100644 --- a/src/components/AppHeader/AppHeader.vue +++ b/src/components/AppHeader/AppHeader.vue @@ -39,7 +39,9 @@ </b-navbar-brand> <div v-if="isNavTagPresent" :key="routerKey" class="ps-2 nav-tags"> <span>|</span> - <span class="ps-3 asset-tag">{{ assetTag }}</span> + <span class="ps-3 asset-tag" :title="assetTag"> + {{ assetTag }} + </span> <span class="ps-3">{{ modelType }}</span> <span class="ps-3">{{ serialNumber }}</span> </div> @@ -367,6 +369,12 @@ export default { @include media-breakpoint-down($responsive-layout-bp) { @include visually-hidden; } + max-width: 50rem; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + display: inline-block; + vertical-align: middle; } } } diff --git a/src/locales/en-US.json b/src/locales/en-US.json index 99f4bd8b6..07b5a94ca 100644 --- a/src/locales/en-US.json +++ b/src/locales/en-US.json @@ -627,6 +627,7 @@ } }, "pageOverview": { + "assetTag": "Asset tag", "backupVersion": "Backup", "bmcTime": "BMC date and time", "criticalEvents": "Critical", @@ -654,7 +655,14 @@ "systemInformation": "System information", "total": "Total", "warningEvents": "Warning", - "viewMore": "View more" + "viewMore": "View more", + "modal": { + "editAssetTag": "Edit asset tag" + }, + "toast": { + "successSaveAssetTag": "Successfully updated asset tag.", + "errorSaveAssetTag": "Error updating asset tag." + } }, "pagePostCodeLogs": { "allExportFilePrefix": "All_POST_codes_log_", diff --git a/src/locales/ka-GE.json b/src/locales/ka-GE.json index 5ada54f16..1bab9028c 100644 --- a/src/locales/ka-GE.json +++ b/src/locales/ka-GE.json @@ -627,6 +627,7 @@ } }, "pageOverview": { + "assetTag": "აქტივის იდენტიფიკატორი", "backupVersion": "მარქაფი", "bmcTime": "BMC-ის დრო და თარიღი", "criticalEvents": "კრიტიკული", @@ -654,7 +655,14 @@ "systemInformation": "სისტემის ინფორმაცია", "total": "სულ", "warningEvents": "გაფრთხილება", - "viewMore": "მეტის ნახვა" + "viewMore": "მეტის ნახვა", + "modal": { + "editAssetTag": "აქტივის იდენტიფიკატორის რედაქტირება" + }, + "toast": { + "successSaveAssetTag": "აქტივის იდენტიფიკატორი წარმატებით განახლდა.", + "errorSaveAssetTag": "აქტივის იდენტიფიკატორის განახლების შეცდომა." + } }, "pagePostCodeLogs": { "allExportFilePrefix": "ყველა_POST_კოდის_ჟურნალი", diff --git a/src/locales/ru-RU.json b/src/locales/ru-RU.json index e9b049462..a22de1e9c 100644 --- a/src/locales/ru-RU.json +++ b/src/locales/ru-RU.json @@ -627,6 +627,7 @@ } }, "pageOverview": { + "assetTag": "Метка актива", "backupVersion": "Резервный", "bmcTime": "Дата и время BMC", "criticalEvents": "Критические", @@ -654,7 +655,14 @@ "systemInformation": "Информация о системе", "total": "Всего", "warningEvents": "Предупреждения", - "viewMore": "Подробнее" + "viewMore": "Подробнее", + "modal": { + "editAssetTag": "Изменить метку актива" + }, + "toast": { + "successSaveAssetTag": "Метка актива успешно обновлена.", + "errorSaveAssetTag": "Ошибка при обновлении метки актива." + } }, "pagePostCodeLogs": { "allExportFilePrefix": "Лог_всех_POST_кодов_", diff --git a/src/store/modules/HardwareStatus/SystemStore.js b/src/store/modules/HardwareStatus/SystemStore.js index 7fbd6bc41..87bf4696c 100644 --- a/src/store/modules/HardwareStatus/SystemStore.js +++ b/src/store/modules/HardwareStatus/SystemStore.js @@ -74,6 +74,17 @@ const SystemStore = { } }); }, + async saveAssetTag(_, assetTag) { + return await api + .patch(`${await this.dispatch('global/getSystemPath')}`, assetTag) + .then(() => { + return i18n.global.t('pageOverview.toast.successSaveAssetTag'); + }) + .catch((error) => { + console.log(error); + throw new Error(i18n.global.t('pageOverview.toast.errorSaveAssetTag')); + }); + }, }, }; diff --git a/src/views/Overview/ModalAssetTag.vue b/src/views/Overview/ModalAssetTag.vue new file mode 100644 index 000000000..c73b5ba5e --- /dev/null +++ b/src/views/Overview/ModalAssetTag.vue @@ -0,0 +1,126 @@ +<template> + <b-modal + id="modal-asset-tag" + ref="modal" + :title="$t('pageOverview.modal.editAssetTag')" + @hidden="resetForm" + > + <b-form id="asset-settings" @submit.prevent="handleSubmit"> + <b-row> + <b-col sm="8"> + <b-form-group + :label="$t('pageOverview.assetTag')" + label-for="asset-tag" + > + <b-form-input + id="asset-tag" + v-model="form.assetTag" + type="text" + :state="getValidationState(v$.form.assetTag)" + @input="v$.form.assetTag.$touch()" + /> + <b-form-invalid-feedback role="alert"> + <template v-if="v$.form.assetTag.required.$invalid"> + {{ $t('global.form.fieldRequired') }} + </template> + </b-form-invalid-feedback> + </b-form-group> + </b-col> + </b-row> + </b-form> + <template #footer="{ cancel }"> + <b-button variant="secondary" @click="cancel()"> + {{ $t('global.action.cancel') }} + </b-button> + <b-button + form="asset-settings" + type="submit" + variant="primary" + @click="onOk" + > + {{ $t('global.action.save') }} + </b-button> + </template> + </b-modal> +</template> + +<script> +import VuelidateMixin from '@/components/Mixins/VuelidateMixin.js'; +import { useVuelidate } from '@vuelidate/core'; +import { required } from '@vuelidate/validators'; + +export default { + mixins: [VuelidateMixin], + props: { + modelValue: { + type: Boolean, + default: false, + }, + tag: { + type: String, + default: '', + }, + }, + emits: ['ok', 'hidden', 'update:modelValue'], + setup() { + return { + v$: useVuelidate(), + }; + }, + data() { + return { + form: { + assetTag: this.tag ? this.tag : '', + }, + }; + }, + watch: { + tag() { + this.form.assetTag = this.tag; + }, + modelValue: { + handler(newValue) { + if (newValue) { + this.$nextTick(() => { + this.$refs.modal?.show(); + }); + } + }, + immediate: true, + }, + }, + validations() { + return { + form: { + assetTag: { + required, + }, + }, + }; + }, + methods: { + handleSubmit() { + this.v$.$touch(); + if (this.v$.$invalid) return; + this.$emit('ok', { AssetTag: this.form.assetTag }); + this.closeModal(); + }, + closeModal() { + this.$nextTick(() => { + this.$refs.modal.hide(); + }); + }, + resetForm() { + this.form.assetTag = this.tag; + this.v$.$reset(); + this.$emit('update:modelValue', false); + this.$emit('hidden'); + }, + onOk(bvModalEvt) { + // prevent modal close + bvModalEvt.preventDefault(); + this.handleSubmit(); + }, + }, +}; +</script> diff --git a/src/views/Overview/OverviewServer.vue b/src/views/Overview/OverviewServer.vue index 044440a04..8d66da689 100644 --- a/src/views/Overview/OverviewServer.vue +++ b/src/views/Overview/OverviewServer.vue @@ -10,6 +10,13 @@ <dd>{{ dataFormatter(serverModel) }}</dd> <dt>{{ $t('pageOverview.serialNumber') }}</dt> <dd>{{ dataFormatter(serverSerialNumber) }}</dd> + <dt> + {{ $t('pageOverview.assetTag') }} + <b-button variant="link" class="p-1" @click="initAssetTagModal()"> + <icon-edit :title="$t('pageOverview.modal.editAssetTag')" /> + </b-button> + </dt> + <dd :title="assetTag">{{ dataFormatter(assetTag) }}</dd> </dl> </b-col> <b-col sm="6"> @@ -19,26 +26,41 @@ </dl> </b-col> </b-row> + <modal-asset-tag v-model="showAssetTagModal" :tag="assetTag" @ok="saveAssetTag" /> </overview-card> </template> <script> import OverviewCard from './OverviewCard'; import DataFormatterMixin from '@/components/Mixins/DataFormatterMixin'; +import BVToastMixin from '@/components/Mixins/BVToastMixin'; +import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin'; import { mapState } from 'vuex'; +import ModalAssetTag from './ModalAssetTag.vue'; +import IconEdit from '@carbon/icons-vue/es/edit/16'; export default { name: 'Server', components: { OverviewCard, + IconEdit, + ModalAssetTag, + }, + mixins: [DataFormatterMixin, BVToastMixin, LoadingBarMixin], + data() { + return { + showAssetTagModal: false, + }; }, - mixins: [DataFormatterMixin], computed: { ...mapState({ server: (state) => state.system.systems[0], serverModel() { return this.server?.model; }, + assetTag() { + return this.$store.getters['global/assetTag']; + }, serverSerialNumber() { return this.server?.serialNumber; }, @@ -52,5 +74,21 @@ export default { this.$eventBus.$emit('overview-server-complete'); }); }, + methods: { + initAssetTagModal() { + this.showAssetTagModal = true; + }, + saveAssetTag(modalFormData) { + this.startLoader(); + this.$store + .dispatch('system/saveAssetTag', modalFormData) + .then((message) => { + this.$store.dispatch('global/getSystemInfo'); + this.successToast(message); + }) + .catch(({ message }) => this.errorToast(message)) + .finally(() => this.endLoader()); + }, + } }; </script> |
