@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/store/type-map.js
CHANGED
package/types/shell/index.d.ts
CHANGED
|
@@ -1738,6 +1738,7 @@ export namespace MANAGEMENT {
|
|
|
1738
1738
|
const GLOBAL_ROLE_BINDING_1: string;
|
|
1739
1739
|
export { GLOBAL_ROLE_BINDING_1 as GLOBAL_ROLE_BINDING };
|
|
1740
1740
|
export const POD_SECURITY_POLICY_TEMPLATE: string;
|
|
1741
|
+
export const PSP_TEMPLATE_BINDING: string;
|
|
1741
1742
|
export const PSA: string;
|
|
1742
1743
|
export const MANAGED_CHART: string;
|
|
1743
1744
|
export const USER_NOTIFICATION: string;
|
|
@@ -1840,6 +1841,7 @@ export namespace HCI {
|
|
|
1840
1841
|
export const IMAGE: string;
|
|
1841
1842
|
const SETTING_1: string;
|
|
1842
1843
|
export { SETTING_1 as SETTING };
|
|
1844
|
+
export const HARVESTER_CONFIG: string;
|
|
1843
1845
|
}
|
|
1844
1846
|
export const VIRTUAL_HARVESTER_PROVIDER: "harvester";
|
|
1845
1847
|
export namespace ADDRESSES {
|
|
@@ -2491,10 +2493,33 @@ export default _default;
|
|
|
2491
2493
|
// @shell/utils/create-yaml
|
|
2492
2494
|
|
|
2493
2495
|
declare module '@shell/utils/create-yaml' {
|
|
2494
|
-
export function
|
|
2496
|
+
export function createYamlWithOptions(schemas: any, type: any, data: any, options: any): string;
|
|
2497
|
+
export function createYaml(schemas: any, type: any, data: any, processAlwaysAdd?: boolean, depth?: number, path?: string, rootType?: any, dataOptions?: {}): string;
|
|
2498
|
+
export function getBlockDescriptor(value: any, key: any): {
|
|
2499
|
+
header: string;
|
|
2500
|
+
indentation: string;
|
|
2501
|
+
};
|
|
2495
2502
|
export function typeRef(type: any, str: any): any;
|
|
2496
2503
|
export function typeMunge(type: any): any;
|
|
2497
2504
|
export function saferDump(obj: any): any;
|
|
2505
|
+
/**
|
|
2506
|
+
* Handles newlines indicators in the multiline blocks.
|
|
2507
|
+
*
|
|
2508
|
+
* this is required since jsyaml.dump doesn't support chomping and scalar style at the moment.
|
|
2509
|
+
* see: https://github.com/nodeca/js-yaml/issues/171
|
|
2510
|
+
*
|
|
2511
|
+
* @param {*} data the multiline block
|
|
2512
|
+
* @param {*} options blocks indicators, see: https://yaml-multiline.info
|
|
2513
|
+
*
|
|
2514
|
+
* - scalarStyle:
|
|
2515
|
+
* one of '|', '>'
|
|
2516
|
+
* default '|'
|
|
2517
|
+
* - chomping:
|
|
2518
|
+
* one of: null, '', '-', '+'
|
|
2519
|
+
* default: null
|
|
2520
|
+
* @returns the result of jsyaml.dump with the addition of multiline indicators
|
|
2521
|
+
*/
|
|
2522
|
+
export function dumpBlock(data: any, options?: any): any;
|
|
2498
2523
|
export const SIMPLE_TYPES: string[];
|
|
2499
2524
|
export const NEVER_ADD: string[];
|
|
2500
2525
|
export const ACTIVELY_REMOVE: string[];
|
|
@@ -2655,14 +2680,24 @@ export function haveV1MonitoringWorkloads(store: any): Promise<boolean>;
|
|
|
2655
2680
|
// @shell/utils/namespace-filter
|
|
2656
2681
|
|
|
2657
2682
|
declare module '@shell/utils/namespace-filter' {
|
|
2658
|
-
export const
|
|
2683
|
+
export const NAMESPACE_FILTER_ALL_PREFIX: "all";
|
|
2684
|
+
export const NAMESPACE_FILTER_NS_PREFIX: "ns";
|
|
2685
|
+
export const NAMESPACE_FILTER_P_PREFIX: "project";
|
|
2686
|
+
export const NAMESPACE_FILTER_NS_FULL_PREFIX: string;
|
|
2687
|
+
export const NAMESPACE_FILTER_P_FULL_PREFIX: string;
|
|
2659
2688
|
export const NAMESPACE_FILTER_ALL: "all";
|
|
2660
|
-
export const NAMESPACE_FILTER_ALL_SYSTEM:
|
|
2661
|
-
export const NAMESPACE_FILTER_ALL_USER:
|
|
2662
|
-
export const NAMESPACE_FILTER_ALL_ORPHANS:
|
|
2689
|
+
export const NAMESPACE_FILTER_ALL_SYSTEM: string;
|
|
2690
|
+
export const NAMESPACE_FILTER_ALL_USER: string;
|
|
2691
|
+
export const NAMESPACE_FILTER_ALL_ORPHANS: string;
|
|
2663
2692
|
export const NAMESPACE_FILTER_NAMESPACED_PREFIX: "namespaced://";
|
|
2664
2693
|
export const NAMESPACE_FILTER_NAMESPACED_YES: "namespaced://true";
|
|
2665
2694
|
export const NAMESPACE_FILTER_NAMESPACED_NO: "namespaced://false";
|
|
2695
|
+
export namespace NAMESPACE_FILTER_KINDS {
|
|
2696
|
+
const DIVIDER: string;
|
|
2697
|
+
const PROJECT: string;
|
|
2698
|
+
const NAMESPACE: string;
|
|
2699
|
+
const SPECIAL: string;
|
|
2700
|
+
}
|
|
2666
2701
|
export function createNamespaceFilterKey(clusterId: any, product: any): any;
|
|
2667
2702
|
export function createNamespaceFilterKeyWithId(clusterId: any, productId: any): string;
|
|
2668
2703
|
export function splitNamespaceFilterKey(key: any): {
|
|
@@ -2926,8 +2961,8 @@ export function simplify(matchExpressionsInput: any): {
|
|
|
2926
2961
|
matchLabels: {};
|
|
2927
2962
|
matchExpressions: any[];
|
|
2928
2963
|
};
|
|
2929
|
-
export function matches(obj: any, selector: any): boolean;
|
|
2930
|
-
export function matching(ary: any, selector: any): any;
|
|
2964
|
+
export function matches(obj: any, selector: any, labelKey?: string): boolean;
|
|
2965
|
+
export function matching(ary: any, selector: any, labelKey: any): any;
|
|
2931
2966
|
}
|
|
2932
2967
|
|
|
2933
2968
|
// @shell/utils/socket
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getBlockDescriptor,
|
|
3
|
+
dumpBlock,
|
|
4
|
+
} from '@shell/utils/create-yaml';
|
|
5
|
+
|
|
6
|
+
const key = 'example';
|
|
7
|
+
const randomData = '\n foo\n bar\n';
|
|
8
|
+
|
|
9
|
+
const scalarStyles = ['>', '|'];
|
|
10
|
+
const chomping = ['+', '-', ''];
|
|
11
|
+
const indentations = ['4', '2', ''];
|
|
12
|
+
|
|
13
|
+
describe('fx: getBlockDescriptor', () => {
|
|
14
|
+
describe('should parse blocks header for all block indicators combo', () => {
|
|
15
|
+
scalarStyles.forEach((scalar) => {
|
|
16
|
+
chomping.forEach((chomping) => {
|
|
17
|
+
indentations.forEach((indentation) => {
|
|
18
|
+
const combo = `${ scalar }${ indentation }${ chomping }`;
|
|
19
|
+
|
|
20
|
+
it(`combo: ${ combo }`, () => {
|
|
21
|
+
const toParse = `${ key }: ${ combo }${ randomData }`;
|
|
22
|
+
|
|
23
|
+
const desc = getBlockDescriptor(toParse, key);
|
|
24
|
+
|
|
25
|
+
expect(desc?.header).toBe(`${ key }: ${ combo }`);
|
|
26
|
+
expect(desc?.indentation).toBe(indentation);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('fx: dumpBlock', () => {
|
|
35
|
+
describe('should create a data block replacing indicators with blocks indicator from options', () => {
|
|
36
|
+
const key = 'example';
|
|
37
|
+
|
|
38
|
+
scalarStyles.forEach((scalarStyle) => {
|
|
39
|
+
chomping.forEach((chomping) => {
|
|
40
|
+
const options = {
|
|
41
|
+
[key]: {
|
|
42
|
+
chomping,
|
|
43
|
+
scalarStyle
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
it(`options: { scalarStyle: ${ scalarStyle }, chomping: ${ chomping } } with indentation`, () => {
|
|
48
|
+
const data = { [key]: ' foo \n bar \n \n foo\n bar\n ' };
|
|
49
|
+
const block = dumpBlock(data, options);
|
|
50
|
+
|
|
51
|
+
expect(block.includes(`example: ${ scalarStyle }${ chomping }2`)).toBeTruthy();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it(`options: { scalarStyle: ${ scalarStyle }, chomping: ${ chomping } } without indentation`, () => {
|
|
55
|
+
const data = { [key]: 'foo \nbar \n\nfoo\nbar\n ' };
|
|
56
|
+
const block = dumpBlock(data, options);
|
|
57
|
+
|
|
58
|
+
expect(block.includes(`example: ${ scalarStyle }${ chomping }`)).toBeTruthy();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
});
|
package/utils/array.ts
CHANGED
|
@@ -188,6 +188,10 @@ export function uniq<T>(ary: T[]): T[] {
|
|
|
188
188
|
return out;
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
export function concatStrings(a: string[], b: string[]) {
|
|
192
|
+
return [...a.map(aa => b.map(bb => aa.concat(bb)))].reduce((acc, arr) => [...arr, ...acc], []);
|
|
193
|
+
}
|
|
194
|
+
|
|
191
195
|
interface KubeResource { metadata: { labels: { [name: string]: string} } } // Migrate to central kube types resource when those are brought in
|
|
192
196
|
export function getUniqueLabelKeys<T extends KubeResource>(aryResources: T[]): string[] {
|
|
193
197
|
const uniqueObj = aryResources.reduce((res, r) => {
|
package/utils/create-yaml.js
CHANGED
|
@@ -65,7 +65,26 @@ export const ACTIVELY_REMOVE = [
|
|
|
65
65
|
|
|
66
66
|
const INDENT = 2;
|
|
67
67
|
|
|
68
|
-
export function
|
|
68
|
+
export function createYamlWithOptions(schemas, type, data, options) {
|
|
69
|
+
return createYaml(
|
|
70
|
+
schemas,
|
|
71
|
+
type,
|
|
72
|
+
data,
|
|
73
|
+
true, 0, '', null,
|
|
74
|
+
options
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function createYaml(
|
|
79
|
+
schemas,
|
|
80
|
+
type,
|
|
81
|
+
data,
|
|
82
|
+
processAlwaysAdd = true,
|
|
83
|
+
depth = 0,
|
|
84
|
+
path = '',
|
|
85
|
+
rootType = null,
|
|
86
|
+
dataOptions = {}
|
|
87
|
+
) {
|
|
69
88
|
const schema = findBy(schemas, 'id', type);
|
|
70
89
|
|
|
71
90
|
if ( !rootType ) {
|
|
@@ -220,25 +239,25 @@ export function createYaml(schemas, type, data, processAlwaysAdd = true, depth =
|
|
|
220
239
|
if (data[key]) {
|
|
221
240
|
try {
|
|
222
241
|
const cleaned = cleanUp(data);
|
|
223
|
-
const parsedData =
|
|
242
|
+
const parsedData = dumpBlock(cleaned[key], dataOptions[key]);
|
|
224
243
|
|
|
225
|
-
out += `\n${ indent(parsedData
|
|
244
|
+
out += `\n${ indent(parsedData) }`;
|
|
226
245
|
} catch (e) {
|
|
227
246
|
console.error(`Error: Unable to parse map data for yaml of type: ${ type }`, e); // eslint-disable-line no-console
|
|
228
247
|
}
|
|
229
248
|
}
|
|
230
249
|
|
|
231
250
|
if ( SIMPLE_TYPES.includes(mapOf) ) {
|
|
232
|
-
out +=
|
|
251
|
+
out += `# key: ${ mapOf }`;
|
|
233
252
|
} else {
|
|
234
253
|
// If not a simple type ie some sort of object/array, recusively build out commented fields (note data = null here) per the type's (mapOf's) schema
|
|
235
|
-
const chunk = createYaml(schemas, mapOf, null, processAlwaysAdd, depth + 1, (path ? `${ path }.${ key }` : key), rootType);
|
|
254
|
+
const chunk = createYaml(schemas, mapOf, null, processAlwaysAdd, depth + 1, (path ? `${ path }.${ key }` : key), rootType, dataOptions);
|
|
236
255
|
let indented = indent(chunk);
|
|
237
256
|
|
|
238
257
|
// convert "# foo" to "#foo"
|
|
239
258
|
indented = indented.replace(/^(#)?\s\s\s\s/, '$1');
|
|
240
259
|
|
|
241
|
-
out +=
|
|
260
|
+
out += `${ indented }`;
|
|
242
261
|
}
|
|
243
262
|
|
|
244
263
|
return out;
|
|
@@ -263,7 +282,7 @@ export function createYaml(schemas, type, data, processAlwaysAdd = true, depth =
|
|
|
263
282
|
if ( SIMPLE_TYPES.includes(arrayOf) ) {
|
|
264
283
|
out += `\n# - ${ arrayOf }`;
|
|
265
284
|
} else {
|
|
266
|
-
const chunk = createYaml(schemas, arrayOf, null, false, depth + 1, (path ? `${ path }.${ key }` : key), rootType);
|
|
285
|
+
const chunk = createYaml(schemas, arrayOf, null, false, depth + 1, (path ? `${ path }.${ key }` : key), rootType, dataOptions);
|
|
267
286
|
let indented = indent(chunk, 2);
|
|
268
287
|
|
|
269
288
|
// turn "# foo" into "# - foo"
|
|
@@ -318,7 +337,7 @@ export function createYaml(schemas, type, data, processAlwaysAdd = true, depth =
|
|
|
318
337
|
let chunk;
|
|
319
338
|
|
|
320
339
|
if (subDef?.resourceFields && !isEmpty(subDef?.resourceFields)) {
|
|
321
|
-
chunk = createYaml(schemas, type, data[key], processAlwaysAdd, depth + 1, (path ? `${ path }.${ key }` : key), rootType);
|
|
340
|
+
chunk = createYaml(schemas, type, data[key], processAlwaysAdd, depth + 1, (path ? `${ path }.${ key }` : key), rootType, dataOptions);
|
|
322
341
|
} else if (data[key]) {
|
|
323
342
|
// if there are no fields defined on the schema but there are in the data, just format data as yaml and add to output yaml
|
|
324
343
|
try {
|
|
@@ -351,6 +370,43 @@ function serializeSimpleValue(data) {
|
|
|
351
370
|
return jsyaml.dump(data).trim();
|
|
352
371
|
}
|
|
353
372
|
|
|
373
|
+
export function getBlockDescriptor(value, key) {
|
|
374
|
+
const header = getBlockHeader(value, key);
|
|
375
|
+
|
|
376
|
+
return {
|
|
377
|
+
header,
|
|
378
|
+
indentation: getBlockIndentation(header),
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
*
|
|
384
|
+
* @param {string} value the block of text to be parsed
|
|
385
|
+
* @param {*} blockKey the key of the block
|
|
386
|
+
* @returns the key + the block scalar indicators, see https://yaml-multiline.info - Block Scalars
|
|
387
|
+
*/
|
|
388
|
+
function getBlockHeader(value, blockKey) {
|
|
389
|
+
const card = `(${ blockKey })[\\:][\\s|\\t]+[\\|\\>][\\d]*[\\-\\+]?`;
|
|
390
|
+
const re = new RegExp(card, 'gi');
|
|
391
|
+
|
|
392
|
+
const found = value.match(re);
|
|
393
|
+
|
|
394
|
+
return found?.[0] || '';
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
*
|
|
399
|
+
* @param {string} blockHeader the key + the block scalar indicators
|
|
400
|
+
* @returns the indentation indicator from the block header, see https://yaml-multiline.info - Indentation
|
|
401
|
+
*/
|
|
402
|
+
function getBlockIndentation(blockHeader) {
|
|
403
|
+
const blockScalars = blockHeader.substr(blockHeader.indexOf(':') + 1);
|
|
404
|
+
|
|
405
|
+
const indentation = blockScalars.match(/\d+/);
|
|
406
|
+
|
|
407
|
+
return indentation?.[0] || '';
|
|
408
|
+
}
|
|
409
|
+
|
|
354
410
|
export function typeRef(type, str) {
|
|
355
411
|
const re = new RegExp(`^${ type }\\[(.*)\\]$`);
|
|
356
412
|
const match = str.match(re);
|
|
@@ -381,3 +437,44 @@ export function saferDump(obj) {
|
|
|
381
437
|
|
|
382
438
|
return out;
|
|
383
439
|
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Handles newlines indicators in the multiline blocks.
|
|
443
|
+
*
|
|
444
|
+
* this is required since jsyaml.dump doesn't support chomping and scalar style at the moment.
|
|
445
|
+
* see: https://github.com/nodeca/js-yaml/issues/171
|
|
446
|
+
*
|
|
447
|
+
* @param {*} data the multiline block
|
|
448
|
+
* @param {*} options blocks indicators, see: https://yaml-multiline.info
|
|
449
|
+
*
|
|
450
|
+
* - scalarStyle:
|
|
451
|
+
* one of '|', '>'
|
|
452
|
+
* default '|'
|
|
453
|
+
* - chomping:
|
|
454
|
+
* one of: null, '', '-', '+'
|
|
455
|
+
* default: null
|
|
456
|
+
* @returns the result of jsyaml.dump with the addition of multiline indicators
|
|
457
|
+
*/
|
|
458
|
+
export function dumpBlock(data, options = {}) {
|
|
459
|
+
const parsed = jsyaml.dump(data);
|
|
460
|
+
|
|
461
|
+
let out = parsed;
|
|
462
|
+
|
|
463
|
+
const blockFields = Object.keys(data).filter(k => data[k].includes('\n'));
|
|
464
|
+
|
|
465
|
+
if (blockFields.length) {
|
|
466
|
+
for (const key of blockFields) {
|
|
467
|
+
const { header, indentation } = getBlockDescriptor(out, key);
|
|
468
|
+
|
|
469
|
+
const scalarStyle = options[key]?.scalarStyle ?? '|';
|
|
470
|
+
const chomping = options[key]?.chomping ?? '';
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Replace the original block indicators with the ones provided in the options param
|
|
474
|
+
*/
|
|
475
|
+
out = out.replace(header, `${ key }: ${ scalarStyle }${ chomping }${ indentation }`);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
return out;
|
|
480
|
+
}
|
|
@@ -1,13 +1,25 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const NAMESPACE_FILTER_ALL_PREFIX = 'all';
|
|
2
|
+
export const NAMESPACE_FILTER_NS_PREFIX = 'ns';
|
|
3
|
+
export const NAMESPACE_FILTER_P_PREFIX = 'project';
|
|
2
4
|
|
|
3
|
-
export const
|
|
4
|
-
export const
|
|
5
|
-
|
|
6
|
-
export const
|
|
5
|
+
export const NAMESPACE_FILTER_NS_FULL_PREFIX = `${ NAMESPACE_FILTER_NS_PREFIX }://`;
|
|
6
|
+
export const NAMESPACE_FILTER_P_FULL_PREFIX = `${ NAMESPACE_FILTER_P_PREFIX }://`;
|
|
7
|
+
|
|
8
|
+
export const NAMESPACE_FILTER_ALL = NAMESPACE_FILTER_ALL_PREFIX;
|
|
9
|
+
export const NAMESPACE_FILTER_ALL_SYSTEM = `${ NAMESPACE_FILTER_ALL_PREFIX }://system`;
|
|
10
|
+
export const NAMESPACE_FILTER_ALL_USER = `${ NAMESPACE_FILTER_ALL_PREFIX }://user`;
|
|
11
|
+
export const NAMESPACE_FILTER_ALL_ORPHANS = `${ NAMESPACE_FILTER_ALL_PREFIX }://orphans`;
|
|
7
12
|
export const NAMESPACE_FILTER_NAMESPACED_PREFIX = 'namespaced://';
|
|
8
13
|
export const NAMESPACE_FILTER_NAMESPACED_YES = 'namespaced://true';
|
|
9
14
|
export const NAMESPACE_FILTER_NAMESPACED_NO = 'namespaced://false';
|
|
10
15
|
|
|
16
|
+
export const NAMESPACE_FILTER_KINDS = {
|
|
17
|
+
DIVIDER: 'divider',
|
|
18
|
+
PROJECT: 'project',
|
|
19
|
+
NAMESPACE: 'namespace',
|
|
20
|
+
SPECIAL: 'special'
|
|
21
|
+
};
|
|
22
|
+
|
|
11
23
|
const SEPARATOR = '__%%__';
|
|
12
24
|
|
|
13
25
|
export const createNamespaceFilterKey = (clusterId, product) => {
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { NAMESPACE_FILTER_NS_FULL_PREFIX, NAMESPACE_FILTER_P_FULL_PREFIX } from '@shell/utils/namespace-filter';
|
|
2
|
+
import { getPerformanceSetting } from '@shell/utils/settings';
|
|
3
|
+
|
|
4
|
+
type Opt = { [key: string]: any, namespaced?: string[]}
|
|
5
|
+
|
|
6
|
+
class ProjectAndNamespaceFiltering {
|
|
7
|
+
static param = 'projectsornamespaces'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Does the request `opt` definition require resources are fetched from a specific set namespaces/projects?
|
|
11
|
+
*/
|
|
12
|
+
isApplicable(opt: Opt): boolean {
|
|
13
|
+
return Array.isArray(opt.namespaced);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
isEnabled(rootGetters: any): boolean {
|
|
17
|
+
const currentProduct = rootGetters['currentProduct'];
|
|
18
|
+
|
|
19
|
+
// Only enable for the cluster store at the moment. In theory this should work in management as well, as they're both 'steve' stores
|
|
20
|
+
if (currentProduct?.inStore !== 'cluster') {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (currentProduct?.showWorkspaceSwitcher) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const perfConfig = getPerformanceSetting(rootGetters);
|
|
29
|
+
|
|
30
|
+
if (!perfConfig.forceNsFilterV2?.enabled) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Check if `opt` requires resources from specific ns/projects, if so return the required query param (x=y)
|
|
39
|
+
*/
|
|
40
|
+
checkAndCreateParam(opt: Opt): string {
|
|
41
|
+
if (!this.isApplicable(opt)) {
|
|
42
|
+
return '';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return this.createParam(opt.namespaced);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private createParam(namespaceFilter: string[] | undefined): string {
|
|
49
|
+
if (!namespaceFilter || !namespaceFilter.length) {
|
|
50
|
+
return '';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const projectsOrNamespaces = namespaceFilter
|
|
54
|
+
.map(f => f.replace(NAMESPACE_FILTER_NS_FULL_PREFIX, '')
|
|
55
|
+
.replace(NAMESPACE_FILTER_P_FULL_PREFIX, ''))
|
|
56
|
+
.join(',');
|
|
57
|
+
|
|
58
|
+
return `${ ProjectAndNamespaceFiltering.param }=${ projectsOrNamespaces }`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export default new ProjectAndNamespaceFiltering();
|
package/utils/selector.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isArray, addObject, findBy } from '@shell/utils/array';
|
|
2
|
+
import { get } from '@shell/utils/object';
|
|
2
3
|
|
|
3
4
|
const parseCache = {};
|
|
4
5
|
|
|
@@ -121,7 +122,7 @@ export function convert(matchLabelsObj, matchExpressions) {
|
|
|
121
122
|
out.push({
|
|
122
123
|
key,
|
|
123
124
|
operator: 'In',
|
|
124
|
-
values: [value],
|
|
125
|
+
values: isArray(value) ? value : [value],
|
|
125
126
|
});
|
|
126
127
|
}
|
|
127
128
|
}
|
|
@@ -162,7 +163,7 @@ export function simplify(matchExpressionsInput) {
|
|
|
162
163
|
return { matchLabels, matchExpressions };
|
|
163
164
|
}
|
|
164
165
|
|
|
165
|
-
export function matches(obj, selector) {
|
|
166
|
+
export function matches(obj, selector, labelKey = 'metadata.labels') {
|
|
166
167
|
let rules = [];
|
|
167
168
|
|
|
168
169
|
if ( typeof selector === 'string' ) {
|
|
@@ -178,7 +179,7 @@ export function matches(obj, selector) {
|
|
|
178
179
|
return false;
|
|
179
180
|
}
|
|
180
181
|
|
|
181
|
-
const labels = obj
|
|
182
|
+
const labels = get(obj, labelKey) || {};
|
|
182
183
|
|
|
183
184
|
for ( const rule of rules ) {
|
|
184
185
|
const value = labels[rule.key];
|
|
@@ -222,6 +223,6 @@ export function matches(obj, selector) {
|
|
|
222
223
|
return true;
|
|
223
224
|
}
|
|
224
225
|
|
|
225
|
-
export function matching(ary, selector) {
|
|
226
|
-
return ary.filter(obj => matches(obj, selector));
|
|
226
|
+
export function matching(ary, selector, labelKey) {
|
|
227
|
+
return ary.filter(obj => matches(obj, selector, labelKey));
|
|
227
228
|
}
|
package/utils/settings.ts
CHANGED
|
@@ -22,6 +22,18 @@ export const fetchOrCreateSetting = async(store: Store<any>, id: string, val: st
|
|
|
22
22
|
return setting;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Fetch a specific setting that might not exist
|
|
27
|
+
* We fetch all settings - reality is Rancher will have done this already, so there's no overhead in doing
|
|
28
|
+
* this - but if we fetch a specific setting that does not exist, we will get a 404, which we don't want
|
|
29
|
+
*/
|
|
30
|
+
export const fetchSetting = async(store: Store<any>, id: string) => {
|
|
31
|
+
const all = await store.dispatch('management/findAll', { type: MANAGEMENT.SETTING });
|
|
32
|
+
const setting = (all || []).find((setting: any) => setting.id === id);
|
|
33
|
+
|
|
34
|
+
return setting;
|
|
35
|
+
};
|
|
36
|
+
|
|
25
37
|
export const setSetting = async(store: Store<any>, id: string, val: string): Promise<any> => {
|
|
26
38
|
const setting = await fetchOrCreateSetting(store, id, val, false);
|
|
27
39
|
|
|
@@ -32,19 +44,17 @@ export const setSetting = async(store: Store<any>, id: string, val: string): Pro
|
|
|
32
44
|
};
|
|
33
45
|
|
|
34
46
|
export const getPerformanceSetting = (rootGetters: Record<string, (arg0: string, arg1: string) => any>) => {
|
|
35
|
-
const
|
|
36
|
-
let
|
|
47
|
+
const perfSettingResource = rootGetters['management/byId'](MANAGEMENT.SETTING, SETTING.UI_PERFORMANCE);
|
|
48
|
+
let perfSetting = {};
|
|
37
49
|
|
|
38
|
-
if (
|
|
50
|
+
if (perfSettingResource?.value) {
|
|
39
51
|
try {
|
|
40
|
-
|
|
52
|
+
perfSetting = JSON.parse(perfSettingResource.value);
|
|
41
53
|
} catch (e) {
|
|
42
54
|
console.warn('ui-performance setting contains invalid data'); // eslint-disable-line no-console
|
|
43
55
|
}
|
|
44
56
|
}
|
|
45
57
|
|
|
46
58
|
// Start with the default and overwrite the values from the setting - ensures we have defaults for newly added options
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return perfConfig;
|
|
59
|
+
return Object.assign(DEFAULT_PERF_SETTING, perfSetting || {});
|
|
50
60
|
};
|
package/vue.config.js
CHANGED
|
@@ -408,8 +408,8 @@ module.exports = function(dir, _appConfig) {
|
|
|
408
408
|
}),
|
|
409
409
|
}));
|
|
410
410
|
|
|
411
|
-
// The static assets need to be in the built
|
|
412
|
-
config.plugins.push(new CopyWebpackPlugin([{ from: path.join(SHELL_ABS, 'static'), to: '
|
|
411
|
+
// The static assets need to be in the built assets directory in order to get served (primarily the favicon)
|
|
412
|
+
config.plugins.push(new CopyWebpackPlugin([{ from: path.join(SHELL_ABS, 'static'), to: '.' }]));
|
|
413
413
|
|
|
414
414
|
config.resolve.extensions.push(...['.tsx', '.ts', '.js', '.vue', '.scss']);
|
|
415
415
|
config.watchOptions = config.watchOptions || {};
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import Vue from 'vue';
|
|
2
|
-
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
3
|
-
import { HCI } from '@shell/config/labels-annotations';
|
|
4
|
-
|
|
5
|
-
export default class NetworkAttachmentDef extends SteveModel {
|
|
6
|
-
get _availableActions() {
|
|
7
|
-
let out = super._availableActions;
|
|
8
|
-
const toFilter = ['goToClone', 'cloneYaml', 'goToViewConfig', 'goToEditYaml', 'goToEdit'];
|
|
9
|
-
|
|
10
|
-
out = out.filter((action) => {
|
|
11
|
-
if (!toFilter.includes(action.action)) {
|
|
12
|
-
return action;
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
return out;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
applyDefaults() {
|
|
20
|
-
const spec = this.spec || {
|
|
21
|
-
config: JSON.stringify({
|
|
22
|
-
cniVersion: '0.3.1',
|
|
23
|
-
name: '',
|
|
24
|
-
type: 'bridge',
|
|
25
|
-
bridge: 'harvester-br0',
|
|
26
|
-
promiscMode: true,
|
|
27
|
-
vlan: '',
|
|
28
|
-
ipam: {}
|
|
29
|
-
})
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
Vue.set(this, 'spec', spec);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
get parseConfig() {
|
|
36
|
-
try {
|
|
37
|
-
return JSON.parse(this.spec.config) || {};
|
|
38
|
-
} catch (err) {
|
|
39
|
-
return {};
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
get isIpamStatic() {
|
|
44
|
-
return this.parseConfig.ipam?.type === 'static';
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
get vlanType() {
|
|
48
|
-
const type = this.parseConfig.type;
|
|
49
|
-
|
|
50
|
-
return type === 'bridge' ? 'L2VlanNetwork' : type;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
get vlanId() {
|
|
54
|
-
return this.parseConfig.vlan;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
get customValidationRules() {
|
|
58
|
-
const rules = [
|
|
59
|
-
{
|
|
60
|
-
nullable: false,
|
|
61
|
-
path: 'metadata.name',
|
|
62
|
-
required: true,
|
|
63
|
-
minLength: 1,
|
|
64
|
-
maxLength: 63,
|
|
65
|
-
translationKey: 'harvester.fields.name'
|
|
66
|
-
}
|
|
67
|
-
];
|
|
68
|
-
|
|
69
|
-
return rules;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
get connectivity() {
|
|
73
|
-
const annotations = this.metadata?.annotations || {};
|
|
74
|
-
const route = annotations[HCI.NETWORK_ROUTE];
|
|
75
|
-
let config = {};
|
|
76
|
-
|
|
77
|
-
try {
|
|
78
|
-
config = JSON.parse(route || '{}');
|
|
79
|
-
} catch {
|
|
80
|
-
return 'invalid';
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const connectivity = config.connectivity;
|
|
84
|
-
|
|
85
|
-
if (connectivity === 'false') {
|
|
86
|
-
return 'inactive';
|
|
87
|
-
} else if (connectivity === 'true') {
|
|
88
|
-
return 'active';
|
|
89
|
-
} else {
|
|
90
|
-
return connectivity;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|