@rancher/shell 0.1.3 → 0.1.21
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/brand/suse/dark/rancher-logo.svg +1 -148
- package/assets/brand/suse/favicon.png +0 -0
- package/assets/brand/suse/rancher-logo.svg +1 -130
- package/assets/images/featured/img1.jpg +0 -0
- package/assets/images/featured.jpg +0 -0
- package/assets/images/generic-plugin.svg +1 -0
- package/assets/styles/themes/_dark.scss +3 -0
- package/assets/styles/themes/_light.scss +3 -0
- package/assets/styles/themes/_suse.scss +1 -1
- package/assets/translations/en-us.yaml +219 -47
- package/assets/translations/zh-hans.yaml +21 -24
- package/components/AsyncButton.vue +17 -2
- package/components/ButtonDropdown.vue +4 -0
- package/components/Carousel.vue +291 -0
- package/components/CommunityLinks.vue +64 -22
- package/components/CruResource.vue +11 -3
- package/components/Dialog.vue +102 -0
- package/components/ExplorerMembers.vue +2 -4
- package/components/ExplorerProjectsNamespaces.vue +25 -9
- package/components/IconMessage.vue +9 -1
- package/components/LazyImage.vue +21 -8
- package/components/LocaleSelector.vue +62 -29
- package/components/PromptRemove.vue +2 -2
- package/components/ResourceList/Masthead.vue +21 -1
- package/components/ResourceList/ResourceLoadingIndicator.vue +0 -8
- package/components/ResourceList/index.vue +9 -23
- package/components/ResourceTable.vue +7 -2
- package/components/SimpleBox.vue +6 -4
- package/components/SortableTable/index.vue +18 -25
- package/components/Tabbed/Tab.vue +5 -0
- package/components/Tabbed/index.vue +54 -9
- package/components/TypeDescription.vue +10 -1
- package/components/auth/Principal.vue +1 -0
- package/components/fleet/FleetBundles.vue +8 -3
- package/components/fleet/FleetClusters.vue +6 -0
- package/components/fleet/FleetRepos.vue +7 -1
- package/components/fleet/FleetSummary.vue +6 -0
- package/components/form/Command.vue +5 -0
- package/components/form/EnvVars.vue +5 -0
- package/components/form/KeyValue.vue +80 -58
- package/components/form/NameNsDescription.vue +13 -5
- package/components/form/NodeScheduling.vue +6 -1
- package/components/form/PodAffinity.vue +5 -0
- package/components/form/ResourceTabs/index.vue +5 -1
- package/components/form/ServiceNameSelect.vue +5 -0
- package/components/form/ValueFromResource.vue +7 -1
- package/components/formatter/ClusterLink.vue +3 -7
- package/components/nav/NamespaceFilter.vue +3 -3
- package/components/nav/TopLevelMenu.vue +12 -29
- package/config/home-links.js +155 -0
- package/config/labels-annotations.js +2 -1
- package/config/private-label.js +1 -1
- package/config/product/explorer.js +5 -4
- package/config/product/legacy.js +0 -47
- package/config/product/manager.js +0 -2
- package/config/product/multi-cluster-apps.js +0 -12
- package/config/product/settings.js +12 -1
- package/config/product/uiplugins.js +17 -0
- package/config/settings.js +23 -2
- package/config/types.js +5 -1
- package/config/uiplugins.js +117 -0
- package/config/version.js +17 -0
- package/content/docs/en-us/getting-started.md +1 -26
- package/core/plugin.ts +12 -0
- package/core/plugins.js +38 -2
- package/core/types.ts +6 -0
- package/creators/app/{.eslintignore → files/.eslintignore} +0 -0
- package/creators/app/{.eslintrc.js → files/.eslintrc.js} +0 -0
- package/creators/app/{.vscode → files/.vscode}/settings.json +0 -0
- package/creators/app/{babel.config.js → files/babel.config.js} +0 -0
- package/creators/app/{nuxt.config.js → files/nuxt.config.js} +0 -0
- package/creators/app/{tsconfig.json → files/tsconfig.json} +2 -1
- package/creators/app/init +16 -17
- package/creators/app/package.json +6 -0
- package/creators/pkg/{babel.config.js → files/babel.config.js} +0 -0
- package/creators/pkg/{index.ts → files/index.ts} +0 -0
- package/creators/pkg/{tsconfig.json → files/tsconfig.json} +13 -12
- package/creators/pkg/{vue.config.js → files/vue.config.js} +0 -0
- package/creators/pkg/init +1 -1
- package/creators/update/init +54 -0
- package/creators/update/package.json +20 -0
- package/creators/update/upgrade +56 -0
- package/creators/update/yarn-error.log +54 -0
- package/detail/provisioning.cattle.io.cluster.vue +3 -3
- package/detail/workload/index.vue +3 -2
- package/dialog/DiagnosticTimingsDialog.vue +116 -0
- package/dialog/RotateCertificatesDialog.vue +9 -3
- package/edit/auth/azuread.vue +28 -9
- package/edit/networking.k8s.io.ingress/index.vue +2 -2
- package/edit/persistentvolume/index.vue +51 -13
- package/edit/persistentvolumeclaim.vue +31 -13
- package/edit/pod.vue +27 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +103 -24
- package/edit/service.vue +7 -5
- package/edit/workload/__tests__/Upgrading.test.ts +1 -0
- package/edit/workload/index.vue +32 -10
- package/edit/workload/mixins/workload.js +121 -126
- package/edit/workload/storage/ContainerMountPaths.vue +240 -0
- package/edit/workload/storage/Mount.vue +1 -0
- package/edit/workload/storage/awsElasticBlockStore.vue +20 -1
- package/edit/workload/storage/azureDisk.vue +22 -2
- package/edit/workload/storage/azureFile.vue +20 -2
- package/edit/workload/storage/csi/index.vue +23 -1
- package/edit/workload/storage/gcePersistentDisk.vue +20 -2
- package/edit/workload/storage/index.vue +33 -65
- package/edit/workload/storage/persistentVolumeClaim/index.vue +5 -0
- package/edit/workload/storage/secret.vue +6 -1
- package/edit/workload/storage/vsphereVolume.vue +11 -1
- package/layouts/default.vue +14 -8
- package/layouts/home.vue +9 -4
- package/layouts/plain.vue +10 -5
- package/list/catalog.cattle.io.app.vue +10 -9
- package/list/catalog.cattle.io.clusterrepo.vue +6 -61
- package/list/cis.cattle.io.clusterscan.vue +12 -12
- package/list/fleet.cattle.io.bundle.vue +33 -28
- package/list/fleet.cattle.io.cluster.vue +26 -22
- package/list/fleet.cattle.io.clustergroup.vue +6 -0
- package/list/fleet.cattle.io.clusterregistrationtoken.vue +28 -24
- package/list/fleet.cattle.io.gitrepo.vue +25 -14
- package/list/helm.cattle.io.projecthelmchart.vue +52 -33
- package/list/logging.banzaicloud.io.clusterflow.vue +7 -12
- package/list/logging.banzaicloud.io.flow.vue +7 -14
- package/list/management.cattle.io.cluster.vue +26 -15
- package/list/management.cattle.io.feature.vue +13 -8
- package/list/management.cattle.io.setting.vue +3 -3
- package/list/management.cattle.io.user.vue +38 -19
- package/list/monitoring.coreos.com.alertmanagerconfig.vue +8 -15
- package/list/namespace.vue +14 -1
- package/list/node.vue +13 -16
- package/list/persistentvolume.vue +16 -9
- package/list/persistentvolumeclaim.vue +5 -8
- package/list/provisioning.cattle.io.cluster.vue +35 -9
- package/list/service.vue +24 -12
- package/list/ui.cattle.io.navlink.vue +6 -0
- package/list/workload.vue +2 -2
- package/machine-config/harvester.vue +5 -3
- package/middleware/authenticated.js +6 -0
- package/mixins/resource-fetch.js +12 -18
- package/mixins/resource-manager.js +126 -0
- package/models/catalog.cattle.io.uiplugin.js +38 -0
- package/models/cluster/node.js +25 -2
- package/models/fleet.cattle.io.bundle.js +1 -1
- package/models/harvesterhci.io.management.cluster.js +11 -5
- package/models/pod.js +15 -5
- package/models/provisioning.cattle.io.cluster.js +16 -6
- package/models/workload.js +5 -3
- package/models/workload.service.js +10 -0
- package/nuxt.config.js +70 -25
- package/package.json +108 -109
- package/pages/auth/login.vue +11 -1
- package/pages/auth/verify.vue +9 -0
- package/pages/c/_cluster/apps/charts/index.vue +46 -1
- package/pages/c/_cluster/apps/charts/install.vue +10 -9
- package/pages/c/_cluster/explorer/index.vue +72 -9
- package/pages/c/_cluster/explorer/tools/index.vue +12 -5
- package/pages/c/_cluster/mcapps/index.vue +1 -1
- package/pages/c/_cluster/settings/DefaultLinksEditor.vue +108 -0
- package/pages/c/_cluster/settings/brand.vue +0 -40
- package/pages/c/_cluster/settings/links.vue +152 -0
- package/pages/c/_cluster/settings/performance.vue +90 -7
- package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +232 -0
- package/pages/c/_cluster/uiplugins/InstallDialog.vue +293 -0
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +300 -0
- package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +125 -0
- package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +261 -0
- package/pages/c/_cluster/uiplugins/UninstallDialog.vue +122 -0
- package/pages/c/_cluster/uiplugins/index.vue +808 -0
- package/pages/diagnostic.vue +185 -101
- package/pages/docs/_doc.vue +3 -1
- package/pages/home.vue +21 -56
- package/pages/prefs.vue +108 -88
- package/pages/safeMode.vue +17 -0
- package/pages/support/index.vue +34 -137
- package/pkg/dynamic-importer.lib.js +4 -0
- package/plugins/dashboard-store/actions.js +19 -0
- package/plugins/dashboard-store/getters.js +20 -3
- package/plugins/dashboard-store/mutations.js +13 -7
- package/plugins/dashboard-store/resource-class.js +2 -2
- package/plugins/formatters.js +15 -0
- package/plugins/plugin.js +61 -6
- package/plugins/steve/getters.js +12 -0
- package/plugins/steve/mutations.js +1 -1
- package/plugins/steve/subscribe.js +94 -72
- package/plugins/steve/web-worker.steve-sub-worker.js +24 -15
- package/plugins/version.js +21 -0
- package/promptRemove/management.cattle.io.globalrole.vue +47 -0
- package/promptRemove/management.cattle.io.roletemplate.vue +47 -0
- package/promptRemove/mixin/roleDeletionCheck.js +97 -0
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +6 -7
- package/rancher-components/components/BadgeState/BadgeState.spec.ts +12 -0
- package/rancher-components/components/BadgeState/BadgeState.vue +107 -0
- package/rancher-components/components/BadgeState/index.ts +1 -0
- package/rancher-components/components/Banner/Banner.test.ts +13 -0
- package/rancher-components/components/Banner/Banner.vue +163 -0
- package/rancher-components/components/Banner/index.ts +1 -0
- package/rancher-components/components/Card/Card.vue +150 -0
- package/rancher-components/components/Card/index.ts +1 -0
- package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +77 -0
- package/rancher-components/components/Form/Checkbox/Checkbox.vue +395 -0
- package/rancher-components/components/Form/Checkbox/index.ts +1 -0
- package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +29 -0
- package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +343 -0
- package/rancher-components/components/Form/LabeledInput/index.ts +1 -0
- package/rancher-components/components/Form/Radio/RadioButton.vue +270 -0
- package/rancher-components/components/Form/Radio/RadioGroup.vue +235 -0
- package/rancher-components/components/Form/Radio/index.ts +2 -0
- package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +168 -0
- package/rancher-components/components/Form/TextArea/index.ts +1 -0
- package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +107 -0
- package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +137 -0
- package/rancher-components/components/Form/ToggleSwitch/index.ts +1 -0
- package/rancher-components/components/Form/index.ts +5 -0
- package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +137 -0
- package/rancher-components/components/LabeledTooltip/index.ts +1 -0
- package/scripts/publish-shell.sh +40 -7
- package/scripts/record-deps.js +37 -0
- package/scripts/sync-shell-deps +37 -0
- package/scripts/test-plugins-build.sh +8 -5
- package/scripts/typegen.sh +84 -0
- package/store/auth.js +3 -0
- package/store/catalog.js +9 -8
- package/store/i18n.js +10 -1
- package/store/index.js +12 -3
- package/store/prefs.js +16 -0
- package/store/type-map.js +32 -5
- package/store/uiplugins.ts +15 -61
- package/types/shell/index.d.ts +3046 -0
- package/utils/__tests__/object.test.ts +0 -24
- package/utils/__tests__/selector.test.ts +1 -1
- package/utils/dynamic-importer.js +4 -0
- package/utils/favicon.js +8 -2
- package/utils/gc/gc-interval.ts +40 -0
- package/utils/gc/gc-root-store.js +76 -0
- package/utils/gc/gc-route-changed.ts +44 -0
- package/utils/gc/gc-types.ts +21 -0
- package/utils/gc/gc.ts +282 -0
- package/utils/grafana.js +2 -6
- package/utils/socket.js +41 -20
- package/utils/string.js +1 -7
- package/utils/validators/formRules/__tests__/index.test.ts +108 -0
- package/utils/validators/formRules/index.ts +9 -1
- package/config/footer.js +0 -19
- package/creators/pkg/nuxt.config.js +0 -6
- package/pages/plugins.vue +0 -387
- package/server/verdaccio-middleware.js +0 -56
|
@@ -3,18 +3,19 @@ import { addObject, addObjects, clear, removeObject } from '@shell/utils/array';
|
|
|
3
3
|
import { SCHEMA } from '@shell/config/types';
|
|
4
4
|
import { normalizeType } from '@shell/plugins/dashboard-store/normalize';
|
|
5
5
|
import { classify } from '@shell/plugins/dashboard-store/classify';
|
|
6
|
+
import garbageCollect from '@shell/utils/gc/gc';
|
|
6
7
|
|
|
7
8
|
function registerType(state, type) {
|
|
8
9
|
let cache = state.types[type];
|
|
9
10
|
|
|
10
11
|
if ( !cache ) {
|
|
11
12
|
cache = {
|
|
12
|
-
list:
|
|
13
|
-
haveAll:
|
|
14
|
-
haveSelector:
|
|
15
|
-
revision:
|
|
16
|
-
generation:
|
|
17
|
-
loadCounter:
|
|
13
|
+
list: [],
|
|
14
|
+
haveAll: false,
|
|
15
|
+
haveSelector: {},
|
|
16
|
+
revision: 0, // The highest known resourceVersion from the server for this type
|
|
17
|
+
generation: 0, // Updated every time something is loaded for this type
|
|
18
|
+
loadCounter: 0, // Used to cancel incremental loads if the page changes during load
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
// Not enumerable so they don't get sent back to the client for SSR
|
|
@@ -120,6 +121,8 @@ export function forgetType(state, type) {
|
|
|
120
121
|
cache.map.clear();
|
|
121
122
|
delete state.types[type];
|
|
122
123
|
|
|
124
|
+
garbageCollect.gcResetType(state, type);
|
|
125
|
+
|
|
123
126
|
return true;
|
|
124
127
|
}
|
|
125
128
|
}
|
|
@@ -131,6 +134,8 @@ export function resetStore(state, commit) {
|
|
|
131
134
|
for ( const type of Object.keys(state.types) ) {
|
|
132
135
|
commit(`${ state.config.namespace }/forgetType`, type);
|
|
133
136
|
}
|
|
137
|
+
|
|
138
|
+
garbageCollect.gcResetStore(state);
|
|
134
139
|
}
|
|
135
140
|
|
|
136
141
|
export function remove(state, obj, getters) {
|
|
@@ -308,5 +313,6 @@ export default {
|
|
|
308
313
|
if (typeData) {
|
|
309
314
|
typeData.loadCounter++;
|
|
310
315
|
}
|
|
311
|
-
}
|
|
316
|
+
},
|
|
317
|
+
|
|
312
318
|
};
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
AS,
|
|
10
10
|
MODE
|
|
11
11
|
} from '@shell/config/query-params';
|
|
12
|
-
import {
|
|
12
|
+
import { VIEW_IN_API } from '@shell/store/prefs';
|
|
13
13
|
import { addObject, addObjects, findBy, removeAt } from '@shell/utils/array';
|
|
14
14
|
import CustomValidators from '@shell/utils/custom-validators';
|
|
15
15
|
import { downloadFile, generateZip } from '@shell/utils/download';
|
|
@@ -966,7 +966,7 @@ export default class Resource {
|
|
|
966
966
|
}
|
|
967
967
|
|
|
968
968
|
get canViewInApi() {
|
|
969
|
-
return this.hasLink('self') && this.$rootGetters['prefs/get'](
|
|
969
|
+
return this.hasLink('self') && this.$rootGetters['prefs/get'](VIEW_IN_API);
|
|
970
970
|
}
|
|
971
971
|
|
|
972
972
|
get canYaml() {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// This registers all of the built-in formatters into the SortableTable cache
|
|
2
|
+
|
|
3
|
+
// We do it here to keep it away from plugins
|
|
4
|
+
// It was in SortableTable itself, but this causes plugins to pull in all formatters and their dependencies
|
|
5
|
+
|
|
6
|
+
import { FORMATTERS } from '@shell/components/SortableTable';
|
|
7
|
+
|
|
8
|
+
const components = require.context('@shell/components/formatter', false, /[A-Z]\w+\.(vue)$/);
|
|
9
|
+
|
|
10
|
+
components.keys().forEach((fileName) => {
|
|
11
|
+
const componentConfig = components(fileName);
|
|
12
|
+
const componentName = fileName.split('/').pop().split('.')[0];
|
|
13
|
+
|
|
14
|
+
FORMATTERS[componentName] = componentConfig.default || componentConfig;
|
|
15
|
+
});
|
package/plugins/plugin.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
// This plugin loads any
|
|
2
|
-
|
|
3
|
-
import {
|
|
1
|
+
// This plugin loads any UI Plugins at app load time
|
|
2
|
+
import { allHashSettled } from '@shell/utils/promise';
|
|
3
|
+
import { shouldNotLoadPlugin, UI_PLUGIN_BASE_URL } from '@shell/config/uiplugins';
|
|
4
4
|
|
|
5
5
|
const META_NAME_PREFIX = 'app-autoload-';
|
|
6
6
|
|
|
7
|
-
export default async(context)
|
|
7
|
+
export default async function(context) {
|
|
8
|
+
// UI Plugins declared in the HTML head
|
|
8
9
|
const meta = context.app?.head?.meta || [];
|
|
9
10
|
const hash = {};
|
|
10
11
|
|
|
@@ -18,5 +19,59 @@ export default async(context) => {
|
|
|
18
19
|
}
|
|
19
20
|
});
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
// Provide a mechanism to load the UI without the plugins loaded - in case there is a problem
|
|
23
|
+
let loadPlugins = true;
|
|
24
|
+
|
|
25
|
+
if (context.route?.path.endsWith('/safeMode')) {
|
|
26
|
+
loadPlugins = false;
|
|
27
|
+
console.warn('Safe Mode - plugins will not be loaded'); // eslint-disable-line no-console
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (loadPlugins) {
|
|
31
|
+
// TODO: Get rancher version using the new API (can't use setting as we have not loading the store)
|
|
32
|
+
const rancherVersion = undefined;
|
|
33
|
+
|
|
34
|
+
// Fetch list of installed plugins from endpoint
|
|
35
|
+
try {
|
|
36
|
+
const res = await context.store.dispatch('management/request', {
|
|
37
|
+
url: `${ UI_PLUGIN_BASE_URL }/index.json`,
|
|
38
|
+
method: 'GET',
|
|
39
|
+
headers: { accept: 'application/json' },
|
|
40
|
+
redirectUnauthorized: false,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (res) {
|
|
44
|
+
const entries = res.entries || res.Entries || {};
|
|
45
|
+
|
|
46
|
+
Object.values(entries).forEach((plugin) => {
|
|
47
|
+
const shouldNotLoad = shouldNotLoadPlugin(plugin, rancherVersion); // Error key string or false
|
|
48
|
+
|
|
49
|
+
if (!shouldNotLoad) {
|
|
50
|
+
hash[plugin.name] = context.$plugin.loadPluginAsync(plugin);
|
|
51
|
+
} else {
|
|
52
|
+
context.store.dispatch('uiplugins/setError', { name: plugin.name, error: shouldNotLoad });
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
} catch (e) {
|
|
57
|
+
console.error('Could not load UI Plugin list', e); // eslint-disable-line no-console
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Load all of the plugins
|
|
61
|
+
const pluginLoads = await allHashSettled(hash);
|
|
62
|
+
|
|
63
|
+
// Some pluigns may have failed to load - store this
|
|
64
|
+
Object.keys(pluginLoads).forEach((name) => {
|
|
65
|
+
const res = pluginLoads[name];
|
|
66
|
+
|
|
67
|
+
if (res?.status === 'rejected') {
|
|
68
|
+
console.error(`Failed to load plugin: ${ name }`); // eslint-disable-line no-console
|
|
69
|
+
|
|
70
|
+
// Record error in the uiplugins store, so that we can show this to the user
|
|
71
|
+
context.store.dispatch('uiplugins/setError', { name, error: 'plugins.error.load' });
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return true;
|
|
77
|
+
}
|
package/plugins/steve/getters.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isArray } from '@shell/utils/array';
|
|
2
2
|
import { BY_TYPE } from '@shell/plugins/dashboard-store/classify';
|
|
3
3
|
import { lookup } from '@shell/plugins/dashboard-store/model-loader';
|
|
4
|
+
import { NAMESPACE, SCHEMA, COUNT, UI } from '@shell/config/types';
|
|
4
5
|
|
|
5
6
|
import SteveModel from './steve-class';
|
|
6
7
|
import HybridModel, { cleanHybridResources } from './hybrid-class';
|
|
@@ -12,6 +13,13 @@ export const STEVE_MODEL_TYPES = {
|
|
|
12
13
|
BY_TYPE: 'byType'
|
|
13
14
|
};
|
|
14
15
|
|
|
16
|
+
const GC_IGNORE_TYPES = {
|
|
17
|
+
[COUNT]: true,
|
|
18
|
+
[NAMESPACE]: true,
|
|
19
|
+
[SCHEMA]: true,
|
|
20
|
+
[UI.NAV_LINK]: true,
|
|
21
|
+
};
|
|
22
|
+
|
|
15
23
|
export default {
|
|
16
24
|
urlOptions: () => (url, opt) => {
|
|
17
25
|
opt = opt || {};
|
|
@@ -110,4 +118,8 @@ export default {
|
|
|
110
118
|
return map?.list || [];
|
|
111
119
|
},
|
|
112
120
|
|
|
121
|
+
gcIgnoreTypes: () => {
|
|
122
|
+
return GC_IGNORE_TYPES;
|
|
123
|
+
}
|
|
124
|
+
|
|
113
125
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { addObject, clear, removeObject } from '@shell/utils/array';
|
|
2
2
|
import { get } from '@shell/utils/object';
|
|
3
|
-
import { COUNT,
|
|
4
|
-
import {
|
|
3
|
+
import { COUNT, SCHEMA } from '@shell/config/types';
|
|
4
|
+
import { getPerformanceSetting } from '@shell/config/settings';
|
|
5
5
|
import Socket, {
|
|
6
6
|
EVENT_CONNECTED,
|
|
7
7
|
EVENT_DISCONNECTED,
|
|
@@ -16,8 +16,7 @@ import { DATE_FORMAT, TIME_FORMAT } from '@shell/store/prefs';
|
|
|
16
16
|
import { escapeHtml } from '@shell/utils/string';
|
|
17
17
|
|
|
18
18
|
// eslint-disable-next-line
|
|
19
|
-
import
|
|
20
|
-
import * as Comlink from 'comlink';
|
|
19
|
+
import webworker from './web-worker.steve-sub-worker.js';
|
|
21
20
|
|
|
22
21
|
export const NO_WATCH = 'NO_WATCH';
|
|
23
22
|
export const NO_SCHEMA = 'NO_SCHEMA';
|
|
@@ -25,9 +24,6 @@ export const NO_SCHEMA = 'NO_SCHEMA';
|
|
|
25
24
|
// minimum length of time a disconnect notification is shown
|
|
26
25
|
const MINIMUM_TIME_NOTIFIED = 3000;
|
|
27
26
|
|
|
28
|
-
// minimum time a socket must be disconnected for before sending a growl
|
|
29
|
-
const MINIMUM_TIME_DISCONNECTED = 10000;
|
|
30
|
-
|
|
31
27
|
// We only create a worker for the cluster store
|
|
32
28
|
export function createWorker(store, ctx) {
|
|
33
29
|
const { getters } = ctx;
|
|
@@ -39,16 +35,33 @@ export function createWorker(store, ctx) {
|
|
|
39
35
|
return;
|
|
40
36
|
}
|
|
41
37
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
const workerActions = {
|
|
39
|
+
load: (resource) => {
|
|
40
|
+
queueChange(ctx, resource, true, 'Change');
|
|
41
|
+
},
|
|
42
|
+
destroyWorker: () => {
|
|
43
|
+
if (store.$workers) {
|
|
44
|
+
delete store.$workers[storeName];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
45
48
|
|
|
46
49
|
if (!store.$workers[storeName]) {
|
|
47
|
-
const worker =
|
|
50
|
+
const worker = new webworker();
|
|
48
51
|
|
|
49
52
|
store.$workers[storeName] = worker;
|
|
50
53
|
|
|
51
|
-
worker.initWorker
|
|
54
|
+
worker.postMessage({ initWorker: { storeName } });
|
|
55
|
+
|
|
56
|
+
store.$workers[storeName].onmessage = (e) => {
|
|
57
|
+
/* on the off chance there's more than key in the message, we handle them in the order that they "keys" method provides which is
|
|
58
|
+
// good enough for now considering that we never send more than one message action at a time right now */
|
|
59
|
+
const messageActions = Object.keys(e?.data);
|
|
60
|
+
|
|
61
|
+
messageActions.forEach((action) => {
|
|
62
|
+
workerActions[action](e?.data[action]);
|
|
63
|
+
});
|
|
64
|
+
};
|
|
52
65
|
}
|
|
53
66
|
}
|
|
54
67
|
|
|
@@ -119,6 +132,10 @@ function queueChange({ getters, state }, { data, revision }, load, label) {
|
|
|
119
132
|
}
|
|
120
133
|
}
|
|
121
134
|
|
|
135
|
+
function growlsDisabled(rootGetters) {
|
|
136
|
+
return getPerformanceSetting(rootGetters)?.disableWebsocketNotification;
|
|
137
|
+
}
|
|
138
|
+
|
|
122
139
|
export const actions = {
|
|
123
140
|
subscribe(ctx, opt) {
|
|
124
141
|
const {
|
|
@@ -145,7 +162,9 @@ export const actions = {
|
|
|
145
162
|
socket.setAutoReconnect(true);
|
|
146
163
|
socket.setUrl(url);
|
|
147
164
|
} else {
|
|
148
|
-
|
|
165
|
+
const maxTries = growlsDisabled(rootGetters) ? null : 3;
|
|
166
|
+
|
|
167
|
+
socket = new Socket(`${ state.config.baseUrl }/subscribe`, true, null, null, maxTries);
|
|
149
168
|
|
|
150
169
|
commit('setSocket', socket);
|
|
151
170
|
socket.addEventListener(EVENT_CONNECTED, (e) => {
|
|
@@ -177,24 +196,17 @@ export const actions = {
|
|
|
177
196
|
});
|
|
178
197
|
}
|
|
179
198
|
|
|
180
|
-
socket.connect(get(opt, 'metadata'));
|
|
199
|
+
socket.connect(get(opt, 'metadata') );
|
|
181
200
|
},
|
|
182
201
|
|
|
183
|
-
unsubscribe({
|
|
202
|
+
unsubscribe({ commit, getters, state }) {
|
|
184
203
|
const socket = state.socket;
|
|
185
204
|
const worker = (this.$workers || {})[getters.storeName];
|
|
186
205
|
|
|
187
206
|
commit('setWantSocket', false);
|
|
188
207
|
|
|
189
208
|
if (worker) {
|
|
190
|
-
|
|
191
|
-
worker.destroyWorker();
|
|
192
|
-
worker[Comlink.releaseProxy]();
|
|
193
|
-
} catch (e) {
|
|
194
|
-
console.error(e); // eslint-disable-line no-console
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
delete this.$workers[getters.storeName];
|
|
209
|
+
worker.postMessage({ destroyWorker: true }); // we're only passing the boolean here because the key needs to be something truthy to ensure it's passed on the object.
|
|
198
210
|
}
|
|
199
211
|
|
|
200
212
|
if ( socket ) {
|
|
@@ -396,8 +408,10 @@ export const actions = {
|
|
|
396
408
|
commit, dispatch, state, getters, rootGetters
|
|
397
409
|
}, event) {
|
|
398
410
|
state.debugSocket && console.info(`WebSocket Opened [${ getters.storeName }]`); // eslint-disable-line no-console
|
|
399
|
-
|
|
400
411
|
const socket = event.currentTarget;
|
|
412
|
+
const tries = event?.detail?.tries; // have to pull it off of the event because the socket's tries is already reset to 0
|
|
413
|
+
const t = rootGetters['i18n/t'];
|
|
414
|
+
const disableGrowl = growlsDisabled(rootGetters);
|
|
401
415
|
|
|
402
416
|
this.$socket = socket;
|
|
403
417
|
|
|
@@ -420,19 +434,16 @@ export const actions = {
|
|
|
420
434
|
if ( socket.hasReconnected ) {
|
|
421
435
|
await dispatch('reconnectWatches');
|
|
422
436
|
// Check for disconnect notifications and clear them
|
|
423
|
-
const growlErr = rootGetters['growl/find']({ key: 'url', val:
|
|
437
|
+
const growlErr = rootGetters['growl/find']({ key: 'url', val: socket.url });
|
|
424
438
|
|
|
425
439
|
if (growlErr) {
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
dispatch('growl/remove', growlErr.id, { root: true });
|
|
434
|
-
}, growlErr.earliestClose - now);
|
|
435
|
-
}
|
|
440
|
+
dispatch('growl/remove', growlErr.id, { root: true });
|
|
441
|
+
}
|
|
442
|
+
if (tries > 1 && !disableGrowl) {
|
|
443
|
+
dispatch('growl/success', {
|
|
444
|
+
title: t('growl.reconnected.title'),
|
|
445
|
+
message: t('growl.reconnected.message', { url: this.$socket.url, tries }),
|
|
446
|
+
}, { root: true });
|
|
436
447
|
}
|
|
437
448
|
}
|
|
438
449
|
|
|
@@ -456,42 +467,53 @@ export const actions = {
|
|
|
456
467
|
}, e) {
|
|
457
468
|
clearTimeout(state.queueTimer);
|
|
458
469
|
state.queueTimer = null;
|
|
459
|
-
if (e.type === EVENT_DISCONNECT_ERROR) {
|
|
460
|
-
// determine if websocket notifications are disabled
|
|
461
|
-
const perfSetting = rootGetters['management/byId'](MANAGEMENT.SETTING, SETTING.UI_PERFORMANCE);
|
|
462
|
-
let disableGrowl = false;
|
|
463
470
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
}
|
|
471
|
+
// determine if websocket notifications are disabled
|
|
472
|
+
const disableGrowl = growlsDisabled(rootGetters);
|
|
467
473
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
dispatch('growl/
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
url
|
|
489
|
-
}, {
|
|
490
|
-
|
|
474
|
+
if (!disableGrowl) {
|
|
475
|
+
const dateFormat = escapeHtml( rootGetters['prefs/get'](DATE_FORMAT));
|
|
476
|
+
const timeFormat = escapeHtml( rootGetters['prefs/get'](TIME_FORMAT));
|
|
477
|
+
const time = e?.srcElement?.disconnectedAt || Date.now();
|
|
478
|
+
|
|
479
|
+
const timeFormatted = `${ day(time).format(`${ dateFormat } ${ timeFormat }`) }`;
|
|
480
|
+
const url = e?.srcElement?.url;
|
|
481
|
+
const tries = state?.socket?.tries;
|
|
482
|
+
|
|
483
|
+
const t = rootGetters['i18n/t'];
|
|
484
|
+
|
|
485
|
+
const growlErr = rootGetters['growl/find']({ key: 'url', val: url });
|
|
486
|
+
|
|
487
|
+
if (e.type === EVENT_CONNECT_ERROR) { // if this occurs, then we're at least retrying to connect
|
|
488
|
+
if (growlErr) {
|
|
489
|
+
dispatch('growl/remove', growlErr.id, { root: true });
|
|
490
|
+
}
|
|
491
|
+
dispatch('growl/error', {
|
|
492
|
+
title: t('growl.connectError.title'),
|
|
493
|
+
message: t('growl.connectError.message', {
|
|
494
|
+
url, time: timeFormatted, tries
|
|
495
|
+
}, { raw: true }),
|
|
496
|
+
icon: 'error',
|
|
497
|
+
earliestClose: time + MINIMUM_TIME_NOTIFIED,
|
|
498
|
+
url
|
|
499
|
+
}, { root: true });
|
|
500
|
+
} else if (e.type === EVENT_DISCONNECT_ERROR) { // if this occurs, we've given up on trying to reconnect
|
|
501
|
+
if (growlErr) {
|
|
502
|
+
dispatch('growl/remove', growlErr.id, { root: true });
|
|
503
|
+
}
|
|
504
|
+
dispatch('growl/error', {
|
|
505
|
+
title: t('growl.disconnectError.title'),
|
|
506
|
+
message: t('growl.disconnectError.message', {
|
|
507
|
+
url, time: timeFormatted, tries
|
|
508
|
+
}, { raw: true }),
|
|
509
|
+
icon: 'error',
|
|
510
|
+
earliestClose: time + MINIMUM_TIME_NOTIFIED,
|
|
511
|
+
url
|
|
512
|
+
}, { root: true });
|
|
513
|
+
} else {
|
|
514
|
+
// if the error is not a connect error or disconnect error, the socket never worked: log whether the current browser is safari
|
|
515
|
+
console.error(`WebSocket Connection Error [${ getters.storeName }]`, e.detail); // eslint-disable-line no-console
|
|
491
516
|
}
|
|
492
|
-
} else {
|
|
493
|
-
// if the error is not a disconnect error, the socket never worked: log whether the current browser is safari
|
|
494
|
-
console.error(`WebSocket Connection Error [${ getters.storeName }]`, e.detail); // eslint-disable-line no-console
|
|
495
517
|
}
|
|
496
518
|
},
|
|
497
519
|
|
|
@@ -583,7 +605,7 @@ export const actions = {
|
|
|
583
605
|
const worker = (this.$workers || {})[ctx.getters.storeName];
|
|
584
606
|
|
|
585
607
|
if (worker) {
|
|
586
|
-
worker.countsUpdate
|
|
608
|
+
worker.postMessage({ countsUpdate: msg });
|
|
587
609
|
|
|
588
610
|
// No further processing - let the web worker debounce the counts
|
|
589
611
|
return;
|
|
@@ -596,7 +618,7 @@ export const actions = {
|
|
|
596
618
|
const worker = (this.$workers || {})[ctx.getters.storeName];
|
|
597
619
|
|
|
598
620
|
if (worker) {
|
|
599
|
-
worker.updateSchema
|
|
621
|
+
worker.postMessage({ updateSchema: data });
|
|
600
622
|
|
|
601
623
|
// No further processing - let the web worker check the schema updates
|
|
602
624
|
return;
|
|
@@ -631,7 +653,7 @@ export const actions = {
|
|
|
631
653
|
const worker = (this.$workers || {})[ctx.getters.storeName];
|
|
632
654
|
|
|
633
655
|
if (worker) {
|
|
634
|
-
worker.removeSchema
|
|
656
|
+
worker.postMessage({ removeSchema: data.id });
|
|
635
657
|
}
|
|
636
658
|
}
|
|
637
659
|
|
|
@@ -712,7 +734,7 @@ export const mutations = {
|
|
|
712
734
|
clear(state.started);
|
|
713
735
|
clear(state.pendingFrames);
|
|
714
736
|
clear(state.queue);
|
|
715
|
-
|
|
737
|
+
clearTimeout(state.queueTimer);
|
|
716
738
|
state.deferredRequests = {};
|
|
717
739
|
state.queueTimer = null;
|
|
718
740
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import * as Comlink from 'comlink';
|
|
2
1
|
import { SCHEMA } from '@shell/config/types';
|
|
3
2
|
|
|
4
3
|
const COUNTS_FLUSH_TIMEOUT = 5000;
|
|
@@ -6,7 +5,6 @@ const SCHEMA_FLUSH_TIMEOUT = 2500;
|
|
|
6
5
|
|
|
7
6
|
const state = {
|
|
8
7
|
store: '', // Store name
|
|
9
|
-
load: undefined, // Load callback to load a resource into the store
|
|
10
8
|
counts: [], // Buffer of count resources recieved in a given window
|
|
11
9
|
countTimer: undefined, // Tiemr to flush the count buffer
|
|
12
10
|
flushTimer: undefined, // Timer to flush the schema chaneg queue
|
|
@@ -61,22 +59,33 @@ state.flushTimer = setTimeout(flush, SCHEMA_FLUSH_TIMEOUT);
|
|
|
61
59
|
|
|
62
60
|
// Callback to the store's load function (in the main thread) to process a load
|
|
63
61
|
function load(data) {
|
|
64
|
-
|
|
65
|
-
state.load(data);
|
|
66
|
-
}
|
|
62
|
+
self.postMessage({ load: data });
|
|
67
63
|
}
|
|
68
64
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
const workerActions = {
|
|
66
|
+
onmessage: (e) => {
|
|
67
|
+
/* on the off chance there's more than key in the message, we handle them in the order that they "keys" method provides which is
|
|
68
|
+
// good enough for now considering that we never send more than one message action at a time right now */
|
|
69
|
+
const messageActions = Object.keys(e?.data);
|
|
70
|
+
|
|
71
|
+
messageActions.forEach((action) => {
|
|
72
|
+
if (workerActions[action]) {
|
|
73
|
+
workerActions[action](e?.data[action]);
|
|
74
|
+
} else {
|
|
75
|
+
console.warn('no associated action for:', action); // eslint-disable-line no-console
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
initWorker: ({ storeName }) => {
|
|
72
80
|
state.store = storeName;
|
|
73
|
-
state.load = loadFn;
|
|
74
81
|
},
|
|
75
82
|
|
|
76
|
-
destroyWorker() {
|
|
83
|
+
destroyWorker: () => {
|
|
77
84
|
clearTimeout(state.countTimer);
|
|
78
85
|
clearTimeout(state.flushTimer);
|
|
79
86
|
|
|
87
|
+
self.postMessage({ destroyWorker: true }); // we're only passing the boolean here because the key needs to be something truthy to ensure it's passed on the object.
|
|
88
|
+
|
|
80
89
|
// Web worker global function to terminate the web worker
|
|
81
90
|
close();
|
|
82
91
|
},
|
|
@@ -98,7 +107,7 @@ const fns = {
|
|
|
98
107
|
},
|
|
99
108
|
|
|
100
109
|
// Called to load schema
|
|
101
|
-
|
|
110
|
+
loadSchemas: (schemas) => {
|
|
102
111
|
schemas.forEach((schema) => {
|
|
103
112
|
// These properties are added to the object, but aren't on the raw object, so remove them
|
|
104
113
|
// otherwise our comparison will show changes when there aren't any
|
|
@@ -107,16 +116,17 @@ const fns = {
|
|
|
107
116
|
|
|
108
117
|
state.schemas[schema.id] = hashObj(schema);
|
|
109
118
|
});
|
|
119
|
+
// console.log(JSON.parse(JSON.stringify(state.resources.schemas)));
|
|
110
120
|
},
|
|
111
121
|
|
|
112
122
|
// Called when schema is updated
|
|
113
|
-
updateSchema(schema) {
|
|
123
|
+
updateSchema: (schema) => {
|
|
114
124
|
// Add the schema to the queue to be checked to see if the schema really changed
|
|
115
125
|
state.queue.push(schema);
|
|
116
126
|
},
|
|
117
127
|
|
|
118
128
|
// Remove the cached schema
|
|
119
|
-
removeSchema(id) {
|
|
129
|
+
removeSchema: (id) => {
|
|
120
130
|
// Remove anything in the queue related to the schema - we don't want to send any pending updates later for a schema that has been removed
|
|
121
131
|
state.queue = state.queue.filter(schema => schema.id !== id);
|
|
122
132
|
|
|
@@ -125,5 +135,4 @@ const fns = {
|
|
|
125
135
|
}
|
|
126
136
|
};
|
|
127
137
|
|
|
128
|
-
//
|
|
129
|
-
Comlink.expose(fns);
|
|
138
|
+
onmessage = workerActions.onmessage; // bind everything to the worker's onmessage handler via the workerAction
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch version metadata from backend /rancherversion API and store it
|
|
3
|
+
*
|
|
4
|
+
* This metadata does not change for an installation of Rancher
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { setVersionData } from '@shell/config/version';
|
|
8
|
+
|
|
9
|
+
export default async function({ store }) {
|
|
10
|
+
try {
|
|
11
|
+
const response = await store.dispatch('rancher/request', {
|
|
12
|
+
url: '/rancherversion',
|
|
13
|
+
method: 'get',
|
|
14
|
+
redirectUnauthorized: false
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
setVersionData(response);
|
|
18
|
+
} catch (e) {
|
|
19
|
+
console.warn('Failed to fetch Rancher version metadata', e); // eslint-disable-line no-console
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import RoleDeletionCheck from '@shell/promptRemove/mixin/roleDeletionCheck';
|
|
3
|
+
export default {
|
|
4
|
+
name: 'GlobalRolePromptRemove',
|
|
5
|
+
mixins: [RoleDeletionCheck],
|
|
6
|
+
props: {
|
|
7
|
+
value: {
|
|
8
|
+
type: Array,
|
|
9
|
+
default: () => {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
type: {
|
|
15
|
+
type: String,
|
|
16
|
+
required: true
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<div>
|
|
24
|
+
<template>
|
|
25
|
+
{{ t('promptRemove.attemptingToRemove', { type }) }} <span
|
|
26
|
+
v-html="resourceNames(names, plusMore, t)"
|
|
27
|
+
></span>
|
|
28
|
+
</template>
|
|
29
|
+
<div v-if="info" class="text info mb-10 mt-20">
|
|
30
|
+
<span v-html="info" />
|
|
31
|
+
</div>
|
|
32
|
+
<div v-if="warning" class="text-warning mb-10 mt-20">
|
|
33
|
+
{{ warning }}
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<style lang="scss" scoped>
|
|
39
|
+
.text.info {
|
|
40
|
+
display: flex;
|
|
41
|
+
align-items: center;
|
|
42
|
+
|
|
43
|
+
> span {
|
|
44
|
+
margin-right: 5px;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
</style>
|