@rancher/shell 3.0.5-rc.2 → 3.0.5-rc.3
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/data/aws-regions.json +2 -0
- package/assets/styles/global/_layout.scss +0 -1
- package/assets/translations/en-us.yaml +61 -19
- package/assets/translations/zh-hans.yaml +0 -10
- package/chart/monitoring/index.vue +1 -1
- package/components/AsyncButton.vue +2 -0
- package/components/CodeMirror.vue +3 -3
- package/components/CruResource.vue +103 -15
- package/components/ExplorerProjectsNamespaces.vue +7 -2
- package/components/FixedBanner.vue +19 -5
- package/components/PaginatedResourceTable.vue +7 -0
- package/components/ResourceDetail/Masthead.vue +0 -1
- package/components/ResourceList/index.vue +2 -1
- package/components/SlideInPanelManager.vue +1 -2
- package/components/SortableTable/selection.js +1 -1
- package/components/Tabbed/index.vue +6 -0
- package/components/__tests__/AsyncButton.test.ts +39 -0
- package/components/__tests__/CruResource.test.ts +63 -0
- package/components/__tests__/PromptModal.test.ts +0 -2
- package/components/form/ArrayList.vue +134 -118
- package/components/form/BannerSettings.vue +145 -96
- package/components/form/KeyValue.vue +10 -7
- package/components/form/LabeledSelect.vue +9 -2
- package/components/form/MatchExpressions.vue +5 -1
- package/components/form/NameNsDescription.vue +1 -1
- package/components/form/ResourceSelector.vue +26 -23
- package/components/form/ResourceTabs/index.vue +2 -1
- package/components/form/Select.vue +9 -2
- package/components/form/UnitInput.vue +13 -0
- package/components/form/__tests__/ArrayList.test.ts +32 -0
- package/components/form/__tests__/KeyValue.test.ts +36 -0
- package/components/form/__tests__/LabeledSelect.test.ts +33 -0
- package/components/form/__tests__/Select.test.ts +34 -1
- package/components/form/__tests__/UnitInput.test.ts +23 -1
- package/components/formatter/ClusterLink.vue +5 -8
- package/components/formatter/Description.vue +30 -0
- package/components/formatter/__tests__/ClusterLink.test.ts +2 -32
- package/components/nav/NamespaceFilter.vue +1 -1
- package/components/nav/WindowManager/index.vue +1 -0
- package/config/product/explorer.js +16 -13
- package/config/product/manager.js +1 -28
- package/config/settings.ts +11 -13
- package/config/table-headers.js +7 -5
- package/detail/catalog.cattle.io.app.vue +0 -1
- package/detail/provisioning.cattle.io.cluster.vue +13 -3
- package/detail/service.vue +0 -1
- package/detail/workload/index.vue +21 -34
- package/dialog/ExtensionCatalogUninstallDialog.vue +14 -8
- package/edit/__tests__/service.test.ts +2 -1
- package/edit/networking.k8s.io.networkpolicy/PolicyRule.vue +3 -14
- package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +57 -62
- package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +3 -14
- package/edit/networking.k8s.io.networkpolicy/__tests__/PolicyRuleTarget.test.ts +72 -41
- package/edit/networking.k8s.io.networkpolicy/__tests__/utils/mock.json +17 -1
- package/edit/networking.k8s.io.networkpolicy/index.vue +18 -30
- package/edit/provisioning.cattle.io.cluster/index.vue +21 -73
- package/edit/service.vue +13 -28
- package/list/workload.vue +6 -1
- package/mixins/resource-fetch-api-pagination.js +55 -43
- package/mixins/resource-fetch.js +14 -5
- package/models/__tests__/workload.test.ts +1 -0
- package/models/cluster/node.js +1 -0
- package/models/cluster.js +32 -2
- package/models/management.cattle.io.cluster.js +0 -20
- package/models/management.cattle.io.node.js +7 -22
- package/models/management.cattle.io.nodepool.js +12 -0
- package/models/namespace.js +5 -0
- package/models/provisioning.cattle.io.cluster.js +18 -64
- package/models/service.js +24 -9
- package/models/workload.js +70 -31
- package/package.json +1 -1
- package/pages/c/_cluster/apps/charts/install.vue +0 -1
- package/pages/c/_cluster/explorer/index.vue +11 -0
- package/pages/c/_cluster/longhorn/index.vue +2 -2
- package/pages/c/_cluster/settings/banners.vue +56 -2
- package/pages/c/_cluster/settings/performance.vue +7 -26
- package/pages/home.vue +11 -52
- package/plugins/clean-html.js +2 -0
- package/plugins/dashboard-store/__tests__/actions.test.ts +4 -1
- package/plugins/dashboard-store/actions.js +122 -21
- package/plugins/dashboard-store/getters.js +74 -3
- package/plugins/dashboard-store/mutations.js +10 -5
- package/plugins/dashboard-store/resource-class.js +23 -3
- package/plugins/steve/__tests__/getters.test.ts +18 -11
- package/plugins/steve/__tests__/steve-class.test.ts +1 -0
- package/plugins/steve/actions.js +34 -12
- package/plugins/steve/getters.js +39 -10
- package/plugins/steve/steve-class.js +5 -0
- package/plugins/steve/steve-pagination-utils.ts +199 -37
- package/plugins/steve/worker/web-worker.advanced.js +3 -1
- package/rancher-components/Banner/Banner.test.ts +51 -3
- package/rancher-components/Banner/Banner.vue +28 -6
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +5 -1
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +21 -1
- package/store/features.js +0 -1
- package/store/type-map.utils.ts +45 -2
- package/types/fleet.d.ts +1 -1
- package/types/kube/kube-api.ts +22 -0
- package/types/resources/settings.d.ts +0 -4
- package/types/shell/index.d.ts +346 -289
- package/types/store/dashboard-store.types.ts +24 -1
- package/types/store/pagination.types.ts +19 -2
- package/utils/cluster.js +24 -20
- package/utils/grafana.js +1 -0
- package/utils/object.js +0 -12
- package/utils/pagination-utils.ts +6 -2
- package/utils/perf-setting.utils.ts +28 -0
- package/utils/selector-typed.ts +205 -0
- package/utils/selector.js +29 -6
- package/utils/uiplugins.ts +10 -6
- package/utils/v-sphere.ts +5 -1
- package/components/formatter/RKETemplateName.vue +0 -37
- package/dialog/SaveAsRKETemplateDialog.vue +0 -139
package/plugins/steve/actions.js
CHANGED
|
@@ -9,6 +9,7 @@ import { classify } from '@shell/plugins/dashboard-store/classify';
|
|
|
9
9
|
import { NAMESPACE } from '@shell/config/types';
|
|
10
10
|
import { handleKubeApiHeaderWarnings } from '@shell/plugins/steve/header-warnings';
|
|
11
11
|
import { steveCleanForDownload } from '@shell/plugins/steve/resource-utils';
|
|
12
|
+
import paginationUtils from '@shell/utils/pagination-utils';
|
|
12
13
|
|
|
13
14
|
export default {
|
|
14
15
|
|
|
@@ -17,7 +18,9 @@ export default {
|
|
|
17
18
|
return await loadSchemas(ctx, watch);
|
|
18
19
|
},
|
|
19
20
|
|
|
20
|
-
async request({
|
|
21
|
+
async request({
|
|
22
|
+
state, dispatch, rootGetters, getters
|
|
23
|
+
}, pOpt ) {
|
|
21
24
|
const opt = pOpt.opt || pOpt;
|
|
22
25
|
const spoofedRes = await handleSpoofedRequest(rootGetters, 'cluster', opt);
|
|
23
26
|
|
|
@@ -82,6 +85,7 @@ export default {
|
|
|
82
85
|
}
|
|
83
86
|
|
|
84
87
|
let paginatedResult;
|
|
88
|
+
const isSteveCacheUrl = getters.isSteveCacheUrl(opt.url);
|
|
85
89
|
|
|
86
90
|
while (true) {
|
|
87
91
|
try {
|
|
@@ -92,24 +96,42 @@ export default {
|
|
|
92
96
|
}
|
|
93
97
|
|
|
94
98
|
if (!paginatedResult) {
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
const pageByNumber = isSteveCacheUrl && opt.url.includes(`pagesize=${ paginationUtils.defaultPageSize }`) ? {
|
|
100
|
+
total: out.count,
|
|
101
|
+
page: 1,
|
|
102
|
+
url: opt.url,
|
|
103
|
+
} : null;
|
|
104
|
+
const pageByLimit = !pageByNumber ? { } : null;
|
|
105
|
+
|
|
106
|
+
paginatedResult = {
|
|
107
|
+
// initialise some settings
|
|
108
|
+
pageByLimit,
|
|
109
|
+
pageByNumber,
|
|
110
|
+
// First result, so store it
|
|
111
|
+
out
|
|
112
|
+
};
|
|
97
113
|
} else {
|
|
98
114
|
// Subsequent request, so add to it
|
|
99
|
-
paginatedResult.data = paginatedResult.data.concat(out.data);
|
|
115
|
+
paginatedResult.out.data = paginatedResult.out.data.concat(out.data);
|
|
100
116
|
}
|
|
101
117
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
118
|
+
const { total, page, url } = paginatedResult.pageByNumber || {};
|
|
119
|
+
|
|
120
|
+
if (paginatedResult.pageByLimit && out?.pagination?.next) {
|
|
121
|
+
opt.url = out?.pagination?.next;
|
|
122
|
+
} else if (paginatedResult.pageByNumber && (total > paginationUtils.defaultPageSize * page)) {
|
|
123
|
+
paginatedResult.pageByNumber.page += 1;
|
|
124
|
+
|
|
125
|
+
opt.url = addParam(url, 'page', `${ paginatedResult.pageByNumber.page }`);
|
|
105
126
|
} else {
|
|
106
127
|
// No more results, so clear out the pagination section (which will be stale from the first request)
|
|
107
|
-
delete paginatedResult.pagination?.first;
|
|
108
|
-
delete paginatedResult.pagination?.last;
|
|
109
|
-
delete paginatedResult.pagination?.next;
|
|
110
|
-
delete paginatedResult.pagination?.partial;
|
|
128
|
+
delete paginatedResult.out.pagination?.first;
|
|
129
|
+
delete paginatedResult.out.pagination?.last;
|
|
130
|
+
delete paginatedResult.out.pagination?.next;
|
|
131
|
+
delete paginatedResult.out.pagination?.partial;
|
|
132
|
+
delete paginatedResult.out.continue;
|
|
111
133
|
|
|
112
|
-
return paginatedResult;
|
|
134
|
+
return paginatedResult.out;
|
|
113
135
|
}
|
|
114
136
|
} catch (err) {
|
|
115
137
|
return onError(err);
|
package/plugins/steve/getters.js
CHANGED
|
@@ -15,9 +15,10 @@ import { splitObjectPath } from '@shell/utils/string';
|
|
|
15
15
|
import { parseType } from '@shell/models/schema';
|
|
16
16
|
import {
|
|
17
17
|
STEVE_AGE_COL,
|
|
18
|
-
STEVE_ID_COL, STEVE_LIST_GROUPS, STEVE_NAMESPACE_COL, STEVE_STATE_COL
|
|
18
|
+
STEVE_ID_COL, STEVE_LIST_GROUPS, STEVE_NAME_COL, STEVE_NAMESPACE_COL, STEVE_STATE_COL
|
|
19
19
|
} from '@shell/config/pagination-table-headers';
|
|
20
20
|
import { createHeaders } from '@shell/store/type-map.utils';
|
|
21
|
+
import paginationUtils from '@shell/utils/pagination-utils';
|
|
21
22
|
|
|
22
23
|
export const STEVE_MODEL_TYPES = {
|
|
23
24
|
NORMAN: 'norman',
|
|
@@ -36,16 +37,34 @@ const GC_IGNORE_TYPES = {
|
|
|
36
37
|
const steveRegEx = new RegExp('(/v1)|(\/k8s\/clusters\/[a-z0-9-]+\/v1)');
|
|
37
38
|
|
|
38
39
|
export default {
|
|
39
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Is the url path a rancher steve one?
|
|
42
|
+
*
|
|
43
|
+
* Can be used to change behaviour given steve api
|
|
44
|
+
*/
|
|
45
|
+
isSteveUrl: () => (urlPath) => steveRegEx.test(urlPath),
|
|
46
|
+
/**
|
|
47
|
+
* Is the url path a rancher steve one AND the steve cache is enabled?
|
|
48
|
+
*
|
|
49
|
+
* Can be used to change behaviour given steve cache api functionality
|
|
50
|
+
*/
|
|
51
|
+
isSteveCacheUrl: (state, getters, rootState, rootGetters) => (urlPath) => getters.isSteveUrl(urlPath) && paginationUtils.isSteveCacheEnabled({ rootGetters }),
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* opt: ActionFindPageArgs
|
|
55
|
+
*/
|
|
56
|
+
urlOptions: (state, getters) => (url, opt, schema) => {
|
|
40
57
|
opt = opt || {};
|
|
41
|
-
const parsedUrl = parse(url);
|
|
42
|
-
const isSteve = steveRegEx.test(parsedUrl.path);
|
|
58
|
+
const parsedUrl = parse(url || '');
|
|
43
59
|
|
|
44
|
-
const
|
|
60
|
+
const isSteveUrl = getters.isSteveUrl(parsedUrl.path);
|
|
61
|
+
const stevePagination = stevePaginationUtils.createParamsForPagination({ schema, opt });
|
|
45
62
|
|
|
46
63
|
if (stevePagination) {
|
|
47
64
|
url += `${ (url.includes('?') ? '&' : '?') + stevePagination }`;
|
|
48
65
|
} else {
|
|
66
|
+
const isSteveCacheUrl = getters.isSteveCacheUrl(parsedUrl.path);
|
|
67
|
+
|
|
49
68
|
// labelSelector
|
|
50
69
|
if ( opt.labelSelector ) {
|
|
51
70
|
url += `${ url.includes('?') ? '&' : '?' }labelSelector=${ opt.labelSelector }`;
|
|
@@ -54,6 +73,7 @@ export default {
|
|
|
54
73
|
|
|
55
74
|
// Filter
|
|
56
75
|
if ( opt.filter ) {
|
|
76
|
+
// When ui-sql-cache is always on we should look to replace the usages of this with findPage (basically using the new filter definitions)
|
|
57
77
|
url += `${ (url.includes('?') ? '&' : '?') }`;
|
|
58
78
|
const keys = Object.keys(opt.filter);
|
|
59
79
|
|
|
@@ -64,13 +84,12 @@ export default {
|
|
|
64
84
|
vals = [vals];
|
|
65
85
|
}
|
|
66
86
|
|
|
67
|
-
|
|
68
|
-
if (isSteve) {
|
|
87
|
+
if (isSteveUrl) {
|
|
69
88
|
url += `${ (url.includes('filter=') ? '&' : 'filter=') }`;
|
|
70
89
|
}
|
|
71
90
|
|
|
72
91
|
const filterStrings = vals.map((val) => {
|
|
73
|
-
return `${ encodeURI(key) }
|
|
92
|
+
return `${ encodeURI(key) }${ isSteveCacheUrl ? '~' : '=' }${ encodeURI(val) }`;
|
|
74
93
|
});
|
|
75
94
|
const urlEnding = url.charAt(url.length - 1);
|
|
76
95
|
const nextStringConnector = ['&', '?', '='].includes(urlEnding) ? '' : '&';
|
|
@@ -97,13 +116,22 @@ export default {
|
|
|
97
116
|
}
|
|
98
117
|
// End: Limit
|
|
99
118
|
|
|
119
|
+
// Page Size
|
|
120
|
+
if (isSteveCacheUrl && opt.isCollection) {
|
|
121
|
+
// This is a steve url and the new cache is being used.
|
|
122
|
+
// Pre-cache there was always a max page size (given kube proxy). With cache there's not.
|
|
123
|
+
// So ensure we don't go backwards (and fetch crazy high resource counts) by adding a default
|
|
124
|
+
url += `${ url.includes('?') ? '&' : '?' }pagesize=${ paginationUtils.defaultPageSize }`;
|
|
125
|
+
}
|
|
126
|
+
// End: Page Size
|
|
127
|
+
|
|
100
128
|
// Sort
|
|
101
129
|
// Steve's sort options supports multi-column sorting and column specific sort orders, not implemented yet #9341
|
|
102
130
|
const sortBy = opt.sortBy;
|
|
103
131
|
const orderBy = opt.sortOrder;
|
|
104
132
|
|
|
105
133
|
if ( sortBy ) {
|
|
106
|
-
if (
|
|
134
|
+
if (isSteveUrl) {
|
|
107
135
|
url += `${ url.includes('?') ? '&' : '?' }sort=${ (orderBy === 'desc' ? '-' : '') + encodeURI(sortBy) }`;
|
|
108
136
|
} else {
|
|
109
137
|
url += `${ url.includes('?') ? '&' : '?' }sort=${ encodeURI(sortBy) }`;
|
|
@@ -118,7 +146,7 @@ export default {
|
|
|
118
146
|
// Exclude
|
|
119
147
|
// excludeFields should be an array of strings representing the paths of the fields to exclude
|
|
120
148
|
// only works on Steve but is ignored without error by Norman
|
|
121
|
-
if (
|
|
149
|
+
if (isSteveUrl) {
|
|
122
150
|
if (!Array.isArray(opt?.excludeFields)) {
|
|
123
151
|
const excludeFields = ['metadata.managedFields'];
|
|
124
152
|
|
|
@@ -312,6 +340,7 @@ export default {
|
|
|
312
340
|
typeOptions: typeMapGetters['optionsFor'](schema, true),
|
|
313
341
|
schema,
|
|
314
342
|
columns: {
|
|
343
|
+
name: STEVE_NAME_COL,
|
|
315
344
|
state: STEVE_STATE_COL,
|
|
316
345
|
namespace: STEVE_NAMESPACE_COL,
|
|
317
346
|
age: STEVE_AGE_COL,
|
|
@@ -11,6 +11,7 @@ const STEVE_ADD = [
|
|
|
11
11
|
'metadata.clusterName',
|
|
12
12
|
'metadata.deletionGracePeriodSeconds',
|
|
13
13
|
'metadata.generateName',
|
|
14
|
+
'metadata.ownerReferences',
|
|
14
15
|
];
|
|
15
16
|
const STEVE_NEVER_SAVE = NEVER_ADD.filter((na) => !STEVE_ADD.includes(na));
|
|
16
17
|
|
|
@@ -58,4 +59,8 @@ export default class SteveModel extends HybridModel {
|
|
|
58
59
|
|
|
59
60
|
return val;
|
|
60
61
|
}
|
|
62
|
+
|
|
63
|
+
paginationEnabled() {
|
|
64
|
+
return this.$getters['paginationEnabled'](this.type);
|
|
65
|
+
}
|
|
61
66
|
}
|
|
@@ -15,9 +15,11 @@ import {
|
|
|
15
15
|
HPA,
|
|
16
16
|
SECRET
|
|
17
17
|
} from '@shell/config/types';
|
|
18
|
-
import { CAPI as CAPI_LAB_AND_ANO, CATTLE_PUBLIC_ENDPOINTS } from '@shell/config/labels-annotations';
|
|
18
|
+
import { CAPI as CAPI_LAB_AND_ANO, CATTLE_PUBLIC_ENDPOINTS, STORAGE } from '@shell/config/labels-annotations';
|
|
19
19
|
import { Schema } from '@shell/plugins/steve/schema';
|
|
20
20
|
import { PaginationSettingsStore } from '@shell/types/resources/settings';
|
|
21
|
+
import paginationUtils from '@shell/utils/pagination-utils';
|
|
22
|
+
import { KubeLabelSelector, KubeLabelSelectorExpression } from '@shell/types/kube/kube-api';
|
|
21
23
|
|
|
22
24
|
/**
|
|
23
25
|
* This is a workaround for a ts build issue found in check-plugins-build.
|
|
@@ -25,19 +27,30 @@ import { PaginationSettingsStore } from '@shell/types/resources/settings';
|
|
|
25
27
|
* The build would error on <ns>.name, it somehow doesn't know about the steve model's properties (they are included in typegen)
|
|
26
28
|
*/
|
|
27
29
|
interface Namespace extends ModelNamespace {
|
|
30
|
+
id: string;
|
|
28
31
|
name: string;
|
|
32
|
+
metadata: {
|
|
33
|
+
name: string
|
|
34
|
+
}
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
class NamespaceProjectFilters {
|
|
32
38
|
/**
|
|
33
39
|
* User needs all resources.... except if there's some settings which should remove resources in specific circumstances
|
|
34
40
|
*/
|
|
35
|
-
protected handlePrefAndSettingFilter(
|
|
41
|
+
protected handlePrefAndSettingFilter(args: {
|
|
42
|
+
allNamespaces: Namespace[],
|
|
43
|
+
showReservedRancherNamespaces: boolean,
|
|
44
|
+
productHidesSystemNamespaces: boolean,
|
|
45
|
+
}): PaginationParamFilter[] {
|
|
46
|
+
const { allNamespaces, showReservedRancherNamespaces, productHidesSystemNamespaces } = args;
|
|
47
|
+
|
|
36
48
|
// These are AND'd together
|
|
37
49
|
// Not ns 1 AND ns 2
|
|
38
50
|
return allNamespaces.reduce((res, ns) => {
|
|
39
51
|
// Links to ns.isObscure and covers things like `c-`, `user-`, etc (see OBSCURE_NAMESPACE_PREFIX)
|
|
40
|
-
const hideObscure =
|
|
52
|
+
const hideObscure = showReservedRancherNamespaces ? false : ns.isObscure;
|
|
53
|
+
|
|
41
54
|
// Links to ns.isSystem and covers things like ns with system annotation, hardcoded list, etc
|
|
42
55
|
const hideSystem = productHidesSystemNamespaces ? ns.isSystem : false;
|
|
43
56
|
|
|
@@ -58,7 +71,12 @@ class NamespaceProjectFilters {
|
|
|
58
71
|
*
|
|
59
72
|
* Users resources are those not in system namespaces
|
|
60
73
|
*/
|
|
61
|
-
protected handleSystemOrUserFilter(
|
|
74
|
+
protected handleSystemOrUserFilter(args: {
|
|
75
|
+
allNamespaces: Namespace[],
|
|
76
|
+
isAllSystem: boolean,
|
|
77
|
+
isAllUser: boolean,
|
|
78
|
+
}) {
|
|
79
|
+
const { allNamespaces, isAllSystem } = args;
|
|
62
80
|
const allSystem = allNamespaces.filter((ns) => ns.isSystem);
|
|
63
81
|
|
|
64
82
|
// > Neither of these use projectsOrNamespaces to avoid scenarios where the local cluster provides a namespace which has
|
|
@@ -118,6 +136,14 @@ class NamespaceProjectFilters {
|
|
|
118
136
|
* Helper functions for steve pagination
|
|
119
137
|
*/
|
|
120
138
|
class StevePaginationUtils extends NamespaceProjectFilters {
|
|
139
|
+
/**
|
|
140
|
+
* Match
|
|
141
|
+
* - a-z (case insensitive)
|
|
142
|
+
* - 0-9
|
|
143
|
+
* - `-`, `_`, `.`
|
|
144
|
+
*/
|
|
145
|
+
static VALID_FIELD_VALUE_REGEX = /^[\w\-.]+$/;
|
|
146
|
+
|
|
121
147
|
/**
|
|
122
148
|
* Filtering with the vai cache supports specific fields
|
|
123
149
|
* 1) Those listed here
|
|
@@ -168,7 +194,7 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
168
194
|
{ field: '_type' },
|
|
169
195
|
{ field: 'reason' },
|
|
170
196
|
{ field: 'involvedObject.kind' },
|
|
171
|
-
|
|
197
|
+
{ field: 'involvedObject.uid' },
|
|
172
198
|
{ field: 'message' },
|
|
173
199
|
],
|
|
174
200
|
[CATALOG.CLUSTER_REPO]: [
|
|
@@ -189,17 +215,17 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
189
215
|
],
|
|
190
216
|
[SERVICE]: [
|
|
191
217
|
{ field: 'spec.type' },
|
|
192
|
-
|
|
218
|
+
{ field: 'spec.clusterIP' },
|
|
193
219
|
],
|
|
194
220
|
[INGRESS]: [
|
|
195
|
-
|
|
196
|
-
|
|
221
|
+
{ field: 'spec.rules.host' }, // Pending API Support - BUG - https://github.com/rancher/rancher/issues/50526
|
|
222
|
+
{ field: 'spec.ingressClassName' },
|
|
197
223
|
],
|
|
198
224
|
[HPA]: [
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
225
|
+
{ field: 'spec.scaleTargetRef.name' }, // Pending API Support - BUG - https://github.com/rancher/rancher/issues/50527
|
|
226
|
+
{ field: 'spec.minReplicas' }, // Pending API Support - BUG - https://github.com/rancher/rancher/issues/50527
|
|
227
|
+
{ field: 'spec.maxReplicas' }, // Pending API Support - BUG - https://github.com/rancher/rancher/issues/50527
|
|
228
|
+
{ field: 'spec.currentReplicas' }, // Pending API Support - BUG - https://github.com/rancher/rancher/issues/50527
|
|
203
229
|
],
|
|
204
230
|
[PVC]: [
|
|
205
231
|
{ field: 'spec.volumeName' },
|
|
@@ -210,27 +236,37 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
210
236
|
],
|
|
211
237
|
[STORAGE_CLASS]: [
|
|
212
238
|
{ field: 'provisioner' },
|
|
213
|
-
|
|
239
|
+
{ field: `metadata.annotations[${ STORAGE.DEFAULT_STORAGE_CLASS }]` },
|
|
214
240
|
],
|
|
215
241
|
[CATALOG.APP]: [
|
|
216
242
|
{ field: 'spec.chart.metadata.name' }
|
|
217
243
|
],
|
|
218
244
|
[WORKLOAD_TYPES.CRON_JOB]: [
|
|
219
|
-
{ field: `metadata.annotations[${ CATTLE_PUBLIC_ENDPOINTS }]` }
|
|
245
|
+
{ field: `metadata.annotations[${ CATTLE_PUBLIC_ENDPOINTS }]` },
|
|
246
|
+
{ field: 'spec.template.spec.containers.image' }, // Pending API Support - BUG - https://github.com/rancher/rancher/issues/50526
|
|
220
247
|
],
|
|
221
248
|
[WORKLOAD_TYPES.DAEMON_SET]: [
|
|
222
|
-
{ field: `metadata.annotations[${ CATTLE_PUBLIC_ENDPOINTS }]` }
|
|
249
|
+
{ field: `metadata.annotations[${ CATTLE_PUBLIC_ENDPOINTS }]` },
|
|
250
|
+
{ field: 'spec.template.spec.containers.image' }, // Pending API Support - BUG - https://github.com/rancher/rancher/issues/50526
|
|
223
251
|
],
|
|
224
252
|
[WORKLOAD_TYPES.DEPLOYMENT]: [
|
|
225
|
-
{ field: `metadata.annotations[${ CATTLE_PUBLIC_ENDPOINTS }]` }
|
|
253
|
+
{ field: `metadata.annotations[${ CATTLE_PUBLIC_ENDPOINTS }]` },
|
|
254
|
+
{ field: 'spec.template.spec.containers.image' }, // Pending API Support - BUG - https://github.com/rancher/rancher/issues/50526
|
|
226
255
|
],
|
|
227
256
|
[WORKLOAD_TYPES.JOB]: [
|
|
228
|
-
{ field: `metadata.annotations[${ CATTLE_PUBLIC_ENDPOINTS }]` }
|
|
257
|
+
{ field: `metadata.annotations[${ CATTLE_PUBLIC_ENDPOINTS }]` },
|
|
258
|
+
{ field: 'spec.template.spec.containers.image' }, // Pending API Support - BUG - https://github.com/rancher/rancher/issues/50526
|
|
229
259
|
],
|
|
230
260
|
[WORKLOAD_TYPES.STATEFUL_SET]: [
|
|
231
|
-
{ field: `metadata.annotations[${ CATTLE_PUBLIC_ENDPOINTS }]` }
|
|
232
|
-
|
|
233
|
-
|
|
261
|
+
{ field: `metadata.annotations[${ CATTLE_PUBLIC_ENDPOINTS }]` },
|
|
262
|
+
{ field: 'spec.template.spec.containers.image' }, // Pending API Support - BUG - https://github.com/rancher/rancher/issues/50526
|
|
263
|
+
],
|
|
264
|
+
[WORKLOAD_TYPES.REPLICA_SET]: [
|
|
265
|
+
{ field: 'spec.template.spec.containers.image' }, // Pending API Support - BUG - https://github.com/rancher/rancher/issues/50526
|
|
266
|
+
],
|
|
267
|
+
[WORKLOAD_TYPES.REPLICATION_CONTROLLER]: [
|
|
268
|
+
{ field: 'spec.template.spec.containers.image' }, // Pending API Support - BUG - https://github.com/rancher/rancher/issues/50526
|
|
269
|
+
],
|
|
234
270
|
}
|
|
235
271
|
|
|
236
272
|
private convertArrayPath(path: string): string {
|
|
@@ -253,7 +289,7 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
253
289
|
selection,
|
|
254
290
|
isAllNamespaces,
|
|
255
291
|
isLocalCluster,
|
|
256
|
-
|
|
292
|
+
showReservedRancherNamespaces,
|
|
257
293
|
productHidesSystemNamespaces,
|
|
258
294
|
}: {
|
|
259
295
|
allNamespaces: Namespace[],
|
|
@@ -263,14 +299,18 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
263
299
|
*/
|
|
264
300
|
isAllNamespaces: boolean,
|
|
265
301
|
/**
|
|
266
|
-
* Weird things be happening if the target cluster is local / upstream.
|
|
302
|
+
* Weird things be happening if the target cluster is local / upstream. Use this to check what cluster we're in
|
|
267
303
|
*/
|
|
268
304
|
isLocalCluster: boolean,
|
|
269
305
|
/**
|
|
306
|
+
* User preference states we should show reserved rancher namespaces. Preference description "Show dynamic Namespaces managed by Rancher (not intended for editing or deletion)"
|
|
307
|
+
*
|
|
270
308
|
* Links to ns.isObscure and covers things like `c-`, `user-`, etc (see OBSCURE_NAMESPACE_PREFIX)
|
|
271
309
|
*/
|
|
272
|
-
|
|
310
|
+
showReservedRancherNamespaces: boolean,
|
|
273
311
|
/**
|
|
312
|
+
* Product config states that system namespaces should be hidden
|
|
313
|
+
*
|
|
274
314
|
* Links to ns.isSystem and covers things like ns with system annotation, hardcoded list, etc
|
|
275
315
|
*/
|
|
276
316
|
productHidesSystemNamespaces: boolean,
|
|
@@ -288,7 +328,7 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
288
328
|
// - Only System Namespaces - Gimme resources in the system namespaces (which shouldn't be many namespaces)
|
|
289
329
|
// - Only User Namespaces - Gimme resources NOT in system namespaces
|
|
290
330
|
// - User selection - Gimme resources in specific Projects or Namespaces
|
|
291
|
-
if (isAllNamespaces && (
|
|
331
|
+
if (isAllNamespaces && (showReservedRancherNamespaces && !productHidesSystemNamespaces)) {
|
|
292
332
|
// No-op. Everything is returned
|
|
293
333
|
return {
|
|
294
334
|
projectsOrNamespaces: [],
|
|
@@ -303,9 +343,11 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
303
343
|
// &filter=metadata.namespace=abc
|
|
304
344
|
let filters: PaginationParamFilter[] = [];
|
|
305
345
|
|
|
306
|
-
if (!
|
|
307
|
-
// We need to hide
|
|
308
|
-
filters = this.handlePrefAndSettingFilter(
|
|
346
|
+
if (!showReservedRancherNamespaces || productHidesSystemNamespaces) {
|
|
347
|
+
// We need to hide reserved namespaces ('c-', 'user-', etc) OR system namespaces
|
|
348
|
+
filters = this.handlePrefAndSettingFilter({
|
|
349
|
+
allNamespaces, showReservedRancherNamespaces, productHidesSystemNamespaces
|
|
350
|
+
});
|
|
309
351
|
}
|
|
310
352
|
|
|
311
353
|
const isAllSystem = selection[0] === NAMESPACE_FILTER_ALL_SYSTEM;
|
|
@@ -313,7 +355,9 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
313
355
|
|
|
314
356
|
if (selection.length === 1 && (isAllSystem || isAllUser)) {
|
|
315
357
|
// Filter by resources either in or not in system namespaces
|
|
316
|
-
filters.push(...this.handleSystemOrUserFilter(
|
|
358
|
+
filters.push(...this.handleSystemOrUserFilter({
|
|
359
|
+
allNamespaces, isAllSystem, isAllUser
|
|
360
|
+
}));
|
|
317
361
|
} else {
|
|
318
362
|
// User has one or more projects or namespaces
|
|
319
363
|
const res = this.handleSelectionFilter(selection, isLocalCluster);
|
|
@@ -328,13 +372,13 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
328
372
|
};
|
|
329
373
|
}
|
|
330
374
|
|
|
331
|
-
public createParamsForPagination(schema: Schema, opt: ActionFindPageArgs): string | undefined {
|
|
375
|
+
public createParamsForPagination({ schema, opt }: {schema?: Schema, opt: ActionFindPageArgs}): string | undefined {
|
|
332
376
|
if (!opt.pagination) {
|
|
333
377
|
return;
|
|
334
378
|
}
|
|
335
379
|
|
|
336
380
|
const params: string[] = [];
|
|
337
|
-
const namespaceParam = this.convertPaginationParams(schema, opt.pagination.projectsOrNamespaces);
|
|
381
|
+
const namespaceParam = this.convertPaginationParams({ schema, filters: opt.pagination.projectsOrNamespaces });
|
|
338
382
|
|
|
339
383
|
if (namespaceParam) {
|
|
340
384
|
params.push(namespaceParam);
|
|
@@ -344,8 +388,11 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
344
388
|
params.push(`page=${ opt.pagination.page }`);
|
|
345
389
|
}
|
|
346
390
|
|
|
347
|
-
if (opt.pagination.pageSize) {
|
|
391
|
+
if (!!opt.pagination.pageSize || opt.pagination.pageSize === 0) {
|
|
348
392
|
params.push(`pagesize=${ opt.pagination.pageSize }`);
|
|
393
|
+
} else {
|
|
394
|
+
// Prevent unlimited resources in response
|
|
395
|
+
params.push(`pagesize=${ paginationUtils.defaultPageSize }`);
|
|
349
396
|
}
|
|
350
397
|
|
|
351
398
|
if (opt.pagination.sort?.length) {
|
|
@@ -365,12 +412,20 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
365
412
|
params.push(`sort=${ joined }`);
|
|
366
413
|
|
|
367
414
|
if (validateFields.invalid.length) {
|
|
368
|
-
console.warn(`Pagination API does not support sorting '${ schema
|
|
415
|
+
console.warn(`Pagination API does not support sorting '${ schema?.id || opt.url }' by the requested fields: ${ uniq(validateFields.invalid).join(', ') }`); // eslint-disable-line no-console
|
|
369
416
|
}
|
|
370
417
|
}
|
|
371
418
|
|
|
372
419
|
if (opt.pagination.filters?.length) {
|
|
373
|
-
const filters = this.convertPaginationParams(schema, opt.pagination.filters);
|
|
420
|
+
const filters = this.convertPaginationParams({ schema, filters: opt.pagination.filters });
|
|
421
|
+
|
|
422
|
+
if (filters) {
|
|
423
|
+
params.push(filters);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (opt.pagination.labelSelector) {
|
|
428
|
+
const filters = this.convertLabelSelectorPaginationParams({ labelSelector: opt.pagination.labelSelector });
|
|
374
429
|
|
|
375
430
|
if (filters) {
|
|
376
431
|
params.push(filters);
|
|
@@ -386,7 +441,7 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
386
441
|
/**
|
|
387
442
|
* Check if the API supports filtering by this field
|
|
388
443
|
*/
|
|
389
|
-
private validateField(state: { checked: string[], invalid: string[]}, schema
|
|
444
|
+
private validateField(state: { checked: string[], invalid: string[]}, schema?: Schema, field?: string) {
|
|
390
445
|
if (!field) {
|
|
391
446
|
return; // no field, so not invalid
|
|
392
447
|
}
|
|
@@ -400,6 +455,7 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
400
455
|
// First check in our hardcoded list of supported filters
|
|
401
456
|
if (
|
|
402
457
|
process.env.NODE_ENV === 'dev' &&
|
|
458
|
+
!!schema &&
|
|
403
459
|
[
|
|
404
460
|
StevePaginationUtils.VALID_FIELDS[''], // Global
|
|
405
461
|
StevePaginationUtils.VALID_FIELDS[schema.id], // Type specific
|
|
@@ -430,7 +486,7 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
430
486
|
/**
|
|
431
487
|
* Convert our {@link PaginationParam} definition of params to a set of url params
|
|
432
488
|
*/
|
|
433
|
-
private convertPaginationParams(schema: Schema, filters: PaginationParam[]
|
|
489
|
+
private convertPaginationParams({ schema, filters = [] }: {schema?: Schema, filters: PaginationParam[]}): string {
|
|
434
490
|
const validateFields = {
|
|
435
491
|
checked: new Array<string>(),
|
|
436
492
|
invalid: new Array<string>(),
|
|
@@ -451,8 +507,9 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
451
507
|
// != not exact match (!equals + exact)
|
|
452
508
|
// !~ not partial match (!equals + !exact)
|
|
453
509
|
const operator = `${ field.equals ? '' : '!' }${ field.exact ? '=' : '~' }`;
|
|
510
|
+
const quotedValue = StevePaginationUtils.VALID_FIELD_VALUE_REGEX.test(value) ? value : `"${ value }"`;
|
|
454
511
|
|
|
455
|
-
return `${ this.convertArrayPath(field.field) }${ operator }${
|
|
512
|
+
return `${ this.convertArrayPath(field.field) }${ operator }${ quotedValue }`;
|
|
456
513
|
}
|
|
457
514
|
|
|
458
515
|
return field.value;
|
|
@@ -470,11 +527,116 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
470
527
|
const res = Object.keys(unique).join('&'); // This means AND
|
|
471
528
|
|
|
472
529
|
if (validateFields.invalid.length) {
|
|
473
|
-
console.warn(`Pagination API does not support filtering '${ schema
|
|
530
|
+
console.warn(`Pagination API does not support filtering '${ schema?.id || 'unknown' }' by the requested fields: ${ uniq(validateFields.invalid).join(', ') }`); // eslint-disable-line no-console
|
|
474
531
|
}
|
|
475
532
|
|
|
476
533
|
return res;
|
|
477
534
|
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Convert kube labelSelector object into steve filter params
|
|
538
|
+
*
|
|
539
|
+
* A lot of the requirements and details are taken directly from
|
|
540
|
+
* https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
|
|
541
|
+
*/
|
|
542
|
+
private convertLabelSelectorPaginationParams({ labelSelector }: { labelSelector: KubeLabelSelector}): string {
|
|
543
|
+
// Get a list of matchExpressions
|
|
544
|
+
const expressions: KubeLabelSelectorExpression[] = labelSelector.matchExpressions ? [...labelSelector.matchExpressions] : [];
|
|
545
|
+
|
|
546
|
+
// matchLabels are just simpler versions of matchExpressions, for ease convert them
|
|
547
|
+
if (labelSelector.matchLabels) {
|
|
548
|
+
Object.entries(labelSelector.matchLabels).forEach(([key, value]) => {
|
|
549
|
+
const expression: KubeLabelSelectorExpression = {
|
|
550
|
+
key,
|
|
551
|
+
values: [value],
|
|
552
|
+
operator: 'In'
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
expressions.push(expression);
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// concert all matchExpressions into string params
|
|
560
|
+
const filters: string[] = expressions.reduce((res, exp) => {
|
|
561
|
+
const labelKey = `metadata.labels[${ exp.key }]`;
|
|
562
|
+
|
|
563
|
+
switch (exp.operator) {
|
|
564
|
+
case 'In':
|
|
565
|
+
if (!exp.values?.length) {
|
|
566
|
+
console.error(`Skipping labelSelector to API filter param conversion for ${ exp.key }(IN) as no value was supplied`); // eslint-disable-line no-console
|
|
567
|
+
|
|
568
|
+
return res;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// foo IN [bar] => ?filter=foo+IN+(bar)
|
|
572
|
+
// foo IN [bar, baz2] => ?filter=foo+IN+(bar,baz2)
|
|
573
|
+
res.push(`filter=${ labelKey } IN (${ exp.values.join(',') })`);
|
|
574
|
+
break;
|
|
575
|
+
case 'NotIn':
|
|
576
|
+
|
|
577
|
+
if (!exp.values?.length) {
|
|
578
|
+
console.error(`Skipping labelSelector to API filter param conversion for ${ exp.key }(NOTIN) as no value was supplied`); // eslint-disable-line no-console
|
|
579
|
+
|
|
580
|
+
return res;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// aaa NotIn [bar, baz2]=> ?filter=foo+NOTIN+(bar,baz2)
|
|
584
|
+
res.push(`filter=${ labelKey } NOTIN (${ exp.values.join(',') })`);
|
|
585
|
+
break;
|
|
586
|
+
case 'Exists':
|
|
587
|
+
|
|
588
|
+
if (exp.values?.length) {
|
|
589
|
+
console.error(`Skipping labelSelector to API filter param conversion for ${ exp.key }(Exists) as no value was supplied`); // eslint-disable-line no-console
|
|
590
|
+
|
|
591
|
+
return res;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// bbb Exists=> ?filter=bbb
|
|
595
|
+
res.push(`filter=${ labelKey }`);
|
|
596
|
+
break;
|
|
597
|
+
case 'DoesNotExist':
|
|
598
|
+
if (exp.values?.length) {
|
|
599
|
+
console.error(`Skipping labelSelector to API filter param conversion for ${ exp.key }(DoesNotExist) as no value was supplied`); // eslint-disable-line no-console
|
|
600
|
+
|
|
601
|
+
return res;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// ccc DoesNotExist ?filter=!bbb. # or %21bbb
|
|
605
|
+
res.push(`filter=!${ labelKey }`);
|
|
606
|
+
break;
|
|
607
|
+
case 'Gt':
|
|
608
|
+
// Currently broken - see https://github.com/rancher/rancher/issues/50057
|
|
609
|
+
// Only applicable to node affinity (atm) - https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#operators
|
|
610
|
+
|
|
611
|
+
if (typeof exp.values !== 'string') {
|
|
612
|
+
console.error(`Skipping labelSelector to API filter param conversion for ${ exp.key }(Gt) as no value was supplied`); // eslint-disable-line no-console
|
|
613
|
+
|
|
614
|
+
return res;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// ddd Gt 1=> ?filter=ddd+>+1
|
|
618
|
+
res.push(`filter=${ labelKey } > (${ exp.values })`);
|
|
619
|
+
break;
|
|
620
|
+
case 'Lt':
|
|
621
|
+
// Currently broken - see https://github.com/rancher/rancher/issues/50057
|
|
622
|
+
// Only applicable to node affinity (atm) - https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#operators
|
|
623
|
+
if (typeof exp.values !== 'string') {
|
|
624
|
+
console.error(`Skipping labelSelector to API filter param conversion for ${ exp.key }(Lt) as no value was supplied`); // eslint-disable-line no-console
|
|
625
|
+
|
|
626
|
+
return res;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// eee Lt 2=> ?filter=eee+<+2
|
|
630
|
+
res.push(`filter=${ labelKey } < (${ exp.values })`);
|
|
631
|
+
break;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
return res;
|
|
635
|
+
}, [] as string[]);
|
|
636
|
+
|
|
637
|
+
// "All of the requirements, from both matchLabels and matchExpressions are ANDed together -- they must all be satisfied in order to match"
|
|
638
|
+
return filters.join('&');
|
|
639
|
+
}
|
|
478
640
|
}
|
|
479
641
|
|
|
480
642
|
export const PAGINATION_SETTINGS_STORE_DEFAULTS: PaginationSettingsStore = {
|
|
@@ -314,7 +314,9 @@ self.onmessage = (e) => {
|
|
|
314
314
|
if (workerActions[action]) {
|
|
315
315
|
workerActions[action](e?.data[action]);
|
|
316
316
|
} else {
|
|
317
|
-
|
|
317
|
+
// This catches any window sendMessage event. We're hitting this on hot-reload of code where somehow this file is loaded
|
|
318
|
+
// Could be related to extensions, which have their own version of this
|
|
319
|
+
console.debug('no associated action for:', action); // eslint-disable-line no-console
|
|
318
320
|
}
|
|
319
321
|
});
|
|
320
322
|
}; // bind everything to the worker's onmessage handler via the workerActions
|