@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.
Files changed (192) hide show
  1. package/apis/intf/modal.ts +38 -0
  2. package/apis/intf/slide-in.ts +3 -1
  3. package/apis/shell/__tests__/slide-in.test.ts +36 -0
  4. package/apis/shell/slide-in.ts +5 -1
  5. package/assets/styles/base/_color.scss +1 -0
  6. package/assets/styles/base/_typography.scss +14 -5
  7. package/assets/styles/themes/_light.scss +1 -1
  8. package/assets/styles/themes/_modern.scss +1 -1
  9. package/assets/translations/en-us.yaml +94 -33
  10. package/assets/translations/zh-hans.yaml +0 -2
  11. package/components/ActionMenuShell.vue +4 -4
  12. package/components/CodeMirror.vue +4 -3
  13. package/components/DetailText.vue +54 -7
  14. package/components/Drawer/Chrome.vue +11 -4
  15. package/components/Drawer/DrawerCard.vue +19 -0
  16. package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +3 -11
  17. package/components/Drawer/ResourceDetailDrawer/__tests__/ConfigTab.test.ts +2 -2
  18. package/components/Drawer/ResourceDetailDrawer/index.vue +3 -20
  19. package/components/Drawer/types.ts +1 -0
  20. package/components/DynamicContent/DynamicContentCloseButton.vue +2 -2
  21. package/components/LocaleSelector.vue +1 -1
  22. package/components/Markdown.vue +1 -1
  23. package/components/PopoverCard.vue +3 -3
  24. package/components/Resource/Detail/Card/ExtrasCard.vue +39 -0
  25. package/components/Resource/Detail/Card/StateCard/__tests__/composables.test.ts +142 -0
  26. package/components/Resource/Detail/Card/StateCard/composables.ts +41 -11
  27. package/components/Resource/Detail/Card/StateCard/index.vue +3 -9
  28. package/components/Resource/Detail/Card/StateCard/types.ts +6 -0
  29. package/components/Resource/Detail/Card/{PodsCard → StatusCard}/index.vue +11 -10
  30. package/components/Resource/Detail/Card/__tests__/PodsCard.test.ts +24 -25
  31. package/components/Resource/Detail/Cards.vue +27 -0
  32. package/components/Resource/Detail/Masthead/__tests__/index.test.ts +70 -0
  33. package/components/Resource/Detail/Masthead/index.vue +5 -0
  34. package/components/Resource/Detail/Metadata/KeyValueRow.vue +4 -2
  35. package/components/Resource/Detail/ResourcePopover/ResourcePopoverCard.vue +2 -2
  36. package/components/Resource/Detail/ResourceRow.types.ts +14 -0
  37. package/components/Resource/Detail/ResourceRow.vue +23 -35
  38. package/components/Resource/Detail/StatusRow.vue +5 -2
  39. package/components/Resource/Detail/TitleBar/__tests__/composables.test.ts +38 -7
  40. package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +106 -2
  41. package/components/Resource/Detail/TitleBar/composables.ts +2 -1
  42. package/components/Resource/Detail/TitleBar/index.vue +41 -6
  43. package/components/ResourceDetail/Masthead/__tests__/index.test.ts +49 -1
  44. package/components/ResourceDetail/Masthead/__tests__/latest.test.ts +85 -0
  45. package/components/ResourceDetail/Masthead/index.vue +1 -0
  46. package/components/ResourceDetail/Masthead/latest.vue +8 -1
  47. package/components/ResourceDetail/Masthead/legacy.vue +1 -1
  48. package/components/Setting.vue +1 -1
  49. package/components/SortableTable/index.vue +25 -0
  50. package/components/SortableTable/selection.js +25 -12
  51. package/components/SortableTable/sorting.js +1 -1
  52. package/components/Tabbed/Tab.vue +1 -0
  53. package/components/Tabbed/index.vue +29 -6
  54. package/components/Window/ContainerShell.vue +10 -13
  55. package/components/fleet/FleetClusterTargets/TargetsList.vue +47 -29
  56. package/components/fleet/FleetClusterTargets/index.vue +82 -29
  57. package/components/fleet/FleetClusters.vue +26 -12
  58. package/components/fleet/FleetGitRepoPaths.vue +2 -2
  59. package/components/fleet/FleetResources.vue +14 -0
  60. package/components/fleet/FleetValuesFrom.vue +2 -2
  61. package/components/fleet/__tests__/FleetClusterTargets.test.ts +531 -0
  62. package/components/fleet/__tests__/FleetClusters.test.ts +576 -0
  63. package/components/fleet/dashboard/ResourceDetails.vue +96 -123
  64. package/components/form/Conditions.vue +1 -15
  65. package/components/form/HookOption.vue +5 -0
  66. package/components/form/LabeledSelect.vue +1 -1
  67. package/components/form/LifecycleHooks.vue +2 -6
  68. package/components/form/ResourceLabeledSelect.vue +12 -1
  69. package/components/form/SeccompProfile.vue +113 -0
  70. package/components/form/Security.vue +244 -133
  71. package/components/form/__tests__/LabeledSelect.test.ts +1 -1
  72. package/components/form/__tests__/SeccompProfile.test.js +124 -0
  73. package/components/form/__tests__/Security.test.ts +125 -37
  74. package/components/formatter/Autoscaler.vue +2 -2
  75. package/components/formatter/FleetSummaryGraph.vue +4 -1
  76. package/components/nav/Group.vue +5 -0
  77. package/components/nav/Header.vue +3 -3
  78. package/components/nav/HeaderPageActionMenu.vue +1 -1
  79. package/components/nav/NamespaceFilter.vue +6 -6
  80. package/components/nav/NotificationCenter/index.vue +1 -1
  81. package/components/nav/TopLevelMenu.helper.ts +41 -16
  82. package/components/nav/TopLevelMenu.vue +45 -25
  83. package/components/nav/WorkspaceSwitcher.vue +1 -1
  84. package/components/nav/__tests__/TopLevelMenu.helper.test.ts +277 -0
  85. package/components/nav/__tests__/TopLevelMenu.test.ts +160 -4
  86. package/components/templates/default.vue +0 -3
  87. package/components/templates/home.vue +0 -3
  88. package/components/templates/plain.vue +0 -3
  89. package/composables/useClickOutside.ts +1 -1
  90. package/config/product/explorer.js +1 -2
  91. package/config/types.js +41 -8
  92. package/detail/__tests__/workload.test.ts +8 -16
  93. package/detail/catalog.cattle.io.app.vue +6 -0
  94. package/detail/fleet.cattle.io.cluster.vue +6 -0
  95. package/detail/workload/index.vue +7 -109
  96. package/edit/__tests__/projectsecret.test.ts +42 -0
  97. package/edit/auth/__tests__/oidc.test.ts +50 -0
  98. package/edit/auth/oidc.vue +68 -44
  99. package/edit/autoscaling.horizontalpodautoscaler/index.vue +140 -59
  100. package/edit/autoscaling.horizontalpodautoscaler/metrics-row.vue +41 -5
  101. package/edit/projectsecret.vue +29 -0
  102. package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +89 -200
  103. package/edit/provisioning.cattle.io.cluster/__tests__/Networking.test.ts +58 -17
  104. package/edit/provisioning.cattle.io.cluster/rke2.vue +11 -0
  105. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +3 -63
  106. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +82 -14
  107. package/edit/workload/__tests__/index.test.ts +122 -85
  108. package/edit/workload/index.vue +48 -29
  109. package/edit/workload/mixins/workload.js +85 -32
  110. package/list/catalog.cattle.io.clusterrepo.vue +1 -1
  111. package/list/projectsecret.vue +2 -2
  112. package/machine-config/__tests__/vmwarevsphere.test.ts +64 -0
  113. package/machine-config/amazonec2.vue +2 -2
  114. package/machine-config/vmwarevsphere.vue +58 -4
  115. package/mixins/__tests__/brand.spec.ts +18 -13
  116. package/mixins/__tests__/chart.test.ts +63 -0
  117. package/mixins/chart.js +56 -51
  118. package/models/__tests__/catalog.cattle.io.app.test.ts +33 -0
  119. package/models/__tests__/workload.test.ts +333 -0
  120. package/models/catalog.cattle.io.app.js +8 -0
  121. package/models/pod.js +14 -0
  122. package/models/secret.js +1 -1
  123. package/models/workload.js +93 -27
  124. package/package.json +4 -4
  125. package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +91 -0
  126. package/pages/c/_cluster/apps/charts/install.vue +4 -4
  127. package/pages/c/_cluster/explorer/EventsTable.vue +2 -2
  128. package/pages/c/_cluster/fleet/index.vue +18 -12
  129. package/pages/c/_cluster/manager/hostedprovider/index.vue +1 -19
  130. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +1 -1
  131. package/pages/c/_cluster/uiplugins/index.vue +1 -1
  132. package/plugins/dashboard-store/__tests__/resource-class.test.ts +234 -0
  133. package/plugins/dashboard-store/actions.js +9 -8
  134. package/plugins/dashboard-store/resource-class.js +97 -1
  135. package/plugins/steve/__tests__/revision.test.ts +84 -0
  136. package/plugins/steve/__tests__/steve-pagination-utils.test.ts +30 -0
  137. package/plugins/steve/__tests__/subscribe.spec.ts +134 -0
  138. package/plugins/steve/mutations.js +9 -0
  139. package/plugins/steve/revision.ts +26 -0
  140. package/plugins/steve/steve-pagination-utils.ts +6 -5
  141. package/plugins/steve/subscribe.js +211 -51
  142. package/plugins/subscribe-events.ts +2 -2
  143. package/rancher-components/Form/Checkbox/Checkbox.vue +13 -0
  144. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +1 -1
  145. package/rancher-components/Pill/RcCounterBadge/RcCounterBadge.vue +1 -1
  146. package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +3 -1
  147. package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +3 -1
  148. package/rancher-components/Pill/RcTag/RcTag.vue +1 -1
  149. package/rancher-components/Pill/index.ts +4 -0
  150. package/rancher-components/RcButton/RcButton.test.ts +53 -9
  151. package/rancher-components/RcButton/RcButton.vue +217 -25
  152. package/rancher-components/RcButton/types.ts +27 -1
  153. package/rancher-components/RcDropdown/RcDropdownMenu.vue +4 -4
  154. package/rancher-components/RcDropdown/types.ts +3 -3
  155. package/rancher-components/RcIcon/RcIcon.test.ts +42 -0
  156. package/rancher-components/RcIcon/RcIcon.vue +9 -6
  157. package/rancher-components/RcIcon/types.ts +13 -9
  158. package/rancher-components/utils/status.test.ts +10 -15
  159. package/rancher-components/utils/status.ts +5 -6
  160. package/store/aws.js +18 -12
  161. package/store/index.js +4 -8
  162. package/store/type-map.utils.ts +1 -1
  163. package/types/kube/kube-api.ts +29 -3
  164. package/types/rancher/steve.api.ts +40 -0
  165. package/types/shell/index.d.ts +99 -0
  166. package/types/store/dashboard-store.types.ts +29 -7
  167. package/types/store/pagination.types.ts +1 -0
  168. package/types/store/subscribe-events.types.ts +1 -0
  169. package/utils/__tests__/azure.test.ts +56 -0
  170. package/utils/__tests__/back-off.test.ts +364 -245
  171. package/utils/__tests__/error.test.ts +44 -0
  172. package/utils/__tests__/fleet.test.ts +8 -1
  173. package/utils/__tests__/pagination-wrapper.test.ts +167 -0
  174. package/utils/__tests__/version.test.ts +55 -1
  175. package/utils/azure.js +12 -0
  176. package/utils/back-off.ts +302 -69
  177. package/utils/cspAdaptor.ts +32 -14
  178. package/utils/dynamic-content/__tests__/index.test.ts +1 -1
  179. package/utils/dynamic-content/__tests__/new-release.test.ts +48 -7
  180. package/utils/dynamic-content/__tests__/support-notice.test.ts +1 -4
  181. package/utils/dynamic-content/index.ts +1 -6
  182. package/utils/dynamic-content/new-release.ts +5 -3
  183. package/utils/dynamic-content/types.d.ts +0 -1
  184. package/utils/error.js +9 -0
  185. package/utils/fleet.ts +2 -2
  186. package/utils/inactivity.ts +2 -3
  187. package/utils/pagination-wrapper.ts +101 -17
  188. package/utils/validators/formRules/index.ts +3 -0
  189. package/utils/version.js +38 -0
  190. package/components/auth/AzureWarning.vue +0 -77
  191. /package/components/Resource/Detail/{Card/PodsCard/Bubble.vue → Bubble.vue} +0 -0
  192. /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
- it('should display all the inputs', () => {
7
- const wrapper = mount(Security, { props: { mode: _EDIT } });
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
- const inputWraps = wrapper.findAll('[data-testid^=input-security-]');
10
+ const inputWrappers = wrapper.findAll('[data-testid^=input-security-]');
11
+ const actualIds = inputWrappers.map((wrap) => wrap.attributes('data-testid'));
10
12
 
11
- expect(inputWraps).toHaveLength(7);
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
- it.each([
15
- 'runAsUser',
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
- input.setValue(newValue);
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
- expect(wrapper.emitted('input')).toHaveLength(1);
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
- it.each([
27
- 'privileged',
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
- radioOption.trigger('click');
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
- expect(wrapper.emitted('update:value')).toHaveLength(1);
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
- it.each([
43
- 'add',
44
- 'drop',
45
- ])('should emit an update on %p selection change', async(field) => {
46
- const wrapper = mount(Security, { props: { mode: _EDIT } });
47
- const select = wrapper.find(`[data-testid="input-security-${ field }"]`);
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
- select.find('button').trigger('click');
50
- await wrapper.trigger('keydown.down');
51
- await wrapper.trigger('keydown.enter');
138
+ input.setValue(newValue);
52
139
 
53
- expect(wrapper.emitted('update:value')).toHaveLength(1);
140
+ expect(wrapper.emitted('update:value')).toHaveLength(1);
141
+ });
54
142
  });
55
143
  });
@@ -46,8 +46,8 @@ const stopPropagation = (event: Event) => {
46
46
  >
47
47
  <RcButton
48
48
  v-if="row.canPauseResumeAutoscaler"
49
- secondary
50
- small
49
+ variant="secondary"
50
+ size="small"
51
51
  class="action"
52
52
  @click="() => {props.row.toggleAutoscalerRunner(); close()}"
53
53
  >
@@ -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
  },
@@ -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-role="tertiary"
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"
@@ -36,7 +36,7 @@ const open = (opened: boolean) => {
36
36
  @update:open="open"
37
37
  >
38
38
  <rc-dropdown-trigger
39
- tertiary
39
+ variant="tertiary"
40
40
  data-testid="notifications-center"
41
41
  :aria-label="t('nav.notifications.button.label')"
42
42
  >
@@ -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: 'tlm-pinned-clusters',
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: 'tlm-unpinned-clusters',
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: 'tlm-prov-clusters',
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
- const provClusters = await this.updateProvCluster(res.notPinned, res.pinned, args.forceWatch || false);
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
- }).then((r) => r.data);
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
- }).then((r) => r.data);
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[], forceWatch: boolean): Promise<ProvCluster[]> {
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
- }).then((r) => r.data);
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, but only if we're not making a request
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.pinnedIds,
50
- searchTerm: this.search,
51
- unPinnedMax: this.maxClustersToShow
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: false,
62
+ shown: false,
59
63
  displayVersion,
60
64
  fullVersion,
61
- clusterFilter: '',
65
+ clusterFilter: '',
62
66
  hasProvCluster,
63
- maxClustersToShow: MENU_MAX_CLUSTERS,
64
- emptyCluster: BLANK_CLUSTER,
65
- routeCombo: false,
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: true,
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: true,
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
- switch (speed) {
458
- case 'slow':
459
- this.debouncedHelperUpdateSlow(args);
460
- break;
461
- case 'medium':
462
- this.debouncedHelperUpdateMedium(args);
463
- break;
464
- case 'quick':
465
- this.debouncedHelperUpdateQuick(args);
466
- break;
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 = !this.workspace ? this.$store.getters['prefs/get'](LAST_NAMESPACE) : '';
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
  },