diff --git a/magefiles/targets/generate_proto.go b/magefiles/targets/generate_proto.go index ef31acae3c..042de9caa1 100644 --- a/magefiles/targets/generate_proto.go +++ b/magefiles/targets/generate_proto.go @@ -110,7 +110,7 @@ func (Generate) ProtobufTypescript() error { }, }), external.NewGenerator([]string{"./web/service-generator/generate"}, external.GeneratorOptions{ - Opt: "target=ts", + Opt: "target=ts,import_extension=none", }), }, targets...) if err != nil { diff --git a/web/package.json b/web/package.json index 82249bf6a0..174f0c2a69 100644 --- a/web/package.json +++ b/web/package.json @@ -12,6 +12,7 @@ "chartjs-plugin-annotation": "^2.0.1", "core-js": "3.21.1", "css-loader": "4.3.0", + "dayjs": "^1.8.16", "express": "^4.18.2", "http-proxy-middleware": "^2.0.6", "js-yaml": "4.1.0", @@ -19,8 +20,7 @@ "marked": "^4.3.0", "unique-names-generator": "^4.7.1", "vue-chartjs": "^4.1.1", - "vue-fragment": "^1.6.0", - "dayjs": "^1.8.16" + "vue-fragment": "^1.6.0" }, "resolutions": { "**/webpack": "4", @@ -37,5 +37,8 @@ "docker": "docker build -t opni-ui -f ./Dockerfile .", "build": "IS_STANDALONE=true ./node_modules/.bin/vue-cli-service build", "start": "node prod.js" + }, + "devDependencies": { + "@bufbuild/protobuf": "1.2.1" } -} \ No newline at end of file +} diff --git a/web/pkg/opni/api/opni.ts b/web/pkg/opni/api/opni.ts new file mode 100644 index 0000000000..950b1a8cb0 --- /dev/null +++ b/web/pkg/opni/api/opni.ts @@ -0,0 +1,13 @@ +import * as CortexOpsService from '@pkg/opni/generated/github.com/rancher/opni/plugins/metrics/apis/cortexops/cortexops_svc'; +import * as CortexOpsTypes from '@pkg/opni/generated/github.com/rancher/opni/plugins/metrics/apis/cortexops/cortexops_pb'; +import * as StorageTypes from '@pkg/opni/generated/github.com/rancher/opni/internal/cortex/config/storage/storage_pb'; +import * as DryRunTypes from '@pkg/opni/generated/github.com/rancher/opni/pkg/plugins/driverutil/dryrun_pb'; + +export const CortexOps = { + service: CortexOpsService, + types: CortexOpsTypes, +}; + +export const DryRun = { types: DryRunTypes }; + +export const Storage = { types: StorageTypes }; diff --git a/web/pkg/opni/components/Alarm/AgentDisconnect.vue b/web/pkg/opni/components/Alarm/AgentDisconnect.vue index e8a0f1c11a..6b9f0c8d8e 100644 --- a/web/pkg/opni/components/Alarm/AgentDisconnect.vue +++ b/web/pkg/opni/components/Alarm/AgentDisconnect.vue @@ -2,6 +2,7 @@ import LabeledSelect from '@shell/components/form/LabeledSelect'; import UnitInput from '@shell/components/form/UnitInput'; import Loading from '@shell/components/Loading'; +import { createComputedTime } from '@pkg/opni/utils/computed'; import { AlertType } from '../../models/alerting/Condition'; import { loadClusters, loadChoices } from './shared'; @@ -65,15 +66,7 @@ export default { return options; }, - systemTimeout: { - get() { - return Number.parseInt(this.value.timeout || '0'); - }, - - set(value) { - this.$set(this.value, 'timeout', `${ (value || 0) }s`); - } - }, + systemTimeout: createComputedTime('value.timeout'), }, }; diff --git a/web/pkg/opni/components/Alarm/CPU.vue b/web/pkg/opni/components/Alarm/CPU.vue index 4ca059ab38..cf57ef60d5 100644 --- a/web/pkg/opni/components/Alarm/CPU.vue +++ b/web/pkg/opni/components/Alarm/CPU.vue @@ -10,6 +10,7 @@ import Tab from '@shell/components/Tabbed/Tab'; import Tabbed from '@shell/components/Tabbed'; import { Banner } from '@components/Banner'; import dayjs from 'dayjs'; +import { createComputedTime } from '@pkg/opni/utils/computed'; import { AlertType, Severity, SeverityResponseToEnum } from '../models/alerting/Condition'; import { createAlertCondition, getAlertConditionChoices, getAlertCondition, updateAlertCondition, deactivateSilenceAlertCondition, silenceAlertCondition @@ -357,25 +358,9 @@ export default { return options; }, - systemTimeout: { - get() { - return Number.parseInt(this.system.config.timeout || '0'); - }, - - set(value) { - this.$set(this.system.config, 'timeout', `${ (value || 0) }s`); - } - }, + systemTimeout: createComputedTime('system.config.timeout'), - kubeStateFor: { - get() { - return Number.parseInt(this.kubeState.config.for || '0'); - }, - - set(value) { - this.$set(this.kubeState.config, 'for', `${ (value || 0) }s`); - } - }, + kubeStateFor: createComputedTime('kubeState.config.for'), silenceUntil() { if (!this.config?.silence?.endsAt) { @@ -393,15 +378,9 @@ export default { return options; }, - downstreamCapabilityFor: { - get() { - return Number.parseInt(this.downstreamCapability.config.for || '0'); - }, - set(value) { - this.$set(this.downstreamCapability.config, 'for', `${ (value || 0) }s`); - } - }, + downstreamCapabilityFor: createComputedTime('downstreamCapability.config.for'), + downstreamCapabilityStateOptions() { const options = this.downstreamCapability.choices.clusters[this.downstreamCapability.config.clusterId]?.states || []; @@ -421,15 +400,7 @@ export default { return options; }, - monitoringBackendFor: { - get() { - return Number.parseInt(this.monitoringBackend.config.for || '0'); - }, - - set(value) { - this.$set(this.monitoringBackend.config, 'for', `${ (value || 0) }s`); - } - } + monitoringBackendFor: createComputedTime('monitoringBackend.config.for'), }, watch: { diff --git a/web/pkg/opni/components/Alarm/DownstreamCapability.vue b/web/pkg/opni/components/Alarm/DownstreamCapability.vue index 04d570ea3b..c70b07c9a5 100644 --- a/web/pkg/opni/components/Alarm/DownstreamCapability.vue +++ b/web/pkg/opni/components/Alarm/DownstreamCapability.vue @@ -3,6 +3,7 @@ import ArrayListSelect from '@shell/components/form/ArrayListSelect'; import LabeledSelect from '@shell/components/form/LabeledSelect'; import UnitInput from '@shell/components/form/UnitInput'; import Loading from '@shell/components/Loading'; +import { createComputedTime } from '@pkg/opni/utils/computed'; import { AlertType } from '../../models/alerting/Condition'; import { loadClusters, loadChoices } from './shared'; @@ -71,15 +72,9 @@ export default { return options; }, - downstreamCapabilityFor: { - get() { - return Number.parseInt(this.value.for || '0'); - }, - set(value) { - this.$set(this.value, 'for', `${ (value || 0) }s`); - } - }, + downstreamCapabilityFor: createComputedTime('value.for'), + downstreamCapabilityStateOptions() { if (!this.value.clusterId) { return []; diff --git a/web/pkg/opni/components/Alarm/Filesystem.vue b/web/pkg/opni/components/Alarm/Filesystem.vue index aff08def46..e53f12dd9f 100644 --- a/web/pkg/opni/components/Alarm/Filesystem.vue +++ b/web/pkg/opni/components/Alarm/Filesystem.vue @@ -10,6 +10,7 @@ import Tab from '@shell/components/Tabbed/Tab'; import Tabbed from '@shell/components/Tabbed'; import { Banner } from '@components/Banner'; import dayjs from 'dayjs'; +import { createComputedTime } from '@pkg/opni/utils/computed'; import { exceptionToErrorsArray } from '../utils/error'; import { AlertType, Severity, SeverityResponseToEnum } from '../models/alerting/Condition'; import { @@ -357,25 +358,9 @@ export default { return options; }, - systemTimeout: { - get() { - return Number.parseInt(this.system.config.timeout || '0'); - }, - - set(value) { - this.$set(this.system.config, 'timeout', `${ (value || 0) }s`); - } - }, + systemTimeout: createComputedTime('system.config.timeout'), - kubeStateFor: { - get() { - return Number.parseInt(this.kubeState.config.for || '0'); - }, - - set(value) { - this.$set(this.kubeState.config, 'for', `${ (value || 0) }s`); - } - }, + kubeStateFor: createComputedTime('kubeState.config.for'), silenceUntil() { if (!this.config?.silence?.endsAt) { @@ -393,15 +378,9 @@ export default { return options; }, - downstreamCapabilityFor: { - get() { - return Number.parseInt(this.downstreamCapability.config.for || '0'); - }, - set(value) { - this.$set(this.downstreamCapability.config, 'for', `${ (value || 0) }s`); - } - }, + downstreamCapabilityFor: createComputedTime('downstreamCapability.config.for'), + downstreamCapabilityStateOptions() { const options = this.downstreamCapability.choices.clusters[this.downstreamCapability.config.clusterId]?.states || []; @@ -421,15 +400,7 @@ export default { return options; }, - monitoringBackendFor: { - get() { - return Number.parseInt(this.monitoringBackend.config.for || '0'); - }, - - set(value) { - this.$set(this.monitoringBackend.config, 'for', `${ (value || 0) }s`); - } - } + monitoringBackendFor: createComputedTime('monitoringBackend.config.for'), }, watch: { diff --git a/web/pkg/opni/components/Alarm/KubeState.vue b/web/pkg/opni/components/Alarm/KubeState.vue index 1ac4506d01..a5f73df7e2 100644 --- a/web/pkg/opni/components/Alarm/KubeState.vue +++ b/web/pkg/opni/components/Alarm/KubeState.vue @@ -2,6 +2,7 @@ import LabeledSelect from '@shell/components/form/LabeledSelect'; import UnitInput from '@shell/components/form/UnitInput'; import Loading from '@shell/components/Loading'; +import { createComputedTime } from '@pkg/opni/utils/computed'; import { AlertType } from '../../models/alerting/Condition'; import { loadClusters, loadChoices } from './shared'; @@ -123,15 +124,7 @@ export default { return options; }, - kubeStateFor: { - get() { - return Number.parseInt(this.value.for || '0'); - }, - - set(value) { - this.$set(this.value, 'for', `${ (value || 0) }s`); - } - }, + kubeStateFor: createComputedTime('value.for'), }, watch: { diff --git a/web/pkg/opni/components/Alarm/Memory.vue b/web/pkg/opni/components/Alarm/Memory.vue index aff08def46..83055383e3 100644 --- a/web/pkg/opni/components/Alarm/Memory.vue +++ b/web/pkg/opni/components/Alarm/Memory.vue @@ -10,6 +10,7 @@ import Tab from '@shell/components/Tabbed/Tab'; import Tabbed from '@shell/components/Tabbed'; import { Banner } from '@components/Banner'; import dayjs from 'dayjs'; +import { createComputedTime } from '@pkg/opni/utils/computed'; import { exceptionToErrorsArray } from '../utils/error'; import { AlertType, Severity, SeverityResponseToEnum } from '../models/alerting/Condition'; import { @@ -357,25 +358,7 @@ export default { return options; }, - systemTimeout: { - get() { - return Number.parseInt(this.system.config.timeout || '0'); - }, - - set(value) { - this.$set(this.system.config, 'timeout', `${ (value || 0) }s`); - } - }, - - kubeStateFor: { - get() { - return Number.parseInt(this.kubeState.config.for || '0'); - }, - - set(value) { - this.$set(this.kubeState.config, 'for', `${ (value || 0) }s`); - } - }, + systemTimeout: createComputedTime('system.config.timeout'), silenceUntil() { if (!this.config?.silence?.endsAt) { @@ -393,15 +376,8 @@ export default { return options; }, - downstreamCapabilityFor: { - get() { - return Number.parseInt(this.downstreamCapability.config.for || '0'); - }, + downstreamCapabilityFor: createComputedTime('downstreamCapability.config.for'), - set(value) { - this.$set(this.downstreamCapability.config, 'for', `${ (value || 0) }s`); - } - }, downstreamCapabilityStateOptions() { const options = this.downstreamCapability.choices.clusters[this.downstreamCapability.config.clusterId]?.states || []; @@ -421,15 +397,7 @@ export default { return options; }, - monitoringBackendFor: { - get() { - return Number.parseInt(this.monitoringBackend.config.for || '0'); - }, - - set(value) { - this.$set(this.monitoringBackend.config, 'for', `${ (value || 0) }s`); - } - } + monitoringBackendFor: createComputedTime('monitoringBackend.config.for') }, watch: { diff --git a/web/pkg/opni/components/Alarm/MonitoringBackend.vue b/web/pkg/opni/components/Alarm/MonitoringBackend.vue index e49dcd6d62..4ce55cb460 100644 --- a/web/pkg/opni/components/Alarm/MonitoringBackend.vue +++ b/web/pkg/opni/components/Alarm/MonitoringBackend.vue @@ -2,6 +2,7 @@ import ArrayListSelect from '@shell/components/form/ArrayListSelect'; import UnitInput from '@shell/components/form/UnitInput'; import Loading from '@shell/components/Loading'; +import { createComputedTime } from '@pkg/opni/utils/computed'; import { AlertType } from '../../models/alerting/Condition'; import { loadClusters, loadChoices } from './shared'; @@ -66,15 +67,7 @@ export default { return options; }, - monitoringBackendFor: { - get() { - return Number.parseInt(this.value.for || '0'); - }, - - set(value) { - this.$set(this.value, 'for', `${ (value || 0) }s`); - } - } + monitoringBackendFor: createComputedTime('value.for'), }, }; diff --git a/web/pkg/opni/components/Alarm/Prometheus.vue b/web/pkg/opni/components/Alarm/Prometheus.vue index 8e9abce049..d9c3ba30c3 100644 --- a/web/pkg/opni/components/Alarm/Prometheus.vue +++ b/web/pkg/opni/components/Alarm/Prometheus.vue @@ -3,6 +3,7 @@ import LabeledSelect from '@shell/components/form/LabeledSelect'; import UnitInput from '@shell/components/form/UnitInput'; import TextAreaAutoGrow from '@components/Form/TextArea/TextAreaAutoGrow'; import Loading from '@shell/components/Loading'; +import { createComputedTime } from '@pkg/opni/utils/computed'; import { AlertType } from '../../models/alerting/Condition'; import { loadClusters, loadChoices } from './shared'; @@ -71,14 +72,7 @@ export default { return options; }, - prometheusQueryFor: { - get() { - return Math.floor(Number.parseInt(this.value.for || '0') / 60); - }, - set(value) { - this.$set(this.value, 'for', `${ (value || 0) * 60 }s`); - } - } + prometheusQueryFor: createComputedTime('value.for', 60), }, }; diff --git a/web/pkg/opni/components/AttachedEndpoints.vue b/web/pkg/opni/components/AttachedEndpoints.vue index edfbbee172..649d14d8bd 100644 --- a/web/pkg/opni/components/AttachedEndpoints.vue +++ b/web/pkg/opni/components/AttachedEndpoints.vue @@ -6,6 +6,7 @@ import { Checkbox } from '@components/Form/Checkbox'; import TextAreaAutoGrow from '@components/Form/TextArea/TextAreaAutoGrow'; import Loading from '@shell/components/Loading'; import { Banner } from '@components/Banner'; +import { createComputedTime } from '@pkg/opni/utils/computed'; import { Severity } from '../models/alerting/Condition'; import { getAlertEndpoints } from '../utils/requests/alerts'; import ArrayListSelect from './RancherOverride/ArrayListSelect'; @@ -99,40 +100,16 @@ export default { }, set(value) { - console.log('seeeti', value); this.$emit('input', { ...this.value, items: value.map(v => ({ endpointId: v })) }); } }, - initialDelay: { - get() { - return Number.parseInt(this.value.initialDelay || '0'); - }, + initialDelay: createComputedTime('value.initialDelay'), - set(value) { - this.$emit('input', { ...this.value, initialDelay: `${ (value || 0) }s` }); - } - }, + repeatInterval: createComputedTime('value.repeatInterval', 60), - repeatInterval: { - get() { - return Number.parseInt(this.value.repeatInterval || '0') / 60; - }, + throttlingDuration: createComputedTime('value.throttlingDuration', 60), - set(value) { - this.$emit('input', { ...this.value, repeatInterval: `${ Math.round(value * 60 || 0) }s` }); - } - }, - - throttlingDuration: { - get() { - return Number.parseInt(this.value.throttlingDuration || '0') / 60; - }, - - set(value) { - this.$emit('input', { ...this.value, throttlingDuration: `${ Math.round(value * 60 || 0) }s` }); - } - }, showMessageOptions() { return this.value.items.length > 0 && this.value.items.some(item => item?.endpointId); } diff --git a/web/pkg/opni/components/Backend.vue b/web/pkg/opni/components/Backend.vue index 7dc1b2981e..fa5ff00c22 100644 --- a/web/pkg/opni/components/Backend.vue +++ b/web/pkg/opni/components/Backend.vue @@ -2,6 +2,7 @@ import Loading from '@shell/components/Loading'; import AsyncButton from '@shell/components/AsyncButton'; import { Banner } from '@components/Banner'; +import LoadingSpinner from '@pkg/opni/components/LoadingSpinner'; import { exceptionToErrorsArray } from '../utils/error'; export default { @@ -9,6 +10,7 @@ export default { AsyncButton, Banner, Loading, + LoadingSpinner }, props: { @@ -42,6 +44,11 @@ export default { default: () => null }, + getConfig: { + type: Function, + default: () => null + }, + save: { type: Function, required: true @@ -80,6 +87,7 @@ export default { statsInterval: null, statusInterval: null, + loadingConfig: false, }; }, @@ -115,9 +123,11 @@ export default { this.$set(this, 'editing', true); }, - async loadStatus() { + loadStatus() { if (this.enabled || this.editing) { - this.$set(this, 'status', await this.getStatus()); + this.getStatus().then((status) => { + this.$set(this, 'status', status); + }); } }, @@ -163,6 +173,19 @@ export default { } } }, + + watch: { + async editing() { + if (this.editing && this.getConfig) { + try { + this.$set(this, 'loadingConfig', true); + this.$set(this, 'config', await this.getConfig()); + } finally { + this.$set(this, 'loadingConfig', false); + } + } + } + } };