@rancher/shell 3.0.8-rc.7 → 3.0.8-rc.9
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/brand/suse/dark/rancher-logo.svg +1 -64
- package/assets/translations/en-us.yaml +9 -1
- package/components/BackLink.vue +8 -0
- package/components/BannerGraphic.vue +1 -5
- package/components/BrandImage.vue +17 -6
- package/components/Cron/CronExpressionEditor.vue +1 -1
- package/components/Cron/CronExpressionEditorModal.vue +1 -1
- package/components/Drawer/Chrome.vue +2 -6
- package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +4 -9
- package/components/Drawer/ResourceDetailDrawer/YamlTab.vue +3 -8
- package/components/Drawer/ResourceDetailDrawer/composables.ts +3 -4
- package/components/Drawer/ResourceDetailDrawer/index.vue +4 -9
- package/components/Drawer/ResourceDetailDrawer/types.ts +17 -0
- package/components/Drawer/types.ts +3 -0
- package/components/PaginatedResourceTable.vue +2 -6
- package/components/Questions/__tests__/index.test.ts +159 -0
- package/components/Resource/Detail/Metadata/Annotations/index.vue +2 -2
- package/components/Resource/Detail/Metadata/Labels/index.vue +2 -2
- package/components/Resource/Detail/Metadata/composables.ts +9 -9
- package/components/Resource/Detail/Metadata/index.vue +3 -3
- package/components/Resource/Detail/TitleBar/composables.ts +2 -1
- package/components/Resource/Detail/composables.ts +12 -0
- package/components/Tabbed/__tests__/index.test.ts +86 -0
- package/components/auth/SelectPrincipal.vue +24 -6
- package/components/auth/__tests__/SelectPrincipal.test.ts +119 -0
- package/components/formatter/InternalExternalIP.vue +4 -1
- package/components/formatter/__tests__/InternalExternalIP.test.ts +1 -1
- package/components/nav/Header.vue +1 -2
- package/components/nav/TopLevelMenu.helper.ts +16 -6
- package/components/templates/standalone.vue +1 -1
- package/composables/useI18n.ts +10 -1
- package/config/__test__/uiplugins.test.ts +309 -0
- package/config/labels-annotations.js +1 -0
- package/config/product/explorer.js +3 -1
- package/config/router/routes.js +6 -2
- package/config/types.js +7 -0
- package/config/uiplugins.js +46 -2
- package/core/__test__/extension-manager-impl.test.js +236 -0
- package/core/extension-manager-impl.js +23 -6
- package/core/types-provisioning.ts +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +1 -0
- package/dialog/DeveloperLoadExtensionDialog.vue +12 -3
- package/dialog/RollbackWorkloadDialog.vue +2 -5
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +2 -2
- package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -0
- package/edit/configmap.vue +1 -0
- package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
- package/edit/fleet.cattle.io.helmop.vue +6 -6
- package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
- package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +1 -0
- package/edit/logging-flow/index.vue +1 -0
- package/edit/logging.banzaicloud.io.output/index.vue +1 -0
- package/edit/management.cattle.io.fleetworkspace.vue +1 -1
- package/edit/management.cattle.io.project.vue +1 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +4 -1
- package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +2 -1
- package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -0
- package/edit/monitoring.coreos.com.receiver/index.vue +2 -1
- package/edit/monitoring.coreos.com.route.vue +1 -1
- package/edit/namespace.vue +1 -0
- package/edit/networking.istio.io.destinationrule/index.vue +1 -0
- package/edit/networking.k8s.io.ingress/index.vue +1 -0
- package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +1 -0
- package/edit/networking.k8s.io.networkpolicy/index.vue +1 -0
- package/edit/node.vue +1 -0
- package/edit/persistentvolume/index.vue +27 -22
- package/edit/persistentvolume/plugins/awsElasticBlockStore.vue +13 -14
- package/edit/persistentvolume/plugins/azureDisk.vue +49 -48
- package/edit/persistentvolume/plugins/azureFile.vue +15 -14
- package/edit/persistentvolume/plugins/cephfs.vue +15 -14
- package/edit/persistentvolume/plugins/cinder.vue +15 -14
- package/edit/persistentvolume/plugins/csi.vue +18 -16
- package/edit/persistentvolume/plugins/fc.vue +13 -14
- package/edit/persistentvolume/plugins/flexVolume.vue +15 -14
- package/edit/persistentvolume/plugins/flocker.vue +1 -3
- package/edit/persistentvolume/plugins/gcePersistentDisk.vue +13 -14
- package/edit/persistentvolume/plugins/glusterfs.vue +15 -14
- package/edit/persistentvolume/plugins/hostPath.vue +40 -39
- package/edit/persistentvolume/plugins/iscsi.vue +13 -14
- package/edit/persistentvolume/plugins/local.vue +1 -3
- package/edit/persistentvolume/plugins/longhorn.vue +23 -22
- package/edit/persistentvolume/plugins/nfs.vue +15 -14
- package/edit/persistentvolume/plugins/photonPersistentDisk.vue +1 -14
- package/edit/persistentvolume/plugins/portworxVolume.vue +15 -14
- package/edit/persistentvolume/plugins/quobyte.vue +15 -14
- package/edit/persistentvolume/plugins/rbd.vue +15 -14
- package/edit/persistentvolume/plugins/scaleIO.vue +15 -14
- package/edit/persistentvolume/plugins/storageos.vue +15 -14
- package/edit/persistentvolume/plugins/vsphereVolume.vue +1 -3
- package/edit/provisioning.cattle.io.cluster/rke2.vue +1 -0
- package/edit/secret/index.vue +1 -1
- package/edit/service.vue +1 -0
- package/edit/serviceaccount.vue +1 -0
- package/edit/storage.k8s.io.storageclass/index.vue +1 -0
- package/edit/workload/index.vue +2 -1
- package/edit/workload/mixins/workload.js +1 -1
- package/initialize/App.vue +4 -4
- package/initialize/install-plugins.js +17 -2
- package/machine-config/components/EC2Networking.vue +5 -2
- package/machine-config/components/__tests__/EC2Networking.test.ts +24 -0
- package/mixins/__tests__/brand.spec.ts +2 -2
- package/mixins/__tests__/chart.test.ts +21 -0
- package/mixins/brand.js +1 -7
- package/mixins/chart.js +7 -1
- package/mixins/create-edit-view/index.js +5 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +112 -5
- package/models/management.cattle.io.cluster.js +21 -3
- package/models/provisioning.cattle.io.cluster.js +21 -9
- package/package.json +5 -4
- package/pages/auth/login.vue +1 -3
- package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +135 -0
- package/pages/c/_cluster/apps/charts/chart.vue +33 -15
- package/pages/c/_cluster/explorer/index.vue +8 -6
- package/pages/c/_cluster/manager/hostedprovider/index.vue +12 -6
- package/pages/c/_cluster/settings/brand.vue +1 -1
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +7 -0
- package/pages/c/_cluster/uiplugins/catalogs.vue +147 -0
- package/pages/c/_cluster/uiplugins/index.vue +126 -184
- package/pages/home.vue +5 -2
- package/pkg/dynamic-importer.lib.js +4 -0
- package/plugins/dashboard-client-init.js +3 -0
- package/plugins/dashboard-store/getters.js +18 -1
- package/plugins/dashboard-store/resource-class.js +4 -4
- package/plugins/i18n.js +8 -0
- package/plugins/steve/__tests__/steve-pagination-utils.test.ts +333 -0
- package/plugins/steve/steve-pagination-utils.ts +39 -20
- package/plugins/steve/subscribe.js +17 -9
- package/plugins/subscribe-events.ts +4 -2
- package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +6 -42
- package/rancher-components/Pill/RcStatusBadge/index.ts +0 -1
- package/rancher-components/Pill/RcStatusBadge/types.ts +1 -1
- package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +5 -28
- package/rancher-components/Pill/RcStatusIndicator/types.ts +2 -1
- package/rancher-components/Pill/types.ts +0 -1
- package/rancher-components/RcIcon/RcIcon.test.ts +51 -0
- package/rancher-components/RcIcon/RcIcon.vue +46 -0
- package/rancher-components/RcIcon/index.ts +1 -0
- package/rancher-components/RcIcon/types.ts +160 -0
- package/rancher-components/utils/status.test.ts +67 -0
- package/rancher-components/utils/status.ts +77 -0
- package/scripts/typegen.sh +1 -0
- package/store/action-menu.js +8 -0
- package/store/auth.js +3 -3
- package/store/catalog.js +6 -0
- package/store/index.js +36 -17
- package/store/prefs.js +4 -5
- package/store/type-map.js +3 -3
- package/store/wm.ts +4 -4
- package/types/shell/index.d.ts +39 -2
- package/types/store/__tests__/pagination.types.spec.ts +137 -0
- package/types/store/pagination.types.ts +157 -9
- package/types/store/subscribe-events.types.ts +8 -1
- package/types/store/subscribe.types.ts +1 -0
- package/utils/__tests__/provider.test.ts +98 -0
- package/utils/__tests__/selector-typed.test.ts +263 -0
- package/utils/__tests__/version.test.ts +19 -1
- package/utils/back-off.ts +3 -3
- package/utils/color.js +1 -1
- package/utils/dynamic-content/__tests__/info.test.ts +21 -9
- package/utils/dynamic-content/info.ts +44 -2
- package/utils/favicon.js +4 -4
- package/utils/pagination-wrapper.ts +12 -8
- package/utils/provider.ts +14 -0
- package/utils/selector-typed.ts +6 -2
- package/utils/version.js +15 -0
- package/plugins/nuxt-client-init.js +0 -3
package/types/shell/index.d.ts
CHANGED
|
@@ -79,6 +79,7 @@ export namespace CATALOG {
|
|
|
79
79
|
let _RANCHER: string;
|
|
80
80
|
let _PARTNER: string;
|
|
81
81
|
let _OTHER: string;
|
|
82
|
+
let PRIME_ONLY: string;
|
|
82
83
|
let EXPERIMENTAL: string;
|
|
83
84
|
let NAMESPACE: string;
|
|
84
85
|
let RELEASE_NAME: string;
|
|
@@ -2206,6 +2207,12 @@ export namespace MANAGEMENT {
|
|
|
2206
2207
|
export let CLUSTER_PROXY_CONFIG: string;
|
|
2207
2208
|
export let OIDC_CLIENT: string;
|
|
2208
2209
|
}
|
|
2210
|
+
export namespace BRAND {
|
|
2211
|
+
let SUSE: string;
|
|
2212
|
+
let CSP: string;
|
|
2213
|
+
let FEDERAL: string;
|
|
2214
|
+
let RGS: string;
|
|
2215
|
+
}
|
|
2209
2216
|
export namespace EXT {
|
|
2210
2217
|
let USER_ACTIVITY: string;
|
|
2211
2218
|
}
|
|
@@ -2442,6 +2449,10 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
2442
2449
|
type: BooleanConstructor;
|
|
2443
2450
|
default: any;
|
|
2444
2451
|
};
|
|
2452
|
+
defaultTab: {
|
|
2453
|
+
type: StringConstructor;
|
|
2454
|
+
default: any;
|
|
2455
|
+
};
|
|
2445
2456
|
}>, {}, {
|
|
2446
2457
|
errors: any[];
|
|
2447
2458
|
}, {
|
|
@@ -2499,6 +2510,10 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
2499
2510
|
type: BooleanConstructor;
|
|
2500
2511
|
default: any;
|
|
2501
2512
|
};
|
|
2513
|
+
defaultTab: {
|
|
2514
|
+
type: StringConstructor;
|
|
2515
|
+
default: any;
|
|
2516
|
+
};
|
|
2502
2517
|
}>> & Readonly<{
|
|
2503
2518
|
[x: `on${Capitalize<string>}`]: (...args: any[]) => any;
|
|
2504
2519
|
}>, {
|
|
@@ -2509,6 +2524,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
2509
2524
|
liveValue: Record<string, any>;
|
|
2510
2525
|
realMode: string;
|
|
2511
2526
|
useTabbedHash: boolean;
|
|
2527
|
+
defaultTab: string;
|
|
2512
2528
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2513
2529
|
export default _default;
|
|
2514
2530
|
}
|
|
@@ -3315,7 +3331,7 @@ export default class Resource {
|
|
|
3315
3331
|
weight: number;
|
|
3316
3332
|
divider?: undefined;
|
|
3317
3333
|
})[];
|
|
3318
|
-
showConfiguration(returnFocusSelector: any): void;
|
|
3334
|
+
showConfiguration(returnFocusSelector: any, defaultTab: any): void;
|
|
3319
3335
|
get _availableActions(): ({
|
|
3320
3336
|
action: string;
|
|
3321
3337
|
label: any;
|
|
@@ -3633,6 +3649,26 @@ export default class Resource {
|
|
|
3633
3649
|
}
|
|
3634
3650
|
}
|
|
3635
3651
|
|
|
3652
|
+
// @shell/plugins/i18n
|
|
3653
|
+
|
|
3654
|
+
declare module '@shell/plugins/i18n' {
|
|
3655
|
+
/**
|
|
3656
|
+
* @param {import('vuex').Store<any>} store
|
|
3657
|
+
* @param {string} key
|
|
3658
|
+
* @param {Record<string, any>} [args]
|
|
3659
|
+
* @param {boolean} [raw]
|
|
3660
|
+
* @param {boolean} [escapehtml]
|
|
3661
|
+
* @returns {string}
|
|
3662
|
+
*/
|
|
3663
|
+
export function stringFor(store: import("vuex").Store<any>, key: string, args?: Record<string, any>, raw?: boolean, escapehtml?: boolean): string;
|
|
3664
|
+
export function directiveSsr(vnode: any, binding: any): void;
|
|
3665
|
+
export default i18n;
|
|
3666
|
+
declare namespace i18n {
|
|
3667
|
+
let name: string;
|
|
3668
|
+
function install(vueApp: any, _options: any): void;
|
|
3669
|
+
}
|
|
3670
|
+
}
|
|
3671
|
+
|
|
3636
3672
|
// @shell/plugins/steve/hybrid-class
|
|
3637
3673
|
|
|
3638
3674
|
declare module '@shell/plugins/steve/hybrid-class' {
|
|
@@ -4083,7 +4119,7 @@ export function contrastColor(color: any, contrastOptions?: {
|
|
|
4083
4119
|
dark: string;
|
|
4084
4120
|
light: string;
|
|
4085
4121
|
}): string;
|
|
4086
|
-
export function parseColor(str: any):
|
|
4122
|
+
export function parseColor(str: any): import("color").ColorInstance;
|
|
4087
4123
|
export function textColor(color: any): "black" | "white";
|
|
4088
4124
|
export function hexToRgb(hex: any): {
|
|
4089
4125
|
r: number;
|
|
@@ -5257,6 +5293,7 @@ export function parse(str: any): any;
|
|
|
5257
5293
|
export function sortable(str: any): any;
|
|
5258
5294
|
export function compare(in1: any, in2: any): any;
|
|
5259
5295
|
export function isPrerelease(version?: string): boolean;
|
|
5296
|
+
export function isUpgradeFromPreToStable(currentVersion: any, targetVersion: any): any;
|
|
5260
5297
|
export function isDevBuild(version: any): boolean;
|
|
5261
5298
|
export function getVersionInfo(store: any): {
|
|
5262
5299
|
displayVersion: any;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { PaginationFilterEquality, PaginationFilterField } from '@shell/types/store/pagination.types';
|
|
2
|
+
|
|
3
|
+
describe('pagination-types', () => {
|
|
4
|
+
describe('class: PaginationFilterField', () => {
|
|
5
|
+
describe('constructor', () => {
|
|
6
|
+
it('should set properties correctly with default values', () => {
|
|
7
|
+
const field = 'testField';
|
|
8
|
+
const value = 'testValue';
|
|
9
|
+
const filterField = new PaginationFilterField({ field, value });
|
|
10
|
+
|
|
11
|
+
expect(filterField.field).toBe(field);
|
|
12
|
+
expect(filterField.value).toBe(value);
|
|
13
|
+
expect(filterField.equals).toBe(true);
|
|
14
|
+
expect(filterField.exact).toBe(true);
|
|
15
|
+
expect(filterField.exists).toBe(false);
|
|
16
|
+
expect(filterField.equality).toBe(PaginationFilterEquality.EQUALS);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should handle deprecated `equals` and `exact` to set `equality`', () => {
|
|
20
|
+
// equals: true, exact: true
|
|
21
|
+
let ff = new PaginationFilterField({
|
|
22
|
+
field: 'f', value: 'v', equals: true, exact: true
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
expect(ff.equality).toBe(PaginationFilterEquality.EQUALS);
|
|
26
|
+
|
|
27
|
+
// equals: true, exact: false
|
|
28
|
+
ff = new PaginationFilterField({
|
|
29
|
+
field: 'f', value: 'v', equals: true, exact: false
|
|
30
|
+
});
|
|
31
|
+
expect(ff.equality).toBe(PaginationFilterEquality.CONTAINS);
|
|
32
|
+
|
|
33
|
+
// equals: false, exact: true
|
|
34
|
+
ff = new PaginationFilterField({
|
|
35
|
+
field: 'f', value: 'v', equals: false, exact: true
|
|
36
|
+
});
|
|
37
|
+
expect(ff.equality).toBe(PaginationFilterEquality.NOT_EQUALS);
|
|
38
|
+
|
|
39
|
+
// equals: false, exact: false
|
|
40
|
+
ff = new PaginationFilterField({
|
|
41
|
+
field: 'f', value: 'v', equals: false, exact: false
|
|
42
|
+
});
|
|
43
|
+
expect(ff.equality).toBe(PaginationFilterEquality.NOT_CONTAINS);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should prioritize `equality` over `equals` and `exact`', () => {
|
|
47
|
+
const filterField = new PaginationFilterField({
|
|
48
|
+
field: 'f',
|
|
49
|
+
value: 'v',
|
|
50
|
+
equals: false,
|
|
51
|
+
exact: false,
|
|
52
|
+
equality: PaginationFilterEquality.GREATER_THAN
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
expect(filterField.equality).toBe(PaginationFilterEquality.GREATER_THAN);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should throw an error if no equality can be determined', () => {
|
|
59
|
+
expect(() => new PaginationFilterField({
|
|
60
|
+
field: 'f',
|
|
61
|
+
value: 'v',
|
|
62
|
+
equals: null,
|
|
63
|
+
exact: null
|
|
64
|
+
})).toThrow('A pagination filter must have either equals or equality set');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should set `exists` property', () => {
|
|
68
|
+
const filterField = new PaginationFilterField({ field: 'f', exists: true });
|
|
69
|
+
|
|
70
|
+
expect(filterField.exists).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('safeEquality', () => {
|
|
75
|
+
it('should return EQUALS for equals=true, exact=true', () => {
|
|
76
|
+
const equality = PaginationFilterField.safeEquality({ equals: true, exact: true });
|
|
77
|
+
|
|
78
|
+
expect(equality).toBe(PaginationFilterEquality.EQUALS);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should return CONTAINS for equals=true, exact=false', () => {
|
|
82
|
+
const equality = PaginationFilterField.safeEquality({ equals: true, exact: false });
|
|
83
|
+
|
|
84
|
+
expect(equality).toBe(PaginationFilterEquality.CONTAINS);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should return NOT_EQUALS for equals=false, exact=true', () => {
|
|
88
|
+
const equality = PaginationFilterField.safeEquality({ equals: false, exact: true });
|
|
89
|
+
|
|
90
|
+
expect(equality).toBe(PaginationFilterEquality.NOT_EQUALS);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should return NOT_CONTAINS for equals=false, exact=false', () => {
|
|
94
|
+
const equality = PaginationFilterField.safeEquality({ equals: false, exact: false });
|
|
95
|
+
|
|
96
|
+
expect(equality).toBe(PaginationFilterEquality.NOT_CONTAINS);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should return equality if it is provided', () => {
|
|
100
|
+
const equality = PaginationFilterField.safeEquality({ equality: PaginationFilterEquality.IN });
|
|
101
|
+
|
|
102
|
+
expect(equality).toBe(PaginationFilterEquality.IN);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should prioritize equality over equals/exact', () => {
|
|
106
|
+
const equality = PaginationFilterField.safeEquality({
|
|
107
|
+
equals: true,
|
|
108
|
+
exact: false,
|
|
109
|
+
equality: PaginationFilterEquality.LESS_THAN
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
expect(equality).toBe(PaginationFilterEquality.LESS_THAN);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should return undefined if no equality can be determined', () => {
|
|
116
|
+
const equality = PaginationFilterField.safeEquality({});
|
|
117
|
+
|
|
118
|
+
expect(equality).toBeUndefined();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should work with an instance of PaginationFilterField', () => {
|
|
122
|
+
const ff = new PaginationFilterField({
|
|
123
|
+
field: 'f',
|
|
124
|
+
value: 'v',
|
|
125
|
+
equals: false,
|
|
126
|
+
exact: false,
|
|
127
|
+
equality: PaginationFilterEquality.GREATER_THAN
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// safeEquality will prioritize the `equality` property on the instance
|
|
131
|
+
const equality = PaginationFilterField.safeEquality(ff);
|
|
132
|
+
|
|
133
|
+
expect(equality).toBe(PaginationFilterEquality.GREATER_THAN);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
});
|
|
@@ -13,6 +13,8 @@ import { KubeLabelSelector } from '@shell/types/kube/kube-api';
|
|
|
13
13
|
// The two important / complex params are currently
|
|
14
14
|
// - `filter` https://github.com/rancher/steve?tab=readme-ov-file#filter
|
|
15
15
|
// - represented by `PaginationParamFilter extends PaginationParam`
|
|
16
|
+
// - a filter has filter fields which are made up of a field name, equality and value/s
|
|
17
|
+
// - filter=<field><equality><value>
|
|
16
18
|
// - Examples
|
|
17
19
|
// - filter=metadata.name=123
|
|
18
20
|
// - filter=metadata.name=123,metadata.name=456 (name is 123 OR 456)
|
|
@@ -45,14 +47,111 @@ export interface PaginationSort {
|
|
|
45
47
|
asc: boolean
|
|
46
48
|
}
|
|
47
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Equalities that can be used with a `filter` query param
|
|
52
|
+
*
|
|
53
|
+
* filter=<field><equality><values>
|
|
54
|
+
*
|
|
55
|
+
* For example
|
|
56
|
+
* - filter=a=b
|
|
57
|
+
* - filter=a!=b
|
|
58
|
+
* - filter=a NOT IN (b,c,d)
|
|
59
|
+
*/
|
|
60
|
+
export const enum PaginationFilterEquality {
|
|
61
|
+
/**
|
|
62
|
+
* Field is in a collection of values
|
|
63
|
+
*/
|
|
64
|
+
IN = ' IN ', // eslint-disable-line no-unused-vars
|
|
65
|
+
/**
|
|
66
|
+
* Field is not in a collection of values
|
|
67
|
+
*/
|
|
68
|
+
NOT_IN = ' NOTIN ', // eslint-disable-line no-unused-vars
|
|
69
|
+
/**
|
|
70
|
+
* Field matches a value
|
|
71
|
+
*/
|
|
72
|
+
EQUALS= '=', // eslint-disable-line no-unused-vars
|
|
73
|
+
/**
|
|
74
|
+
* Field does not match a value
|
|
75
|
+
*/
|
|
76
|
+
NOT_EQUALS= '!=', // eslint-disable-line no-unused-vars
|
|
77
|
+
/**
|
|
78
|
+
* Unknown
|
|
79
|
+
*/
|
|
80
|
+
STRICT_EQUALS = '==', // eslint-disable-line no-unused-vars
|
|
81
|
+
/**
|
|
82
|
+
* Field must partially match a value
|
|
83
|
+
*/
|
|
84
|
+
CONTAINS= '~', // eslint-disable-line no-unused-vars
|
|
85
|
+
/**
|
|
86
|
+
* Field must not partially match a value
|
|
87
|
+
*/
|
|
88
|
+
NOT_CONTAINS= '!~', // eslint-disable-line no-unused-vars
|
|
89
|
+
/**
|
|
90
|
+
* Field must be greater than a value
|
|
91
|
+
*/
|
|
92
|
+
GREATER_THAN= 'gt', // eslint-disable-line no-unused-vars
|
|
93
|
+
/**
|
|
94
|
+
* Field must be less than a value
|
|
95
|
+
*/
|
|
96
|
+
LESS_THAN= 'lt', // eslint-disable-line no-unused-vars
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Ctor args for a @PaginationFilterField
|
|
101
|
+
*/
|
|
102
|
+
type FilterFieldCtorArgs = {
|
|
103
|
+
/**
|
|
104
|
+
* Name of field within the object to filter by for example the x of x=y
|
|
105
|
+
*
|
|
106
|
+
* This can be optional for some (projectsornamespaces)
|
|
107
|
+
*/
|
|
108
|
+
field?: string;
|
|
109
|
+
/**
|
|
110
|
+
* Value of field within the object to filter by for example the y of x=y
|
|
111
|
+
*
|
|
112
|
+
* This can be empty if `exists` is true
|
|
113
|
+
*/
|
|
114
|
+
value?: string;
|
|
115
|
+
/**
|
|
116
|
+
* Equality field within the object to filter by for example the `=` or `!=` of x=y
|
|
117
|
+
*
|
|
118
|
+
* @deprecated Please use `equality` instead of equals and exact
|
|
119
|
+
*/
|
|
120
|
+
equals?: boolean;
|
|
121
|
+
/**
|
|
122
|
+
* Match the field exactly. False for partial matches
|
|
123
|
+
*
|
|
124
|
+
* Value: pod1
|
|
125
|
+
* Exact: true. "p" no, "pod", no, "pod1" yes
|
|
126
|
+
* Exact: false. "p" yes, "pod", yes, "pod1" yes
|
|
127
|
+
*
|
|
128
|
+
* @deprecated Please use `equality` instead of equals and exact
|
|
129
|
+
*/
|
|
130
|
+
exact?: boolean,
|
|
131
|
+
/**
|
|
132
|
+
* Check if the field/property exists, regardless of value
|
|
133
|
+
*
|
|
134
|
+
* If this is false it does not flip the expectation, just doesn't add the field
|
|
135
|
+
*/
|
|
136
|
+
exists?: boolean,
|
|
137
|
+
/**
|
|
138
|
+
* Equality symbol used to compare the field with the value
|
|
139
|
+
*/
|
|
140
|
+
equality?: PaginationFilterEquality
|
|
141
|
+
}
|
|
142
|
+
|
|
48
143
|
/**
|
|
49
144
|
* Filter the pagination result by these specific fields
|
|
50
145
|
*
|
|
146
|
+
* In format of <field><equality><value>
|
|
147
|
+
*
|
|
51
148
|
* For example
|
|
52
149
|
*
|
|
53
150
|
* - metadata.name=test
|
|
54
151
|
* - metadata.namespace!=system
|
|
55
152
|
*
|
|
153
|
+
* These are sub items for @PaginationParam, for example filter=<PaginationFilterField>
|
|
154
|
+
*
|
|
56
155
|
* For more information regarding the API see https://github.com/rancher/steve?tab=readme-ov-file#query-parameters
|
|
57
156
|
*/
|
|
58
157
|
export class PaginationFilterField {
|
|
@@ -70,6 +169,8 @@ export class PaginationFilterField {
|
|
|
70
169
|
value?: string;
|
|
71
170
|
/**
|
|
72
171
|
* Equality field within the object to filter by for example the `=` or `!=` of x=y
|
|
172
|
+
*
|
|
173
|
+
* @deprecated Please use `equality` instead of equals and exact
|
|
73
174
|
*/
|
|
74
175
|
equals?: boolean;
|
|
75
176
|
/**
|
|
@@ -78,9 +179,14 @@ export class PaginationFilterField {
|
|
|
78
179
|
* Value: pod1
|
|
79
180
|
* Exact: true. "p" no, "pod", no, "pod1" yes
|
|
80
181
|
* Exact: false. "p" yes, "pod", yes, "pod1" yes
|
|
182
|
+
*
|
|
183
|
+
* @deprecated Please use `equality` instead of equals and exact
|
|
81
184
|
*/
|
|
82
185
|
exact?: boolean;
|
|
83
|
-
|
|
186
|
+
/**
|
|
187
|
+
* Equality symbol used to compare the field with the value
|
|
188
|
+
*/
|
|
189
|
+
equality?: PaginationFilterEquality;
|
|
84
190
|
/**
|
|
85
191
|
* Check if the field/property exists, regardless of value
|
|
86
192
|
*
|
|
@@ -88,17 +194,51 @@ export class PaginationFilterField {
|
|
|
88
194
|
*/
|
|
89
195
|
exists?: boolean;
|
|
90
196
|
|
|
91
|
-
constructor(
|
|
92
|
-
{
|
|
93
|
-
field, value = '', equals = true, exact = true, exists = false
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
) {
|
|
197
|
+
constructor(args: FilterFieldCtorArgs) {
|
|
198
|
+
const {
|
|
199
|
+
field, value = '', equals = true, exact = true, equality = undefined, exists = false
|
|
200
|
+
} = args;
|
|
201
|
+
|
|
97
202
|
this.field = field;
|
|
98
203
|
this.value = value;
|
|
99
204
|
this.equals = equals;
|
|
100
205
|
this.exact = exact;
|
|
101
206
|
this.exists = exists;
|
|
207
|
+
|
|
208
|
+
const _equality = PaginationFilterField.safeEquality({
|
|
209
|
+
field, value, equals, exact, equality, exists
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
if (_equality) {
|
|
213
|
+
this.equality = _equality;
|
|
214
|
+
} else {
|
|
215
|
+
throw new Error('A pagination filter must have either equals or equality set');
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Determine equality for this field.
|
|
221
|
+
*
|
|
222
|
+
* Mainly to ensure legacy objects using deprecated fields instead of new equality field fall back on something sensible
|
|
223
|
+
*/
|
|
224
|
+
static safeEquality(args: FilterFieldCtorArgs | PaginationFilterField): PaginationFilterEquality | undefined {
|
|
225
|
+
if (args.equality) {
|
|
226
|
+
return args.equality;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (args.equals === true) {
|
|
230
|
+
if (args.exact === true) {
|
|
231
|
+
return PaginationFilterEquality.EQUALS;
|
|
232
|
+
} else {
|
|
233
|
+
return PaginationFilterEquality.CONTAINS;
|
|
234
|
+
}
|
|
235
|
+
} else if (args.equals === false) {
|
|
236
|
+
if (args.exact === true) {
|
|
237
|
+
return PaginationFilterEquality.NOT_EQUALS;
|
|
238
|
+
} else {
|
|
239
|
+
return PaginationFilterEquality.NOT_CONTAINS;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
102
242
|
}
|
|
103
243
|
}
|
|
104
244
|
|
|
@@ -202,7 +342,15 @@ export abstract class PaginationParam {
|
|
|
202
342
|
}
|
|
203
343
|
|
|
204
344
|
/**
|
|
205
|
-
* This is a convenience class for the `filter` param which works some magic, adds defaults and converts to the required PaginationParam format
|
|
345
|
+
* This is a convenience class for the `filter` param which works some magic, adds defaults and converts to the required PaginationParam format.
|
|
346
|
+
*
|
|
347
|
+
* for example
|
|
348
|
+
*
|
|
349
|
+
* - filter=???
|
|
350
|
+
*
|
|
351
|
+
* including `fields` this could be
|
|
352
|
+
*
|
|
353
|
+
* - filter=a=b
|
|
206
354
|
*
|
|
207
355
|
* See description for {@link PaginationParam} for how multiple of these can be combined together to AND or OR together
|
|
208
356
|
*
|
|
@@ -238,7 +386,7 @@ export class PaginationParamFilter extends PaginationParam {
|
|
|
238
386
|
/**
|
|
239
387
|
* Convenience method when you just want an instance of {@link PaginationParamFilter} with a simple `filter=x=y` param
|
|
240
388
|
*/
|
|
241
|
-
static createSingleField(field:
|
|
389
|
+
static createSingleField(field: FilterFieldCtorArgs): PaginationParam {
|
|
242
390
|
return new PaginationParamFilter({ fields: [new PaginationFilterField(field)] });
|
|
243
391
|
}
|
|
244
392
|
|
|
@@ -12,10 +12,17 @@ export interface STEVE_WATCH_EVENT_PARAMS_COMMON {
|
|
|
12
12
|
params: STEVE_WATCH_PARAMS,
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Args for @STEVE_WATCH_EVENT_LISTENER_CALLBACK
|
|
17
|
+
*/
|
|
18
|
+
export type STEVE_WATCH_EVENT_LISTENER_CALLBACK_PARAMS = {
|
|
19
|
+
forceWatch?: boolean,
|
|
20
|
+
}
|
|
21
|
+
|
|
15
22
|
/**
|
|
16
23
|
* Executes when a watch event has a listener and it's triggered
|
|
17
24
|
*/
|
|
18
|
-
export type STEVE_WATCH_EVENT_LISTENER_CALLBACK = () => void
|
|
25
|
+
export type STEVE_WATCH_EVENT_LISTENER_CALLBACK = (params: STEVE_WATCH_EVENT_LISTENER_CALLBACK_PARAMS) => void
|
|
19
26
|
|
|
20
27
|
/**
|
|
21
28
|
* Common params used when a watcher adds a listener to a watch
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { getHostedProviders, isHostedProvider } from '../provider';
|
|
2
|
+
import { ClusterProvisionerContext, IClusterProvisioner } from '@shell/core/types';
|
|
3
|
+
|
|
4
|
+
const DEFAULT_CONTEXT = {
|
|
5
|
+
dispatch: {},
|
|
6
|
+
getters: {},
|
|
7
|
+
axios: {},
|
|
8
|
+
t: (args: any) => args.join(' '),
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const MOCK_PROVIDERS: IClusterProvisioner[] = [
|
|
12
|
+
{ id: 'AKS', group: 'hosted' } as IClusterProvisioner,
|
|
13
|
+
{ id: 'EKS', group: 'hosted' } as IClusterProvisioner,
|
|
14
|
+
{ id: 'GKE', group: 'hosted' } as IClusterProvisioner,
|
|
15
|
+
{ id: 'alibaba', group: 'hosted' } as IClusterProvisioner,
|
|
16
|
+
{ id: 'other', group: 'other' } as IClusterProvisioner,
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
describe('utils/provider', () => {
|
|
20
|
+
describe('getHostedProviders', () => {
|
|
21
|
+
it('should return an empty array when context.$extension is undefined', () => {
|
|
22
|
+
const context = { ...DEFAULT_CONTEXT } as ClusterProvisionerContext;
|
|
23
|
+
const result = getHostedProviders(context);
|
|
24
|
+
|
|
25
|
+
expect(result).toStrictEqual([]);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should return hosted providers when context.$extension is defined', () => {
|
|
29
|
+
const context = {
|
|
30
|
+
...DEFAULT_CONTEXT,
|
|
31
|
+
$extension: { getProviders: jest.fn().mockReturnValue(MOCK_PROVIDERS) }
|
|
32
|
+
} as unknown as ClusterProvisionerContext;
|
|
33
|
+
|
|
34
|
+
const result = getHostedProviders(context);
|
|
35
|
+
|
|
36
|
+
expect(result).toStrictEqual([
|
|
37
|
+
{ id: 'AKS', group: 'hosted' },
|
|
38
|
+
{ id: 'EKS', group: 'hosted' },
|
|
39
|
+
{ id: 'GKE', group: 'hosted' },
|
|
40
|
+
{ id: 'alibaba', group: 'hosted' },
|
|
41
|
+
]);
|
|
42
|
+
expect(context.$extension.getProviders).toHaveBeenCalledWith(context);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should return an empty array if getProviders returns null', () => {
|
|
46
|
+
const context = {
|
|
47
|
+
...DEFAULT_CONTEXT,
|
|
48
|
+
$extension: { getProviders: jest.fn().mockReturnValue(null) }
|
|
49
|
+
} as unknown as ClusterProvisionerContext;
|
|
50
|
+
|
|
51
|
+
const result = getHostedProviders(context);
|
|
52
|
+
|
|
53
|
+
expect(result).toStrictEqual([]);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should return an empty array if getProviders returns undefined', () => {
|
|
57
|
+
const context = {
|
|
58
|
+
...DEFAULT_CONTEXT,
|
|
59
|
+
$extension: { getProviders: jest.fn().mockReturnValue(undefined) }
|
|
60
|
+
} as unknown as ClusterProvisionerContext;
|
|
61
|
+
|
|
62
|
+
const result = getHostedProviders(context);
|
|
63
|
+
|
|
64
|
+
expect(result).toStrictEqual([]);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('isHostedProvider', () => {
|
|
69
|
+
it('should return false if provisioner is not provided', () => {
|
|
70
|
+
const context = {
|
|
71
|
+
...DEFAULT_CONTEXT,
|
|
72
|
+
$extension: { getProviders: jest.fn().mockReturnValue(MOCK_PROVIDERS) }
|
|
73
|
+
} as ClusterProvisionerContext;
|
|
74
|
+
|
|
75
|
+
expect(isHostedProvider(context, '')).toBe(false);
|
|
76
|
+
expect(isHostedProvider(context, undefined as any)).toBe(false);
|
|
77
|
+
expect(isHostedProvider(context, null as any)).toBe(false);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should return true only if provisioner is in the list of hosted providers', () => {
|
|
81
|
+
const context = {
|
|
82
|
+
...DEFAULT_CONTEXT,
|
|
83
|
+
$extension: { getProviders: jest.fn().mockReturnValue(MOCK_PROVIDERS) }
|
|
84
|
+
} as ClusterProvisionerContext;
|
|
85
|
+
|
|
86
|
+
expect(isHostedProvider(context, 'AKS')).toBe(true);
|
|
87
|
+
expect(isHostedProvider(context, 'eks')).toBe(true);
|
|
88
|
+
expect(isHostedProvider(context, 'different')).toBe(false); // case-insensitive check
|
|
89
|
+
expect(isHostedProvider(context, 'other')).toBe(false); // case-insensitive check
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should return false if there are no hosted providers', () => {
|
|
93
|
+
const context = { ...DEFAULT_CONTEXT, $extension: { getProviders: jest.fn().mockReturnValue([]) } } as ClusterProvisionerContext;
|
|
94
|
+
|
|
95
|
+
expect(isHostedProvider(context, 'prov1')).toBe(false);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|