@rancher/shell 0.3.9 → 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.
Files changed (127) hide show
  1. package/assets/translations/en-us.yaml +19 -24
  2. package/assets/translations/zh-hans.yaml +82 -16
  3. package/chart/istio.vue +11 -11
  4. package/chart/rancher-backup/S3.vue +1 -1
  5. package/components/AsyncButton.vue +2 -2
  6. package/components/ButtonGroup.vue +1 -1
  7. package/components/CompoundStatusBadge.vue +1 -1
  8. package/components/CopyCode.vue +1 -1
  9. package/components/DetailTop.vue +1 -1
  10. package/components/ExplorerProjectsNamespaces.vue +3 -3
  11. package/components/GlobalRoleBindings.vue +1 -1
  12. package/components/HarvesterServiceAddOnConfig.vue +2 -117
  13. package/components/ResourceDetail/Masthead.vue +1 -1
  14. package/components/ResourceList/Masthead.vue +0 -6
  15. package/components/ResourceList/ResourceLoadingIndicator.vue +1 -9
  16. package/components/ResourceList/index.vue +7 -6
  17. package/components/ResourceTable.vue +13 -3
  18. package/components/SortableTable/THead.vue +3 -3
  19. package/components/SortableTable/index.vue +3 -3
  20. package/components/Tabbed/Tab.vue +1 -1
  21. package/components/Tabbed/index.vue +1 -1
  22. package/components/Wizard.vue +9 -6
  23. package/components/__tests__/NamespaceFilter.test.ts +26 -7
  24. package/components/auth/RoleDetailEdit.vue +1 -1
  25. package/components/auth/SelectPrincipal.vue +1 -1
  26. package/components/fleet/FleetRepos.vue +1 -1
  27. package/components/form/ArrayList.vue +1 -1
  28. package/components/form/KeyValue.vue +3 -2
  29. package/components/form/Labels.vue +34 -14
  30. package/components/form/Members/ClusterPermissionsEditor.vue +1 -1
  31. package/components/form/NameNsDescription.vue +1 -1
  32. package/components/form/PlusMinus.vue +2 -2
  33. package/components/form/Probe.vue +1 -1
  34. package/components/form/ProjectMemberEditor.vue +8 -4
  35. package/components/form/ResourceQuota/NamespaceRow.vue +1 -1
  36. package/components/form/ServicePorts.vue +2 -2
  37. package/components/form/Tolerations.vue +30 -3
  38. package/components/form/WorkloadPorts.vue +2 -1
  39. package/components/form/__tests__/KeyValue.test.ts +17 -0
  40. package/components/formatter/ClusterLink.vue +3 -3
  41. package/components/formatter/LiveDate.vue +1 -1
  42. package/components/formatter/PodImages.vue +1 -1
  43. package/components/formatter/RKETemplateName.vue +1 -1
  44. package/components/formatter/Shortened.vue +1 -1
  45. package/components/nav/Header.vue +7 -7
  46. package/components/nav/NamespaceFilter.vue +103 -54
  47. package/config/labels-annotations.js +8 -5
  48. package/config/settings.ts +2 -5
  49. package/config/types.js +6 -4
  50. package/core/plugin-routes.ts +26 -7
  51. package/core/plugins-loader.js +2 -0
  52. package/detail/provisioning.cattle.io.cluster.vue +4 -4
  53. package/edit/cis.cattle.io.clusterscan.vue +1 -1
  54. package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +19 -149
  55. package/edit/logging-flow/index.vue +2 -2
  56. package/edit/logging.banzaicloud.io.output/providers/elasticsearch.vue +12 -0
  57. package/edit/logging.banzaicloud.io.output/providers/opensearch.vue +12 -0
  58. package/edit/management.cattle.io.project.vue +7 -0
  59. package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +1 -1
  60. package/edit/monitoring.coreos.com.alertmanagerconfig/routeConfig.vue +2 -2
  61. package/edit/monitoring.coreos.com.prometheusrule/GroupRules.vue +11 -8
  62. package/edit/networking.k8s.io.networkpolicy/PolicyRule.vue +2 -2
  63. package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +12 -4
  64. package/edit/networking.k8s.io.networkpolicy/__tests__/PolicyRuleTarget.spec.ts +140 -0
  65. package/edit/networking.k8s.io.networkpolicy/__tests__/utils/mock.json +158 -0
  66. package/edit/networking.k8s.io.networkpolicy/__tests__/utils/selectors.ts +45 -0
  67. package/edit/networking.k8s.io.networkpolicy/index.vue +1 -1
  68. package/edit/provisioning.cattle.io.cluster/AgentConfiguration.vue +1 -1
  69. package/edit/provisioning.cattle.io.cluster/MachinePool.vue +1 -1
  70. package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +1 -1
  71. package/edit/provisioning.cattle.io.cluster/RegistryMirrors.vue +2 -2
  72. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +143 -169
  73. package/edit/provisioning.cattle.io.cluster/rke2.vue +15 -6
  74. package/edit/resources.cattle.io.restore.vue +2 -2
  75. package/edit/service.vue +22 -3
  76. package/edit/storage.k8s.io.storageclass/index.vue +1 -1
  77. package/edit/workload/Job.vue +2 -2
  78. package/edit/workload/index.vue +1 -1
  79. package/edit/workload/mixins/workload.js +7 -1
  80. package/edit/workload/storage/__tests__/Storage.test.ts +84 -5
  81. package/initialize/index.js +1 -0
  82. package/layouts/default.vue +1 -1
  83. package/mixins/resource-fetch-namespaced.js +19 -27
  84. package/mixins/resource-fetch.js +0 -5
  85. package/models/__tests__/namespace.test.ts +125 -0
  86. package/models/management.cattle.io.project.js +6 -1
  87. package/models/persistentvolume.js +1 -1
  88. package/models/workload.service.js +22 -7
  89. package/package.json +17 -5
  90. package/pages/auth/login.vue +46 -49
  91. package/pages/c/_cluster/apps/charts/chart.vue +1 -1
  92. package/pages/c/_cluster/apps/charts/install.vue +42 -51
  93. package/pages/c/_cluster/explorer/index.vue +1 -1
  94. package/pages/c/_cluster/monitoring/index.vue +1 -1
  95. package/pages/c/_cluster/settings/performance.vue +53 -18
  96. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +1 -1
  97. package/pages/c/_cluster/uiplugins/index.vue +16 -5
  98. package/pages/home.vue +1 -1
  99. package/pkg/vue.config.js +1 -0
  100. package/plugins/clean-html-directive.js +1 -1
  101. package/plugins/clean-tooltip-directive.js +33 -0
  102. package/plugins/dashboard-store/actions.js +4 -2
  103. package/plugins/dashboard-store/getters.js +6 -0
  104. package/plugins/dashboard-store/mutations.js +2 -2
  105. package/plugins/plugin.js +6 -1
  106. package/plugins/steve/actions.js +1 -1
  107. package/plugins/steve/getters.js +14 -3
  108. package/plugins/steve/resourceWatcher.js +36 -62
  109. package/plugins/steve/subscribe.js +137 -21
  110. package/plugins/steve/worker/index.js +7 -1
  111. package/plugins/steve/worker/web-worker.advanced.js +26 -8
  112. package/plugins/steve/worker/web-worker.basic.js +23 -4
  113. package/rancher-components/components/Form/Checkbox/Checkbox.vue +2 -2
  114. package/rancher-components/components/Form/Radio/RadioGroup.vue +2 -2
  115. package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +1 -1
  116. package/store/index.js +16 -61
  117. package/store/store-types.js +5 -0
  118. package/store/type-map.js +1 -1
  119. package/types/shell/index.d.ts +23 -7
  120. package/utils/__tests__/create-yaml.test.ts +63 -0
  121. package/utils/array.ts +4 -0
  122. package/utils/create-yaml.js +5 -5
  123. package/utils/namespace-filter.js +17 -5
  124. package/utils/projectAndNamespaceFiltering.utils.ts +62 -0
  125. package/utils/selector.js +6 -5
  126. package/utils/settings.ts +5 -7
  127. package/models/k8s.cni.cncf.io.networkattachmentdefinition.js +0 -93
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: 'management',
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: 'cluster',
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: 'rancher',
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
- return state.isMultiCluster === true;
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('ns://');
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, isMultiCluster, isRancher }) {
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
- let isMultiCluster = true;
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
@@ -0,0 +1,5 @@
1
+ export const STORE = {
2
+ CLUSTER: 'cluster',
3
+ RANCHER: 'rancher',
4
+ MANAGEMENT: 'management',
5
+ };
package/store/type-map.js CHANGED
@@ -971,7 +971,7 @@ export const getters = {
971
971
 
972
972
  groupByFor(state) {
973
973
  return (schema) => {
974
- return state.groupBy[schema.id];
974
+ return state.groupBy[schema?.id];
975
975
  };
976
976
  },
977
977
 
@@ -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 {
@@ -2493,6 +2495,10 @@ export default _default;
2493
2495
  declare module '@shell/utils/create-yaml' {
2494
2496
  export function createYamlWithOptions(schemas: any, type: any, data: any, options: any): string;
2495
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
+ };
2496
2502
  export function typeRef(type: any, str: any): any;
2497
2503
  export function typeMunge(type: any): any;
2498
2504
  export function saferDump(obj: any): any;
@@ -2509,7 +2515,7 @@ export function saferDump(obj: any): any;
2509
2515
  * one of '|', '>'
2510
2516
  * default '|'
2511
2517
  * - chomping:
2512
- * one of: null, '-', '+'
2518
+ * one of: null, '', '-', '+'
2513
2519
  * default: null
2514
2520
  * @returns the result of jsyaml.dump with the addition of multiline indicators
2515
2521
  */
@@ -2674,14 +2680,24 @@ export function haveV1MonitoringWorkloads(store: any): Promise<boolean>;
2674
2680
  // @shell/utils/namespace-filter
2675
2681
 
2676
2682
  declare module '@shell/utils/namespace-filter' {
2677
- export const NAMESPACE_FILTER_SPECIAL: "special";
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;
2678
2688
  export const NAMESPACE_FILTER_ALL: "all";
2679
- export const NAMESPACE_FILTER_ALL_SYSTEM: "all://system";
2680
- export const NAMESPACE_FILTER_ALL_USER: "all://user";
2681
- export const NAMESPACE_FILTER_ALL_ORPHANS: "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;
2682
2692
  export const NAMESPACE_FILTER_NAMESPACED_PREFIX: "namespaced://";
2683
2693
  export const NAMESPACE_FILTER_NAMESPACED_YES: "namespaced://true";
2684
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
+ }
2685
2701
  export function createNamespaceFilterKey(clusterId: any, product: any): any;
2686
2702
  export function createNamespaceFilterKeyWithId(clusterId: any, productId: any): string;
2687
2703
  export function splitNamespaceFilterKey(key: any): {
@@ -2945,8 +2961,8 @@ export function simplify(matchExpressionsInput: any): {
2945
2961
  matchLabels: {};
2946
2962
  matchExpressions: any[];
2947
2963
  };
2948
- export function matches(obj: any, selector: any): boolean;
2949
- 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;
2950
2966
  }
2951
2967
 
2952
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) => {
@@ -370,7 +370,7 @@ function serializeSimpleValue(data) {
370
370
  return jsyaml.dump(data).trim();
371
371
  }
372
372
 
373
- function getBlockDescriptor(value, key) {
373
+ export function getBlockDescriptor(value, key) {
374
374
  const header = getBlockHeader(value, key);
375
375
 
376
376
  return {
@@ -451,7 +451,7 @@ export function saferDump(obj) {
451
451
  * one of '|', '>'
452
452
  * default '|'
453
453
  * - chomping:
454
- * one of: null, '-', '+'
454
+ * one of: null, '', '-', '+'
455
455
  * default: null
456
456
  * @returns the result of jsyaml.dump with the addition of multiline indicators
457
457
  */
@@ -464,15 +464,15 @@ export function dumpBlock(data, options = {}) {
464
464
 
465
465
  if (blockFields.length) {
466
466
  for (const key of blockFields) {
467
+ const { header, indentation } = getBlockDescriptor(out, key);
468
+
467
469
  const scalarStyle = options[key]?.scalarStyle ?? '|';
468
470
  const chomping = options[key]?.chomping ?? '';
469
471
 
470
- const desc = getBlockDescriptor(out, key);
471
-
472
472
  /**
473
473
  * Replace the original block indicators with the ones provided in the options param
474
474
  */
475
- out = out.replace(desc.header, `${ key }: ${ scalarStyle }${ chomping }${ desc.indentation }`);
475
+ out = out.replace(header, `${ key }: ${ scalarStyle }${ chomping }${ indentation }`);
476
476
  }
477
477
  }
478
478
 
@@ -1,13 +1,25 @@
1
- export const NAMESPACE_FILTER_SPECIAL = 'special';
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 NAMESPACE_FILTER_ALL = 'all';
4
- export const NAMESPACE_FILTER_ALL_SYSTEM = 'all://system';
5
- export const NAMESPACE_FILTER_ALL_USER = 'all://user';
6
- export const NAMESPACE_FILTER_ALL_ORPHANS = 'all://orphans';
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?.metadata?.labels || {};
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
@@ -44,19 +44,17 @@ export const setSetting = async(store: Store<any>, id: string, val: string): Pro
44
44
  };
45
45
 
46
46
  export const getPerformanceSetting = (rootGetters: Record<string, (arg0: string, arg1: string) => any>) => {
47
- const perfSetting = rootGetters['management/byId'](MANAGEMENT.SETTING, SETTING.UI_PERFORMANCE);
48
- let perfConfig = {};
47
+ const perfSettingResource = rootGetters['management/byId'](MANAGEMENT.SETTING, SETTING.UI_PERFORMANCE);
48
+ let perfSetting = {};
49
49
 
50
- if (perfSetting && perfSetting.value) {
50
+ if (perfSettingResource?.value) {
51
51
  try {
52
- perfConfig = JSON.parse(perfSetting.value);
52
+ perfSetting = JSON.parse(perfSettingResource.value);
53
53
  } catch (e) {
54
54
  console.warn('ui-performance setting contains invalid data'); // eslint-disable-line no-console
55
55
  }
56
56
  }
57
57
 
58
58
  // Start with the default and overwrite the values from the setting - ensures we have defaults for newly added options
59
- perfConfig = Object.assign(DEFAULT_PERF_SETTING, perfConfig);
60
-
61
- return perfConfig;
59
+ return Object.assign(DEFAULT_PERF_SETTING, perfSetting || {});
62
60
  };
@@ -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
- }