@rancher/shell 3.0.5-rc.8 → 3.0.5

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 (199) hide show
  1. package/assets/styles/base/_color.scss +4 -1
  2. package/assets/styles/global/_tooltip.scss +7 -4
  3. package/assets/styles/themes/_dark.scss +11 -0
  4. package/assets/styles/themes/_light.scss +13 -1
  5. package/assets/styles/themes/_modern.scss +22 -0
  6. package/assets/translations/en-us.yaml +147 -19
  7. package/assets/translations/zh-hans.yaml +0 -1
  8. package/chart/monitoring/grafana/index.vue +8 -2
  9. package/components/ActionMenuShell.vue +3 -1
  10. package/components/Cron/CronExpressionEditor.vue +299 -0
  11. package/components/Cron/CronExpressionEditorModal.vue +247 -0
  12. package/components/Cron/CronTooltip.vue +87 -0
  13. package/components/Cron/types.ts +13 -0
  14. package/components/ForceDirectedTreeChart/composable.ts +11 -0
  15. package/components/PodSecurityAdmission.vue +2 -0
  16. package/components/PromptModal.vue +1 -1
  17. package/components/Resource/Detail/Card/__tests__/StateCard.test.ts +1 -0
  18. package/components/Resource/Detail/CopyToClipboard.vue +78 -0
  19. package/components/Resource/Detail/FetchLoader/__tests__/composables.test.ts +69 -0
  20. package/components/Resource/Detail/FetchLoader/composables.ts +27 -0
  21. package/components/Resource/Detail/Metadata/Annotations/__tests__/index.test.ts +1 -1
  22. package/components/Resource/Detail/Metadata/Annotations/index.vue +1 -1
  23. package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +13 -61
  24. package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/index.test.ts +33 -6
  25. package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +24 -38
  26. package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +25 -5
  27. package/components/Resource/Detail/Metadata/KeyValue.vue +12 -23
  28. package/components/Resource/Detail/Metadata/KeyValueRow.vue +144 -0
  29. package/components/Resource/Detail/Metadata/Labels/__tests__/index.test.ts +1 -0
  30. package/components/Resource/Detail/Metadata/Labels/index.vue +1 -0
  31. package/components/Resource/Detail/Metadata/__tests__/KeyValue.test.ts +30 -32
  32. package/components/Resource/Detail/Metadata/__tests__/KeyValueRow.test.ts +108 -0
  33. package/components/Resource/Detail/Metadata/__tests__/composables.test.ts +0 -3
  34. package/components/Resource/Detail/Metadata/__tests__/index.test.ts +12 -5
  35. package/components/Resource/Detail/Metadata/composables.ts +1 -4
  36. package/components/Resource/Detail/Metadata/index.vue +1 -0
  37. package/components/Resource/Detail/Preview/Content.vue +63 -0
  38. package/components/Resource/Detail/Preview/Preview.vue +128 -0
  39. package/components/Resource/Detail/Preview/__tests__/Content.spec.ts +71 -0
  40. package/components/Resource/Detail/Preview/__tests__/Preview.spec.ts +121 -0
  41. package/components/Resource/Detail/ResourcePopover/ResourcePopoverCard.vue +141 -0
  42. package/components/Resource/Detail/ResourcePopover/__tests__/ResourcePopoverCard.test.ts +136 -0
  43. package/components/Resource/Detail/ResourcePopover/__tests__/index.test.ts +245 -0
  44. package/components/Resource/Detail/ResourcePopover/index.vue +226 -0
  45. package/components/Resource/Detail/SpacedRow.vue +1 -0
  46. package/components/Resource/Detail/TitleBar/__tests__/composables.test.ts +0 -5
  47. package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +1 -1
  48. package/components/Resource/Detail/TitleBar/composables.ts +1 -3
  49. package/components/Resource/Detail/TitleBar/index.vue +2 -29
  50. package/components/Resource/Detail/ViewOptions/composable.ts +9 -0
  51. package/components/Resource/Detail/ViewOptions/index.vue +41 -0
  52. package/components/Resource/Detail/__tests__/CopyToClipboard.spec.ts +82 -0
  53. package/components/ResourceDetail/Masthead/legacy.vue +0 -19
  54. package/components/ResourceDetail/index.vue +1 -26
  55. package/components/ResourceTable.vue +24 -0
  56. package/components/SortableTable/index.vue +7 -1
  57. package/components/SortableTable/paging.js +3 -0
  58. package/components/Tabbed/Tab.vue +43 -1
  59. package/components/Tabbed/index.vue +3 -1
  60. package/components/__tests__/Cron/CronExpressionEditor.test.ts +151 -0
  61. package/components/__tests__/Cron/CronExpressionEditorModal.test.ts +81 -0
  62. package/components/auth/login/saml.vue +86 -0
  63. package/components/form/LabeledSelect.vue +8 -8
  64. package/components/form/ProjectMemberEditor.vue +2 -0
  65. package/components/form/ResourceTabs/composable.ts +54 -0
  66. package/components/form/ResourceTabs/index.vue +10 -7
  67. package/components/form/Select.vue +13 -10
  68. package/components/form/__tests__/LabeledSelect.test.ts +133 -0
  69. package/components/form/__tests__/Select.test.ts +134 -0
  70. package/components/nav/Header.vue +6 -5
  71. package/composables/useExtensionManager.ts +17 -0
  72. package/config/home-links.js +12 -0
  73. package/config/labels-annotations.js +0 -1
  74. package/config/page-actions.js +0 -1
  75. package/config/product/explorer.js +3 -1
  76. package/config/product/fleet.js +2 -7
  77. package/config/product/manager.js +0 -5
  78. package/config/query-params.js +1 -0
  79. package/config/router/navigation-guards/clusters.js +2 -1
  80. package/config/router/navigation-guards/products.js +1 -1
  81. package/config/store.js +2 -0
  82. package/core/extension-manager-impl.js +518 -0
  83. package/core/plugins.js +35 -468
  84. package/core/types.ts +8 -2
  85. package/detail/__tests__/autoscaling.horizontalpodautoscaler.test.ts +1 -0
  86. package/detail/catalog.cattle.io.app.vue +7 -4
  87. package/detail/fleet.cattle.io.bundle.vue +1 -5
  88. package/detail/fleet.cattle.io.cluster.vue +3 -2
  89. package/detail/fleet.cattle.io.gitrepo.vue +76 -49
  90. package/detail/fleet.cattle.io.helmop.vue +78 -49
  91. package/dialog/AddonConfigConfirmationDialog.vue +1 -1
  92. package/dialog/GenericPrompt.vue +1 -1
  93. package/dialog/ImportDialog.vue +9 -2
  94. package/dialog/InstallExtensionDialog.vue +18 -10
  95. package/dialog/SloDialog.vue +1 -1
  96. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +2 -1
  97. package/edit/__tests__/resources.cattle.io.restore.test.ts +106 -0
  98. package/edit/auth/oidc.vue +106 -6
  99. package/edit/auth/saml.vue +5 -5
  100. package/edit/cloudcredential.vue +31 -17
  101. package/edit/constraints.gatekeeper.sh.constraint/index.vue +10 -2
  102. package/edit/fleet.cattle.io.cluster.vue +19 -0
  103. package/edit/fleet.cattle.io.gitrepo.vue +23 -16
  104. package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +12 -11
  105. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +11 -1
  106. package/edit/provisioning.cattle.io.cluster/index.vue +14 -19
  107. package/edit/provisioning.cattle.io.cluster/rke2.vue +11 -3
  108. package/edit/provisioning.cattle.io.cluster/tabs/AddOnAdditionalManifest.vue +1 -0
  109. package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +1 -0
  110. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +1 -0
  111. package/edit/provisioning.cattle.io.cluster/tabs/etcd/S3Config.vue +1 -0
  112. package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +2 -0
  113. package/edit/provisioning.cattle.io.cluster/tabs/upgrade/DrainOptions.vue +6 -0
  114. package/edit/resources.cattle.io.restore.vue +5 -8
  115. package/initialize/install-plugins.js +1 -3
  116. package/list/__tests__/workload.test.ts +1 -0
  117. package/list/workload.vue +8 -1
  118. package/machine-config/components/GCEImage.vue +6 -5
  119. package/machine-config/google.vue +11 -6
  120. package/mixins/__tests__/auth-config.test.ts +4 -6
  121. package/mixins/__tests__/chart.test.ts +139 -1
  122. package/mixins/auth-config.js +33 -10
  123. package/mixins/chart.js +58 -18
  124. package/models/__tests__/namespace.test.ts +69 -0
  125. package/models/apps.statefulset.js +8 -10
  126. package/models/chart.js +5 -1
  127. package/models/fleet-application.js +16 -46
  128. package/models/fleet.cattle.io.bundle.js +1 -38
  129. package/models/fleet.cattle.io.gitrepo.js +4 -0
  130. package/models/fleet.cattle.io.helmop.js +4 -0
  131. package/models/management.cattle.io.cluster.js +1 -1
  132. package/models/management.cattle.io.project.js +12 -0
  133. package/models/namespace.js +30 -0
  134. package/models/workload.js +4 -1
  135. package/package.json +10 -10
  136. package/pages/auth/login.vue +8 -3
  137. package/pages/auth/logout.vue +6 -5
  138. package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +26 -11
  139. package/pages/c/_cluster/apps/charts/chart.vue +29 -20
  140. package/pages/c/_cluster/apps/charts/index.vue +1 -0
  141. package/pages/c/_cluster/apps/charts/install.vue +6 -5
  142. package/pages/c/_cluster/explorer/tools/__tests__/index.test.ts +102 -12
  143. package/pages/c/_cluster/explorer/tools/index.vue +145 -254
  144. package/pages/c/_cluster/manager/cloudCredential/index.vue +18 -1
  145. package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +12 -2
  146. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +1 -1
  147. package/pages/c/_cluster/uiplugins/__tests__/index.spec.ts +318 -0
  148. package/pages/c/_cluster/uiplugins/index.vue +221 -363
  149. package/pages/home.vue +1 -9
  150. package/plugins/axios.js +3 -2
  151. package/plugins/dashboard-store/resource-class.js +49 -0
  152. package/plugins/ember-cookie.js +7 -3
  153. package/plugins/steve/subscribe.js +4 -2
  154. package/public/index.html +2 -1
  155. package/rancher-components/Card/Card.vue +1 -1
  156. package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
  157. package/rancher-components/Form/Radio/RadioButton.vue +1 -1
  158. package/rancher-components/Form/Radio/RadioGroup.vue +1 -1
  159. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +1 -11
  160. package/rancher-components/Pill/RcCounterBadge/RcCounterBadge.test.ts +53 -0
  161. package/rancher-components/Pill/RcCounterBadge/RcCounterBadge.vue +65 -0
  162. package/rancher-components/Pill/RcCounterBadge/index.ts +1 -0
  163. package/rancher-components/Pill/RcCounterBadge/types.ts +7 -0
  164. package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +1 -1
  165. package/rancher-components/Pill/RcStatusBadge/index.ts +1 -1
  166. package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +3 -3
  167. package/rancher-components/Pill/RcStatusIndicator/types.ts +1 -1
  168. package/rancher-components/Pill/RcTag/RcTag.test.ts +64 -0
  169. package/rancher-components/Pill/RcTag/RcTag.vue +94 -0
  170. package/rancher-components/Pill/RcTag/index.ts +1 -0
  171. package/rancher-components/Pill/RcTag/types.ts +9 -0
  172. package/rancher-components/Pill/types.ts +1 -0
  173. package/rancher-components/RcItemCard/RcItemCard.vue +1 -0
  174. package/rancher-components/RcItemCard/RcItemCardAction.vue +12 -0
  175. package/scripts/test-plugins-build.sh +0 -1
  176. package/store/__tests__/catalog.test.ts +63 -0
  177. package/store/__tests__/cookies.test.ts +72 -0
  178. package/store/auth.js +33 -10
  179. package/store/catalog.js +2 -2
  180. package/store/cookies.ts +30 -0
  181. package/store/prefs.js +10 -5
  182. package/store/type-map.js +3 -15
  183. package/types/extension-manager.ts +26 -0
  184. package/types/shell/index.d.ts +123 -27
  185. package/utils/__tests__/product.test.ts +129 -0
  186. package/utils/__tests__/resource.test.ts +87 -0
  187. package/utils/alertmanagerconfig.js +2 -2
  188. package/utils/auth.js +4 -77
  189. package/utils/product.ts +39 -0
  190. package/utils/resource.ts +35 -0
  191. package/utils/select.js +0 -24
  192. package/utils/validators/formRules/__tests__/index.test.ts +3 -0
  193. package/utils/validators/formRules/index.ts +2 -1
  194. package/vue.config.js +1 -1
  195. package/components/Resource/Detail/Metadata/Rectangle.vue +0 -34
  196. package/components/Resource/Detail/Metadata/__tests__/Rectangle.test.ts +0 -24
  197. package/components/ResourceDetail/Masthead/__tests__/legacy.test.ts +0 -65
  198. package/utils/cookie-universal.js +0 -10
  199. /package/components/{ForceDirectedTreeChart.vue → ForceDirectedTreeChart/index.vue} +0 -0
package/core/plugins.js CHANGED
@@ -1,471 +1,38 @@
1
- import { productsLoaded } from '@shell/store/type-map';
2
- import { clearModelCache } from '@shell/plugins/dashboard-store/model-loader';
3
- import { EXT_IDS, Plugin } from './plugin';
4
- import { PluginRoutes } from './plugin-routes';
5
- import { UI_PLUGIN_BASE_URL } from '@shell/config/uiplugins';
6
- import { ExtensionPoint } from './types';
7
- import { addLinkInterceptor, removeLinkInterceptor } from '@shell/plugins/clean-html';
1
+ import { throttle } from 'lodash';
2
+ import { initExtensionManager } from './extension-manager-impl';
8
3
 
9
- export default function(context, inject, vueApp) {
10
- const {
11
- app, store, $axios, redirect
12
- } = context;
13
- const dynamic = {};
14
- const validators = {};
15
- let _lastLoaded = 0;
4
+ export default function(context, inject) {
5
+ const extensionManager = initExtensionManager(context);
6
+ const deprecationMessage = '[DEPRECATED] `this.$plugin` is deprecated and will be removed in a future version. Use `this.$extension` instead.';
16
7
 
17
- // Track which plugin loaded what, so we can unload stuff
18
- const plugins = {};
19
-
20
- const pluginRoutes = new PluginRoutes(app.router);
21
-
22
- const uiConfig = {};
23
-
24
- // Builtin extensions - these are registered when the UI loads and then initialized/loaded at the same time as the external extensions
25
- let builtin = [];
26
-
27
- for (const ep in ExtensionPoint) {
28
- uiConfig[ExtensionPoint[ep]] = {};
29
- }
30
-
31
- /**
32
- * When an extension adds a model extension, it provides the class - we will instantiate that class and store and use that
33
- */
34
- function instantiateModelExtension($plugin, clz) {
35
- const context = {
36
- dispatch: store.dispatch,
37
- getters: store.getters,
38
- t: store.getters['i18n/t'],
39
- $axios,
40
- $plugin,
41
- };
42
-
43
- return new clz(context);
44
- }
45
-
46
- inject(
47
- 'plugin',
48
- {
49
- // Plugins should not use these - but we will pass them in for now as a 2nd argument
50
- // in case there are use cases not covered that require direct access - we may remove access later
51
- internal() {
52
- const internal = {
53
- app,
54
- store,
55
- $axios,
56
- redirect,
57
- plugins: this
58
- };
59
-
60
- return internal;
61
- },
62
-
63
- // Load a plugin from a UI package
64
- loadPluginAsync(plugin) {
65
- const { name, version } = plugin;
66
- const id = `${ name }-${ version }`;
67
- let url;
68
-
69
- if (plugin?.metadata?.direct === 'true') {
70
- url = plugin.endpoint;
71
- } else {
72
- // See if the plugin has a main metadata property set
73
- const main = plugin?.metadata?.main || `${ id }.umd.min.js`;
74
-
75
- url = `${ UI_PLUGIN_BASE_URL }/${ name }/${ version }/plugin/${ main }`;
76
- }
77
-
78
- return this.loadAsync(id, url);
79
- },
80
-
81
- // Load a plugin from a UI package
82
- loadAsync(id, mainFile) {
83
- return new Promise((resolve, reject) => {
84
- // The plugin is already loaded so we should avoid loading it again.
85
- // This will primarily affect plugins that load prior to authentication and we attempt to load again after authentication.
86
- if (document.getElementById(id)) {
87
- return resolve();
88
- }
89
- const moduleUrl = mainFile;
90
- const element = document.createElement('script');
91
-
92
- element.src = moduleUrl;
93
- element.type = 'text/javascript';
94
- element.async = true;
95
- element.id = id;
96
- element.dataset.purpose = 'extension';
97
-
98
- element.onload = () => {
99
- if (!window[id] || (typeof window[id].default !== 'function')) {
100
- return reject(new Error('Could not load plugin code'));
101
- }
102
-
103
- // Update the timestamp that new plugins were loaded - may be needed
104
- // to update caches when new plugins are loaded
105
- _lastLoaded = new Date().getTime();
106
-
107
- // name is the name of the plugin, including the version number
108
- const plugin = new Plugin(id);
109
-
110
- plugins[id] = plugin;
111
-
112
- // Initialize the plugin
113
- try {
114
- window[id].default(plugin, this.internal());
115
- } catch (e) {
116
- delete plugins[id];
117
-
118
- return reject(new Error('Could not initialize plugin'));
119
- }
120
-
121
- // Load all of the types etc from the plugin
122
- this.applyPlugin(plugin);
123
-
124
- // Add the plugin to the store
125
- store.dispatch('uiplugins/addPlugin', plugin);
126
-
127
- resolve();
128
- };
129
-
130
- element.onerror = (e) => {
131
- element.parentElement.removeChild(element);
132
-
133
- // Massage the error into something useful
134
- const errorMessage = `Failed to load script from '${ e.target.src }'`;
135
-
136
- console.error(errorMessage, e); // eslint-disable-line no-console
137
- reject(new Error(errorMessage)); // This is more useful where it's used
138
- };
139
-
140
- document.head.appendChild(element);
141
- });
142
- },
143
-
144
- /**
145
- * Load the builtin extensions by initializing them in turn
146
- */
147
- loadBuiltinExtensions() {
148
- builtin.forEach((ext) => {
149
- this.initBuiltinExtension(ext.id, ext.module);
150
- });
151
-
152
- // We've loaded the builtin extensions, so clear out the list so we don't load again
153
- builtin = [];
154
- },
155
-
156
- /**
157
- * Register a builtin extension that should be loaded
158
- *
159
- * Used by the dynamic loader when a plugin is included in the build (see shell/vue.config.js)
160
- */
161
- registerBuiltinExtension(id, module) {
162
- builtin.push({ id, module });
163
- },
164
-
165
- /**
166
- * Initialize a builtin extension
167
- *
168
- * This is only used by the 'loadBuiltinExtensions' function above
169
- */
170
- initBuiltinExtension(id, module) {
171
- const plugin = new Plugin(id);
172
-
173
- // Mark the plugin as being built-in
174
- plugin.builtin = true;
175
-
176
- plugins[id] = plugin;
177
-
178
- // Initialize the plugin
179
- const p = module;
180
-
181
- try {
182
- const load = p.default(plugin, this.internal());
183
-
184
- // The function must explicitly return false to skip loading of the extension (this is only allows on builtin extensions)
185
- // Only built-in extensions can return that they should not be loaded, because the extension can still do 'things'
186
- // in its init code (inject code, styles etc), so we do not want to hide an extension that has 'partially' loaded,
187
- // just because it tells us it should not load.
188
- // Built-in extensions are compiled into the app, so there is a level of trust assumed with them
189
- if (load !== false) {
190
- // Update last load so that the translations get loaded
191
- _lastLoaded = new Date().getTime();
192
-
193
- // Load all of the types etc from the extension
194
- this.applyPlugin(plugin);
195
-
196
- // Add the extension to the store
197
- store.dispatch('uiplugins/addPlugin', plugin);
198
- } else {
199
- // Plugin did not load, so remove it so it is not shown as loaded
200
- delete plugins[id];
201
- }
202
- } catch (e) {
203
- console.error(`Error loading extension ${ plugin.name }`); // eslint-disable-line no-console
204
- console.error(e); // eslint-disable-line no-console
205
-
206
- // Plugin did not load, so remove it so it is not shown as loaded
207
- delete plugins[id];
208
- }
209
- },
210
-
211
- async logout() {
212
- const all = Object.values(plugins);
213
-
214
- for (let i = 0; i < all.length; i++) {
215
- const plugin = all[i];
216
-
217
- if (plugin.builtin) {
218
- continue;
219
- }
220
-
221
- try {
222
- await this.removePlugin(plugin.name);
223
- } catch (e) {
224
- console.error('Error removing extension', e); // eslint-disable-line no-console
225
- }
226
-
227
- delete plugins[plugin.id];
228
- }
229
- },
230
-
231
- // Remove the plugin
232
- async removePlugin(name) {
233
- const plugin = Object.values(plugins).find((p) => p.name === name);
234
-
235
- if (!plugin) {
236
- return;
237
- }
238
-
239
- const promises = [];
240
-
241
- plugin.productNames.forEach((product) => {
242
- promises.push(store.dispatch('type-map/removeProduct', { product, plugin }));
243
- });
244
-
245
- // Remove all of the types
246
- Object.keys(plugin.types).forEach((typ) => {
247
- Object.keys(plugin.types[typ]).forEach((name) => {
248
- this.unregister(typ, name);
249
-
250
- if (typ === EXT_IDS.MODELS) {
251
- clearModelCache(name);
252
- }
253
- });
254
- });
255
-
256
- // Remove locales
257
- plugin.locales.forEach((localeObj) => {
258
- promises.push(store.dispatch('i18n/removeLocale', localeObj));
259
- });
260
-
261
- if (plugin.types.models) {
262
- // Ask the Steve stores to forget any data it has for models that we are removing
263
- promises.push(...this.removeTypeFromStore(store, 'rancher', Object.keys(plugin.types.models)));
264
- promises.push(...this.removeTypeFromStore(store, 'management', Object.keys(plugin.types.models)));
265
- }
266
-
267
- // Call plugin uninstall hooks
268
- plugin.uninstallHooks.forEach((fn) => fn(plugin, this.internal()));
269
-
270
- // Remove the plugin itself
271
- promises.push( store.dispatch('uiplugins/removePlugin', name));
272
-
273
- // Unregister vuex stores
274
- plugin.stores.forEach((pStore) => pStore.unregister(store));
275
-
276
- // Remove validators
277
- Object.keys(plugin.validators).forEach((key) => {
278
- delete validators[key];
279
- });
280
-
281
- // Remove link interceptors
282
- if (plugin.types.linkInterceptor) {
283
- Object.keys(plugin.types.linkInterceptor).forEach((name) => {
284
- removeLinkInterceptor(plugin.types.linkInterceptor[name]);
285
- });
286
- }
287
-
288
- await Promise.all(promises);
289
-
290
- // Update last load since we removed a plugin
291
- _lastLoaded = new Date().getTime();
292
- },
293
-
294
- removeTypeFromStore(store, storeName, types) {
295
- return (types || []).map((type) => store.commit(`${ storeName }/forgetType`, type));
296
- },
297
-
298
- // Apply the plugin based on its metadata
299
- applyPlugin(plugin) {
300
- // Types
301
- Object.keys(plugin.types).forEach((typ) => {
302
- Object.keys(plugin.types[typ]).forEach((name) => {
303
- this.register(typ, name, plugin.types[typ][name]);
304
- });
305
- });
306
-
307
- // UI Configuration - copy UI config from a plugin into the global uiConfig object
308
- Object.keys(plugin.uiConfig).forEach((actionType) => {
309
- Object.keys(plugin.uiConfig[actionType]).forEach((actionLocation) => {
310
- plugin.uiConfig[actionType][actionLocation].forEach((action) => {
311
- if (!uiConfig[actionType][actionLocation]) {
312
- uiConfig[actionType][actionLocation] = [];
313
- }
314
- uiConfig[actionType][actionLocation].push(action);
315
- });
316
- });
317
- });
318
-
319
- // l10n
320
- Object.keys(plugin.l10n).forEach((name) => {
321
- plugin.l10n[name].forEach((fn) => {
322
- this.register('l10n', name, fn);
323
- });
324
- });
325
-
326
- // Model extensions
327
- Object.keys(plugin.modelExtensions).forEach((name) => {
328
- plugin.modelExtensions[name].forEach((fn) => {
329
- this.register(EXT_IDS.MODEL_EXTENSION, name, instantiateModelExtension(this, fn));
330
- });
331
- });
332
-
333
- // Initialize the product if the store is ready
334
- if (productsLoaded()) {
335
- this.loadProducts([plugin]);
336
- }
337
-
338
- // Register vuex stores
339
- plugin.stores.forEach((pStore) => pStore.register()(store));
340
-
341
- // Locales
342
- plugin.locales.forEach((localeObj) => {
343
- store.dispatch('i18n/addLocale', localeObj);
344
- });
345
-
346
- // Routes
347
- pluginRoutes.addRoutes(plugin.routes);
348
-
349
- // Validators
350
- Object.keys(plugin.validators).forEach((key) => {
351
- validators[key] = plugin.validators[key];
352
- });
353
-
354
- // Link Interceptors
355
- if (dynamic.linkInterceptor) {
356
- Object.keys(dynamic.linkInterceptor).forEach((name) => {
357
- addLinkInterceptor(dynamic.linkInterceptor[name], name);
358
- });
359
- }
360
- },
361
-
362
- /**
363
- * Register 'something' that can be dynamically loaded - e.g. model, edit, create, list, i18n
364
- * @param {String} type type of thing to register, e.g. 'edit'
365
- * @param {String} name unique name of 'something'
366
- * @param {Function} fn function that dynamically loads the module for the thing being registered
367
- */
368
- register(type, name, fn) {
369
- if (!dynamic[type]) {
370
- dynamic[type] = {};
371
- }
372
-
373
- // Accumulate l10n resources and model extensions rather than replace
374
- if (type === 'l10n' || type === EXT_IDS.MODEL_EXTENSION) {
375
- if (!dynamic[type][name]) {
376
- dynamic[type][name] = [];
377
- }
378
-
379
- dynamic[type][name].push(fn);
380
- } else {
381
- dynamic[type][name] = fn;
382
- }
383
- },
384
-
385
- unregister(type, name, fn) {
386
- if (type === 'l10n') {
387
- if (dynamic[type]?.[name]) {
388
- const index = dynamic[type][name].find((func) => func === fn);
389
-
390
- if (index !== -1) {
391
- dynamic[type][name].splice(index, 1);
392
- }
393
- }
394
- } else if (dynamic[type]?.[name]) {
395
- delete dynamic[type][name];
396
- }
397
- },
398
-
399
- // For debugging
400
- getAll() {
401
- return dynamic;
402
- },
403
-
404
- getPlugins() {
405
- return plugins;
406
- },
407
-
408
- getDynamic(typeName, name) {
409
- return dynamic[typeName]?.[name];
410
- },
411
-
412
- getValidator(name) {
413
- return validators[name];
414
- },
415
-
416
- /**
417
- * Return the UI configuration for the given type and location
418
- */
419
- getUIConfig(type, uiArea) {
420
- return uiConfig[type][uiArea] || [];
421
- },
422
-
423
- /**
424
- * Returns all UI Configuration (useful for debugging)
425
- */
426
- getAllUIConfig() {
427
- return uiConfig;
428
- },
429
-
430
- // Timestamp that a UI package was last loaded
431
- // Typically used to invalidate caches (e.g. i18n) when new plugins are loaded
432
- get lastLoad() {
433
- return _lastLoaded;
434
- },
435
-
436
- listDynamic(typeName) {
437
- if (!dynamic[typeName]) {
438
- return [];
439
- }
440
-
441
- return Object.keys(dynamic[typeName]);
442
- },
443
-
444
- // Get the products provided by plugins
445
- get products() {
446
- return dynamic.products || [];
447
- },
448
-
449
- // Load all of the products provided by plugins
450
- loadProducts(loadPlugins) {
451
- if (!loadPlugins) {
452
- loadPlugins = Object.values(plugins);
453
- }
454
-
455
- loadPlugins.forEach((plugin) => {
456
- if (plugin.products) {
457
- plugin.products.forEach(async(p) => {
458
- const impl = await p;
459
-
460
- if (impl.init) {
461
- impl.init(plugin, store);
462
- }
463
- });
464
- }
465
- });
466
- },
467
- },
468
- context,
469
- vueApp
470
- );
8
+ inject('plugin', deprecationProxy(extensionManager, deprecationMessage));
9
+ inject('extension', extensionManager);
471
10
  }
11
+
12
+ /**
13
+ * Proxy to log a deprecation warning when target is accessed. Only prints
14
+ * deprecation warnings in dev builds.
15
+ * @param {*} target the object to proxy
16
+ * @param {*} message the deprecation warning to print to the console
17
+ * @returns The proxied target that prints a deprecation warning when target is
18
+ * accessed
19
+ */
20
+ const deprecationProxy = (target, message) => {
21
+ const logWarning = throttle(() => {
22
+ // eslint-disable-next-line no-console
23
+ console.warn(message);
24
+ }, 150);
25
+
26
+ const deprecationHandler = {
27
+ get(target, prop) {
28
+ logWarning();
29
+
30
+ return Reflect.get(target, prop);
31
+ }
32
+ };
33
+
34
+ // an empty handler allows the proxy to behave just like the original target
35
+ const proxyHandler = !!process.env.dev ? deprecationHandler : {};
36
+
37
+ return new Proxy(target, proxyHandler);
38
+ };
package/core/types.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { ProductFunction } from './plugin';
2
2
  import { RouteRecordRaw } from 'vue-router';
3
+ import type { ExtensionManager } from '@shell/types/extension-manager';
3
4
 
4
5
  // Cluster Provisioning types
5
6
  export * from './types-provisioning';
@@ -129,6 +130,7 @@ export type Card = {
129
130
  component: Function;
130
131
  };
131
132
 
133
+ // Duplication of HeaderOptions?
132
134
  export type TableColumn = any;
133
135
 
134
136
  /** Definition of a tab (options that can be passed when defining an extension tab enhancement) */
@@ -327,7 +329,7 @@ export interface HeaderOptions {
327
329
  formatterOpts?: any;
328
330
 
329
331
  /**
330
- * Provide a function which accets a row and returns the value that should be displayed in the column
332
+ * Provide a function which accepts a row and returns the value that should be displayed in the column
331
333
  * @param row This can be any value which represents the row
332
334
  * @returns Can return {@link string | number | null | undefined} to display in the column
333
335
  */
@@ -541,10 +543,14 @@ export type ModelExtensionContext = {
541
543
  * Used to make http requests
542
544
  */
543
545
  axios: any,
546
+ /**
547
+ * [DEPRECATED] Definition of the extension
548
+ */
549
+ $plugin: ExtensionManager,
544
550
  /**
545
551
  * Definition of the extension
546
552
  */
547
- $plugin: any,
553
+ $extension: ExtensionManager,
548
554
  /**
549
555
  * Function to retrieve a localised string
550
556
  */
@@ -20,6 +20,7 @@ describe('view: autoscaling.horizontalpodautoscaler', () => {
20
20
  'current_store/all': jest.fn(),
21
21
  workspace: jest.fn(),
22
22
  'i18n/exists': jest.fn(),
23
+ 'management/byId': jest.fn()
23
24
  },
24
25
  };
25
26
 
@@ -2,7 +2,6 @@
2
2
  import YamlEditor from '@shell/components/YamlEditor';
3
3
  import Loading from '@shell/components/Loading';
4
4
  import Markdown from '@shell/components/Markdown';
5
- import Tabbed from '@shell/components/Tabbed';
6
5
  import Tab from '@shell/components/Tabbed/Tab';
7
6
  import { Banner } from '@components/Banner';
8
7
  import RelatedResources from '@shell/components/RelatedResources';
@@ -12,12 +11,13 @@ import { CATALOG } from '@shell/config/types';
12
11
  import { sortBy } from '@shell/utils/sort';
13
12
  import { allHash } from '@shell/utils/promise';
14
13
  import { mergeWithReplace } from '@shell/utils/object';
14
+ import ResourceTabs from '@shell/components/form/ResourceTabs/index.vue';
15
15
 
16
16
  export default {
17
17
  name: 'DetailRelease',
18
18
 
19
19
  components: {
20
- Markdown, Tabbed, Tab, Loading, YamlEditor, Banner, RelatedResources
20
+ Markdown, ResourceTabs, Tab, Loading, YamlEditor, Banner, RelatedResources
21
21
  },
22
22
 
23
23
  props: {
@@ -125,9 +125,12 @@ export default {
125
125
  {{ t('catalog.app.section.lastOperation') }}: ( {{ latestOperation.status.action }} ) - <a @click="latestOperation.openLogs()"> {{ t('catalog.app.section.openLogs') }}</a>
126
126
  </span>
127
127
 
128
- <Tabbed
128
+ <ResourceTabs
129
129
  class="mt-20"
130
130
  default-tab="resources"
131
+ :needConditions="false"
132
+ :needEvents="false"
133
+ :needRelated="false"
131
134
  @changed="tabChanged($event)"
132
135
  >
133
136
  <Tab
@@ -174,7 +177,7 @@ export default {
174
177
  >
175
178
  <Markdown v-model:value="value.spec.info.notes" />
176
179
  </Tab>
177
- </Tabbed>
180
+ </ResourceTabs>
178
181
  </div>
179
182
  </template>
180
183
 
@@ -1,5 +1,5 @@
1
1
  <script>
2
- import { FLEET, MANAGEMENT } from '@shell/config/types';
2
+ import { FLEET } from '@shell/config/types';
3
3
  import FleetResources from '@shell/components/fleet/FleetResources';
4
4
  import FleetUtils from '@shell/utils/fleet';
5
5
  import { checkSchemasForFindAllHash } from '@shell/utils/auth';
@@ -39,10 +39,6 @@ export default {
39
39
  }
40
40
  }, this.$store);
41
41
 
42
- if (this.value.authorId && this.$store.getters['management/schemaFor'](MANAGEMENT.USER)) {
43
- await this.$store.dispatch(`management/findAll`, { type: MANAGEMENT.USER }, { root: true });
44
- }
45
-
46
42
  this.allBundleDeployments = allDispatches.allBundleDeployments || [];
47
43
  },
48
44
 
@@ -38,6 +38,7 @@ export default {
38
38
  gitRepos: this.$store.dispatch('management/findAll', { type: FLEET.GIT_REPO }),
39
39
  helmOps: this.$store.dispatch('management/findAll', { type: FLEET.HELM_OP }),
40
40
  workspaces: this.$store.dispatch('management/findAll', { type: FLEET.WORKSPACE }),
41
+ clusterGroups: this.$store.dispatch('management/findAll', { type: FLEET.CLUSTER_GROUP }), // Needed for calculating targetClusters
41
42
  bundleDeployments: this.$store.dispatch('management/findAll', { type: FLEET.BUNDLE_DEPLOYMENT })
42
43
  });
43
44
 
@@ -67,8 +68,8 @@ export default {
67
68
  return [
68
69
  ...this.gitRepos,
69
70
  ...this.helmOps
70
- ].filter((x) => {
71
- return x.targetClusters.includes(this.value);
71
+ ].filter((resource) => {
72
+ return !!resource.targetClusters.find((c) => c.id === this.clusterId);
72
73
  });
73
74
  },
74
75