@rancher/shell 3.0.12-rc.3 → 3.0.12-rc.5
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/_button.scss +1 -1
- package/assets/styles/global/_layout.scss +4 -0
- package/assets/translations/en-us.yaml +183 -51
- 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/ActionDropdownShell.vue +5 -3
- package/components/ButtonGroup.vue +26 -1
- package/components/CruResource.vue +212 -16
- 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/PromptRestore.vue +93 -32
- package/components/Questions/index.vue +1 -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/ResourceTable.vue +1 -0
- package/components/RichTranslation.vue +5 -2
- package/components/Setting.vue +1 -0
- package/components/SortableTable/index.vue +4 -3
- 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 +23 -5
- package/components/__tests__/ButtonGroup.test.ts +56 -0
- package/components/__tests__/PromptRestore.test.ts +169 -19
- 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/GitRepoAdvancedTab.vue +1 -0
- package/components/fleet/GitRepoMetadataTab.vue +5 -0
- package/components/fleet/GitRepoTargetTab.vue +0 -2
- package/components/fleet/HelmOpAdvancedTab.vue +19 -53
- package/components/fleet/HelmOpAppCoConfigTab.vue +597 -0
- package/components/fleet/HelmOpAppCoResourcesSection.vue +162 -0
- package/components/fleet/HelmOpMetadataTab.vue +5 -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/FileSelector.vue +39 -1
- 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/PrivateRegistry.constants.ts +7 -0
- package/components/form/PrivateRegistry.vue +253 -18
- package/components/form/ResourceTabs/index.vue +1 -0
- package/components/form/SelectOrCreateAuthSecret.vue +140 -17
- package/components/form/__tests__/FileSelector.test.ts +23 -0
- package/components/form/__tests__/NameNsDescription.test.ts +75 -0
- package/components/form/__tests__/PrivateRegistry.test.ts +463 -73
- package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +122 -0
- package/components/formatter/EtcdSnapshotName.vue +73 -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 +12 -1
- 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 +16 -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/features.js +1 -0
- package/config/home-links.js +1 -1
- package/config/labels-annotations.js +3 -0
- package/config/product/explorer.js +17 -4
- package/config/product/manager.js +8 -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/secret.ts +10 -0
- package/config/settings.ts +6 -4
- package/config/table-headers.js +3 -4
- package/config/types.js +16 -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 +109 -7
- package/detail/workload/index.vue +12 -55
- package/dialog/RotateEncryptionKeyDialog.vue +33 -9
- package/dialog/__tests__/RotateEncryptionKeyDialog.test.ts +78 -0
- package/edit/__tests__/catalog.cattle.io.clusterrepo.test.ts +248 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +92 -0
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +206 -0
- package/edit/__tests__/management.cattle.io.setting.test.ts +2 -1
- 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/compliance.cattle.io.clusterscanprofile.vue +39 -41
- package/edit/fleet.cattle.io.gitrepo.vue +70 -16
- package/edit/fleet.cattle.io.helmop.vue +542 -141
- package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
- package/edit/{management.cattle.io.setting.vue → management.cattle.io.setting/index.vue} +32 -9
- package/edit/management.cattle.io.setting/system-default-registry-pull-secrets.vue +81 -0
- package/edit/management.cattle.io.user.vue +5 -2
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +3 -12
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +18 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +89 -11
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +11 -0
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +0 -1
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +14 -55
- 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 +205 -0
- package/models/__tests__/secret.test.ts +68 -1
- 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 +39 -5
- package/models/management.cattle.io.node.js +44 -3
- package/models/namespace.js +1 -1
- package/models/pod.js +46 -3
- package/models/provisioning.cattle.io.cluster.js +64 -14
- package/models/rke.cattle.io.etcdsnapshot.js +17 -9
- package/models/secret.js +19 -0
- package/models/workload.js +120 -20
- 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/__tests__/install.test.ts +485 -107
- 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 +236 -144
- 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/pkg/require-asset.lib.js +25 -0
- package/pkg/vue.config.js +7 -0
- package/plugins/clean-html.d.ts +9 -0
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +177 -0
- package/plugins/dashboard-store/getters.js +0 -1
- package/plugins/dashboard-store/resource-class.js +114 -19
- 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/Form/TextArea/TextAreaAutoGrow.vue +30 -0
- package/rancher-components/Form/TextArea/__tests__/TextAreaAutoGrow.test.ts +95 -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/index.ts +1 -1
- package/rancher-components/RcButton/types.ts +3 -0
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +6 -1
- 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__/features.test.ts +131 -0
- package/store/__tests__/growl.test.ts +374 -0
- package/store/__tests__/modal.test.ts +131 -0
- package/store/__tests__/notifications.test.ts +434 -0
- package/store/__tests__/slideInPanel.test.ts +88 -0
- package/store/__tests__/type-map.utils.test.ts +433 -0
- package/store/catalog.js +57 -0
- package/store/features.js +4 -0
- package/store/plugins.js +7 -4
- package/types/components/buttonGroup.ts +5 -0
- package/types/shell/index.d.ts +166 -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__/operation-cr.test.ts +34 -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/operation-cr.js +19 -0
- package/utils/provider.ts +12 -0
- package/utils/require-asset.ts +7 -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/validators/__tests__/private-registry.test.ts +27 -15
- package/utils/validators/private-registry.ts +15 -4
- 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
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
import {
|
|
2
|
+
conditionalDepaginate,
|
|
3
|
+
configureConditionalDepaginate,
|
|
4
|
+
headerFromSchemaCol,
|
|
5
|
+
rowValueGetter,
|
|
6
|
+
} from '../type-map.utils';
|
|
7
|
+
|
|
8
|
+
const makeGetters = (overrides: any = {}) => ({
|
|
9
|
+
'i18n/exists': jest.fn(() => false),
|
|
10
|
+
'i18n/t': jest.fn((key: string) => key),
|
|
11
|
+
currentStore: jest.fn(() => 'cluster'),
|
|
12
|
+
'cluster/all': jest.fn(() => []),
|
|
13
|
+
...overrides,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const makeCol = (overrides: any = {}) => ({
|
|
17
|
+
description: '',
|
|
18
|
+
field: '$.metadata.name',
|
|
19
|
+
format: '',
|
|
20
|
+
name: 'Name',
|
|
21
|
+
priority: 0,
|
|
22
|
+
type: 'string',
|
|
23
|
+
...overrides,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const makeAgeColumn = () => ({
|
|
27
|
+
name: 'age',
|
|
28
|
+
label: 'Age',
|
|
29
|
+
value: 'metadata.creationTimestamp',
|
|
30
|
+
sort: ['metadata.creationTimestamp'],
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('rowValueGetter', () => {
|
|
34
|
+
describe('fields matching $.metadata.fields[N] pattern', () => {
|
|
35
|
+
it.each([
|
|
36
|
+
{
|
|
37
|
+
desc: 'returns function accessing index 0',
|
|
38
|
+
field: '$.metadata.fields[0]',
|
|
39
|
+
asFn: true as const,
|
|
40
|
+
expectedValue: { metadata: { fields: ['first', 'second'] } },
|
|
41
|
+
expectedIdx: 0,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
desc: 'returns function accessing index 2',
|
|
45
|
+
field: '$.metadata.fields[2]',
|
|
46
|
+
asFn: true as const,
|
|
47
|
+
expectedValue: { metadata: { fields: ['a', 'b', 'c'] } },
|
|
48
|
+
expectedIdx: 2,
|
|
49
|
+
},
|
|
50
|
+
])('$desc', ({
|
|
51
|
+
field, asFn, expectedValue, expectedIdx,
|
|
52
|
+
}) => {
|
|
53
|
+
const getter = rowValueGetter(makeCol({ field }), asFn) as (row: any) => any;
|
|
54
|
+
|
|
55
|
+
expect(typeof getter).toStrictEqual('function');
|
|
56
|
+
expect(getter(expectedValue)).toStrictEqual(expectedValue.metadata.fields[expectedIdx]);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it.each([
|
|
60
|
+
{
|
|
61
|
+
desc: 'returns string path for index 0',
|
|
62
|
+
field: '$.metadata.fields[0]',
|
|
63
|
+
asFn: false as const,
|
|
64
|
+
expected: 'metadata.fields.0',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
desc: 'returns string path for index 3',
|
|
68
|
+
field: '$.metadata.fields[3]',
|
|
69
|
+
asFn: false as const,
|
|
70
|
+
expected: 'metadata.fields.3',
|
|
71
|
+
},
|
|
72
|
+
])('$desc', ({ field, asFn, expected }) => {
|
|
73
|
+
expect(rowValueGetter(makeCol({ field }), asFn)).toStrictEqual(expected);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('returns undefined when row has no fields array', () => {
|
|
77
|
+
const getter = rowValueGetter(makeCol({ field: '$.metadata.fields[0]' }), true) as (row: any) => any;
|
|
78
|
+
|
|
79
|
+
expect(getter({})).toBeUndefined();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('returns undefined when metadata is missing', () => {
|
|
83
|
+
const getter = rowValueGetter(makeCol({ field: '$.metadata.fields[1]' }), true) as (row: any) => any;
|
|
84
|
+
|
|
85
|
+
expect(getter({ other: 'data' })).toBeUndefined();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe('fields starting with . (dot-prefixed)', () => {
|
|
90
|
+
it('prepends $ to dot-prefixed fields', () => {
|
|
91
|
+
const result = rowValueGetter(makeCol({ field: '.metadata.name' }), false);
|
|
92
|
+
|
|
93
|
+
expect(result).toStrictEqual('$.metadata.name');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('does not modify fields already starting with $', () => {
|
|
97
|
+
const result = rowValueGetter(makeCol({ field: '$.metadata.name' }), false);
|
|
98
|
+
|
|
99
|
+
expect(result).toStrictEqual('$.metadata.name');
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('fields with escaped dots (rewriteJsonPath)', () => {
|
|
104
|
+
it.each([
|
|
105
|
+
{
|
|
106
|
+
desc: 'rewrites single escaped dot in label key',
|
|
107
|
+
field: '$.metadata.labels.topology\\.kubernetes\\.io/zone',
|
|
108
|
+
expected: '$.metadata.labels.["topology.kubernetes.io/zone"]',
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
desc: 'rewrites escaped dot in annotation key',
|
|
112
|
+
field: '$.metadata.annotations.cattle\\.io/hash',
|
|
113
|
+
expected: '$.metadata.annotations.["cattle.io/hash"]',
|
|
114
|
+
},
|
|
115
|
+
])('$desc', ({ field, expected }) => {
|
|
116
|
+
expect(rowValueGetter(makeCol({ field }), false)).toStrictEqual(expected);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('returns path unchanged when no escaped dots present', () => {
|
|
120
|
+
const field = '$.metadata.labels.app';
|
|
121
|
+
|
|
122
|
+
expect(rowValueGetter(makeCol({ field }), false)).toStrictEqual(field);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe('conditionalDepaginate', () => {
|
|
128
|
+
it.each([
|
|
129
|
+
{
|
|
130
|
+
desc: 'returns true when depaginate is boolean true',
|
|
131
|
+
depaginate: true,
|
|
132
|
+
args: undefined,
|
|
133
|
+
expected: true,
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
desc: 'returns false when depaginate is boolean false',
|
|
137
|
+
depaginate: false,
|
|
138
|
+
args: undefined,
|
|
139
|
+
expected: false,
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
desc: 'returns undefined when depaginate is undefined',
|
|
143
|
+
depaginate: undefined,
|
|
144
|
+
args: undefined,
|
|
145
|
+
expected: undefined,
|
|
146
|
+
},
|
|
147
|
+
])('$desc', ({ depaginate, args, expected }) => {
|
|
148
|
+
expect(conditionalDepaginate(depaginate as any, args)).toStrictEqual(expected);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('calls function with args and returns its result when args are provided', () => {
|
|
152
|
+
const fn = jest.fn(() => true);
|
|
153
|
+
const args = { ctx: { rootGetters: {} as any }, args: { type: 'pod', opt: {} } };
|
|
154
|
+
|
|
155
|
+
const result = conditionalDepaginate(fn, args);
|
|
156
|
+
|
|
157
|
+
expect(fn).toHaveBeenCalledWith(args);
|
|
158
|
+
expect(result).toStrictEqual(true);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('returns false when depaginate is a function but no args are provided', () => {
|
|
162
|
+
const fn = jest.fn(() => true);
|
|
163
|
+
|
|
164
|
+
expect(conditionalDepaginate(fn, undefined)).toStrictEqual(false);
|
|
165
|
+
expect(fn).not.toHaveBeenCalled();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe('configureConditionalDepaginate', () => {
|
|
170
|
+
const makeRootGetters = (resourceCount: number | undefined, type: string, store = 'cluster') => {
|
|
171
|
+
const counts: any = {};
|
|
172
|
+
|
|
173
|
+
if (resourceCount !== undefined) {
|
|
174
|
+
counts[type] = { summary: { count: resourceCount } };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
currentStore: jest.fn(() => store),
|
|
179
|
+
[`${ store }/all`]: jest.fn(() => [{ counts }]),
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
it('returns true when resource count is below maxResourceCount', () => {
|
|
184
|
+
const type = 'pod';
|
|
185
|
+
const rootGetters = makeRootGetters(50, type) as any;
|
|
186
|
+
const fn = configureConditionalDepaginate({ maxResourceCount: 100, isNorman: false });
|
|
187
|
+
const result = fn({
|
|
188
|
+
ctx: { rootGetters },
|
|
189
|
+
args: { type, opt: {} },
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
expect(result).toStrictEqual(true);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('returns false when resource count equals maxResourceCount', () => {
|
|
196
|
+
const type = 'pod';
|
|
197
|
+
const rootGetters = makeRootGetters(100, type) as any;
|
|
198
|
+
const fn = configureConditionalDepaginate({ maxResourceCount: 100, isNorman: false });
|
|
199
|
+
const result = fn({
|
|
200
|
+
ctx: { rootGetters },
|
|
201
|
+
args: { type, opt: {} },
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
expect(result).toStrictEqual(false);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('returns false when resource count exceeds maxResourceCount', () => {
|
|
208
|
+
const type = 'pod';
|
|
209
|
+
const rootGetters = makeRootGetters(200, type) as any;
|
|
210
|
+
const fn = configureConditionalDepaginate({ maxResourceCount: 100, isNorman: false });
|
|
211
|
+
const result = fn({
|
|
212
|
+
ctx: { rootGetters },
|
|
213
|
+
args: { type, opt: {} },
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
expect(result).toStrictEqual(false);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('returns false when resource count is undefined', () => {
|
|
220
|
+
const type = 'pod';
|
|
221
|
+
const rootGetters = makeRootGetters(undefined, type) as any;
|
|
222
|
+
const fn = configureConditionalDepaginate({ maxResourceCount: 100, isNorman: false });
|
|
223
|
+
const result = fn({
|
|
224
|
+
ctx: { rootGetters },
|
|
225
|
+
args: { type, opt: {} },
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
expect(result).toStrictEqual(false);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('uses management.cattle.io. prefix for Norman types', () => {
|
|
232
|
+
const type = 'node';
|
|
233
|
+
const normanType = `management.cattle.io.${ type }`;
|
|
234
|
+
const rootGetters = makeRootGetters(5, normanType) as any;
|
|
235
|
+
const fn = configureConditionalDepaginate({ maxResourceCount: 100, isNorman: true });
|
|
236
|
+
const result = fn({
|
|
237
|
+
ctx: { rootGetters },
|
|
238
|
+
args: { type, opt: {} },
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
expect(result).toStrictEqual(true);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
describe('headerFromSchemaCol', () => {
|
|
246
|
+
describe('age column shortcut', () => {
|
|
247
|
+
it.each([
|
|
248
|
+
{
|
|
249
|
+
desc: 'returns ageColumn when format is empty and name is age',
|
|
250
|
+
col: makeCol({
|
|
251
|
+
name: 'age',
|
|
252
|
+
format: '',
|
|
253
|
+
}),
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
desc: 'returns ageColumn when format is date and name is age',
|
|
257
|
+
col: makeCol({
|
|
258
|
+
name: 'age',
|
|
259
|
+
format: 'date',
|
|
260
|
+
}),
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
desc: 'returns ageColumn when type is date and name is age',
|
|
264
|
+
col: makeCol({
|
|
265
|
+
name: 'age',
|
|
266
|
+
type: 'date',
|
|
267
|
+
format: '',
|
|
268
|
+
}),
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
desc: 'returns ageColumn when name is Age (case insensitive)',
|
|
272
|
+
col: makeCol({
|
|
273
|
+
name: 'Age',
|
|
274
|
+
format: '',
|
|
275
|
+
}),
|
|
276
|
+
},
|
|
277
|
+
])('$desc', ({ col }) => {
|
|
278
|
+
const ageColumn = makeAgeColumn() as any;
|
|
279
|
+
const result = headerFromSchemaCol(col as any, makeGetters() as any, false, ageColumn);
|
|
280
|
+
|
|
281
|
+
expect(result).toStrictEqual(ageColumn);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('does not return ageColumn when ageColumn is not provided', () => {
|
|
285
|
+
const col = makeCol({ name: 'age', format: '' });
|
|
286
|
+
const result = headerFromSchemaCol(col as any, makeGetters() as any, false, null as any);
|
|
287
|
+
|
|
288
|
+
expect(result).not.toStrictEqual(null);
|
|
289
|
+
expect(result.name).toStrictEqual('age');
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
describe('formatter assignment', () => {
|
|
294
|
+
it('sets formatter to Date and width 120 for date format', () => {
|
|
295
|
+
const col = makeCol({
|
|
296
|
+
name: 'created',
|
|
297
|
+
format: 'date',
|
|
298
|
+
});
|
|
299
|
+
const result = headerFromSchemaCol(col as any, makeGetters() as any, false, null as any);
|
|
300
|
+
|
|
301
|
+
expect(result.formatter).toStrictEqual('Date');
|
|
302
|
+
expect(result.width).toStrictEqual(120);
|
|
303
|
+
expect(result.formatterOpts).toStrictEqual({ multiline: true });
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it('sets formatter to Date and width 120 when type is date', () => {
|
|
307
|
+
const col = makeCol({
|
|
308
|
+
name: 'modified',
|
|
309
|
+
format: '',
|
|
310
|
+
type: 'date',
|
|
311
|
+
});
|
|
312
|
+
const result = headerFromSchemaCol(col as any, makeGetters() as any, false, null as any);
|
|
313
|
+
|
|
314
|
+
expect(result.formatter).toStrictEqual('Date');
|
|
315
|
+
expect(result.width).toStrictEqual(120);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it('sets formatter to Number when type is number', () => {
|
|
319
|
+
const col = makeCol({
|
|
320
|
+
name: 'count',
|
|
321
|
+
type: 'number',
|
|
322
|
+
});
|
|
323
|
+
const result = headerFromSchemaCol(col as any, makeGetters() as any, false, null as any);
|
|
324
|
+
|
|
325
|
+
expect(result.formatter).toStrictEqual('Number');
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('sets formatter to Number when type is int', () => {
|
|
329
|
+
const col = makeCol({
|
|
330
|
+
name: 'replicas',
|
|
331
|
+
type: 'int',
|
|
332
|
+
});
|
|
333
|
+
const result = headerFromSchemaCol(col as any, makeGetters() as any, false, null as any);
|
|
334
|
+
|
|
335
|
+
expect(result.formatter).toStrictEqual('Number');
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it('does not set formatter for plain text column', () => {
|
|
339
|
+
const col = makeCol({ name: 'status', type: 'string' });
|
|
340
|
+
const result = headerFromSchemaCol(col as any, makeGetters() as any, false, null as any);
|
|
341
|
+
|
|
342
|
+
expect(result.formatter).toBeUndefined();
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
describe('label resolution', () => {
|
|
347
|
+
it('uses i18n translation when key exists', () => {
|
|
348
|
+
const getters = makeGetters({
|
|
349
|
+
'i18n/exists': jest.fn(() => true),
|
|
350
|
+
'i18n/t': jest.fn((key: string) => `translated:${ key }`),
|
|
351
|
+
});
|
|
352
|
+
const col = makeCol({ name: 'status' });
|
|
353
|
+
const result = headerFromSchemaCol(col as any, getters as any, false, null as any);
|
|
354
|
+
|
|
355
|
+
expect(result.label).toStrictEqual('translated:tableHeaders.status');
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
it('uses column name when i18n key does not exist', () => {
|
|
359
|
+
const getters = makeGetters({ 'i18n/exists': jest.fn(() => false) });
|
|
360
|
+
const col = makeCol({ name: 'MyColumn' });
|
|
361
|
+
const result = headerFromSchemaCol(col as any, getters as any, false, null as any);
|
|
362
|
+
|
|
363
|
+
expect(result.label).toStrictEqual('MyColumn');
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it('camelCases the i18n key when col name has spaces', () => {
|
|
367
|
+
const getters = makeGetters({
|
|
368
|
+
'i18n/exists': jest.fn((key: string) => key === 'tableHeaders.myLabel'),
|
|
369
|
+
'i18n/t': jest.fn((key: string) => `t:${ key }`),
|
|
370
|
+
});
|
|
371
|
+
const col = makeCol({ name: 'my label' });
|
|
372
|
+
const result = headerFromSchemaCol(col as any, getters as any, false, null as any);
|
|
373
|
+
|
|
374
|
+
expect(result.label).toStrictEqual('t:tableHeaders.myLabel');
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
describe('tooltip from description', () => {
|
|
379
|
+
it('uses description as tooltip when not ending with dot', () => {
|
|
380
|
+
const col = makeCol({ name: 'status', description: 'Current status' });
|
|
381
|
+
const result = headerFromSchemaCol(col as any, makeGetters() as any, false, null as any);
|
|
382
|
+
|
|
383
|
+
expect(result.tooltip).toStrictEqual('Current status');
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
it('strips trailing dot from description for tooltip', () => {
|
|
387
|
+
const col = makeCol({ name: 'status', description: 'Current status.' });
|
|
388
|
+
const result = headerFromSchemaCol(col as any, makeGetters() as any, false, null as any);
|
|
389
|
+
|
|
390
|
+
expect(result.tooltip).toStrictEqual('Current status');
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it('uses empty string as tooltip when description is empty', () => {
|
|
394
|
+
const col = makeCol({ name: 'status', description: '' });
|
|
395
|
+
const result = headerFromSchemaCol(col as any, makeGetters() as any, false, null as any);
|
|
396
|
+
|
|
397
|
+
expect(result.tooltip).toStrictEqual('');
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
describe('pagination mode', () => {
|
|
402
|
+
it('uses string path as value when pagination is true', () => {
|
|
403
|
+
const col = makeCol({ name: 'status', field: '$.metadata.name' });
|
|
404
|
+
const result = headerFromSchemaCol(col as any, makeGetters() as any, true, null as any);
|
|
405
|
+
|
|
406
|
+
expect(typeof result.value).toStrictEqual('string');
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
it('uses function as value when pagination is false', () => {
|
|
410
|
+
const col = makeCol({ name: 'status', field: '$.metadata.fields[0]' });
|
|
411
|
+
const result = headerFromSchemaCol(col as any, makeGetters() as any, false, null as any);
|
|
412
|
+
|
|
413
|
+
expect(typeof result.value).toStrictEqual('function');
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
describe('output shape', () => {
|
|
418
|
+
it('sets name to lowercase version of col.name', () => {
|
|
419
|
+
const col = makeCol({ name: 'Status' });
|
|
420
|
+
const result = headerFromSchemaCol(col as any, makeGetters() as any, false, null as any);
|
|
421
|
+
|
|
422
|
+
expect(result.name).toStrictEqual('status');
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
it('sets sort and search from string path', () => {
|
|
426
|
+
const col = makeCol({ name: 'name', field: '$.metadata.name' });
|
|
427
|
+
const result = headerFromSchemaCol(col as any, makeGetters() as any, true, null as any);
|
|
428
|
+
|
|
429
|
+
expect(result.sort).toStrictEqual(['$.metadata.name']);
|
|
430
|
+
expect(result.search).toStrictEqual('$.metadata.name');
|
|
431
|
+
});
|
|
432
|
+
});
|
|
433
|
+
});
|
package/store/catalog.js
CHANGED
|
@@ -302,6 +302,16 @@ export const mutations = {
|
|
|
302
302
|
state.namespacedRepos = namespaced;
|
|
303
303
|
},
|
|
304
304
|
|
|
305
|
+
addClusterRepo(state, repo) {
|
|
306
|
+
if (!state.clusterRepos) {
|
|
307
|
+
state.clusterRepos = [];
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (!state.clusterRepos.find((r) => r.metadata?.name === repo.metadata?.name)) {
|
|
311
|
+
state.clusterRepos.push(repo);
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
|
|
305
315
|
setCharts(state, { charts, errors = [], loaded = [] }) {
|
|
306
316
|
state.charts = charts;
|
|
307
317
|
state.errors = errors;
|
|
@@ -445,6 +455,53 @@ export const actions = {
|
|
|
445
455
|
}
|
|
446
456
|
},
|
|
447
457
|
|
|
458
|
+
async loadRepo(ctx, { repoName }) {
|
|
459
|
+
const {
|
|
460
|
+
state, getters, rootGetters, commit, dispatch
|
|
461
|
+
} = ctx;
|
|
462
|
+
|
|
463
|
+
const inStore = rootGetters['currentCluster'] ? rootGetters['currentProduct'].inStore : 'management';
|
|
464
|
+
|
|
465
|
+
let repo = rootGetters[`${ inStore }/byId`](CATALOG.CLUSTER_REPO, repoName);
|
|
466
|
+
|
|
467
|
+
if (!repo) {
|
|
468
|
+
try {
|
|
469
|
+
repo = await dispatch(`${ inStore }/find`, { type: CATALOG.CLUSTER_REPO, id: repoName }, { root: true });
|
|
470
|
+
} catch (e) {
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if (!repo) {
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
commit('addClusterRepo', repo);
|
|
480
|
+
|
|
481
|
+
if (getters.isLoaded(repo)) {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
try {
|
|
486
|
+
const index = await repo.followLink('index');
|
|
487
|
+
const charts = { ...state.charts };
|
|
488
|
+
|
|
489
|
+
for (const k in index?.entries) {
|
|
490
|
+
for (const entry of index.entries[k]) {
|
|
491
|
+
addChart(ctx, charts, entry, repo);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
commit('setCharts', {
|
|
496
|
+
charts,
|
|
497
|
+
errors: state.errors,
|
|
498
|
+
loaded: [repo],
|
|
499
|
+
});
|
|
500
|
+
} catch (e) {
|
|
501
|
+
console.error(`Failed to load repo ${ repoName }:`, e); // eslint-disable-line no-console
|
|
502
|
+
}
|
|
503
|
+
},
|
|
504
|
+
|
|
448
505
|
/**
|
|
449
506
|
* Globally refreshes all loaded repositories by triggering their refresh actions concurrently,
|
|
450
507
|
* bypassing individual catalog loads, and then performs a single, global catalog/load.
|
package/store/features.js
CHANGED
|
@@ -39,6 +39,10 @@ export const PROVISIONING_PRE_BOOTSTRAP = create('provisioningprebootstrap', fal
|
|
|
39
39
|
export const SCHEDULING_CUSTOMIZATION = create(SCHEDULING_CUSTOMIZATION_FEATURE, false);
|
|
40
40
|
export const SCC = create('rancher-scc-registration-extension', true);
|
|
41
41
|
export const AUTOSCALER = create('cluster-autoscaling', false);
|
|
42
|
+
// Feature flags for disabling shell access to clusters, nodes, pods
|
|
43
|
+
export const CLUSTER_SHELL = create('cluster-shell', true);
|
|
44
|
+
export const NODE_SHELL = create('node-shell', true);
|
|
45
|
+
export const POD_SHELL = create('pod-shell', true);
|
|
42
46
|
|
|
43
47
|
// Not currently used.. no point defining ones we don't use
|
|
44
48
|
// export const EMBEDDED_CLUSTER_API = create('embedded-cluster-api', true);
|
package/store/plugins.js
CHANGED
|
@@ -172,14 +172,14 @@ export const getters = {
|
|
|
172
172
|
return async(name) => {
|
|
173
173
|
const schema = getters.schemaForDriver(name);
|
|
174
174
|
|
|
175
|
-
await schema.fetchResourceFields();
|
|
176
|
-
|
|
177
175
|
if ( !schema ) {
|
|
178
176
|
// eslint-disable-next-line no-console
|
|
179
177
|
console.error(`Machine Driver Config schema not found for ${ name }`);
|
|
180
178
|
|
|
181
179
|
return [];
|
|
182
180
|
}
|
|
181
|
+
await schema.fetchResourceFields();
|
|
182
|
+
|
|
183
183
|
// This is used in places where `createPopulated` has been called, which has called fetchResourceFields to populate resourceFields
|
|
184
184
|
const out = Object.keys(schema?.resourceFields || {});
|
|
185
185
|
|
|
@@ -191,13 +191,16 @@ export const getters = {
|
|
|
191
191
|
|
|
192
192
|
fieldsForDriver(state, getters) {
|
|
193
193
|
return async(name) => {
|
|
194
|
+
const out = {};
|
|
194
195
|
const schema = getters.schemaForDriver(name);
|
|
195
196
|
|
|
197
|
+
if ( !schema ) {
|
|
198
|
+
return out;
|
|
199
|
+
}
|
|
200
|
+
|
|
196
201
|
await schema.fetchResourceFields();
|
|
197
202
|
const names = await getters.fieldNamesForDriver(name);
|
|
198
203
|
|
|
199
|
-
const out = {};
|
|
200
|
-
|
|
201
204
|
for ( const n of names ) {
|
|
202
205
|
out[n] = schema.resourceFields[n];
|
|
203
206
|
}
|