@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
package/plugins/codemirror.js
CHANGED
|
@@ -167,3 +167,161 @@ CodeMirror.registerHelper('fold', 'yamlcomments', (cm, start) => {
|
|
|
167
167
|
};
|
|
168
168
|
}
|
|
169
169
|
});
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* It display a dot for each space character in the text;
|
|
173
|
+
* used in combination with 'as-text-area' css properties in CodeMirror.vue to display line break markdowns
|
|
174
|
+
*/
|
|
175
|
+
CodeMirror.defineOption('showMarkdownLineBreaks', false, (codeMirror) => {
|
|
176
|
+
codeMirror.addOverlay({
|
|
177
|
+
name: 'show-markdown-line-breaks',
|
|
178
|
+
token: (stream) => {
|
|
179
|
+
if (stream.string[stream.pos].match(/\s/)) {
|
|
180
|
+
stream.next();
|
|
181
|
+
|
|
182
|
+
return stream.pos % 2 === 0 ? 'markdown-single-trailing-space-even' : 'markdown-single-trailing-space-odd';
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
stream.next();
|
|
186
|
+
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* It enables the text color selection in CodeMirror.vue
|
|
194
|
+
* references:
|
|
195
|
+
* demo: https://codemirror.net/5/demo/markselection.html#
|
|
196
|
+
* add-on: https://codemirror.net/5/doc/manual.html#addon_mark-selection
|
|
197
|
+
* source: https://codemirror.net/5/addon/selection/mark-selection.js
|
|
198
|
+
*/
|
|
199
|
+
CodeMirror.defineOption('styleSelectedText', false, (cm, val, old) => {
|
|
200
|
+
const prev = old && old !== CodeMirror.Init;
|
|
201
|
+
|
|
202
|
+
if (val && !prev) {
|
|
203
|
+
cm.state.markedSelection = [];
|
|
204
|
+
cm.state.markedSelectionStyle = typeof val === 'string' ? val : 'CodeMirror-selectedtext';
|
|
205
|
+
reset(cm);
|
|
206
|
+
cm.on('cursorActivity', onCursorActivity);
|
|
207
|
+
cm.on('change', onChange);
|
|
208
|
+
} else if (!val && prev) {
|
|
209
|
+
cm.off('cursorActivity', onCursorActivity);
|
|
210
|
+
cm.off('change', onChange);
|
|
211
|
+
clear(cm);
|
|
212
|
+
cm.state.markedSelection = cm.state.markedSelectionStyle = null;
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
function onCursorActivity(cm) {
|
|
217
|
+
if (cm.state.markedSelection) {
|
|
218
|
+
cm.operation(() => {
|
|
219
|
+
update(cm);
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function onChange(cm) {
|
|
225
|
+
if (cm.state.markedSelection && cm.state.markedSelection.length) {
|
|
226
|
+
cm.operation(() => {
|
|
227
|
+
clear(cm);
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const CHUNK_SIZE = 8;
|
|
233
|
+
const Pos = CodeMirror.Pos;
|
|
234
|
+
const cmp = CodeMirror.cmpPos;
|
|
235
|
+
|
|
236
|
+
function coverRange(cm, from, to, addAt) {
|
|
237
|
+
if (cmp(from, to) === 0) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const array = cm.state.markedSelection;
|
|
241
|
+
const cls = cm.state.markedSelectionStyle;
|
|
242
|
+
|
|
243
|
+
for (let line = from.line;;) {
|
|
244
|
+
const start = line === from.line ? from : Pos(line, 0);
|
|
245
|
+
const endLine = line + CHUNK_SIZE; const atEnd = endLine >= to.line;
|
|
246
|
+
const end = atEnd ? to : Pos(endLine, 0);
|
|
247
|
+
const mark = cm.markText(start, end, { className: cls });
|
|
248
|
+
|
|
249
|
+
if (addAt === null || addAt === undefined) {
|
|
250
|
+
array.push(mark);
|
|
251
|
+
} else {
|
|
252
|
+
array.splice(addAt++, 0, mark);
|
|
253
|
+
}
|
|
254
|
+
if (atEnd) {
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
line = endLine;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function clear(cm) {
|
|
262
|
+
const array = cm.state.markedSelection;
|
|
263
|
+
|
|
264
|
+
for (let i = 0; i < array.length; ++i) {
|
|
265
|
+
array[i].clear();
|
|
266
|
+
}
|
|
267
|
+
array.length = 0;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function reset(cm) {
|
|
271
|
+
clear(cm);
|
|
272
|
+
const ranges = cm.listSelections();
|
|
273
|
+
|
|
274
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
275
|
+
coverRange(cm, ranges[i].from(), ranges[i].to());
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function update(cm) {
|
|
280
|
+
if (!cm.somethingSelected()) {
|
|
281
|
+
return clear(cm);
|
|
282
|
+
}
|
|
283
|
+
if (cm.listSelections().length > 1) {
|
|
284
|
+
return reset(cm);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const from = cm.getCursor('start'); const to = cm.getCursor('end');
|
|
288
|
+
|
|
289
|
+
const array = cm.state.markedSelection;
|
|
290
|
+
|
|
291
|
+
if (!array.length) {
|
|
292
|
+
return coverRange(cm, from, to);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
let coverStart = array[0].find(); let coverEnd = array[array.length - 1].find();
|
|
296
|
+
|
|
297
|
+
if (!coverStart || !coverEnd || to.line - from.line <= CHUNK_SIZE ||
|
|
298
|
+
cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0) {
|
|
299
|
+
return reset(cm);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
while (cmp(from, coverStart.from) > 0) {
|
|
303
|
+
array.shift().clear();
|
|
304
|
+
coverStart = array[0].find();
|
|
305
|
+
}
|
|
306
|
+
if (cmp(from, coverStart.from) < 0) {
|
|
307
|
+
if (coverStart.to.line - from.line < CHUNK_SIZE) {
|
|
308
|
+
array.shift().clear();
|
|
309
|
+
coverRange(cm, from, coverStart.to, 0);
|
|
310
|
+
} else {
|
|
311
|
+
coverRange(cm, from, coverStart.from, 0);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
while (cmp(to, coverEnd.to) < 0) {
|
|
316
|
+
array.pop().clear();
|
|
317
|
+
coverEnd = array[array.length - 1].find();
|
|
318
|
+
}
|
|
319
|
+
if (cmp(to, coverEnd.to) > 0) {
|
|
320
|
+
if (to.line - coverEnd.from.line < CHUNK_SIZE) {
|
|
321
|
+
array.pop().clear();
|
|
322
|
+
coverRange(cm, coverEnd.from, to);
|
|
323
|
+
} else {
|
|
324
|
+
coverRange(cm, coverEnd.to, to);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
@@ -317,13 +317,15 @@ export default {
|
|
|
317
317
|
|
|
318
318
|
// ToDo: SM if we start a "bigger" watch (such as watch without a namespace vs a watch with a namespace), we should stop the stop the "smaller" watch so we don't have duplicate events coming back
|
|
319
319
|
if ( opt.watch !== false ) {
|
|
320
|
-
|
|
320
|
+
const args = {
|
|
321
321
|
type,
|
|
322
322
|
revision: out.revision,
|
|
323
323
|
namespace: opt.watchNamespace || opt.namespaced, // it could be either apparently
|
|
324
324
|
// ToDo: SM namespaced is sometimes a boolean and sometimes a string, I don't see it as especially broken but we should refactor that in the future
|
|
325
325
|
force: opt.forceWatch === true,
|
|
326
|
-
}
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
dispatch('watch', args);
|
|
327
329
|
}
|
|
328
330
|
|
|
329
331
|
const all = getters.all(type);
|
|
@@ -274,6 +274,12 @@ export default {
|
|
|
274
274
|
return false;
|
|
275
275
|
},
|
|
276
276
|
|
|
277
|
+
haveNamespace: (state, getters) => (type) => {
|
|
278
|
+
type = getters.normalizeType(type);
|
|
279
|
+
|
|
280
|
+
return state.types[type]?.haveNamespace || null;
|
|
281
|
+
},
|
|
282
|
+
|
|
277
283
|
haveSelector: (state, getters) => (type, selector) => {
|
|
278
284
|
type = getters.normalizeType(type);
|
|
279
285
|
const entry = state.types[type];
|
|
@@ -209,9 +209,9 @@ export function batchChanges(state, { ctx, batch }) {
|
|
|
209
209
|
const removeAtIndexes = [];
|
|
210
210
|
|
|
211
211
|
// looping through the batch, executing changes, deferring creates and removes since they change the array length
|
|
212
|
-
Object.keys(
|
|
212
|
+
Object.keys(combinedBatch[normalizedType]).forEach((id) => {
|
|
213
213
|
const index = typeCacheIndexMap[id];
|
|
214
|
-
const resource =
|
|
214
|
+
const resource = combinedBatch[normalizedType][id];
|
|
215
215
|
|
|
216
216
|
// an empty resource passed into batch changes is how we'll signal which ones to delete
|
|
217
217
|
if (Object.keys(resource).length === 0 && index !== undefined) {
|
package/plugins/plugin.js
CHANGED
|
@@ -40,7 +40,12 @@ export default async function(context) {
|
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
42
|
} catch (e) {
|
|
43
|
-
|
|
43
|
+
if (e?.code === 404) {
|
|
44
|
+
// Not found, so extensions operator probably not installed
|
|
45
|
+
console.log('Could not load UI Extensions list (Extensions Operator may not be installed)'); // eslint-disable-line no-console
|
|
46
|
+
} else {
|
|
47
|
+
console.error('Could not load UI Extensions list', e); // eslint-disable-line no-console
|
|
48
|
+
}
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
// Load all of the plugins
|
package/plugins/steve/actions.js
CHANGED
|
@@ -11,7 +11,7 @@ import jsyaml from 'js-yaml';
|
|
|
11
11
|
|
|
12
12
|
export default {
|
|
13
13
|
|
|
14
|
-
// Need to override this, so that
|
|
14
|
+
// Need to override this, so that the 'this' context is correct (this class not the base class)
|
|
15
15
|
async loadSchemas(ctx, watch = true) {
|
|
16
16
|
return await loadSchemas(ctx, watch);
|
|
17
17
|
},
|
package/plugins/steve/getters.js
CHANGED
|
@@ -8,6 +8,7 @@ import HybridModel, { cleanHybridResources } from './hybrid-class';
|
|
|
8
8
|
import NormanModel from './norman-class';
|
|
9
9
|
import { urlFor } from '@shell/plugins/dashboard-store/getters';
|
|
10
10
|
import { normalizeType } from '@shell/plugins/dashboard-store/normalize';
|
|
11
|
+
import pAndNFiltering from '@shell/utils/projectAndNamespaceFiltering.utils';
|
|
11
12
|
|
|
12
13
|
export const STEVE_MODEL_TYPES = {
|
|
13
14
|
NORMAN: 'norman',
|
|
@@ -42,6 +43,15 @@ export default {
|
|
|
42
43
|
});
|
|
43
44
|
});
|
|
44
45
|
}
|
|
46
|
+
|
|
47
|
+
// `opt.namespaced` is either
|
|
48
|
+
// - a string representing a single namespace - add restriction to the url
|
|
49
|
+
// - an array of namespaces or projects - add restriction as a param
|
|
50
|
+
const namespaceProjectFilter = pAndNFiltering.checkAndCreateParam(opt);
|
|
51
|
+
|
|
52
|
+
if (namespaceProjectFilter) {
|
|
53
|
+
url += `${ (url.includes('?') ? '&' : '?') + namespaceProjectFilter }`;
|
|
54
|
+
}
|
|
45
55
|
// End: Filter
|
|
46
56
|
|
|
47
57
|
// Limit
|
|
@@ -72,12 +82,13 @@ export default {
|
|
|
72
82
|
urlFor: (state, getters) => (type, id, opt) => {
|
|
73
83
|
let url = urlFor(state, getters)(type, id, opt);
|
|
74
84
|
|
|
75
|
-
|
|
85
|
+
// `namespaced` is either
|
|
86
|
+
// - a string representing a single namespace - add restriction to the url
|
|
87
|
+
// - an array of namespaces or projects - add restriction as a param
|
|
88
|
+
if (opt.namespaced && !pAndNFiltering.isApplicable(opt)) {
|
|
76
89
|
const parts = url.split('/');
|
|
77
90
|
|
|
78
91
|
url = `${ parts.join('/') }/${ opt.namespaced }`;
|
|
79
|
-
|
|
80
|
-
return url;
|
|
81
92
|
}
|
|
82
93
|
|
|
83
94
|
return url;
|
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
import Socket, {
|
|
6
6
|
NO_WATCH,
|
|
7
7
|
NO_SCHEMA,
|
|
8
|
-
EVENT_MESSAGE,
|
|
9
8
|
EVENT_CONNECTED,
|
|
9
|
+
REVISION_TOO_OLD
|
|
10
10
|
} from '@shell/utils/socket';
|
|
11
|
-
import { addParam } from '@shell/utils/url';
|
|
12
11
|
|
|
13
12
|
export const WATCH_STATUSES = {
|
|
14
13
|
/**
|
|
@@ -64,7 +63,7 @@ export const watchKeyFromMessage = (msg) => {
|
|
|
64
63
|
};
|
|
65
64
|
|
|
66
65
|
const {
|
|
67
|
-
WATCH_PENDING, WATCH_REQUESTED, WATCHING,
|
|
66
|
+
WATCH_PENDING, WATCH_REQUESTED, WATCHING, REMOVE_PENDING, REQUESTED_REMOVE
|
|
68
67
|
} = WATCH_STATUSES;
|
|
69
68
|
|
|
70
69
|
export default class ResourceWatcher extends Socket {
|
|
@@ -110,12 +109,13 @@ export default class ResourceWatcher extends Socket {
|
|
|
110
109
|
return !!this.watches?.[watchKey];
|
|
111
110
|
}
|
|
112
111
|
|
|
113
|
-
|
|
112
|
+
watch(watchKey, providedResourceVersion, providedResourceVersionTime, providedKeyParts = {}, providedSkipResourceVersion) {
|
|
114
113
|
const {
|
|
115
114
|
resourceType: providedResourceType,
|
|
116
115
|
id: providedId,
|
|
117
116
|
namespace: providedNamespace,
|
|
118
|
-
selector: providedSelector
|
|
117
|
+
selector: providedSelector,
|
|
118
|
+
force: providedForce,
|
|
119
119
|
} = providedKeyParts;
|
|
120
120
|
|
|
121
121
|
this.trace('watch:', 'requested', watchKey);
|
|
@@ -126,8 +126,10 @@ export default class ResourceWatcher extends Socket {
|
|
|
126
126
|
return;
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
if (this.watches?.[watchKey]?.error) {
|
|
130
|
-
this.
|
|
129
|
+
if (!providedForce && this.watches?.[watchKey]?.error) {
|
|
130
|
+
if (this.watches?.[watchKey]?.error.reason !== REVISION_TOO_OLD) {
|
|
131
|
+
this.trace('watch:', 'in error, aborting', watchKey);
|
|
132
|
+
}
|
|
131
133
|
|
|
132
134
|
return;
|
|
133
135
|
}
|
|
@@ -136,7 +138,7 @@ export default class ResourceWatcher extends Socket {
|
|
|
136
138
|
const id = providedId || this.watches?.[watchKey]?.id;
|
|
137
139
|
const namespace = providedNamespace || this.watches?.[watchKey]?.namespace;
|
|
138
140
|
const selector = providedSelector || this.watches?.[watchKey]?.selector;
|
|
139
|
-
|
|
141
|
+
const skipResourceVersion = this.watches?.[watchKey]?.skipResourceVersion || providedSkipResourceVersion;
|
|
140
142
|
|
|
141
143
|
const watchObject = {
|
|
142
144
|
resourceType,
|
|
@@ -145,47 +147,8 @@ export default class ResourceWatcher extends Socket {
|
|
|
145
147
|
selector
|
|
146
148
|
};
|
|
147
149
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (!skipResourceVersion && (!resourceVersion || Date.now() - resourceVersionTime > 300000)) { // 300000ms is 5minutes
|
|
152
|
-
this.trace('watch:', 'revision update required', watchKey);
|
|
153
|
-
|
|
154
|
-
const resourceUrl = this.baseUrl + resourceType;
|
|
155
|
-
const limitedResourceUrl = addParam(resourceUrl, 'limit', 1);
|
|
156
|
-
const opt = {
|
|
157
|
-
method: 'get',
|
|
158
|
-
headers: { accept: 'application/json' },
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
if (this.csrf) {
|
|
162
|
-
opt.headers['x-api-csrf'] = this.csrf;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
await fetch(limitedResourceUrl, opt)
|
|
166
|
-
.then((res) => {
|
|
167
|
-
this.watches[watchKey] = { ...watchObject };
|
|
168
|
-
if (!res.ok) {
|
|
169
|
-
this.watches[watchKey].error = res.json();
|
|
170
|
-
console.warn(`Resource error retrieving resourceVersion`, resourceType, ':', res.json()); // eslint-disable-line no-console
|
|
171
|
-
} else {
|
|
172
|
-
this.watches[watchKey].error = undefined;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return res.json();
|
|
176
|
-
})
|
|
177
|
-
.then((res) => {
|
|
178
|
-
if (res.revision) {
|
|
179
|
-
resourceVersionTime = Date.now();
|
|
180
|
-
resourceVersion = res.revision;
|
|
181
|
-
} else if (!this.watches[watchKey].error) {
|
|
182
|
-
// if there wasn't a revision in the response and there wasn't an error we wrote to the watch then the resource doesn't get a revision and we can skip it on subsequent rewatches
|
|
183
|
-
skipResourceVersion = true;
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
|
-
// When this fails we should re-fetch all resources (aka same as resyncWatch, or we actually call it). #7917
|
|
187
|
-
// This would match the old approach
|
|
188
|
-
}
|
|
150
|
+
const resourceVersionTime = providedResourceVersionTime || this.watches?.[watchKey]?.resourceVersionTime;
|
|
151
|
+
const resourceVersion = providedResourceVersion || this.watches?.[watchKey]?.resourceVersion;
|
|
189
152
|
|
|
190
153
|
const success = this.send(JSON.stringify({
|
|
191
154
|
...watchObject,
|
|
@@ -240,16 +203,21 @@ export default class ResourceWatcher extends Socket {
|
|
|
240
203
|
|
|
241
204
|
if (eventName === 'resource.start' && this.watches?.[watchKey]?.status === WATCH_REQUESTED) {
|
|
242
205
|
this.watches[watchKey].status = WATCHING;
|
|
206
|
+
delete this.watches[watchKey].error;
|
|
243
207
|
} else if (eventName === 'resource.stop' && this.watches?.[watchKey]) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
208
|
+
// Find some way to resolve the correct resourceVersion from within the resourceWatcher until then:
|
|
209
|
+
// reset the watch in the resourceWatcher, we'll handle recovery up the chain. For now
|
|
210
|
+
// dispatch the event to the host process which should have a handler for resource.stop
|
|
211
|
+
|
|
212
|
+
// if (this.watches?.[watchKey]?.status === REQUESTED_REMOVE) {
|
|
213
|
+
this.watches[watchKey] = { error: this.watches[watchKey]?.error };
|
|
214
|
+
// } else {
|
|
215
|
+
// this.watches[watchKey].status = STOPPED;
|
|
216
|
+
// delete this.watches[watchKey].resourceVersion;
|
|
217
|
+
// delete this.watches[watchKey].resourceVersionTime;
|
|
218
|
+
// this.watch(watchKey);
|
|
219
|
+
// this.dispatchEvent(new CustomEvent(EVENT_MESSAGE, { detail: event }));
|
|
220
|
+
// }
|
|
253
221
|
} else if (eventName === 'resource.error') {
|
|
254
222
|
const err = data?.error?.toLowerCase();
|
|
255
223
|
|
|
@@ -262,14 +230,20 @@ export default class ResourceWatcher extends Socket {
|
|
|
262
230
|
|
|
263
231
|
this.watches[watchKey].error = { type: resourceType, reason: NO_SCHEMA };
|
|
264
232
|
} else if ( err.includes('too old') ) {
|
|
265
|
-
// We don't actually know the gap between the requested revision and the oldest available revision.
|
|
266
|
-
// For this case we should re-fetch all resources (aka same as resyncWatch, or we actually call it). #7917
|
|
267
|
-
// This would match the old approach
|
|
268
233
|
delete this.watches[watchKey].resourceVersion;
|
|
269
234
|
delete this.watches[watchKey].resourceVersionTime;
|
|
270
235
|
delete this.watches[watchKey].skipResourceVersion;
|
|
271
|
-
this.
|
|
236
|
+
this.watches[watchKey].error = { type: resourceType, reason: REVISION_TOO_OLD };
|
|
237
|
+
// Needs to match sub resyncWatch params
|
|
238
|
+
this.dispatchEvent(new CustomEvent('resync', {
|
|
239
|
+
detail: {
|
|
240
|
+
data: {
|
|
241
|
+
resourceType, id, namespace, selector
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}));
|
|
272
245
|
}
|
|
246
|
+
this.trace('_onmessage:', 'new error', this.watches[watchKey].error);
|
|
273
247
|
}
|
|
274
248
|
|
|
275
249
|
super._onmessage(event);
|