@rancher/shell 3.0.0-rc.8 → 3.0.0
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 +12 -11
- package/assets/translations/zh-hans.yaml +1 -4
- package/components/EmberPage.vue +0 -8
- package/components/ResourceTable.vue +26 -1
- package/components/SortableTable/actions.js +1 -1
- package/components/SortableTable/index.vue +17 -1
- package/components/SortableTable/selection.js +1 -1
- package/components/SortableTable/sorting.js +11 -3
- package/components/fleet/FleetClusters.vue +0 -3
- package/components/form/ColorInput.vue +13 -2
- package/components/form/HookOption.vue +31 -29
- package/components/form/LabeledSelect.vue +0 -1
- package/components/form/LifecycleHooks.vue +2 -2
- package/components/form/__tests__/ColorInput.test.ts +27 -0
- package/components/formatter/SecretData.vue +1 -1
- package/components/nav/Header.vue +10 -13
- package/components/nav/TopLevelMenu.vue +0 -40
- package/components/nav/WorkspaceSwitcher.vue +0 -1
- package/config/private-label.js +2 -1
- package/config/router/routes.js +2 -26
- package/config/settings.ts +5 -0
- package/config/version.js +2 -0
- package/detail/catalog.cattle.io.app.vue +17 -4
- package/detail/fleet.cattle.io.cluster.vue +11 -9
- package/detail/fleet.cattle.io.gitrepo.vue +1 -1
- package/edit/cis.cattle.io.clusterscan.vue +4 -3
- package/edit/cis.cattle.io.clusterscanbenchmark.vue +2 -0
- package/edit/constraints.gatekeeper.sh.constraint/index.vue +2 -0
- package/edit/fleet.cattle.io.cluster.vue +4 -0
- package/edit/fleet.cattle.io.gitrepo.vue +11 -8
- package/edit/helm.cattle.io.projecthelmchart.vue +2 -0
- package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +2 -0
- package/edit/kontainerDriver.vue +2 -0
- package/edit/logging-flow/index.vue +2 -0
- package/edit/management.cattle.io.project.vue +2 -1
- package/edit/management.cattle.io.projectroletemplatebinding.vue +2 -1
- package/edit/management.cattle.io.user.vue +3 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +2 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +2 -0
- package/edit/monitoring.coreos.com.prometheusrule/AlertingRule.vue +5 -5
- package/edit/monitoring.coreos.com.prometheusrule/index.vue +3 -1
- package/edit/monitoring.coreos.com.receiver/index.vue +2 -0
- package/edit/monitoring.coreos.com.route.vue +2 -0
- package/edit/networking.istio.io.destinationrule/index.vue +2 -0
- package/edit/nodeDriver.vue +2 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +26 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +63 -149
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +4 -1
- package/edit/provisioning.cattle.io.cluster/import.vue +2 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +5 -3
- package/edit/provisioning.cattle.io.cluster/tabs/Advanced.vue +7 -2
- package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +108 -35
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +1 -1
- package/edit/ui.cattle.io.navlink.vue +4 -3
- package/edit/workload/mixins/workload.js +1 -1
- package/mixins/browser-tab-visibility.js +1 -1
- package/mixins/chart.js +6 -2
- package/mixins/metric-poller.js +1 -1
- package/mixins/resource-fetch.js +1 -1
- package/models/catalog.cattle.io.app.js +108 -21
- package/models/cloudcredential.js +4 -4
- package/models/fleet.cattle.io.gitrepo.js +8 -13
- package/models/management.cattle.io.cluster.js +13 -2
- package/models/management.cattle.io.project.js +4 -0
- package/models/provisioning.cattle.io.cluster.js +1 -2
- package/models/workload.js +1 -1
- package/package.json +11 -4
- package/pages/auth/logout.vue +7 -9
- package/pages/auth/setup.vue +3 -0
- package/pages/c/_cluster/apps/charts/install.vue +11 -3
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +7 -4
- package/pages/c/_cluster/explorer/index.vue +45 -24
- package/pages/c/_cluster/fleet/index.vue +11 -5
- package/pages/c/_cluster/uiplugins/index.vue +4 -2
- package/pages/diagnostic.vue +1 -0
- package/plugins/steve/mutations.js +4 -1
- package/plugins/steve/subscribe.js +3 -4
- package/types/shell/index.d.ts +13 -0
- package/utils/__tests__/object.test.ts +152 -1
- package/utils/object.js +37 -0
- package/utils/string.js +9 -0
- package/utils/validators/formRules/index.ts +1 -1
- package/config/product/multi-cluster-apps.js +0 -61
|
@@ -12,6 +12,7 @@ import { WORKSPACE_ANNOTATION } from '@shell/config/labels-annotations';
|
|
|
12
12
|
import { filterBy } from '@shell/utils/array';
|
|
13
13
|
import FleetNoWorkspaces from '@shell/components/fleet/FleetNoWorkspaces.vue';
|
|
14
14
|
import { NAME } from '@shell/config/product/fleet';
|
|
15
|
+
import { xOfy } from '@shell/utils/string';
|
|
15
16
|
|
|
16
17
|
export default {
|
|
17
18
|
name: 'FleetDashboard',
|
|
@@ -175,7 +176,12 @@ export default {
|
|
|
175
176
|
}
|
|
176
177
|
|
|
177
178
|
if (area === 'clusters') {
|
|
178
|
-
|
|
179
|
+
if (row.clusterInfo?.ready === row.clusterInfo?.total && row.clusterInfo?.ready) {
|
|
180
|
+
return {
|
|
181
|
+
badgeClass: STATES[STATES_ENUM.ACTIVE].color,
|
|
182
|
+
icon: STATES[STATES_ENUM.ACTIVE].compoundIcon
|
|
183
|
+
};
|
|
184
|
+
}
|
|
179
185
|
} else if (area === 'bundles') {
|
|
180
186
|
group = row.bundles;
|
|
181
187
|
} else if (area === 'resources') {
|
|
@@ -223,7 +229,7 @@ export default {
|
|
|
223
229
|
}
|
|
224
230
|
|
|
225
231
|
if (area === 'clusters') {
|
|
226
|
-
group =
|
|
232
|
+
group = '';
|
|
227
233
|
} else if (area === 'bundles') {
|
|
228
234
|
group = row.bundles;
|
|
229
235
|
} else if (area === 'resources') {
|
|
@@ -262,11 +268,11 @@ export default {
|
|
|
262
268
|
}
|
|
263
269
|
|
|
264
270
|
if (area === 'clusters') {
|
|
265
|
-
|
|
271
|
+
return `${ row.clusterInfo.ready }/${ row.clusterInfo.total }`;
|
|
266
272
|
} else if (area === 'bundles') {
|
|
267
|
-
value =
|
|
273
|
+
value = xOfy(row.bundlesReady?.length, row.bundles?.length);
|
|
268
274
|
} else if (area === 'resources') {
|
|
269
|
-
value =
|
|
275
|
+
value = xOfy(row.status?.resourceCounts?.ready, row.status?.resourceCounts?.desiredReady);
|
|
270
276
|
}
|
|
271
277
|
|
|
272
278
|
return value;
|
|
@@ -154,7 +154,8 @@ export default {
|
|
|
154
154
|
},
|
|
155
155
|
|
|
156
156
|
showAddReposBanner() {
|
|
157
|
-
|
|
157
|
+
// because of https://github.com/rancher/rancher/pull/45894 we need to consider other start values
|
|
158
|
+
const hasExtensionReposBannerSetting = this.addExtensionReposBannerSetting?.value === 'true' || this.addExtensionReposBannerSetting?.value === '' || this.addExtensionReposBannerSetting?.value === undefined;
|
|
158
159
|
const uiPluginsRepoNotFound = isRancherPrime() && !this.repos?.find((r) => r.urlDisplay === UI_PLUGINS_REPOS.OFFICIAL.URL);
|
|
159
160
|
const uiPluginsPartnersRepoNotFound = !this.repos?.find((r) => r.urlDisplay === UI_PLUGINS_REPOS.PARTNERS.URL);
|
|
160
161
|
|
|
@@ -615,7 +616,8 @@ export default {
|
|
|
615
616
|
},
|
|
616
617
|
|
|
617
618
|
updateAddReposSetting() {
|
|
618
|
-
|
|
619
|
+
// because of https://github.com/rancher/rancher/pull/45894 we need to consider other start values
|
|
620
|
+
if (this.addExtensionReposBannerSetting?.value === 'true' || this.addExtensionReposBannerSetting?.value === '' || this.addExtensionReposBannerSetting?.value === undefined) {
|
|
619
621
|
this.addExtensionReposBannerSetting.value = 'false';
|
|
620
622
|
this.addExtensionReposBannerSetting.save();
|
|
621
623
|
}
|
package/pages/diagnostic.vue
CHANGED
|
@@ -215,6 +215,7 @@ export default {
|
|
|
215
215
|
'linode',
|
|
216
216
|
'targetRoute', // contains circular references, isn't useful (added later to store)
|
|
217
217
|
'$router', // also contains a circular reference to $store, not useful for diagnostics
|
|
218
|
+
'$route', // also contains a circular reference to $store, not useful for diagnostics
|
|
218
219
|
];
|
|
219
220
|
|
|
220
221
|
const clearListsKeys = [
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import { perfLoadAll } from '@shell/plugins/steve/performanceTesting';
|
|
14
14
|
import { classify } from '@shell/plugins/dashboard-store/classify';
|
|
15
15
|
import SteveSchema from '@shell/models/steve-schema';
|
|
16
|
+
import { deepToRaw } from '@shell/utils/object';
|
|
16
17
|
|
|
17
18
|
function registerNamespace(state, namespace) {
|
|
18
19
|
let cache = state.podsByNamespace[namespace];
|
|
@@ -145,7 +146,9 @@ export default {
|
|
|
145
146
|
|
|
146
147
|
if (worker) {
|
|
147
148
|
// Store raw json objects, not the proxies
|
|
148
|
-
|
|
149
|
+
const rawData = deepToRaw(data);
|
|
150
|
+
|
|
151
|
+
worker.postMessage({ loadSchemas: rawData });
|
|
149
152
|
}
|
|
150
153
|
}
|
|
151
154
|
},
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { addObject, clear, removeObject } from '@shell/utils/array';
|
|
11
|
-
import { get } from '@shell/utils/object';
|
|
11
|
+
import { get, deepToRaw } from '@shell/utils/object';
|
|
12
12
|
import { SCHEMA, MANAGEMENT } from '@shell/config/types';
|
|
13
13
|
import { SETTING } from '@shell/config/settings';
|
|
14
14
|
import { CSRF } from '@shell/config/cookies';
|
|
@@ -35,7 +35,6 @@ import { WORKER_MODES } from './worker';
|
|
|
35
35
|
import acceptOrRejectSocketMessage from './accept-or-reject-socket-message';
|
|
36
36
|
import { BLANK_CLUSTER, STORE } from '@shell/store/store-types.js';
|
|
37
37
|
import paginationUtils from '@shell/utils/pagination-utils';
|
|
38
|
-
import _ from 'lodash';
|
|
39
38
|
|
|
40
39
|
// minimum length of time a disconnect notification is shown
|
|
41
40
|
const MINIMUM_TIME_NOTIFIED = 3000;
|
|
@@ -179,9 +178,9 @@ export async function createWorker(store, ctx) {
|
|
|
179
178
|
|
|
180
179
|
while (workerQueues[storeName]?.length) {
|
|
181
180
|
const message = workerQueues[storeName].shift();
|
|
181
|
+
const safeMessage = deepToRaw(message);
|
|
182
182
|
|
|
183
|
-
|
|
184
|
-
store.$workers[storeName].postMessage(_.cloneDeep(message));
|
|
183
|
+
store.$workers[storeName].postMessage(safeMessage);
|
|
185
184
|
}
|
|
186
185
|
}
|
|
187
186
|
|
package/types/shell/index.d.ts
CHANGED
|
@@ -3900,6 +3900,13 @@ export function applyChangeset(obj: any, changeset: any): any;
|
|
|
3900
3900
|
*/
|
|
3901
3901
|
export function pickBy(obj?: {}, predicate?: (value: any, key: any) => boolean): {};
|
|
3902
3902
|
export function dropKeys(obj: any, keys: any): void;
|
|
3903
|
+
/**
|
|
3904
|
+
* Recursively convert a reactive object to a raw object
|
|
3905
|
+
* @param {*} obj
|
|
3906
|
+
* @param {*} cache
|
|
3907
|
+
* @returns
|
|
3908
|
+
*/
|
|
3909
|
+
export function deepToRaw(obj: any, cache?: any): any;
|
|
3903
3910
|
export { isEqualBasic as isEqual };
|
|
3904
3911
|
export function toDictionary(array: any, callback: any): any;
|
|
3905
3912
|
/**
|
|
@@ -4281,6 +4288,12 @@ export function isIpv4(ip: any): boolean;
|
|
|
4281
4288
|
export function sanitizeKey(k: any): any;
|
|
4282
4289
|
export function sanitizeValue(v: any): any;
|
|
4283
4290
|
export function sanitizeIP(v: any): any;
|
|
4291
|
+
/**
|
|
4292
|
+
* Return the string `<x> / <y>`
|
|
4293
|
+
*
|
|
4294
|
+
* Each param should be a number, otherwise `?` is used
|
|
4295
|
+
*/
|
|
4296
|
+
export function xOfy(x: any, y: any): string;
|
|
4284
4297
|
export namespace CHARSET {
|
|
4285
4298
|
export { num as NUMERIC };
|
|
4286
4299
|
export const NO_VOWELS: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { reactive, isReactive } from 'vue';
|
|
1
2
|
import {
|
|
2
|
-
clone, get, getter, isEmpty, toDictionary, remove, diff, definedKeys
|
|
3
|
+
clone, get, getter, isEmpty, toDictionary, remove, diff, definedKeys, deepToRaw
|
|
3
4
|
} from '@shell/utils/object';
|
|
4
5
|
|
|
5
6
|
describe('fx: get', () => {
|
|
@@ -227,3 +228,153 @@ describe('fx: definedKeys', () => {
|
|
|
227
228
|
expect(result).toStrictEqual(expected);
|
|
228
229
|
});
|
|
229
230
|
});
|
|
231
|
+
|
|
232
|
+
describe('fx: deepToRaw', () => {
|
|
233
|
+
it('should return primitives as is', () => {
|
|
234
|
+
expect(deepToRaw(null)).toBeNull();
|
|
235
|
+
expect(deepToRaw(undefined)).toBeUndefined();
|
|
236
|
+
expect(deepToRaw(42)).toBe(42);
|
|
237
|
+
expect(deepToRaw('test')).toBe('test');
|
|
238
|
+
expect(deepToRaw(true)).toBe(true);
|
|
239
|
+
|
|
240
|
+
const sym = Symbol('symbol');
|
|
241
|
+
|
|
242
|
+
expect(deepToRaw(sym)).toBe(sym);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('should handle simple objects', () => {
|
|
246
|
+
const obj = { a: 1, b: 2 };
|
|
247
|
+
const result = deepToRaw(obj);
|
|
248
|
+
|
|
249
|
+
expect(result).toStrictEqual({ a: 1, b: 2 });
|
|
250
|
+
expect(result).not.toBe(obj); // Should not be the same reference
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('should handle arrays', () => {
|
|
254
|
+
const arr = [1, 2, 3];
|
|
255
|
+
const result = deepToRaw(arr);
|
|
256
|
+
|
|
257
|
+
expect(result).toStrictEqual([1, 2, 3]);
|
|
258
|
+
expect(result).not.toBe(arr); // Should not be the same reference
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('should handle nested objects', () => {
|
|
262
|
+
const obj = { a: { b: { c: 3 } } };
|
|
263
|
+
const result = deepToRaw(obj);
|
|
264
|
+
|
|
265
|
+
expect(result).toStrictEqual({ a: { b: { c: 3 } } });
|
|
266
|
+
expect(result).not.toBe(obj);
|
|
267
|
+
expect(result.a).not.toBe(obj.a);
|
|
268
|
+
expect(result.a.b).not.toBe(obj.a.b);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('should handle nested arrays', () => {
|
|
272
|
+
const arr = [1, [2, [3]]];
|
|
273
|
+
const result = deepToRaw(arr);
|
|
274
|
+
|
|
275
|
+
expect(result).toStrictEqual([1, [2, [3]]]);
|
|
276
|
+
expect(result).not.toBe(arr);
|
|
277
|
+
expect(result[1]).not.toBe(arr[1]);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('should handle reactive proxies (reactive object)', () => {
|
|
281
|
+
const reactiveObj = reactive({ a: 1, b: { c: 2 } });
|
|
282
|
+
const result = deepToRaw(reactiveObj);
|
|
283
|
+
|
|
284
|
+
expect(result).toStrictEqual({ a: 1, b: { c: 2 } });
|
|
285
|
+
expect(result).not.toBe(reactiveObj);
|
|
286
|
+
expect(isReactive(result)).toBe(false);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('should handle nested reactive properties', () => {
|
|
290
|
+
const data = reactive({
|
|
291
|
+
num: 1,
|
|
292
|
+
str: 'test',
|
|
293
|
+
bool: true,
|
|
294
|
+
nil: null,
|
|
295
|
+
undef: undefined,
|
|
296
|
+
arr: [1, 2, { a: 3 }],
|
|
297
|
+
obj: { nested: reactive({ a: 1 }) },
|
|
298
|
+
func: null,
|
|
299
|
+
sym: null,
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
const result = deepToRaw(data);
|
|
303
|
+
|
|
304
|
+
expect(result).toStrictEqual({
|
|
305
|
+
num: 1,
|
|
306
|
+
str: 'test',
|
|
307
|
+
bool: true,
|
|
308
|
+
nil: null,
|
|
309
|
+
undef: undefined,
|
|
310
|
+
arr: [1, 2, { a: 3 }],
|
|
311
|
+
obj: { nested: { a: 1 } },
|
|
312
|
+
func: null,
|
|
313
|
+
sym: null,
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
expect(isReactive(result)).toBe(false);
|
|
317
|
+
expect(isReactive(result.obj)).toBe(false);
|
|
318
|
+
expect(isReactive(result.obj.nested)).toBe(false);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it('should handle circular references', () => {
|
|
322
|
+
const obj: { name: string; [key: string]: any } = { name: 'Alice' };
|
|
323
|
+
|
|
324
|
+
obj.self = obj; // Circular reference
|
|
325
|
+
|
|
326
|
+
const result = deepToRaw(obj);
|
|
327
|
+
|
|
328
|
+
expect(result).toStrictEqual({ name: 'Alice', self: result });
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it('should handle objects with functions and symbols', () => {
|
|
332
|
+
const symbolKey = Symbol('key');
|
|
333
|
+
const obj = {
|
|
334
|
+
a: 1,
|
|
335
|
+
b() {},
|
|
336
|
+
[symbolKey]: 'symbolValue',
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
const result = deepToRaw(obj);
|
|
340
|
+
|
|
341
|
+
expect(result).toStrictEqual({ a: 1, b: null });
|
|
342
|
+
expect(result[symbolKey]).toBeUndefined(); // Symbols are skipped
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('should not mutate the original data', () => {
|
|
346
|
+
const obj = { a: { b: 2 } };
|
|
347
|
+
const original = JSON.stringify(obj);
|
|
348
|
+
|
|
349
|
+
deepToRaw(obj);
|
|
350
|
+
expect(JSON.stringify(obj)).toBe(original);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it('should handle complex data structures', () => {
|
|
354
|
+
const data = reactive({
|
|
355
|
+
num: 1,
|
|
356
|
+
str: 'test',
|
|
357
|
+
bool: true,
|
|
358
|
+
nil: null,
|
|
359
|
+
undef: undefined,
|
|
360
|
+
arr: [1, 2, { a: 3 }],
|
|
361
|
+
obj: { nested: { a: 1 } },
|
|
362
|
+
func: () => {},
|
|
363
|
+
sym: Symbol('sym'),
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
const result = deepToRaw(data);
|
|
367
|
+
|
|
368
|
+
expect(result).toStrictEqual({
|
|
369
|
+
num: 1,
|
|
370
|
+
str: 'test',
|
|
371
|
+
bool: true,
|
|
372
|
+
nil: null,
|
|
373
|
+
undef: undefined,
|
|
374
|
+
arr: [1, 2, { a: 3 }],
|
|
375
|
+
obj: { nested: { a: 1 } },
|
|
376
|
+
func: null,
|
|
377
|
+
sym: null,
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
});
|
package/utils/object.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { toRaw } from 'vue';
|
|
1
2
|
import cloneDeep from 'lodash/cloneDeep';
|
|
2
3
|
import flattenDeep from 'lodash/flattenDeep';
|
|
3
4
|
import compact from 'lodash/compact';
|
|
@@ -434,3 +435,39 @@ export function dropKeys(obj, keys) {
|
|
|
434
435
|
delete obj[k];
|
|
435
436
|
}
|
|
436
437
|
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Recursively convert a reactive object to a raw object
|
|
441
|
+
* @param {*} obj
|
|
442
|
+
* @param {*} cache
|
|
443
|
+
* @returns
|
|
444
|
+
*/
|
|
445
|
+
export function deepToRaw(obj, cache = new WeakSet()) {
|
|
446
|
+
if (obj === null || typeof obj !== 'object') {
|
|
447
|
+
// If obj is null or a primitive, return it as is
|
|
448
|
+
return obj;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// If the object has already been processed, return it to prevent circular references
|
|
452
|
+
if (cache.has(obj)) {
|
|
453
|
+
return obj;
|
|
454
|
+
}
|
|
455
|
+
cache.add(obj);
|
|
456
|
+
|
|
457
|
+
if (Array.isArray(obj)) {
|
|
458
|
+
return obj.map((item) => deepToRaw(item, cache));
|
|
459
|
+
} else {
|
|
460
|
+
const rawObj = toRaw(obj);
|
|
461
|
+
const result = {};
|
|
462
|
+
|
|
463
|
+
for (const key in rawObj) {
|
|
464
|
+
if (typeof rawObj[key] === 'function' || typeof rawObj[key] === 'symbol') {
|
|
465
|
+
result[key] = null;
|
|
466
|
+
} else {
|
|
467
|
+
result[key] = deepToRaw(rawObj[key], cache);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return result;
|
|
472
|
+
}
|
|
473
|
+
}
|
package/utils/string.js
CHANGED
|
@@ -321,3 +321,12 @@ export function sanitizeValue(v) {
|
|
|
321
321
|
export function sanitizeIP(v) {
|
|
322
322
|
return (v || '').replace(/[^a-z0-9.:_-]/ig, '');
|
|
323
323
|
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Return the string `<x> / <y>`
|
|
327
|
+
*
|
|
328
|
+
* Each param should be a number, otherwise `?` is used
|
|
329
|
+
*/
|
|
330
|
+
export function xOfy(x, y) {
|
|
331
|
+
return `${ typeof x === 'number' ? x : '?' }/${ typeof y === 'number' ? y : '?' }`;
|
|
332
|
+
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { LEGACY } from '@shell/store/features';
|
|
2
|
-
import { DSL } from '@shell/store/type-map';
|
|
3
|
-
|
|
4
|
-
export const NAME = 'mcapps';
|
|
5
|
-
|
|
6
|
-
export function init(store) {
|
|
7
|
-
const {
|
|
8
|
-
product,
|
|
9
|
-
basicType,
|
|
10
|
-
virtualType,
|
|
11
|
-
} = DSL(store, NAME);
|
|
12
|
-
|
|
13
|
-
product({
|
|
14
|
-
icon: 'marketplace',
|
|
15
|
-
category: 'legacy',
|
|
16
|
-
inStore: 'management',
|
|
17
|
-
ifFeature: LEGACY,
|
|
18
|
-
removable: false,
|
|
19
|
-
showClusterSwitcher: false,
|
|
20
|
-
showWorkspaceSwitcher: false,
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
virtualType({
|
|
24
|
-
labelKey: 'legacy.catalogs',
|
|
25
|
-
name: 'mc-catalogs',
|
|
26
|
-
group: 'Root',
|
|
27
|
-
namespaced: false,
|
|
28
|
-
weight: 111,
|
|
29
|
-
icon: 'folder',
|
|
30
|
-
route: { name: 'c-cluster-mcapps-pages-page', params: { cluster: 'local', page: 'catalogs' } },
|
|
31
|
-
exact: true
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
virtualType({
|
|
35
|
-
labelKey: 'legacy.globalDnsEntries',
|
|
36
|
-
name: 'global-dns-entries',
|
|
37
|
-
group: 'Root',
|
|
38
|
-
namespaced: false,
|
|
39
|
-
weight: 110,
|
|
40
|
-
icon: 'folder',
|
|
41
|
-
route: { name: 'c-cluster-mcapps-pages-page', params: { cluster: 'local', page: 'global-dns-entries' } },
|
|
42
|
-
exact: true
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
virtualType({
|
|
46
|
-
labelKey: 'legacy.globalDnsProviders',
|
|
47
|
-
name: 'global-dns-providers',
|
|
48
|
-
group: 'Root',
|
|
49
|
-
namespaced: false,
|
|
50
|
-
weight: 109,
|
|
51
|
-
icon: 'folder',
|
|
52
|
-
route: { name: 'c-cluster-mcapps-pages-page', params: { cluster: 'local', page: 'global-dns-providers' } },
|
|
53
|
-
exact: true
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
basicType([
|
|
57
|
-
'mc-catalogs',
|
|
58
|
-
'global-dns-entries',
|
|
59
|
-
'global-dns-providers',
|
|
60
|
-
]);
|
|
61
|
-
}
|