@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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import isEmpty from 'lodash/isEmpty';
|
|
3
|
+
import throttle from 'lodash/throttle';
|
|
3
4
|
import { createYamlWithOptions } from '@shell/utils/create-yaml';
|
|
4
5
|
import { clone, get } from '@shell/utils/object';
|
|
5
6
|
import { SCHEMA, NAMESPACE } from '@shell/config/types';
|
|
@@ -11,6 +12,10 @@ import { stringify, exceptionToErrorsArray } from '@shell/utils/error';
|
|
|
11
12
|
import CruResourceFooter from '@shell/components/CruResourceFooter';
|
|
12
13
|
import { useResourceCreatePageProvider, useResourceEditPageProvider } from '@shell/composables/cruResource';
|
|
13
14
|
|
|
15
|
+
import { useFormSummary } from '@shell/components/TableOfContents/composables';
|
|
16
|
+
import { useTemplateRef } from 'vue';
|
|
17
|
+
import TableOfContents from '@shell/components/TableOfContents/TableOfContents.vue';
|
|
18
|
+
|
|
14
19
|
import {
|
|
15
20
|
_EDIT, _VIEW, AS, _YAML, _UNFLAG, SUB_TYPE, _CREATE
|
|
16
21
|
} from '@shell/config/query-params';
|
|
@@ -31,7 +36,8 @@ export default {
|
|
|
31
36
|
Banner,
|
|
32
37
|
CruResourceFooter,
|
|
33
38
|
ResourceYaml,
|
|
34
|
-
Wizard
|
|
39
|
+
Wizard,
|
|
40
|
+
TableOfContents
|
|
35
41
|
},
|
|
36
42
|
|
|
37
43
|
props: {
|
|
@@ -162,9 +168,22 @@ export default {
|
|
|
162
168
|
yamlModifiers: {
|
|
163
169
|
type: Object,
|
|
164
170
|
default: undefined
|
|
171
|
+
},
|
|
172
|
+
|
|
173
|
+
showToc: {
|
|
174
|
+
type: Boolean,
|
|
175
|
+
default: false
|
|
165
176
|
}
|
|
166
177
|
},
|
|
167
178
|
|
|
179
|
+
setup() {
|
|
180
|
+
const cruFormRef = useTemplateRef('cru-form');
|
|
181
|
+
const { locatedComponents } = useFormSummary(cruFormRef);
|
|
182
|
+
const accordions = locatedComponents;
|
|
183
|
+
|
|
184
|
+
return { accordions };
|
|
185
|
+
},
|
|
186
|
+
|
|
168
187
|
data(props) {
|
|
169
188
|
const inStore = this.$store.getters['currentStore'](this.resource);
|
|
170
189
|
const schema = this.$store.getters[`${ inStore }/schemaFor`](this.resource.type);
|
|
@@ -176,27 +195,30 @@ export default {
|
|
|
176
195
|
}
|
|
177
196
|
|
|
178
197
|
return {
|
|
179
|
-
isCancelModal:
|
|
180
|
-
showAsForm:
|
|
198
|
+
isCancelModal: false,
|
|
199
|
+
showAsForm: this.$route.query[AS] !== _YAML,
|
|
200
|
+
tocContainerHeight: 0,
|
|
201
|
+
mainLayoutEl: null,
|
|
202
|
+
throttledComputeTocContainerHeight: null,
|
|
181
203
|
/**
|
|
182
204
|
* Initialised on demand (given that it needs to make a request to fetch schema definition)
|
|
183
205
|
*/
|
|
184
|
-
resourceYaml:
|
|
206
|
+
resourceYaml: null,
|
|
185
207
|
/**
|
|
186
208
|
* Initialised on demand (given that it needs to make a request to fetch schema definition)
|
|
187
209
|
*/
|
|
188
|
-
initialYaml:
|
|
210
|
+
initialYaml: null,
|
|
189
211
|
/**
|
|
190
212
|
* Save a copy of the initial resource. This is used to calc the initial yaml later on
|
|
191
213
|
*/
|
|
192
|
-
initialResource:
|
|
193
|
-
abbrSizes:
|
|
214
|
+
initialResource: clone(this.resource),
|
|
215
|
+
abbrSizes: {
|
|
194
216
|
3: '24px',
|
|
195
217
|
4: '18px',
|
|
196
218
|
5: '16px',
|
|
197
219
|
6: '14px'
|
|
198
220
|
},
|
|
199
|
-
schema
|
|
221
|
+
schema,
|
|
200
222
|
};
|
|
201
223
|
},
|
|
202
224
|
|
|
@@ -276,10 +298,11 @@ export default {
|
|
|
276
298
|
icon: null
|
|
277
299
|
}
|
|
278
300
|
}), {});
|
|
279
|
-
}
|
|
301
|
+
}
|
|
280
302
|
},
|
|
281
303
|
|
|
282
304
|
created() {
|
|
305
|
+
this.throttledComputeTocContainerHeight = throttle(this.computeTocContainerHeight, 20);
|
|
283
306
|
if ( this._selectedSubtype ) {
|
|
284
307
|
this.$emit('select-type', this._selectedSubtype);
|
|
285
308
|
}
|
|
@@ -290,12 +313,42 @@ export default {
|
|
|
290
313
|
},
|
|
291
314
|
|
|
292
315
|
beforeUnmount() {
|
|
316
|
+
this.mainLayoutEl?.removeEventListener('scroll', this.throttledComputeTocContainerHeight);
|
|
317
|
+
window.removeEventListener('resize', this.throttledComputeTocContainerHeight);
|
|
318
|
+
this.throttledComputeTocContainerHeight?.cancel?.();
|
|
293
319
|
this.$store.dispatch('cru-resource/setCreateNamespace', false);
|
|
294
320
|
},
|
|
295
321
|
|
|
296
322
|
methods: {
|
|
297
323
|
stringify,
|
|
298
324
|
|
|
325
|
+
// as the user scrolls past the CruResource Masthead, the amount of vertical space available to the table of contents changes
|
|
326
|
+
computeTocContainerHeight() {
|
|
327
|
+
const root = this.$el;
|
|
328
|
+
|
|
329
|
+
if (!root) {
|
|
330
|
+
this.tocContainerHeight = 0;
|
|
331
|
+
|
|
332
|
+
return 0;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const tocEl = root.querySelector('.cru__toc');
|
|
336
|
+
const footerEl = root.querySelector('.cru__footer');
|
|
337
|
+
|
|
338
|
+
if (!tocEl || !footerEl) {
|
|
339
|
+
this.tocContainerHeight = 0;
|
|
340
|
+
|
|
341
|
+
return 0;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const tocTop = tocEl.getBoundingClientRect().top;
|
|
345
|
+
const footerTop = footerEl.getBoundingClientRect().top;
|
|
346
|
+
const gapLgValue = getComputedStyle(root).getPropertyValue('--gap-lg').trim();
|
|
347
|
+
const gapLg = Number.parseFloat(gapLgValue) || 0;
|
|
348
|
+
|
|
349
|
+
this.tocContainerHeight = Math.max(0, Math.round((footerTop - tocTop) - gapLg));
|
|
350
|
+
},
|
|
351
|
+
|
|
299
352
|
confirmCancel(isCancelNotBack = true) {
|
|
300
353
|
if (isCancelNotBack) {
|
|
301
354
|
this.emitOrRoute();
|
|
@@ -532,13 +585,38 @@ export default {
|
|
|
532
585
|
this.initialYaml = await this.createResourceYaml(undefined, this.initialResource);
|
|
533
586
|
}
|
|
534
587
|
}
|
|
588
|
+
},
|
|
589
|
+
|
|
590
|
+
showToc: {
|
|
591
|
+
handler(neu, old) {
|
|
592
|
+
if (neu) {
|
|
593
|
+
// Compute height on first render
|
|
594
|
+
this.$nextTick(() => {
|
|
595
|
+
this.throttledComputeTocContainerHeight?.();
|
|
596
|
+
});
|
|
597
|
+
// Add event listeners for computeTocContainerHeight on scroll
|
|
598
|
+
this.mainLayoutEl = document.querySelector('.main-layout');
|
|
599
|
+
this.mainLayoutEl?.addEventListener('scroll', this.throttledComputeTocContainerHeight, { passive: true });
|
|
600
|
+
// Add event listener for computeTocContainerHeight on window resize
|
|
601
|
+
window.addEventListener('resize', this.throttledComputeTocContainerHeight, { passive: true });
|
|
602
|
+
} else if (old) {
|
|
603
|
+
// Remove event listeners for computeTocContainerHeight when TOC is hidden
|
|
604
|
+
this.mainLayoutEl?.removeEventListener('scroll', this.throttledComputeTocContainerHeight);
|
|
605
|
+
window.removeEventListener('resize', this.throttledComputeTocContainerHeight);
|
|
606
|
+
}
|
|
607
|
+
},
|
|
608
|
+
immediate: true
|
|
535
609
|
}
|
|
536
610
|
}
|
|
537
611
|
};
|
|
538
612
|
</script>
|
|
539
613
|
|
|
540
614
|
<template>
|
|
541
|
-
<section
|
|
615
|
+
<section
|
|
616
|
+
ref="cru-form"
|
|
617
|
+
:class="{'show-toc':showToc}"
|
|
618
|
+
class="cru"
|
|
619
|
+
>
|
|
542
620
|
<slot name="noticeBanner" />
|
|
543
621
|
<p
|
|
544
622
|
v-if="description"
|
|
@@ -548,6 +626,7 @@ export default {
|
|
|
548
626
|
</p>
|
|
549
627
|
<component
|
|
550
628
|
:is="(isView? 'div' : 'form')"
|
|
629
|
+
|
|
551
630
|
:value="resource"
|
|
552
631
|
data-testid="cru-form"
|
|
553
632
|
class="create-resource-container cru__form"
|
|
@@ -771,15 +850,23 @@ export default {
|
|
|
771
850
|
</template>
|
|
772
851
|
<!------ SINGLE PROCESS ------>
|
|
773
852
|
<template v-else-if="showAsForm">
|
|
853
|
+
<TableOfContents
|
|
854
|
+
v-if="showToc"
|
|
855
|
+
class="cru__toc"
|
|
856
|
+
:style="tocContainerHeight ? { '--toc-container-height': `${tocContainerHeight}px` } : {}"
|
|
857
|
+
:accordions="accordions"
|
|
858
|
+
/>
|
|
774
859
|
<div
|
|
775
860
|
v-if="_selectedSubtype || !subtypes.length"
|
|
776
|
-
class="resource-container
|
|
861
|
+
class="cru__content resource-container"
|
|
862
|
+
|
|
777
863
|
:style="[minHeight ? { 'min-height': minHeight } : {}]"
|
|
778
864
|
>
|
|
779
865
|
<slot name="single">
|
|
780
866
|
<slot />
|
|
781
867
|
</slot>
|
|
782
868
|
</div>
|
|
869
|
+
|
|
783
870
|
<slot name="form-footer">
|
|
784
871
|
<CruResourceFooter
|
|
785
872
|
v-if="!isView"
|
|
@@ -912,6 +999,11 @@ export default {
|
|
|
912
999
|
</template>
|
|
913
1000
|
|
|
914
1001
|
<style lang='scss' scoped>
|
|
1002
|
+
$logo: 60px;
|
|
1003
|
+
$logo-space: 100px;
|
|
1004
|
+
|
|
1005
|
+
$table-contents-width: 250px;
|
|
1006
|
+
|
|
915
1007
|
.cru-resource-yaml-container {
|
|
916
1008
|
.resource-yaml {
|
|
917
1009
|
.yaml-editor {
|
|
@@ -937,9 +1029,6 @@ export default {
|
|
|
937
1029
|
}
|
|
938
1030
|
}
|
|
939
1031
|
|
|
940
|
-
$logo: 60px;
|
|
941
|
-
$logo-space: 100px;
|
|
942
|
-
|
|
943
1032
|
.title {
|
|
944
1033
|
margin-top: 20px;
|
|
945
1034
|
|
|
@@ -992,10 +1081,26 @@ form.create-resource-container .cru {
|
|
|
992
1081
|
display: flex;
|
|
993
1082
|
flex-direction: column;
|
|
994
1083
|
flex-grow: 1;
|
|
1084
|
+
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
&__toc {
|
|
1088
|
+
width: $table-contents-width;
|
|
1089
|
+
margin: 20px var(--gap-lg) 20px var(--gap-lg);
|
|
1090
|
+
min-width: $table-contents-width;
|
|
1091
|
+
max-width: $table-contents-width;
|
|
1092
|
+
position: sticky;
|
|
1093
|
+
top: 24px;
|
|
1094
|
+
align-self: flex-start;
|
|
1095
|
+
max-height: var(--toc-container-height, calc(100vh - 24px - $footer-height - calc( 2 * var(--gap-lg)) - 125px));
|
|
1096
|
+
transition: max-height 50ms ease-in-out;
|
|
1097
|
+
overflow-y: auto;
|
|
1098
|
+
overflow-x: hidden;
|
|
995
1099
|
}
|
|
996
1100
|
|
|
997
1101
|
&__content {
|
|
998
1102
|
flex-grow: 1;
|
|
1103
|
+
|
|
999
1104
|
&-wizard {
|
|
1000
1105
|
display: flex;
|
|
1001
1106
|
}
|
|
@@ -1025,6 +1130,48 @@ form.create-resource-container .cru {
|
|
|
1025
1130
|
}
|
|
1026
1131
|
}
|
|
1027
1132
|
|
|
1133
|
+
.show-toc.cru{
|
|
1134
|
+
&>.cru__form{
|
|
1135
|
+
display: grid;
|
|
1136
|
+
grid-template-columns: [content] 1fr [toc] calc(#{$table-contents-width} + var(--gap-lg));
|
|
1137
|
+
grid-template-rows: [errors] auto [content] 1fr [footer] min-content;
|
|
1138
|
+
|
|
1139
|
+
&>.cru__errors {
|
|
1140
|
+
grid-column: content;
|
|
1141
|
+
grid-row: errors;
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
&>.cru__toc {
|
|
1145
|
+
grid-column: toc;
|
|
1146
|
+
grid-row: errors / footer;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
&>.cru__content {
|
|
1150
|
+
grid-column: content;
|
|
1151
|
+
grid-row: content;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
&>.cru__footer {
|
|
1155
|
+
grid-column: content / 3;
|
|
1156
|
+
grid-row: footer;
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
@media (max-width: map-get($breakpoints, '--viewport-9')) {
|
|
1162
|
+
.show-toc.cru {
|
|
1163
|
+
& > .cru__form {
|
|
1164
|
+
display: flex;
|
|
1165
|
+
grid-template-columns: none;
|
|
1166
|
+
grid-template-rows: none;
|
|
1167
|
+
|
|
1168
|
+
& > .cru__toc {
|
|
1169
|
+
display: none;
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1028
1175
|
.description {
|
|
1029
1176
|
margin-bottom: 15px;
|
|
1030
1177
|
margin-top: 5px;
|
|
@@ -12,6 +12,7 @@ import { mapGetters } from 'vuex';
|
|
|
12
12
|
import { canViewProjectMembershipEditor } from '@shell/components/form/Members/ProjectMembershipEditor.vue';
|
|
13
13
|
import { allHash } from '@shell/utils/promise';
|
|
14
14
|
import { HARVESTER_NAME as HARVESTER } from '@shell/config/features';
|
|
15
|
+
import { RcButton } from '@components/RcButton';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Explorer members page.
|
|
@@ -26,7 +27,8 @@ export default {
|
|
|
26
27
|
ResourceTable,
|
|
27
28
|
Tabbed,
|
|
28
29
|
Tab,
|
|
29
|
-
SortableTable
|
|
30
|
+
SortableTable,
|
|
31
|
+
RcButton,
|
|
30
32
|
},
|
|
31
33
|
|
|
32
34
|
props: {
|
|
@@ -308,12 +310,14 @@ export default {
|
|
|
308
310
|
v-if="canEditClusterMembers"
|
|
309
311
|
class="row mb-10 cluster-add"
|
|
310
312
|
>
|
|
311
|
-
<
|
|
313
|
+
<rc-button
|
|
314
|
+
size="large"
|
|
315
|
+
class="pull-right"
|
|
316
|
+
data-testid="button-cluster-member-add"
|
|
312
317
|
:to="createLocation"
|
|
313
|
-
class="btn role-primary pull-right"
|
|
314
318
|
>
|
|
315
319
|
{{ t('members.createActionLabel') }}
|
|
316
|
-
</
|
|
320
|
+
</rc-button>
|
|
317
321
|
</div>
|
|
318
322
|
<ResourceTable
|
|
319
323
|
:schema="schema"
|
|
@@ -20,6 +20,7 @@ import { HARVESTER_NAME as HARVESTER } from '@shell/config/features';
|
|
|
20
20
|
import perfSettingsUtils from '@shell/utils/perf-setting.utils';
|
|
21
21
|
import ActionMenu from '@shell/components/ActionMenuShell.vue';
|
|
22
22
|
import { useRuntimeFlag } from '@shell/composables/useRuntimeFlag';
|
|
23
|
+
import { RcButton } from '@components/RcButton';
|
|
23
24
|
|
|
24
25
|
export default {
|
|
25
26
|
name: 'ListProjectNamespace',
|
|
@@ -29,6 +30,7 @@ export default {
|
|
|
29
30
|
ResourceTable,
|
|
30
31
|
ButtonMultiAction,
|
|
31
32
|
ActionMenu,
|
|
33
|
+
RcButton
|
|
32
34
|
},
|
|
33
35
|
mixins: [ResourceFetch],
|
|
34
36
|
|
|
@@ -445,13 +447,14 @@ export default {
|
|
|
445
447
|
v-if="showCreateNsButton"
|
|
446
448
|
#extraActions
|
|
447
449
|
>
|
|
448
|
-
<
|
|
450
|
+
<rc-button
|
|
451
|
+
size="large"
|
|
452
|
+
class="mr-10"
|
|
449
453
|
:to="createNamespaceLocationFlatList()"
|
|
450
|
-
class="btn role-primary mr-10"
|
|
451
454
|
data-testid="create_project_namespaces"
|
|
452
455
|
>
|
|
453
456
|
{{ t('projectNamespaces.createNamespace') }}
|
|
454
|
-
</
|
|
457
|
+
</rc-button>
|
|
455
458
|
</template>
|
|
456
459
|
</Masthead>
|
|
457
460
|
<!-- Extensions area -->
|
|
@@ -495,13 +498,14 @@ export default {
|
|
|
495
498
|
</div>
|
|
496
499
|
</div>
|
|
497
500
|
<div class="right mr-10">
|
|
498
|
-
<
|
|
501
|
+
<rc-button
|
|
499
502
|
v-if="isNamespaceCreatable && (canSeeProjectlessNamespaces || group.group.key !== notInProjectKey)"
|
|
500
|
-
|
|
503
|
+
variant="secondary"
|
|
504
|
+
class="mr-5"
|
|
501
505
|
:to="createNamespaceLocation(group.group)"
|
|
502
506
|
>
|
|
503
507
|
{{ t('projectNamespaces.createNamespace') }}
|
|
504
|
-
</
|
|
508
|
+
</rc-button>
|
|
505
509
|
<template v-if="featureDropdownMenu">
|
|
506
510
|
<ActionMenu
|
|
507
511
|
v-if="showProjectActionButton(group.group)"
|
|
@@ -204,6 +204,10 @@ export default {
|
|
|
204
204
|
> P {
|
|
205
205
|
padding-top: 2px;
|
|
206
206
|
|
|
207
|
+
// Limit size of message and scroll just the message, not the entire growl, so that the title and icon are always visible
|
|
208
|
+
max-height: 200px;
|
|
209
|
+
overflow-y: scroll;
|
|
210
|
+
|
|
207
211
|
&.has-title {
|
|
208
212
|
margin-top: 5px;
|
|
209
213
|
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { MANAGEMENT } from '@shell/config/types';
|
|
3
|
+
import ResourceTable from '@shell/components/ResourceTable';
|
|
4
|
+
import {
|
|
5
|
+
INTERNAL_EXTERNAL_IP,
|
|
6
|
+
STATE, NAME as NAME_COL, AGE, MANAGEMENT_NODE_OS
|
|
7
|
+
} from '@shell/config/table-headers';
|
|
8
|
+
|
|
9
|
+
// exclude roles column - it is not necessarily used (or used the same way) outside of Rancher provisioning
|
|
10
|
+
export const DEFAULT_HEADERS = [STATE, {
|
|
11
|
+
...NAME_COL,
|
|
12
|
+
value: 'status.nodeName',
|
|
13
|
+
formatterOpts: { reference: 'kubeNodeDetailLocation' }
|
|
14
|
+
}, INTERNAL_EXTERNAL_IP, MANAGEMENT_NODE_OS, AGE];
|
|
15
|
+
|
|
16
|
+
export default {
|
|
17
|
+
name: 'ClusterScopedManagementNodeList',
|
|
18
|
+
|
|
19
|
+
components: { ResourceTable },
|
|
20
|
+
|
|
21
|
+
props: {
|
|
22
|
+
resource: {
|
|
23
|
+
type: Object,
|
|
24
|
+
default: () => {
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
// override default management node schema headers
|
|
30
|
+
headers: {
|
|
31
|
+
type: Array,
|
|
32
|
+
default: () => DEFAULT_HEADERS
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
// function to get node group for a given node, used for grouping nodes by pool in the table
|
|
36
|
+
// result should be an object with name and (optionally) description properties
|
|
37
|
+
getNodeGroup: {
|
|
38
|
+
type: Function,
|
|
39
|
+
default: null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* avoid fetching ALL nodes to find this cluster's nodes
|
|
46
|
+
* mgmt nodes do not have labels that can be used with a labelSelector action
|
|
47
|
+
* neither the prov cluster nor mgmt cluster list mgmt nodes in their metadata.relationships nor are the node names listed in either cluster's status
|
|
48
|
+
* BUT mgmt nodes are scoped to a cluster's namespace, so we can fetch only mgmt nodes in the cluster's namespace
|
|
49
|
+
*/
|
|
50
|
+
async fetch() {
|
|
51
|
+
const canList = this.$store.getters['management/canList'](MANAGEMENT.NODE);
|
|
52
|
+
|
|
53
|
+
if ( canList ) {
|
|
54
|
+
const hasAllMgmtNodes = this.$store.getters['management/haveAll'](MANAGEMENT.NODE);
|
|
55
|
+
|
|
56
|
+
if (hasAllMgmtNodes) {
|
|
57
|
+
this.mgmtNodes = this.$store.getters['management/all'](MANAGEMENT.NODE);
|
|
58
|
+
} else {
|
|
59
|
+
const res = await this.$store.dispatch('management/findLabelSelector', {
|
|
60
|
+
type: MANAGEMENT.NODE,
|
|
61
|
+
matching: {
|
|
62
|
+
namespace: this.resource.mgmtClusterId,
|
|
63
|
+
labelSelector: {
|
|
64
|
+
matchExpressions: [
|
|
65
|
+
{
|
|
66
|
+
key: 'management.cattle.io/nodename',
|
|
67
|
+
operator: 'Exists',
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
} );
|
|
73
|
+
|
|
74
|
+
this.mgmtNodes = res;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
data() {
|
|
80
|
+
return {
|
|
81
|
+
mgmtNodes: [],
|
|
82
|
+
|
|
83
|
+
mgmtNodeSchema: this.$store.getters[`management/schemaFor`](MANAGEMENT.NODE),
|
|
84
|
+
|
|
85
|
+
noneGroupOption: {
|
|
86
|
+
tooltipKey: 'resourceTable.groupBy.none',
|
|
87
|
+
icon: 'icon-list-flat',
|
|
88
|
+
value: 'none',
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
poolGroupOption: {
|
|
92
|
+
tooltipKey: 'resourceTable.groupBy.pool',
|
|
93
|
+
icon: 'icon-cluster',
|
|
94
|
+
value: 'poolRef',
|
|
95
|
+
field: 'poolRef.name'
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
};
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
computed: {
|
|
102
|
+
nodes() {
|
|
103
|
+
return this.mgmtNodes.filter((x) => x.mgmtClusterId === this.resource.mgmtClusterId).map((node) => {
|
|
104
|
+
const poolRef = typeof this.getNodeGroup === 'function' ? this.getNodeGroup(node) : null;
|
|
105
|
+
|
|
106
|
+
node.poolRef = poolRef;
|
|
107
|
+
|
|
108
|
+
return node;
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
</script>
|
|
114
|
+
|
|
115
|
+
<template>
|
|
116
|
+
<ResourceTable
|
|
117
|
+
v-bind="$attrs"
|
|
118
|
+
:schema="mgmtNodeSchema"
|
|
119
|
+
:headers="headers"
|
|
120
|
+
:rows="nodes"
|
|
121
|
+
:ignore-filter="true"
|
|
122
|
+
group-ref="poolRef"
|
|
123
|
+
data-testid="mgmt-node-table"
|
|
124
|
+
:group-options="[noneGroupOption, poolGroupOption]"
|
|
125
|
+
>
|
|
126
|
+
<template #main-row:isFake="{fullColspan}">
|
|
127
|
+
<tr class="main-row">
|
|
128
|
+
<td
|
|
129
|
+
:colspan="fullColspan"
|
|
130
|
+
class="no-entries"
|
|
131
|
+
>
|
|
132
|
+
{{ t('node.list.noNodes') }}
|
|
133
|
+
</td>
|
|
134
|
+
</tr>
|
|
135
|
+
</template>
|
|
136
|
+
|
|
137
|
+
<template #group-by="{group}">
|
|
138
|
+
<div
|
|
139
|
+
class="pool-row"
|
|
140
|
+
:class="{'has-description':group.ref}"
|
|
141
|
+
>
|
|
142
|
+
<div
|
|
143
|
+
v-trim-whitespace
|
|
144
|
+
class="group-tab"
|
|
145
|
+
>
|
|
146
|
+
{{ group.ref?.name || t('resourceTable.groupLabel.notInANodePool') }}
|
|
147
|
+
<div
|
|
148
|
+
v-if="group.ref && group.ref.description"
|
|
149
|
+
v-clean-html="group.ref.description"
|
|
150
|
+
class="description text-muted text-small"
|
|
151
|
+
/>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
</template>
|
|
155
|
+
</ResourceTable>
|
|
156
|
+
</template>
|
|
157
|
+
|
|
158
|
+
<style scoped lang="scss">
|
|
159
|
+
.pool-row {
|
|
160
|
+
display: flex;
|
|
161
|
+
align-items: center;
|
|
162
|
+
justify-content: space-between;
|
|
163
|
+
|
|
164
|
+
&.has-description {
|
|
165
|
+
.group-tab {
|
|
166
|
+
&, &::after {
|
|
167
|
+
height: 50px;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
&::after {
|
|
171
|
+
right: -20px;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.description {
|
|
175
|
+
margin-top: -20px;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
.group-header-buttons {
|
|
180
|
+
align-items: center;
|
|
181
|
+
display: flex;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
</style>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useResourceCardRow } from '@shell/components/Resource/Detail/Card/StateCard/composables';
|
|
1
|
+
import { useResourceCardRow, useResourceCardRowFromRelationships } from '@shell/components/Resource/Detail/Card/StateCard/composables';
|
|
2
2
|
|
|
3
3
|
describe('useResourceCardRow', () => {
|
|
4
4
|
describe('with default keys', () => {
|
|
@@ -140,3 +140,92 @@ describe('useResourceCardRow', () => {
|
|
|
140
140
|
});
|
|
141
141
|
});
|
|
142
142
|
});
|
|
143
|
+
|
|
144
|
+
describe('useResourceCardRowFromRelationships', () => {
|
|
145
|
+
it('should return empty props for empty relationships', () => {
|
|
146
|
+
const result = useResourceCardRowFromRelationships('Refers to', []);
|
|
147
|
+
|
|
148
|
+
expect(result.label).toBe('Refers to');
|
|
149
|
+
expect(result.color).toBeUndefined();
|
|
150
|
+
expect(result.counts).toBeUndefined();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should aggregate relationship states', () => {
|
|
154
|
+
const rels = [
|
|
155
|
+
{ toType: 'configmap', state: 'active' },
|
|
156
|
+
{ toType: 'secret', state: 'active' },
|
|
157
|
+
{ toType: 'serviceaccount', state: 'error' }
|
|
158
|
+
];
|
|
159
|
+
|
|
160
|
+
const result = useResourceCardRowFromRelationships('Refers to', rels);
|
|
161
|
+
|
|
162
|
+
expect(result.counts).toHaveLength(2);
|
|
163
|
+
expect(result.counts).toContainEqual(expect.objectContaining({ label: 'active', count: 2 }));
|
|
164
|
+
expect(result.counts).toContainEqual(expect.objectContaining({ label: 'error', count: 1 }));
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should default missing state to "missing"', () => {
|
|
168
|
+
const rels = [
|
|
169
|
+
{ toType: 'configmap' },
|
|
170
|
+
{ toType: 'secret', state: 'active' }
|
|
171
|
+
];
|
|
172
|
+
|
|
173
|
+
const result = useResourceCardRowFromRelationships('Refers to', rels);
|
|
174
|
+
|
|
175
|
+
expect(result.counts).toContainEqual(expect.objectContaining({
|
|
176
|
+
label: 'missing', count: 1, color: 'warning'
|
|
177
|
+
}));
|
|
178
|
+
expect(result.counts).toContainEqual(expect.objectContaining({
|
|
179
|
+
label: 'active', count: 1, color: 'success'
|
|
180
|
+
}));
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('should set the highest alert color as main color', () => {
|
|
184
|
+
const rels = [
|
|
185
|
+
{ toType: 'configmap', state: 'active' },
|
|
186
|
+
{ toType: 'secret', state: 'error' }
|
|
187
|
+
];
|
|
188
|
+
|
|
189
|
+
const result = useResourceCardRowFromRelationships('Refers to', rels);
|
|
190
|
+
|
|
191
|
+
expect(result.color).toBe('error');
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('should sort by alert level then by count', () => {
|
|
195
|
+
const rels = [
|
|
196
|
+
{ toType: 'a', state: 'active' },
|
|
197
|
+
{ toType: 'b', state: 'active' },
|
|
198
|
+
{ toType: 'c', state: 'active' },
|
|
199
|
+
{ toType: 'd', state: 'error' },
|
|
200
|
+
{ toType: 'e', state: 'warning' },
|
|
201
|
+
{ toType: 'f', state: 'warning' }
|
|
202
|
+
];
|
|
203
|
+
|
|
204
|
+
const result = useResourceCardRowFromRelationships('Refers to', rels);
|
|
205
|
+
|
|
206
|
+
expect(result.counts![0].color).toBe('error');
|
|
207
|
+
expect(result.counts![1].color).toBe('warning');
|
|
208
|
+
expect(result.counts![2].color).toBe('success');
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it('should pass the to parameter through', () => {
|
|
212
|
+
const to = { hash: '#related' };
|
|
213
|
+
const result = useResourceCardRowFromRelationships('Refers to', [], to);
|
|
214
|
+
|
|
215
|
+
expect(result.to).toStrictEqual(to);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('should handle all relationships having no state', () => {
|
|
219
|
+
const rels = [
|
|
220
|
+
{ toType: 'configmap' },
|
|
221
|
+
{ toType: 'secret' }
|
|
222
|
+
];
|
|
223
|
+
|
|
224
|
+
const result = useResourceCardRowFromRelationships('Refers to', rels);
|
|
225
|
+
|
|
226
|
+
expect(result.counts).toHaveLength(1);
|
|
227
|
+
expect(result.counts![0]).toStrictEqual(expect.objectContaining({
|
|
228
|
+
label: 'missing', count: 2, color: 'warning'
|
|
229
|
+
}));
|
|
230
|
+
});
|
|
231
|
+
});
|