@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.
- package/assets/translations/en-us.yaml +19 -24
- package/assets/translations/zh-hans.yaml +82 -16
- 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/CompoundStatusBadge.vue +1 -1
- package/components/CopyCode.vue +1 -1
- package/components/DetailTop.vue +1 -1
- package/components/ExplorerProjectsNamespaces.vue +3 -3
- package/components/GlobalRoleBindings.vue +1 -1
- 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/__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 +1 -1
- package/components/form/KeyValue.vue +3 -2
- package/components/form/Labels.vue +34 -14
- package/components/form/Members/ClusterPermissionsEditor.vue +1 -1
- package/components/form/NameNsDescription.vue +1 -1
- package/components/form/PlusMinus.vue +2 -2
- 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 +30 -3
- package/components/form/WorkloadPorts.vue +2 -1
- package/components/form/__tests__/KeyValue.test.ts +17 -0
- 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 +7 -7
- package/components/nav/NamespaceFilter.vue +103 -54
- package/config/labels-annotations.js +8 -5
- package/config/settings.ts +2 -5
- package/config/types.js +6 -4
- package/core/plugin-routes.ts +26 -7
- package/core/plugins-loader.js +2 -0
- package/detail/provisioning.cattle.io.cluster.vue +4 -4
- package/edit/cis.cattle.io.clusterscan.vue +1 -1
- 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 +1 -1
- 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/rke2.vue +15 -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/resource-fetch-namespaced.js +19 -27
- package/mixins/resource-fetch.js +0 -5
- package/models/__tests__/namespace.test.ts +125 -0
- package/models/management.cattle.io.project.js +6 -1
- package/models/persistentvolume.js +1 -1
- package/models/workload.service.js +22 -7
- package/package.json +17 -5
- package/pages/auth/login.vue +46 -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/pkg/vue.config.js +1 -0
- package/plugins/clean-html-directive.js +1 -1
- package/plugins/clean-tooltip-directive.js +33 -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/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 +23 -7
- package/utils/__tests__/create-yaml.test.ts +63 -0
- package/utils/array.ts +4 -0
- package/utils/create-yaml.js +5 -5
- package/utils/namespace-filter.js +17 -5
- package/utils/projectAndNamespaceFiltering.utils.ts +62 -0
- package/utils/selector.js +6 -5
- package/utils/settings.ts +5 -7
- 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:
|
|
46
|
+
namespace: STORE.MANAGEMENT,
|
|
45
47
|
baseUrl: '/v1',
|
|
46
48
|
modelBaseClass: BY_TYPE,
|
|
47
49
|
supportsStream: false, // true, -- Disabled due to report that it's sometimes much slower in Chrome
|
|
48
50
|
}),
|
|
49
51
|
Steve({
|
|
50
|
-
namespace:
|
|
52
|
+
namespace: STORE.CLUSTER,
|
|
51
53
|
baseUrl: '', // URL is dynamically set for the selected cluster
|
|
52
54
|
supportsStream: false, // true, -- Disabled due to report that it's sometimes much slower in Chrome
|
|
53
55
|
supportsGc: true, // Enable garbage collection for this store only
|
|
54
56
|
}),
|
|
55
57
|
Steve({
|
|
56
|
-
namespace:
|
|
58
|
+
namespace: STORE.RANCHER,
|
|
57
59
|
baseUrl: '/v3',
|
|
58
60
|
supportsStream: false, // The norman API doesn't support streaming
|
|
59
61
|
modelBaseClass: STEVE_MODEL_TYPES.NORMAN,
|
|
@@ -225,7 +227,6 @@ export const state = () => {
|
|
|
225
227
|
return {
|
|
226
228
|
managementReady: false,
|
|
227
229
|
clusterReady: false,
|
|
228
|
-
isMultiCluster: false,
|
|
229
230
|
isRancher: false,
|
|
230
231
|
namespaceFilters: [],
|
|
231
232
|
activeNamespaceCache: {}, // Used to efficiently check if a resource should be displayed
|
|
@@ -241,7 +242,6 @@ export const state = () => {
|
|
|
241
242
|
serverVersion: null,
|
|
242
243
|
systemNamespaces: [],
|
|
243
244
|
isSingleProduct: undefined,
|
|
244
|
-
namespaceFilterMode: null,
|
|
245
245
|
};
|
|
246
246
|
};
|
|
247
247
|
|
|
@@ -250,8 +250,14 @@ export const getters = {
|
|
|
250
250
|
return state.clusterReady === true;
|
|
251
251
|
},
|
|
252
252
|
|
|
253
|
-
isMultiCluster(state) {
|
|
254
|
-
|
|
253
|
+
isMultiCluster(state, getters) {
|
|
254
|
+
const clusters = getters['management/all'](MANAGEMENT.CLUSTER);
|
|
255
|
+
|
|
256
|
+
if (clusters.length === 1 && clusters[0].metadata?.name === 'local') {
|
|
257
|
+
return false;
|
|
258
|
+
} else {
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
255
261
|
},
|
|
256
262
|
|
|
257
263
|
isRancher(state) {
|
|
@@ -278,15 +284,6 @@ export const getters = {
|
|
|
278
284
|
return state.systemNamespaces;
|
|
279
285
|
},
|
|
280
286
|
|
|
281
|
-
/**
|
|
282
|
-
* Namespace Filter Mode supplies a resource type to the NamespaceFilter.
|
|
283
|
-
*
|
|
284
|
-
* Only one of the resource type is allowed to be selected
|
|
285
|
-
*/
|
|
286
|
-
namespaceFilterMode(state) {
|
|
287
|
-
return state.namespaceFilterMode;
|
|
288
|
-
},
|
|
289
|
-
|
|
290
287
|
currentCluster(state, getters) {
|
|
291
288
|
return getters['management/byId'](MANAGEMENT.CLUSTER, state.clusterId);
|
|
292
289
|
},
|
|
@@ -372,34 +369,6 @@ export const getters = {
|
|
|
372
369
|
return state.namespaceFilters.filter(x => !`${ x }`.startsWith(NAMESPACED_PREFIX)).length === 0;
|
|
373
370
|
},
|
|
374
371
|
|
|
375
|
-
isSingleNamespace(state, getters) {
|
|
376
|
-
const product = getters['currentProduct'];
|
|
377
|
-
|
|
378
|
-
if ( !product ) {
|
|
379
|
-
return false;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
if ( product.showWorkspaceSwitcher ) {
|
|
383
|
-
return false;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
if ( getters.isAllNamespaces ) {
|
|
387
|
-
return false;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
const filters = state.namespaceFilters;
|
|
391
|
-
|
|
392
|
-
if ( filters.length !== 1 ) {
|
|
393
|
-
return false;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
if (filters[0].startsWith('ns://')) {
|
|
397
|
-
return filters[0];
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
return false;
|
|
401
|
-
},
|
|
402
|
-
|
|
403
372
|
isMultipleNamespaces(state, getters) {
|
|
404
373
|
const product = getters['currentProduct'];
|
|
405
374
|
|
|
@@ -421,7 +390,7 @@ export const getters = {
|
|
|
421
390
|
return true;
|
|
422
391
|
}
|
|
423
392
|
|
|
424
|
-
return !filters[0].startsWith(
|
|
393
|
+
return !filters[0].startsWith(NAMESPACE_FILTER_NS_FULL_PREFIX);
|
|
425
394
|
},
|
|
426
395
|
|
|
427
396
|
namespaceFilters(state) {
|
|
@@ -591,9 +560,8 @@ export const getters = {
|
|
|
591
560
|
};
|
|
592
561
|
|
|
593
562
|
export const mutations = {
|
|
594
|
-
managementChanged(state, { ready,
|
|
563
|
+
managementChanged(state, { ready, isRancher }) {
|
|
595
564
|
state.managementReady = ready;
|
|
596
|
-
state.isMultiCluster = isMultiCluster;
|
|
597
565
|
state.isRancher = isRancher;
|
|
598
566
|
},
|
|
599
567
|
clusterReady(state, ready) {
|
|
@@ -621,10 +589,6 @@ export const mutations = {
|
|
|
621
589
|
state.allNamespaces = namespace;
|
|
622
590
|
},
|
|
623
591
|
|
|
624
|
-
setNamespaceFilterMode(state, mode) {
|
|
625
|
-
state.namespaceFilterMode = mode;
|
|
626
|
-
},
|
|
627
|
-
|
|
628
592
|
pageActions(state, pageActions) {
|
|
629
593
|
state.pageActions = pageActions;
|
|
630
594
|
},
|
|
@@ -747,11 +711,7 @@ export const actions = {
|
|
|
747
711
|
|
|
748
712
|
res = await allHash(promises);
|
|
749
713
|
dispatch('i18n/init');
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
if ( res.clusters.length === 1 && res.clusters[0].metadata?.name === 'local' ) {
|
|
753
|
-
isMultiCluster = false;
|
|
754
|
-
}
|
|
714
|
+
const isMultiCluster = getters['isMultiCluster'];
|
|
755
715
|
|
|
756
716
|
const pl = res.settings?.find(x => x.id === 'ui-pl')?.value;
|
|
757
717
|
const brand = res.settings?.find(x => x.id === SETTING.BRAND)?.value;
|
|
@@ -773,7 +733,6 @@ export const actions = {
|
|
|
773
733
|
|
|
774
734
|
commit('managementChanged', {
|
|
775
735
|
ready: true,
|
|
776
|
-
isMultiCluster,
|
|
777
736
|
isRancher,
|
|
778
737
|
});
|
|
779
738
|
|
|
@@ -967,10 +926,6 @@ export const actions = {
|
|
|
967
926
|
commit('updateNamespaces', { filters: ids });
|
|
968
927
|
},
|
|
969
928
|
|
|
970
|
-
setNamespaceFilterMode({ commit }, mode) {
|
|
971
|
-
commit('setNamespaceFilterMode', mode);
|
|
972
|
-
},
|
|
973
|
-
|
|
974
929
|
async cleanNamespaces({ getters, dispatch }) {
|
|
975
930
|
// Initialise / Remove any filters that the user no-longer has access to
|
|
976
931
|
await dispatch('management/findAll', { type: MANAGEMENT.CLUSTER }); // So they can be got byId below
|
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 {
|
|
@@ -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
|
|
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:
|
|
2680
|
-
export const NAMESPACE_FILTER_ALL_USER:
|
|
2681
|
-
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;
|
|
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) => {
|
package/utils/create-yaml.js
CHANGED
|
@@ -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(
|
|
475
|
+
out = out.replace(header, `${ key }: ${ scalarStyle }${ chomping }${ indentation }`);
|
|
476
476
|
}
|
|
477
477
|
}
|
|
478
478
|
|
|
@@ -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
|
@@ -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
|
|
48
|
-
let
|
|
47
|
+
const perfSettingResource = rootGetters['management/byId'](MANAGEMENT.SETTING, SETTING.UI_PERFORMANCE);
|
|
48
|
+
let perfSetting = {};
|
|
49
49
|
|
|
50
|
-
if (
|
|
50
|
+
if (perfSettingResource?.value) {
|
|
51
51
|
try {
|
|
52
|
-
|
|
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
|
-
|
|
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
|
-
}
|