@rancher/shell 0.3.8 → 0.3.10
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/translations/en-us.yaml +47 -26
- package/assets/translations/zh-hans.yaml +82 -16
- package/babel.config.js +17 -4
- package/chart/istio.vue +11 -11
- package/chart/rancher-backup/S3.vue +1 -1
- package/components/AsyncButton.vue +2 -2
- package/components/ButtonGroup.vue +1 -1
- package/components/CodeMirror.vue +146 -14
- package/components/CompoundStatusBadge.vue +1 -1
- package/components/ContainerResourceLimit.vue +14 -1
- package/components/CopyCode.vue +1 -1
- package/components/CruResource.vue +21 -5
- package/components/DetailTop.vue +1 -1
- package/components/ExplorerProjectsNamespaces.vue +8 -4
- package/components/GlobalRoleBindings.vue +1 -1
- package/components/GroupPanel.vue +57 -0
- package/components/HarvesterServiceAddOnConfig.vue +2 -117
- package/components/ResourceDetail/Masthead.vue +1 -1
- package/components/ResourceList/Masthead.vue +0 -6
- package/components/ResourceList/ResourceLoadingIndicator.vue +1 -9
- package/components/ResourceList/index.vue +7 -6
- package/components/ResourceTable.vue +13 -3
- package/components/SortableTable/THead.vue +3 -3
- package/components/SortableTable/index.vue +3 -3
- package/components/Tabbed/Tab.vue +1 -1
- package/components/Tabbed/index.vue +1 -1
- package/components/Wizard.vue +9 -6
- package/components/YamlEditor.vue +2 -2
- package/components/__tests__/NamespaceFilter.test.ts +26 -7
- package/components/auth/RoleDetailEdit.vue +1 -1
- package/components/auth/SelectPrincipal.vue +1 -1
- package/components/fleet/FleetRepos.vue +1 -1
- package/components/form/ArrayList.vue +2 -2
- package/components/form/KeyValue.vue +37 -3
- package/components/form/Labels.vue +34 -14
- package/components/form/MatchExpressions.vue +120 -21
- package/components/form/Members/ClusterPermissionsEditor.vue +1 -1
- package/components/form/NameNsDescription.vue +1 -1
- package/components/form/NodeAffinity.vue +54 -4
- package/components/form/PlusMinus.vue +2 -2
- package/components/form/PodAffinity.vue +160 -47
- package/components/form/Probe.vue +1 -1
- package/components/form/ProjectMemberEditor.vue +8 -4
- package/components/form/ResourceQuota/NamespaceRow.vue +1 -1
- package/components/form/ServicePorts.vue +2 -2
- package/components/form/Tolerations.vue +70 -7
- package/components/form/WorkloadPorts.vue +2 -1
- package/components/form/__tests__/ArrayList.test.ts +3 -3
- package/components/form/__tests__/KeyValue.test.ts +17 -0
- package/components/form/__tests__/MatchExpressions.test.ts +1 -1
- package/components/formatter/ClusterLink.vue +3 -3
- package/components/formatter/LiveDate.vue +1 -1
- package/components/formatter/PodImages.vue +1 -1
- package/components/formatter/RKETemplateName.vue +1 -1
- package/components/formatter/Shortened.vue +1 -1
- package/components/nav/Header.vue +9 -7
- package/components/nav/NamespaceFilter.vue +103 -54
- package/config/labels-annotations.js +8 -5
- package/config/settings.ts +8 -6
- package/config/types.js +6 -4
- package/core/plugin-routes.ts +26 -7
- package/detail/provisioning.cattle.io.cluster.vue +4 -4
- package/edit/cis.cattle.io.clusterscan.vue +1 -1
- package/edit/configmap.vue +33 -6
- package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +19 -149
- package/edit/logging-flow/index.vue +2 -2
- package/edit/logging.banzaicloud.io.output/providers/elasticsearch.vue +12 -0
- package/edit/logging.banzaicloud.io.output/providers/opensearch.vue +12 -0
- package/edit/management.cattle.io.project.vue +7 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +1 -1
- package/edit/monitoring.coreos.com.alertmanagerconfig/routeConfig.vue +2 -2
- package/edit/monitoring.coreos.com.prometheusrule/GroupRules.vue +11 -8
- package/edit/networking.k8s.io.networkpolicy/PolicyRule.vue +2 -2
- package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +12 -4
- package/edit/networking.k8s.io.networkpolicy/__tests__/PolicyRuleTarget.spec.ts +140 -0
- package/edit/networking.k8s.io.networkpolicy/__tests__/utils/mock.json +158 -0
- package/edit/networking.k8s.io.networkpolicy/__tests__/utils/selectors.ts +45 -0
- package/edit/networking.k8s.io.networkpolicy/index.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/AgentConfiguration.vue +326 -0
- package/edit/provisioning.cattle.io.cluster/MachinePool.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/RegistryMirrors.vue +2 -2
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +143 -169
- package/edit/provisioning.cattle.io.cluster/index.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +75 -6
- package/edit/resources.cattle.io.restore.vue +2 -2
- package/edit/service.vue +22 -3
- package/edit/storage.k8s.io.storageclass/index.vue +1 -1
- package/edit/workload/Job.vue +2 -2
- package/edit/workload/index.vue +1 -1
- package/edit/workload/mixins/workload.js +7 -1
- package/edit/workload/storage/__tests__/Storage.test.ts +84 -5
- package/initialize/index.js +1 -0
- package/layouts/default.vue +1 -1
- package/mixins/chart.js +1 -1
- package/mixins/resource-fetch-namespaced.js +19 -27
- package/mixins/resource-fetch.js +0 -5
- package/models/__tests__/namespace.test.ts +125 -0
- package/models/batch.cronjob.js +18 -3
- package/models/management.cattle.io.project.js +6 -1
- package/models/persistentvolume.js +1 -1
- package/models/workload.js +1 -1
- package/models/workload.service.js +22 -7
- package/package.json +17 -6
- package/pages/auth/login.vue +47 -49
- package/pages/c/_cluster/apps/charts/chart.vue +1 -1
- package/pages/c/_cluster/apps/charts/install.vue +42 -51
- package/pages/c/_cluster/explorer/index.vue +1 -1
- package/pages/c/_cluster/monitoring/index.vue +1 -1
- package/pages/c/_cluster/settings/performance.vue +53 -18
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +1 -1
- package/pages/c/_cluster/uiplugins/index.vue +16 -5
- package/pages/home.vue +1 -1
- package/pages/prefs.vue +18 -2
- package/plugins/clean-html-directive.js +1 -1
- package/plugins/clean-tooltip-directive.js +33 -0
- package/plugins/codemirror.js +158 -0
- package/plugins/dashboard-store/actions.js +4 -2
- package/plugins/dashboard-store/getters.js +6 -0
- package/plugins/dashboard-store/mutations.js +2 -2
- package/plugins/plugin.js +6 -1
- package/plugins/steve/actions.js +1 -1
- package/plugins/steve/getters.js +14 -3
- package/plugins/steve/resourceWatcher.js +36 -62
- package/plugins/steve/subscribe.js +137 -21
- package/plugins/steve/worker/index.js +7 -1
- package/plugins/steve/worker/web-worker.advanced.js +26 -8
- package/plugins/steve/worker/web-worker.basic.js +23 -4
- package/public/index.html +1 -1
- package/rancher-components/components/Form/Checkbox/Checkbox.vue +2 -2
- package/rancher-components/components/Form/Radio/RadioGroup.vue +2 -2
- package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +1 -1
- package/store/index.js +16 -61
- package/store/store-types.js +5 -0
- package/store/type-map.js +1 -1
- package/types/shell/index.d.ts +42 -7
- package/utils/__tests__/create-yaml.test.ts +63 -0
- package/utils/array.ts +4 -0
- package/utils/create-yaml.js +105 -8
- package/utils/namespace-filter.js +17 -5
- package/utils/projectAndNamespaceFiltering.utils.ts +62 -0
- package/utils/selector.js +6 -5
- package/utils/settings.ts +17 -7
- package/vue.config.js +2 -2
- package/models/k8s.cni.cncf.io.networkattachmentdefinition.js +0 -93
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
import { addObject, clear, removeObject } from '@shell/utils/array';
|
|
11
11
|
import { get } from '@shell/utils/object';
|
|
12
|
-
import { SCHEMA } from '@shell/config/types';
|
|
12
|
+
import { SCHEMA, MANAGEMENT } from '@shell/config/types';
|
|
13
|
+
import { SETTING } from '@shell/config/settings';
|
|
13
14
|
import { CSRF } from '@shell/config/cookies';
|
|
14
15
|
import { getPerformanceSetting } from '@shell/utils/settings';
|
|
15
16
|
import Socket, {
|
|
@@ -29,16 +30,25 @@ import { DATE_FORMAT, TIME_FORMAT } from '@shell/store/prefs';
|
|
|
29
30
|
import { escapeHtml } from '@shell/utils/string';
|
|
30
31
|
import { keyForSubscribe } from '@shell/plugins/steve/resourceWatcher';
|
|
31
32
|
import { waitFor } from '@shell/utils/async';
|
|
33
|
+
import { WORKER_MODES } from './worker';
|
|
34
|
+
import pAndNFiltering from '@shell/utils/projectAndNamespaceFiltering.utils';
|
|
32
35
|
|
|
33
36
|
import { BLANK_CLUSTER } from '@shell/store/index.js';
|
|
37
|
+
import { STORE } from '@shell/store/store-types';
|
|
34
38
|
|
|
35
39
|
// minimum length of time a disconnect notification is shown
|
|
36
40
|
const MINIMUM_TIME_NOTIFIED = 3000;
|
|
37
41
|
|
|
38
|
-
const
|
|
39
|
-
const managementReady = () => store.state?.managementReady;
|
|
42
|
+
const workerQueues = {};
|
|
40
43
|
|
|
41
|
-
|
|
44
|
+
const supportedStores = [STORE.CLUSTER, STORE.RANCHER, STORE.MANAGEMENT];
|
|
45
|
+
|
|
46
|
+
const waitForSettingsSchema = (store) => {
|
|
47
|
+
return waitFor(() => !!store.getters['management/byId'](SCHEMA, MANAGEMENT.SETTING));
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const waitForSettings = (store) => {
|
|
51
|
+
return waitFor(() => !!store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.UI_PERFORMANCE));
|
|
42
52
|
};
|
|
43
53
|
|
|
44
54
|
const isAdvancedWorker = (ctx) => {
|
|
@@ -46,7 +56,7 @@ const isAdvancedWorker = (ctx) => {
|
|
|
46
56
|
const storeName = getters.storeName;
|
|
47
57
|
const clusterId = rootGetters.clusterId;
|
|
48
58
|
|
|
49
|
-
if (storeName
|
|
59
|
+
if (!supportedStores.includes(storeName) || (clusterId === BLANK_CLUSTER && storeName === STORE.CLUSTER)) {
|
|
50
60
|
return false;
|
|
51
61
|
}
|
|
52
62
|
|
|
@@ -55,19 +65,33 @@ const isAdvancedWorker = (ctx) => {
|
|
|
55
65
|
return perfSetting?.advancedWorker.enabled;
|
|
56
66
|
};
|
|
57
67
|
|
|
58
|
-
// We only create a worker for the cluster store
|
|
59
68
|
export async function createWorker(store, ctx) {
|
|
60
69
|
const { getters, dispatch } = ctx;
|
|
61
70
|
const storeName = getters.storeName;
|
|
62
71
|
|
|
63
72
|
store.$workers = store.$workers || {};
|
|
64
73
|
|
|
65
|
-
if (storeName
|
|
74
|
+
if (!supportedStores.includes(storeName)) {
|
|
66
75
|
return;
|
|
67
76
|
}
|
|
68
77
|
|
|
69
|
-
|
|
70
|
-
|
|
78
|
+
if (!store.$workers[storeName]) {
|
|
79
|
+
// we know we need a worker at this point but we don't know which one so we're creating a mock interface
|
|
80
|
+
// it will simply queue up any messages for the real worker to process when it loads up
|
|
81
|
+
store.$workers[storeName] = {
|
|
82
|
+
postMessage: (msg) => {
|
|
83
|
+
if (workerQueues[storeName]) {
|
|
84
|
+
workerQueues[storeName].push(msg);
|
|
85
|
+
} else {
|
|
86
|
+
workerQueues[storeName] = [msg];
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
mode: WORKER_MODES.WAITING
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
await waitForSettingsSchema(store);
|
|
94
|
+
await waitForSettings(store);
|
|
71
95
|
const advancedWorker = isAdvancedWorker(ctx);
|
|
72
96
|
|
|
73
97
|
const workerActions = {
|
|
@@ -81,21 +105,30 @@ export async function createWorker(store, ctx) {
|
|
|
81
105
|
}
|
|
82
106
|
},
|
|
83
107
|
batchChanges: (batch) => {
|
|
84
|
-
dispatch('batchChanges', batch);
|
|
108
|
+
dispatch('batchChanges', namespaceHandler.validateBatchChange(ctx, batch));
|
|
85
109
|
},
|
|
86
110
|
dispatch: (msg) => {
|
|
87
111
|
dispatch(`ws.${ msg.name }`, msg);
|
|
88
112
|
},
|
|
113
|
+
redispatch: (msg) => {
|
|
114
|
+
/**
|
|
115
|
+
* because we had to queue up some messages prior to loading the worker:
|
|
116
|
+
* the basic worker will need to redispatch some of the queued messages back to the UI thread
|
|
117
|
+
*/
|
|
118
|
+
Object.entries(msg).forEach(([action, params]) => {
|
|
119
|
+
dispatch(action, params);
|
|
120
|
+
});
|
|
121
|
+
},
|
|
89
122
|
[EVENT_CONNECT_ERROR]: (e) => {
|
|
90
123
|
dispatch('error', e );
|
|
91
124
|
},
|
|
92
125
|
[EVENT_DISCONNECT_ERROR]: (e) => {
|
|
93
126
|
dispatch('error', e );
|
|
94
|
-
}
|
|
127
|
+
},
|
|
95
128
|
};
|
|
96
129
|
|
|
97
|
-
if (!store.$workers[storeName]) {
|
|
98
|
-
const workerMode = advancedWorker ?
|
|
130
|
+
if (!store.$workers[storeName] || store.$workers[storeName].mode === WORKER_MODES.WAITING) {
|
|
131
|
+
const workerMode = advancedWorker ? WORKER_MODES.ADVANCED : WORKER_MODES.BASIC;
|
|
99
132
|
const worker = store.steveCreateWorker(workerMode);
|
|
100
133
|
|
|
101
134
|
store.$workers[storeName] = worker;
|
|
@@ -115,6 +148,12 @@ export async function createWorker(store, ctx) {
|
|
|
115
148
|
});
|
|
116
149
|
};
|
|
117
150
|
}
|
|
151
|
+
|
|
152
|
+
while (workerQueues[storeName]?.length) {
|
|
153
|
+
const message = workerQueues[storeName].shift();
|
|
154
|
+
|
|
155
|
+
store.$workers[storeName].postMessage(message);
|
|
156
|
+
}
|
|
118
157
|
}
|
|
119
158
|
|
|
120
159
|
export function equivalentWatch(a, b) {
|
|
@@ -140,7 +179,67 @@ export function equivalentWatch(a, b) {
|
|
|
140
179
|
return true;
|
|
141
180
|
}
|
|
142
181
|
|
|
143
|
-
|
|
182
|
+
/**
|
|
183
|
+
* Sockets will not be able to subscribe to more than one namespace. If this is requested we pretend to handle it
|
|
184
|
+
* - Changes to all resources are monitored (no namespace provided in sub)
|
|
185
|
+
* - We ignore any events not from a required namespace (we have the conversion of project --> namespaces already)
|
|
186
|
+
*/
|
|
187
|
+
const namespaceHandler = {
|
|
188
|
+
/**
|
|
189
|
+
* Note - namespace can be a list of projects or namespaces
|
|
190
|
+
*/
|
|
191
|
+
subscribeNamespace: (namespace) => {
|
|
192
|
+
if (pAndNFiltering.isApplicable({ namespaced: namespace }) && namespace.length) {
|
|
193
|
+
return undefined; // AKA sub to everything
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return namespace;
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
validChange: ({ getters, rootGetters }, type, data) => {
|
|
200
|
+
const haveNamespace = getters.haveNamespace(type);
|
|
201
|
+
|
|
202
|
+
if (haveNamespace?.length) {
|
|
203
|
+
const namespaces = rootGetters.activeNamespaceCache;
|
|
204
|
+
|
|
205
|
+
if (!namespaces[data.metadata.namespace]) {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return true;
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
validateBatchChange: ({ getters, rootGetters }, batch) => {
|
|
214
|
+
const namespaces = rootGetters.activeNamespaceCache;
|
|
215
|
+
|
|
216
|
+
Object.entries(batch).forEach(([type, entries]) => {
|
|
217
|
+
const haveNamespace = getters.haveNamespace(type);
|
|
218
|
+
|
|
219
|
+
if (!haveNamespace?.length) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const schema = getters.schemaFor(type);
|
|
224
|
+
|
|
225
|
+
if (!schema?.attributes?.namespaced) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
Object.keys(entries).forEach((id) => {
|
|
230
|
+
const namespace = id.split('/')[0];
|
|
231
|
+
|
|
232
|
+
if (!namespace || !namespaces[namespace]) {
|
|
233
|
+
delete entries[id];
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
return batch;
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
function queueChange({ getters, state, rootGetters }, { data, revision }, load, label) {
|
|
144
243
|
const type = getters.normalizeType(data.type);
|
|
145
244
|
|
|
146
245
|
const entry = getters.typeEntry(type);
|
|
@@ -153,6 +252,10 @@ function queueChange({ getters, state }, { data, revision }, load, label) {
|
|
|
153
252
|
|
|
154
253
|
// console.log(`${ label } Event [${ state.config.namespace }]`, data.type, data.id); // eslint-disable-line no-console
|
|
155
254
|
|
|
255
|
+
if (!namespaceHandler.validChange({ getters, rootGetters }, type, data)) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
156
259
|
if ( load ) {
|
|
157
260
|
state.queue.push({
|
|
158
261
|
action: 'dispatch',
|
|
@@ -212,7 +315,7 @@ const sharedActions = {
|
|
|
212
315
|
|
|
213
316
|
const url = `${ state.config.baseUrl }/subscribe`;
|
|
214
317
|
const maxTries = growlsDisabled(rootGetters) ? null : 3;
|
|
215
|
-
const
|
|
318
|
+
const metadata = get(opt, 'metadata');
|
|
216
319
|
|
|
217
320
|
if (isAdvancedWorker(ctx)) {
|
|
218
321
|
if (!this.$workers[getters.storeName]) {
|
|
@@ -222,7 +325,7 @@ const sharedActions = {
|
|
|
222
325
|
// if the worker is in advanced mode then it'll contain it's own socket which it calls a 'watcher'
|
|
223
326
|
this.$workers[getters.storeName].postMessage({
|
|
224
327
|
createWatcher: {
|
|
225
|
-
|
|
328
|
+
metadata,
|
|
226
329
|
url: `${ state.config.baseUrl }/subscribe`,
|
|
227
330
|
csrf: this.$cookies.get(CSRF, { parseJSON: false }),
|
|
228
331
|
maxTries
|
|
@@ -231,7 +334,7 @@ const sharedActions = {
|
|
|
231
334
|
} else if ( socket ) {
|
|
232
335
|
socket.setAutoReconnect(true);
|
|
233
336
|
socket.setUrl(url);
|
|
234
|
-
socket.connect(
|
|
337
|
+
socket.connect(metadata);
|
|
235
338
|
} else {
|
|
236
339
|
socket = new Socket(`${ state.config.baseUrl }/subscribe`, true, null, null, maxTries);
|
|
237
340
|
|
|
@@ -263,7 +366,7 @@ const sharedActions = {
|
|
|
263
366
|
}
|
|
264
367
|
}
|
|
265
368
|
});
|
|
266
|
-
socket.connect(
|
|
369
|
+
socket.connect(metadata);
|
|
267
370
|
}
|
|
268
371
|
},
|
|
269
372
|
|
|
@@ -297,6 +400,7 @@ const sharedActions = {
|
|
|
297
400
|
type, selector, id, revision, namespace, stop, force
|
|
298
401
|
} = params;
|
|
299
402
|
|
|
403
|
+
namespace = namespaceHandler.subscribeNamespace(namespace);
|
|
300
404
|
type = getters.normalizeType(type);
|
|
301
405
|
|
|
302
406
|
if (rootGetters['type-map/isSpoofed'](type)) {
|
|
@@ -356,7 +460,7 @@ const sharedActions = {
|
|
|
356
460
|
|
|
357
461
|
const worker = this.$workers?.[getters.storeName] || {};
|
|
358
462
|
|
|
359
|
-
if (worker.mode ===
|
|
463
|
+
if (worker.mode === WORKER_MODES.ADVANCED || worker.mode === WORKER_MODES.WAITING) {
|
|
360
464
|
if ( force ) {
|
|
361
465
|
msg.force = true;
|
|
362
466
|
}
|
|
@@ -375,6 +479,8 @@ const sharedActions = {
|
|
|
375
479
|
const { commit, getters, dispatch } = ctx;
|
|
376
480
|
|
|
377
481
|
if (getters['schemaFor'](type)) {
|
|
482
|
+
namespace = namespaceHandler.subscribeNamespace(namespace);
|
|
483
|
+
|
|
378
484
|
const obj = {
|
|
379
485
|
type,
|
|
380
486
|
id,
|
|
@@ -760,8 +866,18 @@ const defaultActions = {
|
|
|
760
866
|
}
|
|
761
867
|
|
|
762
868
|
// If we're trying to watch this event, attempt to re-watch
|
|
763
|
-
|
|
764
|
-
|
|
869
|
+
//
|
|
870
|
+
// To make life easier in the advanced worker `resource.stop` --> `watch` is handled here (basically for access to getters.nextResourceVersion)
|
|
871
|
+
// This means the concept of resource sub watch state needs massaging
|
|
872
|
+
const advancedWorker = msg.advancedWorker;
|
|
873
|
+
const localState = !advancedWorker;
|
|
874
|
+
const watchStarted = localState ? getters['watchStarted'](obj) : advancedWorker;
|
|
875
|
+
|
|
876
|
+
if ( getters['schemaFor'](type) && watchStarted) {
|
|
877
|
+
if (localState) {
|
|
878
|
+
commit('setWatchStopped', obj);
|
|
879
|
+
}
|
|
880
|
+
|
|
765
881
|
dispatch('watch', obj);
|
|
766
882
|
}
|
|
767
883
|
},
|
|
@@ -3,10 +3,16 @@ import basicWorkerConstructor from '@shell/plugins/steve/worker/web-worker.basic
|
|
|
3
3
|
// eslint-disable-next-line no-unused-vars
|
|
4
4
|
import advancedWorkerConstructor from '@shell/plugins/steve/worker/web-worker.advanced.js';
|
|
5
5
|
|
|
6
|
+
export const WORKER_MODES = {
|
|
7
|
+
WAITING: 'waiting',
|
|
8
|
+
BASIC: 'basic',
|
|
9
|
+
ADVANCED: 'advanced'
|
|
10
|
+
};
|
|
11
|
+
|
|
6
12
|
export default function storeWorker(mode, options = {}, closures = {}) {
|
|
7
13
|
let worker;
|
|
8
14
|
|
|
9
|
-
if (mode ===
|
|
15
|
+
if (mode === WORKER_MODES.ADVANCED) {
|
|
10
16
|
worker = new advancedWorkerConstructor();
|
|
11
17
|
} else {
|
|
12
18
|
worker = new basicWorkerConstructor();
|
|
@@ -93,12 +93,12 @@ const workerActions = {
|
|
|
93
93
|
}
|
|
94
94
|
caches[SCHEMA].load(collection);
|
|
95
95
|
},
|
|
96
|
-
createWatcher: (
|
|
97
|
-
trace('createWatcher',
|
|
96
|
+
createWatcher: (opt) => {
|
|
97
|
+
trace('createWatcher', opt);
|
|
98
98
|
|
|
99
99
|
const {
|
|
100
|
-
|
|
101
|
-
} =
|
|
100
|
+
metadata, maxTries, url, csrf
|
|
101
|
+
} = opt;
|
|
102
102
|
|
|
103
103
|
if (!state.watcher) {
|
|
104
104
|
state.watcher = new ResourceWatcher(url, true, null, null, maxTries, csrf);
|
|
@@ -119,6 +119,10 @@ const workerActions = {
|
|
|
119
119
|
}
|
|
120
120
|
});
|
|
121
121
|
|
|
122
|
+
state.watcher.addEventListener('resync', (e) => {
|
|
123
|
+
self.postMessage({ redispatch: { resyncWatch: e.detail.data } });
|
|
124
|
+
});
|
|
125
|
+
|
|
122
126
|
state.watcher.addEventListener(EVENT_CONNECT_ERROR, (e) => {
|
|
123
127
|
handleConnectionError(EVENT_CONNECT_ERROR, e, state.watcher);
|
|
124
128
|
});
|
|
@@ -129,7 +133,7 @@ const workerActions = {
|
|
|
129
133
|
|
|
130
134
|
state.watcher.setDebug(state.debugWorker);
|
|
131
135
|
|
|
132
|
-
state.watcher.connect(
|
|
136
|
+
state.watcher.connect(metadata);
|
|
133
137
|
|
|
134
138
|
// Flush the workerQueue
|
|
135
139
|
while (state.workerQueue.length > 0) {
|
|
@@ -183,7 +187,8 @@ const workerActions = {
|
|
|
183
187
|
resourceType,
|
|
184
188
|
id,
|
|
185
189
|
namespace,
|
|
186
|
-
selector
|
|
190
|
+
selector,
|
|
191
|
+
force: msg.force,
|
|
187
192
|
};
|
|
188
193
|
|
|
189
194
|
state.watcher.watch(watchKey, resourceVersion, resourceVersionTime, watchObject, skipResourceVersion);
|
|
@@ -270,10 +275,23 @@ const resourceWatcherActions = {
|
|
|
270
275
|
}
|
|
271
276
|
},
|
|
272
277
|
'resource.stop': (msg) => {
|
|
273
|
-
|
|
278
|
+
trace('resource.stop', msg);
|
|
279
|
+
|
|
280
|
+
// State is handled in the resourceWatcher....
|
|
274
281
|
const watchKey = watchKeyFromMessage(msg);
|
|
275
282
|
|
|
276
283
|
removeFromWorkerQueue(watchKey);
|
|
284
|
+
|
|
285
|
+
// ... however we still want to bubble out to UI thread
|
|
286
|
+
// We'll save some hassle and ignore any resource.stop bubble if we're in error. the only thing that will clear that is a resync
|
|
287
|
+
if (!state.watcher?.watches[watchKey]?.error) {
|
|
288
|
+
// See comment in resourceWatcher 'resource.stop' handler, until we can resolve the resourceVersion within the resourceWatcher
|
|
289
|
+
// internally, we'll want to bubble this out to the UI thread. When that's resolved this won't be needed
|
|
290
|
+
resourceWatcherActions.dispatch({
|
|
291
|
+
...msg,
|
|
292
|
+
advancedWorker: true,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
277
295
|
},
|
|
278
296
|
'resource.error': (msg) => {
|
|
279
297
|
// State is handled in the resourceWatcher, no need to bubble out to UI thread
|
|
@@ -287,7 +305,7 @@ const resourceWatcherActions = {
|
|
|
287
305
|
/**
|
|
288
306
|
* Covers message from UI Thread to Worker
|
|
289
307
|
*/
|
|
290
|
-
onmessage = (e) => {
|
|
308
|
+
self.onmessage = (e) => {
|
|
291
309
|
/* 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
|
|
292
310
|
// good enough for now considering that we never send more than one message action at a time right now */
|
|
293
311
|
const messageActions = Object.keys(e?.data);
|
|
@@ -6,7 +6,7 @@ const SCHEMA_FLUSH_TIMEOUT = 2500;
|
|
|
6
6
|
|
|
7
7
|
const state = {
|
|
8
8
|
store: '', // Store name
|
|
9
|
-
flushTimer: undefined, // Timer to flush the schema
|
|
9
|
+
flushTimer: undefined, // Timer to flush the schema change queue
|
|
10
10
|
queue: [], // Schema change queue
|
|
11
11
|
schemas: {} // Map of schema id to hash to track when a schema actually changes
|
|
12
12
|
};
|
|
@@ -42,6 +42,25 @@ function load(data) {
|
|
|
42
42
|
self.postMessage({ load: data });
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
// used for dispatching a function in the worker, primarily for redirecting messages intended for the advanced worker back to the UI thread
|
|
46
|
+
function redispatch(msg) {
|
|
47
|
+
self.postMessage({ redispatch: msg });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* These actions aren't applicable to the basic worker, so bounce back to ui thread
|
|
52
|
+
*
|
|
53
|
+
* These are called when a queue of actions is flushed. Queue is populated from requests made before we know if worker is basic or advanced.
|
|
54
|
+
*/
|
|
55
|
+
const advancedWorkerActions = {
|
|
56
|
+
watch: (msg) => {
|
|
57
|
+
redispatch({ send: msg });
|
|
58
|
+
},
|
|
59
|
+
createWatcher: (msg) => {
|
|
60
|
+
redispatch({ subscribe: msg });
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
45
64
|
const workerActions = {
|
|
46
65
|
onmessage: (e) => {
|
|
47
66
|
/* 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
|
|
@@ -75,7 +94,6 @@ const workerActions = {
|
|
|
75
94
|
|
|
76
95
|
state.schemas[schema.id] = hashObj(schema);
|
|
77
96
|
});
|
|
78
|
-
// console.log(JSON.parse(JSON.stringify(state.resources.schemas)));
|
|
79
97
|
},
|
|
80
98
|
|
|
81
99
|
// Called when schema is updated
|
|
@@ -91,7 +109,8 @@ const workerActions = {
|
|
|
91
109
|
|
|
92
110
|
// Delete the schema from the map, so if it comes back we don't ignore it if the hash is the same
|
|
93
111
|
delete state.schemas[id];
|
|
94
|
-
}
|
|
112
|
+
},
|
|
113
|
+
...advancedWorkerActions
|
|
95
114
|
};
|
|
96
115
|
|
|
97
|
-
onmessage = workerActions.onmessage; // bind everything to the worker's onmessage handler via the workerAction
|
|
116
|
+
self.onmessage = workerActions.onmessage; // bind everything to the worker's onmessage handler via the workerAction
|
package/public/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta charset="utf-8">
|
|
6
6
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
7
7
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
8
|
-
<link rel="shortcut icon" type="image/x-icon" href="/
|
|
8
|
+
<link rel="shortcut icon" type="image/x-icon" href="/favicon.png">
|
|
9
9
|
<title>Rancher</title>
|
|
10
10
|
</head>
|
|
11
11
|
|
|
@@ -251,12 +251,12 @@ export default Vue.extend({
|
|
|
251
251
|
<template v-else-if="label">{{ label }}</template>
|
|
252
252
|
<i
|
|
253
253
|
v-if="tooltipKey"
|
|
254
|
-
v-tooltip="t(tooltipKey)"
|
|
254
|
+
v-clean-tooltip="t(tooltipKey)"
|
|
255
255
|
class="checkbox-info icon icon-info icon-lg"
|
|
256
256
|
/>
|
|
257
257
|
<i
|
|
258
258
|
v-else-if="tooltip"
|
|
259
|
-
v-tooltip="tooltip"
|
|
259
|
+
v-clean-tooltip="tooltip"
|
|
260
260
|
class="checkbox-info icon icon-info icon-lg"
|
|
261
261
|
/>
|
|
262
262
|
</slot>
|
|
@@ -184,12 +184,12 @@ export default Vue.extend({
|
|
|
184
184
|
</template>
|
|
185
185
|
<i
|
|
186
186
|
v-if="tooltipKey"
|
|
187
|
-
v-tooltip="t(tooltipKey)"
|
|
187
|
+
v-clean-tooltip="t(tooltipKey)"
|
|
188
188
|
class="icon icon-info icon-lg"
|
|
189
189
|
/>
|
|
190
190
|
<i
|
|
191
191
|
v-else-if="tooltip"
|
|
192
|
-
v-tooltip="tooltip"
|
|
192
|
+
v-clean-tooltip="tooltip"
|
|
193
193
|
class="icon icon-info icon-lg"
|
|
194
194
|
/>
|
|
195
195
|
</h3>
|
|
@@ -44,7 +44,7 @@ export default Vue.extend({
|
|
|
44
44
|
>
|
|
45
45
|
<template v-if="hover">
|
|
46
46
|
<i
|
|
47
|
-
v-tooltip="value.content ? { ...{content: value.content, classes: [`tooltip-${status}`]}, ...value } : value"
|
|
47
|
+
v-clean-tooltip="value.content ? { ...{content: value.content, classes: [`tooltip-${status}`]}, ...value } : value"
|
|
48
48
|
:class="{'hover':!value, [iconClass]: true}"
|
|
49
49
|
class="icon status-icon"
|
|
50
50
|
/>
|
package/store/index.js
CHANGED
|
@@ -27,11 +27,13 @@ import {
|
|
|
27
27
|
NAMESPACE_FILTER_NAMESPACED_PREFIX as NAMESPACED_PREFIX,
|
|
28
28
|
NAMESPACE_FILTER_NAMESPACED_YES as NAMESPACED_YES,
|
|
29
29
|
splitNamespaceFilterKey,
|
|
30
|
+
NAMESPACE_FILTER_NS_FULL_PREFIX,
|
|
30
31
|
} from '@shell/utils/namespace-filter';
|
|
31
32
|
import { allHash, allHashSettled } from '@shell/utils/promise';
|
|
32
33
|
import { sortBy } from '@shell/utils/sort';
|
|
33
34
|
import { addParam } from '@shell/utils/url';
|
|
34
35
|
import semver from 'semver';
|
|
36
|
+
import { STORE } from '@shell/store/store-types';
|
|
35
37
|
|
|
36
38
|
// Disables strict mode for all store instances to prevent warning about changing state outside of mutations
|
|
37
39
|
// because it's more efficient to do that sometimes.
|
|
@@ -41,19 +43,19 @@ export const BLANK_CLUSTER = '_';
|
|
|
41
43
|
|
|
42
44
|
export const plugins = [
|
|
43
45
|
Steve({
|
|
44
|
-
namespace:
|
|
46
|
+
namespace: STORE.MANAGEMENT,
|
|
45
47
|
baseUrl: '/v1',
|
|
46
48
|
modelBaseClass: BY_TYPE,
|
|
47
49
|
supportsStream: false, // true, -- Disabled due to report that it's sometimes much slower in Chrome
|
|
48
50
|
}),
|
|
49
51
|
Steve({
|
|
50
|
-
namespace:
|
|
52
|
+
namespace: STORE.CLUSTER,
|
|
51
53
|
baseUrl: '', // URL is dynamically set for the selected cluster
|
|
52
54
|
supportsStream: false, // true, -- Disabled due to report that it's sometimes much slower in Chrome
|
|
53
55
|
supportsGc: true, // Enable garbage collection for this store only
|
|
54
56
|
}),
|
|
55
57
|
Steve({
|
|
56
|
-
namespace:
|
|
58
|
+
namespace: STORE.RANCHER,
|
|
57
59
|
baseUrl: '/v3',
|
|
58
60
|
supportsStream: false, // The norman API doesn't support streaming
|
|
59
61
|
modelBaseClass: STEVE_MODEL_TYPES.NORMAN,
|
|
@@ -225,7 +227,6 @@ export const state = () => {
|
|
|
225
227
|
return {
|
|
226
228
|
managementReady: false,
|
|
227
229
|
clusterReady: false,
|
|
228
|
-
isMultiCluster: false,
|
|
229
230
|
isRancher: false,
|
|
230
231
|
namespaceFilters: [],
|
|
231
232
|
activeNamespaceCache: {}, // Used to efficiently check if a resource should be displayed
|
|
@@ -241,7 +242,6 @@ export const state = () => {
|
|
|
241
242
|
serverVersion: null,
|
|
242
243
|
systemNamespaces: [],
|
|
243
244
|
isSingleProduct: undefined,
|
|
244
|
-
namespaceFilterMode: null,
|
|
245
245
|
};
|
|
246
246
|
};
|
|
247
247
|
|
|
@@ -250,8 +250,14 @@ export const getters = {
|
|
|
250
250
|
return state.clusterReady === true;
|
|
251
251
|
},
|
|
252
252
|
|
|
253
|
-
isMultiCluster(state) {
|
|
254
|
-
|
|
253
|
+
isMultiCluster(state, getters) {
|
|
254
|
+
const clusters = getters['management/all'](MANAGEMENT.CLUSTER);
|
|
255
|
+
|
|
256
|
+
if (clusters.length === 1 && clusters[0].metadata?.name === 'local') {
|
|
257
|
+
return false;
|
|
258
|
+
} else {
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
255
261
|
},
|
|
256
262
|
|
|
257
263
|
isRancher(state) {
|
|
@@ -278,15 +284,6 @@ export const getters = {
|
|
|
278
284
|
return state.systemNamespaces;
|
|
279
285
|
},
|
|
280
286
|
|
|
281
|
-
/**
|
|
282
|
-
* Namespace Filter Mode supplies a resource type to the NamespaceFilter.
|
|
283
|
-
*
|
|
284
|
-
* Only one of the resource type is allowed to be selected
|
|
285
|
-
*/
|
|
286
|
-
namespaceFilterMode(state) {
|
|
287
|
-
return state.namespaceFilterMode;
|
|
288
|
-
},
|
|
289
|
-
|
|
290
287
|
currentCluster(state, getters) {
|
|
291
288
|
return getters['management/byId'](MANAGEMENT.CLUSTER, state.clusterId);
|
|
292
289
|
},
|
|
@@ -372,34 +369,6 @@ export const getters = {
|
|
|
372
369
|
return state.namespaceFilters.filter(x => !`${ x }`.startsWith(NAMESPACED_PREFIX)).length === 0;
|
|
373
370
|
},
|
|
374
371
|
|
|
375
|
-
isSingleNamespace(state, getters) {
|
|
376
|
-
const product = getters['currentProduct'];
|
|
377
|
-
|
|
378
|
-
if ( !product ) {
|
|
379
|
-
return false;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
if ( product.showWorkspaceSwitcher ) {
|
|
383
|
-
return false;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
if ( getters.isAllNamespaces ) {
|
|
387
|
-
return false;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
const filters = state.namespaceFilters;
|
|
391
|
-
|
|
392
|
-
if ( filters.length !== 1 ) {
|
|
393
|
-
return false;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
if (filters[0].startsWith('ns://')) {
|
|
397
|
-
return filters[0];
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
return false;
|
|
401
|
-
},
|
|
402
|
-
|
|
403
372
|
isMultipleNamespaces(state, getters) {
|
|
404
373
|
const product = getters['currentProduct'];
|
|
405
374
|
|
|
@@ -421,7 +390,7 @@ export const getters = {
|
|
|
421
390
|
return true;
|
|
422
391
|
}
|
|
423
392
|
|
|
424
|
-
return !filters[0].startsWith(
|
|
393
|
+
return !filters[0].startsWith(NAMESPACE_FILTER_NS_FULL_PREFIX);
|
|
425
394
|
},
|
|
426
395
|
|
|
427
396
|
namespaceFilters(state) {
|
|
@@ -591,9 +560,8 @@ export const getters = {
|
|
|
591
560
|
};
|
|
592
561
|
|
|
593
562
|
export const mutations = {
|
|
594
|
-
managementChanged(state, { ready,
|
|
563
|
+
managementChanged(state, { ready, isRancher }) {
|
|
595
564
|
state.managementReady = ready;
|
|
596
|
-
state.isMultiCluster = isMultiCluster;
|
|
597
565
|
state.isRancher = isRancher;
|
|
598
566
|
},
|
|
599
567
|
clusterReady(state, ready) {
|
|
@@ -621,10 +589,6 @@ export const mutations = {
|
|
|
621
589
|
state.allNamespaces = namespace;
|
|
622
590
|
},
|
|
623
591
|
|
|
624
|
-
setNamespaceFilterMode(state, mode) {
|
|
625
|
-
state.namespaceFilterMode = mode;
|
|
626
|
-
},
|
|
627
|
-
|
|
628
592
|
pageActions(state, pageActions) {
|
|
629
593
|
state.pageActions = pageActions;
|
|
630
594
|
},
|
|
@@ -747,11 +711,7 @@ export const actions = {
|
|
|
747
711
|
|
|
748
712
|
res = await allHash(promises);
|
|
749
713
|
dispatch('i18n/init');
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
if ( res.clusters.length === 1 && res.clusters[0].metadata?.name === 'local' ) {
|
|
753
|
-
isMultiCluster = false;
|
|
754
|
-
}
|
|
714
|
+
const isMultiCluster = getters['isMultiCluster'];
|
|
755
715
|
|
|
756
716
|
const pl = res.settings?.find(x => x.id === 'ui-pl')?.value;
|
|
757
717
|
const brand = res.settings?.find(x => x.id === SETTING.BRAND)?.value;
|
|
@@ -773,7 +733,6 @@ export const actions = {
|
|
|
773
733
|
|
|
774
734
|
commit('managementChanged', {
|
|
775
735
|
ready: true,
|
|
776
|
-
isMultiCluster,
|
|
777
736
|
isRancher,
|
|
778
737
|
});
|
|
779
738
|
|
|
@@ -967,10 +926,6 @@ export const actions = {
|
|
|
967
926
|
commit('updateNamespaces', { filters: ids });
|
|
968
927
|
},
|
|
969
928
|
|
|
970
|
-
setNamespaceFilterMode({ commit }, mode) {
|
|
971
|
-
commit('setNamespaceFilterMode', mode);
|
|
972
|
-
},
|
|
973
|
-
|
|
974
929
|
async cleanNamespaces({ getters, dispatch }) {
|
|
975
930
|
// Initialise / Remove any filters that the user no-longer has access to
|
|
976
931
|
await dispatch('management/findAll', { type: MANAGEMENT.CLUSTER }); // So they can be got byId below
|