Skip to content
Open
Show file tree
Hide file tree
Changes from all 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