@rancher/shell 3.0.8 → 3.0.9-rc.2
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/intf/modal.ts +38 -0
- package/apis/intf/slide-in.ts +3 -1
- package/apis/shell/__tests__/slide-in.test.ts +36 -0
- package/apis/shell/slide-in.ts +5 -1
- package/assets/styles/base/_color.scss +1 -0
- package/assets/styles/base/_typography.scss +14 -5
- package/assets/styles/themes/_light.scss +1 -1
- package/assets/styles/themes/_modern.scss +1 -1
- package/assets/translations/en-us.yaml +94 -33
- package/assets/translations/zh-hans.yaml +0 -2
- package/components/ActionMenuShell.vue +4 -4
- package/components/CodeMirror.vue +4 -3
- package/components/DetailText.vue +54 -7
- package/components/Drawer/Chrome.vue +11 -4
- package/components/Drawer/DrawerCard.vue +19 -0
- package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +3 -11
- package/components/Drawer/ResourceDetailDrawer/__tests__/ConfigTab.test.ts +2 -2
- package/components/Drawer/ResourceDetailDrawer/index.vue +3 -20
- package/components/Drawer/types.ts +1 -0
- package/components/DynamicContent/DynamicContentCloseButton.vue +2 -2
- package/components/LocaleSelector.vue +1 -1
- package/components/Markdown.vue +1 -1
- package/components/PopoverCard.vue +3 -3
- package/components/Resource/Detail/Card/ExtrasCard.vue +39 -0
- package/components/Resource/Detail/Card/StateCard/__tests__/composables.test.ts +142 -0
- package/components/Resource/Detail/Card/StateCard/composables.ts +41 -11
- package/components/Resource/Detail/Card/StateCard/index.vue +3 -9
- package/components/Resource/Detail/Card/StateCard/types.ts +6 -0
- package/components/Resource/Detail/Card/{PodsCard → StatusCard}/index.vue +11 -10
- package/components/Resource/Detail/Card/__tests__/PodsCard.test.ts +24 -25
- package/components/Resource/Detail/Cards.vue +27 -0
- package/components/Resource/Detail/Masthead/__tests__/index.test.ts +70 -0
- package/components/Resource/Detail/Masthead/index.vue +5 -0
- package/components/Resource/Detail/Metadata/KeyValueRow.vue +4 -2
- package/components/Resource/Detail/ResourcePopover/ResourcePopoverCard.vue +2 -2
- package/components/Resource/Detail/ResourceRow.types.ts +14 -0
- package/components/Resource/Detail/ResourceRow.vue +23 -35
- package/components/Resource/Detail/StatusRow.vue +5 -2
- package/components/Resource/Detail/TitleBar/__tests__/composables.test.ts +38 -7
- package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +106 -2
- package/components/Resource/Detail/TitleBar/composables.ts +2 -1
- package/components/Resource/Detail/TitleBar/index.vue +41 -6
- package/components/ResourceDetail/Masthead/__tests__/index.test.ts +49 -1
- package/components/ResourceDetail/Masthead/__tests__/latest.test.ts +85 -0
- package/components/ResourceDetail/Masthead/index.vue +1 -0
- package/components/ResourceDetail/Masthead/latest.vue +8 -1
- package/components/ResourceDetail/Masthead/legacy.vue +1 -1
- package/components/Setting.vue +1 -1
- package/components/SortableTable/index.vue +25 -0
- package/components/SortableTable/selection.js +25 -12
- package/components/SortableTable/sorting.js +1 -1
- package/components/Tabbed/Tab.vue +1 -0
- package/components/Tabbed/index.vue +29 -6
- package/components/Window/ContainerShell.vue +10 -13
- package/components/fleet/FleetClusterTargets/TargetsList.vue +47 -29
- package/components/fleet/FleetClusterTargets/index.vue +82 -29
- package/components/fleet/FleetClusters.vue +26 -12
- package/components/fleet/FleetGitRepoPaths.vue +2 -2
- package/components/fleet/FleetResources.vue +14 -0
- package/components/fleet/FleetValuesFrom.vue +2 -2
- package/components/fleet/__tests__/FleetClusterTargets.test.ts +531 -0
- package/components/fleet/__tests__/FleetClusters.test.ts +576 -0
- package/components/fleet/dashboard/ResourceDetails.vue +96 -123
- package/components/form/Conditions.vue +1 -15
- package/components/form/HookOption.vue +5 -0
- package/components/form/LabeledSelect.vue +1 -1
- package/components/form/LifecycleHooks.vue +2 -6
- package/components/form/ResourceLabeledSelect.vue +12 -1
- package/components/form/SeccompProfile.vue +113 -0
- package/components/form/Security.vue +244 -133
- package/components/form/__tests__/LabeledSelect.test.ts +1 -1
- package/components/form/__tests__/SeccompProfile.test.js +124 -0
- package/components/form/__tests__/Security.test.ts +125 -37
- package/components/formatter/Autoscaler.vue +2 -2
- package/components/formatter/FleetSummaryGraph.vue +4 -1
- package/components/nav/Group.vue +5 -0
- package/components/nav/Header.vue +3 -3
- package/components/nav/HeaderPageActionMenu.vue +1 -1
- package/components/nav/NamespaceFilter.vue +6 -6
- package/components/nav/NotificationCenter/index.vue +1 -1
- package/components/nav/TopLevelMenu.helper.ts +41 -16
- package/components/nav/TopLevelMenu.vue +45 -25
- package/components/nav/WorkspaceSwitcher.vue +1 -1
- package/components/nav/__tests__/TopLevelMenu.helper.test.ts +277 -0
- package/components/nav/__tests__/TopLevelMenu.test.ts +160 -4
- package/components/templates/default.vue +0 -3
- package/components/templates/home.vue +0 -3
- package/components/templates/plain.vue +0 -3
- package/composables/useClickOutside.ts +1 -1
- package/config/product/explorer.js +1 -2
- package/config/types.js +41 -8
- package/detail/__tests__/workload.test.ts +8 -16
- package/detail/catalog.cattle.io.app.vue +6 -0
- package/detail/fleet.cattle.io.cluster.vue +6 -0
- package/detail/workload/index.vue +7 -109
- package/edit/__tests__/projectsecret.test.ts +42 -0
- package/edit/auth/__tests__/oidc.test.ts +50 -0
- package/edit/auth/oidc.vue +68 -44
- package/edit/autoscaling.horizontalpodautoscaler/index.vue +140 -59
- package/edit/autoscaling.horizontalpodautoscaler/metrics-row.vue +41 -5
- package/edit/projectsecret.vue +29 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +89 -200
- package/edit/provisioning.cattle.io.cluster/__tests__/Networking.test.ts +58 -17
- package/edit/provisioning.cattle.io.cluster/rke2.vue +11 -0
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +3 -63
- package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +82 -14
- package/edit/workload/__tests__/index.test.ts +122 -85
- package/edit/workload/index.vue +48 -29
- package/edit/workload/mixins/workload.js +85 -32
- package/list/catalog.cattle.io.clusterrepo.vue +1 -1
- package/list/projectsecret.vue +2 -2
- package/machine-config/__tests__/vmwarevsphere.test.ts +64 -0
- package/machine-config/amazonec2.vue +2 -2
- package/machine-config/vmwarevsphere.vue +58 -4
- package/mixins/__tests__/brand.spec.ts +18 -13
- package/mixins/__tests__/chart.test.ts +63 -0
- package/mixins/chart.js +56 -51
- package/models/__tests__/catalog.cattle.io.app.test.ts +33 -0
- package/models/__tests__/workload.test.ts +333 -0
- package/models/catalog.cattle.io.app.js +8 -0
- package/models/pod.js +14 -0
- package/models/secret.js +1 -1
- package/models/workload.js +93 -27
- package/package.json +4 -4
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +91 -0
- package/pages/c/_cluster/apps/charts/install.vue +4 -4
- package/pages/c/_cluster/explorer/EventsTable.vue +2 -2
- package/pages/c/_cluster/fleet/index.vue +18 -12
- package/pages/c/_cluster/manager/hostedprovider/index.vue +1 -19
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +1 -1
- package/pages/c/_cluster/uiplugins/index.vue +1 -1
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +234 -0
- package/plugins/dashboard-store/actions.js +9 -8
- package/plugins/dashboard-store/resource-class.js +97 -1
- package/plugins/steve/__tests__/revision.test.ts +84 -0
- package/plugins/steve/__tests__/steve-pagination-utils.test.ts +30 -0
- package/plugins/steve/__tests__/subscribe.spec.ts +134 -0
- package/plugins/steve/mutations.js +9 -0
- package/plugins/steve/revision.ts +26 -0
- package/plugins/steve/steve-pagination-utils.ts +6 -5
- package/plugins/steve/subscribe.js +211 -51
- package/plugins/subscribe-events.ts +2 -2
- package/rancher-components/Form/Checkbox/Checkbox.vue +13 -0
- package/rancher-components/LabeledTooltip/LabeledTooltip.vue +1 -1
- package/rancher-components/Pill/RcCounterBadge/RcCounterBadge.vue +1 -1
- package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +3 -1
- package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +3 -1
- package/rancher-components/Pill/RcTag/RcTag.vue +1 -1
- package/rancher-components/Pill/index.ts +4 -0
- package/rancher-components/RcButton/RcButton.test.ts +53 -9
- package/rancher-components/RcButton/RcButton.vue +217 -25
- package/rancher-components/RcButton/types.ts +27 -1
- package/rancher-components/RcDropdown/RcDropdownMenu.vue +4 -4
- package/rancher-components/RcDropdown/types.ts +3 -3
- package/rancher-components/RcIcon/RcIcon.test.ts +42 -0
- package/rancher-components/RcIcon/RcIcon.vue +9 -6
- package/rancher-components/RcIcon/types.ts +13 -9
- package/rancher-components/utils/status.test.ts +10 -15
- package/rancher-components/utils/status.ts +5 -6
- package/store/aws.js +18 -12
- package/store/index.js +4 -8
- package/store/type-map.utils.ts +1 -1
- package/types/kube/kube-api.ts +29 -3
- package/types/rancher/steve.api.ts +40 -0
- package/types/shell/index.d.ts +99 -0
- package/types/store/dashboard-store.types.ts +29 -7
- package/types/store/pagination.types.ts +1 -0
- package/types/store/subscribe-events.types.ts +1 -0
- package/utils/__tests__/azure.test.ts +56 -0
- package/utils/__tests__/back-off.test.ts +364 -245
- package/utils/__tests__/error.test.ts +44 -0
- package/utils/__tests__/fleet.test.ts +8 -1
- package/utils/__tests__/pagination-wrapper.test.ts +167 -0
- package/utils/__tests__/version.test.ts +55 -1
- package/utils/azure.js +12 -0
- package/utils/back-off.ts +302 -69
- package/utils/cspAdaptor.ts +32 -14
- package/utils/dynamic-content/__tests__/index.test.ts +1 -1
- package/utils/dynamic-content/__tests__/new-release.test.ts +48 -7
- package/utils/dynamic-content/__tests__/support-notice.test.ts +1 -4
- package/utils/dynamic-content/index.ts +1 -6
- package/utils/dynamic-content/new-release.ts +5 -3
- package/utils/dynamic-content/types.d.ts +0 -1
- package/utils/error.js +9 -0
- package/utils/fleet.ts +2 -2
- package/utils/inactivity.ts +2 -3
- package/utils/pagination-wrapper.ts +101 -17
- package/utils/validators/formRules/index.ts +3 -0
- package/utils/version.js +38 -0
- package/components/auth/AzureWarning.vue +0 -77
- /package/components/Resource/Detail/{Card/PodsCard/Bubble.vue → Bubble.vue} +0 -0
- /package/components/Resource/Detail/Card/{PodsCard → StatusCard}/composable.ts +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rancher/shell",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.9-rc.2",
|
|
4
4
|
"description": "Rancher Dashboard Shell",
|
|
5
5
|
"repository": "https://github.com/rancher/dashboard",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"cookie": "0.7.0",
|
|
68
68
|
"core-js": "3.45.0",
|
|
69
69
|
"cron-validator": "1.4.0",
|
|
70
|
-
"cronstrue": "
|
|
70
|
+
"cronstrue": "3.9.0",
|
|
71
71
|
"cross-env": "7.0.3",
|
|
72
72
|
"css-loader": "6.7.3",
|
|
73
73
|
"csv-loader": "3.0.3",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"d3-selection": "3.0.0",
|
|
77
77
|
"d3": "7.3.0",
|
|
78
78
|
"dayjs": "1.11.18",
|
|
79
|
-
"defu": "
|
|
79
|
+
"defu": "6.1.4",
|
|
80
80
|
"diff2html": "3.4.24",
|
|
81
81
|
"dompurify": "3.2.5",
|
|
82
82
|
"element-matches": "^0.1.2",
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
"jsonpath-plus": "10.3.0",
|
|
112
112
|
"jsrsasign": "11.0.0",
|
|
113
113
|
"jszip": "3.10.1",
|
|
114
|
-
"lodash": "4.17.
|
|
114
|
+
"lodash": "4.17.23",
|
|
115
115
|
"marked": "4.0.17",
|
|
116
116
|
"node-polyfill-webpack-plugin": "3.0.0",
|
|
117
117
|
"nodemon": "2.0.22",
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
|
|
2
|
+
import { mount } from '@vue/test-utils';
|
|
3
|
+
import Install from '@shell/pages/c/_cluster/apps/charts/install.vue';
|
|
4
|
+
import { CATALOG as CATALOG_ANNOTATIONS } from '@shell/config/labels-annotations';
|
|
5
|
+
|
|
6
|
+
describe('page: Install', () => {
|
|
7
|
+
it('should use version annotations for target namespace and name', async() => {
|
|
8
|
+
const mockStore = {
|
|
9
|
+
dispatch: jest.fn((action) => {
|
|
10
|
+
if (action === 'cluster/create') {
|
|
11
|
+
return Promise.resolve({ metadata: { namespace: '', name: '' } });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return Promise.resolve();
|
|
15
|
+
}),
|
|
16
|
+
getters: {
|
|
17
|
+
'catalog/inStore': 'cluster',
|
|
18
|
+
'features/get': () => false,
|
|
19
|
+
defaultNamespace: 'default',
|
|
20
|
+
'i18n/withFallback': (key: string) => key,
|
|
21
|
+
'type-map/hasCustomChart': () => false,
|
|
22
|
+
'cluster/all': () => [],
|
|
23
|
+
'cluster/byId': () => null,
|
|
24
|
+
'management/all': () => [],
|
|
25
|
+
'prefs/get': () => {},
|
|
26
|
+
'catalog/charts': [],
|
|
27
|
+
'wm/byId': () => null,
|
|
28
|
+
'i18n/t': (key: string) => key,
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const wrapper = mount(Install, {
|
|
33
|
+
global: {
|
|
34
|
+
mocks: {
|
|
35
|
+
$store: mockStore,
|
|
36
|
+
$route: { query: {} },
|
|
37
|
+
$fetchState: { pending: false },
|
|
38
|
+
t: (key: string) => key,
|
|
39
|
+
},
|
|
40
|
+
stubs: {
|
|
41
|
+
Loading: true,
|
|
42
|
+
Wizard: true,
|
|
43
|
+
Banner: true,
|
|
44
|
+
Checkbox: true,
|
|
45
|
+
LabeledInput: true,
|
|
46
|
+
LabeledSelect: true,
|
|
47
|
+
NameNsDescription: true,
|
|
48
|
+
Tabbed: true,
|
|
49
|
+
Questions: true,
|
|
50
|
+
YamlEditor: true,
|
|
51
|
+
ResourceCancelModal: true,
|
|
52
|
+
UnitInput: true,
|
|
53
|
+
TypeDescription: true,
|
|
54
|
+
LazyImage: true,
|
|
55
|
+
ChartReadme: true,
|
|
56
|
+
ButtonGroup: true,
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
data() {
|
|
60
|
+
return {
|
|
61
|
+
version: {
|
|
62
|
+
annotations: {
|
|
63
|
+
[CATALOG_ANNOTATIONS.NAMESPACE]: 'custom-ns',
|
|
64
|
+
[CATALOG_ANNOTATIONS.RELEASE_NAME]: 'custom-name',
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
chart: {
|
|
68
|
+
targetNamespace: 'wrong-ns',
|
|
69
|
+
targetName: 'wrong-name',
|
|
70
|
+
versions: []
|
|
71
|
+
},
|
|
72
|
+
query: { versionName: '1.0.0' }
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Mock methods from mixins
|
|
78
|
+
jest.spyOn((wrapper.vm as any), 'fetchChart').mockImplementation().mockResolvedValue(undefined);
|
|
79
|
+
jest.spyOn((wrapper.vm as any), 'fetchAutoInstallInfo').mockImplementation().mockResolvedValue(undefined);
|
|
80
|
+
jest.spyOn((wrapper.vm as any), 'getClusterRegistry').mockImplementation().mockResolvedValue(undefined);
|
|
81
|
+
jest.spyOn((wrapper.vm as any), 'getGlobalRegistry').mockImplementation().mockResolvedValue(undefined);
|
|
82
|
+
jest.spyOn((wrapper.vm as any), 'loadValuesComponent').mockImplementation().mockResolvedValue(undefined);
|
|
83
|
+
jest.spyOn((wrapper.vm as any), 'updateStepOneReady').mockImplementation();
|
|
84
|
+
|
|
85
|
+
// Trigger fetch
|
|
86
|
+
await Install.fetch.call(wrapper.vm);
|
|
87
|
+
|
|
88
|
+
expect(wrapper.vm.forceNamespace).toBe('custom-ns');
|
|
89
|
+
expect(wrapper.vm.value.metadata.name).toBe('custom-name');
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -166,10 +166,10 @@ export default {
|
|
|
166
166
|
} else if (this.$route.query[FROM_CLUSTER] === _FLAGGED) {
|
|
167
167
|
/* For Fleet, use the fleet-default namespace. */
|
|
168
168
|
this.forceNamespace = DEFAULT_WORKSPACE;
|
|
169
|
-
} else if ( this.
|
|
169
|
+
} else if ( this.version?.annotations?.[CATALOG_ANNOTATIONS.NAMESPACE] ) {
|
|
170
170
|
/* If a target namespace is defined in the chart,
|
|
171
171
|
set the target namespace as default. */
|
|
172
|
-
this.forceNamespace = this.
|
|
172
|
+
this.forceNamespace = this.version.annotations[CATALOG_ANNOTATIONS.NAMESPACE];
|
|
173
173
|
} else if ( this.query.appNamespace ) {
|
|
174
174
|
/* If a namespace is defined in the URL query,
|
|
175
175
|
use that namespace as default. */
|
|
@@ -219,13 +219,13 @@ export default {
|
|
|
219
219
|
The target name indicates the name of the cluster
|
|
220
220
|
group that the chart is meant to be installed in.
|
|
221
221
|
*/
|
|
222
|
-
if ( this.
|
|
222
|
+
if ( this.version?.annotations?.[CATALOG_ANNOTATIONS.RELEASE_NAME] ) {
|
|
223
223
|
/*
|
|
224
224
|
Set the name of the chartInstallAction
|
|
225
225
|
to the name of the cluster group
|
|
226
226
|
where the chart should be installed.
|
|
227
227
|
*/
|
|
228
|
-
this.value.metadata.name = this.
|
|
228
|
+
this.value.metadata.name = this.version.annotations[CATALOG_ANNOTATIONS.RELEASE_NAME];
|
|
229
229
|
this.nameDisabled = true;
|
|
230
230
|
} else if ( this.query.appName ) {
|
|
231
231
|
this.value.metadata.name = this.query.appName;
|
|
@@ -170,8 +170,8 @@ export default {
|
|
|
170
170
|
<rc-dropdown-trigger
|
|
171
171
|
data-testid="events-list-row-count-menu-toggle"
|
|
172
172
|
:aria-label="t('glance.changeEventsListRowCount')"
|
|
173
|
-
ghost
|
|
174
|
-
small
|
|
173
|
+
variant="ghost"
|
|
174
|
+
size="small"
|
|
175
175
|
>
|
|
176
176
|
<i class="icon icon-gear" />
|
|
177
177
|
</rc-dropdown-trigger>
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
<script>
|
|
1
|
+
<script lang="ts">
|
|
2
2
|
import debounce from 'lodash/debounce';
|
|
3
3
|
import { getVersionData } from '@shell/config/version';
|
|
4
4
|
import { mapState, mapGetters } from 'vuex';
|
|
5
5
|
import { isEmpty } from '@shell/utils/object';
|
|
6
6
|
import { FLEET } from '@shell/config/types';
|
|
7
7
|
import { WORKSPACE } from '@shell/store/prefs';
|
|
8
|
-
import Loading from '@shell/components/Loading';
|
|
8
|
+
import Loading from '@shell/components/Loading.vue';
|
|
9
9
|
import { checkPermissions, checkSchemasForFindAllHash } from '@shell/utils/auth';
|
|
10
10
|
import { WORKSPACE_ANNOTATION } from '@shell/config/labels-annotations';
|
|
11
11
|
import { filterBy } from '@shell/utils/array';
|
|
@@ -15,7 +15,7 @@ import ResourcePanel from '@shell/components/fleet/dashboard/ResourcePanel.vue';
|
|
|
15
15
|
import ResourceCard from '@shell/components/fleet/dashboard/ResourceCard.vue';
|
|
16
16
|
import ResourceDetails from '@shell/components/fleet/dashboard/ResourceDetails.vue';
|
|
17
17
|
import EmptyDashboard from '@shell/components/fleet/dashboard/Empty.vue';
|
|
18
|
-
import ButtonGroup from '@shell/components/ButtonGroup';
|
|
18
|
+
import ButtonGroup from '@shell/components/ButtonGroup.vue';
|
|
19
19
|
import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
|
|
20
20
|
import FleetApplications from '@shell/components/fleet/FleetApplications.vue';
|
|
21
21
|
import FleetUtils from '@shell/utils/fleet';
|
|
@@ -322,13 +322,19 @@ export default {
|
|
|
322
322
|
this.selectedCard = selected;
|
|
323
323
|
|
|
324
324
|
this.$shell.slideIn.open(ResourceDetails, {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
width: window.innerWidth / 3 > 530 ? `${ window.innerWidth / 3 }px` : '530px',
|
|
325
|
+
showHeader: false,
|
|
326
|
+
props: {
|
|
328
327
|
value,
|
|
329
328
|
statePanel,
|
|
330
329
|
workspace
|
|
331
|
-
}
|
|
330
|
+
},
|
|
331
|
+
width: '73%',
|
|
332
|
+
// We want this to be full viewport height top to bottom
|
|
333
|
+
height: '100vh',
|
|
334
|
+
top: '0',
|
|
335
|
+
'z-index': 101, // We want this to be above the main side menu
|
|
336
|
+
closeOnRouteChange: ['name', 'params', 'query'], // We want to ignore hash changes, tables in extensions can trigger the drawer to close while opening
|
|
337
|
+
triggerFocusTrap: false,
|
|
332
338
|
});
|
|
333
339
|
},
|
|
334
340
|
|
|
@@ -493,8 +499,8 @@ export default {
|
|
|
493
499
|
@update:value="viewMode = $event"
|
|
494
500
|
/>
|
|
495
501
|
<RcButton
|
|
496
|
-
small
|
|
497
|
-
ghost
|
|
502
|
+
size="small"
|
|
503
|
+
variant="ghost"
|
|
498
504
|
data-testid="fleet-dashboard-expand-all"
|
|
499
505
|
class="collapse-all-btn"
|
|
500
506
|
@click="toggleCardAll(allCardsExpanded ? 'collapse' : 'expand')"
|
|
@@ -579,8 +585,8 @@ export default {
|
|
|
579
585
|
:data-testid="'expand-button'"
|
|
580
586
|
>
|
|
581
587
|
<RcButton
|
|
582
|
-
small
|
|
583
|
-
ghost
|
|
588
|
+
size="small"
|
|
589
|
+
variant="ghost"
|
|
584
590
|
:aria-label="`workspace-expand-btn-${ workspace.id }`"
|
|
585
591
|
:data-testid="`workspace-expand-btn-${ workspace.id }`"
|
|
586
592
|
@click="toggleCard(workspace.id)"
|
|
@@ -646,7 +652,7 @@ export default {
|
|
|
646
652
|
class="create-button"
|
|
647
653
|
>
|
|
648
654
|
<RcButton
|
|
649
|
-
small
|
|
655
|
+
size="small"
|
|
650
656
|
@click="createResource(workspace.id)"
|
|
651
657
|
>
|
|
652
658
|
{{ t('fleet.application.intro.add') }}
|
|
@@ -7,7 +7,6 @@ import Masthead from '@shell/components/ResourceList/Masthead';
|
|
|
7
7
|
import Banner from '@components/Banner/Banner.vue';
|
|
8
8
|
import RcStatusBadge from '@components/Pill/RcStatusBadge/RcStatusBadge.vue';
|
|
9
9
|
import { exceptionToErrorsArray } from '@shell/utils/error';
|
|
10
|
-
import { isRancherPrime } from '@shell/config/version';
|
|
11
10
|
import { stateDisplay, STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
|
|
12
11
|
import { getHostedProviders } from '@shell/utils/provider';
|
|
13
12
|
|
|
@@ -23,7 +22,6 @@ export default {
|
|
|
23
22
|
allProviders: null,
|
|
24
23
|
resource: HOSTED_PROVIDER,
|
|
25
24
|
schema: this.$store.getters['rancher/schemaFor'](HOSTED_PROVIDER),
|
|
26
|
-
prime: isRancherPrime(),
|
|
27
25
|
settingResource: null
|
|
28
26
|
};
|
|
29
27
|
},
|
|
@@ -107,14 +105,13 @@ export default {
|
|
|
107
105
|
async generateRows() {
|
|
108
106
|
this.rows = this.allProviders.map((p) => {
|
|
109
107
|
const active = p.id in this.settings ? this.settings[p.id] : true;
|
|
110
|
-
const canNotPrime = p.prime && !this.prime;
|
|
111
108
|
const canNotChangeSettings = !this.settingResource?.canUpdate;
|
|
112
109
|
const enableAction = {
|
|
113
110
|
action: 'activate',
|
|
114
111
|
label: this.t('action.activate'),
|
|
115
112
|
icon: 'icon icon-play',
|
|
116
113
|
bulkable: true,
|
|
117
|
-
enabled: !active && !
|
|
114
|
+
enabled: !active && !canNotChangeSettings,
|
|
118
115
|
invoke: async(opts, resources) => {
|
|
119
116
|
await this.setSetting(resources, true);
|
|
120
117
|
}
|
|
@@ -137,7 +134,6 @@ export default {
|
|
|
137
134
|
name: p.label,
|
|
138
135
|
nameDisplay: p.label,
|
|
139
136
|
description: p.description || '',
|
|
140
|
-
prime: p.prime,
|
|
141
137
|
active,
|
|
142
138
|
availableActions
|
|
143
139
|
};
|
|
@@ -192,13 +188,6 @@ export default {
|
|
|
192
188
|
<div class="col">
|
|
193
189
|
<div class="row">
|
|
194
190
|
<span class="mr-10">{{ row.name }}</span>
|
|
195
|
-
<RcStatusBadge
|
|
196
|
-
v-if="row.prime"
|
|
197
|
-
class="prime-badge"
|
|
198
|
-
status="success"
|
|
199
|
-
>
|
|
200
|
-
{{ t('providers.hosted.prime') }}
|
|
201
|
-
</RcStatusBadge>
|
|
202
191
|
</div>
|
|
203
192
|
<div
|
|
204
193
|
v-if="row.description"
|
|
@@ -211,10 +200,3 @@ export default {
|
|
|
211
200
|
</ResourceTable>
|
|
212
201
|
</div>
|
|
213
202
|
</template>
|
|
214
|
-
|
|
215
|
-
<style lang="scss" scoped>
|
|
216
|
-
.prime-badge {
|
|
217
|
-
font-size: 10px;
|
|
218
|
-
line-height: 15px;
|
|
219
|
-
}
|
|
220
|
-
</style>
|
|
@@ -917,7 +917,7 @@ export default {
|
|
|
917
917
|
<div v-if="hasFeatureFlag && hasMenuActions">
|
|
918
918
|
<ActionMenu
|
|
919
919
|
data-testid="extensions-page-menu"
|
|
920
|
-
button-
|
|
920
|
+
button-variant="tertiary"
|
|
921
921
|
:button-aria-label="t('plugins.labels.menu')"
|
|
922
922
|
:custom-actions="menuActions"
|
|
923
923
|
@devLoad="showDeveloperLoadDialog"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import jsyaml from 'js-yaml';
|
|
2
2
|
import Resource from '@shell/plugins/dashboard-store/resource-class.js';
|
|
3
3
|
import { resourceClassJunkObject } from '@shell/plugins/dashboard-store/__tests__/utils/store-mocks';
|
|
4
|
+
import { EVENT } from '@shell/config/types';
|
|
4
5
|
|
|
5
6
|
describe('class: Resource', () => {
|
|
6
7
|
describe('given custom resource keys', () => {
|
|
@@ -237,4 +238,237 @@ describe('class: Resource', () => {
|
|
|
237
238
|
expect(mockStore.dispatch).not.toHaveBeenCalledWith('load', expect.any(Object));
|
|
238
239
|
});
|
|
239
240
|
});
|
|
241
|
+
|
|
242
|
+
describe('getter: resourceConditions', () => {
|
|
243
|
+
it('should return empty array when status.conditions is undefined', () => {
|
|
244
|
+
const resource = new Resource({ type: 'test' }, {
|
|
245
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
246
|
+
dispatch: jest.fn(),
|
|
247
|
+
rootGetters: { 'i18n/t': jest.fn() },
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
expect(resource.resourceConditions).toStrictEqual([]);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('should return empty array when status is undefined', () => {
|
|
254
|
+
const resource = new Resource({ type: 'test', status: {} }, {
|
|
255
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
256
|
+
dispatch: jest.fn(),
|
|
257
|
+
rootGetters: { 'i18n/t': jest.fn() },
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
expect(resource.resourceConditions).toStrictEqual([]);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('should map conditions correctly', () => {
|
|
264
|
+
const resource = new Resource({
|
|
265
|
+
type: 'test',
|
|
266
|
+
status: {
|
|
267
|
+
conditions: [
|
|
268
|
+
{
|
|
269
|
+
type: 'Ready', status: 'True', message: 'Resource is ready', lastTransitionTime: '2024-01-01T00:00:00Z'
|
|
270
|
+
},
|
|
271
|
+
]
|
|
272
|
+
}
|
|
273
|
+
}, {
|
|
274
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
275
|
+
dispatch: jest.fn(),
|
|
276
|
+
rootGetters: { 'i18n/t': jest.fn() },
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
const conditions = resource.resourceConditions;
|
|
280
|
+
|
|
281
|
+
expect(conditions).toHaveLength(1);
|
|
282
|
+
expect(conditions[0].condition).toBe('Ready');
|
|
283
|
+
expect(conditions[0].status).toBe('True');
|
|
284
|
+
expect(conditions[0].message).toBe('Resource is ready');
|
|
285
|
+
expect(conditions[0].stateSimpleColor).toBe('disabled');
|
|
286
|
+
expect(conditions[0].time).toBe('2024-01-01T00:00:00Z');
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('should set error color when condition has error', () => {
|
|
290
|
+
const resource = new Resource({
|
|
291
|
+
type: 'test',
|
|
292
|
+
status: {
|
|
293
|
+
conditions: [
|
|
294
|
+
{
|
|
295
|
+
type: 'Ready', status: 'False', error: true, message: 'Something failed'
|
|
296
|
+
},
|
|
297
|
+
]
|
|
298
|
+
}
|
|
299
|
+
}, {
|
|
300
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
301
|
+
dispatch: jest.fn(),
|
|
302
|
+
rootGetters: { 'i18n/t': jest.fn() },
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
const conditions = resource.resourceConditions;
|
|
306
|
+
|
|
307
|
+
expect(conditions[0].stateSimpleColor).toBe('error');
|
|
308
|
+
expect(conditions[0].error).toBe(true);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it('should prepend reason to message when present', () => {
|
|
312
|
+
const resource = new Resource({
|
|
313
|
+
type: 'test',
|
|
314
|
+
status: {
|
|
315
|
+
conditions: [
|
|
316
|
+
{
|
|
317
|
+
type: 'Ready', status: 'False', reason: 'MinimumReplicasUnavailable', message: 'Deployment does not have minimum availability.'
|
|
318
|
+
},
|
|
319
|
+
]
|
|
320
|
+
}
|
|
321
|
+
}, {
|
|
322
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
323
|
+
dispatch: jest.fn(),
|
|
324
|
+
rootGetters: { 'i18n/t': jest.fn() },
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
const conditions = resource.resourceConditions;
|
|
328
|
+
|
|
329
|
+
expect(conditions[0].message).toBe('[MinimumReplicasUnavailable] Deployment does not have minimum availability.');
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it('should use Unknown for missing type and status', () => {
|
|
333
|
+
const resource = new Resource({
|
|
334
|
+
type: 'test',
|
|
335
|
+
status: {
|
|
336
|
+
conditions: [
|
|
337
|
+
{ message: 'Some message' },
|
|
338
|
+
]
|
|
339
|
+
}
|
|
340
|
+
}, {
|
|
341
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
342
|
+
dispatch: jest.fn(),
|
|
343
|
+
rootGetters: { 'i18n/t': jest.fn() },
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
const conditions = resource.resourceConditions;
|
|
347
|
+
|
|
348
|
+
expect(conditions[0].condition).toBe('Unknown');
|
|
349
|
+
expect(conditions[0].status).toBe('Unknown');
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('should prioritize time fields correctly', () => {
|
|
353
|
+
const resource = new Resource({
|
|
354
|
+
type: 'test',
|
|
355
|
+
status: {
|
|
356
|
+
conditions: [
|
|
357
|
+
{
|
|
358
|
+
type: 'Test', lastProbeTime: 'probe-time', lastUpdateTime: 'update-time', lastTransitionTime: 'transition-time'
|
|
359
|
+
},
|
|
360
|
+
]
|
|
361
|
+
}
|
|
362
|
+
}, {
|
|
363
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
364
|
+
dispatch: jest.fn(),
|
|
365
|
+
rootGetters: { 'i18n/t': jest.fn() },
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
const conditions = resource.resourceConditions;
|
|
369
|
+
|
|
370
|
+
expect(conditions[0].time).toBe('probe-time');
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
describe('getter: resourceEvents', () => {
|
|
375
|
+
it('should return events from the store', () => {
|
|
376
|
+
const mockEvents = [{ type: 'Normal', reason: 'Test' }];
|
|
377
|
+
const resource = new Resource({ type: 'test' }, {
|
|
378
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
379
|
+
dispatch: jest.fn(),
|
|
380
|
+
rootGetters: { 'i18n/t': jest.fn(), 'cluster/all': (type: string) => (type === EVENT ? mockEvents : []) },
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
expect(resource.resourceEvents).toStrictEqual(mockEvents);
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
describe('getter: cards', () => {
|
|
388
|
+
it('should return an array containing the insight card', () => {
|
|
389
|
+
const resource = new Resource({ type: 'test' }, {
|
|
390
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
391
|
+
dispatch: jest.fn(),
|
|
392
|
+
rootGetters: {
|
|
393
|
+
'i18n/t': (key: string) => key,
|
|
394
|
+
'cluster/all': () => []
|
|
395
|
+
},
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
const cards = resource.cards;
|
|
399
|
+
|
|
400
|
+
expect(cards).toHaveLength(1);
|
|
401
|
+
expect(cards[0]).toHaveProperty('component');
|
|
402
|
+
expect(cards[0]).toHaveProperty('props');
|
|
403
|
+
});
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
describe('getter: insightCardProps', () => {
|
|
407
|
+
it('should return props with title and rows', () => {
|
|
408
|
+
const resource = new Resource({
|
|
409
|
+
type: 'test',
|
|
410
|
+
status: {
|
|
411
|
+
conditions: [
|
|
412
|
+
{ type: 'Ready', status: 'True' }
|
|
413
|
+
]
|
|
414
|
+
}
|
|
415
|
+
}, {
|
|
416
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
417
|
+
dispatch: jest.fn(),
|
|
418
|
+
rootGetters: {
|
|
419
|
+
'i18n/t': (key: string) => key,
|
|
420
|
+
'cluster/all': () => []
|
|
421
|
+
},
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
const props = resource.insightCardProps;
|
|
425
|
+
|
|
426
|
+
expect(props.title).toBe('component.resource.detail.card.insightsCard.title');
|
|
427
|
+
expect(props.rows).toHaveLength(2);
|
|
428
|
+
expect(props.rows[0].label).toBe('component.resource.detail.card.insightsCard.rows.conditions');
|
|
429
|
+
expect(props.rows[1].label).toBe('component.resource.detail.card.insightsCard.rows.events');
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
describe('getter: detailPageAdditionalActions', () => {
|
|
434
|
+
it('should return undefined by default', () => {
|
|
435
|
+
const resource = new Resource({ type: 'test-type' }, {
|
|
436
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
437
|
+
dispatch: jest.fn(),
|
|
438
|
+
rootGetters: { 'i18n/t': jest.fn() },
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
expect(resource.detailPageAdditionalActions).toBeUndefined();
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
it('should allow subclasses to override and return button props array', () => {
|
|
445
|
+
class CustomResource extends Resource {
|
|
446
|
+
get detailPageAdditionalActions() {
|
|
447
|
+
return [
|
|
448
|
+
{
|
|
449
|
+
label: 'Action 1', variant: 'secondary', onClick: () => {}
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
label: 'Action 2', variant: 'primary', onClick: () => {}
|
|
453
|
+
}
|
|
454
|
+
];
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const resource = new CustomResource({ type: 'test-type' }, {
|
|
459
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
460
|
+
dispatch: jest.fn(),
|
|
461
|
+
rootGetters: { 'i18n/t': jest.fn() },
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
const actions = resource.detailPageAdditionalActions;
|
|
465
|
+
|
|
466
|
+
expect(Array.isArray(actions)).toBe(true);
|
|
467
|
+
expect(actions).toHaveLength(2);
|
|
468
|
+
expect(actions[0].label).toBe('Action 1');
|
|
469
|
+
expect(actions[0].variant).toBe('secondary');
|
|
470
|
+
expect(actions[1].label).toBe('Action 2');
|
|
471
|
+
expect(actions[1].variant).toBe('primary');
|
|
472
|
+
});
|
|
473
|
+
});
|
|
240
474
|
});
|
|
@@ -471,7 +471,7 @@ export default {
|
|
|
471
471
|
return findAllGetter(getters, type, opt);
|
|
472
472
|
}
|
|
473
473
|
|
|
474
|
-
console.log(`Find Page: [${ ctx.state.config.namespace }] ${ type }. Page: ${ opt.pagination.page }. Size: ${ opt.pagination.pageSize }. Sort: ${ opt.pagination.sort.map((s) => s.field).join(', ') }`); // eslint-disable-line no-console
|
|
474
|
+
console.log(`Find Page: [${ ctx.state.config.namespace }] ${ type }. Page: ${ opt.pagination.page }. Revision: ${ opt.revision || 'none' }. Size: ${ opt.pagination.pageSize }. Sort: ${ opt.pagination.sort.map((s) => s.field).join(', ') }`); // eslint-disable-line no-console
|
|
475
475
|
opt = opt || {};
|
|
476
476
|
opt.url = getters.urlFor(type, null, opt);
|
|
477
477
|
|
|
@@ -491,7 +491,7 @@ export default {
|
|
|
491
491
|
return Promise.reject(e);
|
|
492
492
|
}
|
|
493
493
|
|
|
494
|
-
// Of type @
|
|
494
|
+
// Of type @StorePaginationResult
|
|
495
495
|
const pagination = opt.pagination ? {
|
|
496
496
|
request: {
|
|
497
497
|
namespace: opt.namespaced,
|
|
@@ -500,7 +500,8 @@ export default {
|
|
|
500
500
|
result: {
|
|
501
501
|
count: out.count,
|
|
502
502
|
pages: out.pages || Math.ceil(out.count / (opt.pagination.pageSize || Number.MAX_SAFE_INTEGER)),
|
|
503
|
-
timestamp: new Date().getTime()
|
|
503
|
+
timestamp: new Date().getTime(),
|
|
504
|
+
revision: out.revision
|
|
504
505
|
}
|
|
505
506
|
} : undefined;
|
|
506
507
|
|
|
@@ -698,19 +699,19 @@ export default {
|
|
|
698
699
|
|
|
699
700
|
const res = await dispatch('request', { opt, type });
|
|
700
701
|
|
|
701
|
-
|
|
702
|
+
if (!opt.transient) {
|
|
703
|
+
await dispatch('load', { data: res, invalidatePageCache: opt.invalidatePageCache });
|
|
704
|
+
}
|
|
702
705
|
|
|
703
|
-
if ( opt.watch !== false ) {
|
|
706
|
+
if (!opt.transient && opt.watch !== false ) {
|
|
704
707
|
dispatch('watch', createFindWatchArg({
|
|
705
708
|
type, id, opt, res
|
|
706
709
|
}));
|
|
707
710
|
}
|
|
708
711
|
|
|
709
|
-
out = getters.byId(type, id);
|
|
710
|
-
|
|
711
712
|
garbageCollect.gcUpdateLastAccessed(ctx, type);
|
|
712
713
|
|
|
713
|
-
return
|
|
714
|
+
return opt.transient ? await dispatch('create', res) : getters.byId(type, id);
|
|
714
715
|
},
|
|
715
716
|
|
|
716
717
|
/**
|