diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 529929eb524..c87f49ab590 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -511,6 +511,7 @@ "label.capacitybytes": "Capacity bytes", "label.capacityiops": "IOPS total", "label.category": "Category", +"label.categoryname": "Category name", "label.certchain": "Chain", "label.certificate": "Certificate", "label.certificate.chain": "Certificate chain", @@ -1165,6 +1166,10 @@ "label.guest.os.category": "Guest OS Category", "label.guest.os.categories": "Guest OS Categories", "label.guest.os.hypervisor.mappings": "Guest OS mappings", +"label.service.offering.categories": "Service Offering Categories", +"label.add.service.offering.category": "Add Service Offering Category", +"label.action.delete.service.offering.category": "Delete Service Offering Category", +"message.action.delete.service.offering.category": "Please confirm that you want to delete this service offering category", "label.guest.start.ip": "Guest start IP", "label.guest.traffic": "Guest traffic", "label.guestcidraddress": "Guest CIDR", diff --git a/ui/src/components/view/ListView.vue b/ui/src/components/view/ListView.vue index 47aa3d2ddef..7ddaa79bdc3 100644 --- a/ui/src/components/view/ListView.vue +++ b/ui/src/components/view/ListView.vue @@ -1027,6 +1027,9 @@ + + {{ text }} + @@ -1309,6 +1312,9 @@ export default { case 'guestoscategory': apiCommand = 'updateOsCategory' break + case 'serviceofferingcategory': + apiCommand = 'updateServiceOfferingCategory' + break } return apiCommand }, @@ -1322,7 +1328,7 @@ export default { return new Promise((resolve, reject) => { postAPI(apiCommand, { id, - sortKey: index + sortkey: index }).then((response) => { resolve(response) }).catch((reason) => { diff --git a/ui/src/config/section/config.js b/ui/src/config/section/config.js index e190515855e..0906765331c 100644 --- a/ui/src/config/section/config.js +++ b/ui/src/config/section/config.js @@ -202,6 +202,40 @@ export default { } ] }, + { + name: 'serviceofferingcategory', + title: 'label.service.offering.categories', + icon: 'shopping-outlined', + permission: ['listServiceOfferingCategories'], + columns: ['name', 'order'], + details: ['name', 'id'], + actions: [ + { + api: 'createServiceOfferingCategory', + icon: 'plus-outlined', + label: 'label.add.service.offering.category', + listView: true, + dataView: false, + args: ['name'] + }, + { + api: 'updateServiceOfferingCategory', + icon: 'edit-outlined', + label: 'label.edit', + dataView: true, + popup: true, + args: ['name'] + }, + { + api: 'deleteServiceOfferingCategory', + icon: 'delete-outlined', + label: 'label.action.delete.service.offering.category', + message: 'message.action.delete.service.offering.category', + dataView: true, + popup: true + } + ] + }, { name: 'guestos', title: 'label.guest.os', diff --git a/ui/src/config/section/offering.js b/ui/src/config/section/offering.js index 4a32619b8c2..9b890c2be28 100644 --- a/ui/src/config/section/offering.js +++ b/ui/src/config/section/offering.js @@ -30,7 +30,7 @@ export default { docHelp: 'adminguide/service_offerings.html#compute-and-disk-service-offerings', icon: 'cloud-outlined', permission: ['listServiceOfferings'], - searchFilters: ['name', 'gpuenabled', 'zoneid', 'domainid', 'cpunumber', 'cpuspeed', 'memory'], + searchFilters: ['name', 'gpuenabled', 'zoneid', 'domainid', 'cpunumber', 'cpuspeed', 'memory', 'category'], params: () => { var params = {} if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) { @@ -39,9 +39,9 @@ export default { return params }, filters: ['active', 'inactive'], - columns: ['name', 'displaytext', 'state', 'cpunumber', 'cpuspeed', 'memory', 'gpu', 'domain', 'zone', 'order'], + columns: ['name', 'displaytext', 'state', 'cpunumber', 'cpuspeed', 'memory', 'gpu', 'category', 'domain', 'zone', 'order'], details: () => { - var fields = ['name', 'id', 'displaytext', 'offerha', 'provisioningtype', 'storagetype', 'iscustomized', 'iscustomizediops', 'limitcpuuse', 'cpunumber', 'cpuspeed', 'memory', 'hosttags', 'tags', 'storageaccessgroups', 'storagetags', 'domain', 'zone', 'created', 'dynamicscalingenabled', 'diskofferingstrictness', 'encryptroot', 'purgeresources', 'leaseduration', 'gpucardid', 'gpucardname', 'vgpuprofileid', 'vgpuprofilename', 'gpucount', 'gpudisplay', 'leaseexpiryaction', 'externaldetails'] + var fields = ['name', 'id', 'displaytext', 'offerha', 'provisioningtype', 'storagetype', 'iscustomized', 'iscustomizediops', 'limitcpuuse', 'cpunumber', 'cpuspeed', 'memory', 'hosttags', 'tags', 'storageaccessgroups', 'storagetags', 'domain', 'zone', 'created', 'dynamicscalingenabled', 'diskofferingstrictness', 'encryptroot', 'purgeresources', 'leaseduration', 'gpucardid', 'gpucardname', 'vgpuprofileid', 'vgpuprofilename', 'gpucount', 'gpudisplay', 'leaseexpiryaction', 'externaldetails', 'categoryid', 'category'] if (store.getters.apis.createServiceOffering && store.getters.apis.createServiceOffering.params.filter(x => x.name === 'storagepolicy').length > 0) { fields.splice(6, 0, 'vspherestoragepolicy') @@ -96,8 +96,11 @@ export default { label: 'label.edit', docHelp: 'adminguide/service_offerings.html#modifying-or-deleting-a-service-offering', dataView: true, - args: ['name', 'displaytext', 'storagetags', 'hosttags', 'externaldetails'], + args: ['name', 'displaytext', 'categoryid', 'storagetags', 'hosttags', 'externaldetails'], mapping: { + categoryid: { + api: 'listServiceOfferingCategories' + }, externaldetails: { transformedvalue: (record) => { return getFilteredExternalDetails(record.serviceofferingdetails) } } diff --git a/ui/src/views/compute/DeployVM.vue b/ui/src/views/compute/DeployVM.vue index e13c9bc17b2..579a1a90e2e 100644 --- a/ui/src/views/compute/DeployVM.vue +++ b/ui/src/views/compute/DeployVM.vue @@ -261,8 +261,11 @@ :minimum-cpunumber="templateConfigurationExists && selectedTemplateConfiguration && selectedTemplateConfiguration.cpunumber ? selectedTemplateConfiguration.cpunumber : 0" :minimum-cpuspeed="templateConfigurationExists && selectedTemplateConfiguration && selectedTemplateConfiguration.cpuspeed ? selectedTemplateConfiguration.cpuspeed : 0" :minimum-memory="templateConfigurationExists && selectedTemplateConfiguration && selectedTemplateConfiguration.memory ? selectedTemplateConfiguration.memory : 0" + :service-offering-categories="options.serviceOfferingCategories" + :selected-service-offering-category-id="selectedServiceOfferingCategoryId" @select-compute-item="($event) => updateComputeOffering($event)" @handle-search-filter="($event) => handleSearchFilter('serviceOfferings', $event)" + @service-offering-category-change="($event) => handleServiceOfferingCategoryChange($event)" > { + getAPI('listServiceOfferingCategories').then(json => { + const categories = json.listserviceofferingcategoriesresponse.serviceofferingcategory || [] + this.options.serviceOfferingCategories = [ + { + id: '-1', + name: this.$t('label.all') + }, + ...categories + ] + resolve() + }).catch(error => { + console.error('Error fetching service offering categories:', error) + this.options.serviceOfferingCategories = [ + { + id: '-1', + name: this.$t('label.all') + } + ] + reject(error) + }).finally(() => { + this.loading.serviceOfferingCategories = false + }) + }) + }, + handleServiceOfferingCategoryChange (categoryId) { + this.selectedServiceOfferingCategoryId = categoryId + const params = { + page: 1, + pageSize: 10 + } + if (categoryId && categoryId !== '-1') { + params.serviceofferingcategoryid = categoryId + } else { + params.serviceofferingcategoryid = null + } + this.handleSearchFilter('serviceOfferings', params) + }, changeArchitecture (arch) { this.selectedArchitecture = arch this.updateImages() @@ -3027,6 +3070,8 @@ export default { if (this.isModernImageSelection && guestOsFetch) { await guestOsFetch } + // Load service offering categories + this.fetchServiceOfferingCategories() this.fetchImages() this.updateTemplateKey() this.formModel = toRaw(this.form) diff --git a/ui/src/views/compute/wizard/ComputeOfferingSelection.vue b/ui/src/views/compute/wizard/ComputeOfferingSelection.vue index eb6e228a93f..4436c7b749e 100644 --- a/ui/src/views/compute/wizard/ComputeOfferingSelection.vue +++ b/ui/src/views/compute/wizard/ComputeOfferingSelection.vue @@ -17,6 +17,25 @@ + + + + {{ item.name }} + + + {{ $t('label.show.only.gpu.enabled.offerings') }} @@ -94,8 +113,13 @@