@rancher/shell 2.0.1 → 2.0.2

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 (112) hide show
  1. package/assets/translations/en-us.yaml +73 -34
  2. package/assets/translations/zh-hans.yaml +1 -0
  3. package/components/AssignTo.vue +2 -0
  4. package/components/PromptRemove.vue +8 -3
  5. package/components/Questions/index.vue +2 -2
  6. package/components/ResourceDetail/Masthead.vue +1 -0
  7. package/components/auth/RoleDetailEdit.vue +5 -4
  8. package/components/fleet/FleetClusters.vue +0 -3
  9. package/components/form/Members/ClusterPermissionsEditor.vue +1 -1
  10. package/components/form/ProjectMemberEditor.vue +1 -1
  11. package/components/form/ResourceLabeledSelect.vue +11 -3
  12. package/components/form/labeled-select-utils/labeled-select.utils.ts +1 -1
  13. package/components/formatter/CloudCredExpired.vue +69 -0
  14. package/components/formatter/Date.vue +1 -1
  15. package/components/nav/Header.vue +9 -5
  16. package/components/nav/TopLevelMenu.vue +115 -51
  17. package/components/nav/__tests__/TopLevelMenu.test.ts +53 -27
  18. package/config/labels-annotations.js +2 -0
  19. package/config/pagination-table-headers.js +5 -4
  20. package/config/roles.ts +34 -19
  21. package/config/router/navigation-guards/attempt-first-login.js +1 -1
  22. package/config/router/navigation-guards/authentication.js +1 -1
  23. package/config/router/navigation-guards/i18n.js +1 -1
  24. package/config/router/navigation-guards/index.js +2 -1
  25. package/config/router/navigation-guards/load-initial-settings.js +1 -1
  26. package/config/router/navigation-guards/runtime-extension-route.js +31 -0
  27. package/config/router/routes.js +10 -1
  28. package/config/uiplugins.js +130 -61
  29. package/core/plugin.ts +5 -0
  30. package/core/plugins.js +7 -1
  31. package/detail/catalog.cattle.io.app.vue +17 -4
  32. package/detail/fleet.cattle.io.cluster.vue +11 -9
  33. package/detail/fleet.cattle.io.gitrepo.vue +1 -1
  34. package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +86 -13
  35. package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +3 -134
  36. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +209 -0
  37. package/edit/provisioning.cattle.io.cluster/index.vue +8 -4
  38. package/edit/provisioning.cattle.io.cluster/rke2.vue +128 -17
  39. package/edit/provisioning.cattle.io.cluster/tabs/AddOnAdditionalManifest.vue +50 -0
  40. package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +29 -64
  41. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +42 -3
  42. package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +22 -86
  43. package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +8 -2
  44. package/edit/provisioning.cattle.io.cluster/tabs/registries/__tests__/RegistryConfigs.test.ts +61 -0
  45. package/initialize/entry-helpers.js +4 -21
  46. package/list/provisioning.cattle.io.cluster.vue +56 -5
  47. package/mixins/__tests__/chart.test.ts +4 -1
  48. package/mixins/chart.js +36 -16
  49. package/models/__tests__/apps.deployment.test.ts +93 -0
  50. package/models/apps.deployment.js +18 -4
  51. package/models/catalog.cattle.io.app.js +108 -21
  52. package/models/cloudcredential.js +159 -2
  53. package/models/fleet.cattle.io.gitrepo.js +4 -13
  54. package/models/management.cattle.io.cluster.js +15 -4
  55. package/models/management.cattle.io.user.js +3 -3
  56. package/models/nodedriver.js +5 -0
  57. package/models/provisioning.cattle.io.cluster.js +41 -3
  58. package/package.json +1 -1
  59. package/pages/404.vue +15 -0
  60. package/pages/auth/login.vue +4 -1
  61. package/pages/auth/setup.vue +4 -1
  62. package/pages/c/_cluster/apps/charts/install.vue +2 -1
  63. package/pages/c/_cluster/explorer/__tests__/index.test.ts +1 -1
  64. package/pages/c/_cluster/explorer/index.vue +6 -2
  65. package/pages/c/_cluster/fleet/index.vue +11 -5
  66. package/pages/c/_cluster/manager/cloudCredential/index.vue +68 -4
  67. package/pages/c/_cluster/manager/jwt.authentication/index.vue +10 -4
  68. package/pages/c/_cluster/settings/performance.vue +2 -2
  69. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +7 -10
  70. package/pages/c/_cluster/uiplugins/index.vue +28 -18
  71. package/pages/home.vue +2 -13
  72. package/plugins/dashboard-store/actions.js +1 -1
  73. package/plugins/dashboard-store/getters.js +1 -1
  74. package/plugins/steve/__tests__/getters.test.ts +5 -5
  75. package/plugins/steve/getters.js +6 -4
  76. package/plugins/steve/hybrid-class.js +1 -5
  77. package/scripts/extension/bundle +1 -1
  78. package/scripts/extension/helm/charts/ui-plugin-server/Chart.yaml +1 -1
  79. package/scripts/publish-shell.sh +56 -59
  80. package/scripts/test-plugins-build.sh +45 -39
  81. package/scripts/typegen.sh +26 -23
  82. package/store/type-map.js +4 -2
  83. package/types/shell/index.d.ts +10 -0
  84. package/types/store/pagination.types.ts +1 -1
  85. package/utils/cluster.js +9 -0
  86. package/utils/settings.ts +3 -1
  87. package/utils/string.js +9 -0
  88. package/utils/v-sphere.ts +251 -0
  89. package/creators/app/app.package.json +0 -14
  90. package/creators/app/files/.eslintignore +0 -16
  91. package/creators/app/files/.eslintrc.js +0 -173
  92. package/creators/app/files/.gitignore +0 -70
  93. package/creators/app/files/.gitlab-ci.yml +0 -14
  94. package/creators/app/files/.vscode/settings.json +0 -21
  95. package/creators/app/files/babel.config.js +0 -1
  96. package/creators/app/files/tsconfig.json +0 -42
  97. package/creators/app/files/vue.config.js +0 -6
  98. package/creators/app/init +0 -120
  99. package/creators/app/package.json +0 -25
  100. package/creators/pkg/files/.github/workflows/build-extension-catalog.yml +0 -24
  101. package/creators/pkg/files/.github/workflows/build-extension-charts.yml +0 -22
  102. package/creators/pkg/files/babel.config.js +0 -1
  103. package/creators/pkg/files/index.ts +0 -14
  104. package/creators/pkg/files/tsconfig.json +0 -53
  105. package/creators/pkg/files/vue.config.js +0 -1
  106. package/creators/pkg/init +0 -286
  107. package/creators/pkg/package.json +0 -19
  108. package/creators/pkg/pkg.package.json +0 -21
  109. package/creators/pkg/vue-shim.ts +0 -4
  110. package/creators/update/init +0 -56
  111. package/creators/update/package.json +0 -20
  112. package/creators/update/upgrade +0 -56
@@ -76,58 +76,102 @@ export default {
76
76
  return this.clusters.length > this.maxClustersToShow;
77
77
  },
78
78
 
79
+ /**
80
+ * Filter mgmt clusters by
81
+ * 1. Harvester type 1 (filterOnlyKubernetesClusters)
82
+ * 2. Harvester type 2 (filterHiddenLocalCluster)
83
+ * 3. There's a matching prov cluster
84
+ *
85
+ * Convert remaining clusters to special format
86
+ */
79
87
  clusters() {
80
- const all = this.$store.getters['management/all'](MANAGEMENT.CLUSTER);
81
- let kubeClusters = filterHiddenLocalCluster(filterOnlyKubernetesClusters(all, this.$store), this.$store);
82
- let pClusters = null;
88
+ if (!this.hasProvCluster) {
89
+ // We're filtering out mgmt clusters without prov clusters, so if the user can't see any prov clusters at all
90
+ // exit early
91
+ return [];
92
+ }
83
93
 
84
- if (this.hasProvCluster) {
85
- pClusters = this.$store.getters['management/all'](CAPI.RANCHER_CLUSTER);
86
- const available = pClusters.reduce((p, c) => {
87
- p[c.mgmt] = true;
94
+ const all = this.$store.getters['management/all'](MANAGEMENT.CLUSTER);
95
+ const mgmtClusters = filterHiddenLocalCluster(filterOnlyKubernetesClusters(all, this.$store), this.$store);
96
+ const provClusters = this.$store.getters['management/all'](CAPI.RANCHER_CLUSTER);
97
+ const provClustersByMgmtId = provClusters.reduce((res, provCluster) => {
98
+ if (provCluster.mgmt?.id) {
99
+ res[provCluster.mgmt.id] = provCluster;
100
+ }
88
101
 
89
- return p;
90
- }, {});
102
+ return res;
103
+ }, {});
91
104
 
105
+ return (mgmtClusters || []).reduce((res, mgmtCluster) => {
92
106
  // Filter to only show mgmt clusters that exist for the available provisioning clusters
93
107
  // Addresses issue where a mgmt cluster can take some time to get cleaned up after the corresponding
94
108
  // provisioning cluster has been deleted
95
- kubeClusters = kubeClusters.filter((c) => !!available[c]);
96
- }
109
+ if (!provClustersByMgmtId[mgmtCluster.id]) {
110
+ return res;
111
+ }
97
112
 
98
- return kubeClusters?.map((x) => {
99
- const pCluster = pClusters?.find((c) => c.mgmt?.id === x.id);
113
+ const pCluster = provClustersByMgmtId[mgmtCluster.id];
114
+
115
+ res.push({
116
+ id: mgmtCluster.id,
117
+ label: mgmtCluster.nameDisplay,
118
+ ready: mgmtCluster.isReady && !pCluster?.hasError,
119
+ osLogo: mgmtCluster.providerOsLogo,
120
+ providerNavLogo: mgmtCluster.providerMenuLogo,
121
+ badge: mgmtCluster.badge,
122
+ isLocal: mgmtCluster.isLocal,
123
+ isHarvester: mgmtCluster.isHarvester,
124
+ pinned: mgmtCluster.pinned,
125
+ description: pCluster?.description || mgmtCluster.description,
126
+ pin: () => mgmtCluster.pin(),
127
+ unpin: () => mgmtCluster.unpin(),
128
+ clusterRoute: { name: 'c-cluster-explorer', params: { cluster: mgmtCluster.id } }
129
+ });
100
130
 
101
- return {
102
- id: x.id,
103
- label: x.nameDisplay,
104
- ready: x.isReady && !pCluster?.hasError,
105
- osLogo: x.providerOsLogo,
106
- providerNavLogo: x.providerMenuLogo,
107
- badge: x.badge,
108
- isLocal: x.isLocal,
109
- isHarvester: x.isHarvester,
110
- pinned: x.pinned,
111
- description: pCluster?.description || x.description,
112
- pin: () => x.pin(),
113
- unpin: () => x.unpin(),
114
- clusterRoute: { name: 'c-cluster-explorer', params: { cluster: x.id } }
115
- };
116
- }) || [];
131
+ return res;
132
+ }, []);
117
133
  },
118
134
 
135
+ /**
136
+ * Filter clusters by
137
+ * 1. Not pinned
138
+ * 2. Includes search term
139
+ *
140
+ * Sort remaining clusters
141
+ *
142
+ * Reduce number of clusters if too many too show
143
+ *
144
+ * Important! This is used to show unpinned clusters OR results of search
145
+ */
119
146
  clustersFiltered() {
120
147
  const search = (this.clusterFilter || '').toLowerCase();
121
- const out = search ? this.clusters.filter((item) => item.label?.toLowerCase().includes(search)) : this.clusters;
122
- const sorted = sortBy(out, ['ready:desc', 'label']);
148
+ let localCluster = null;
123
149
 
124
- // put local cluster on top of list always
125
- // https://github.com/rancher/dashboard/issues/10975
126
- if (sorted.findIndex((c) => c.id === 'local') > 0) {
127
- const localCluster = sorted.find((c) => c.id === 'local');
128
- const localIndex = sorted.findIndex((c) => c.id === 'local');
150
+ const filtered = this.clusters.filter((c) => {
151
+ // If we're searching we don't care if pinned or not
152
+ if (search) {
153
+ if (!c.label?.toLowerCase().includes(search)) {
154
+ return false;
155
+ }
156
+ } else if (c.pinned) {
157
+ // Not searching, not pinned, don't care
158
+ return false;
159
+ }
160
+
161
+ if (!localCluster && c.id === 'local') {
162
+ // Local cluster is a special case, we're inserting it at top so don't include in the middle
163
+ localCluster = c;
164
+
165
+ return false;
166
+ }
129
167
 
130
- sorted.splice(localIndex, 1);
168
+ return true;
169
+ });
170
+
171
+ const sorted = sortBy(filtered, ['ready:desc', 'label']);
172
+
173
+ // put local cluster on top of list always - https://github.com/rancher/dashboard/issues/10975
174
+ if (localCluster) {
131
175
  sorted.unshift(localCluster);
132
176
  }
133
177
 
@@ -141,25 +185,45 @@ export default {
141
185
  this.searchActive = false;
142
186
 
143
187
  if (sorted.length >= this.maxClustersToShow) {
144
- const sortedPinOut = sorted.filter((item) => !item.pinned).slice(0, this.maxClustersToShow);
145
-
146
- return sortedPinOut;
147
- } else {
148
- return sorted.filter((item) => !item.pinned);
188
+ return sorted.slice(0, this.maxClustersToShow);
149
189
  }
190
+
191
+ return sorted;
150
192
  },
151
193
 
194
+ /**
195
+ * Filter clusters by
196
+ * 1. Not pinned
197
+ * 2. Includes search term
198
+ *
199
+ * Sort remaining clusters
200
+ *
201
+ * Reduce number of clusters if too many too show
202
+ *
203
+ * Important! This is hidden if there's a filter (user searching)
204
+ */
152
205
  pinFiltered() {
153
- const out = this.clusters.filter((item) => item.pinned);
154
- const sorted = sortBy(out, ['ready:desc', 'label']);
206
+ let localCluster = null;
207
+ const filtered = this.clusters.filter((c) => {
208
+ if (!c.pinned) {
209
+ // We only care about pinned clusters
210
+ return false;
211
+ }
212
+
213
+ if (c.id === 'local') {
214
+ // Special case, we're going to add this at the start so filter out
215
+ localCluster = c;
216
+
217
+ return false;
218
+ }
219
+
220
+ return true;
221
+ });
155
222
 
156
- // put local cluster on top of list always
157
- // https://github.com/rancher/dashboard/issues/10975
158
- if (sorted.findIndex((c) => c.id === 'local') > 0) {
159
- const localCluster = sorted.find((c) => c.id === 'local');
160
- const localIndex = sorted.findIndex((c) => c.id === 'local');
223
+ const sorted = sortBy(filtered, ['ready:desc', 'label']);
161
224
 
162
- sorted.splice(localIndex, 1);
225
+ // put local cluster on top of list always - https://github.com/rancher/dashboard/issues/10975
226
+ if (localCluster) {
163
227
  sorted.unshift(localCluster);
164
228
  }
165
229
 
@@ -167,7 +231,7 @@ export default {
167
231
  },
168
232
 
169
233
  pinnedClustersHeight() {
170
- const pinCount = this.clusters.filter((item) => item.pinned).length;
234
+ const pinCount = this.pinFiltered.length;
171
235
  const height = pinCount > 2 ? (pinCount * 43) : 90;
172
236
 
173
237
  return `min-height: ${ height }px`;
@@ -5,7 +5,7 @@ import { mount, Wrapper } from '@vue/test-utils';
5
5
  // DISCLAIMER: This should not be added here, although we have several store requests which are irrelevant
6
6
  const defaultStore = {
7
7
  'management/byId': jest.fn(),
8
- 'management/schemaFor': jest.fn(),
8
+ 'management/schemaFor': () => ({}),
9
9
  'i18n/t': jest.fn(),
10
10
  'features/get': jest.fn(),
11
11
  'prefs/theme': jest.fn(),
@@ -20,7 +20,11 @@ describe('topLevelMenu', () => {
20
20
  mocks: {
21
21
  $store: {
22
22
  getters: {
23
- 'management/all': () => [{ name: 'whatever' }],
23
+ 'management/all': () => [{
24
+ name: 'whatever',
25
+ id: 'an-id1',
26
+ mgmt: { id: 'an-id1' },
27
+ }],
24
28
  ...defaultStore
25
29
  },
26
30
  },
@@ -48,21 +52,21 @@ describe('topLevelMenu', () => {
48
52
  'management/all': () => [
49
53
  {
50
54
  name: 'x32-cwf5-name',
51
- id: 'x32-cwf5-id',
55
+ id: 'an-id1',
52
56
  mgmt: { id: 'an-id1' },
53
57
  nameDisplay: 'c-cluster',
54
58
  isReady: true
55
59
  },
56
60
  {
57
61
  name: 'x33-cwf5-name',
58
- id: 'x33-cwf5-id',
62
+ id: 'an-id2',
59
63
  mgmt: { id: 'an-id2' },
60
64
  nameDisplay: 'a-cluster',
61
65
  isReady: true
62
66
  },
63
67
  {
64
68
  name: 'x34-cwf5-name',
65
- id: 'x34-cwf5-id',
69
+ id: 'an-id3',
66
70
  mgmt: { id: 'an-id3' },
67
71
  nameDisplay: 'b-cluster',
68
72
  isReady: true
@@ -70,7 +74,7 @@ describe('topLevelMenu', () => {
70
74
  {
71
75
  name: 'local-name',
72
76
  id: 'local',
73
- mgmt: { id: 'an-id4' },
77
+ mgmt: { id: 'local' },
74
78
  nameDisplay: 'local',
75
79
  isReady: true
76
80
  },
@@ -103,21 +107,21 @@ describe('topLevelMenu', () => {
103
107
  'management/all': () => [
104
108
  {
105
109
  name: 'x32-cwf5-name',
106
- id: 'x32-cwf5-id',
110
+ id: 'an-id1',
107
111
  mgmt: { id: 'an-id1' },
108
112
  nameDisplay: 'c-cluster',
109
113
  isReady: true
110
114
  },
111
115
  {
112
116
  name: 'x33-cwf5-name',
113
- id: 'x33-cwf5-id',
117
+ id: 'an-id2',
114
118
  mgmt: { id: 'an-id2' },
115
119
  nameDisplay: 'a-cluster',
116
120
  isReady: false
117
121
  },
118
122
  {
119
123
  name: 'x34-cwf5-name',
120
- id: 'x34-cwf5-id',
124
+ id: 'an-id3',
121
125
  mgmt: { id: 'an-id3' },
122
126
  nameDisplay: 'b-cluster',
123
127
  isReady: true
@@ -125,7 +129,7 @@ describe('topLevelMenu', () => {
125
129
  {
126
130
  name: 'local-name',
127
131
  id: 'local',
128
- mgmt: { id: 'an-id4' },
132
+ mgmt: { id: 'local' },
129
133
  nameDisplay: 'local',
130
134
  isReady: true
131
135
  },
@@ -158,7 +162,7 @@ describe('topLevelMenu', () => {
158
162
  'management/all': () => [
159
163
  {
160
164
  name: 'x32-cwf5-name',
161
- id: 'x32-cwf5-id',
165
+ id: 'an-id1',
162
166
  mgmt: { id: 'an-id1' },
163
167
  nameDisplay: 'c-cluster',
164
168
  isReady: true,
@@ -166,7 +170,7 @@ describe('topLevelMenu', () => {
166
170
  },
167
171
  {
168
172
  name: 'x33-cwf5-name',
169
- id: 'x33-cwf5-id',
173
+ id: 'an-id2',
170
174
  mgmt: { id: 'an-id2' },
171
175
  nameDisplay: 'a-cluster',
172
176
  isReady: true,
@@ -174,7 +178,7 @@ describe('topLevelMenu', () => {
174
178
  },
175
179
  {
176
180
  name: 'x34-cwf5-name',
177
- id: 'x34-cwf5-id',
181
+ id: 'an-id3',
178
182
  mgmt: { id: 'an-id3' },
179
183
  nameDisplay: 'b-cluster',
180
184
  isReady: true,
@@ -183,7 +187,7 @@ describe('topLevelMenu', () => {
183
187
  {
184
188
  name: 'local-name',
185
189
  id: 'local',
186
- mgmt: { id: 'an-id4' },
190
+ mgmt: { id: 'local' },
187
191
  nameDisplay: 'local',
188
192
  isReady: true,
189
193
  pinned: true
@@ -217,7 +221,7 @@ describe('topLevelMenu', () => {
217
221
  'management/all': () => [
218
222
  {
219
223
  name: 'x32-cwf5-name',
220
- id: 'x32-cwf5-id',
224
+ id: 'an-id1',
221
225
  mgmt: { id: 'an-id1' },
222
226
  nameDisplay: 'c-cluster',
223
227
  isReady: true,
@@ -225,7 +229,7 @@ describe('topLevelMenu', () => {
225
229
  },
226
230
  {
227
231
  name: 'x33-cwf5-name',
228
- id: 'x33-cwf5-id',
232
+ id: 'an-id2',
229
233
  mgmt: { id: 'an-id2' },
230
234
  nameDisplay: 'a-cluster',
231
235
  isReady: true,
@@ -233,7 +237,7 @@ describe('topLevelMenu', () => {
233
237
  },
234
238
  {
235
239
  name: 'x34-cwf5-name',
236
- id: 'x34-cwf5-id',
240
+ id: 'an-id3',
237
241
  mgmt: { id: 'an-id3' },
238
242
  nameDisplay: 'b-cluster',
239
243
  isReady: false,
@@ -242,7 +246,7 @@ describe('topLevelMenu', () => {
242
246
  {
243
247
  name: 'local-name',
244
248
  id: 'local',
245
- mgmt: { id: 'an-id4' },
249
+ mgmt: { id: 'local' },
246
250
  nameDisplay: 'local',
247
251
  isReady: true,
248
252
  pinned: true
@@ -333,7 +337,7 @@ describe('topLevelMenu', () => {
333
337
  it('should show description if it is available on the mgmt cluster (relevant for RKE1/ember world)', async() => {
334
338
  const wrapper: Wrapper<InstanceType<typeof TopLevelMenu>> = mount(TopLevelMenu, {
335
339
  data: () => {
336
- return { hasProvCluster: false, showPinClusters: true };
340
+ return { hasProvCluster: true, showPinClusters: true };
337
341
  },
338
342
  mocks: {
339
343
  $store: {
@@ -347,6 +351,7 @@ describe('topLevelMenu', () => {
347
351
  {
348
352
  name: 'whatever',
349
353
  id: 'an-id1',
354
+ mgmt: { id: 'an-id1' },
350
355
  description: 'some-description1',
351
356
  nameDisplay: 'some-label',
352
357
  isReady: true,
@@ -356,6 +361,7 @@ describe('topLevelMenu', () => {
356
361
  {
357
362
  name: 'whatever',
358
363
  id: 'an-id2',
364
+ mgmt: { id: 'an-id2' },
359
365
  description: 'some-description2',
360
366
  nameDisplay: 'some-label',
361
367
  pinned: true
@@ -364,6 +370,7 @@ describe('topLevelMenu', () => {
364
370
  {
365
371
  name: 'whatever',
366
372
  id: 'an-id3',
373
+ mgmt: { id: 'an-id3' },
367
374
  description: 'some-description3',
368
375
  nameDisplay: 'some-label',
369
376
  isReady: true
@@ -372,6 +379,7 @@ describe('topLevelMenu', () => {
372
379
  {
373
380
  name: 'whatever',
374
381
  id: 'an-id4',
382
+ mgmt: { id: 'an-id4' },
375
383
  description: 'some-description4',
376
384
  nameDisplay: 'some-label'
377
385
  },
@@ -430,11 +438,15 @@ describe('topLevelMenu', () => {
430
438
  describe('should displays a no results message if have clusters but', () => {
431
439
  it('given no matching clusters', () => {
432
440
  const wrapper: Wrapper<InstanceType<typeof TopLevelMenu>> = mount(TopLevelMenu, {
433
- data: () => ({ clusterFilter: 'whatever' }),
441
+ data: () => ({ hasProvCluster: true, clusterFilter: 'whatever' }),
434
442
  mocks: {
435
443
  $store: {
436
444
  getters: {
437
- 'management/all': () => [{ nameDisplay: 'something else' }],
445
+ 'management/all': () => [{
446
+ id: 'an-id1',
447
+ mgmt: { id: 'an-id1' },
448
+ nameDisplay: 'something else'
449
+ }],
438
450
  ...defaultStore
439
451
  },
440
452
  },
@@ -449,11 +461,16 @@ describe('topLevelMenu', () => {
449
461
 
450
462
  it('given no matched pinned clusters', () => {
451
463
  const wrapper: Wrapper<InstanceType<typeof TopLevelMenu>> = mount(TopLevelMenu, {
452
- data: () => ({ clusterFilter: 'whatever' }),
464
+ data: () => ({ hasProvCluster: true, clusterFilter: 'whatever' }),
453
465
  mocks: {
454
466
  $store: {
455
467
  getters: {
456
- 'management/all': () => [{ nameDisplay: 'something else', pinned: true }],
468
+ 'management/all': () => [{
469
+ id: 'an-id1',
470
+ mgmt: { id: 'an-id1' },
471
+ nameDisplay: 'something else',
472
+ pinned: true
473
+ }],
457
474
  ...defaultStore
458
475
  },
459
476
  },
@@ -471,11 +488,15 @@ describe('topLevelMenu', () => {
471
488
  it('given matching clusters', () => {
472
489
  const search = 'you found me';
473
490
  const wrapper: Wrapper<InstanceType<typeof TopLevelMenu>> = mount(TopLevelMenu, {
474
- data: () => ({ clusterFilter: search }),
491
+ data: () => ({ hasProvCluster: true, clusterFilter: search }),
475
492
  mocks: {
476
493
  $store: {
477
494
  getters: {
478
- 'management/all': () => [{ nameDisplay: search }],
495
+ 'management/all': () => [{
496
+ id: 'an-id1',
497
+ mgmt: { id: 'an-id1' },
498
+ nameDisplay: search
499
+ }],
479
500
  ...defaultStore
480
501
  },
481
502
  },
@@ -492,11 +513,16 @@ describe('topLevelMenu', () => {
492
513
  it('given clusters with status pinned', () => {
493
514
  const search = 'you found me';
494
515
  const wrapper: Wrapper<InstanceType<typeof TopLevelMenu>> = mount(TopLevelMenu, {
495
- data: () => ({ clusterFilter: search }),
516
+ data: () => ({ hasProvCluster: true, clusterFilter: search }),
496
517
  mocks: {
497
518
  $store: {
498
519
  getters: {
499
- 'management/all': () => [{ nameDisplay: search, pinned: true }],
520
+ 'management/all': () => [{
521
+ nameDisplay: search,
522
+ pinned: true,
523
+ id: 'an-id1',
524
+ mgmt: { id: 'an-id1' },
525
+ }],
500
526
  ...defaultStore
501
527
  },
502
528
  },
@@ -172,3 +172,5 @@ export const SYSTEM_LABELS = [
172
172
  'node.kubernetes.io',
173
173
  'egress.rke2.io'
174
174
  ];
175
+
176
+ export const CLOUD_CREDENTIALS = { EXPIRATION: 'rancher.io/expiration-timestamp' };
@@ -17,15 +17,16 @@ export const STEVE_ID_COL = {
17
17
  name: 'steve-id',
18
18
  labelKey: 'tableHeaders.id',
19
19
  value: 'id',
20
- sort: ['id'],
21
- search: 'id',
20
+ sort: false, // sort: ['id'], // Pending API support
21
+ search: false, // search: 'id', // Pending API support
22
22
  };
23
23
 
24
24
  export const STEVE_STATE_COL = {
25
25
  ...STATE,
26
- // value: 'metadata.state.name', Use the state as defined by the resource rather than converted via the model.
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
+ // 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)
27
28
  // This means we'll show something different to what we sort and filter on.
28
- sort: [], // ['metadata.state.name'], // Pending API support
29
+ sort: false, // ['metadata.state.name'], // Pending API support
29
30
  search: false, // 'metadata.state.name', // Pending API support
30
31
  };
31
32
 
package/config/roles.ts CHANGED
@@ -1,3 +1,17 @@
1
+ export const enum SCOPED_RESOURCE_GROUPS {
2
+ GLOBAL = 'globalScopedApiGroups', // eslint-disable-line no-unused-vars
3
+ CLUSTER = 'clusterScopedApiGroups', // eslint-disable-line no-unused-vars
4
+ PROJECT_NAMESPACE = 'projectScopedApiGroups', // eslint-disable-line no-unused-vars
5
+ }
6
+
7
+ /**
8
+ * Resources users can select when creating grants when managing global, cluster and project/namespace roles
9
+ *
10
+ * **************NOTE*****************
11
+ * Global roles will show ALL entries
12
+ * Cluster roles will show cluster AND project/namespace entries
13
+ * Project/Namespace roles will show ONLY project/namespace entries
14
+ */
1
15
  export const SCOPED_RESOURCES = {
2
16
  // With this hardcoded list, it will be easier to curate a more useful
3
17
  // and human-understandable list of resources to choose from
@@ -13,7 +27,7 @@ export const SCOPED_RESOURCES = {
13
27
  // the global scoped list, and the project role creation form includes a
14
28
  // subset of the cluster scoped list.
15
29
 
16
- globalScopedApiGroups: {
30
+ [SCOPED_RESOURCE_GROUPS.GLOBAL]: {
17
31
  // Global scoped resources are resources for
18
32
  // Rancher's global apps, mainly Cluster
19
33
  // Management and Continuous Delivery.
@@ -130,9 +144,9 @@ export const SCOPED_RESOURCES = {
130
144
  resources: [
131
145
  'Clusters'
132
146
  ]
133
- }
147
+ },
134
148
  },
135
- clusterScopedApiGroups: {
149
+ [SCOPED_RESOURCE_GROUPS.CLUSTER]: {
136
150
  // Cluster scoped resources are for non-namespaced
137
151
  // resources at the cluster level, for example,
138
152
  // storage resources.
@@ -201,15 +215,16 @@ export const SCOPED_RESOURCES = {
201
215
  },
202
216
  neuvectorApi: {
203
217
  resources: [
204
- 'nv-perm.admctrl',
205
- 'nv-perm.authentication',
206
- 'nv-perm.ci-scan',
207
- 'nv-perm.fed',
208
- 'nv-perm.vulnerability'
218
+ 'AdmissionControl',
219
+ 'Authentication',
220
+ 'CIScan',
221
+ 'Cluster',
222
+ 'Federation',
223
+ 'Vulnerability',
209
224
  ]
210
225
  }
211
226
  },
212
- projectScopedApiGroups: {
227
+ [SCOPED_RESOURCE_GROUPS.PROJECT_NAMESPACE]: {
213
228
  // Project scoped resources include all other namespaced
214
229
  // resources.
215
230
  coreKubernetesApi: {
@@ -378,16 +393,16 @@ export const SCOPED_RESOURCES = {
378
393
  },
379
394
  neuvectorApi: {
380
395
  resources: [
381
- 'nv-perm.all-permissions',
382
- 'nv-perm.audit-events',
383
- 'nv-perm.authorization',
384
- 'nv-perm.compliance',
385
- 'nv-perm.events',
386
- 'nv-perm.reg-scan',
387
- 'nv-perm.rt-policy',
388
- 'nv-perm.rt-scan',
389
- 'nv-perm.security-events',
390
- 'nv-perm.config',
396
+ 'AuditEvents',
397
+ 'Authorization',
398
+ 'Compliance',
399
+ 'Events',
400
+ 'Namespace',
401
+ 'RegistryScan',
402
+ 'RuntimePolicy',
403
+ 'RuntimeScan',
404
+ 'SecurityEvents',
405
+ 'SystemConfig',
391
406
  ]
392
407
  }
393
408
  }
@@ -5,7 +5,7 @@ import { tryInitialSetup } from '@shell/utils/auth';
5
5
  import { routeRequiresAuthentication } from '@shell/utils/router';
6
6
 
7
7
  export function install(router, context) {
8
- router.beforeEach((to, from, next) => attemptFirstLogin(to, from, next, context));
8
+ router.beforeEach(async(to, from, next) => await attemptFirstLogin(to, from, next, context));
9
9
  }
10
10
 
11
11
  export async function attemptFirstLogin(to, from, next, { store }) {
@@ -2,7 +2,7 @@ import { routeRequiresAuthentication } from '@shell/utils/router';
2
2
  import { isLoggedIn, notLoggedIn, noAuth, findMe } from '@shell/utils/auth';
3
3
 
4
4
  export function install(router, context) {
5
- router.beforeEach((to, from, next) => authenticate(to, from, next, context));
5
+ router.beforeEach(async(to, from, next) => await authenticate(to, from, next, context));
6
6
  }
7
7
 
8
8
  export async function authenticate(to, from, next, { store }) {
@@ -1,5 +1,5 @@
1
1
  export function install(router, context) {
2
- router.beforeEach((to, from, next) => loadI18n(to, from, next, context));
2
+ router.beforeEach(async(to, from, next) => await loadI18n(to, from, next, context));
3
3
  }
4
4
 
5
5
  export async function loadI18n(to, from, next, { store }) {
@@ -1,6 +1,7 @@
1
1
  import { install as installLoadInitialSettings } from '@shell/config/router/navigation-guards/load-initial-settings';
2
2
  import { install as installAttemptFirstLogin } from '@shell/config/router/navigation-guards/attempt-first-login';
3
3
  import { install as installAuthentication } from '@shell/config/router/navigation-guards/authentication';
4
+ import { install as installRuntimeExtensionRoute } from '@shell/config/router/navigation-guards/runtime-extension-route';
4
5
  import { install as installI18N } from '@shell/config/router/navigation-guards/i18n';
5
6
 
6
7
  /**
@@ -10,7 +11,7 @@ export function installNavigationGuards(router, context) {
10
11
  // NOTE: the order of the installation matters.
11
12
  // Be intentional when adding, removing or modifying the guards that are installed.
12
13
 
13
- const navigationGuardInstallers = [installLoadInitialSettings, installAttemptFirstLogin, installAuthentication, installI18N];
14
+ const navigationGuardInstallers = [installLoadInitialSettings, installAttemptFirstLogin, installAuthentication, installRuntimeExtensionRoute, installI18N];
14
15
 
15
16
  navigationGuardInstallers.forEach((installer) => installer(router, context));
16
17
  }
@@ -1,7 +1,7 @@
1
1
  import { fetchInitialSettings } from '@shell/utils/settings';
2
2
 
3
3
  export function install(router, context) {
4
- router.beforeEach((to, from, next) => loadInitialSettings(to, from, next, context));
4
+ router.beforeEach(async(to, from, next) => await loadInitialSettings(to, from, next, context));
5
5
  }
6
6
 
7
7
  export async function loadInitialSettings(to, from, next, { store }) {