@rancher/shell 3.0.10 → 3.0.12-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/styles/base/_mixins.scss +31 -0
- package/assets/styles/base/_variables.scss +2 -0
- package/assets/styles/themes/_modern.scss +6 -5
- package/assets/translations/en-us.yaml +12 -9
- package/assets/translations/zh-hans.yaml +0 -3
- package/chart/__tests__/rancher-backup-index.test.ts +248 -0
- package/chart/rancher-backup/index.vue +41 -2
- package/components/BrandImage.vue +6 -5
- package/components/ConsumptionGauge.vue +12 -4
- package/components/DynamicContent/DynamicContentIcon.vue +3 -2
- package/components/EmptyProductPage.vue +76 -0
- package/components/ExplorerProjectsNamespaces.vue +1 -4
- package/components/LazyImage.vue +2 -1
- package/components/Resource/Detail/Card/Scaler.vue +4 -4
- package/components/Resource/Detail/CopyToClipboard.vue +1 -2
- package/components/Resource/Detail/Metadata/KeyValueRow.vue +9 -3
- package/components/Resource/Detail/TitleBar/__tests__/__snapshots__/index.test.ts.snap +31 -0
- package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +45 -1
- package/components/Resource/Detail/TitleBar/index.vue +1 -1
- package/components/Resource/Detail/ViewOptions/__tests__/__snapshots__/index.test.ts.snap +9 -0
- package/components/Resource/Detail/ViewOptions/__tests__/index.test.ts +62 -0
- package/components/Resource/Detail/ViewOptions/index.vue +2 -1
- package/components/ResourceList/Masthead.vue +25 -2
- package/components/SideNav.vue +13 -0
- package/components/Tabbed/index.vue +6 -0
- package/components/__tests__/ConsumptionGauge.test.ts +31 -0
- package/components/__tests__/PromptModal.test.ts +2 -0
- package/components/fleet/FleetClusters.vue +1 -0
- package/components/fleet/__tests__/FleetClusters.test.ts +71 -0
- package/components/form/NodeScheduling.vue +17 -3
- package/components/form/PrivateRegistry.vue +69 -0
- package/components/form/ProjectMemberEditor.vue +0 -10
- package/components/form/__tests__/PrivateRegistry.test.ts +133 -0
- package/components/formatter/WorkloadHealthScale.vue +3 -1
- package/components/nav/Group.vue +26 -3
- package/components/nav/Header.vue +32 -7
- package/components/nav/TopLevelMenu.helper.ts +7 -79
- package/components/nav/TopLevelMenu.vue +15 -1
- package/components/nav/__tests__/TopLevelMenu.helper.test.ts +2 -53
- package/config/pagination-table-headers.js +8 -1
- package/config/private-label.js +2 -1
- package/config/product/apps.js +3 -1
- package/config/product/auth.js +1 -0
- package/config/product/backup.js +1 -0
- package/config/product/compliance.js +1 -1
- package/config/product/explorer.js +25 -6
- package/config/product/fleet.js +1 -0
- package/config/product/gatekeeper.js +1 -0
- package/config/product/istio.js +1 -0
- package/config/product/logging.js +1 -0
- package/config/product/longhorn.js +2 -1
- package/config/product/manager.js +1 -0
- package/config/product/monitoring.js +1 -0
- package/config/product/navlinks.js +1 -0
- package/config/product/neuvector.js +2 -1
- package/config/product/settings.js +1 -0
- package/config/product/uiplugins.js +1 -0
- package/core/__tests__/extension-manager-impl.test.js +187 -2
- package/core/__tests__/plugin-products-helpers.test.ts +454 -0
- package/core/__tests__/plugin-products.test.ts +3219 -0
- package/core/extension-manager-impl.js +34 -3
- package/core/plugin-helpers.ts +31 -0
- package/core/plugin-products-base.ts +375 -0
- package/core/plugin-products-extending.ts +44 -0
- package/core/plugin-products-helpers.ts +262 -0
- package/core/plugin-products-top-level.ts +66 -0
- package/core/plugin-products-type-guards.ts +33 -0
- package/core/plugin-products.ts +50 -0
- package/core/plugin-types.ts +222 -0
- package/core/plugin.ts +45 -10
- package/core/productDebugger.js +48 -0
- package/core/types.ts +95 -11
- package/detail/__tests__/__snapshots__/fleet.cattle.io.bundle.test.ts.snap +52 -0
- package/detail/__tests__/fleet.cattle.io.bundle.test.ts +171 -0
- package/detail/__tests__/node.test.ts +83 -0
- package/detail/fleet.cattle.io.bundle.vue +21 -34
- package/detail/management.cattle.io.oidcclient.vue +2 -1
- package/detail/node.vue +1 -0
- package/dialog/ExtensionCatalogInstallDialog.vue +1 -1
- package/dialog/InstallExtensionDialog.vue +6 -27
- package/dialog/UninstallExistingExtensionDialog.vue +141 -0
- package/dialog/UninstallExtensionDialog.vue +4 -26
- package/dialog/__tests__/UninstallExistingExtensionDialog.test.ts +114 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +1 -0
- package/edit/catalog.cattle.io.clusterrepo.vue +17 -3
- package/edit/cloudcredential.vue +2 -1
- package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +11 -6
- package/edit/provisioning.cattle.io.cluster/__tests__/Ingress.test.ts +176 -0
- package/edit/provisioning.cattle.io.cluster/index.vue +5 -4
- package/edit/provisioning.cattle.io.cluster/rke2.vue +4 -1
- package/edit/provisioning.cattle.io.cluster/shared.ts +4 -2
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +6 -0
- package/edit/provisioning.cattle.io.cluster/tabs/Ingress.vue +7 -2
- package/edit/secret/generic.vue +1 -0
- package/edit/secret/index.vue +2 -1
- package/edit/service.vue +2 -14
- package/list/management.cattle.io.feature.vue +7 -1
- package/list/provisioning.cattle.io.cluster.vue +0 -50
- package/list/workload.vue +11 -4
- package/mixins/brand.js +2 -1
- package/mixins/resource-fetch.js +12 -3
- package/models/catalog.cattle.io.clusterrepo.js +9 -0
- package/models/cluster.x-k8s.io.machinedeployment.js +8 -3
- package/models/management.cattle.io.authconfig.js +2 -1
- package/models/management.cattle.io.cluster.js +4 -3
- package/models/monitoring.coreos.com.receiver.js +11 -6
- package/models/pod.js +18 -0
- package/models/provisioning.cattle.io.cluster.js +2 -2
- package/models/workload.js +20 -2
- package/package.json +5 -6
- package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +0 -1
- package/pages/c/_cluster/apps/charts/index.vue +3 -8
- package/pages/c/_cluster/apps/charts/install.vue +8 -9
- package/pages/c/_cluster/istio/index.vue +4 -2
- package/pages/c/_cluster/longhorn/index.vue +2 -1
- package/pages/c/_cluster/monitoring/index.vue +2 -2
- package/pages/c/_cluster/neuvector/index.vue +2 -1
- package/pages/c/_cluster/settings/brand.vue +4 -4
- package/pages/c/_cluster/settings/performance.vue +0 -5
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +2 -1
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +231 -13
- package/pages/c/_cluster/uiplugins/index.vue +145 -38
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +1 -0
- package/plugins/dashboard-store/actions.js +3 -2
- package/plugins/dashboard-store/resource-class.js +62 -6
- package/plugins/plugin.js +16 -0
- package/plugins/steve/steve-pagination-utils.ts +8 -2
- package/plugins/steve/subscribe.js +29 -4
- package/rancher-components/RcButton/RcButton.vue +3 -3
- package/rancher-components/RcButtonSplit/RcButtonSplit.test.ts +253 -0
- package/rancher-components/RcButtonSplit/RcButtonSplit.vue +158 -0
- package/rancher-components/RcButtonSplit/index.ts +1 -0
- package/scripts/test-plugins-build.sh +4 -4
- package/scripts/typegen.sh +13 -1
- package/store/__tests__/type-map.test.ts +84 -24
- package/store/type-map.js +42 -3
- package/tsconfig.paths.json +1 -0
- package/types/resources/pod.ts +18 -0
- package/types/shell/index.d.ts +8506 -2908
- package/types/store/dashboard-store.types.ts +5 -0
- package/types/store/pagination.types.ts +6 -0
- package/utils/__tests__/require-asset.test.ts +98 -0
- package/utils/async.ts +1 -5
- package/utils/axios.js +1 -4
- package/utils/brand.ts +3 -1
- package/utils/dynamic-importer.js +3 -2
- package/utils/favicon.js +4 -3
- package/utils/pagination-utils.ts +1 -1
- package/utils/require-asset.ts +95 -0
- package/utils/uiplugins.ts +12 -16
- package/utils/validators/__tests__/private-registry.test.ts +76 -0
- package/utils/validators/private-registry.ts +28 -0
- package/vue.config.js +4 -3
- package/components/HarvesterServiceAddOnConfig.vue +0 -207
|
@@ -161,3 +161,34 @@
|
|
|
161
161
|
// we need to use !important because it needs to superseed other classes that might impact outlines
|
|
162
162
|
outline: 2px solid var(--primary-keyboard-focus);
|
|
163
163
|
}
|
|
164
|
+
|
|
165
|
+
// -------------------------------------------------------------------------------------------------
|
|
166
|
+
// Extension dialog styles
|
|
167
|
+
|
|
168
|
+
@mixin extension-dialog {
|
|
169
|
+
padding: 8px 16px 16px 16px;
|
|
170
|
+
|
|
171
|
+
h4 {
|
|
172
|
+
font-weight: bold;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.dialog-panel {
|
|
176
|
+
display: flex;
|
|
177
|
+
flex-direction: column;
|
|
178
|
+
min-height: 96px;
|
|
179
|
+
|
|
180
|
+
.dialog-info {
|
|
181
|
+
flex: 1;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.dialog-buttons {
|
|
186
|
+
display: flex;
|
|
187
|
+
justify-content: flex-end;
|
|
188
|
+
margin-top: 24px;
|
|
189
|
+
|
|
190
|
+
> *:not(:last-child) {
|
|
191
|
+
margin-right: 8px;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -74,6 +74,7 @@ $contrasted-light: $lightest !default;
|
|
|
74
74
|
$selected: rgba(#3D98D3, .5);
|
|
75
75
|
|
|
76
76
|
$drag-over: #DCDEE7;
|
|
77
|
+
$body-bg : $lightest;
|
|
77
78
|
|
|
78
79
|
BODY, .theme-light {
|
|
79
80
|
|
|
@@ -418,7 +419,7 @@ BODY, .theme-light {
|
|
|
418
419
|
}
|
|
419
420
|
|
|
420
421
|
|
|
421
|
-
--body-bg : #{$
|
|
422
|
+
--body-bg : #{$body-bg};
|
|
422
423
|
--body-text : #{$darkest};
|
|
423
424
|
--body-text-hover : var(--body-text);
|
|
424
425
|
--scrollbar-thumb : #{$dark};
|
|
@@ -724,8 +725,8 @@ BODY, .theme-light {
|
|
|
724
725
|
--rc-disabled-background: #{$gray001};
|
|
725
726
|
--rc-disabled-text-color: #{$gray004};
|
|
726
727
|
|
|
727
|
-
--rc-section-background-primary: #{$
|
|
728
|
-
--rc-section-background-secondary: #{$
|
|
728
|
+
--rc-section-background-primary: #{$body-bg};
|
|
729
|
+
--rc-section-background-secondary: #{$grey-5};
|
|
729
730
|
--rc-section-action-color: #{$gray009};
|
|
730
731
|
|
|
731
732
|
--rc-image-bg: #{$lightest};
|
|
@@ -1072,8 +1073,8 @@ BODY, .theme-dark {
|
|
|
1072
1073
|
--rc-disabled-background: #{$gray005};
|
|
1073
1074
|
--rc-disabled-text-color: #{$gray004};
|
|
1074
1075
|
|
|
1075
|
-
--rc-section-background-primary: #{$
|
|
1076
|
-
--rc-section-background-secondary: #{$
|
|
1076
|
+
--rc-section-background-primary: #{$body-bg};
|
|
1077
|
+
--rc-section-background-secondary: #{$darkest};
|
|
1077
1078
|
--rc-section-action-color: #{$gray010};
|
|
1078
1079
|
|
|
1079
1080
|
--rc-image-bg: #{$lightest};
|
|
@@ -1018,6 +1018,11 @@ asyncButton:
|
|
|
1018
1018
|
waiting: Generating…
|
|
1019
1019
|
|
|
1020
1020
|
backupRestoreOperator:
|
|
1021
|
+
monitoring:
|
|
1022
|
+
label: Monitoring
|
|
1023
|
+
enableMetrics: Enable Metrics
|
|
1024
|
+
enableServiceMonitor: Enable ServiceMonitor
|
|
1025
|
+
serviceMonitorTooltip: Requires rancher-monitoring to be installed before this can be enabled.
|
|
1021
1026
|
backup:
|
|
1022
1027
|
label: Resource Set
|
|
1023
1028
|
description: The Resource Set determines which resources the backup-restore-operator collects in a backup
|
|
@@ -1374,6 +1379,7 @@ catalog:
|
|
|
1374
1379
|
releaseName: Release Name
|
|
1375
1380
|
releaseNamespace: Release Namespace
|
|
1376
1381
|
repo:
|
|
1382
|
+
add: Add Repository
|
|
1377
1383
|
action:
|
|
1378
1384
|
refresh: Refresh
|
|
1379
1385
|
all: All
|
|
@@ -2719,8 +2725,6 @@ cluster:
|
|
|
2719
2725
|
v2: RKE2/K3s
|
|
2720
2726
|
validation:
|
|
2721
2727
|
iamInstanceProfileName: If the Amazon cloud provider is selected the "IAM Instance Profile Name" must be defined for each Machine Pool
|
|
2722
|
-
capi:
|
|
2723
|
-
notSupported: Managing clusters provisioned using CAPI infrastructure providers via the UI is currently limited to Rancher Turtles provisioned clusters.
|
|
2724
2728
|
|
|
2725
2729
|
clusterIndexPage:
|
|
2726
2730
|
hardwareResourceGauge:
|
|
@@ -2985,7 +2989,7 @@ fleet:
|
|
|
2985
2989
|
add: Add Selector
|
|
2986
2990
|
tolerations:
|
|
2987
2991
|
label: Tolerations
|
|
2988
|
-
description: "List of node taints to tolerate
|
|
2992
|
+
description: "List of node taints to tolerate."
|
|
2989
2993
|
add: Add Toleration
|
|
2990
2994
|
priorityClassName:
|
|
2991
2995
|
label: Priority Class Name
|
|
@@ -5029,6 +5033,7 @@ node:
|
|
|
5029
5033
|
cpu: CPU
|
|
5030
5034
|
memory: MEMORY
|
|
5031
5035
|
pods: PODS
|
|
5036
|
+
running: Running
|
|
5032
5037
|
diskPressure: Disk Pressure
|
|
5033
5038
|
kubelet: kubelet
|
|
5034
5039
|
memoryPressure: Memory Pressure
|
|
@@ -5573,6 +5578,9 @@ plugins:
|
|
|
5573
5578
|
prompt: "Are you sure that you want to install this extension?"
|
|
5574
5579
|
version: Version
|
|
5575
5580
|
warnNotCertified: Please ensure that you are aware of the risks of installing Extensions from untrusted authors
|
|
5581
|
+
alreadyInstalledTitle: This extension is already installed from another source
|
|
5582
|
+
alreadyInstalledPrompt: To install it from this source, you need to uninstall the existing version first and reload the page (required). Would you like to continue?
|
|
5583
|
+
uninstallExisting: Uninstall existing version
|
|
5576
5584
|
upgrade:
|
|
5577
5585
|
label: Upgrade
|
|
5578
5586
|
title: Upgrade extension {name}
|
|
@@ -5773,7 +5781,6 @@ projectMembers:
|
|
|
5773
5781
|
createNs: Create Namespaces
|
|
5774
5782
|
configmapsManage: Manage Config Maps
|
|
5775
5783
|
ingressManage: Manage Ingress
|
|
5776
|
-
projectcatalogsManage: Manage Project Catalogs
|
|
5777
5784
|
projectroletemplatebindingsManage: Manage Project Members
|
|
5778
5785
|
secretsManage: Manage Secrets
|
|
5779
5786
|
serviceaccountsManage: Manage Service Accounts
|
|
@@ -5783,7 +5790,6 @@ projectMembers:
|
|
|
5783
5790
|
configmapsView: View Config Maps
|
|
5784
5791
|
ingressView: View Ingress
|
|
5785
5792
|
monitoringUiView: View Monitoring
|
|
5786
|
-
projectcatalogsView: View Project Catalogs
|
|
5787
5793
|
projectroletemplatebindingsView: View Project Members
|
|
5788
5794
|
secretsView: View Secrets
|
|
5789
5795
|
serviceaccountsView: View Service Accounts
|
|
@@ -6985,6 +6991,7 @@ tableHeaders:
|
|
|
6985
6991
|
progress: Progress
|
|
6986
6992
|
podImages: Image
|
|
6987
6993
|
podRestarts: Restarts
|
|
6994
|
+
podLastRestart: Last Restart
|
|
6988
6995
|
pods: Pods
|
|
6989
6996
|
pod-Selector: Pod-Selector
|
|
6990
6997
|
providers: Providers
|
|
@@ -8042,10 +8049,7 @@ typeDescription:
|
|
|
8042
8049
|
monitoring.coreos.com.prometheus: A Prometheus server is a Prometheus deployment whose scrape configuration and rules are determined by selected ServiceMonitors, PodMonitors, and PrometheusRules and whose alerts will be sent to all selected Alertmanagers with the custom resource's configuration.
|
|
8043
8050
|
monitoring.coreos.com.alertmanager: An alert manager is deployment whose configuration will be specified by a secret in the same namespace, which determines which alerts should go to which receiver.
|
|
8044
8051
|
node: The base Kubernetes Node resource represents a virtual or physical machine which hosts deployments. To manage the machine lifecycle, if available, go to Cluster Management.
|
|
8045
|
-
catalog.cattle.io.clusterrepo: 'A chart repository is a Helm repository or {vendor} git based application catalog. It provides the list of available charts in the cluster.'
|
|
8046
|
-
catalog.cattle.io.clusterrepo.local: ' A chart repository is a Helm repository or {vendor} git based application catalog. It provides the list of available charts in the cluster. Cluster Templates are deployed via Helm charts.'
|
|
8047
8052
|
catalog.cattle.io.operation: An operation is the list of recent Helm operations that have been applied to the cluster.
|
|
8048
|
-
catalog.cattle.io.app: An installed application is a Helm 3 chart that was installed either via our charts or through the Helm CLI.
|
|
8049
8053
|
logging.banzaicloud.io.clusterflow: Logs from the cluster will be collected and logged to the selected Cluster Output.
|
|
8050
8054
|
logging.banzaicloud.io.clusteroutput: A cluster output defines which logging providers that logs can be sent to and is only effective when deployed in the namespace that the logging operator is in.
|
|
8051
8055
|
logging.banzaicloud.io.flow: A flow defines which logs to collect and filter as well as which output to send the logs. The flow is a namespaced resource, which means logs will only be collected from the namespace that the flow is deployed in.
|
|
@@ -8946,7 +8950,6 @@ performance:
|
|
|
8946
8950
|
label: Server-side Pagination
|
|
8947
8951
|
description: By default Lists will fetch all resources and paginate (create the page given sort and filter settings) locally in the browser. Server-Side Pagination moves this out from the browser to the server. This improves performance of the UI, especially in systems with lots of resources.
|
|
8948
8952
|
applicable: "Server-side pagination applies to Resource Types"
|
|
8949
|
-
featureFlag: Enabling/Disabling <i class="mr-5">"Server-side Pagination"</i> is now solely done so via the <i class="mr-5">ui-sql-cache</i> <a href="{ffUrl}">Feature Flag</a>
|
|
8950
8953
|
resources:
|
|
8951
8954
|
generic: most resources in the cluster's 'More Resources' section
|
|
8952
8955
|
all: All Resources
|
|
@@ -6339,10 +6339,7 @@ typeDescription:
|
|
|
6339
6339
|
monitoring.coreos.com.prometheus: Prometheus server 是一个 Prometheus deployment,其抓取的配置和规则由选定的 ServiceMonitor、PodMonitor 和 PrometheusRule 决定。它将其告警信息发送给所有选择的具有定制资源配置的 AlertManager。
|
|
6340
6340
|
monitoring.coreos.com.alertmanager: Alertmanager 是一个 deployment。其配置由同一命名空间中的密文指定,该密文决定了告警的接收器。
|
|
6341
6341
|
node: Kubernetes 节点资源展示了承载 Deployment 的虚拟机或物理机。请进入"集群管理"页面管理可用节点的生命周期。
|
|
6342
|
-
catalog.cattle.io.clusterrepo: 'Chart 仓库是一个 Helm 仓库或 {vendor} 基于 Git 的应用商店。此处列出了集群中可用的 Chart。'
|
|
6343
|
-
catalog.cattle.io.clusterrepo.local: ' Chart 仓库是一个 Helm 仓库或 {vendor} 基于 Git 的应用商店。此处列出了集群中可用的 Chart。集群模板是通过 Helm Chart 部署的。'
|
|
6344
6342
|
catalog.cattle.io.operation: 最近的操作指的是最近应用于集群的一系列 Helm 操作。
|
|
6345
|
-
catalog.cattle.io.app: 已安装的应用指的是通过我们的 Chart 或 Helm CLI 安装的 Helm 3 Chart。
|
|
6346
6343
|
logging.banzaicloud.io.clusterflow: 集群日志将被收集并投递到选定的 ClusterOutput 中。
|
|
6347
6344
|
logging.banzaicloud.io.clusteroutput: ClusterOutput 定义了日志可以发送到哪些日志提供程序。只有部署在 Logging operator 所在的命名空间中时,ClusterOutput 才生效。
|
|
6348
6345
|
logging.banzaicloud.io.flow: Flow 定义了要收集和过滤的日志,以及日志的输出目标。Flow 是一个命名空间资源。换言之,只有部署了该 Flow 的命名空间日志才能被该 Flow 收集。
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import RancherBackup from '@shell/chart/rancher-backup/index.vue';
|
|
3
|
+
import { set } from '@shell/utils/object';
|
|
4
|
+
|
|
5
|
+
describe('rancher-backup: index', () => {
|
|
6
|
+
const defaultMocks = {
|
|
7
|
+
$store: {
|
|
8
|
+
dispatch: jest.fn().mockResolvedValue([]),
|
|
9
|
+
getters: {
|
|
10
|
+
'i18n/t': (text: string) => text,
|
|
11
|
+
t: (text: string) => text,
|
|
12
|
+
'cluster/all': () => [],
|
|
13
|
+
'cluster/paginationEnabled': () => false,
|
|
14
|
+
currentStore: () => 'cluster',
|
|
15
|
+
currentCluster: () => ({ id: 'local' }),
|
|
16
|
+
getStoreNameByProductId: 'cluster',
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
$fetchState: { pending: false }
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const defaultStubs = {
|
|
23
|
+
Tab: { template: '<div><slot /></div>' },
|
|
24
|
+
Tabbed: { template: '<div><slot /></div>' },
|
|
25
|
+
S3: true,
|
|
26
|
+
RadioGroup: true,
|
|
27
|
+
LabeledInput: true,
|
|
28
|
+
LabeledSelect: true,
|
|
29
|
+
Banner: true,
|
|
30
|
+
Checkbox: true
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const createWrapper = (propsData = {}, mocks = {}, monitoringInstalled = false) => {
|
|
34
|
+
return shallowMount(RancherBackup, {
|
|
35
|
+
props: {
|
|
36
|
+
value: {},
|
|
37
|
+
mode: 'create',
|
|
38
|
+
...propsData
|
|
39
|
+
},
|
|
40
|
+
global: {
|
|
41
|
+
mocks: {
|
|
42
|
+
...defaultMocks,
|
|
43
|
+
...mocks
|
|
44
|
+
},
|
|
45
|
+
stubs: defaultStubs
|
|
46
|
+
},
|
|
47
|
+
computed: {
|
|
48
|
+
monitoringStatus: () => ({ installed: monitoringInstalled }),
|
|
49
|
+
radioOptions: () => ({
|
|
50
|
+
options: ['none', 's3', 'pickSC', 'pickPV'],
|
|
51
|
+
labels: ['None', 'S3', 'Storage Class', 'Persistent Volume']
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
describe('monitoring section initialization', () => {
|
|
58
|
+
it('should initialize monitoring object with default values when not present', async() => {
|
|
59
|
+
const value: Record<string, any> = {};
|
|
60
|
+
|
|
61
|
+
// Call set directly to test the initialization logic
|
|
62
|
+
set(value, 'monitoring', {
|
|
63
|
+
metrics: { enabled: false },
|
|
64
|
+
serviceMonitor: { enabled: false }
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
expect(value).toHaveProperty('monitoring');
|
|
68
|
+
expect(value).toHaveProperty('monitoring.metrics.enabled', false);
|
|
69
|
+
expect(value).toHaveProperty('monitoring.serviceMonitor.enabled', false);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should not overwrite existing monitoring values when already set', async() => {
|
|
73
|
+
const value = {
|
|
74
|
+
monitoring: {
|
|
75
|
+
metrics: { enabled: true },
|
|
76
|
+
serviceMonitor: { enabled: true }
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// The fetch logic only sets monitoring if it doesn't exist
|
|
81
|
+
// Since value.monitoring already exists, it should NOT be overwritten
|
|
82
|
+
// This test validates the conditional check in the component's fetch()
|
|
83
|
+
expect(value.monitoring).toBeDefined();
|
|
84
|
+
expect(value.monitoring.metrics.enabled).toBe(true);
|
|
85
|
+
expect(value.monitoring.serviceMonitor.enabled).toBe(true);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe('monitoring checkboxes rendering', () => {
|
|
90
|
+
it('should render both monitoring checkboxes', async() => {
|
|
91
|
+
const value = {
|
|
92
|
+
monitoring: {
|
|
93
|
+
metrics: { enabled: false },
|
|
94
|
+
serviceMonitor: { enabled: false }
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const wrapper = createWrapper({ value });
|
|
98
|
+
|
|
99
|
+
const checkboxes = wrapper.findAllComponents({ name: 'Checkbox' });
|
|
100
|
+
|
|
101
|
+
expect(checkboxes).toHaveLength(2);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should pass correct props to metrics checkbox', async() => {
|
|
105
|
+
const value = {
|
|
106
|
+
monitoring: {
|
|
107
|
+
metrics: { enabled: true },
|
|
108
|
+
serviceMonitor: { enabled: false }
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
const wrapper = createWrapper({ value });
|
|
112
|
+
|
|
113
|
+
const checkboxes = wrapper.findAllComponents({ name: 'Checkbox' });
|
|
114
|
+
const metricsCheckbox = checkboxes[0];
|
|
115
|
+
|
|
116
|
+
// The t() mock wraps strings in %, so we check for containment
|
|
117
|
+
expect(metricsCheckbox.attributes('label')).toContain('backupRestoreOperator.monitoring.enableMetrics');
|
|
118
|
+
expect(metricsCheckbox.attributes('value')).toBe('true');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should pass correct props to serviceMonitor checkbox', async() => {
|
|
122
|
+
const value = {
|
|
123
|
+
monitoring: {
|
|
124
|
+
metrics: { enabled: false },
|
|
125
|
+
serviceMonitor: { enabled: true }
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
const wrapper = createWrapper({ value });
|
|
129
|
+
|
|
130
|
+
const checkboxes = wrapper.findAllComponents({ name: 'Checkbox' });
|
|
131
|
+
const serviceMonitorCheckbox = checkboxes[1];
|
|
132
|
+
|
|
133
|
+
expect(serviceMonitorCheckbox.attributes('label')).toContain('backupRestoreOperator.monitoring.enableServiceMonitor');
|
|
134
|
+
expect(serviceMonitorCheckbox.attributes('value')).toBe('true');
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe('serviceMonitor checkbox disabled state', () => {
|
|
139
|
+
it('should set disabled to true when monitoring is not installed', async() => {
|
|
140
|
+
const value = {
|
|
141
|
+
monitoring: {
|
|
142
|
+
metrics: { enabled: false },
|
|
143
|
+
serviceMonitor: { enabled: false }
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
const wrapper = createWrapper({ value }, {}, false);
|
|
147
|
+
|
|
148
|
+
const checkboxes = wrapper.findAllComponents({ name: 'Checkbox' });
|
|
149
|
+
const serviceMonitorCheckbox = checkboxes[1];
|
|
150
|
+
|
|
151
|
+
expect(serviceMonitorCheckbox.attributes('disabled')).toBe('true');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should not set disabled when monitoring is installed', async() => {
|
|
155
|
+
const value = {
|
|
156
|
+
monitoring: {
|
|
157
|
+
metrics: { enabled: false },
|
|
158
|
+
serviceMonitor: { enabled: false }
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
const wrapper = createWrapper({ value }, {}, true);
|
|
162
|
+
|
|
163
|
+
const checkboxes = wrapper.findAllComponents({ name: 'Checkbox' });
|
|
164
|
+
const serviceMonitorCheckbox = checkboxes[1];
|
|
165
|
+
|
|
166
|
+
// When monitoring is installed, disabled should be 'false' (string)
|
|
167
|
+
expect(serviceMonitorCheckbox.attributes('disabled')).toBe('false');
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
describe('serviceMonitor checkbox tooltip', () => {
|
|
172
|
+
it('should show tooltip when monitoring is not installed', async() => {
|
|
173
|
+
const value = {
|
|
174
|
+
monitoring: {
|
|
175
|
+
metrics: { enabled: false },
|
|
176
|
+
serviceMonitor: { enabled: false }
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
const wrapper = createWrapper({ value }, {}, false);
|
|
180
|
+
|
|
181
|
+
const checkboxes = wrapper.findAllComponents({ name: 'Checkbox' });
|
|
182
|
+
const serviceMonitorCheckbox = checkboxes[1];
|
|
183
|
+
|
|
184
|
+
expect(serviceMonitorCheckbox.attributes('tooltip')).toContain('backupRestoreOperator.monitoring.serviceMonitorTooltip');
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('should not show tooltip when monitoring is installed', async() => {
|
|
188
|
+
const value = {
|
|
189
|
+
monitoring: {
|
|
190
|
+
metrics: { enabled: false },
|
|
191
|
+
serviceMonitor: { enabled: false }
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
const wrapper = createWrapper({ value }, {}, true);
|
|
195
|
+
|
|
196
|
+
const checkboxes = wrapper.findAllComponents({ name: 'Checkbox' });
|
|
197
|
+
const serviceMonitorCheckbox = checkboxes[1];
|
|
198
|
+
|
|
199
|
+
expect(serviceMonitorCheckbox.attributes('tooltip')).toBeFalsy();
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
describe('metrics checkbox', () => {
|
|
204
|
+
it('should never be disabled regardless of monitoring status', async() => {
|
|
205
|
+
const value = {
|
|
206
|
+
monitoring: {
|
|
207
|
+
metrics: { enabled: false },
|
|
208
|
+
serviceMonitor: { enabled: false }
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// Test with monitoring not installed
|
|
213
|
+
const wrapperNotInstalled = createWrapper({ value }, {}, false);
|
|
214
|
+
const checkboxesNotInstalled = wrapperNotInstalled.findAllComponents({ name: 'Checkbox' });
|
|
215
|
+
const metricsCheckboxNotInstalled = checkboxesNotInstalled[0];
|
|
216
|
+
|
|
217
|
+
// The metrics checkbox does not have a disabled prop bound, so it should be 'false' or undefined
|
|
218
|
+
const disabledAttr = metricsCheckboxNotInstalled.attributes('disabled');
|
|
219
|
+
|
|
220
|
+
expect(disabledAttr === 'false' || disabledAttr === undefined).toBe(true);
|
|
221
|
+
|
|
222
|
+
// Test with monitoring installed
|
|
223
|
+
const wrapperInstalled = createWrapper({ value }, {}, true);
|
|
224
|
+
const checkboxesInstalled = wrapperInstalled.findAllComponents({ name: 'Checkbox' });
|
|
225
|
+
const metricsCheckboxInstalled = checkboxesInstalled[0];
|
|
226
|
+
const disabledAttrInstalled = metricsCheckboxInstalled.attributes('disabled');
|
|
227
|
+
|
|
228
|
+
expect(disabledAttrInstalled === 'false' || disabledAttrInstalled === undefined).toBe(true);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
describe('monitoring section heading', () => {
|
|
233
|
+
it('should render the monitoring section heading', async() => {
|
|
234
|
+
const value = {
|
|
235
|
+
monitoring: {
|
|
236
|
+
metrics: { enabled: false },
|
|
237
|
+
serviceMonitor: { enabled: false }
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
const wrapper = createWrapper({ value });
|
|
241
|
+
|
|
242
|
+
const heading = wrapper.find('h3');
|
|
243
|
+
|
|
244
|
+
expect(heading.exists()).toBe(true);
|
|
245
|
+
expect(heading.text()).toContain('backupRestoreOperator.monitoring.label');
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
});
|
|
@@ -6,11 +6,13 @@ import { RadioGroup } from '@components/Form/Radio';
|
|
|
6
6
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
|
7
7
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
|
8
8
|
import { Banner } from '@components/Banner';
|
|
9
|
-
import { get } from '@shell/utils/object';
|
|
9
|
+
import { get, set } from '@shell/utils/object';
|
|
10
10
|
import { allHash } from '@shell/utils/promise';
|
|
11
11
|
import { STORAGE_CLASS, PV } from '@shell/config/types';
|
|
12
12
|
import { mapGetters } from 'vuex';
|
|
13
13
|
import { STORAGE } from '@shell/config/labels-annotations';
|
|
14
|
+
import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
|
|
15
|
+
import { monitoringStatus } from '@shell/utils/monitoring';
|
|
14
16
|
|
|
15
17
|
export default {
|
|
16
18
|
emits: ['valid'],
|
|
@@ -22,7 +24,8 @@ export default {
|
|
|
22
24
|
S3,
|
|
23
25
|
LabeledInput,
|
|
24
26
|
LabeledSelect,
|
|
25
|
-
Banner
|
|
27
|
+
Banner,
|
|
28
|
+
Checkbox
|
|
26
29
|
},
|
|
27
30
|
|
|
28
31
|
props: {
|
|
@@ -39,6 +42,16 @@ export default {
|
|
|
39
42
|
}
|
|
40
43
|
},
|
|
41
44
|
|
|
45
|
+
created() {
|
|
46
|
+
// Initialize monitoring before template renders to avoid undefined access
|
|
47
|
+
if (!this.value.monitoring) {
|
|
48
|
+
set(this.value, 'monitoring', {
|
|
49
|
+
metrics: { enabled: false },
|
|
50
|
+
serviceMonitor: { enabled: false }
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
|
|
42
55
|
async fetch() {
|
|
43
56
|
const hash = await allHash({
|
|
44
57
|
storageClasses: this.$store.dispatch('cluster/findAll', { type: STORAGE_CLASS }),
|
|
@@ -64,6 +77,8 @@ export default {
|
|
|
64
77
|
},
|
|
65
78
|
|
|
66
79
|
computed: {
|
|
80
|
+
...monitoringStatus(),
|
|
81
|
+
|
|
67
82
|
defaultStorageClass() {
|
|
68
83
|
return this.storageClasses.filter((sc) => sc.metadata.annotations?.[STORAGE.DEFAULT_STORAGE_CLASS] && sc.metadata.annotations[STORAGE.DEFAULT_STORAGE_CLASS] !== 'false' )[0] || '';
|
|
69
84
|
},
|
|
@@ -248,6 +263,24 @@ export default {
|
|
|
248
263
|
</div>
|
|
249
264
|
</div>
|
|
250
265
|
</template>
|
|
266
|
+
|
|
267
|
+
<h3 class="mb-10 mt-10">
|
|
268
|
+
{{ t('backupRestoreOperator.monitoring.label') }}
|
|
269
|
+
</h3>
|
|
270
|
+
<div class="row monitoring-options">
|
|
271
|
+
<Checkbox
|
|
272
|
+
v-model:value="value.monitoring.metrics.enabled"
|
|
273
|
+
:label="t('backupRestoreOperator.monitoring.enableMetrics')"
|
|
274
|
+
:mode="mode"
|
|
275
|
+
/>
|
|
276
|
+
<Checkbox
|
|
277
|
+
v-model:value="value.monitoring.serviceMonitor.enabled"
|
|
278
|
+
:label="t('backupRestoreOperator.monitoring.enableServiceMonitor')"
|
|
279
|
+
:disabled="!monitoringStatus.installed"
|
|
280
|
+
:tooltip="!monitoringStatus.installed ? t('backupRestoreOperator.monitoring.serviceMonitorTooltip') : null"
|
|
281
|
+
:mode="mode"
|
|
282
|
+
/>
|
|
283
|
+
</div>
|
|
251
284
|
</Tab>
|
|
252
285
|
</Tabbed>
|
|
253
286
|
</div>
|
|
@@ -257,4 +290,10 @@ export default {
|
|
|
257
290
|
:deep() .radio-group.label>SPAN {
|
|
258
291
|
font-size: 1em;
|
|
259
292
|
}
|
|
293
|
+
|
|
294
|
+
.monitoring-options {
|
|
295
|
+
display: flex;
|
|
296
|
+
flex-direction: column;
|
|
297
|
+
gap: 4px;
|
|
298
|
+
}
|
|
260
299
|
</style>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { mapGetters } from 'vuex';
|
|
3
3
|
import { MANAGEMENT } from '@shell/config/types';
|
|
4
4
|
import { SETTING } from '@shell/config/settings';
|
|
5
|
+
import { requireAsset } from '@shell/utils/require-asset';
|
|
5
6
|
|
|
6
7
|
export default {
|
|
7
8
|
props: {
|
|
@@ -72,9 +73,9 @@ export default {
|
|
|
72
73
|
const themePrefix = this.theme === 'dark' ? 'dark/' : '';
|
|
73
74
|
|
|
74
75
|
try {
|
|
75
|
-
return
|
|
76
|
+
return requireAsset(`~shell/assets/images/pl/${ themePrefix }${ this.fileName }`);
|
|
76
77
|
} catch {
|
|
77
|
-
return
|
|
78
|
+
return requireAsset(`~shell/assets/images/pl/${ this.fileName }`);
|
|
78
79
|
}
|
|
79
80
|
},
|
|
80
81
|
|
|
@@ -95,7 +96,7 @@ export default {
|
|
|
95
96
|
// csp, rgs, and federal map to SUSE, but have their own custom logos
|
|
96
97
|
if (this.brandBase !== this.brand) {
|
|
97
98
|
try {
|
|
98
|
-
return
|
|
99
|
+
return requireAsset(`~shell/assets/brand/${ this.brandBase }/${ this.isDark ? 'dark/' : '' }${ this.fileName }`);
|
|
99
100
|
} catch { }
|
|
100
101
|
}
|
|
101
102
|
}
|
|
@@ -125,11 +126,11 @@ export default {
|
|
|
125
126
|
} else {
|
|
126
127
|
if (this.isDark || this.dark) {
|
|
127
128
|
try {
|
|
128
|
-
return
|
|
129
|
+
return requireAsset(`~shell/assets/brand/${ this.brand }/dark/${ this.fileName }`);
|
|
129
130
|
} catch {}
|
|
130
131
|
}
|
|
131
132
|
try {
|
|
132
|
-
return
|
|
133
|
+
return requireAsset(`~shell/assets/brand/${ this.brand }/${ this.fileName }`);
|
|
133
134
|
} catch {}
|
|
134
135
|
|
|
135
136
|
return this.defaultPathToBrandedImage;
|
|
@@ -54,11 +54,19 @@ export default {
|
|
|
54
54
|
},
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
|
-
* Reduce the
|
|
57
|
+
* Reduce the vertical height by replacing 'Used'/usedLabel with the resource name
|
|
58
58
|
*/
|
|
59
59
|
usedAsResourceName: {
|
|
60
|
-
type:
|
|
61
|
-
|
|
60
|
+
type: Boolean,
|
|
61
|
+
default: false
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Override the default "Used" label text (e.g. "Running" for pods).
|
|
66
|
+
*/
|
|
67
|
+
usedLabel: {
|
|
68
|
+
type: String,
|
|
69
|
+
default: null
|
|
62
70
|
}
|
|
63
71
|
},
|
|
64
72
|
computed: {
|
|
@@ -105,7 +113,7 @@ export default {
|
|
|
105
113
|
<h4 v-if="usedAsResourceName">
|
|
106
114
|
{{ resourceName }}
|
|
107
115
|
</h4>
|
|
108
|
-
<span v-else>{{ t('node.detail.glance.consumptionGauge.used') }}</span>
|
|
116
|
+
<span v-else>{{ usedLabel || t('node.detail.glance.consumptionGauge.used') }}</span>
|
|
109
117
|
<span class="numbers-stats">
|
|
110
118
|
{{ t('node.detail.glance.consumptionGauge.amount', amountTemplateValues) }}
|
|
111
119
|
<span class="percentage"><i>/ </i>{{ formattedPercentage }}</span>
|
|
@@ -7,6 +7,7 @@ import { useStore } from 'vuex';
|
|
|
7
7
|
import { computed } from 'vue';
|
|
8
8
|
|
|
9
9
|
import { AnnouncementNotificationIconData } from '@shell/utils/dynamic-content/types';
|
|
10
|
+
import { requireAsset } from '@shell/utils/require-asset';
|
|
10
11
|
|
|
11
12
|
type KeyValues = {
|
|
12
13
|
[key: string]: string;
|
|
@@ -49,9 +50,9 @@ const src = computed(() => {
|
|
|
49
50
|
const themePrefix = theme.value === 'dark' ? 'dark/' : '';
|
|
50
51
|
|
|
51
52
|
try {
|
|
52
|
-
return
|
|
53
|
+
return requireAsset(`~shell/assets/images/content/${ themePrefix }${ img }`);
|
|
53
54
|
} catch {
|
|
54
|
-
return
|
|
55
|
+
return requireAsset(`~shell/assets/images/content/${ img }`);
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
58
|
|