@rancher/shell 3.0.12-rc.3 → 3.0.12-rc.4
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/global/_layout.scss +4 -0
- package/assets/translations/en-us.yaml +144 -41
- package/assets/translations/zh-hans.yaml +1 -7
- package/chart/monitoring/ClusterSelector.vue +0 -21
- package/chart/monitoring/prometheus/index.vue +6 -3
- package/components/CruResource.vue +161 -14
- package/components/ExplorerMembers.vue +8 -4
- package/components/ExplorerProjectsNamespaces.vue +10 -6
- package/components/GrowlManager.vue +4 -0
- package/components/MgmtNodeList.vue +184 -0
- package/components/Resource/Detail/Card/StateCard/__tests__/composables.test.ts +90 -1
- package/components/Resource/Detail/Card/StateCard/composables.ts +57 -87
- package/components/Resource/Detail/Card/StatusCard/__tests__/StatusCard.test.ts +61 -0
- package/components/Resource/Detail/Card/StatusCard/index.vue +61 -15
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +2 -0
- package/components/Resource/Detail/Metadata/KeyValue.vue +5 -2
- package/components/Resource/Detail/Metadata/KeyValueRow.vue +2 -6
- package/components/ResourceDetail/index.vue +1 -1
- package/components/ResourceList/Masthead.vue +7 -1
- package/components/ResourceList/index.vue +82 -1
- package/components/RichTranslation.vue +5 -2
- package/components/Setting.vue +1 -0
- package/components/SubtleLink.vue +31 -6
- package/components/Tabbed/Tab.vue +29 -3
- package/components/Tabbed/index.vue +25 -3
- package/components/TableOfContents/TableOfContents.vue +109 -0
- package/components/TableOfContents/composables.ts +258 -0
- package/components/Window/ContainerShell.vue +21 -11
- package/components/Window/__tests__/ContainerShell.test.ts +107 -37
- package/components/Wizard.vue +9 -4
- package/components/fleet/AppCoChartGrid.vue +401 -0
- package/components/fleet/AppCoEmptyState.vue +127 -0
- package/components/fleet/AppCoPageHeader.vue +119 -0
- package/components/fleet/AppCoVersionSelect.vue +70 -0
- package/components/fleet/FleetClusterTargets/ClusterSelectionFields.vue +217 -0
- package/components/fleet/FleetClusterTargets/TargetsList.vue +123 -35
- package/components/fleet/FleetClusterTargets/index.vue +189 -146
- package/components/fleet/FleetIntro.vue +7 -3
- package/components/fleet/FleetNoWorkspaces.vue +7 -3
- package/components/fleet/FleetSecretSelector.vue +5 -3
- package/components/fleet/FleetValuesFrom.vue +8 -2
- package/components/fleet/GitRepoTargetTab.vue +0 -2
- package/components/fleet/HelmOpAdvancedTab.vue +19 -53
- package/components/fleet/HelmOpAppCoConfigTab.vue +593 -0
- package/components/fleet/HelmOpAppCoResourcesSection.vue +162 -0
- package/components/fleet/HelmOpResourcesSection.vue +82 -0
- package/components/fleet/HelmOpTargetOptionsSection.vue +89 -0
- package/components/fleet/HelmOpTargetTab.vue +64 -60
- package/components/fleet/HelmOpValuesTab.vue +129 -105
- package/components/fleet/__tests__/AppCoEmptyState.test.ts +71 -0
- package/components/fleet/__tests__/AppCoVersionSelect.test.ts +36 -0
- package/components/fleet/__tests__/ClusterSelectionFields.test.ts +62 -0
- package/components/fleet/__tests__/FleetClusterTargets.test.ts +253 -0
- package/components/fleet/__tests__/FleetSecretSelector.test.ts +16 -0
- package/components/fleet/__tests__/FleetValuesFrom.test.ts +44 -0
- package/components/fleet/__tests__/HelmOpAppCoConfigTab.test.ts +59 -0
- package/components/fleet/__tests__/HelmOpAppCoResourcesSection.test.ts +62 -0
- package/components/fleet/__tests__/HelmOpResourcesSection.test.ts +43 -0
- package/components/fleet/__tests__/HelmOpTargetOptionsSection.test.ts +34 -0
- package/components/fleet/__tests__/HelmOpValuesTab.test.ts +39 -0
- package/components/fleet/__tests__/__snapshots__/AppCoEmptyState.test.ts.snap +97 -0
- package/components/fleet/__tests__/__snapshots__/AppCoVersionSelect.test.ts.snap +30 -0
- package/components/fleet/__tests__/__snapshots__/ClusterSelectionFields.test.ts.snap +209 -0
- package/components/fleet/__tests__/__snapshots__/HelmOpTargetOptionsSection.test.ts.snap +140 -0
- package/components/fleet/dashboard/Empty.vue +8 -4
- package/components/fleet/dashboard/ResourceCard.vue +28 -0
- package/components/fleet/dashboard/ResourceDetails.vue +28 -0
- package/components/fleet/dashboard/__tests__/ResourceCard.test.ts +87 -0
- package/components/form/ArrayList.vue +61 -4
- package/components/form/KeyValue.vue +23 -2
- package/components/form/LabeledSelect.vue +39 -1
- package/components/form/Labels.vue +22 -3
- package/components/form/NameNsDescription.vue +13 -5
- package/components/form/ResourceTabs/index.vue +1 -0
- package/components/form/__tests__/NameNsDescription.test.ts +75 -0
- package/components/formatter/InternalExternalIP.vue +10 -4
- package/components/formatter/ServiceTargets.vue +26 -7
- package/components/formatter/__tests__/InternalExternalIP.test.ts +132 -0
- package/components/formatter/__tests__/ServiceTargets.test.ts +412 -0
- package/components/nav/Header.vue +4 -0
- package/components/nav/TopLevelMenu.vue +7 -2
- package/components/nav/__tests__/Header.test.ts +15 -0
- package/components/nav/__tests__/TopLevelMenu.test.ts +120 -2
- package/components/templates/default.vue +9 -4
- package/components/templates/home.vue +9 -4
- package/components/templates/plain.vue +9 -4
- package/composables/useHelmOpResources.test.ts +56 -0
- package/composables/useHelmOpResources.ts +32 -0
- package/composables/useStateColor.test.ts +325 -0
- package/composables/useStateColor.ts +128 -0
- package/config/home-links.js +1 -1
- package/config/labels-annotations.js +1 -0
- package/config/product/explorer.js +17 -4
- package/config/product/manager.js +2 -0
- package/config/router/index.js +16 -0
- package/config/router/navigation-guards/__tests__/authentication.test.ts +130 -0
- package/config/router/navigation-guards/authentication.js +10 -4
- package/config/router/routes.js +20 -6
- package/config/settings.ts +0 -2
- package/config/table-headers.js +3 -4
- package/config/types.js +9 -0
- package/core/plugin-products-base.ts +3 -3
- package/core/plugin-types.ts +83 -30
- package/core/plugin.ts +3 -0
- package/core/types-provisioning.ts +34 -1
- package/core/types.ts +15 -2
- package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +114 -0
- package/detail/__tests__/workload.test.ts +3 -152
- package/detail/catalog.cattle.io.clusterrepo.vue +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +30 -4
- package/detail/workload/index.vue +12 -55
- package/edit/__tests__/catalog.cattle.io.clusterrepo.test.ts +248 -0
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +105 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/index.test.ts.snap +1 -0
- package/edit/auth/__tests__/azuread.test.ts +34 -9
- package/edit/auth/__tests__/github.test.ts +234 -0
- package/edit/auth/__tests__/oidc.test.ts +26 -6
- package/edit/auth/__tests__/saml.test.ts +196 -0
- package/edit/auth/azuread.vue +128 -95
- package/edit/auth/github.vue +72 -13
- package/edit/auth/ldap/__tests__/index.test.ts +206 -0
- package/edit/auth/ldap/config.vue +8 -0
- package/edit/auth/ldap/index.vue +75 -1
- package/edit/auth/oidc.vue +119 -73
- package/edit/auth/saml.vue +76 -12
- package/edit/catalog.cattle.io.clusterrepo.vue +140 -32
- package/edit/fleet.cattle.io.helmop.vue +491 -136
- package/edit/management.cattle.io.user.vue +5 -2
- package/edit/provisioning.cattle.io.cluster/rke2.vue +84 -10
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +11 -0
- package/list/group.principal.vue +5 -4
- package/list/harvesterhci.io.management.cluster.vue +8 -9
- package/list/management.cattle.io.user.vue +12 -9
- package/list/provisioning.cattle.io.cluster.vue +16 -10
- package/mixins/__tests__/auth-config.test.ts +90 -0
- package/mixins/__tests__/chart.test.ts +94 -0
- package/mixins/__tests__/resource-fetch-api-pagination.test.ts +48 -0
- package/mixins/auth-config.js +7 -0
- package/mixins/chart.js +11 -2
- package/mixins/child-hook.js +12 -6
- package/mixins/create-edit-view/impl.js +5 -3
- package/mixins/resource-fetch-api-pagination.js +21 -1
- package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +57 -0
- package/models/__tests__/compliance.cattle.io.clusterscan.test.ts +144 -0
- package/models/__tests__/fleet-application.test.ts +175 -0
- package/models/__tests__/fleet.cattle.io.bundle.test.ts +169 -0
- package/models/__tests__/fleet.cattle.io.helmop.test.ts +84 -0
- package/models/__tests__/management.cattle.io.node.ts +22 -0
- package/models/__tests__/namespace.test.ts +36 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +49 -0
- package/models/__tests__/workload.test.ts +401 -26
- package/models/catalog.cattle.io.clusterrepo.js +28 -4
- package/models/compliance.cattle.io.clusterscan.js +39 -4
- package/models/fleet-application.js +4 -0
- package/models/fleet.cattle.io.helmop.js +20 -1
- package/models/management.cattle.io.cluster.js +18 -2
- package/models/management.cattle.io.node.js +44 -3
- package/models/namespace.js +1 -1
- package/models/pod.js +33 -1
- package/models/provisioning.cattle.io.cluster.js +5 -5
- package/models/workload.js +108 -13
- package/models/workload.service.js +5 -0
- package/package.json +14 -13
- package/pages/about.vue +5 -6
- package/pages/auth/login.vue +0 -35
- package/pages/auth/setup.vue +11 -0
- package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +2 -2
- package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +10 -1
- package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +93 -0
- package/pages/c/_cluster/apps/charts/chart.vue +2 -1
- package/pages/c/_cluster/apps/charts/index.vue +48 -10
- package/pages/c/_cluster/apps/charts/install.vue +122 -116
- package/pages/c/_cluster/auth/roles/index.vue +5 -4
- package/pages/c/_cluster/explorer/workload-dashboard/ByNamespaceSection.vue +31 -0
- package/pages/c/_cluster/explorer/workload-dashboard/ByStateSection.vue +138 -0
- package/pages/c/_cluster/explorer/workload-dashboard/ByTypeSection.vue +30 -0
- package/pages/c/_cluster/explorer/workload-dashboard/WorkloadCard.vue +155 -0
- package/pages/c/_cluster/explorer/workload-dashboard/WorkloadNamespaceCard.vue +142 -0
- package/pages/c/_cluster/explorer/workload-dashboard/WorkloadTypeCard.vue +159 -0
- package/pages/c/_cluster/explorer/workload-dashboard/__tests__/composable.test.ts +561 -0
- package/pages/c/_cluster/explorer/workload-dashboard/composable.ts +440 -0
- package/pages/c/_cluster/explorer/workload-dashboard/index.vue +187 -0
- package/pages/c/_cluster/explorer/workload-dashboard/types.ts +80 -0
- package/pages/c/_cluster/fleet/application/create.vue +187 -136
- package/pages/c/_cluster/fleet/application/index.vue +5 -3
- package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailBody.vue +338 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailHeader.vue +121 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/chart.vue +369 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/charts.vue +248 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/credentials.vue +310 -0
- package/pages/c/_cluster/fleet/index.vue +2 -2
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +96 -0
- package/pages/c/_cluster/uiplugins/index.vue +15 -0
- package/pages/fail-whale.vue +16 -11
- package/pages/home.vue +16 -46
- package/plugins/clean-html.d.ts +9 -0
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +93 -0
- package/plugins/dashboard-store/resource-class.js +62 -7
- package/plugins/steve/__tests__/actions.test.ts +212 -0
- package/plugins/steve/actions.js +96 -0
- package/plugins/steve/steve-pagination-utils.ts +1 -1
- package/rancher-components/Accordion/Accordion.vue +53 -9
- package/rancher-components/Form/Checkbox/Checkbox.vue +14 -0
- package/rancher-components/Form/Radio/RadioButton.vue +17 -1
- package/rancher-components/Form/Radio/RadioGroup.vue +10 -0
- package/rancher-components/Pill/RcTag/RcTag.vue +3 -2
- package/rancher-components/RcButton/RcButton.test.ts +103 -0
- package/rancher-components/RcButton/RcButton.vue +94 -15
- package/rancher-components/RcButton/types.ts +3 -0
- package/rancher-components/RcItemCard/RcItemCard.test.ts +18 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +2 -2
- package/rancher-components/RcSection/RcSection.vue +28 -3
- package/scripts/extension/helm/package/Dockerfile +1 -1
- package/scripts/test-plugins-build.sh +2 -1
- package/store/__tests__/notifications.test.ts +434 -0
- package/store/catalog.js +57 -0
- package/store/plugins.js +7 -4
- package/types/components/buttonGroup.ts +5 -0
- package/types/shell/index.d.ts +104 -70
- package/utils/__tests__/auth.test.ts +273 -0
- package/utils/__tests__/computed.test.ts +193 -0
- package/utils/__tests__/cspAdaptor.test.ts +163 -0
- package/utils/__tests__/dom.test.ts +81 -0
- package/utils/__tests__/duration.test.ts +37 -1
- package/utils/__tests__/dynamic-importer.test.ts +102 -0
- package/utils/__tests__/fleet-appco.test.ts +312 -0
- package/utils/__tests__/monitoring.test.ts +130 -0
- package/utils/__tests__/object.test.ts +22 -0
- package/utils/__tests__/platform.test.ts +91 -0
- package/utils/__tests__/position.test.ts +237 -0
- package/utils/__tests__/provider.test.ts +51 -1
- package/utils/__tests__/queue.test.ts +232 -0
- package/utils/__tests__/release-notes.test.ts +221 -0
- package/utils/__tests__/router.test.js +254 -1
- package/utils/__tests__/select.test.ts +208 -0
- package/utils/__tests__/time.test.ts +265 -1
- package/utils/__tests__/title.test.ts +47 -0
- package/utils/__tests__/width.test.ts +53 -0
- package/utils/__tests__/window.test.ts +158 -0
- package/utils/__tests__/xccdf.test.ts +126 -6
- package/utils/crypto/__tests__/browserHashUtils.test.ts +98 -0
- package/utils/crypto/__tests__/index.test.ts +144 -0
- package/utils/duration.ts +104 -0
- package/utils/dynamic-content/__tests__/notification-handler.test.ts +196 -0
- package/utils/dynamic-content/info.ts +2 -1
- package/utils/error.js +13 -0
- package/utils/fleet-appco.ts +323 -0
- package/utils/object.js +22 -2
- package/utils/provider.ts +12 -0
- package/utils/validators/__tests__/container-images.test.ts +104 -0
- package/utils/validators/__tests__/flow-output.test.ts +91 -0
- package/utils/validators/__tests__/logging-outputs.test.ts +58 -0
- package/utils/validators/__tests__/monitoring-route.test.ts +119 -0
- package/utils/xccdf.ts +39 -42
- package/vue.config.js +1 -1
- package/pages/support/index.vue +0 -264
- package/utils/duration.js +0 -43
|
@@ -17,7 +17,7 @@ import { KEV1 } from './management.cattle.io.kontainerdriver';
|
|
|
17
17
|
import { requireAsset } from '@shell/utils/require-asset';
|
|
18
18
|
import { PINNED_CLUSTERS } from '@shell/store/prefs';
|
|
19
19
|
import { copyTextToClipboard } from '@shell/utils/clipboard';
|
|
20
|
-
import { isHostedProvider } from '@shell/utils/provider';
|
|
20
|
+
import { isHostedProvider, isCAPIProvider } from '@shell/utils/provider';
|
|
21
21
|
import { ucFirst } from '@shell/utils/string';
|
|
22
22
|
import { sortBy } from '@shell/utils/sort';
|
|
23
23
|
|
|
@@ -180,7 +180,7 @@ export default class MgmtCluster extends SteveModel {
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
get machineProvider() {
|
|
183
|
-
return this.status?.info
|
|
183
|
+
return this.status?.info?.machineProvider;
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
get machineProviderDisplay() {
|
|
@@ -261,6 +261,22 @@ export default class MgmtCluster extends SteveModel {
|
|
|
261
261
|
return !!capiMachines;
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
+
get isCAPIProvider() {
|
|
265
|
+
if (!this.isCapiHybrid || !this.machineProvider) {
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const context = {
|
|
270
|
+
dispatch: this.$dispatch,
|
|
271
|
+
getters: this.$getters,
|
|
272
|
+
axios: this.$axios,
|
|
273
|
+
$extension: this.$extension,
|
|
274
|
+
t: (...args) => this.t.apply(this, args),
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
return isCAPIProvider(context, this.machineProvider.toLowerCase());
|
|
278
|
+
}
|
|
279
|
+
|
|
264
280
|
get isHostedKubernetesProvider() {
|
|
265
281
|
const context = {
|
|
266
282
|
dispatch: this.$dispatch,
|
|
@@ -10,7 +10,8 @@ import { notOnlyOfRole } from '@shell/models/cluster.x-k8s.io.machine';
|
|
|
10
10
|
const RKE1_ALLOWED_ACTIONS = [
|
|
11
11
|
'goToViewYaml',
|
|
12
12
|
'download',
|
|
13
|
-
'viewInApi'
|
|
13
|
+
'viewInApi',
|
|
14
|
+
'showConfiguration'
|
|
14
15
|
];
|
|
15
16
|
|
|
16
17
|
export default class MgmtNode extends HybridModel {
|
|
@@ -63,6 +64,10 @@ export default class MgmtNode extends HybridModel {
|
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
get pool() {
|
|
67
|
+
if (!this.spec?.nodePoolName) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
|
|
66
71
|
const nodePoolID = this.spec.nodePoolName.replace(':', '/');
|
|
67
72
|
|
|
68
73
|
return this.$rootGetters['management/byId'](MANAGEMENT.NODE_POOL, nodePoolID);
|
|
@@ -118,6 +123,42 @@ export default class MgmtNode extends HybridModel {
|
|
|
118
123
|
return this.status?.addresses || this.status?.internalNodeStatus?.addresses || [];
|
|
119
124
|
}
|
|
120
125
|
|
|
126
|
+
get internalIps() {
|
|
127
|
+
const internal = this.addresses.filter(({ type }) => {
|
|
128
|
+
return type === ADDRESSES.INTERNAL_IP;
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
if (!internal.length) {
|
|
132
|
+
// For RKE1 clusters in EC2, node addresses are
|
|
133
|
+
// under status.rkeNode.address and status.rkeNode.internalAddress
|
|
134
|
+
if (this.status?.rkeNode) {
|
|
135
|
+
return this.status.rkeNode.internalAddress ? [this.status.rkeNode.internalAddress] : [];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return internal.map(({ address }) => address);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
get externalIps() {
|
|
145
|
+
const external = this.addresses.filter(({ type }) => {
|
|
146
|
+
return type === ADDRESSES.EXTERNAL_IP;
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
if (!external.length) {
|
|
150
|
+
// For RKE1 clusters in EC2, node addresses are
|
|
151
|
+
// under status.rkeNode.address and status.rkeNode.internalAddress
|
|
152
|
+
if (this.status?.rkeNode) {
|
|
153
|
+
return this.status.rkeNode.address ? [this.status.rkeNode.address] : [];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return [];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return external.map(({ address }) => address);
|
|
160
|
+
}
|
|
161
|
+
|
|
121
162
|
get internalIp() {
|
|
122
163
|
// This shows in the IP address column for RKE1 nodes in the
|
|
123
164
|
// list of nodes in the cluster detail page of Cluster Management.
|
|
@@ -131,7 +172,7 @@ export default class MgmtNode extends HybridModel {
|
|
|
131
172
|
|
|
132
173
|
// For RKE1 clusters in EC2, node addresses are
|
|
133
174
|
// under status.rkeNode.address and status.rkeNode.internalAddress
|
|
134
|
-
if (!internal && this.status
|
|
175
|
+
if (!internal && this.status?.rkeNode) {
|
|
135
176
|
return this.status.rkeNode.internalAddress;
|
|
136
177
|
}
|
|
137
178
|
|
|
@@ -147,7 +188,7 @@ export default class MgmtNode extends HybridModel {
|
|
|
147
188
|
|
|
148
189
|
// For RKE1 clusters in EC2, node addresses are
|
|
149
190
|
// under status.rkeNode.address and status.rkeNode.internalAddress
|
|
150
|
-
if (!statusAddress && this.status
|
|
191
|
+
if (!statusAddress && this.status?.rkeNode) {
|
|
151
192
|
return this.status.rkeNode.address;
|
|
152
193
|
}
|
|
153
194
|
|
package/models/namespace.js
CHANGED
package/models/pod.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { insertAt } from '@shell/utils/array';
|
|
2
|
-
import { colorForState, stateDisplay } from '@shell/plugins/dashboard-store/resource-class';
|
|
2
|
+
import { colorForState, simpleColorForState, stateDisplay } from '@shell/plugins/dashboard-store/resource-class';
|
|
3
3
|
import { NODE, WORKLOAD_TYPES } from '@shell/config/types';
|
|
4
4
|
import { escapeHtml, shortenedImage } from '@shell/utils/string';
|
|
5
5
|
import WorkloadService from '@shell/models/workload.service';
|
|
6
6
|
import { deleteProperty } from '@shell/utils/object';
|
|
7
7
|
import { POD_RESTARTS_REG_EX } from '@shell/types/resources/pod';
|
|
8
|
+
import { useResourceCardRow } from '@shell/components/Resource/Detail/Card/StateCard/composables';
|
|
8
9
|
|
|
9
10
|
export const WORKLOAD_PRIORITY = {
|
|
10
11
|
[WORKLOAD_TYPES.DEPLOYMENT]: 1,
|
|
@@ -156,6 +157,37 @@ export default class Pod extends WorkloadService {
|
|
|
156
157
|
return initContainers.includes(container);
|
|
157
158
|
}
|
|
158
159
|
|
|
160
|
+
get resourceContainers() {
|
|
161
|
+
const statuses = [...(this.status?.containerStatuses || []), ...(this.status?.initContainerStatuses || [])];
|
|
162
|
+
|
|
163
|
+
return statuses.map((s) => {
|
|
164
|
+
const state = Object.keys(s.state || {})[0] || 'unknown';
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
stateDisplay: stateDisplay(state),
|
|
168
|
+
stateSimpleColor: simpleColorForState(state),
|
|
169
|
+
};
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
get resourcesCardRows() {
|
|
174
|
+
const rows = [...this._resourcesCardRows];
|
|
175
|
+
|
|
176
|
+
if (this.resourceContainers.length) {
|
|
177
|
+
rows.unshift(useResourceCardRow(this.t('workload.container.titles.containers'), this.resourceContainers, 'stateSimpleColor', 'stateDisplay', '#containers'));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return rows;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
get cards() {
|
|
184
|
+
return [
|
|
185
|
+
this.resourcesCard,
|
|
186
|
+
this.insightCard,
|
|
187
|
+
...this._cards
|
|
188
|
+
].filter((c) => c);
|
|
189
|
+
}
|
|
190
|
+
|
|
159
191
|
get imageNames() {
|
|
160
192
|
return this.spec.containers.map((container) => shortenedImage(container.image));
|
|
161
193
|
}
|
|
@@ -97,7 +97,7 @@ export default class ProvCluster extends SteveModel {
|
|
|
97
97
|
|
|
98
98
|
get canEdit() {
|
|
99
99
|
// If the cluster is a KEV1 cluster, Harvester cluster, or v2 provisioning cluster that uses upstream capi infrastructure providers, then prevent edit
|
|
100
|
-
if (this.isKev1 || this.isHarvester || this.
|
|
100
|
+
if (this.isKev1 || this.isHarvester || this.isCapiWithoutExtension) {
|
|
101
101
|
return false;
|
|
102
102
|
}
|
|
103
103
|
|
|
@@ -105,7 +105,7 @@ export default class ProvCluster extends SteveModel {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
get canCustomEdit() {
|
|
108
|
-
return !this.
|
|
108
|
+
return !this.isCapiWithoutExtension && super.canCustomEdit;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
get _availableActions() {
|
|
@@ -319,8 +319,8 @@ export default class ProvCluster extends SteveModel {
|
|
|
319
319
|
}
|
|
320
320
|
|
|
321
321
|
// identify v2 provisioning clusters created using upstream capi infrastructure providers instead of rancher/machine
|
|
322
|
-
get
|
|
323
|
-
return this.mgmt?.isCapiHybrid;
|
|
322
|
+
get isCapiWithoutExtension() {
|
|
323
|
+
return this.mgmt?.isCapiHybrid && !this.mgmt?.isCAPIProvider;
|
|
324
324
|
}
|
|
325
325
|
|
|
326
326
|
get mgmtClusterId() {
|
|
@@ -789,7 +789,7 @@ export default class ProvCluster extends SteveModel {
|
|
|
789
789
|
}
|
|
790
790
|
|
|
791
791
|
get disableResourceDetailDrawerConfigTab() {
|
|
792
|
-
return !!this.isHarvester || this.
|
|
792
|
+
return !!this.isHarvester || this.isCapiWithoutExtension;
|
|
793
793
|
}
|
|
794
794
|
|
|
795
795
|
get fullDetailPageOverride() {
|
package/models/workload.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { findBy, insertAt } from '@shell/utils/array';
|
|
2
2
|
import { CATTLE_PUBLIC_ENDPOINTS } from '@shell/config/labels-annotations';
|
|
3
|
-
import { WORKLOAD_TYPES, SERVICE, POD } from '@shell/config/types';
|
|
3
|
+
import { WORKLOAD_TYPES, SERVICE, INGRESS, POD } from '@shell/config/types';
|
|
4
4
|
import { set } from '@shell/utils/object';
|
|
5
5
|
import day from 'dayjs';
|
|
6
|
-
import { convertSelectorObj, parse, matches } from '@shell/utils/selector';
|
|
6
|
+
import { convertSelectorObj, parse, matches, convert } from '@shell/utils/selector';
|
|
7
7
|
import { SEPARATOR } from '@shell/config/workload';
|
|
8
8
|
import WorkloadService from '@shell/models/workload.service';
|
|
9
9
|
import { matching } from '@shell/utils/selector-typed';
|
|
@@ -586,6 +586,29 @@ export default class Workload extends WorkloadService {
|
|
|
586
586
|
return undefined;
|
|
587
587
|
}
|
|
588
588
|
|
|
589
|
+
async fetchSummaries() {
|
|
590
|
+
const summaries = { pods: null };
|
|
591
|
+
|
|
592
|
+
try {
|
|
593
|
+
if (this.podMatchExpression) {
|
|
594
|
+
summaries.pods = await this.$dispatch('fetchResourceSummary', {
|
|
595
|
+
type: POD,
|
|
596
|
+
opt: {
|
|
597
|
+
summaryField: 'metadata.state.name',
|
|
598
|
+
namespace: this.metadata.namespace,
|
|
599
|
+
labelSelector: { matchExpressions: this.podMatchExpression },
|
|
600
|
+
}
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
} catch (e) {
|
|
604
|
+
console.warn('fetchSummaries: failed to fetch pod summary', e); // eslint-disable-line no-console
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
set(this, '_summaries', summaries);
|
|
608
|
+
|
|
609
|
+
return summaries;
|
|
610
|
+
}
|
|
611
|
+
|
|
589
612
|
async unWatchPods() {
|
|
590
613
|
return await this.$dispatch('unwatch', { type: POD, all: true });
|
|
591
614
|
}
|
|
@@ -747,16 +770,70 @@ export default class Workload extends WorkloadService {
|
|
|
747
770
|
}
|
|
748
771
|
|
|
749
772
|
get relatedServices() {
|
|
750
|
-
|
|
773
|
+
if (this.type === WORKLOAD_TYPES.JOB || this.type === WORKLOAD_TYPES.CRON_JOB) {
|
|
774
|
+
return [];
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
const podTemplateLabels = this.spec?.template?.metadata?.labels;
|
|
778
|
+
|
|
779
|
+
if (!podTemplateLabels || Object.keys(podTemplateLabels).length === 0) {
|
|
780
|
+
return [];
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
const templateAsObj = { metadata: { labels: podTemplateLabels } };
|
|
784
|
+
|
|
751
785
|
return this.servicesInNamespace.filter((service) => {
|
|
752
786
|
const selector = service.spec.selector;
|
|
753
787
|
|
|
754
|
-
|
|
755
|
-
|
|
788
|
+
if (!selector || typeof selector !== 'object') {
|
|
789
|
+
return false;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
return matches(templateAsObj, convert(selector));
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
get matchingIngresses() {
|
|
797
|
+
const allIngresses = this.$rootGetters['cluster/all'](INGRESS);
|
|
798
|
+
const services = this.relatedServices;
|
|
756
799
|
|
|
757
|
-
|
|
758
|
-
|
|
800
|
+
if (!services.length) {
|
|
801
|
+
return [];
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
return allIngresses.filter((ingress) => {
|
|
805
|
+
try {
|
|
806
|
+
const rules = ingress.spec?.rules;
|
|
807
|
+
|
|
808
|
+
if (!rules || !Array.isArray(rules)) {
|
|
809
|
+
return false;
|
|
759
810
|
}
|
|
811
|
+
|
|
812
|
+
for (const rule of rules) {
|
|
813
|
+
const paths = rule?.http?.paths;
|
|
814
|
+
|
|
815
|
+
if (!paths || !Array.isArray(paths)) {
|
|
816
|
+
continue;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
for (const pathData of paths) {
|
|
820
|
+
const targetServiceName = pathData?.backend?.service?.name;
|
|
821
|
+
|
|
822
|
+
if (!targetServiceName) {
|
|
823
|
+
continue;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
for (const service of services) {
|
|
827
|
+
if (ingress.metadata?.namespace === this.metadata?.namespace && service?.metadata?.name === targetServiceName) {
|
|
828
|
+
return true;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
} catch (err) {
|
|
834
|
+
console.warn(`matchingIngresses: failed to match ingress "${ ingress.id }"`, err); // eslint-disable-line no-console
|
|
835
|
+
|
|
836
|
+
return false;
|
|
760
837
|
}
|
|
761
838
|
|
|
762
839
|
return false;
|
|
@@ -764,10 +841,23 @@ export default class Workload extends WorkloadService {
|
|
|
764
841
|
}
|
|
765
842
|
|
|
766
843
|
get resourcesCardRows() {
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
844
|
+
const rows = [...this._resourcesCardRows];
|
|
845
|
+
const showsIngressesAndServices = this.type !== WORKLOAD_TYPES.JOB && this.type !== WORKLOAD_TYPES.CRON_JOB;
|
|
846
|
+
|
|
847
|
+
if (showsIngressesAndServices) {
|
|
848
|
+
const services = this.relatedServices || [];
|
|
849
|
+
const ingresses = this.matchingIngresses || [];
|
|
850
|
+
|
|
851
|
+
if (ingresses.length) {
|
|
852
|
+
rows.unshift(useResourceCardRow(this.t('component.resource.detail.card.resourcesCard.rows.ingresses'), ingresses, undefined, undefined, '#ingresses'));
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
if (services.length) {
|
|
856
|
+
rows.unshift(useResourceCardRow(this.t('component.resource.detail.card.resourcesCard.rows.services'), services, undefined, undefined, '#services'));
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
return rows;
|
|
771
861
|
}
|
|
772
862
|
|
|
773
863
|
get podsCard() {
|
|
@@ -779,8 +869,11 @@ export default class Workload extends WorkloadService {
|
|
|
779
869
|
|
|
780
870
|
const scalingTypes = [WORKLOAD_TYPES.DEPLOYMENT, WORKLOAD_TYPES.STATEFUL_SET];
|
|
781
871
|
const canScale = this.canUpdate && scalingTypes.includes(this.type);
|
|
872
|
+
const summaryData = this._summaries?.pods || null;
|
|
873
|
+
const hasPods = this.pods?.length > 0;
|
|
874
|
+
const hasSummary = summaryData?.count > 0;
|
|
782
875
|
|
|
783
|
-
if (!
|
|
876
|
+
if (!hasPods && !hasSummary && !canScale) {
|
|
784
877
|
return null;
|
|
785
878
|
}
|
|
786
879
|
|
|
@@ -789,6 +882,7 @@ export default class Workload extends WorkloadService {
|
|
|
789
882
|
props: {
|
|
790
883
|
title: this.t('component.resource.detail.card.podsCard.title'),
|
|
791
884
|
resources: this.pods,
|
|
885
|
+
summaryData,
|
|
792
886
|
showScaling: canScale,
|
|
793
887
|
onIncrease: () => this.scale(true),
|
|
794
888
|
onDecrease: () => this.scale(false),
|
|
@@ -818,8 +912,9 @@ export default class Workload extends WorkloadService {
|
|
|
818
912
|
return [
|
|
819
913
|
this.podsCard,
|
|
820
914
|
this.jobsCard,
|
|
915
|
+
this.resourcesCard,
|
|
821
916
|
this.insightCard,
|
|
822
917
|
...this._cards
|
|
823
|
-
];
|
|
918
|
+
].filter((c) => c);
|
|
824
919
|
}
|
|
825
920
|
}
|
|
@@ -5,8 +5,13 @@ import { WORKLOAD_TYPES, SERVICE } from '@shell/config/types';
|
|
|
5
5
|
import { clone, get } from '@shell/utils/object';
|
|
6
6
|
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
7
7
|
import { shortenedImage } from '@shell/utils/string';
|
|
8
|
+
import { stateDisplay } from '@shell/plugins/dashboard-store/resource-class';
|
|
8
9
|
|
|
9
10
|
export default class WorkloadService extends SteveModel {
|
|
11
|
+
get stateDisplay() {
|
|
12
|
+
return stateDisplay(this.state, true);
|
|
13
|
+
}
|
|
14
|
+
|
|
10
15
|
async getPortsWithServiceType() {
|
|
11
16
|
const ports = [];
|
|
12
17
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rancher/shell",
|
|
3
|
-
"version": "3.0.12-rc.
|
|
3
|
+
"version": "3.0.12-rc.4",
|
|
4
4
|
"description": "Rancher Dashboard Shell",
|
|
5
5
|
"repository": "https://github.com/rancher/dashboard",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -33,13 +33,14 @@
|
|
|
33
33
|
"@babel/preset-typescript": "7.16.7",
|
|
34
34
|
"@novnc/novnc": "1.2.0",
|
|
35
35
|
"@popperjs/core": "2.11.8",
|
|
36
|
-
"@rancher/icons": "2.0.
|
|
36
|
+
"@rancher/icons": "2.0.62",
|
|
37
37
|
"@smithy/fetch-http-handler": "5.1.1",
|
|
38
38
|
"@types/is-url": "1.2.30",
|
|
39
39
|
"@types/node": "25.3.3",
|
|
40
40
|
"@types/semver": "^7.5.8",
|
|
41
41
|
"@typescript-eslint/eslint-plugin": "5.62.0",
|
|
42
42
|
"@typescript-eslint/parser": "5.62.0",
|
|
43
|
+
"@vee-validate/zod": "4.15.0",
|
|
43
44
|
"@vue/cli-plugin-babel": "~5.0.0",
|
|
44
45
|
"@vue/cli-plugin-typescript": "~5.0.0",
|
|
45
46
|
"@vue/cli-service": "5.0.8",
|
|
@@ -47,7 +48,7 @@
|
|
|
47
48
|
"@vue/vue3-jest": "27.0.0",
|
|
48
49
|
"add": "2.0.6",
|
|
49
50
|
"ansi_up": "5.0.0",
|
|
50
|
-
"axios": "1.
|
|
51
|
+
"axios": "1.16.0",
|
|
51
52
|
"axios-retry": "3.1.9",
|
|
52
53
|
"babel-eslint": "10.1.0",
|
|
53
54
|
"babel-preset-vue": "2.0.2",
|
|
@@ -80,14 +81,13 @@
|
|
|
80
81
|
"eslint-plugin-n": "15.2.0",
|
|
81
82
|
"eslint-plugin-vue": "9.32.0",
|
|
82
83
|
"event-target-shim": "5.0.1",
|
|
83
|
-
"express": "4.
|
|
84
|
-
"file-saver": "2.0.
|
|
84
|
+
"express": "4.22.2",
|
|
85
|
+
"file-saver": "2.0.5",
|
|
85
86
|
"floating-vue": "5.2.2",
|
|
86
87
|
"focus-trap": "7.6.5",
|
|
87
88
|
"frontmatter-markdown-loader": "3.7.0",
|
|
88
89
|
"identicon.js": "2.3.3",
|
|
89
90
|
"intl-messageformat": "7.8.4",
|
|
90
|
-
"ip": "2.0.1",
|
|
91
91
|
"is-url": "1.2.4",
|
|
92
92
|
"jest": "27.5.1",
|
|
93
93
|
"jest-serializer-vue": "2.0.2",
|
|
@@ -124,12 +124,13 @@
|
|
|
124
124
|
"webpack-virtual-modules": "0.6.2",
|
|
125
125
|
"worker-loader": "3.0.8",
|
|
126
126
|
"xmlbuilder2": "4.0.1",
|
|
127
|
-
"
|
|
128
|
-
"xterm
|
|
129
|
-
"xterm
|
|
130
|
-
"xterm
|
|
131
|
-
"xterm
|
|
132
|
-
"xterm
|
|
127
|
+
"zod": "3.24.3",
|
|
128
|
+
"@xterm/xterm": "6.0.0",
|
|
129
|
+
"@xterm/addon-fit": "0.11.0",
|
|
130
|
+
"@xterm/addon-search": "0.16.0",
|
|
131
|
+
"@xterm/addon-web-links": "0.12.0",
|
|
132
|
+
"@xterm/addon-webgl": "0.19.0",
|
|
133
|
+
"@xterm/addon-canvas": "0.7.0",
|
|
133
134
|
"yarn": "1.22.22"
|
|
134
135
|
},
|
|
135
136
|
"resolutions": {
|
|
@@ -142,7 +143,7 @@
|
|
|
142
143
|
"merge": "2.1.1",
|
|
143
144
|
"node-forge": "1.3.1",
|
|
144
145
|
"nth-check": "2.1.1",
|
|
145
|
-
"qs": "6.
|
|
146
|
+
"qs": "6.15.2",
|
|
146
147
|
"roarr": "7.0.4",
|
|
147
148
|
"semver": "7.5.4",
|
|
148
149
|
"@types/lodash": "4.17.5",
|
package/pages/about.vue
CHANGED
|
@@ -10,10 +10,11 @@ import TabTitle from '@shell/components/TabTitle';
|
|
|
10
10
|
import { PanelLocation, ExtensionPoint } from '@shell/core/types';
|
|
11
11
|
import ExtensionPanel from '@shell/components/ExtensionPanel';
|
|
12
12
|
import { getVersionInfo } from '@shell/utils/version';
|
|
13
|
+
import { RcButton } from '@components/RcButton';
|
|
13
14
|
|
|
14
15
|
export default {
|
|
15
16
|
components: {
|
|
16
|
-
BackLink, ExtensionPanel, Loading, TabTitle
|
|
17
|
+
BackLink, ExtensionPanel, Loading, TabTitle, RcButton
|
|
17
18
|
},
|
|
18
19
|
mixins: [BackRoute],
|
|
19
20
|
async fetch() {
|
|
@@ -85,16 +86,14 @@ export default {
|
|
|
85
86
|
{{ t('about.title') }}
|
|
86
87
|
</TabTitle>
|
|
87
88
|
</h1>
|
|
88
|
-
<
|
|
89
|
+
<rc-button
|
|
90
|
+
size="large"
|
|
89
91
|
:to="{ name: 'diagnostic' }"
|
|
90
|
-
class="btn role-primary"
|
|
91
92
|
data-testid="about__diagnostics_button"
|
|
92
|
-
role="button"
|
|
93
93
|
:aria-label="t('about.diagnostic.title')"
|
|
94
|
-
@keyup.space="$router.push({ name: 'diagnostic' })"
|
|
95
94
|
>
|
|
96
95
|
{{ t('about.diagnostic.title') }}
|
|
97
|
-
</
|
|
96
|
+
</rc-button>
|
|
98
97
|
</div>
|
|
99
98
|
<!-- Extensions area -->
|
|
100
99
|
<ExtensionPanel
|
package/pages/auth/login.vue
CHANGED
|
@@ -410,41 +410,6 @@ export default {
|
|
|
410
410
|
k="setup.defaultPassword.intro"
|
|
411
411
|
:raw="true"
|
|
412
412
|
/>
|
|
413
|
-
|
|
414
|
-
<div>
|
|
415
|
-
<t
|
|
416
|
-
k="setup.defaultPassword.dockerPrefix"
|
|
417
|
-
:raw="true"
|
|
418
|
-
/>
|
|
419
|
-
</div>
|
|
420
|
-
<ul>
|
|
421
|
-
<li>
|
|
422
|
-
<t
|
|
423
|
-
k="setup.defaultPassword.dockerPs"
|
|
424
|
-
:raw="true"
|
|
425
|
-
/>
|
|
426
|
-
</li>
|
|
427
|
-
<li>
|
|
428
|
-
<CopyCode>
|
|
429
|
-
docker logs <u>container-id</u> 2>&1 | grep "Bootstrap Password:"
|
|
430
|
-
</CopyCode>
|
|
431
|
-
</li>
|
|
432
|
-
</ul>
|
|
433
|
-
<div>
|
|
434
|
-
<t
|
|
435
|
-
k="setup.defaultPassword.dockerSuffix"
|
|
436
|
-
:raw="true"
|
|
437
|
-
/>
|
|
438
|
-
</div>
|
|
439
|
-
|
|
440
|
-
<br>
|
|
441
|
-
<div>
|
|
442
|
-
<t
|
|
443
|
-
k="setup.defaultPassword.helmPrefix"
|
|
444
|
-
:raw="true"
|
|
445
|
-
/>
|
|
446
|
-
</div>
|
|
447
|
-
<br>
|
|
448
413
|
<CopyCode>
|
|
449
414
|
{{ kubectlCmd }}
|
|
450
415
|
</CopyCode>
|
package/pages/auth/setup.vue
CHANGED
|
@@ -20,6 +20,7 @@ import FormValidation from '@shell/mixins/form-validation';
|
|
|
20
20
|
import { isLocalhost, isValidUrl } from '@shell/utils/validators/setting';
|
|
21
21
|
import Loading from '@shell/components/Loading';
|
|
22
22
|
import { getBrandMeta } from '@shell/utils/brand';
|
|
23
|
+
import { findMe } from '@shell/utils/auth';
|
|
23
24
|
|
|
24
25
|
const calcIsFirstLogin = (store) => {
|
|
25
26
|
const firstLoginSetting = store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.FIRST_LOGIN);
|
|
@@ -77,6 +78,16 @@ export default {
|
|
|
77
78
|
// Always show setup if this is the first log in
|
|
78
79
|
return;
|
|
79
80
|
} else if (mustChangePassword) {
|
|
81
|
+
// Skip password change for non-local sessions
|
|
82
|
+
try {
|
|
83
|
+
const me = await findMe(this.$store);
|
|
84
|
+
|
|
85
|
+
if (me && me.provider !== 'local') {
|
|
86
|
+
return this.$router.replace('/');
|
|
87
|
+
}
|
|
88
|
+
} catch (e) {
|
|
89
|
+
}
|
|
90
|
+
|
|
80
91
|
// If the password needs changing and this isn't the first log in ensure we have the password
|
|
81
92
|
if (!!this.$store.getters['auth/initialPass']) {
|
|
82
93
|
// Got it... show setup
|
|
@@ -3,7 +3,7 @@ import { reactive } from 'vue';
|
|
|
3
3
|
import { RcItemCardAction } from '@components/RcItemCard';
|
|
4
4
|
import { RcButton } from '@components/RcButton';
|
|
5
5
|
import { isTruncated } from '@shell/utils/style';
|
|
6
|
-
import RcIcon from '@components/RcIcon
|
|
6
|
+
import { RcIcon } from '@components/RcIcon';
|
|
7
7
|
import type { RcIconType } from '@components/RcIcon/types';
|
|
8
8
|
|
|
9
9
|
interface FooterItem {
|
|
@@ -195,7 +195,7 @@ function getTooltip(key: string, fallback?: string): string | undefined {
|
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
button.variant-ghost.app-chart-card-footer-button {
|
|
198
|
+
button.rc-button.variant-ghost.app-chart-card-footer-button {
|
|
199
199
|
padding: 0;
|
|
200
200
|
gap: 0;
|
|
201
201
|
min-height: 20px;
|
|
@@ -9,12 +9,16 @@ interface SubHeaderItem {
|
|
|
9
9
|
|
|
10
10
|
defineProps<{
|
|
11
11
|
items: SubHeaderItem[];
|
|
12
|
+
removeMarginBottom?: boolean;
|
|
12
13
|
}>();
|
|
13
14
|
|
|
14
15
|
</script>
|
|
15
16
|
|
|
16
17
|
<template>
|
|
17
|
-
<div
|
|
18
|
+
<div
|
|
19
|
+
class="app-chart-card-sub-header"
|
|
20
|
+
:class="{ 'no-margin-bottom': removeMarginBottom }"
|
|
21
|
+
>
|
|
18
22
|
<div
|
|
19
23
|
v-for="(subHeaderItem, i) in items"
|
|
20
24
|
:key="i"
|
|
@@ -38,8 +42,13 @@ defineProps<{
|
|
|
38
42
|
flex-wrap: wrap;
|
|
39
43
|
gap: var(--gap) var(--gap-md);
|
|
40
44
|
color: var(--link-text-secondary);
|
|
45
|
+
height: 22px;
|
|
41
46
|
margin-bottom: 8px;
|
|
42
47
|
|
|
48
|
+
&.no-margin-bottom {
|
|
49
|
+
margin-bottom: 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
43
52
|
&-item {
|
|
44
53
|
display: flex;
|
|
45
54
|
align-items: center;
|