@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.
- package/assets/styles/base/_color.scss +4 -1
- package/assets/styles/global/_tooltip.scss +7 -4
- package/assets/styles/themes/_dark.scss +11 -0
- package/assets/styles/themes/_light.scss +13 -1
- package/assets/styles/themes/_modern.scss +22 -0
- package/assets/translations/en-us.yaml +147 -19
- package/assets/translations/zh-hans.yaml +0 -1
- package/chart/monitoring/grafana/index.vue +8 -2
- package/components/ActionMenuShell.vue +3 -1
- package/components/Cron/CronExpressionEditor.vue +299 -0
- package/components/Cron/CronExpressionEditorModal.vue +247 -0
- package/components/Cron/CronTooltip.vue +87 -0
- package/components/Cron/types.ts +13 -0
- package/components/ForceDirectedTreeChart/composable.ts +11 -0
- package/components/PodSecurityAdmission.vue +2 -0
- package/components/PromptModal.vue +1 -1
- package/components/Resource/Detail/Card/__tests__/StateCard.test.ts +1 -0
- package/components/Resource/Detail/CopyToClipboard.vue +78 -0
- package/components/Resource/Detail/FetchLoader/__tests__/composables.test.ts +69 -0
- package/components/Resource/Detail/FetchLoader/composables.ts +27 -0
- package/components/Resource/Detail/Metadata/Annotations/__tests__/index.test.ts +1 -1
- package/components/Resource/Detail/Metadata/Annotations/index.vue +1 -1
- package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +13 -61
- package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/index.test.ts +33 -6
- package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +24 -38
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +25 -5
- package/components/Resource/Detail/Metadata/KeyValue.vue +12 -23
- package/components/Resource/Detail/Metadata/KeyValueRow.vue +144 -0
- package/components/Resource/Detail/Metadata/Labels/__tests__/index.test.ts +1 -0
- package/components/Resource/Detail/Metadata/Labels/index.vue +1 -0
- package/components/Resource/Detail/Metadata/__tests__/KeyValue.test.ts +30 -32
- package/components/Resource/Detail/Metadata/__tests__/KeyValueRow.test.ts +108 -0
- package/components/Resource/Detail/Metadata/__tests__/composables.test.ts +0 -3
- package/components/Resource/Detail/Metadata/__tests__/index.test.ts +12 -5
- package/components/Resource/Detail/Metadata/composables.ts +1 -4
- package/components/Resource/Detail/Metadata/index.vue +1 -0
- package/components/Resource/Detail/Preview/Content.vue +63 -0
- package/components/Resource/Detail/Preview/Preview.vue +128 -0
- package/components/Resource/Detail/Preview/__tests__/Content.spec.ts +71 -0
- package/components/Resource/Detail/Preview/__tests__/Preview.spec.ts +121 -0
- package/components/Resource/Detail/ResourcePopover/ResourcePopoverCard.vue +141 -0
- package/components/Resource/Detail/ResourcePopover/__tests__/ResourcePopoverCard.test.ts +136 -0
- package/components/Resource/Detail/ResourcePopover/__tests__/index.test.ts +245 -0
- package/components/Resource/Detail/ResourcePopover/index.vue +226 -0
- package/components/Resource/Detail/SpacedRow.vue +1 -0
- package/components/Resource/Detail/TitleBar/__tests__/composables.test.ts +0 -5
- package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +1 -1
- package/components/Resource/Detail/TitleBar/composables.ts +1 -3
- package/components/Resource/Detail/TitleBar/index.vue +2 -29
- package/components/Resource/Detail/ViewOptions/composable.ts +9 -0
- package/components/Resource/Detail/ViewOptions/index.vue +41 -0
- package/components/Resource/Detail/__tests__/CopyToClipboard.spec.ts +82 -0
- package/components/ResourceDetail/Masthead/legacy.vue +0 -19
- package/components/ResourceDetail/index.vue +1 -26
- package/components/ResourceTable.vue +24 -0
- package/components/SortableTable/index.vue +7 -1
- package/components/SortableTable/paging.js +3 -0
- package/components/Tabbed/Tab.vue +43 -1
- package/components/Tabbed/index.vue +3 -1
- package/components/__tests__/Cron/CronExpressionEditor.test.ts +151 -0
- package/components/__tests__/Cron/CronExpressionEditorModal.test.ts +81 -0
- package/components/auth/login/saml.vue +86 -0
- package/components/form/LabeledSelect.vue +8 -8
- package/components/form/ProjectMemberEditor.vue +2 -0
- package/components/form/ResourceTabs/composable.ts +54 -0
- package/components/form/ResourceTabs/index.vue +10 -7
- package/components/form/Select.vue +13 -10
- package/components/form/__tests__/LabeledSelect.test.ts +133 -0
- package/components/form/__tests__/Select.test.ts +134 -0
- package/components/nav/Header.vue +6 -5
- package/composables/useExtensionManager.ts +17 -0
- package/config/home-links.js +12 -0
- package/config/labels-annotations.js +0 -1
- package/config/page-actions.js +0 -1
- package/config/product/explorer.js +3 -1
- package/config/product/fleet.js +2 -7
- package/config/product/manager.js +0 -5
- package/config/query-params.js +1 -0
- package/config/router/navigation-guards/clusters.js +2 -1
- package/config/router/navigation-guards/products.js +1 -1
- package/config/store.js +2 -0
- package/core/extension-manager-impl.js +518 -0
- package/core/plugins.js +35 -468
- package/core/types.ts +8 -2
- package/detail/__tests__/autoscaling.horizontalpodautoscaler.test.ts +1 -0
- package/detail/catalog.cattle.io.app.vue +7 -4
- package/detail/fleet.cattle.io.bundle.vue +1 -5
- package/detail/fleet.cattle.io.cluster.vue +3 -2
- package/detail/fleet.cattle.io.gitrepo.vue +76 -49
- package/detail/fleet.cattle.io.helmop.vue +78 -49
- package/dialog/AddonConfigConfirmationDialog.vue +1 -1
- package/dialog/GenericPrompt.vue +1 -1
- package/dialog/ImportDialog.vue +9 -2
- package/dialog/InstallExtensionDialog.vue +18 -10
- package/dialog/SloDialog.vue +1 -1
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +2 -1
- package/edit/__tests__/resources.cattle.io.restore.test.ts +106 -0
- package/edit/auth/oidc.vue +106 -6
- package/edit/auth/saml.vue +5 -5
- package/edit/cloudcredential.vue +31 -17
- package/edit/constraints.gatekeeper.sh.constraint/index.vue +10 -2
- package/edit/fleet.cattle.io.cluster.vue +19 -0
- package/edit/fleet.cattle.io.gitrepo.vue +23 -16
- package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +12 -11
- package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +11 -1
- package/edit/provisioning.cattle.io.cluster/index.vue +14 -19
- package/edit/provisioning.cattle.io.cluster/rke2.vue +11 -3
- package/edit/provisioning.cattle.io.cluster/tabs/AddOnAdditionalManifest.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/S3Config.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +2 -0
- package/edit/provisioning.cattle.io.cluster/tabs/upgrade/DrainOptions.vue +6 -0
- package/edit/resources.cattle.io.restore.vue +5 -8
- package/initialize/install-plugins.js +1 -3
- package/list/__tests__/workload.test.ts +1 -0
- package/list/workload.vue +8 -1
- package/machine-config/components/GCEImage.vue +6 -5
- package/machine-config/google.vue +11 -6
- package/mixins/__tests__/auth-config.test.ts +4 -6
- package/mixins/__tests__/chart.test.ts +139 -1
- package/mixins/auth-config.js +33 -10
- package/mixins/chart.js +58 -18
- package/models/__tests__/namespace.test.ts +69 -0
- package/models/apps.statefulset.js +8 -10
- package/models/chart.js +5 -1
- package/models/fleet-application.js +16 -46
- package/models/fleet.cattle.io.bundle.js +1 -38
- package/models/fleet.cattle.io.gitrepo.js +4 -0
- package/models/fleet.cattle.io.helmop.js +4 -0
- package/models/management.cattle.io.cluster.js +1 -1
- package/models/management.cattle.io.project.js +12 -0
- package/models/namespace.js +30 -0
- package/models/workload.js +4 -1
- package/package.json +10 -10
- package/pages/auth/login.vue +8 -3
- package/pages/auth/logout.vue +6 -5
- package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +26 -11
- package/pages/c/_cluster/apps/charts/chart.vue +29 -20
- package/pages/c/_cluster/apps/charts/index.vue +1 -0
- package/pages/c/_cluster/apps/charts/install.vue +6 -5
- package/pages/c/_cluster/explorer/tools/__tests__/index.test.ts +102 -12
- package/pages/c/_cluster/explorer/tools/index.vue +145 -254
- package/pages/c/_cluster/manager/cloudCredential/index.vue +18 -1
- package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +12 -2
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +1 -1
- package/pages/c/_cluster/uiplugins/__tests__/index.spec.ts +318 -0
- package/pages/c/_cluster/uiplugins/index.vue +221 -363
- package/pages/home.vue +1 -9
- package/plugins/axios.js +3 -2
- package/plugins/dashboard-store/resource-class.js +49 -0
- package/plugins/ember-cookie.js +7 -3
- package/plugins/steve/subscribe.js +4 -2
- package/public/index.html +2 -1
- package/rancher-components/Card/Card.vue +1 -1
- package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
- package/rancher-components/Form/Radio/RadioButton.vue +1 -1
- package/rancher-components/Form/Radio/RadioGroup.vue +1 -1
- package/rancher-components/LabeledTooltip/LabeledTooltip.vue +1 -11
- package/rancher-components/Pill/RcCounterBadge/RcCounterBadge.test.ts +53 -0
- package/rancher-components/Pill/RcCounterBadge/RcCounterBadge.vue +65 -0
- package/rancher-components/Pill/RcCounterBadge/index.ts +1 -0
- package/rancher-components/Pill/RcCounterBadge/types.ts +7 -0
- package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +1 -1
- package/rancher-components/Pill/RcStatusBadge/index.ts +1 -1
- package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +3 -3
- package/rancher-components/Pill/RcStatusIndicator/types.ts +1 -1
- package/rancher-components/Pill/RcTag/RcTag.test.ts +64 -0
- package/rancher-components/Pill/RcTag/RcTag.vue +94 -0
- package/rancher-components/Pill/RcTag/index.ts +1 -0
- package/rancher-components/Pill/RcTag/types.ts +9 -0
- package/rancher-components/Pill/types.ts +1 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +1 -0
- package/rancher-components/RcItemCard/RcItemCardAction.vue +12 -0
- package/scripts/test-plugins-build.sh +0 -1
- package/store/__tests__/catalog.test.ts +63 -0
- package/store/__tests__/cookies.test.ts +72 -0
- package/store/auth.js +33 -10
- package/store/catalog.js +2 -2
- package/store/cookies.ts +30 -0
- package/store/prefs.js +10 -5
- package/store/type-map.js +3 -15
- package/types/extension-manager.ts +26 -0
- package/types/shell/index.d.ts +123 -27
- package/utils/__tests__/product.test.ts +129 -0
- package/utils/__tests__/resource.test.ts +87 -0
- package/utils/alertmanagerconfig.js +2 -2
- package/utils/auth.js +4 -77
- package/utils/product.ts +39 -0
- package/utils/resource.ts +35 -0
- package/utils/select.js +0 -24
- package/utils/validators/formRules/__tests__/index.test.ts +3 -0
- package/utils/validators/formRules/index.ts +2 -1
- package/vue.config.js +1 -1
- package/components/Resource/Detail/Metadata/Rectangle.vue +0 -34
- package/components/Resource/Detail/Metadata/__tests__/Rectangle.test.ts +0 -24
- package/components/ResourceDetail/Masthead/__tests__/legacy.test.ts +0 -65
- package/utils/cookie-universal.js +0 -10
- /package/components/{ForceDirectedTreeChart.vue → ForceDirectedTreeChart/index.vue} +0 -0
package/core/plugins.js
CHANGED
|
@@ -1,471 +1,38 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
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
|
|
10
|
-
const
|
|
11
|
-
|
|
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
|
-
|
|
18
|
-
|
|
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
|
|
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
|
-
$
|
|
553
|
+
$extension: ExtensionManager,
|
|
548
554
|
/**
|
|
549
555
|
* Function to retrieve a localised string
|
|
550
556
|
*/
|
|
@@ -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,
|
|
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
|
-
<
|
|
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
|
-
</
|
|
180
|
+
</ResourceTabs>
|
|
178
181
|
</div>
|
|
179
182
|
</template>
|
|
180
183
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import { FLEET
|
|
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((
|
|
71
|
-
return
|
|
71
|
+
].filter((resource) => {
|
|
72
|
+
return !!resource.targetClusters.find((c) => c.id === this.clusterId);
|
|
72
73
|
});
|
|
73
74
|
},
|
|
74
75
|
|