@rancher/shell 3.0.12-rc.5 → 3.0.12-rc.6
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/apis/intf/resources-api/resource-base.ts +42 -2
- package/apis/intf/resources-api/resource-instance.ts +101 -0
- package/apis/intf/resources-api/resources-api.ts +177 -23
- package/apis/intf/resources.ts +8 -6
- package/apis/resources/__tests__/resources-api-class.test.ts +309 -28
- package/apis/resources/resources-api-class.ts +232 -43
- package/assets/images/providers/traefik.png +0 -0
- package/assets/translations/en-us.yaml +10 -4
- package/chart/__tests__/rancher-monitoring-dashboards-index.test.ts +269 -0
- package/chart/rancher-monitoring-dashboards/index.vue +155 -0
- package/cloud-credential/__tests__/generic.test.ts +132 -0
- package/cloud-credential/generic.vue +33 -3
- package/components/EtcdInfoBanner.vue +2 -12
- package/components/GrafanaDashboard.vue +2 -8
- package/components/Resource/Detail/Masthead/__tests__/index.test.ts +68 -14
- package/components/Resource/Detail/Masthead/index.vue +8 -3
- package/components/form/Security.vue +1 -1
- package/components/formatter/Translate.vue +22 -1
- package/components/nav/Group.vue +5 -10
- package/components/nav/TopLevelMenu.vue +1 -30
- package/components/nav/__tests__/Group.test.ts +61 -0
- package/config/labels-annotations.js +1 -0
- package/config/table-headers.js +5 -2
- package/core/__tests__/plugin-products-apply.test.ts +787 -0
- package/core/__tests__/plugin-products-extend.test.ts +189 -0
- package/core/__tests__/plugin-products-helpers.test.ts +81 -78
- package/core/__tests__/plugin-products-new.test.ts +389 -0
- package/core/__tests__/plugin-products-scenarios.test.ts +980 -0
- package/core/__tests__/plugin-products-side-menu.test.ts +1935 -0
- package/core/plugin-products-base.ts +201 -93
- package/core/plugin-products-extending.ts +1 -1
- package/core/plugin-products-external.ts +380 -0
- package/core/plugin-products-helpers.ts +28 -24
- package/core/plugin-products-internal.ts +207 -0
- package/core/plugin-products-top-level.ts +10 -5
- package/core/plugin-products-type-guards.ts +17 -6
- package/core/plugin-products.ts +5 -7
- package/core/plugin-types.ts +1 -389
- package/core/plugin.ts +10 -11
- package/core/types.ts +6 -202
- package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +52 -0
- package/detail/pod.vue +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +0 -2
- package/edit/auth/AuthProviderWarningBanners.vue +12 -0
- package/edit/auth/__tests__/AuthProviderWarningBanners.test.ts +10 -1
- package/edit/auth/__tests__/azuread.test.ts +1 -0
- package/edit/auth/__tests__/github.test.ts +1 -0
- package/edit/auth/__tests__/oidc.test.ts +1 -0
- package/edit/auth/__tests__/saml.test.ts +1 -0
- package/edit/auth/ldap/__tests__/index.test.ts +1 -0
- package/edit/provisioning.cattle.io.cluster/index.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/rke2.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +2 -2
- package/list/management.cattle.io.user.vue +24 -5
- package/list/utils/management.cattle.io.cluster.utils.ts +1 -1
- package/machine-config/__tests__/generic.test.ts +163 -0
- package/machine-config/components/EC2Networking.vue +31 -7
- package/machine-config/components/__tests__/EC2Networking.test.ts +38 -15
- package/machine-config/generic.vue +32 -5
- package/mixins/resource-fetch.js +1 -1
- package/models/__tests__/rke-machine.cattle.io.vmwarevspheremachinetemplate.test.ts +22 -0
- package/models/pod.js +12 -10
- package/models/rke-machine.cattle.io.vmwarevspheremachinetemplate.js +9 -0
- package/package.json +1 -1
- package/pages/auth/login.vue +1 -1
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +110 -0
- package/pages/c/_cluster/apps/charts/install.vue +29 -0
- package/pages/c/_cluster/auth/config/index.vue +11 -4
- package/pages/c/_cluster/monitoring/index.vue +6 -1
- package/plugins/dashboard-store/resource-class.js +10 -3
- package/plugins/steve/__tests__/steve-class-resource-api.test.ts +147 -0
- package/plugins/steve/steve-class.js +43 -0
- package/plugins/steve/subscribe.js +11 -0
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +115 -0
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +83 -3
- package/store/__tests__/auth.test.ts +18 -0
- package/store/__tests__/notifications.test.ts +466 -1
- package/store/__tests__/ui-context.test.ts +255 -0
- package/store/auth.js +11 -1
- package/store/features.js +1 -0
- package/store/plugins.js +6 -0
- package/types/rancher/steve.api.ts +2 -2
- package/types/shell/index.d.ts +58 -0
- package/types/store/dashboard-store.types.ts +2 -2
- package/types/store/type-map.ts +262 -1
- package/utils/async.ts +2 -0
- package/utils/grafana.js +2 -17
- package/utils/monitoring.js +38 -1
- package/core/__tests__/plugin-products.test.ts +0 -4694
package/types/store/type-map.ts
CHANGED
|
@@ -1,3 +1,264 @@
|
|
|
1
|
+
import { PluginRouteRecordRaw } from '@shell/core/types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The product as seen by the type-map
|
|
5
|
+
*/
|
|
6
|
+
export interface TypeMapProduct {
|
|
7
|
+
/**
|
|
8
|
+
* The category this product belongs under. i.e. 'config'
|
|
9
|
+
*/
|
|
10
|
+
category?: string;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Hide the Copy KubeConfig button in the header
|
|
14
|
+
*/
|
|
15
|
+
hideCopyConfig?: boolean;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Hide the Download KubeConfig button in the header
|
|
19
|
+
*/
|
|
20
|
+
hideKubeConfig?: boolean;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Hide the Kubectl Shell button in the header
|
|
24
|
+
*/
|
|
25
|
+
hideKubeShell?: boolean;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Hide the Namespace location
|
|
29
|
+
*/
|
|
30
|
+
hideNamespaceLocation?: boolean;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Hide the system resources
|
|
34
|
+
*/
|
|
35
|
+
hideSystemResources?: boolean;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The icon that should be displayed beside this item in the navigation.
|
|
39
|
+
*/
|
|
40
|
+
icon?: string;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Alternative to the icon property. Uses require
|
|
44
|
+
*/
|
|
45
|
+
svg?: Function;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Only load the product if the feature is present
|
|
49
|
+
*/
|
|
50
|
+
ifFeature?: string | RegExp;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Only load the product if the type is present
|
|
54
|
+
*/
|
|
55
|
+
ifHave?: string;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Only load the product if the group is present
|
|
59
|
+
*/
|
|
60
|
+
ifHaveGroup?: string | RegExp;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Only load the product if the type is present
|
|
64
|
+
*/
|
|
65
|
+
ifHaveType?: string | RegExp;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Hide the product if the type is present (opposite of ifHaveType)
|
|
69
|
+
*/
|
|
70
|
+
ifNotHaveType?: string | RegExp;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The vuex store that this product should use by default i.e. 'management'
|
|
74
|
+
*/
|
|
75
|
+
inStore?: string;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Show the cluster switcher in the navigation
|
|
79
|
+
*/
|
|
80
|
+
showClusterSwitcher?: boolean;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Indicates whether UI Extensions can add pages to this product
|
|
84
|
+
*/
|
|
85
|
+
extendable?: boolean;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Show the namespace filter in the header
|
|
89
|
+
*/
|
|
90
|
+
showNamespaceFilter?: boolean;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* A number used to determine where in navigation this item will be placed. The highest number will be at the top of the list.
|
|
94
|
+
*/
|
|
95
|
+
weight?: number;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The route that the product will lead to if click on in navigation.
|
|
99
|
+
*/
|
|
100
|
+
to?: PluginRouteRecordRaw;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Product name
|
|
104
|
+
*
|
|
105
|
+
* Defaults to the DSL fn product arg
|
|
106
|
+
*/
|
|
107
|
+
name?: string;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
*
|
|
111
|
+
*/
|
|
112
|
+
label?: string;
|
|
113
|
+
|
|
114
|
+
labelKey?: string;
|
|
115
|
+
|
|
116
|
+
iconHeader?: string;
|
|
117
|
+
|
|
118
|
+
// Do not use - internal use only
|
|
119
|
+
version?: number;
|
|
120
|
+
|
|
121
|
+
renameGroups?: {
|
|
122
|
+
/** String or regex to match against group internal IDs */
|
|
123
|
+
groupSelector: RegExp | string;
|
|
124
|
+
/** Display name to use for matching groups */
|
|
125
|
+
newName: string;
|
|
126
|
+
}[];
|
|
127
|
+
|
|
128
|
+
moveToGroup?: {
|
|
129
|
+
/** Page identifier — the resource `type` string or the custom page `name` */
|
|
130
|
+
entryId: string;
|
|
131
|
+
/** Target group name as defined in your group config (`name` property) */
|
|
132
|
+
groupName: string;
|
|
133
|
+
/** Ordering weight for the mapping (default: 5). Higher weight takes precedence when multiple rules match */
|
|
134
|
+
weight?: number;
|
|
135
|
+
}[];
|
|
136
|
+
|
|
137
|
+
ignoreGroups?: {
|
|
138
|
+
/** String or regex to match against group names */
|
|
139
|
+
groupSelector: string | RegExp;
|
|
140
|
+
/** Optional conditional function that accepts the root Dashboard Vuex store getters and returns true if the group should be ignored */
|
|
141
|
+
condition?: (getters: any) => boolean;
|
|
142
|
+
}[];
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Whether the product can be removed by users (default: false — products are built-in/not removable unless explicitly set to true)
|
|
146
|
+
*/
|
|
147
|
+
removable?: boolean;
|
|
148
|
+
/**
|
|
149
|
+
* controls whether a workspace switcher dropdown appears in the header (instead of the namespace filter) if set to true
|
|
150
|
+
*/
|
|
151
|
+
showWorkspaceSwitcher?: boolean;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Leaving these here for completeness but I don't think these should be advertised as useable to plugin creators.
|
|
155
|
+
*/
|
|
156
|
+
// ifHaveVerb: string | RegExp;
|
|
157
|
+
// supportRoute: string;
|
|
158
|
+
// typeStoreMap: string;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Used by type-map configureType
|
|
163
|
+
*/
|
|
164
|
+
export interface TypeMapConfigureType {
|
|
165
|
+
/** Override for the name displayed */
|
|
166
|
+
displayName?: string;
|
|
167
|
+
/** Override for the create button string on a list view */
|
|
168
|
+
listCreateButtonLabelKey?: string;
|
|
169
|
+
/** If false, disable create even if schema says it's allowed */
|
|
170
|
+
isCreatable?: boolean;
|
|
171
|
+
/** If false, disable for edit */
|
|
172
|
+
isEditable?: boolean;
|
|
173
|
+
/** If false, disable for remove/delete */
|
|
174
|
+
isRemovable?: boolean;
|
|
175
|
+
/** If false, hide state in columns and masthead */
|
|
176
|
+
showState?: boolean;
|
|
177
|
+
/** If false, hide age in columns and masthead */
|
|
178
|
+
showAge?: boolean;
|
|
179
|
+
/** If false, hide masthead config button in view mode */
|
|
180
|
+
showConfigView?: boolean;
|
|
181
|
+
/** If false, hide masthead in list view */
|
|
182
|
+
showListMasthead?: boolean;
|
|
183
|
+
/** If false, cannot edit or show yaml */
|
|
184
|
+
canYaml?: boolean;
|
|
185
|
+
/** Show the Masthead in the edit resource component */
|
|
186
|
+
resourceEditMasthead?: boolean;
|
|
187
|
+
/** Entry route definition for this resource page */
|
|
188
|
+
customRoute?: PluginRouteRecordRaw | Object;
|
|
189
|
+
/** Hide this type from the nav/search bar on downstream clusters (will only show in "local" cluster) */
|
|
190
|
+
localOnly?: boolean;
|
|
191
|
+
// resource: undefined; // Use this resource in ResourceDetails instead
|
|
192
|
+
// resourceDetail: undefined; // Use this resource specifically for ResourceDetail's detail component
|
|
193
|
+
// resourceEdit: undefined; // Use this resource specifically for ResourceDetail's edit component
|
|
194
|
+
/**
|
|
195
|
+
* Use this to depaginate requests for this type
|
|
196
|
+
*/
|
|
197
|
+
depaginate?: undefined;
|
|
198
|
+
// notFilterNamespace: undefined; // Define namespaces that do not need to be filtered
|
|
199
|
+
// used in configureType options, to be typed later if needed
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Whether this custom page has list groups (definition for grouping items in the list view)
|
|
203
|
+
*/
|
|
204
|
+
listGroups?: {
|
|
205
|
+
/** Icon for the group (relates to icons in rancher-icons */
|
|
206
|
+
icon?: string;
|
|
207
|
+
/** Value for the group (used for grouping items in the list view) */
|
|
208
|
+
value?: string;
|
|
209
|
+
/** Field for the group (used for grouping items in the list view) */
|
|
210
|
+
field?: string;
|
|
211
|
+
/** Column to hide when this group is active */
|
|
212
|
+
hideColumn?: string;
|
|
213
|
+
/** Tooltip key for the group */
|
|
214
|
+
tooltipKey?: string;
|
|
215
|
+
}[];
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Whether the provided list groups will override the default grouping options (e.g. group by namespace, group by cluster, etc.) or be added to them
|
|
219
|
+
*/
|
|
220
|
+
listGroupsWillOverride?: boolean;
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Use this to configure subtypes that should be shown in the list view for this type (e.g. show "pods" and "deployments" in the list view for "workloads")
|
|
224
|
+
*/
|
|
225
|
+
subTypes?: string[];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Used by type-map virtualType
|
|
230
|
+
*/
|
|
231
|
+
export interface TypeMapVirtualType {
|
|
232
|
+
/** Display only if condition is met (relates to IF_HAVE in shell/store/type-map) */
|
|
233
|
+
ifHave?: boolean;
|
|
234
|
+
/** Display only if feature is present (relates to shell/store/features) */
|
|
235
|
+
ifFeature?: string;
|
|
236
|
+
/** Display only if resource type exists */
|
|
237
|
+
ifHaveType?: string;
|
|
238
|
+
/** Used in conjunction with "ifHaveType", display only if resource type allows this verb (GET, POST, PUT, DELETE) */
|
|
239
|
+
ifHaveVerb?: string;
|
|
240
|
+
/** Display label for the custom page */
|
|
241
|
+
label?: string;
|
|
242
|
+
/** Translation key for the label */
|
|
243
|
+
labelKey?: string;
|
|
244
|
+
name: string;
|
|
245
|
+
// /** Name of the page (unique identifier) */
|
|
246
|
+
// name?: string;
|
|
247
|
+
/** Entry route definition for this custom page */
|
|
248
|
+
route?: PluginRouteRecordRaw | Object;
|
|
249
|
+
/** Icon for the custom page (relates to icons in https://github.com/rancher/icons) */
|
|
250
|
+
icon?: 'compass';
|
|
251
|
+
/** Whether this custom page is namespaced or not */
|
|
252
|
+
namespaced?: boolean;
|
|
253
|
+
/** Ordering weight for the custom page */
|
|
254
|
+
weight?: number;
|
|
255
|
+
/** Whether this custom page is exact match */
|
|
256
|
+
exact?: boolean;
|
|
257
|
+
/** Whether this custom page will act as an overview page */
|
|
258
|
+
overview?: boolean;
|
|
259
|
+
/** Whether this custom page has an exact path match */
|
|
260
|
+
'exact-path'?: boolean;
|
|
261
|
+
}
|
|
1
262
|
|
|
2
263
|
/**
|
|
3
264
|
* interface for type-map's' definition for table headers/columns
|
|
@@ -11,7 +272,7 @@ export interface TableColumn {
|
|
|
11
272
|
formatterOpts?: any,
|
|
12
273
|
width?: number,
|
|
13
274
|
tooltip?: string,
|
|
14
|
-
search?: string | boolean,
|
|
275
|
+
search?: string | string[] | boolean,
|
|
15
276
|
}
|
|
16
277
|
|
|
17
278
|
export const COLUMN_BREAKPOINTS = {
|
package/utils/async.ts
CHANGED
|
@@ -5,6 +5,8 @@ export const waitFor = (testFn: Function, msg = '', timeoutMs = 3000000, interva
|
|
|
5
5
|
if (testFn()) {
|
|
6
6
|
gatedLog('Wait for', msg || 'unknown', 'done immediately');
|
|
7
7
|
resolve(this);
|
|
8
|
+
|
|
9
|
+
return;
|
|
8
10
|
}
|
|
9
11
|
const timeout = setTimeout(() => {
|
|
10
12
|
gatedLog('Wait for', msg, 'timed out');
|
package/utils/grafana.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { haveV2Monitoring } from '@shell/utils/monitoring';
|
|
1
|
+
import { haveV2Monitoring, fetchMonitoringVersion } from '@shell/utils/monitoring';
|
|
2
2
|
import { parse as parseUrl, addParam } from '@shell/utils/url';
|
|
3
|
-
import { CATALOG } from '@shell/config/types';
|
|
4
3
|
|
|
5
4
|
// these two versions of monitoring included a bug fix attempt that required the local cluster to use a different url
|
|
6
5
|
// the solution going forward doesn't require this, see https://github.com/rancher/dashboard/issues/8885
|
|
@@ -60,21 +59,7 @@ export async function dashboardExists(monitoringVersion, store, clusterId, embed
|
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
export async function allDashboardsExist(store, clusterId, embeddedUrls, storeName = 'cluster', projectId = null) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
let monitoringVersion = '';
|
|
66
|
-
|
|
67
|
-
if (!projectId && store.getters[`${ storeName }/canList`](CATALOG.APP)) {
|
|
68
|
-
try {
|
|
69
|
-
res = await store.dispatch(`${ storeName }/find`, {
|
|
70
|
-
type: CATALOG.APP,
|
|
71
|
-
id: 'cattle-monitoring-system/rancher-monitoring'
|
|
72
|
-
});
|
|
73
|
-
} catch (err) {
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
monitoringVersion = res?.currentVersion;
|
|
77
|
-
}
|
|
62
|
+
const monitoringVersion = projectId ? '' : await fetchMonitoringVersion(store, storeName);
|
|
78
63
|
|
|
79
64
|
const existPromises = embeddedUrls.map((url) => dashboardExists(monitoringVersion, store, clusterId, url, storeName, projectId));
|
|
80
65
|
|
package/utils/monitoring.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Helpers for determining if V2 or v1 Monitoring are installed
|
|
2
2
|
|
|
3
|
-
import { SCHEMA, MONITORING, ENDPOINTS } from '@shell/config/types';
|
|
3
|
+
import { SCHEMA, MONITORING, ENDPOINTS, CATALOG } from '@shell/config/types';
|
|
4
4
|
import { normalizeType } from '@shell/plugins/dashboard-store/normalize';
|
|
5
5
|
import { findBy } from '@shell/utils/array';
|
|
6
6
|
import { isEmpty } from '@shell/utils/object';
|
|
@@ -30,6 +30,43 @@ export function haveV2Monitoring(getters) {
|
|
|
30
30
|
|
|
31
31
|
export const CATTLE_MONITORING_NAMESPACE = 'cattle-monitoring-system';
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Look up the installed Rancher monitoring app, preferring the new
|
|
35
|
+
* `rancher-monitoring-dashboards` chart and falling back to the legacy
|
|
36
|
+
* `rancher-monitoring`. Returns null if the user lacks permission, neither
|
|
37
|
+
* chart is installed, or any lookup fails.
|
|
38
|
+
*/
|
|
39
|
+
export async function fetchMonitoringApp(store, storeName) {
|
|
40
|
+
if (!store.getters[`${ storeName }/canList`](CATALOG.APP)) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const ids = [
|
|
45
|
+
`${ CATTLE_MONITORING_NAMESPACE }/rancher-monitoring-dashboards`,
|
|
46
|
+
`${ CATTLE_MONITORING_NAMESPACE }/rancher-monitoring`,
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
for (const id of ids) {
|
|
50
|
+
try {
|
|
51
|
+
const res = await store.dispatch(`${ storeName }/find`, { type: CATALOG.APP, id });
|
|
52
|
+
|
|
53
|
+
if (res) {
|
|
54
|
+
return res;
|
|
55
|
+
}
|
|
56
|
+
} catch (err) {
|
|
57
|
+
// Try the next id; both failing means nothing is installed.
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function fetchMonitoringVersion(store, storeName) {
|
|
65
|
+
const app = await fetchMonitoringApp(store, storeName);
|
|
66
|
+
|
|
67
|
+
return app?.currentVersion || '';
|
|
68
|
+
}
|
|
69
|
+
|
|
33
70
|
async function hasEndpointSubsets(store, id) {
|
|
34
71
|
if (store.getters['cluster/schemaFor'](ENDPOINTS)) {
|
|
35
72
|
const endpoints = await store.dispatch('cluster/findAll', { type: ENDPOINTS }) || [];
|