Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ui/public/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,5 +116,6 @@
"message": "🤔 <strong>Sample Announcement</strong>: New Feature Available: Check out our latest dashboard improvements! <a href='/features'>Learn more</a>",
"startDate": "2025-06-01T00:00:00Z",
"endDate": "2025-07-16T00:00:00Z"
}
},
"advisoriesDisabled": false
}
10 changes: 10 additions & 0 deletions ui/public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1149,7 +1149,12 @@
"label.go.back": "Go back",
"label.go.to.compute.offerings": "Go to Compute Offerings",
"label.go.to.global.settings": "Go to Global Settings",
"label.go.to.networks": "Go to Networks",
"label.go.to.templates": "Go to Templates",
"label.go.to.isos": "Go to ISOs",
"label.go.to.volumes": "Go to Volumes",
"label.go.to.kubernetes.isos": "Go to Kubernetes ISOs",
"label.go.to.snapshots": "Go to Volume Snapshots",
"label.gpu": "GPU",
"label.gpucardid": "GPU Card",
"label.gpucardname": "GPU Card",
Expand Down Expand Up @@ -3075,9 +3080,14 @@
"message.add.ip.v6.firewall.rule.failed": "Failed to add IPv6 firewall rule",
"message.add.ip.v6.firewall.rule.processing": "Adding IPv6 firewall rule...",
"message.add.ip.v6.firewall.rule.success": "Added IPv6 firewall rule",
"message.advisory.instance.compute.offering.missing": "No compute offering found for deploying an Instance.",
"message.advisory.instance.image.missing": "No suitable Template/ISO/Volume/Volume Snapshot found for deploying an Instance. Please make sure you have a Template/ISO/Volume/Snapshot ready for Instance deployment.",
"message.advisory.instance.network.missing": "No suitable Network found for deploying an Instance. Please create a Network to be used by the Instance.",
"message.advisory.cks.endpoint.url.not.configured": "Endpoint URL which will be used by Kubernetes clusters is not configured correctly",
"message.advisory.cks.min.offering": "No suitable Compute Offering found for Kubernetes cluster nodes with minimum required resources (2 vCPU, 2 GB RAM)",
"message.advisory.cks.version.check": "No Kubernetes version found that can be used to deploy a Kubernetes cluster",
"message.advisory.vnf.appliance.compute.offering.missing": "No compute offering found for deploying a VNF appliance.",
"message.advisory.vnf.appliance.template.missing": "No VNF Template found for deploying a VNF appliance. Please make sure you have a VNF Template for appliance deployment.",
"message.redeliver.webhook.delivery": "Redeliver this Webhook delivery",
"message.remove.ip.v6.firewall.rule.failed": "Failed to remove IPv6 firewall rule",
"message.remove.ip.v6.firewall.rule.processing": "Removing IPv6 firewall rule...",
Expand Down
6 changes: 4 additions & 2 deletions ui/src/config/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ import tools from '@/config/section/tools'
import quota from '@/config/section/plugin/quota'
import cloudian from '@/config/section/plugin/cloudian'

const isAdvisoriesDisabled = () => vueProps.$config.advisoriesDisabled ?? false

function generateRouterMap (section) {
var map = {
name: section.name,
Expand Down Expand Up @@ -81,7 +83,7 @@ function generateRouterMap (section) {
filters: child.filters,
params: child.params ? child.params : {},
columns: child.columns,
advisories: !vueProps.$config.advisoriesDisabled ? child.advisories : undefined,
advisories: !isAdvisoriesDisabled() ? child.advisories : undefined,
details: child.details,
searchFilters: child.searchFilters,
related: child.related,
Expand Down Expand Up @@ -181,7 +183,7 @@ function generateRouterMap (section) {
map.meta.columns = section.columns
}

if (!vueProps.$config.advisoriesDisabled && section.advisories) {
if (!isAdvisoriesDisabled() && section.advisories) {
map.meta.advisories = section.advisories
}

Expand Down
149 changes: 120 additions & 29 deletions ui/src/config/section/compute.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { isZoneCreated } from '@/utils/zone'
import { getAPI, postAPI, getBaseUrl } from '@/api'
import { getLatestKubernetesIsoParams } from '@/utils/acsrepo'
import kubernetesIcon from '@/assets/icons/kubernetes.svg?inline'
import { hasNoItems } from '@/utils/advisory'

export default {
name: 'compute',
Expand Down Expand Up @@ -100,6 +101,119 @@ export default {
tabs: [{
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/InstanceTab.vue')))
}],
advisories: [
{
id: 'instance-image-check',
severity: 'warning',
message: 'message.advisory.instance.image.missing',
condition: async (store) => {
return await hasNoItems(store,
'listTemplates',
{ isvnf: false, templatefilter: 'executable', isready: true }) &&
await hasNoItems(store, 'listIsos', { isofilter: 'executable', bootable: true, isready: true }) &&
await hasNoItems(store, 'listVolumes', { state: 'Ready' }) &&
await hasNoItems(store, 'listSnapshots')
},
actions: [
{
label: 'label.register.template',
show: (store) => { return ('registerTemplate' in store.getters.apis) },
primary: true,
run: (store, router) => {
router.push({ name: 'template', query: { action: 'registerTemplate' } })
return false
}
},
{
label: 'label.go.to.templates',
show: (store) => { return ('listTemplates' in store.getters.apis) },
run: (store, router) => {
router.push({ name: 'template' })
return false
}
},
{
label: 'label.go.to.isos',
show: (store) => { return ('listIsos' in store.getters.apis) },
run: (store, router) => {
router.push({ name: 'iso' })
return false
}
},
{
label: 'label.go.to.volumes',
show: (store) => { return ('listVolumes' in store.getters.apis) },
run: (store, router) => {
router.push({ name: 'volume' })
return false
}
},
{
label: 'label.go.to.snapshots',
show: (store) => { return ('listSnapshots' in store.getters.apis) },
run: (store, router) => {
router.push({ name: 'snapshot' })
return false
}
}
]
},
{
id: 'instance-compute-offering-check',
severity: 'warning',
message: 'message.advisory.instance.compute.offering.missing',
condition: async (store) => {
return await hasNoItems(store, 'listServiceOfferings', { issystem: false })
},
actions: [
{
label: 'label.add.compute.offering',
show: (store) => { return ('createServiceOffering' in store.getters.apis) },
primary: true,
run: (store, router) => {
router.push({ name: 'computeoffering', query: { action: 'createServiceOffering' } })
return false
}
},
{
label: 'label.go.to.compute.offerings',
show: (store) => { return ('listServiceOfferings' in store.getters.apis) },
run: (store, router) => {
router.push({ name: 'computeoffering' })
return false
}
}
]
},
{
id: 'instance-network-check',
severity: 'warning',
message: 'message.advisory.instance.network.missing',
dismissOnConditionFail: true,
condition: async (store) => {
return await hasNoItems(store, 'listNetworks')
},
actions: [
{
label: 'label.add.network',
show: (store) => { return ('createNetwork' in store.getters.apis) },
primary: true,
run: (store, router) => {
router.push({ name: 'guestnetwork', query: { action: 'createNetwork' } })
return false
}
},
{
label: 'label.go.to.networks',
show: (store) => { return ('listNetworks' in store.getters.apis) },
run: (store, router) => {
router.push({ name: 'guestnetworks' })
return false
}
}
]
}
],
actions: [
{
api: 'deployVirtualMachine',
Expand Down Expand Up @@ -589,23 +703,12 @@ export default {
id: 'cks-min-offering',
severity: 'warning',
message: 'message.advisory.cks.min.offering',
docsHelp: 'plugins/cloudstack-kubernetes-service.html',
dismissOnConditionFail: true,
condition: async (store) => {
if (!('listServiceOfferings' in store.getters.apis)) {
return false
}
const params = {
cpunumber: 2,
memory: 2048,
issystem: false
}
try {
const json = await getAPI('listServiceOfferings', params)
const offerings = json?.listserviceofferingsresponse?.serviceoffering || []
return !offerings.some(o => !o.iscustomized)
} catch (error) {}
return false
return await hasNoItems(store,
'listServiceOfferings',
{ cpunumber: 2, memory: 2048, issystem: false },
o => !o.iscustomized
)
},
actions: [
{
Expand Down Expand Up @@ -647,19 +750,8 @@ export default {
id: 'cks-version-check',
severity: 'warning',
message: 'message.advisory.cks.version.check',
docsHelp: 'plugins/cloudstack-kubernetes-service.html',
dismissOnConditionFail: true,
condition: async (store) => {
const api = 'listKubernetesSupportedVersions'
if (!(api in store.getters.apis)) {
return false
}
try {
const json = await getAPI(api, {})
const versions = json?.listkubernetessupportedversionsresponse?.kubernetessupportedversion || []
return versions.length === 0
} catch (error) {}
return false
return await hasNoItems(store, 'listKubernetesSupportedVersions')
},
actions: [
{
Expand Down Expand Up @@ -702,7 +794,6 @@ export default {
id: 'cks-endpoint-url',
severity: 'warning',
message: 'message.advisory.cks.endpoint.url.not.configured',
docsHelp: 'plugins/cloudstack-kubernetes-service.html',
dismissOnConditionFail: true,
condition: async (store) => {
if (!['Admin'].includes(store.getters.userInfo.roletype)) {
Expand Down
61 changes: 61 additions & 0 deletions ui/src/config/section/network.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import store from '@/store'
import tungsten from '@/assets/icons/tungsten.svg?inline'
import { isAdmin } from '@/role'
import { isZoneCreated } from '@/utils/zone'
import { hasNoItems } from '@/utils/advisory'

export default {
name: 'network',
Expand Down Expand Up @@ -397,6 +398,66 @@ export default {
tabs: [{
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/InstanceTab.vue')))
}],
advisories: [
{
id: 'vnfapp-image-check',
severity: 'warning',
message: 'message.advisory.vnf.appliance.template.missing',
condition: async (store) => {
return await hasNoItems(store,
'listVnfTemplates',
{ isvnf: true, templatefilter: 'executable', isready: true })
},
actions: [
{
label: 'label.register.template',
show: (store) => { return ('registerTemplate' in store.getters.apis) },
primary: true,
run: (store, router) => {
router.push({ name: 'template', query: { action: 'registerTemplate' } })
return false
}
},
{
label: 'label.go.to.templates',
show: (store) => { return ('listTemplates' in store.getters.apis) },
primary: false,
run: (store, router) => {
router.push({ name: 'template' })
return false
}
}
]
},
{
id: 'vnfapp-compute-offering-check',
severity: 'warning',
message: 'message.advisory.vnf.appliance.compute.offering.missing',
condition: async (store) => {
return await hasNoItems(store, 'listServiceOfferings', { issystem: false })
},
actions: [
{
label: 'label.add.compute.offering',
show: (store) => { return ('createServiceOffering' in store.getters.apis) },
primary: true,
run: (store, router) => {
router.push({ name: 'computeoffering', query: { action: 'createServiceOffering' } })
return false
}
},
{
label: 'label.go.to.compute.offerings',
show: (store) => { return ('listServiceOfferings' in store.getters.apis) },
primary: false,
run: (store, router) => {
router.push({ name: 'computeoffering' })
return false
}
}
]
}
],
actions: [
{
api: 'deployVnfAppliance',
Expand Down
Loading
Loading