@rancher/shell 3.0.8-rc.9 → 3.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/apis/impl/apis.ts +61 -0
  2. package/apis/index.ts +40 -0
  3. package/apis/intf/modal.ts +90 -0
  4. package/apis/intf/shell.ts +36 -0
  5. package/apis/intf/slide-in.ts +98 -0
  6. package/apis/intf/system.ts +41 -0
  7. package/apis/shell/__tests__/modal.test.ts +80 -0
  8. package/apis/shell/__tests__/notifications.test.ts +71 -0
  9. package/apis/shell/__tests__/slide-in.test.ts +54 -0
  10. package/apis/shell/__tests__/system.test.ts +129 -0
  11. package/apis/shell/index.ts +38 -0
  12. package/apis/shell/modal.ts +41 -0
  13. package/apis/shell/notifications.ts +65 -0
  14. package/apis/shell/slide-in.ts +33 -0
  15. package/apis/shell/system.ts +65 -0
  16. package/apis/vue-shim.d.ts +11 -0
  17. package/assets/styles/global/_tooltip.scss +6 -1
  18. package/assets/translations/en-us.yaml +5 -0
  19. package/components/ActionMenuShell.vue +3 -1
  20. package/components/CruResource.vue +8 -1
  21. package/components/Drawer/ResourceDetailDrawer/__tests__/composables.test.ts +50 -1
  22. package/components/Drawer/ResourceDetailDrawer/composables.ts +19 -0
  23. package/components/Drawer/ResourceDetailDrawer/index.vue +3 -1
  24. package/components/LocaleSelector.vue +2 -2
  25. package/components/ModalManager.vue +11 -1
  26. package/components/Questions/__tests__/Yaml.test.ts +1 -1
  27. package/components/RelatedResources.vue +5 -0
  28. package/components/Resource/Detail/ResourcePopover/index.vue +5 -1
  29. package/components/ResourceDetail/Masthead/latest.vue +23 -21
  30. package/components/ResourceDetail/index.vue +3 -0
  31. package/components/ResourceTable.vue +54 -21
  32. package/components/SlideInPanelManager.vue +16 -11
  33. package/components/SortableTable/THead.vue +2 -1
  34. package/components/SortableTable/index.vue +20 -2
  35. package/components/Tabbed/index.vue +37 -2
  36. package/components/__tests__/NamespaceFilter.test.ts +49 -0
  37. package/components/auth/SelectPrincipal.vue +4 -0
  38. package/components/auth/login/ldap.vue +3 -3
  39. package/components/fleet/FleetSecretSelector.vue +1 -1
  40. package/components/form/KeyValue.vue +1 -1
  41. package/components/form/NameNsDescription.vue +1 -1
  42. package/components/form/NodeScheduling.vue +2 -2
  43. package/components/form/ResourceTabs/composable.ts +2 -2
  44. package/components/form/ResourceTabs/index.vue +0 -2
  45. package/components/form/__tests__/NameNsDescription.test.ts +42 -0
  46. package/components/formatter/LinkName.vue +5 -0
  47. package/components/nav/Group.vue +25 -7
  48. package/components/nav/Header.vue +1 -1
  49. package/components/nav/NamespaceFilter.vue +1 -0
  50. package/components/nav/Type.vue +17 -6
  51. package/components/nav/WindowManager/panels/TabBodyContainer.vue +1 -1
  52. package/components/nav/__tests__/Type.test.ts +59 -0
  53. package/composables/cruResource.ts +27 -0
  54. package/composables/focusTrap.ts +3 -1
  55. package/composables/resourceDetail.ts +15 -0
  56. package/composables/useLabeledFormElement.ts +3 -4
  57. package/config/product/fleet.js +1 -1
  58. package/config/router/navigation-guards/clusters.js +3 -3
  59. package/config/router/navigation-guards/products.js +1 -1
  60. package/config/router/routes.js +1 -5
  61. package/core/__tests__/extension-manager-impl.test.js +437 -0
  62. package/core/extension-manager-impl.js +6 -27
  63. package/core/plugin-helpers.ts +2 -2
  64. package/core/plugin.ts +9 -1
  65. package/core/plugins-loader.js +2 -2
  66. package/core/types-provisioning.ts +4 -0
  67. package/core/types.ts +35 -0
  68. package/detail/provisioning.cattle.io.cluster.vue +8 -6
  69. package/dialog/DeveloperLoadExtensionDialog.vue +1 -1
  70. package/dialog/MoveNamespaceDialog.vue +20 -4
  71. package/dialog/SearchDialog.vue +1 -0
  72. package/dialog/__tests__/MoveNamespaceDialog.test.ts +249 -0
  73. package/directives/__tests__/clean-tooltip.test.ts +298 -0
  74. package/directives/clean-tooltip.ts +234 -0
  75. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +2 -2
  76. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +98 -1
  77. package/edit/fleet.cattle.io.helmop.vue +5 -0
  78. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +21 -21
  79. package/edit/provisioning.cattle.io.cluster/index.vue +5 -5
  80. package/edit/provisioning.cattle.io.cluster/rke2.vue +8 -8
  81. package/edit/resources.cattle.io.restore.vue +1 -1
  82. package/edit/workload/Job.vue +2 -2
  83. package/edit/workload/index.vue +1 -1
  84. package/initialize/install-plugins.js +4 -5
  85. package/machine-config/azure.vue +1 -1
  86. package/machine-config/components/GCEImage.vue +1 -1
  87. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +16 -0
  88. package/models/chart.js +70 -74
  89. package/models/management.cattle.io.cluster.js +1 -1
  90. package/models/provisioning.cattle.io.cluster.js +11 -3
  91. package/package.json +7 -7
  92. package/pages/auth/login.vue +3 -3
  93. package/pages/auth/setup.vue +1 -1
  94. package/pages/auth/verify.vue +3 -3
  95. package/pages/c/_cluster/apps/charts/index.vue +122 -24
  96. package/pages/c/_cluster/apps/charts/install.vue +33 -0
  97. package/pages/c/_cluster/explorer/__tests__/index.test.ts +1 -1
  98. package/pages/c/_cluster/fleet/index.vue +4 -7
  99. package/pages/c/_cluster/settings/index.vue +5 -0
  100. package/pkg/auto-import.js +3 -3
  101. package/pkg/dynamic-importer.lib.js +1 -1
  102. package/pkg/import.js +1 -1
  103. package/plugins/__tests__/mutations.tests.ts +179 -0
  104. package/plugins/dashboard-store/getters.js +1 -1
  105. package/plugins/dashboard-store/model-loader.js +1 -1
  106. package/plugins/dashboard-store/mutations.js +23 -2
  107. package/plugins/dashboard-store/resource-class.js +8 -3
  108. package/plugins/plugin.js +2 -2
  109. package/plugins/steve/__tests__/steve-pagination-utils.test.ts +301 -128
  110. package/plugins/steve/steve-class.js +1 -1
  111. package/plugins/steve/steve-pagination-utils.ts +108 -43
  112. package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
  113. package/rancher-components/Form/LabeledInput/LabeledInput.vue +1 -1
  114. package/rancher-components/RcDropdown/useDropdownContext.ts +2 -4
  115. package/rancher-components/RcItemCard/RcItemCard.vue +1 -1
  116. package/scripts/publish-shell.sh +25 -0
  117. package/store/__tests__/catalog.test.ts +1 -1
  118. package/store/__tests__/type-map.test.ts +164 -2
  119. package/store/auth.js +23 -11
  120. package/store/i18n.js +3 -3
  121. package/store/index.js +5 -3
  122. package/store/notifications.ts +2 -0
  123. package/store/prefs.js +2 -2
  124. package/store/type-map.js +17 -7
  125. package/types/internal-api/shell/modal.d.ts +6 -6
  126. package/types/notifications/index.ts +126 -15
  127. package/types/rancher/index.d.ts +9 -0
  128. package/types/shell/index.d.ts +16 -1
  129. package/types/vue-shim.d.ts +5 -4
  130. package/utils/__tests__/router.test.js +238 -0
  131. package/utils/cluster.js +4 -1
  132. package/utils/fleet.ts +8 -1
  133. package/utils/pagination-utils.ts +2 -2
  134. package/utils/pagination-wrapper.ts +1 -1
  135. package/utils/router.js +50 -0
  136. package/utils/unit-tests/pagination-utils.spec.ts +8 -8
  137. package/vue.config.js +3 -3
  138. package/composables/useExtensionManager.ts +0 -17
  139. package/core/__test__/extension-manager-impl.test.js +0 -236
  140. package/core/plugins.js +0 -38
  141. package/directives/clean-tooltip.js +0 -32
  142. package/plugins/internal-api/index.ts +0 -37
  143. package/plugins/internal-api/shared/base-api.ts +0 -13
  144. package/plugins/internal-api/shell/shell.api.ts +0 -108
  145. package/types/internal-api/shell/growl.d.ts +0 -25
  146. package/types/internal-api/shell/slideIn.d.ts +0 -15
@@ -0,0 +1,234 @@
1
+ import { DirectiveBinding, Directive } from 'vue';
2
+ import { destroyTooltip, createTooltip } from 'floating-vue';
3
+ import { purifyHTML } from '@shell/plugins/clean-html';
4
+
5
+ // This is a singleton tooltip implementation that improves performance on pages with many tooltips.
6
+ // Instead of instantiating a Vue component for every tooltip on the page, this directive attaches lightweight event listeners.
7
+ // It then imperatively creates and destroys a single tooltip instance as needed, avoiding the high upfront memory and processing cost of many Vue components.
8
+ let singleton: ReturnType<typeof createTooltip> | null = null;
9
+ let currentTarget: HTMLElement | null = null;
10
+
11
+ interface TooltipDelay {
12
+ show: number;
13
+ hide: number;
14
+ }
15
+
16
+ // Options are optional, to be handled by floating-vue's defaults
17
+ interface TooltipOptions {
18
+ content?: string;
19
+ placement?: string;
20
+ popperClass?: string;
21
+ delay?: TooltipDelay;
22
+ triggers?: string[];
23
+ }
24
+
25
+ interface TooltipHTMLElement extends HTMLElement {
26
+ // Store the whole options object for the tooltip
27
+ __tooltipOptions__: TooltipOptions;
28
+ }
29
+
30
+ /**
31
+ * Shows a singleton tooltip for the given target element.
32
+ * If a tooltip is already active, it is hidden before showing the new one.
33
+ * @param {HTMLElement} target The element to which the tooltip is attached.
34
+ * @param {TooltipOptions} options The options for the tooltip.
35
+ */
36
+ function showSingletonTooltip(target: HTMLElement, options: TooltipOptions) {
37
+ // If a tooltip is already active, it should be hidden before showing the new one.
38
+ if (singleton) {
39
+ destroyTooltip(currentTarget);
40
+ singleton = null;
41
+ }
42
+
43
+ const purifiedContent = options.content ? purifyContent(options.content) : '';
44
+
45
+ // Don't show the tooltip if the content is empty.
46
+ if (!purifiedContent) {
47
+ return;
48
+ }
49
+
50
+ const tooltipConfig = {
51
+ ...options,
52
+ content: purifiedContent,
53
+ };
54
+
55
+ // Create a new tooltip instance.
56
+ singleton = createTooltip(target, tooltipConfig, {});
57
+
58
+ singleton.show();
59
+ currentTarget = target;
60
+ }
61
+
62
+ /**
63
+ * Hides the singleton tooltip if it is currently shown for the given target element.
64
+ * @param {HTMLElement} target The element from which the tooltip should be hidden.
65
+ */
66
+ function hideSingletonTooltip(target: HTMLElement) {
67
+ if (!singleton) {
68
+ return;
69
+ }
70
+
71
+ if (currentTarget === target) {
72
+ destroyTooltip(target);
73
+ singleton = null;
74
+ currentTarget = null;
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Purifies and trims the HTML content of the tooltip to prevent XSS attacks.
80
+ * @param {string} rawValue The raw content string to be purified and trimmed.
81
+ * @returns {string} The purified and trimmed content string.
82
+ */
83
+ function purifyContent(rawValue: string): string {
84
+ const purified = purifyHTML(rawValue);
85
+
86
+ return purified.trim();
87
+ }
88
+
89
+ /**
90
+ * A Vue directive that provides a clean singleton tooltip using floating-vue.
91
+ */
92
+ const cleanTooltipDirective: Directive = {
93
+ /**
94
+ * Called when the directive is mounted to an element.
95
+ * It sets up the tooltip options and adds event listeners.
96
+ * @param {HTMLElement} el The element the directive is bound to.
97
+ * @param {object} binding The directive binding object.
98
+ */
99
+ mounted(el: TooltipHTMLElement, binding: DirectiveBinding) {
100
+ el.__tooltipOptions__ = getTooltipOptions(binding.value, binding.modifiers);
101
+
102
+ const triggers = el.__tooltipOptions__.triggers || ['hover'];
103
+
104
+ if (triggers.includes('hover')) {
105
+ el.addEventListener('mouseenter', onMouseEnter);
106
+ el.addEventListener('mouseleave', onMouseLeave);
107
+ }
108
+ if (triggers.includes('focus')) {
109
+ el.addEventListener('focus', onMouseEnter);
110
+ el.addEventListener('blur', onMouseLeave);
111
+ }
112
+ if (triggers.includes('click')) {
113
+ el.addEventListener('click', onMouseClick);
114
+ }
115
+
116
+ if (el.__tooltipOptions__.content) {
117
+ // Add a class to the element to indicate that it has a clean tooltip.
118
+ el.classList.add('has-clean-tooltip');
119
+ }
120
+ },
121
+ /**
122
+ * Called when the directive's binding value is updated.
123
+ * It updates the tooltip options and shows the tooltip if it is already active.
124
+ * @param {HTMLElement} el The element the directive is bound to.
125
+ * @param {object} binding The directive binding object.
126
+ */
127
+ updated(el: TooltipHTMLElement, binding: DirectiveBinding) {
128
+ el.__tooltipOptions__ = getTooltipOptions(binding.value, binding.modifiers);
129
+
130
+ // doing this here too because the tooltip content may change after mount.
131
+ if (el.__tooltipOptions__.content) {
132
+ el.classList.add('has-clean-tooltip');
133
+ } else {
134
+ el.classList.remove('has-clean-tooltip');
135
+ }
136
+
137
+ // If this element's tooltip is currently shown, update it
138
+ if (currentTarget === el) {
139
+ showSingletonTooltip(el, el.__tooltipOptions__);
140
+ }
141
+ },
142
+ /**
143
+ * Called when the directive is unmounted from an element.
144
+ * It removes the event listeners and hides the tooltip if it is active.
145
+ * @param {HTMLElement} el The element the directive is bound to.
146
+ */
147
+ unmounted(el: TooltipHTMLElement) {
148
+ el.removeEventListener('mouseenter', onMouseEnter);
149
+ el.removeEventListener('mouseleave', onMouseLeave);
150
+ el.removeEventListener('focus', onMouseEnter);
151
+ el.removeEventListener('blur', onMouseLeave);
152
+ el.removeEventListener('click', onMouseClick);
153
+ el.classList.remove('has-clean-tooltip');
154
+
155
+ // If this element's tooltip is currently shown, hide it
156
+ if (currentTarget === el) {
157
+ hideSingletonTooltip(el);
158
+ }
159
+ },
160
+ };
161
+
162
+ /**
163
+ * Event handler for mouseenter and focus events.
164
+ * @param {Event} e The event object.
165
+ */
166
+ function onMouseEnter(e: MouseEvent | FocusEvent) {
167
+ const el = e.currentTarget as TooltipHTMLElement;
168
+
169
+ showSingletonTooltip(el, el.__tooltipOptions__);
170
+ }
171
+
172
+ /**
173
+ * Event handler for mouseleave and blur events.
174
+ * @param {Event} e The event object.
175
+ */
176
+ function onMouseLeave(e: MouseEvent | FocusEvent) {
177
+ const el = e.currentTarget as TooltipHTMLElement;
178
+
179
+ hideSingletonTooltip(el);
180
+ }
181
+
182
+ /**
183
+ * Event handler for click events.
184
+ * @param {Event} e The event object.
185
+ */
186
+ function onMouseClick(e: MouseEvent) {
187
+ const el = e.currentTarget as TooltipHTMLElement;
188
+
189
+ if (currentTarget === el) {
190
+ hideSingletonTooltip(el);
191
+ } else {
192
+ showSingletonTooltip(el, el.__tooltipOptions__);
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Parses the tooltip options from the directive's value and modifiers.
198
+ * @param {string|object} value The value of the directive.
199
+ * @param {object} modifiers The modifiers of the directive.
200
+ * @returns {object} The parsed tooltip options.
201
+ */
202
+ function getTooltipOptions(value: string | TooltipOptions, modifiers: Partial<Record<string, boolean>>): TooltipOptions {
203
+ let options: TooltipOptions;
204
+
205
+ if (typeof value === 'string') {
206
+ options = { content: value };
207
+ } else if (value && typeof value === 'object') {
208
+ options = { ...value };
209
+ } else {
210
+ options = {};
211
+ }
212
+
213
+ // Modifiers can also specify placement (e.g., v-clean-tooltip.bottom)
214
+ if (modifiers.top) {
215
+ options.placement = 'top';
216
+ } else if (modifiers.bottom) {
217
+ options.placement = 'bottom';
218
+ } else if (modifiers.left) {
219
+ options.placement = 'left';
220
+ } else if (modifiers.right) {
221
+ options.placement = 'right';
222
+ }
223
+
224
+ return options;
225
+ }
226
+
227
+ export default cleanTooltipDirective;
228
+
229
+ // Exporting for unit testing purposes
230
+ export {
231
+ onMouseEnter,
232
+ onMouseLeave,
233
+ onMouseClick
234
+ };
@@ -109,7 +109,7 @@ describe.each([
109
109
  const correctDriftCheckbox = wrapper.find('[data-testid="gitRepo-correctDrift-checkbox"]');
110
110
  const tooltip = wrapper.find('[data-testid="gitRepo-correctDrift-checkbox"]');
111
111
 
112
- expect(tooltip.element.classList).toContain('v-popper--has-tooltip');
112
+ expect(tooltip.element.classList).toContain('has-clean-tooltip');
113
113
  expect(correctDriftCheckbox.exists()).toBeTruthy();
114
114
  expect(correctDriftCheckbox.attributes().value).toBeFalsy();
115
115
  });
@@ -118,7 +118,7 @@ describe.each([
118
118
  const correctDriftCheckbox = wrapper.find('[data-testid="gitRepo-keepResources-checkbox"]');
119
119
  const tooltip = wrapper.find('[data-testid="gitRepo-keepResources-checkbox"]');
120
120
 
121
- expect(tooltip.element.classList).toContain('v-popper--has-tooltip');
121
+ expect(tooltip.element.classList).toContain('has-clean-tooltip');
122
122
  expect(correctDriftCheckbox.exists()).toBeTruthy();
123
123
  expect(correctDriftCheckbox.attributes().value).toBeFalsy();
124
124
  });
@@ -100,6 +100,49 @@ describe('view: fleet.cattle.io.helmop, mode: view', () => {
100
100
  });
101
101
  });
102
102
 
103
+ describe('helmOp component lifecycle', () => {
104
+ it('should have registerBeforeHook method available and call updateBeforeSave', () => {
105
+ const helmOpOptions = {
106
+ metadata: {
107
+ name: 'test-helmop',
108
+ namespace: 'test-namespace',
109
+ labels: {}
110
+ }
111
+ };
112
+
113
+ const wrapper = mount(HelmOpComponent, initHelmOp({ mode: _CREATE }, helmOpOptions));
114
+
115
+ // Mock registerBeforeHook to spy on calls
116
+ const mockRegisterBeforeHook = jest.fn();
117
+
118
+ wrapper.vm.registerBeforeHook = mockRegisterBeforeHook;
119
+
120
+ // Verify updateBeforeSave method exists
121
+ expect(typeof wrapper.vm.updateBeforeSave).toBe('function');
122
+
123
+ // Call the method that would be called during created lifecycle
124
+ wrapper.vm.registerBeforeHook(wrapper.vm.updateBeforeSave);
125
+
126
+ // Verify that registerBeforeHook was called with updateBeforeSave function
127
+ expect(mockRegisterBeforeHook).toHaveBeenCalledWith(wrapper.vm.updateBeforeSave);
128
+ });
129
+
130
+ it('should have doCreateSecrets method available for registerBeforeHook', () => {
131
+ const helmOpOptions = {
132
+ metadata: {
133
+ name: 'test-helmop',
134
+ namespace: 'test-namespace',
135
+ labels: {}
136
+ }
137
+ };
138
+
139
+ const wrapper = mount(HelmOpComponent, initHelmOp({ mode: _CREATE }, helmOpOptions));
140
+
141
+ // Verify doCreateSecrets method exists
142
+ expect(typeof wrapper.vm.doCreateSecrets).toBe('function');
143
+ });
144
+ });
145
+
103
146
  describe.each([
104
147
  _CREATE,
105
148
  _EDIT,
@@ -174,7 +217,7 @@ describe.each([
174
217
 
175
218
  expect(pollingCheckbox.exists()).toBe(true);
176
219
  expect(pollingCheckbox.vm.value).toBe(enabled);
177
- expect(pollingCheckbox.element.classList.value.includes('v-popper--has-tooltip')).toBe(!enabled);
220
+ expect(pollingCheckbox.element.classList.value.includes('has-clean-tooltip')).toBe(!enabled);
178
221
  expect(pollingIntervalInput.exists()).toBe(enabled);
179
222
  expect(pollingIntervalMinimumValueWarning.exists()).toBe(minValueWarnVisible);
180
223
  });
@@ -262,4 +305,58 @@ describe.each([
262
305
 
263
306
  expect(wrapper.vm.value.spec.downstreamResources).toStrictEqual([{ name: 'configMap2', kind: 'ConfigMap' }, { name: 'configMap3', kind: 'ConfigMap' }]);
264
307
  });
308
+
309
+ if (mode === _CREATE) {
310
+ it('should set created-by-user-id label when updateBeforeSave is called in CREATE mode', () => {
311
+ const mockCurrentUser = { id: 'user-123' };
312
+ const helmOpOptions = {
313
+ metadata: {
314
+ name: 'test-helmop',
315
+ namespace: 'test-namespace',
316
+ labels: {}
317
+ }
318
+ };
319
+ const wrapper = mount(HelmOpComponent, initHelmOp({ mode, realMode: mode }, helmOpOptions));
320
+
321
+ // Ensure metadata.labels exists
322
+ if (!wrapper.vm.value.metadata.labels) {
323
+ wrapper.vm.value.metadata.labels = {};
324
+ }
325
+
326
+ // Mock the currentUser
327
+ (wrapper.vm as any).currentUser = mockCurrentUser;
328
+
329
+ // Call updateBeforeSave method
330
+ wrapper.vm.updateBeforeSave();
331
+
332
+ // Should set the created-by-user-id label in CREATE mode
333
+ expect(wrapper.vm.value.metadata.labels['fleet.cattle.io/created-by-user-id']).toBe('user-123');
334
+ });
335
+ } else {
336
+ it('should not set created-by-user-id label when updateBeforeSave is called in EDIT mode', () => {
337
+ const mockCurrentUser = { id: 'user-123' };
338
+ const helmOpOptions = {
339
+ metadata: {
340
+ name: 'test-helmop',
341
+ namespace: 'test-namespace',
342
+ labels: {}
343
+ }
344
+ };
345
+ const wrapper = mount(HelmOpComponent, initHelmOp({ mode, realMode: mode }, helmOpOptions));
346
+
347
+ // Ensure metadata.labels exists
348
+ if (!wrapper.vm.value.metadata.labels) {
349
+ wrapper.vm.value.metadata.labels = {};
350
+ }
351
+
352
+ // Mock the currentUser
353
+ (wrapper.vm as any).currentUser = mockCurrentUser;
354
+
355
+ // Call updateBeforeSave method
356
+ wrapper.vm.updateBeforeSave();
357
+
358
+ // Should not set the label in EDIT mode
359
+ expect(wrapper.vm.value.metadata.labels['fleet.cattle.io/created-by-user-id']).toBeUndefined();
360
+ });
361
+ }
265
362
  });
@@ -80,6 +80,7 @@ export default {
80
80
  type: CONFIG_MAP
81
81
  }
82
82
  }, this.$store);
83
+ this.currentUser = await this.value.getCurrentUser();
83
84
  },
84
85
 
85
86
  data() {
@@ -405,6 +406,10 @@ export default {
405
406
 
406
407
  updateBeforeSave() {
407
408
  this.value.spec['correctDrift'] = { enabled: this.correctDriftEnabled };
409
+
410
+ if (this.mode === _CREATE) {
411
+ this.value.metadata.labels[FLEET_LABELS.CREATED_BY_USER_ID] = this.currentUser.id;
412
+ }
408
413
  },
409
414
 
410
415
  durationSeconds(value) {
@@ -112,8 +112,8 @@ describe('component: rke2', () => {
112
112
  global: {
113
113
  mocks: {
114
114
  ...defaultMocks,
115
- $store: { dispatch: () => jest.fn(), getters: defaultGetters },
116
- $plugin: { getDynamic: jest.fn(() => undefined ) }
115
+ $store: { dispatch: () => jest.fn(), getters: defaultGetters },
116
+ $extension: { getDynamic: jest.fn(() => undefined ) }
117
117
  },
118
118
 
119
119
  stubs: defaultStubs,
@@ -143,8 +143,8 @@ describe('component: rke2', () => {
143
143
  global: {
144
144
  mocks: {
145
145
  ...defaultMocks,
146
- $store: { dispatch: () => jest.fn(), getters: defaultGetters },
147
- $plugin: { getDynamic: jest.fn(() => undefined ) },
146
+ $store: { dispatch: () => jest.fn(), getters: defaultGetters },
147
+ $extension: { getDynamic: jest.fn(() => undefined ) },
148
148
  },
149
149
 
150
150
  stubs: defaultStubs,
@@ -174,8 +174,8 @@ describe('component: rke2', () => {
174
174
  global: {
175
175
  mocks: {
176
176
  ...defaultMocks,
177
- $store: { dispatch: () => jest.fn(), getters: defaultGetters },
178
- $plugin: { getDynamic: jest.fn(() => undefined ) },
177
+ $store: { dispatch: () => jest.fn(), getters: defaultGetters },
178
+ $extension: { getDynamic: jest.fn(() => undefined ) },
179
179
  },
180
180
 
181
181
  stubs: defaultStubs,
@@ -231,7 +231,7 @@ describe('component: rke2', () => {
231
231
  },
232
232
  getters: defaultGetters
233
233
  },
234
- $plugin: { getDynamic: jest.fn(() => undefined ) },
234
+ $extension: { getDynamic: jest.fn(() => undefined ) },
235
235
  },
236
236
 
237
237
  stubs: defaultStubs,
@@ -275,7 +275,7 @@ describe('component: rke2', () => {
275
275
  'management/findAll': () => ([]),
276
276
  }
277
277
  },
278
- $plugin: { getDynamic: jest.fn(() => undefined ) },
278
+ $extension: { getDynamic: jest.fn(() => undefined ) },
279
279
  },
280
280
 
281
281
  stubs: defaultStubs,
@@ -324,7 +324,7 @@ describe('component: rke2', () => {
324
324
  'management/findAll': () => ([]),
325
325
  }
326
326
  },
327
- $plugin: { getDynamic: jest.fn(() => undefined ) },
327
+ $extension: { getDynamic: jest.fn(() => undefined ) },
328
328
  },
329
329
 
330
330
  stubs: defaultStubs,
@@ -369,8 +369,8 @@ describe('component: rke2', () => {
369
369
  global: {
370
370
  mocks: {
371
371
  ...defaultMocks,
372
- $store: { dispatch: () => jest.fn(), getters: defaultGetters },
373
- $plugin: { getDynamic: jest.fn(() => undefined ) },
372
+ $store: { dispatch: () => jest.fn(), getters: defaultGetters },
373
+ $extension: { getDynamic: jest.fn(() => undefined ) },
374
374
  },
375
375
  stubs: defaultStubs
376
376
  }
@@ -409,8 +409,8 @@ describe('component: rke2', () => {
409
409
  global: {
410
410
  mocks: {
411
411
  ...defaultMocks,
412
- $store: { dispatch: () => jest.fn(), getters: defaultGetters },
413
- $plugin: { getDynamic: jest.fn(() => undefined ) },
412
+ $store: { dispatch: () => jest.fn(), getters: defaultGetters },
413
+ $extension: { getDynamic: jest.fn(() => undefined ) },
414
414
  },
415
415
  stubs: defaultStubs
416
416
  }
@@ -441,8 +441,8 @@ describe('component: rke2', () => {
441
441
  global: {
442
442
  mocks: {
443
443
  ...defaultMocks,
444
- $store: { dispatch: () => jest.fn(), getters: defaultGetters },
445
- $plugin: { getDynamic: jest.fn(() => undefined ) },
444
+ $store: { dispatch: () => jest.fn(), getters: defaultGetters },
445
+ $extension: { getDynamic: jest.fn(() => undefined ) },
446
446
  },
447
447
  stubs: defaultStubs
448
448
  }
@@ -489,8 +489,8 @@ describe('component: rke2', () => {
489
489
  global: {
490
490
  mocks: {
491
491
  ...defaultMocks,
492
- $store: { dispatch: () => jest.fn(), getters: defaultGetters },
493
- $plugin: { getDynamic: jest.fn(() => undefined ) },
492
+ $store: { dispatch: () => jest.fn(), getters: defaultGetters },
493
+ $extension: { getDynamic: jest.fn(() => undefined ) },
494
494
  },
495
495
  stubs: defaultStubs
496
496
  }
@@ -536,8 +536,8 @@ describe('component: rke2', () => {
536
536
  global: {
537
537
  mocks: {
538
538
  ...defaultMocks,
539
- $store: { dispatch: () => jest.fn(), getters: defaultGetters },
540
- $plugin: { getDynamic: jest.fn(() => undefined ) },
539
+ $store: { dispatch: () => jest.fn(), getters: defaultGetters },
540
+ $extension: { getDynamic: jest.fn(() => undefined ) },
541
541
  },
542
542
  stubs: defaultStubs
543
543
  }
@@ -600,8 +600,8 @@ describe('component: rke2', () => {
600
600
  global: {
601
601
  mocks: {
602
602
  ...defaultMocks,
603
- $store: { dispatch: () => jest.fn(), getters: defaultGetters },
604
- $plugin: { getDynamic: jest.fn(() => undefined ) },
603
+ $store: { dispatch: () => jest.fn(), getters: defaultGetters },
604
+ $extension: { getDynamic: jest.fn(() => undefined ) },
605
605
  },
606
606
 
607
607
  stubs: defaultStubs,
@@ -332,9 +332,9 @@ export default {
332
332
  // Keeping this for non Rancher-managed kontainer drivers
333
333
  this.kontainerDrivers.filter((x) => (isImport ? x.showImport : x.showCreate)).forEach((obj) => {
334
334
  if ( vueKontainerTypes.includes(obj.driverName) ) {
335
- addType(this.$plugin, obj.driverName, 'hosted', false);
335
+ addType(this.$extension, obj.driverName, 'hosted', false);
336
336
  } else {
337
- addType(this.$plugin, obj.driverName, 'hosted', false, (isImport ? obj.emberImportPath : obj.emberCreatePath));
337
+ addType(this.$extension, obj.driverName, 'hosted', false, (isImport ? obj.emberImportPath : obj.emberCreatePath));
338
338
  }
339
339
  });
340
340
  if (!isImport) {
@@ -351,7 +351,7 @@ export default {
351
351
 
352
352
  // If Elemental is installed, then add the elemental cluster provider
353
353
  if (isElementalActive) {
354
- addType(this.$plugin, ELEMENTAL_CLUSTER_PROVIDER, 'custom2', false);
354
+ addType(this.$extension, ELEMENTAL_CLUSTER_PROVIDER, 'custom2', false);
355
355
  }
356
356
 
357
357
  // Only add the RKE2 options if RKE2 is enabled
@@ -359,10 +359,10 @@ export default {
359
359
  machineTypes.forEach((type) => {
360
360
  const id = type.spec.displayName || type.id;
361
361
 
362
- addType(this.$plugin, id, _RKE2, false, null, undefined, type);
362
+ addType(this.$extension, id, _RKE2, false, null, undefined, type);
363
363
  });
364
364
 
365
- addType(this.$plugin, 'custom', 'custom2', false);
365
+ addType(this.$extension, 'custom', 'custom2', false);
366
366
  }
367
367
  }
368
368
  // Add from extensions
@@ -502,7 +502,7 @@ export default {
502
502
  * 2) Override via hardcoded setting
503
503
  */
504
504
  cloudCredentialsOverride() {
505
- const cloudCredential = this.$plugin.getDynamic('cloud-credential', this.provider);
505
+ const cloudCredential = this.$extension.getDynamic('cloud-credential', this.provider);
506
506
 
507
507
  if (cloudCredential === undefined) {
508
508
  return CLOUD_CREDENTIAL_OVERRIDE[this.provider];
@@ -527,16 +527,16 @@ export default {
527
527
  * Extension provider where being provisioned by an extension
528
528
  */
529
529
  extensionProvider() {
530
- const extClass = this.$plugin.getDynamic('provisioner', this.provider);
530
+ const extClass = this.$extension.getDynamic('provisioner', this.provider);
531
531
 
532
532
  if (extClass) {
533
533
  return new extClass({
534
- dispatch: this.$store.dispatch,
535
- getters: this.$store.getters,
536
- axios: this.$store.$axios,
537
- $plugin: this.$store.app.$plugin,
538
- $t: this.t,
539
- isCreate: this.isCreate
534
+ dispatch: this.$store.dispatch,
535
+ getters: this.$store.getters,
536
+ axios: this.$store.$axios,
537
+ $extension: this.$store.app.$extension,
538
+ $t: this.t,
539
+ isCreate: this.isCreate
540
540
  });
541
541
  }
542
542
 
@@ -310,7 +310,7 @@ export default {
310
310
  <template #label>
311
311
  <label
312
312
  v-clean-tooltip="t('backupRestoreOperator.deleteTimeout.tip')"
313
- class="v-popper--has-tooltip"
313
+ class="has-clean-tooltip"
314
314
  >
315
315
  {{ t('backupRestoreOperator.deleteTimeout.label') }} <i class="icon icon-info" />
316
316
  </label>
@@ -261,7 +261,7 @@ export default {
261
261
  >
262
262
  <template #label>
263
263
  <label
264
- class="v-popper--has-tooltip"
264
+ class="has-clean-tooltip"
265
265
  :style="{'color':'var(--input-label)'}"
266
266
  >
267
267
  {{ t('workload.upgrading.terminationGracePeriodSeconds.label') }}
@@ -322,7 +322,7 @@ export default {
322
322
  >
323
323
  <template #label>
324
324
  <label
325
- class="v-popper--has-tooltip"
325
+ class="has-clean-tooltip"
326
326
  :style="{'color':'var(--input-label)'}"
327
327
  >
328
328
  {{ t('workload.upgrading.terminationGracePeriodSeconds.label') }}
@@ -155,7 +155,7 @@ export default {
155
155
  :default-tab="defaultTab || defaultWorkloadTab"
156
156
  :flat="true"
157
157
  :use-hash="useTabbedHash"
158
-
158
+ :showExtensionTabs="false"
159
159
  data-testid="workload-horizontal-tabs"
160
160
  @changed="changed"
161
161
  >
@@ -19,13 +19,12 @@ import { InstallCodeMirror } from 'codemirror-editor-vue3';
19
19
  import * as intNumber from '@shell/directives/int-number';
20
20
  import dashboardClientInit from '@shell/plugins/dashboard-client-init';
21
21
  import plugin from '@shell/plugins/plugin';
22
- import plugins from '@shell/core/plugins.js';
23
22
  import pluginsLoader from '@shell/core/plugins-loader.js';
24
23
  import replaceAll from '@shell/plugins/replaceall';
25
24
  import steveCreateWorker from '@shell/plugins/steve-create-worker';
26
25
  import emberCookie from '@shell/plugins/ember-cookie';
27
26
  import ShortKey from '@shell/plugins/shortkey';
28
- import internalApiPlugin from '@shell/plugins/internal-api';
27
+ import { initUiApis } from '@shell/apis/impl/apis';
29
28
 
30
29
  import 'floating-vue/dist/style.css';
31
30
  import { floatingVueOptions } from '@shell/plugins/floating-vue';
@@ -51,7 +50,7 @@ export async function installInjectedPlugins(app, vueApp) {
51
50
  const pluginDefinitions = [
52
51
  config,
53
52
  axios,
54
- plugins,
53
+ initUiApis,
55
54
  pluginsLoader,
56
55
  axiosShell,
57
56
  intNumber,
@@ -61,7 +60,6 @@ export async function installInjectedPlugins(app, vueApp) {
61
60
  plugin,
62
61
  steveCreateWorker,
63
62
  emberCookie,
64
- internalApiPlugin,
65
63
  dynamicContent,
66
64
  ];
67
65
 
@@ -69,7 +67,8 @@ export async function installInjectedPlugins(app, vueApp) {
69
67
  if (typeof pluginDefinition === 'function') {
70
68
  await pluginDefinition(
71
69
  app.context,
72
- (key, value) => inject(key, value, app.context, vueApp)
70
+ (key, value) => inject(key, value, app.context, vueApp),
71
+ vueApp
73
72
  );
74
73
  }
75
74
  });
@@ -37,7 +37,7 @@ const defaultConfig = {
37
37
  faultDomainCount: '3',
38
38
  image: 'canonical:ubuntu-24_04-lts:server-gen1:latest',
39
39
  location: 'westus',
40
- managedDisks: false,
40
+ managedDisks: true,
41
41
  noPublicIp: false,
42
42
  nsg: null,
43
43
  privateIpAddress: null,
@@ -8,7 +8,7 @@ import { getGKEImageFamilies, getGKEFamiliesFromProject } from '@shell/component
8
8
  import debounce from 'lodash/debounce';
9
9
  import { mapGetters } from 'vuex';
10
10
 
11
- const DEFAULT_PROJECTS = 'suse-cloud, ubuntu-os-cloud, rhel-cloud';
11
+ const DEFAULT_PROJECTS = 'ubuntu-os-cloud';
12
12
  const DEFAULT_MIN_DISK = 10;
13
13
 
14
14
  export default {