@rancher/shell 3.0.1-rc.4 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/assets/data/aws-regions.json +1 -0
  2. package/assets/styles/base/_basic.scss +5 -0
  3. package/assets/styles/base/_mixins.scss +8 -0
  4. package/assets/styles/global/_button.scss +5 -0
  5. package/assets/styles/themes/_dark.scss +2 -0
  6. package/assets/styles/themes/_light.scss +2 -0
  7. package/assets/translations/en-us.yaml +27 -11
  8. package/assets/translations/zh-hans.yaml +1 -1
  9. package/chart/monitoring/StorageClassSelector.vue +1 -1
  10. package/components/AssignTo.vue +1 -0
  11. package/components/AsyncButton.vue +1 -0
  12. package/components/BackLink.vue +8 -2
  13. package/components/PaginatedResourceTable.vue +135 -0
  14. package/components/ResourceList/index.vue +0 -1
  15. package/components/ResourceTable.vue +6 -1
  16. package/components/SortableTable/index.vue +8 -6
  17. package/components/Tabbed/index.vue +35 -2
  18. package/components/form/ResourceLabeledSelect.vue +2 -2
  19. package/components/form/ResourceTabs/index.vue +0 -23
  20. package/components/form/Taints.vue +1 -1
  21. package/components/nav/TopLevelMenu.helper.ts +546 -0
  22. package/components/nav/TopLevelMenu.vue +124 -159
  23. package/components/nav/__tests__/TopLevelMenu.test.ts +338 -326
  24. package/config/pagination-table-headers.js +4 -4
  25. package/config/product/explorer.js +2 -0
  26. package/config/router/routes.js +1 -1
  27. package/config/settings.ts +13 -1
  28. package/core/plugin.ts +8 -1
  29. package/core/types-provisioning.ts +5 -0
  30. package/core/types.ts +26 -1
  31. package/dialog/DrainNode.vue +6 -6
  32. package/edit/catalog.cattle.io.clusterrepo.vue +95 -52
  33. package/edit/provisioning.cattle.io.cluster/index.vue +8 -3
  34. package/list/node.vue +8 -5
  35. package/mixins/resource-fetch-api-pagination.js +40 -5
  36. package/mixins/resource-fetch.js +48 -5
  37. package/models/management.cattle.io.nodepool.js +5 -4
  38. package/models/provisioning.cattle.io.cluster.js +2 -10
  39. package/package.json +6 -6
  40. package/pages/about.vue +22 -0
  41. package/pages/c/_cluster/explorer/__tests__/index.test.ts +36 -24
  42. package/pages/c/_cluster/explorer/index.vue +100 -59
  43. package/pages/home.vue +308 -123
  44. package/plugins/dashboard-store/__tests__/mutations.test.ts +2 -0
  45. package/plugins/dashboard-store/actions.js +29 -19
  46. package/plugins/dashboard-store/getters.js +5 -2
  47. package/plugins/dashboard-store/mutations.js +4 -2
  48. package/plugins/steve/__tests__/mutations.test.ts +2 -1
  49. package/plugins/steve/steve-pagination-utils.ts +25 -2
  50. package/plugins/steve/subscribe.js +22 -8
  51. package/scripts/extension/parse-tag-name +2 -0
  52. package/scripts/test-plugins-build.sh +1 -0
  53. package/store/index.js +31 -9
  54. package/tsconfig.json +7 -1
  55. package/types/resources/settings.d.ts +1 -1
  56. package/types/shell/index.d.ts +1107 -1276
  57. package/types/store/dashboard-store.types.ts +4 -0
  58. package/types/store/pagination.types.ts +13 -0
  59. package/types/store/vuex.d.ts +8 -0
  60. package/types/vue-shim.d.ts +6 -31
  61. package/utils/cluster.js +92 -1
  62. package/utils/pagination-utils.ts +17 -8
  63. package/utils/pagination-wrapper.ts +70 -0
  64. package/utils/uiplugins.ts +18 -4
@@ -17,8 +17,8 @@ export const STEVE_ID_COL = {
17
17
  name: 'steve-id',
18
18
  labelKey: 'tableHeaders.id',
19
19
  value: 'id',
20
- sort: false, // sort: ['id'], // Pending API support
21
- search: false, // search: 'id', // Pending API support
20
+ sort: ['id'],
21
+ search: 'id',
22
22
  };
23
23
 
24
24
  export const STEVE_STATE_COL = {
@@ -26,8 +26,8 @@ export const STEVE_STATE_COL = {
26
26
  // Note, we're show the 'state' as per model, not the 'metadata.state.name' that's available in the model to remotely sort/filter
27
27
  // Need to investigate whether we should 'dumb down' the state we show to the native one (tracked via https://github.com/rancher/dashboard/issues/8527)
28
28
  // This means we'll show something different to what we sort and filter on.
29
- sort: false, // ['metadata.state.name'], // Pending API support
30
- search: false, // 'metadata.state.name', // Pending API support
29
+ sort: ['metadata.state.name'],
30
+ search: 'metadata.state.name',
31
31
  };
32
32
 
33
33
  export const STEVE_AGE_COL = {
@@ -9,6 +9,7 @@ import {
9
9
  NORMAN,
10
10
  SNAPSHOT,
11
11
  VIRTUAL_TYPES,
12
+ CAPI,
12
13
  } from '@shell/config/types';
13
14
 
14
15
  import {
@@ -60,6 +61,7 @@ export function init(store) {
60
61
  [MANAGEMENT.PROJECT_ROLE_TEMPLATE_BINDING]: 'management',
61
62
  [NORMAN.CLUSTER_ROLE_TEMPLATE_BINDING]: 'rancher',
62
63
  [NORMAN.PROJECT_ROLE_TEMPLATE_BINDING]: 'rancher',
64
+ [CAPI.RANCHER_CLUSTER]: 'management',
63
65
  }
64
66
  });
65
67
 
@@ -5,7 +5,7 @@ import { CAPI, MANAGEMENT, BACKUP_RESTORE, CIS } from '@shell/config/types';
5
5
  import { NAME as AUTH } from '@shell/config/product/auth';
6
6
 
7
7
  // All these imports are related to the install-redirect.js navigation guard.
8
- import { installRedirectRouteMeta } from 'config/router/navigation-guards/install-redirect';
8
+ import { installRedirectRouteMeta } from '@shell/config/router/navigation-guards/install-redirect';
9
9
  import { NAME as BACKUP_NAME, CHART_NAME as BACKUP_CHART_NAME } from '@shell/config/product/backup';
10
10
  import { NAME as CIS_NAME, CHART_NAME as CIS_CHART_NAME } from '@shell/config/product/cis';
11
11
  import { NAME as GATEKEEPER_NAME, CHART_NAME as GATEKEEPER_CHART_NAME } from '@shell/config/product/gatekeeper';
@@ -1,6 +1,7 @@
1
1
  // Settings
2
2
  import { GC_DEFAULTS, GC_PREFERENCES } from '@shell/utils/gc/gc-types';
3
3
  import { PaginationSettings } from '@shell/types/resources/settings';
4
+ import { CAPI, MANAGEMENT } from '@shell/config/types';
4
5
 
5
6
  interface GlobalSettingRuleset {
6
7
  name: string,
@@ -253,8 +254,19 @@ export const DEFAULT_PERF_SETTING: PerfSettings = {
253
254
  generic: true,
254
255
  }
255
256
  }
257
+ },
258
+ management: {
259
+ resources: {
260
+ enableAll: false,
261
+ enableSome: {
262
+ enabled: [
263
+ { resource: CAPI.RANCHER_CLUSTER, context: ['home', 'side-bar'] },
264
+ { resource: MANAGEMENT.CLUSTER, context: ['side-bar'] },
265
+ ],
266
+ generic: false,
267
+ }
268
+ }
256
269
  }
257
270
  }
258
271
  }
259
-
260
272
  };
package/core/plugin.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable @typescript-eslint/explicit-module-boundary-types */
2
2
  import { RouteRecordRaw } from 'vue-router';
3
3
  import { DSL as STORE_DSL } from '@shell/store/type-map';
4
+ import { _DETAIL } from '@shell/config/query-params';
4
5
  import {
5
6
  CoreStoreInit,
6
7
  Action,
@@ -11,7 +12,7 @@ import {
11
12
  IPlugin,
12
13
  LocationConfig,
13
14
  ExtensionPoint,
14
-
15
+ TabLocation,
15
16
  PluginRouteRecordRaw, RegisterStore, UnregisterStore, CoreStoreSpecifics, CoreStoreConfig, OnNavToPackage, OnNavAwayFromPackage, OnLogOut
16
17
  } from './types';
17
18
  import coreStore, { coreStoreModule, coreStoreState } from '@shell/plugins/dashboard-store';
@@ -162,6 +163,12 @@ export class Plugin implements IPlugin {
162
163
  * Adds a tab to the UI
163
164
  */
164
165
  addTab(where: string, when: LocationConfig | string, tab: Tab): void {
166
+ // tackling https://github.com/rancher/dashboard/issues/11122, we don't want the tab to added in _EDIT view, unless overriden
167
+ // on extensions side we won't document the mode param for this extension point
168
+ if (where === TabLocation.RESOURCE_DETAIL && (typeof when === 'object' && !when.mode)) {
169
+ when.mode = [_DETAIL];
170
+ }
171
+
165
172
  this._addUIConfig(ExtensionPoint.TAB, where, when, this._createAsyncComponent(tab));
166
173
  }
167
174
 
@@ -106,6 +106,11 @@ export interface IClusterProvisioner {
106
106
  */
107
107
  disabled?: boolean;
108
108
 
109
+ /**
110
+ * Hide the cluster provider card
111
+ */
112
+ hidden?: boolean;
113
+
109
114
  /**
110
115
  * Custom Dashboard route to navigate to when the cluster provider card is clicked
111
116
  */
package/core/types.ts CHANGED
@@ -237,6 +237,16 @@ export interface ProductOptions {
237
237
  */
238
238
  to?: PluginRouteRecordRaw;
239
239
 
240
+ /**
241
+ * Alternative to the icon property. Uses require
242
+ */
243
+ svg?: Function;
244
+
245
+ /**
246
+ * Product name
247
+ */
248
+ name?: string;
249
+
240
250
  /**
241
251
  * Leaving these here for completeness but I don't think these should be advertised as useable to plugin creators.
242
252
  */
@@ -373,10 +383,25 @@ export interface ConfigureTypeOptions {
373
383
  }
374
384
 
375
385
  export interface ConfigureVirtualTypeOptions extends ConfigureTypeOptions {
386
+ /**
387
+ * Only load the product if the type is present
388
+ */
389
+ ifHave?: string;
390
+
391
+ /**
392
+ * Only load the product if the type is present
393
+ */
394
+ ifHaveType?: string | RegExp | Object;
395
+
396
+ /**
397
+ * The label that this type should display
398
+ */
399
+ label?: string;
400
+
376
401
  /**
377
402
  * The translation key displayed anywhere this type is referenced
378
403
  */
379
- labelKey: string;
404
+ labelKey?: string;
380
405
 
381
406
  /**
382
407
  * An identifier that should be unique across all types
@@ -146,7 +146,7 @@ export default {
146
146
  <div class="pl-10 pr-10">
147
147
  <div>
148
148
  <RadioGroup
149
- v-model="body.deleteLocalData"
149
+ v-model:value="body.deleteLocalData"
150
150
  name="deleteLocalData"
151
151
  :options="radioOptions"
152
152
  :row="true"
@@ -157,7 +157,7 @@ export default {
157
157
  </template>
158
158
  </RadioGroup>
159
159
  <RadioGroup
160
- v-model="body.force"
160
+ v-model:value="body.force"
161
161
  name="force"
162
162
  :options="radioOptions"
163
163
  :row="true"
@@ -168,7 +168,7 @@ export default {
168
168
  </template>
169
169
  </RadioGroup>
170
170
  <RadioGroup
171
- v-model="gracePeriod"
171
+ v-model:value="gracePeriod"
172
172
  name="gracePeriod"
173
173
  :options="gracePeriodOptions"
174
174
  class="mb-15"
@@ -178,7 +178,7 @@ export default {
178
178
  </template>
179
179
  </RadioGroup>
180
180
  <UnitInput
181
- v-model="body.gracePeriod"
181
+ v-model:value="body.gracePeriod"
182
182
  :mode="gracePeriod ? EDIT : VIEW"
183
183
  type="number"
184
184
  min="1"
@@ -187,7 +187,7 @@ export default {
187
187
  class="mb-10"
188
188
  />
189
189
  <RadioGroup
190
- v-model="timeout"
190
+ v-model:value="timeout"
191
191
  name="timeout"
192
192
  :options="timeoutOptions"
193
193
  class="mb-15"
@@ -197,7 +197,7 @@ export default {
197
197
  </template>
198
198
  </RadioGroup>
199
199
  <UnitInput
200
- v-model="body.timeout"
200
+ v-model:value="body.timeout"
201
201
  :mode="timeout ? EDIT : VIEW"
202
202
  type="number"
203
203
  min="1"
@@ -9,6 +9,7 @@ import SelectOrCreateAuthSecret from '@shell/components/form/SelectOrCreateAuthS
9
9
  import InfoBox from '@shell/components/InfoBox';
10
10
  import { Checkbox } from '@components/Form/Checkbox';
11
11
  import { MANAGEMENT, NAMESPACE, CLUSTER_REPO_TYPES } from '@shell/config/types';
12
+ import UnitInput from '@shell/components/form/UnitInput.vue';
12
13
 
13
14
  export default {
14
15
  name: 'CruCatalogRepo',
@@ -23,7 +24,8 @@ export default {
23
24
  Labels,
24
25
  SelectOrCreateAuthSecret,
25
26
  InfoBox,
26
- Checkbox
27
+ Checkbox,
28
+ UnitInput
27
29
  },
28
30
 
29
31
  mixins: [CreateEditView],
@@ -83,7 +85,7 @@ export default {
83
85
  this.value.spec['exponentialBackOffValues'] = {};
84
86
  }
85
87
  // when user removes the value we remove the key too, backend will set the default value
86
- if (newVal === '') {
88
+ if (newVal === '' || newVal === null) {
87
89
  delete this.value.spec.exponentialBackOffValues[key];
88
90
 
89
91
  return;
@@ -91,15 +93,27 @@ export default {
91
93
 
92
94
  this.value.spec.exponentialBackOffValues[key] = Number(newVal);
93
95
  },
96
+ updateRefreshInterval(newVal) {
97
+ // when user removes the value we don't send refreshInterval along with the payload
98
+ if (newVal === null) {
99
+ delete this.value.spec.refreshInterval;
100
+
101
+ return;
102
+ }
103
+
104
+ this.value.spec.refreshInterval = newVal;
105
+ },
94
106
  resetGitRepoValues() {
95
107
  delete this.value.spec['gitRepo'];
96
108
  delete this.value.spec['gitBranch'];
109
+ delete this.value.spec['refreshInterval'];
97
110
  },
98
111
  resetOciValues() {
99
112
  delete this.value.spec['url'];
100
113
  delete this.value.spec['insecurePlainHttp'];
101
114
  delete this.value.spec['insecureSkipTLSVerify'];
102
115
  delete this.value.spec['caBundle'];
116
+ delete this.value.spec['refreshInterval'];
103
117
  delete this.value.spec['exponentialBackOffValues'];
104
118
  this.ociMinWait = undefined;
105
119
  this.ociMaxWait = undefined;
@@ -139,55 +153,80 @@ export default {
139
153
  </div>
140
154
  </div>
141
155
 
142
- <div
143
- v-if="clusterRepoType === CLUSTER_REPO_TYPES.GIT_REPO"
144
- class="row mb-10"
156
+ <InfoBox
157
+ v-if="clusterRepoType === CLUSTER_REPO_TYPES.OCI_URL"
158
+ class="p-10"
145
159
  >
146
- <div class="col span-6">
160
+ {{ t('catalog.repo.oci.info', null, true) }}
161
+ </InfoBox>
162
+
163
+ <div class="row mb-10">
164
+ <template v-if="clusterRepoType === CLUSTER_REPO_TYPES.GIT_REPO">
165
+ <div class="col span-6">
166
+ <LabeledInput
167
+ v-model:value.trim="value.spec.gitRepo"
168
+ :required="true"
169
+ :label="t('catalog.repo.gitRepo.label')"
170
+ :placeholder="t('catalog.repo.gitRepo.placeholder', null, true)"
171
+ :mode="mode"
172
+ data-testid="clusterrepo-git-repo-input"
173
+ />
174
+ </div>
175
+ <div class="col span-3">
176
+ <LabeledInput
177
+ v-model:value.trim="value.spec.gitBranch"
178
+ :sub-label="!value.spec.gitBranch ? t('catalog.repo.gitBranch.defaultMessage', null, true) : undefined"
179
+ :label="t('catalog.repo.gitBranch.label')"
180
+ :placeholder="t('catalog.repo.gitBranch.placeholder', null, true)"
181
+ :mode="mode"
182
+ data-testid="clusterrepo-git-branch-input"
183
+ />
184
+ </div>
185
+ </template>
186
+
187
+ <template v-else-if="clusterRepoType === CLUSTER_REPO_TYPES.OCI_URL">
188
+ <div class="col span-6">
189
+ <LabeledInput
190
+ v-model:value.trim="value.spec.url"
191
+ :required="true"
192
+ :label="t('catalog.repo.oci.urlLabel')"
193
+ :placeholder="t('catalog.repo.oci.placeholder', null, true)"
194
+ :mode="mode"
195
+ data-testid="clusterrepo-oci-url-input"
196
+ />
197
+ </div>
198
+ </template>
199
+
200
+ <div
201
+ v-else
202
+ class="col span-6"
203
+ >
147
204
  <LabeledInput
148
- v-model:value.trim="value.spec.gitRepo"
205
+ v-model:value.trim="value.spec.url"
149
206
  :required="true"
150
- :label="t('catalog.repo.gitRepo.label')"
151
- :placeholder="t('catalog.repo.gitRepo.placeholder', null, true)"
207
+ :label="t('catalog.repo.url.label')"
208
+ :placeholder="t('catalog.repo.url.placeholder', null, true)"
152
209
  :mode="mode"
153
- data-testid="clusterrepo-git-repo-input"
210
+ data-testid="clusterrepo-helm-url-input"
154
211
  />
155
212
  </div>
156
- <div class="col span-6">
157
- <LabeledInput
158
- v-model:value.trim="value.spec.gitBranch"
159
- :sub-label="!value.spec.gitBranch ? t('catalog.repo.gitBranch.defaultMessage', null, true) : undefined"
160
- :label="t('catalog.repo.gitBranch.label')"
161
- :placeholder="t('catalog.repo.gitBranch.placeholder', null, true)"
213
+
214
+ <div
215
+ class="col span-3"
216
+ data-testid="clusterrepo-refresh-interval"
217
+ >
218
+ <UnitInput
219
+ v-model:value.trim="value.spec.refreshInterval"
220
+ :label="t('catalog.repo.refreshInterval.label')"
162
221
  :mode="mode"
163
- data-testid="clusterrepo-git-branch-input"
222
+ min="0"
223
+ :suffix="t('unit.hour', { count: value.spec.refreshInterval })"
224
+ :placeholder="t('catalog.repo.refreshInterval.placeholder', { hours: clusterRepoType === CLUSTER_REPO_TYPES.OCI_URL ? 24 : 6 })"
225
+ @update:value="updateRefreshInterval($event)"
164
226
  />
165
227
  </div>
166
228
  </div>
167
229
 
168
- <div v-else-if="clusterRepoType === CLUSTER_REPO_TYPES.OCI_URL">
169
- <InfoBox class="p-10">
170
- {{ t('catalog.repo.oci.info', null, true) }}
171
- </InfoBox>
172
- <LabeledInput
173
- v-model:value.trim="value.spec.url"
174
- :required="true"
175
- :label="t('catalog.repo.oci.urlLabel')"
176
- :placeholder="t('catalog.repo.oci.placeholder', null, true)"
177
- :mode="mode"
178
- data-testid="clusterrepo-oci-url-input"
179
- />
180
- </div>
181
-
182
- <LabeledInput
183
- v-else
184
- v-model:value.trim="value.spec.url"
185
- :required="true"
186
- :label="t('catalog.repo.url.label')"
187
- :placeholder="t('catalog.repo.url.placeholder', null, true)"
188
- :mode="mode"
189
- data-testid="clusterrepo-helm-url-input"
190
- />
191
230
  <SelectOrCreateAuthSecret
192
231
  v-model:value="value.spec.clientSecret"
193
232
  :mode="mode"
@@ -231,28 +270,32 @@ export default {
231
270
  <h4 class="mb-10 mt-20">
232
271
  {{ t('catalog.repo.oci.exponentialBackOff.label') }}
233
272
  </h4>
234
- <div class="row mb-10 mt-10">
235
- <div class="col span-4">
236
- <LabeledInput
273
+ <div class="row mb-40 mt-10">
274
+ <div
275
+ class="col span-4"
276
+ data-testid="clusterrepo-oci-min-wait-input"
277
+ >
278
+ <UnitInput
237
279
  v-model:value.trim="ociMinWait"
238
280
  :label="t('catalog.repo.oci.exponentialBackOff.minWait.label')"
239
- :placeholder="!ociMinWait ? t('catalog.repo.oci.exponentialBackOff.minWait.placeholder') : undefined"
281
+ :placeholder="t('catalog.repo.oci.exponentialBackOff.minWait.placeholder')"
240
282
  :mode="mode"
241
- type="number"
242
283
  min="1"
243
- data-testid="clusterrepo-oci-min-wait-input"
284
+ :suffix="t('suffix.seconds', { count: ociMinWait })"
244
285
  @update:value="updateExponentialBackOffValues('minWait', $event)"
245
286
  />
246
287
  </div>
247
- <div class="col span-4">
248
- <LabeledInput
288
+ <div
289
+ class="col span-4"
290
+ data-testid="clusterrepo-oci-max-wait-input"
291
+ >
292
+ <UnitInput
249
293
  v-model:value.trim="ociMaxWait"
250
294
  :label="t('catalog.repo.oci.exponentialBackOff.maxWait.label')"
251
- :placeholder="!ociMaxWait ? t('catalog.repo.oci.exponentialBackOff.maxWait.placeholder') : undefined"
295
+ :placeholder="t('catalog.repo.oci.exponentialBackOff.maxWait.placeholder')"
252
296
  :mode="mode"
253
- type="number"
254
297
  min="1"
255
- data-testid="clusterrepo-oci-max-wait-input"
298
+ :suffix="t('suffix.seconds', { count: ociMaxWait })"
256
299
  @update:value="updateExponentialBackOffValues('maxWait', $event)"
257
300
  />
258
301
  </div>
@@ -260,7 +303,7 @@ export default {
260
303
  <LabeledInput
261
304
  v-model:value.trim="ociMaxRetries"
262
305
  :label="t('catalog.repo.oci.exponentialBackOff.maxRetries.label')"
263
- :placeholder="!ociMaxRetries ? t('catalog.repo.oci.exponentialBackOff.maxRetries.placeholder') : undefined"
306
+ :placeholder="t('catalog.repo.oci.exponentialBackOff.maxRetries.placeholder')"
264
307
  :mode="mode"
265
308
  type="number"
266
309
  min="0"
@@ -404,7 +404,8 @@ export default {
404
404
  disabled: ext.disabled || false,
405
405
  link: ext.link,
406
406
  tag: ext.tag,
407
- component: ext.component
407
+ component: ext.component,
408
+ hidden: ext.hidden,
408
409
  };
409
410
 
410
411
  out.push(subtype);
@@ -449,10 +450,14 @@ export default {
449
450
  }
450
451
  },
451
452
 
453
+ filteredSubTypes() {
454
+ return this.subTypes.filter((subtype) => !subtype.hidden);
455
+ },
456
+
452
457
  groupedSubTypes() {
453
458
  const out = {};
454
459
 
455
- for ( const row of this.subTypes ) {
460
+ for ( const row of this.filteredSubTypes ) {
456
461
  const name = row.group;
457
462
  let entry = out[name];
458
463
 
@@ -623,7 +628,7 @@ export default {
623
628
  <div
624
629
  v-for="(obj, i) in groupedSubTypes"
625
630
  :key="i"
626
- class="mb-20"
631
+ :class="{'mt-5': i === 0, 'mt-20': i !== 0 }"
627
632
  style="width: 100%;"
628
633
  >
629
634
  <h4>
package/list/node.vue CHANGED
@@ -21,6 +21,7 @@ import { COLUMN_BREAKPOINTS } from '@shell/types/store/type-map';
21
21
 
22
22
  import ResourceFetch from '@shell/mixins/resource-fetch';
23
23
  import { mapGetters } from 'vuex';
24
+ import { FetchPageSecondaryResourcesOpts } from 'components/PaginatedResourceTable.vue';
24
25
 
25
26
  export default defineComponent({
26
27
  name: 'ListNode',
@@ -36,10 +37,12 @@ export default defineComponent({
36
37
  type: String,
37
38
  required: true,
38
39
  },
40
+
39
41
  schema: {
40
42
  type: Object,
41
43
  required: true,
42
44
  },
45
+
43
46
  useQueryParamsForSimpleFiltering: {
44
47
  type: Boolean,
45
48
  default: false
@@ -209,8 +212,8 @@ export default defineComponent({
209
212
  *
210
213
  * So when we have a page.... use those entries as filters when fetching the other resources
211
214
  */
212
- async fetchPageSecondaryResources(force = false) {
213
- if (!this.rows?.length) {
215
+ async fetchPageSecondaryResources({ canPaginate, force, page }: FetchPageSecondaryResourcesOpts) {
216
+ if (!page?.length) {
214
217
  return;
215
218
  }
216
219
 
@@ -220,7 +223,7 @@ export default defineComponent({
220
223
  const opt: ActionFindPageArgs = {
221
224
  force,
222
225
  pagination: new FilterArgs({
223
- filters: PaginationParamFilter.createMultipleFields(this.rows.map((r: any) => new PaginationFilterField({
226
+ filters: PaginationParamFilter.createMultipleFields(page.map((r: any) => new PaginationFilterField({
224
227
  field: 'status.nodeName',
225
228
  value: r.id
226
229
  }))),
@@ -242,7 +245,7 @@ export default defineComponent({
242
245
  namespaced: namespace,
243
246
  pagination: new FilterArgs({
244
247
  filters: PaginationParamFilter.createMultipleFields(
245
- this.rows.reduce((res: PaginationFilterField[], r: any ) => {
248
+ page.reduce((res: PaginationFilterField[], r: any ) => {
246
249
  const name = r.metadata?.annotations?.[CAPI_ANNOTATIONS.MACHINE_NAME];
247
250
 
248
251
  if (name) {
@@ -268,7 +271,7 @@ export default defineComponent({
268
271
  force,
269
272
  pagination: new FilterArgs({
270
273
  filters: PaginationParamFilter.createMultipleFields(
271
- this.rows.map((r: any) => new PaginationFilterField({
274
+ page.map((r: any) => new PaginationFilterField({
272
275
  field: 'spec.nodeName',
273
276
  value: r.id,
274
277
  }))
@@ -13,6 +13,21 @@ import stevePaginationUtils from '@shell/plugins/steve/steve-pagination-utils';
13
13
  */
14
14
  export default {
15
15
 
16
+ props: {
17
+ namespaced: {
18
+ type: Boolean,
19
+ default: null, // Automatic from schema
20
+ },
21
+
22
+ /**
23
+ * Where in the ui this mixin is used. For instance the home page cluster list would be `home`
24
+ */
25
+ context: {
26
+ type: String,
27
+ default: null,
28
+ },
29
+ },
30
+
16
31
  data() {
17
32
  return {
18
33
  forceUpdateLiveAndDelayed: 0,
@@ -68,7 +83,7 @@ export default {
68
83
  },
69
84
 
70
85
  namespaceFilterChanged(neu) {
71
- if (!this.canPaginate || !this.schema?.attributes?.namespaced) {
86
+ if (!this.canPaginate || !this.isNamespaced) {
72
87
  return;
73
88
  }
74
89
 
@@ -166,7 +181,16 @@ export default {
166
181
  return;
167
182
  }
168
183
 
169
- return this.resource && this.$store.getters[`${ this.currentProduct?.inStore }/paginationEnabled`]?.(this.resource.id || this.resource);
184
+ if (!this.resource) {
185
+ return false;
186
+ }
187
+
188
+ const args = {
189
+ id: this.resource.id || this.resource,
190
+ context: this.context,
191
+ };
192
+
193
+ return this.resource && this.$store.getters[`${ this.inStore }/paginationEnabled`]?.(args);
170
194
  },
171
195
 
172
196
  paginationResult() {
@@ -182,7 +206,7 @@ export default {
182
206
  return;
183
207
  }
184
208
 
185
- return this.$store.getters[`${ this.currentProduct?.inStore }/havePage`](this.resource);
209
+ return this.$store.getters[`${ this.inStore }/havePage`](this.resource);
186
210
  },
187
211
 
188
212
  /**
@@ -197,6 +221,15 @@ export default {
197
221
  */
198
222
  showDynamicRancherNamespaces() {
199
223
  return this.$store.getters['prefs/get'](ALL_NAMESPACES);
224
+ },
225
+
226
+ isNamespaced() {
227
+ if (this.namespaced !== null) { // null is the default value
228
+ // This is an override, but only if it's set
229
+ return !!this.namespaced;
230
+ }
231
+
232
+ return this.schema?.attributes?.namespaced;
200
233
  }
201
234
  },
202
235
 
@@ -221,7 +254,7 @@ export default {
221
254
  namespaceFilters: {
222
255
  immediate: true,
223
256
  async handler(neu, old) {
224
- if (!this.canPaginate || !this.schema?.attributes?.namespaced) {
257
+ if (!this.canPaginate || !this.isNamespaced) {
225
258
  return;
226
259
  }
227
260
 
@@ -298,7 +331,9 @@ export default {
298
331
  return;
299
332
  }
300
333
 
301
- await this.fetchPageSecondaryResources();
334
+ await this.fetchPageSecondaryResources({
335
+ canPaginate: this.canPaginate, force: false, page: this.rows, pagResult: this.paginationResult
336
+ });
302
337
  }
303
338
  },
304
339
  };