@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
|
@@ -1,55 +1,143 @@
|
|
|
1
1
|
import { mount } from '@vue/test-utils';
|
|
2
|
-
import Security from '@shell/components/form/Security.vue';
|
|
2
|
+
import Security, { FORM_TYPES } from '@shell/components/form/Security.vue';
|
|
3
3
|
import { _EDIT } from '@shell/config/query-params';
|
|
4
4
|
|
|
5
5
|
describe('component: Security', () => {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
describe('formType: container', () => {
|
|
7
|
+
it('should display all the container inputs', () => {
|
|
8
|
+
const wrapper = mount(Security, { props: { mode: _EDIT, formType: FORM_TYPES.CONTAINER } });
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
const inputWrappers = wrapper.findAll('[data-testid^=input-security-]');
|
|
11
|
+
const actualIds = inputWrappers.map((wrap) => wrap.attributes('data-testid'));
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
const expectedIds = [
|
|
14
|
+
'input-security-privileged',
|
|
15
|
+
'input-security-allowPrivilegeEscalation',
|
|
16
|
+
'input-security-seccompProfile-type',
|
|
17
|
+
'input-security-runasNonRoot',
|
|
18
|
+
'input-security-runAsUser',
|
|
19
|
+
'input-security-readOnlyRootFilesystem',
|
|
20
|
+
'input-security-add',
|
|
21
|
+
'input-security-drop',
|
|
22
|
+
];
|
|
13
23
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
])('should emit an update on %p input', (field) => {
|
|
17
|
-
const wrapper = mount(Security, { props: { mode: _EDIT } });
|
|
18
|
-
const input = wrapper.find(`[data-testid="input-security-${ field }"]`).find('input');
|
|
19
|
-
const newValue = 123;
|
|
24
|
+
expect(actualIds).toStrictEqual(expect.arrayContaining(expectedIds));
|
|
25
|
+
});
|
|
20
26
|
|
|
21
|
-
|
|
27
|
+
it('should hide fields when privileged is checked', async() => {
|
|
28
|
+
const wrapper = mount(Security, { props: { mode: _EDIT, formType: FORM_TYPES.CONTAINER } });
|
|
22
29
|
|
|
23
|
-
|
|
24
|
-
|
|
30
|
+
// Before: Check that the fields are visible
|
|
31
|
+
let allowPrivilegeEscalation = wrapper.find('[data-testid="input-security-allowPrivilegeEscalation"]');
|
|
32
|
+
let seccompProfile = wrapper.find('[data-testid="input-security-seccompProfile-type"]');
|
|
33
|
+
|
|
34
|
+
expect(allowPrivilegeEscalation.exists()).toBe(true);
|
|
35
|
+
expect(seccompProfile.exists()).toBe(true);
|
|
36
|
+
|
|
37
|
+
// Action: Click the privileged checkbox
|
|
38
|
+
const privilegedCheckbox = wrapper
|
|
39
|
+
.find(`[data-testid="input-security-privileged"]`)
|
|
40
|
+
.find('label');
|
|
41
|
+
|
|
42
|
+
await privilegedCheckbox.trigger('click');
|
|
43
|
+
|
|
44
|
+
// After: Check that the fields are hidden
|
|
45
|
+
allowPrivilegeEscalation = wrapper.find('[data-testid="input-security-allowPrivilegeEscalation"]');
|
|
46
|
+
seccompProfile = wrapper.find('[data-testid="input-security-seccompProfile-type"]');
|
|
47
|
+
|
|
48
|
+
expect(allowPrivilegeEscalation.exists()).toBe(false);
|
|
49
|
+
expect(seccompProfile.exists()).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should display localhostProfile when seccompProfile type is Localhost', async() => {
|
|
53
|
+
const wrapper = mount(Security, {
|
|
54
|
+
props: {
|
|
55
|
+
mode: _EDIT, formType: FORM_TYPES.CONTAINER, seccompProfileTypes: ['None', 'Unconfined', 'RuntimeDefault', 'Localhost']
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Set seccomp type to 'Localhost'
|
|
60
|
+
const seccompProfile = wrapper.findComponent({ name: 'SeccompProfile' });
|
|
61
|
+
|
|
62
|
+
(seccompProfile.vm as any).type = 'Localhost';
|
|
63
|
+
await wrapper.vm.$nextTick();
|
|
64
|
+
|
|
65
|
+
const localhostInput = wrapper.find('[data-testid="input-security-seccompProfile-localhostProfile"]');
|
|
25
66
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
'allowPrivilegeEscalation',
|
|
29
|
-
'runasNonRoot',
|
|
30
|
-
'readOnlyRootFilesystem',
|
|
31
|
-
])('should emit an update on %p radio option change', (field) => {
|
|
32
|
-
const wrapper = mount(Security, { props: { mode: _EDIT } });
|
|
33
|
-
const radioOption = wrapper
|
|
34
|
-
.find(`[data-testid="input-security-${ field }"]`)
|
|
35
|
-
.find('label');
|
|
67
|
+
expect(localhostInput.exists()).toBe(true);
|
|
68
|
+
});
|
|
36
69
|
|
|
37
|
-
|
|
70
|
+
it.each([
|
|
71
|
+
'runAsUser',
|
|
72
|
+
])('should emit an update on %p input', (field) => {
|
|
73
|
+
const wrapper = mount(Security, { props: { mode: _EDIT, formType: FORM_TYPES.CONTAINER } });
|
|
74
|
+
const input = wrapper.find(`[data-testid="input-security-${ field }"]`).find('input');
|
|
75
|
+
const newValue = 123;
|
|
38
76
|
|
|
39
|
-
|
|
77
|
+
input.setValue(newValue);
|
|
78
|
+
|
|
79
|
+
expect(wrapper.emitted('update:value')).toHaveLength(1);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it.each([
|
|
83
|
+
'privileged',
|
|
84
|
+
'allowPrivilegeEscalation',
|
|
85
|
+
'runasNonRoot',
|
|
86
|
+
'readOnlyRootFilesystem',
|
|
87
|
+
])('should emit an update on %p checkbox option change', (field) => {
|
|
88
|
+
const wrapper = mount(Security, { props: { mode: _EDIT, formType: FORM_TYPES.CONTAINER } });
|
|
89
|
+
const radioOption = wrapper
|
|
90
|
+
.find(`[data-testid="input-security-${ field }"]`)
|
|
91
|
+
.find('label');
|
|
92
|
+
|
|
93
|
+
radioOption.trigger('click');
|
|
94
|
+
|
|
95
|
+
expect(wrapper.emitted('update:value')).toHaveLength(1);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it.each([
|
|
99
|
+
'add',
|
|
100
|
+
'drop',
|
|
101
|
+
])('should emit an update on %p selection change', async(field) => {
|
|
102
|
+
const wrapper = mount(Security, { props: { mode: _EDIT, formType: FORM_TYPES.CONTAINER } });
|
|
103
|
+
const select = wrapper.find(`[data-testid="input-security-${ field }"]`);
|
|
104
|
+
|
|
105
|
+
select.find('button').trigger('click');
|
|
106
|
+
await wrapper.trigger('keydown.down');
|
|
107
|
+
await wrapper.trigger('keydown.enter');
|
|
108
|
+
|
|
109
|
+
expect(wrapper.emitted('update:value')).toHaveLength(1);
|
|
110
|
+
});
|
|
40
111
|
});
|
|
41
112
|
|
|
42
|
-
|
|
43
|
-
'
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
113
|
+
describe('formType: pod', () => {
|
|
114
|
+
it('should display all the pod inputs', () => {
|
|
115
|
+
const wrapper = mount(Security, { props: { mode: _EDIT, formType: FORM_TYPES.POD } });
|
|
116
|
+
|
|
117
|
+
const inputWrappers = wrapper.findAll('[data-testid^=input-security-]');
|
|
118
|
+
const actualIds = inputWrappers.map((wrap) => wrap.attributes('data-testid'));
|
|
119
|
+
|
|
120
|
+
const expectedIds = [
|
|
121
|
+
'input-security-fsGroup',
|
|
122
|
+
'input-security-seccompProfile-type',
|
|
123
|
+
'input-security-runasNonRoot',
|
|
124
|
+
'input-security-runAsUser',
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
expect(actualIds).toStrictEqual(expect.arrayContaining(expectedIds));
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it.each([
|
|
131
|
+
'fsGroup',
|
|
132
|
+
'runAsUser',
|
|
133
|
+
])('should emit an update on %p input', (field) => {
|
|
134
|
+
const wrapper = mount(Security, { props: { mode: _EDIT, formType: FORM_TYPES.POD } });
|
|
135
|
+
const input = wrapper.find(`[data-testid="input-security-${ field }"]`).find('input');
|
|
136
|
+
const newValue = 123;
|
|
48
137
|
|
|
49
|
-
|
|
50
|
-
await wrapper.trigger('keydown.down');
|
|
51
|
-
await wrapper.trigger('keydown.enter');
|
|
138
|
+
input.setValue(newValue);
|
|
52
139
|
|
|
53
|
-
|
|
140
|
+
expect(wrapper.emitted('update:value')).toHaveLength(1);
|
|
141
|
+
});
|
|
54
142
|
});
|
|
55
143
|
});
|
|
@@ -18,7 +18,7 @@ export default {
|
|
|
18
18
|
type: String,
|
|
19
19
|
required: false,
|
|
20
20
|
default: null,
|
|
21
|
-
}
|
|
21
|
+
},
|
|
22
22
|
},
|
|
23
23
|
|
|
24
24
|
computed: {
|
|
@@ -26,6 +26,9 @@ export default {
|
|
|
26
26
|
if (this.clusterId) {
|
|
27
27
|
return this.row.statusResourceCountsForCluster(this.clusterId);
|
|
28
28
|
}
|
|
29
|
+
if (this.row.statusResourceCountsForCluster) {
|
|
30
|
+
return this.row.statusResourceCountsForCluster;
|
|
31
|
+
}
|
|
29
32
|
|
|
30
33
|
return this.row.status?.resourceCounts || {};
|
|
31
34
|
},
|
package/components/nav/Group.vue
CHANGED
|
@@ -262,6 +262,8 @@ export default {
|
|
|
262
262
|
role="button"
|
|
263
263
|
:tabindex="fixedOpen ? -1 : 0"
|
|
264
264
|
:aria-label="group.labelDisplay || group.label || ''"
|
|
265
|
+
:aria-expanded="!canCollapse || isExpanded"
|
|
266
|
+
:aria-controls="!canCollapse ? null : `group-${id}`"
|
|
265
267
|
@click="groupSelected()"
|
|
266
268
|
@keyup.enter="groupSelected()"
|
|
267
269
|
@keyup.space="groupSelected()"
|
|
@@ -291,6 +293,8 @@ export default {
|
|
|
291
293
|
role="button"
|
|
292
294
|
tabindex="0"
|
|
293
295
|
:aria-label="t('nav.ariaLabel.collapseExpand')"
|
|
296
|
+
:aria-expanded="isExpanded"
|
|
297
|
+
:aria-controls="`group-${id}`"
|
|
294
298
|
@click="peek($event, true)"
|
|
295
299
|
@keyup.enter="peek($event, true)"
|
|
296
300
|
@keyup.space="peek($event, true)"
|
|
@@ -298,6 +302,7 @@ export default {
|
|
|
298
302
|
</div>
|
|
299
303
|
<ul
|
|
300
304
|
v-if="isExpanded"
|
|
305
|
+
:id="`group-${id}`"
|
|
301
306
|
class="list-unstyled body"
|
|
302
307
|
v-bind="$attrs"
|
|
303
308
|
>
|
|
@@ -689,8 +689,8 @@ export default {
|
|
|
689
689
|
:aria-label="t('nav.userMenu.label')"
|
|
690
690
|
>
|
|
691
691
|
<rc-dropdown-trigger
|
|
692
|
-
ghost
|
|
693
|
-
small
|
|
692
|
+
variant="ghost"
|
|
693
|
+
size="small"
|
|
694
694
|
data-testid="nav_header_showUserMenu"
|
|
695
695
|
:aria-label="t('nav.userMenu.button.label')"
|
|
696
696
|
>
|
|
@@ -949,7 +949,7 @@ export default {
|
|
|
949
949
|
width: 40px;
|
|
950
950
|
}
|
|
951
951
|
|
|
952
|
-
:deep() div .btn.role-tertiary {
|
|
952
|
+
:deep() div .btn.role-tertiary, :deep() div .rc-button.btn.variant-tertiary {
|
|
953
953
|
border: 1px solid var(--header-btn-bg);
|
|
954
954
|
border: none;
|
|
955
955
|
background: var(--tertiary-header, var(--header-btn-bg));
|
|
@@ -16,7 +16,7 @@ const pageAction = (_event: Event, action: string) => {
|
|
|
16
16
|
:button-aria-label="t('nav.actionMenu.label')"
|
|
17
17
|
:dropdown-aria-label="t('nav.actionMenu.button.label')"
|
|
18
18
|
data-testid="page-actions-menu-action-button"
|
|
19
|
-
button-
|
|
19
|
+
button-variant="tertiary"
|
|
20
20
|
@select="pageAction"
|
|
21
21
|
/>
|
|
22
22
|
</template>
|
|
@@ -785,8 +785,8 @@ export default {
|
|
|
785
785
|
<!-- block user from removing the last selection if ns forced filtering is on -->
|
|
786
786
|
<RcButton
|
|
787
787
|
v-if="!namespaceFilterMode || value.length > 1"
|
|
788
|
-
small
|
|
789
|
-
ghost
|
|
788
|
+
size="small"
|
|
789
|
+
variant="ghost"
|
|
790
790
|
class="ns-chip-button"
|
|
791
791
|
:data-testid="`namespaces-values-close-${j}`"
|
|
792
792
|
:aria-label="t('namespaceFilter.removeNamespace', { name: ns.label })"
|
|
@@ -847,8 +847,8 @@ export default {
|
|
|
847
847
|
>
|
|
848
848
|
<RcButton
|
|
849
849
|
v-if="hasFilter"
|
|
850
|
-
small
|
|
851
|
-
ghost
|
|
850
|
+
size="small"
|
|
851
|
+
variant="ghost"
|
|
852
852
|
class="ns-filter-clear"
|
|
853
853
|
:aria-label="t('namespaceFilter.button.clearFilter')"
|
|
854
854
|
@click="clearFilter"
|
|
@@ -870,8 +870,8 @@ export default {
|
|
|
870
870
|
</div>
|
|
871
871
|
<RcButton
|
|
872
872
|
v-else
|
|
873
|
-
small
|
|
874
|
-
ghost
|
|
873
|
+
size="small"
|
|
874
|
+
variant="ghost"
|
|
875
875
|
class="ns-clear"
|
|
876
876
|
:aria-label="t('namespaceFilter.button.clear')"
|
|
877
877
|
@click="clear"
|
|
@@ -28,7 +28,9 @@ interface UpdateArgs {
|
|
|
28
28
|
searchTerm: string,
|
|
29
29
|
pinnedIds: string[],
|
|
30
30
|
unPinnedMax?: number,
|
|
31
|
-
forceWatch?: boolean
|
|
31
|
+
forceWatch?: boolean,
|
|
32
|
+
mgmtClusterRevision?: string,
|
|
33
|
+
provClusterRevision?: string,
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
type MgmtCluster = {
|
|
@@ -179,7 +181,7 @@ export class TopLevelMenuHelperPagination extends BaseTopLevelMenuHelper impleme
|
|
|
179
181
|
// No need to monitor for changes, the UNPINNED request will handle it
|
|
180
182
|
this.clustersPinnedWrapper = new PaginationWrapper({
|
|
181
183
|
$store,
|
|
182
|
-
id: '
|
|
184
|
+
id: 'top-level-menu-pinned-clusters',
|
|
183
185
|
enabledFor: {
|
|
184
186
|
store: STORE.MANAGEMENT,
|
|
185
187
|
resource: {
|
|
@@ -192,13 +194,19 @@ export class TopLevelMenuHelperPagination extends BaseTopLevelMenuHelper impleme
|
|
|
192
194
|
// Fetch all UNPINNED clusters capped at 10 (see `clustersOthers` description for details)
|
|
193
195
|
this.clustersOthersWrapper = new PaginationWrapper({
|
|
194
196
|
$store,
|
|
195
|
-
id: '
|
|
196
|
-
onChange: async({ forceWatch }) => {
|
|
197
|
-
if (this.args) {
|
|
197
|
+
id: 'top-level-menu-unpinned-clusters',
|
|
198
|
+
onChange: async({ forceWatch, revision }) => {
|
|
199
|
+
if (!this.args) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
198
203
|
await this.update({
|
|
199
204
|
...this.args,
|
|
200
|
-
forceWatch
|
|
205
|
+
forceWatch,
|
|
206
|
+
mgmtClusterRevision: revision,
|
|
201
207
|
});
|
|
208
|
+
} catch {
|
|
209
|
+
// Failures should be logged lower down, not much we can do here except catch to prevent whole ui page warnings in dev mode
|
|
202
210
|
}
|
|
203
211
|
},
|
|
204
212
|
enabledFor: {
|
|
@@ -213,13 +221,19 @@ export class TopLevelMenuHelperPagination extends BaseTopLevelMenuHelper impleme
|
|
|
213
221
|
// Fetch all prov clusters for the mgmt clusters we have
|
|
214
222
|
this.provClusterWrapper = new PaginationWrapper({
|
|
215
223
|
$store,
|
|
216
|
-
id: '
|
|
217
|
-
onChange: async({ forceWatch }) => {
|
|
218
|
-
if (this.args) {
|
|
224
|
+
id: 'top-level-menu-prov-clusters',
|
|
225
|
+
onChange: async({ forceWatch, revision }) => {
|
|
226
|
+
if (!this.args) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
try {
|
|
219
230
|
await this.update({
|
|
220
231
|
...this.args,
|
|
221
|
-
forceWatch
|
|
232
|
+
forceWatch,
|
|
233
|
+
provClusterRevision: revision,
|
|
222
234
|
});
|
|
235
|
+
} catch {
|
|
236
|
+
// Failures should be logged lower down, not much we can do here except catch to prevent whole ui page warnings in dev mode
|
|
223
237
|
}
|
|
224
238
|
},
|
|
225
239
|
enabledFor: {
|
|
@@ -251,7 +265,8 @@ export class TopLevelMenuHelperPagination extends BaseTopLevelMenuHelper impleme
|
|
|
251
265
|
pinned: MgmtCluster[],
|
|
252
266
|
notPinned: MgmtCluster[]
|
|
253
267
|
} = await allHash(promises) as any;
|
|
254
|
-
|
|
268
|
+
|
|
269
|
+
const provClusters = await this.updateProvCluster(res.notPinned, res.pinned, args);
|
|
255
270
|
const provClustersByMgmtId = provClusters.reduce((res: { [mgmtId: string]: ProvCluster}, provCluster: ProvCluster) => {
|
|
256
271
|
if (provCluster.mgmtClusterId) {
|
|
257
272
|
res[provCluster.mgmtClusterId] = provCluster;
|
|
@@ -357,7 +372,9 @@ export class TopLevelMenuHelperPagination extends BaseTopLevelMenuHelper impleme
|
|
|
357
372
|
sort: DEFAULT_SORT,
|
|
358
373
|
projectsOrNamespaces: []
|
|
359
374
|
},
|
|
360
|
-
|
|
375
|
+
revision: args.mgmtClusterRevision
|
|
376
|
+
})
|
|
377
|
+
.then((r) => r.data);
|
|
361
378
|
}
|
|
362
379
|
|
|
363
380
|
/**
|
|
@@ -378,15 +395,17 @@ export class TopLevelMenuHelperPagination extends BaseTopLevelMenuHelper impleme
|
|
|
378
395
|
sort: DEFAULT_SORT,
|
|
379
396
|
projectsOrNamespaces: []
|
|
380
397
|
},
|
|
381
|
-
|
|
398
|
+
revision: args.mgmtClusterRevision
|
|
399
|
+
})
|
|
400
|
+
.then((r) => r.data);
|
|
382
401
|
}
|
|
383
402
|
|
|
384
403
|
/**
|
|
385
404
|
* Find all provisioning clusters associated with the displayed mgmt clusters
|
|
386
405
|
*/
|
|
387
|
-
private async updateProvCluster(notPinned: MgmtCluster[], pinned: MgmtCluster[],
|
|
406
|
+
private async updateProvCluster(notPinned: MgmtCluster[], pinned: MgmtCluster[], args: UpdateArgs): Promise<ProvCluster[]> {
|
|
388
407
|
return this.provClusterWrapper.request({
|
|
389
|
-
forceWatch,
|
|
408
|
+
forceWatch: args.forceWatch,
|
|
390
409
|
pagination: {
|
|
391
410
|
filters: [
|
|
392
411
|
PaginationParamFilter.createMultipleFields(
|
|
@@ -400,7 +419,9 @@ export class TopLevelMenuHelperPagination extends BaseTopLevelMenuHelper impleme
|
|
|
400
419
|
sort: [],
|
|
401
420
|
projectsOrNamespaces: []
|
|
402
421
|
},
|
|
403
|
-
|
|
422
|
+
revision: args.provClusterRevision
|
|
423
|
+
})
|
|
424
|
+
.then((r) => r.data);
|
|
404
425
|
}
|
|
405
426
|
}
|
|
406
427
|
|
|
@@ -585,6 +606,8 @@ export class TopLevelMenuHelperLegacy extends BaseTopLevelMenuHelper implements
|
|
|
585
606
|
*/
|
|
586
607
|
class TopLevelMenuHelperService {
|
|
587
608
|
private _helper?: TopLevelMenuHelper;
|
|
609
|
+
public initialized = false;
|
|
610
|
+
|
|
588
611
|
public init($store: VuexStore) {
|
|
589
612
|
if (this._helper) {
|
|
590
613
|
return;
|
|
@@ -599,6 +622,8 @@ class TopLevelMenuHelperService {
|
|
|
599
622
|
});
|
|
600
623
|
|
|
601
624
|
this._helper = canPagination ? new TopLevelMenuHelperPagination({ $store }) : new TopLevelMenuHelperLegacy({ $store });
|
|
625
|
+
|
|
626
|
+
this.initialized = true;
|
|
602
627
|
}
|
|
603
628
|
|
|
604
629
|
public async reset() {
|
|
@@ -27,6 +27,9 @@ export default {
|
|
|
27
27
|
},
|
|
28
28
|
|
|
29
29
|
data() {
|
|
30
|
+
const sideNavServiceInitialized = sideNavService.initialized;
|
|
31
|
+
const maxClustersToShow = MENU_MAX_CLUSTERS;
|
|
32
|
+
|
|
30
33
|
sideNavService.init(this.$store);
|
|
31
34
|
|
|
32
35
|
const { displayVersion, fullVersion } = getVersionInfo(this.$store);
|
|
@@ -43,26 +46,27 @@ export default {
|
|
|
43
46
|
const provClusters = !canPagination && hasProvCluster ? this.$store.getters[`management/all`](CAPI.RANCHER_CLUSTER) : [];
|
|
44
47
|
const mgmtClusters = !canPagination ? this.$store.getters[`management/all`](MANAGEMENT.CLUSTER) : [];
|
|
45
48
|
|
|
46
|
-
if (!canPagination) {
|
|
47
|
-
// Reduce the impact of the initial load,
|
|
49
|
+
if (!canPagination || !sideNavServiceInitialized) {
|
|
50
|
+
// Reduce the impact of the initial load, or properly initialised
|
|
51
|
+
// Doing this here means we don't need an 'immediate' on the watches below
|
|
48
52
|
const args = {
|
|
49
|
-
pinnedIds: this.
|
|
50
|
-
searchTerm:
|
|
51
|
-
unPinnedMax:
|
|
53
|
+
pinnedIds: this.$store.getters['prefs/get'](PINNED_CLUSTERS),
|
|
54
|
+
searchTerm: '',
|
|
55
|
+
unPinnedMax: maxClustersToShow
|
|
52
56
|
};
|
|
53
57
|
|
|
54
58
|
helper.update(args);
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
return {
|
|
58
|
-
shown:
|
|
62
|
+
shown: false,
|
|
59
63
|
displayVersion,
|
|
60
64
|
fullVersion,
|
|
61
|
-
clusterFilter:
|
|
65
|
+
clusterFilter: '',
|
|
62
66
|
hasProvCluster,
|
|
63
|
-
maxClustersToShow
|
|
64
|
-
emptyCluster:
|
|
65
|
-
routeCombo:
|
|
67
|
+
maxClustersToShow,
|
|
68
|
+
emptyCluster: BLANK_CLUSTER,
|
|
69
|
+
routeCombo: false,
|
|
66
70
|
|
|
67
71
|
canPagination,
|
|
68
72
|
helper,
|
|
@@ -284,7 +288,6 @@ export default {
|
|
|
284
288
|
// 2. When SSP is disabled (legacy) reduce fn churn (this was a known performance customer issue)
|
|
285
289
|
|
|
286
290
|
pinnedIds: {
|
|
287
|
-
immediate: true,
|
|
288
291
|
handler(neu, old) {
|
|
289
292
|
if (sameContents(neu, old)) {
|
|
290
293
|
return;
|
|
@@ -302,20 +305,28 @@ export default {
|
|
|
302
305
|
|
|
303
306
|
provClusters: {
|
|
304
307
|
handler(neu, old) {
|
|
308
|
+
if (this.canPagination) {
|
|
309
|
+
// Shouldn't be doing this at all if pagination is on (updates handled by TopLevelMenu pagination wrapper)
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
|
|
305
313
|
// Potentially incredibly high throughput. Changes should be at least limited (slow if state change, quick if added/removed). Shouldn't get here if SSP
|
|
306
314
|
this.updateClusters(this.pinnedIds, neu?.length === old?.length ? 'slow' : 'quick');
|
|
307
315
|
},
|
|
308
|
-
deep:
|
|
309
|
-
immediate: true,
|
|
316
|
+
deep: true,
|
|
310
317
|
},
|
|
311
318
|
|
|
312
319
|
mgmtClusters: {
|
|
313
320
|
handler(neu, old) {
|
|
321
|
+
if (this.canPagination) {
|
|
322
|
+
// Shouldn't be doing this at all if pagination is on (updates handled by TopLevelMenu pagination wrapper)
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
|
|
314
326
|
// Potentially incredibly high throughput. Changes should be at least limited (slow if state change, quick if added/removed). Shouldn't get here if SSP
|
|
315
327
|
this.updateClusters(this.pinnedIds, neu?.length === old?.length ? 'slow' : 'quick');
|
|
316
328
|
},
|
|
317
|
-
deep:
|
|
318
|
-
immediate: true,
|
|
329
|
+
deep: true,
|
|
319
330
|
},
|
|
320
331
|
|
|
321
332
|
hideLocalCluster() {
|
|
@@ -454,16 +465,25 @@ export default {
|
|
|
454
465
|
unPinnedMax: this.maxClustersToShow
|
|
455
466
|
};
|
|
456
467
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
468
|
+
try {
|
|
469
|
+
switch (speed) {
|
|
470
|
+
case 'slow':
|
|
471
|
+
this.debouncedHelperUpdateSlow(args);
|
|
472
|
+
break;
|
|
473
|
+
case 'medium':
|
|
474
|
+
this.debouncedHelperUpdateMedium(args);
|
|
475
|
+
break;
|
|
476
|
+
case 'quick':
|
|
477
|
+
this.debouncedHelperUpdateQuick(args);
|
|
478
|
+
break;
|
|
479
|
+
}
|
|
480
|
+
} catch (err) {
|
|
481
|
+
if (this.canPagination) {
|
|
482
|
+
// Double bubble up errors here, errors are tracked further down
|
|
483
|
+
// Note that this won't pick up async errors, further tweaks are required for that
|
|
484
|
+
} else {
|
|
485
|
+
throw err;
|
|
486
|
+
}
|
|
467
487
|
}
|
|
468
488
|
}
|
|
469
489
|
}
|
|
@@ -66,7 +66,7 @@ export default {
|
|
|
66
66
|
created() {
|
|
67
67
|
// in fleet standard user with just the project owner and global git repo permissions
|
|
68
68
|
// returns 'default'
|
|
69
|
-
const initValue =
|
|
69
|
+
const initValue = this.workspace || this.$store.getters['prefs/get'](LAST_NAMESPACE) || '';
|
|
70
70
|
|
|
71
71
|
this.value = (initValue === 'default' || initValue === '') && this.options.length ? this.options[0].value : initValue;
|
|
72
72
|
},
|