@rancher/shell 3.0.8-rc.8 → 3.0.8
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/apis/impl/apis.ts +61 -0
- package/apis/index.ts +40 -0
- package/apis/intf/modal.ts +90 -0
- package/apis/intf/shell.ts +36 -0
- package/apis/intf/slide-in.ts +98 -0
- package/apis/intf/system.ts +41 -0
- package/apis/shell/__tests__/modal.test.ts +80 -0
- package/apis/shell/__tests__/notifications.test.ts +71 -0
- package/apis/shell/__tests__/slide-in.test.ts +54 -0
- package/apis/shell/__tests__/system.test.ts +129 -0
- package/apis/shell/index.ts +38 -0
- package/apis/shell/modal.ts +41 -0
- package/apis/shell/notifications.ts +65 -0
- package/apis/shell/slide-in.ts +33 -0
- package/apis/shell/system.ts +65 -0
- package/apis/vue-shim.d.ts +11 -0
- package/assets/brand/suse/dark/rancher-logo.svg +1 -64
- package/assets/styles/global/_tooltip.scss +6 -1
- package/assets/translations/en-us.yaml +14 -1
- package/components/ActionMenuShell.vue +3 -1
- package/components/BackLink.vue +8 -0
- package/components/BannerGraphic.vue +1 -5
- package/components/BrandImage.vue +17 -6
- package/components/Cron/CronExpressionEditor.vue +1 -1
- package/components/Cron/CronExpressionEditorModal.vue +1 -1
- package/components/CruResource.vue +8 -1
- package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +1 -0
- package/components/Drawer/ResourceDetailDrawer/__tests__/composables.test.ts +50 -1
- package/components/Drawer/ResourceDetailDrawer/composables.ts +19 -0
- package/components/Drawer/ResourceDetailDrawer/index.vue +4 -1
- package/components/Drawer/ResourceDetailDrawer/types.ts +2 -1
- package/components/LocaleSelector.vue +2 -2
- package/components/ModalManager.vue +11 -1
- package/components/Questions/__tests__/Yaml.test.ts +1 -1
- package/components/Questions/__tests__/index.test.ts +159 -0
- package/components/RelatedResources.vue +5 -0
- package/components/Resource/Detail/Metadata/Annotations/index.vue +2 -2
- package/components/Resource/Detail/Metadata/Labels/index.vue +2 -2
- package/components/Resource/Detail/Metadata/index.vue +3 -3
- package/components/Resource/Detail/ResourcePopover/index.vue +5 -1
- package/components/Resource/Detail/composables.ts +2 -2
- package/components/ResourceDetail/Masthead/latest.vue +23 -21
- package/components/ResourceDetail/index.vue +3 -0
- package/components/ResourceTable.vue +54 -21
- package/components/SlideInPanelManager.vue +16 -11
- package/components/SortableTable/THead.vue +2 -1
- package/components/SortableTable/index.vue +20 -2
- package/components/Tabbed/__tests__/index.test.ts +86 -0
- package/components/Tabbed/index.vue +37 -2
- package/components/__tests__/NamespaceFilter.test.ts +49 -0
- package/components/auth/SelectPrincipal.vue +28 -6
- package/components/auth/__tests__/SelectPrincipal.test.ts +119 -0
- package/components/auth/login/ldap.vue +3 -3
- package/components/fleet/FleetSecretSelector.vue +1 -1
- package/components/form/KeyValue.vue +1 -1
- package/components/form/NameNsDescription.vue +1 -1
- package/components/form/NodeScheduling.vue +2 -2
- package/components/form/ResourceTabs/composable.ts +2 -2
- package/components/form/ResourceTabs/index.vue +0 -2
- package/components/form/__tests__/NameNsDescription.test.ts +42 -0
- package/components/formatter/InternalExternalIP.vue +4 -1
- package/components/formatter/LinkName.vue +5 -0
- package/components/formatter/__tests__/InternalExternalIP.test.ts +1 -1
- package/components/nav/Group.vue +25 -7
- package/components/nav/Header.vue +1 -1
- package/components/nav/NamespaceFilter.vue +1 -0
- package/components/nav/Type.vue +17 -6
- package/components/nav/WindowManager/panels/TabBodyContainer.vue +1 -1
- package/components/nav/__tests__/Type.test.ts +59 -0
- package/components/templates/standalone.vue +1 -1
- package/composables/cruResource.ts +27 -0
- package/composables/focusTrap.ts +3 -1
- package/composables/resourceDetail.ts +15 -0
- package/composables/useI18n.ts +10 -1
- package/composables/useLabeledFormElement.ts +3 -4
- package/config/__test__/uiplugins.test.ts +309 -0
- package/config/labels-annotations.js +1 -0
- package/config/product/explorer.js +3 -1
- package/config/product/fleet.js +1 -1
- package/config/router/navigation-guards/clusters.js +3 -3
- package/config/router/navigation-guards/products.js +1 -1
- package/config/router/routes.js +7 -7
- package/config/types.js +7 -0
- package/config/uiplugins.js +46 -2
- package/core/__tests__/extension-manager-impl.test.js +437 -0
- package/core/extension-manager-impl.js +21 -25
- package/core/plugin-helpers.ts +2 -2
- package/core/plugin.ts +9 -1
- package/core/plugins-loader.js +2 -2
- package/core/types-provisioning.ts +5 -1
- package/core/types.ts +35 -0
- package/detail/provisioning.cattle.io.cluster.vue +9 -6
- package/dialog/DeveloperLoadExtensionDialog.vue +13 -4
- package/dialog/MoveNamespaceDialog.vue +20 -4
- package/dialog/RollbackWorkloadDialog.vue +2 -5
- package/dialog/SearchDialog.vue +1 -0
- package/dialog/__tests__/MoveNamespaceDialog.test.ts +249 -0
- package/directives/__tests__/clean-tooltip.test.ts +298 -0
- package/directives/clean-tooltip.ts +234 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +2 -2
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +100 -3
- package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -0
- package/edit/configmap.vue +1 -0
- package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
- package/edit/fleet.cattle.io.helmop.vue +11 -6
- package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
- package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +1 -0
- package/edit/logging-flow/index.vue +1 -0
- package/edit/logging.banzaicloud.io.output/index.vue +1 -0
- package/edit/management.cattle.io.fleetworkspace.vue +1 -1
- package/edit/management.cattle.io.project.vue +1 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +4 -1
- package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +2 -1
- package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -0
- package/edit/monitoring.coreos.com.receiver/index.vue +2 -1
- package/edit/monitoring.coreos.com.route.vue +1 -1
- package/edit/namespace.vue +1 -0
- package/edit/networking.istio.io.destinationrule/index.vue +1 -0
- package/edit/networking.k8s.io.ingress/index.vue +1 -0
- package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +1 -0
- package/edit/networking.k8s.io.networkpolicy/index.vue +1 -0
- package/edit/node.vue +1 -0
- package/edit/persistentvolume/index.vue +27 -22
- package/edit/persistentvolume/plugins/awsElasticBlockStore.vue +13 -14
- package/edit/persistentvolume/plugins/azureDisk.vue +49 -48
- package/edit/persistentvolume/plugins/azureFile.vue +15 -14
- package/edit/persistentvolume/plugins/cephfs.vue +15 -14
- package/edit/persistentvolume/plugins/cinder.vue +15 -14
- package/edit/persistentvolume/plugins/csi.vue +18 -16
- package/edit/persistentvolume/plugins/fc.vue +13 -14
- package/edit/persistentvolume/plugins/flexVolume.vue +15 -14
- package/edit/persistentvolume/plugins/flocker.vue +1 -3
- package/edit/persistentvolume/plugins/gcePersistentDisk.vue +13 -14
- package/edit/persistentvolume/plugins/glusterfs.vue +15 -14
- package/edit/persistentvolume/plugins/hostPath.vue +40 -39
- package/edit/persistentvolume/plugins/iscsi.vue +13 -14
- package/edit/persistentvolume/plugins/local.vue +1 -3
- package/edit/persistentvolume/plugins/longhorn.vue +23 -22
- package/edit/persistentvolume/plugins/nfs.vue +15 -14
- package/edit/persistentvolume/plugins/photonPersistentDisk.vue +1 -14
- package/edit/persistentvolume/plugins/portworxVolume.vue +15 -14
- package/edit/persistentvolume/plugins/quobyte.vue +15 -14
- package/edit/persistentvolume/plugins/rbd.vue +15 -14
- package/edit/persistentvolume/plugins/scaleIO.vue +15 -14
- package/edit/persistentvolume/plugins/storageos.vue +15 -14
- package/edit/persistentvolume/plugins/vsphereVolume.vue +1 -3
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +21 -21
- package/edit/provisioning.cattle.io.cluster/index.vue +5 -5
- package/edit/provisioning.cattle.io.cluster/rke2.vue +9 -8
- package/edit/resources.cattle.io.restore.vue +1 -1
- package/edit/secret/index.vue +1 -1
- package/edit/service.vue +1 -0
- package/edit/serviceaccount.vue +1 -0
- package/edit/storage.k8s.io.storageclass/index.vue +1 -0
- package/edit/workload/Job.vue +2 -2
- package/edit/workload/index.vue +2 -1
- package/edit/workload/mixins/workload.js +1 -1
- package/initialize/App.vue +4 -4
- package/initialize/install-plugins.js +19 -5
- package/machine-config/azure.vue +1 -1
- package/machine-config/components/GCEImage.vue +1 -1
- package/mixins/__tests__/brand.spec.ts +2 -2
- package/mixins/brand.js +1 -7
- package/mixins/create-edit-view/index.js +5 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +128 -5
- package/models/chart.js +70 -74
- package/models/management.cattle.io.cluster.js +21 -3
- package/models/provisioning.cattle.io.cluster.js +31 -11
- package/package.json +11 -10
- package/pages/auth/login.vue +4 -6
- package/pages/auth/setup.vue +1 -1
- package/pages/auth/verify.vue +3 -3
- package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +135 -0
- package/pages/c/_cluster/apps/charts/chart.vue +33 -15
- package/pages/c/_cluster/apps/charts/index.vue +122 -24
- package/pages/c/_cluster/apps/charts/install.vue +33 -0
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +1 -1
- package/pages/c/_cluster/explorer/index.vue +8 -6
- package/pages/c/_cluster/fleet/index.vue +4 -7
- package/pages/c/_cluster/manager/hostedprovider/index.vue +12 -6
- package/pages/c/_cluster/settings/brand.vue +1 -1
- package/pages/c/_cluster/settings/index.vue +5 -0
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +7 -0
- package/pages/c/_cluster/uiplugins/catalogs.vue +147 -0
- package/pages/c/_cluster/uiplugins/index.vue +126 -184
- package/pkg/auto-import.js +3 -3
- package/pkg/dynamic-importer.lib.js +1 -1
- package/pkg/import.js +1 -1
- package/plugins/__tests__/mutations.tests.ts +179 -0
- package/plugins/dashboard-client-init.js +3 -0
- package/plugins/dashboard-store/getters.js +19 -2
- package/plugins/dashboard-store/model-loader.js +1 -1
- package/plugins/dashboard-store/mutations.js +23 -2
- package/plugins/dashboard-store/resource-class.js +11 -5
- package/plugins/i18n.js +8 -0
- package/plugins/plugin.js +2 -2
- package/plugins/steve/__tests__/steve-pagination-utils.test.ts +506 -0
- package/plugins/steve/steve-class.js +1 -1
- package/plugins/steve/steve-pagination-utils.ts +131 -47
- package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +1 -1
- package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +6 -42
- package/rancher-components/Pill/RcStatusBadge/index.ts +0 -1
- package/rancher-components/Pill/RcStatusBadge/types.ts +1 -1
- package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +5 -28
- package/rancher-components/Pill/RcStatusIndicator/types.ts +2 -1
- package/rancher-components/Pill/types.ts +0 -1
- package/rancher-components/RcDropdown/useDropdownContext.ts +2 -4
- package/rancher-components/RcIcon/RcIcon.test.ts +51 -0
- package/rancher-components/RcIcon/RcIcon.vue +46 -0
- package/rancher-components/RcIcon/index.ts +1 -0
- package/rancher-components/RcIcon/types.ts +160 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +1 -1
- package/rancher-components/utils/status.test.ts +67 -0
- package/rancher-components/utils/status.ts +77 -0
- package/scripts/publish-shell.sh +25 -0
- package/scripts/typegen.sh +1 -0
- package/store/__tests__/catalog.test.ts +1 -1
- package/store/__tests__/type-map.test.ts +164 -2
- package/store/action-menu.js +8 -0
- package/store/auth.js +25 -13
- package/store/catalog.js +6 -0
- package/store/i18n.js +3 -3
- package/store/index.js +8 -6
- package/store/notifications.ts +2 -0
- package/store/prefs.js +6 -7
- package/store/type-map.js +17 -7
- package/store/wm.ts +4 -4
- package/types/internal-api/shell/modal.d.ts +6 -6
- package/types/notifications/index.ts +126 -15
- package/types/rancher/index.d.ts +9 -0
- package/types/shell/index.d.ts +54 -3
- package/types/store/__tests__/pagination.types.spec.ts +137 -0
- package/types/store/pagination.types.ts +157 -9
- package/types/vue-shim.d.ts +5 -4
- package/utils/__tests__/provider.test.ts +98 -0
- package/utils/__tests__/router.test.js +238 -0
- package/utils/__tests__/selector-typed.test.ts +263 -0
- package/utils/cluster.js +4 -1
- package/utils/color.js +1 -1
- package/utils/dynamic-content/__tests__/info.test.ts +6 -0
- package/utils/dynamic-content/info.ts +43 -0
- package/utils/favicon.js +4 -4
- package/utils/fleet.ts +8 -1
- package/utils/pagination-utils.ts +2 -2
- package/utils/pagination-wrapper.ts +1 -1
- package/utils/provider.ts +14 -0
- package/utils/router.js +50 -0
- package/utils/selector-typed.ts +6 -2
- package/utils/unit-tests/pagination-utils.spec.ts +8 -8
- package/vue.config.js +3 -3
- package/composables/useExtensionManager.ts +0 -17
- package/core/plugins.js +0 -38
- package/directives/clean-tooltip.js +0 -32
- package/plugins/internal-api/index.ts +0 -37
- package/plugins/internal-api/shared/base-api.ts +0 -13
- package/plugins/internal-api/shell/shell.api.ts +0 -108
- package/plugins/nuxt-client-init.js +0 -3
- package/types/internal-api/shell/growl.d.ts +0 -25
- package/types/internal-api/shell/slideIn.d.ts +0 -15
|
@@ -36,9 +36,9 @@ export default {
|
|
|
36
36
|
};
|
|
37
37
|
},
|
|
38
38
|
computed: {
|
|
39
|
-
...mapGetters({ theme: 'prefs/theme' }),
|
|
39
|
+
...mapGetters({ theme: 'prefs/theme', brand: 'management/brand' }),
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
brandBase() {
|
|
42
42
|
const setting = this.managementSettings.filter((setting) => setting.id === SETTING.BRAND)[0] || {};
|
|
43
43
|
|
|
44
44
|
return setting.value;
|
|
@@ -78,19 +78,30 @@ export default {
|
|
|
78
78
|
}
|
|
79
79
|
},
|
|
80
80
|
|
|
81
|
+
isDark() {
|
|
82
|
+
return this.theme === 'dark';
|
|
83
|
+
},
|
|
84
|
+
|
|
81
85
|
pathToBrandedImage() {
|
|
82
86
|
if (this.fileName === 'rancher-logo.svg' || this.supportCustomLogo) {
|
|
83
|
-
if (this.
|
|
87
|
+
if (this.isDark && this.uiLogoDark) {
|
|
84
88
|
return this.uiLogoDark;
|
|
85
89
|
}
|
|
86
90
|
|
|
87
91
|
if (this.uiLogoLight) {
|
|
88
92
|
return this.uiLogoLight;
|
|
89
93
|
}
|
|
94
|
+
|
|
95
|
+
// csp, rgs, and federal map to SUSE, but have their own custom logos
|
|
96
|
+
if (this.brandBase !== this.brand) {
|
|
97
|
+
try {
|
|
98
|
+
return require(`~shell/assets/brand/${ this.brandBase }/${ this.isDark ? 'dark/' : '' }${ this.fileName }`);
|
|
99
|
+
} catch { }
|
|
100
|
+
}
|
|
90
101
|
}
|
|
91
102
|
|
|
92
103
|
if (this.fileName === 'banner.svg') {
|
|
93
|
-
if (this.
|
|
104
|
+
if (this.isDark && this.uiBannerDark) {
|
|
94
105
|
return this.uiBannerDark;
|
|
95
106
|
}
|
|
96
107
|
|
|
@@ -100,7 +111,7 @@ export default {
|
|
|
100
111
|
}
|
|
101
112
|
|
|
102
113
|
if (this.fileName === 'login-landscape.svg') {
|
|
103
|
-
if (this.
|
|
114
|
+
if (this.isDark && this.uiLoginBackgroundDark) {
|
|
104
115
|
return this.uiLoginBackgroundDark;
|
|
105
116
|
}
|
|
106
117
|
|
|
@@ -112,7 +123,7 @@ export default {
|
|
|
112
123
|
if (!this.brand) {
|
|
113
124
|
return this.defaultPathToBrandedImage;
|
|
114
125
|
} else {
|
|
115
|
-
if (this.
|
|
126
|
+
if (this.isDark || this.dark) {
|
|
116
127
|
try {
|
|
117
128
|
return require(`~shell/assets/brand/${ this.brand }/dark/${ this.fileName }`);
|
|
118
129
|
} catch {}
|
|
@@ -9,9 +9,10 @@ import AsyncButton from '@shell/components/AsyncButton';
|
|
|
9
9
|
import { mapGetters, mapState, mapActions } from 'vuex';
|
|
10
10
|
import { stringify, exceptionToErrorsArray } from '@shell/utils/error';
|
|
11
11
|
import CruResourceFooter from '@shell/components/CruResourceFooter';
|
|
12
|
+
import { useResourceCreatePageProvider, useResourceEditPageProvider } from '@shell/composables/cruResource';
|
|
12
13
|
|
|
13
14
|
import {
|
|
14
|
-
_EDIT, _VIEW, AS, _YAML, _UNFLAG, SUB_TYPE
|
|
15
|
+
_EDIT, _VIEW, AS, _YAML, _UNFLAG, SUB_TYPE, _CREATE
|
|
15
16
|
} from '@shell/config/query-params';
|
|
16
17
|
|
|
17
18
|
import { BEFORE_SAVE_HOOKS } from '@shell/mixins/child-hook';
|
|
@@ -168,6 +169,12 @@ export default {
|
|
|
168
169
|
const inStore = this.$store.getters['currentStore'](this.resource);
|
|
169
170
|
const schema = this.$store.getters[`${ inStore }/schemaFor`](this.resource.type);
|
|
170
171
|
|
|
172
|
+
if (this.mode === _CREATE) {
|
|
173
|
+
useResourceCreatePageProvider();
|
|
174
|
+
} else if (this.mode === _EDIT) {
|
|
175
|
+
useResourceEditPageProvider();
|
|
176
|
+
}
|
|
177
|
+
|
|
171
178
|
return {
|
|
172
179
|
isCancelModal: false,
|
|
173
180
|
showAsForm: this.$route.query[AS] !== _YAML,
|
|
@@ -25,6 +25,7 @@ const i18n = useI18n(store);
|
|
|
25
25
|
:real-mode="_VIEW"
|
|
26
26
|
:initial-value="props.resource"
|
|
27
27
|
:use-tabbed-hash="false /* Have to disable hashing on child components or it modifies the url and closes the drawer */"
|
|
28
|
+
:default-tab="props.defaultTab"
|
|
28
29
|
as="config"
|
|
29
30
|
/>
|
|
30
31
|
</div>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { provide, inject } from 'vue';
|
|
2
|
+
import { useDefaultConfigTabProps, useDefaultYamlTabProps, useResourceDetailDrawerProvider, useIsInResourceDetailDrawer } from '@shell/components/Drawer/ResourceDetailDrawer/composables';
|
|
2
3
|
import * as helpers from '@shell/components/Drawer/ResourceDetailDrawer/helpers';
|
|
3
4
|
import * as vuex from 'vuex';
|
|
4
5
|
|
|
@@ -6,6 +7,11 @@ jest.mock('@shell/components/Drawer/ResourceDetailDrawer/helpers');
|
|
|
6
7
|
jest.mock('vuex');
|
|
7
8
|
jest.mock('@shell/composables/drawer');
|
|
8
9
|
jest.mock('@shell/components/Drawer/ResourceDetailDrawer/index.vue', () => ({ name: 'ResourceDetailDrawer' } as any));
|
|
10
|
+
jest.mock('vue', () => ({
|
|
11
|
+
...jest.requireActual('vue'),
|
|
12
|
+
provide: jest.fn(),
|
|
13
|
+
inject: jest.fn()
|
|
14
|
+
}));
|
|
9
15
|
|
|
10
16
|
describe('composables: ResourceDetailDrawer', () => {
|
|
11
17
|
const resource = { type: 'RESOURCE' };
|
|
@@ -78,4 +84,47 @@ describe('composables: ResourceDetailDrawer', () => {
|
|
|
78
84
|
expect(props?.resource).toStrictEqual(resource);
|
|
79
85
|
});
|
|
80
86
|
});
|
|
87
|
+
|
|
88
|
+
describe('useResourceDetailDrawerProvider', () => {
|
|
89
|
+
beforeEach(() => {
|
|
90
|
+
jest.clearAllMocks();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should call provide with the correct key and value', () => {
|
|
94
|
+
useResourceDetailDrawerProvider();
|
|
95
|
+
|
|
96
|
+
expect(provide).toHaveBeenCalledWith('isInResourceDetailDrawerKey', true);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe('useIsInResourceDetailDrawer', () => {
|
|
101
|
+
beforeEach(() => {
|
|
102
|
+
jest.clearAllMocks();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should call inject with the correct key and default value', () => {
|
|
106
|
+
(inject as jest.Mock).mockReturnValue(false);
|
|
107
|
+
|
|
108
|
+
const result = useIsInResourceDetailDrawer();
|
|
109
|
+
|
|
110
|
+
expect(inject).toHaveBeenCalledWith('isInResourceDetailDrawerKey', false);
|
|
111
|
+
expect(result).toBe(false);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should return true when inside a ResourceDetailDrawer', () => {
|
|
115
|
+
(inject as jest.Mock).mockReturnValue(true);
|
|
116
|
+
|
|
117
|
+
const result = useIsInResourceDetailDrawer();
|
|
118
|
+
|
|
119
|
+
expect(result).toBe(true);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('should return false when not inside a ResourceDetailDrawer', () => {
|
|
123
|
+
(inject as jest.Mock).mockReturnValue(false);
|
|
124
|
+
|
|
125
|
+
const result = useIsInResourceDetailDrawer();
|
|
126
|
+
|
|
127
|
+
expect(result).toBe(false);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
81
130
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useStore } from 'vuex';
|
|
2
2
|
import { getYaml } from '@shell/components/Drawer/ResourceDetailDrawer/helpers';
|
|
3
3
|
import { ConfigProps, YamlProps } from '@shell/components/Drawer/ResourceDetailDrawer/types';
|
|
4
|
+
import { inject, provide } from 'vue';
|
|
4
5
|
|
|
5
6
|
export async function useDefaultYamlTabProps(resource: any): Promise<YamlProps> {
|
|
6
7
|
const yaml = await getYaml(resource);
|
|
@@ -27,3 +28,21 @@ export function useDefaultConfigTabProps(resource: any): ConfigProps | undefined
|
|
|
27
28
|
resourceType: resource.type
|
|
28
29
|
};
|
|
29
30
|
}
|
|
31
|
+
|
|
32
|
+
const IS_IN_RESOURCE_DETAIL_DRAWER_KEY = 'isInResourceDetailDrawerKey';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Used to add a provide method which will indicate to all ancestors that they're inside the ResourceDetailDrawer. This is useful because we show
|
|
36
|
+
* config page components both independently and within the ResourceDetailDrawer and we sometimes want to distinguish between the two use cases.
|
|
37
|
+
*/
|
|
38
|
+
export function useResourceDetailDrawerProvider() {
|
|
39
|
+
provide(IS_IN_RESOURCE_DETAIL_DRAWER_KEY, true);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* A composable used to determine if the current component was instantiated as an ancestor of a ResourceDetailDrawer.
|
|
44
|
+
* @returns true if the component is an ancestor of ResourceDetailDrawer, otherwise false
|
|
45
|
+
*/
|
|
46
|
+
export function useIsInResourceDetailDrawer() {
|
|
47
|
+
return inject(IS_IN_RESOURCE_DETAIL_DRAWER_KEY, false);
|
|
48
|
+
}
|
|
@@ -4,7 +4,7 @@ import { useI18n } from '@shell/composables/useI18n';
|
|
|
4
4
|
import { useStore } from 'vuex';
|
|
5
5
|
import Tabbed from '@shell/components/Tabbed/index.vue';
|
|
6
6
|
import YamlTab, { Props as YamlProps } from '@shell/components/Drawer/ResourceDetailDrawer/YamlTab.vue';
|
|
7
|
-
import { useDefaultConfigTabProps, useDefaultYamlTabProps } from '@shell/components/Drawer/ResourceDetailDrawer/composables';
|
|
7
|
+
import { useDefaultConfigTabProps, useDefaultYamlTabProps, useResourceDetailDrawerProvider } from '@shell/components/Drawer/ResourceDetailDrawer/composables';
|
|
8
8
|
import ConfigTab from '@shell/components/Drawer/ResourceDetailDrawer/ConfigTab.vue';
|
|
9
9
|
import { computed, ref } from 'vue';
|
|
10
10
|
import RcButton from '@components/RcButton/RcButton.vue';
|
|
@@ -54,6 +54,8 @@ const canEdit = computed(() => {
|
|
|
54
54
|
return isConfig.value ? props.resource.canEdit : props.resource.canEditYaml;
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
+
useResourceDetailDrawerProvider();
|
|
58
|
+
|
|
57
59
|
</script>
|
|
58
60
|
<template>
|
|
59
61
|
<Drawer
|
|
@@ -79,6 +81,7 @@ const canEdit = computed(() => {
|
|
|
79
81
|
<ConfigTab
|
|
80
82
|
v-if="configTabProps"
|
|
81
83
|
v-bind="configTabProps"
|
|
84
|
+
:default-tab="props.defaultTab"
|
|
82
85
|
/>
|
|
83
86
|
<YamlTab
|
|
84
87
|
v-if="yamlTabProps"
|
|
@@ -45,11 +45,11 @@ export default {
|
|
|
45
45
|
},
|
|
46
46
|
|
|
47
47
|
showLocale() {
|
|
48
|
-
return (this.availableLocales && Object.keys(this.availableLocales).length > 1) || this.
|
|
48
|
+
return (this.availableLocales && Object.keys(this.availableLocales).length > 1) || this.showNone;
|
|
49
49
|
},
|
|
50
50
|
|
|
51
51
|
showNone() {
|
|
52
|
-
return !!process.env.dev
|
|
52
|
+
return !!process.env.dev;
|
|
53
53
|
},
|
|
54
54
|
},
|
|
55
55
|
|
|
@@ -5,6 +5,7 @@ import { useStore } from 'vuex';
|
|
|
5
5
|
import AppModal from '@shell/components/AppModal.vue';
|
|
6
6
|
|
|
7
7
|
const store = useStore();
|
|
8
|
+
const componentRendered = ref(false);
|
|
8
9
|
|
|
9
10
|
const isOpen = computed(() => store.getters['modal/isOpen']);
|
|
10
11
|
const component = computed(() => store.getters['modal/component']);
|
|
@@ -23,12 +24,20 @@ function close() {
|
|
|
23
24
|
backgroundClosing.value();
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
componentRendered.value = false;
|
|
26
28
|
store.commit('modal/closeModal');
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
function registerBackgroundClosing(fn: Function) {
|
|
30
32
|
backgroundClosing.value = fn;
|
|
31
33
|
}
|
|
34
|
+
|
|
35
|
+
function onSlotComponentMounted() {
|
|
36
|
+
// variable for the watcher based focus-trap
|
|
37
|
+
// so that we know when the component is rendered
|
|
38
|
+
// works in tandem with trigger-focus-trap="true"
|
|
39
|
+
componentRendered.value = true;
|
|
40
|
+
}
|
|
32
41
|
</script>
|
|
33
42
|
|
|
34
43
|
<template>
|
|
@@ -39,7 +48,7 @@ function registerBackgroundClosing(fn: Function) {
|
|
|
39
48
|
:width="modalWidth"
|
|
40
49
|
:style="{ '--prompt-modal-width': modalWidth }"
|
|
41
50
|
:trigger-focus-trap="true"
|
|
42
|
-
|
|
51
|
+
:focus-trap-watcher-based-variable="componentRendered"
|
|
43
52
|
@close="close"
|
|
44
53
|
>
|
|
45
54
|
<component
|
|
@@ -48,6 +57,7 @@ function registerBackgroundClosing(fn: Function) {
|
|
|
48
57
|
data-testid="modal-manager-component"
|
|
49
58
|
:resources="resources"
|
|
50
59
|
:register-background-closing="registerBackgroundClosing"
|
|
60
|
+
@vue:mounted="onSlotComponentMounted"
|
|
51
61
|
@close="close"
|
|
52
62
|
/>
|
|
53
63
|
</app-modal>
|
|
@@ -118,7 +118,7 @@ describe('the yaml Component', () => {
|
|
|
118
118
|
|
|
119
119
|
expect(inputFields).toHaveLength(1);
|
|
120
120
|
|
|
121
|
-
const labelFields = wrapper.findAll('[data-testid="yaml-row-var_name"] .
|
|
121
|
+
const labelFields = wrapper.findAll('[data-testid="yaml-row-var_name"] .has-clean-tooltip');
|
|
122
122
|
|
|
123
123
|
expect(labelFields).toHaveLength(1);
|
|
124
124
|
});
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import Questions from '@shell/components/Questions/index.vue';
|
|
3
|
+
|
|
4
|
+
const mockT = jest.fn((key) => key);
|
|
5
|
+
const mockWithFallback = jest.fn((key, args, fallback) => fallback || key);
|
|
6
|
+
|
|
7
|
+
const defaultMocks = {
|
|
8
|
+
$fetchState: { pending: false },
|
|
9
|
+
$store: {
|
|
10
|
+
getters: {
|
|
11
|
+
'i18n/t': mockT,
|
|
12
|
+
'i18n/withFallback': mockWithFallback
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const defaultProps = {
|
|
18
|
+
source: { questions: { questions: [] } },
|
|
19
|
+
value: {},
|
|
20
|
+
targetNamespace: 'default',
|
|
21
|
+
mode: 'edit',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
describe('component: Questions', () => {
|
|
25
|
+
describe('computed: groups', () => {
|
|
26
|
+
it('should group questions with the same group into a single group', () => {
|
|
27
|
+
const questions = [
|
|
28
|
+
{ variable: 'q1', group: 'Group 1' },
|
|
29
|
+
{ variable: 'q2', group: 'Group 1' },
|
|
30
|
+
];
|
|
31
|
+
const wrapper = shallowMount(Questions, {
|
|
32
|
+
props: { ...defaultProps, source: { questions: { questions } } },
|
|
33
|
+
global: { mocks: defaultMocks },
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const groups = wrapper.vm.groups;
|
|
37
|
+
|
|
38
|
+
expect(groups).toHaveLength(1);
|
|
39
|
+
expect(groups[0].name).toBe('Group 1');
|
|
40
|
+
expect(groups[0].questions).toHaveLength(2);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should place questions without a group into a default group', () => {
|
|
44
|
+
const questions = [
|
|
45
|
+
{ variable: 'q1' },
|
|
46
|
+
{ variable: 'q2' },
|
|
47
|
+
];
|
|
48
|
+
const wrapper = shallowMount(Questions, {
|
|
49
|
+
props: { ...defaultProps, source: { questions: { questions } } },
|
|
50
|
+
global: { mocks: defaultMocks },
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const groups = wrapper.vm.groups;
|
|
54
|
+
|
|
55
|
+
expect(groups).toHaveLength(1);
|
|
56
|
+
expect(groups[0].name).toBe('Questions'); // Default group name
|
|
57
|
+
expect(groups[0].questions).toHaveLength(2);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should create multiple groups for questions with different groups', () => {
|
|
61
|
+
const questions = [
|
|
62
|
+
{ variable: 'q1', group: 'Group 1' },
|
|
63
|
+
{ variable: 'q2', group: 'Group 2' },
|
|
64
|
+
];
|
|
65
|
+
const wrapper = shallowMount(Questions, {
|
|
66
|
+
props: { ...defaultProps, source: { questions: { questions } } },
|
|
67
|
+
global: { mocks: defaultMocks },
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const groups = wrapper.vm.groups;
|
|
71
|
+
|
|
72
|
+
expect(groups).toHaveLength(2);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should correctly group a mix of grouped and ungrouped questions', () => {
|
|
76
|
+
const questions = [
|
|
77
|
+
{ variable: 'q1', group: 'Group 1' },
|
|
78
|
+
{ variable: 'q2' },
|
|
79
|
+
{ variable: 'q3', group: 'Group 1' },
|
|
80
|
+
];
|
|
81
|
+
const wrapper = shallowMount(Questions, {
|
|
82
|
+
props: { ...defaultProps, source: { questions: { questions } } },
|
|
83
|
+
global: { mocks: defaultMocks },
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const groups = wrapper.vm.groups;
|
|
87
|
+
|
|
88
|
+
expect(groups).toHaveLength(2); // 'Group 1' and 'Questions'
|
|
89
|
+
const group1 = groups.find((g: any) => g.name === 'Group 1');
|
|
90
|
+
const defaultGroup = groups.find((g: any) => g.name === 'Questions');
|
|
91
|
+
|
|
92
|
+
expect(group1.questions).toHaveLength(2);
|
|
93
|
+
expect(defaultGroup.questions).toHaveLength(1);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe('computed: asTabs', () => {
|
|
98
|
+
it('should be true by default', () => {
|
|
99
|
+
const wrapper = shallowMount(Questions, {
|
|
100
|
+
props: defaultProps,
|
|
101
|
+
global: { mocks: defaultMocks },
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
expect(wrapper.vm.asTabs).toBe(true);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should be true when tabbed is true', () => {
|
|
108
|
+
const wrapper = shallowMount(Questions, {
|
|
109
|
+
props: { ...defaultProps, tabbed: true },
|
|
110
|
+
global: { mocks: defaultMocks },
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
expect(wrapper.vm.asTabs).toBe(true);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should be false when tabbed is false', () => {
|
|
117
|
+
const wrapper = shallowMount(Questions, {
|
|
118
|
+
props: { ...defaultProps, tabbed: false },
|
|
119
|
+
global: { mocks: defaultMocks },
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
expect(wrapper.vm.asTabs).toBe(false);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should be false when tabbed is "never"', () => {
|
|
126
|
+
const wrapper = shallowMount(Questions, {
|
|
127
|
+
props: { ...defaultProps, tabbed: 'never' },
|
|
128
|
+
global: { mocks: defaultMocks },
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
expect(wrapper.vm.asTabs).toBe(false);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
describe('when tabbed is "multiple"', () => {
|
|
135
|
+
it('should be true if there are groups', () => {
|
|
136
|
+
const questions = [{ variable: 'q1', group: 'Group 1' }];
|
|
137
|
+
const wrapper = shallowMount(Questions, {
|
|
138
|
+
props: {
|
|
139
|
+
...defaultProps, source: { questions: { questions } }, tabbed: 'multiple'
|
|
140
|
+
},
|
|
141
|
+
global: { mocks: defaultMocks },
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
expect(wrapper.vm.groups).toHaveLength(1);
|
|
145
|
+
expect(wrapper.vm.asTabs).toBe(true);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should be false if there are no groups', () => {
|
|
149
|
+
const wrapper = shallowMount(Questions, {
|
|
150
|
+
props: { ...defaultProps, tabbed: 'multiple' },
|
|
151
|
+
global: { mocks: defaultMocks },
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
expect(wrapper.vm.groups).toHaveLength(0);
|
|
155
|
+
expect(wrapper.vm.asTabs).toBe(false);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
});
|
|
@@ -102,6 +102,11 @@ export default {
|
|
|
102
102
|
}
|
|
103
103
|
};
|
|
104
104
|
|
|
105
|
+
// Having an undefined param can yield a console warning like [Vue Router warn]: Discarded invalid param(s) "namespace" when navigating
|
|
106
|
+
if (!detailLocation.params.namespace) {
|
|
107
|
+
delete detailLocation.params.namespace;
|
|
108
|
+
}
|
|
109
|
+
|
|
105
110
|
out.push({
|
|
106
111
|
type,
|
|
107
112
|
id: r[`${ this.direction }Id`],
|
|
@@ -8,7 +8,7 @@ export type Annotation = Row;
|
|
|
8
8
|
export interface AnnotationsProps {
|
|
9
9
|
annotations: Annotation[];
|
|
10
10
|
|
|
11
|
-
onShowConfiguration?: (returnFocusSelector: string) => void;
|
|
11
|
+
onShowConfiguration?: (returnFocusSelector: string, defaultTab: string) => void;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
</script>
|
|
@@ -26,6 +26,6 @@ const i18n = useI18n(store);
|
|
|
26
26
|
:rows="annotations"
|
|
27
27
|
type="active"
|
|
28
28
|
|
|
29
|
-
@show-configuration="(returnFocusSelector: string) => emit('show-configuration', returnFocusSelector)"
|
|
29
|
+
@show-configuration="(returnFocusSelector: string) => emit('show-configuration', returnFocusSelector, 'labels-and-annotations')"
|
|
30
30
|
/>
|
|
31
31
|
</template>
|
|
@@ -8,7 +8,7 @@ export type Label = Row;
|
|
|
8
8
|
export interface LabelsProps {
|
|
9
9
|
labels: Label[];
|
|
10
10
|
|
|
11
|
-
onShowConfiguration?: (returnFocusSelector: string) => void;
|
|
11
|
+
onShowConfiguration?: (returnFocusSelector: string, defaultTab: string) => void;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
</script>
|
|
@@ -27,6 +27,6 @@ const i18n = useI18n(store);
|
|
|
27
27
|
:propertyName="i18n.t('component.resource.detail.metadata.labels.title')"
|
|
28
28
|
:rows="labels"
|
|
29
29
|
type="active"
|
|
30
|
-
@show-configuration="(returnFocusSelector: string) => emit('show-configuration', returnFocusSelector)"
|
|
30
|
+
@show-configuration="(returnFocusSelector: string) => emit('show-configuration', returnFocusSelector, 'labels-and-annotations')"
|
|
31
31
|
/>
|
|
32
32
|
</template>
|
|
@@ -48,7 +48,7 @@ const showBothEmpty = computed(() => labels.length === 0 && annotations.length =
|
|
|
48
48
|
type="active"
|
|
49
49
|
:rows="[]"
|
|
50
50
|
:propertyName="i18n.t('component.resource.detail.metadata.labelsAndAnnotations')"
|
|
51
|
-
@show-configuration="(returnFocusSelector: string) => emit('show-configuration', returnFocusSelector)"
|
|
51
|
+
@show-configuration="(returnFocusSelector: string, defaultTab: string) => emit('show-configuration', returnFocusSelector, defaultTab)"
|
|
52
52
|
/>
|
|
53
53
|
</div>
|
|
54
54
|
<!-- I'm not using v-else here so I can maintain the spacing correctly with the other columns in other rows. -->
|
|
@@ -58,7 +58,7 @@ const showBothEmpty = computed(() => labels.length === 0 && annotations.length =
|
|
|
58
58
|
>
|
|
59
59
|
<Labels
|
|
60
60
|
:labels="labels"
|
|
61
|
-
@show-configuration="(returnFocusSelector: string) => emit('show-configuration', returnFocusSelector)"
|
|
61
|
+
@show-configuration="(returnFocusSelector: string, defaultTab: string) => emit('show-configuration', returnFocusSelector, defaultTab)"
|
|
62
62
|
/>
|
|
63
63
|
</div>
|
|
64
64
|
<div
|
|
@@ -67,7 +67,7 @@ const showBothEmpty = computed(() => labels.length === 0 && annotations.length =
|
|
|
67
67
|
>
|
|
68
68
|
<Annotations
|
|
69
69
|
:annotations="annotations"
|
|
70
|
-
@show-configuration="(returnFocusSelector: string) => emit('show-configuration', returnFocusSelector)"
|
|
70
|
+
@show-configuration="(returnFocusSelector: string, defaultTab: string) => emit('show-configuration', returnFocusSelector, defaultTab)"
|
|
71
71
|
/>
|
|
72
72
|
</div>
|
|
73
73
|
</SpacedRow>
|
|
@@ -31,6 +31,10 @@ const fetch = useFetch(async() => {
|
|
|
31
31
|
return r;
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
+
const stateBackground = computed(() => {
|
|
35
|
+
return fetch.value.data?.stateSimpleColor || 'unknown';
|
|
36
|
+
});
|
|
37
|
+
|
|
34
38
|
const resourceTypeLabel = computed(() => {
|
|
35
39
|
if (!fetch.value.data) {
|
|
36
40
|
return '';
|
|
@@ -67,7 +71,7 @@ const actionInvoked = () => {
|
|
|
67
71
|
>
|
|
68
72
|
<RcStatusIndicator
|
|
69
73
|
shape="disc"
|
|
70
|
-
:status="
|
|
74
|
+
:status="stateBackground"
|
|
71
75
|
/>
|
|
72
76
|
<router-link
|
|
73
77
|
:to="props.detailLocation || fetch.data.detailLocation || '#'"
|
|
@@ -46,12 +46,12 @@ export const useResourceDetailBannerProps = (resource: any): Ref<BannerProps | u
|
|
|
46
46
|
};
|
|
47
47
|
|
|
48
48
|
export const useOnShowConfiguration = (resource: any) => {
|
|
49
|
-
return (returnFocusSelector?: string) => {
|
|
49
|
+
return (returnFocusSelector?: string, defaultTab?: string) => {
|
|
50
50
|
const resourceValue = toValue(resource);
|
|
51
51
|
// Because extensions can make a copy of the resource-class it's possible that an extension will have a resource-class which predates the inclusion of showConfiguration
|
|
52
52
|
// to still the rest of shell to consume
|
|
53
53
|
const showConfiguration = resourceValue.showConfiguration ? resourceValue.showConfiguration.bind(resourceValue) : ResourceClass.prototype.showConfiguration.bind(resourceValue);
|
|
54
54
|
|
|
55
|
-
showConfiguration(returnFocusSelector);
|
|
55
|
+
showConfiguration(returnFocusSelector, defaultTab);
|
|
56
56
|
};
|
|
57
57
|
};
|
|
@@ -42,27 +42,29 @@ const store = useStore();
|
|
|
42
42
|
</script>
|
|
43
43
|
|
|
44
44
|
<template>
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
45
|
+
<div>
|
|
46
|
+
<TitleBar v-bind="titleBarProps" />
|
|
47
|
+
<Banner
|
|
48
|
+
v-if="bannerProps"
|
|
49
|
+
v-ui-context="{
|
|
50
|
+
store: store,
|
|
51
|
+
icon: 'icon-info',
|
|
52
|
+
hookable: true,
|
|
53
|
+
value: {
|
|
54
|
+
bannerProps,
|
|
55
|
+
resource: uiCtxResource
|
|
56
|
+
},
|
|
57
|
+
tag: '__details-state-banner',
|
|
58
|
+
description: 'Status Message'
|
|
59
|
+
}"
|
|
60
|
+
class="new state-banner"
|
|
61
|
+
v-bind="bannerProps"
|
|
62
|
+
/>
|
|
63
|
+
<Metadata
|
|
64
|
+
v-bind="metadataProps"
|
|
65
|
+
class="mmt-4"
|
|
66
|
+
/>
|
|
67
|
+
</div>
|
|
66
68
|
</template>
|
|
67
69
|
|
|
68
70
|
<style lang="scss" scoped>
|
|
@@ -14,6 +14,7 @@ import { clone, diff } from '@shell/utils/object';
|
|
|
14
14
|
import IconMessage from '@shell/components/IconMessage';
|
|
15
15
|
import { stringify } from '@shell/utils/error';
|
|
16
16
|
import { Banner } from '@components/Banner';
|
|
17
|
+
import { useResourceDetailPageProvider } from '@shell/composables/resourceDetail';
|
|
17
18
|
|
|
18
19
|
function modeFor(route) {
|
|
19
20
|
if ( route.query?.mode === _IMPORT ) {
|
|
@@ -116,6 +117,7 @@ export default {
|
|
|
116
117
|
|
|
117
118
|
if ( mode === _VIEW && hasCustomDetail && (!requested || requested === _DETAIL) ) {
|
|
118
119
|
as = _DETAIL;
|
|
120
|
+
useResourceDetailPageProvider();
|
|
119
121
|
} else if ( hasCustomEdit && (!requested || requested === _CONFIG) ) {
|
|
120
122
|
as = _CONFIG;
|
|
121
123
|
} else {
|
|
@@ -351,6 +353,7 @@ export default {
|
|
|
351
353
|
|
|
352
354
|
methods: {
|
|
353
355
|
stringify,
|
|
356
|
+
|
|
354
357
|
setSubtype(subtype) {
|
|
355
358
|
this.resourceSubtype = subtype;
|
|
356
359
|
},
|