@rancher/shell 3.0.5 → 3.0.7

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 (92) hide show
  1. package/assets/images/pl/dark/rancher-logo.svg +131 -44
  2. package/assets/images/pl/rancher-logo.svg +120 -44
  3. package/assets/styles/base/_basic.scss +2 -2
  4. package/assets/styles/base/_color-classic.scss +51 -0
  5. package/assets/styles/base/_color.scss +3 -3
  6. package/assets/styles/base/_mixins.scss +1 -1
  7. package/assets/styles/base/_variables-classic.scss +47 -0
  8. package/assets/styles/global/_button.scss +49 -17
  9. package/assets/styles/global/_form.scss +1 -1
  10. package/assets/styles/themes/_dark.scss +4 -0
  11. package/assets/styles/themes/_light.scss +3 -69
  12. package/assets/styles/themes/_modern.scss +194 -50
  13. package/assets/styles/vendor/vue-select.scss +1 -2
  14. package/assets/translations/en-us.yaml +33 -21
  15. package/components/ClusterIconMenu.vue +1 -1
  16. package/components/ClusterProviderIcon.vue +1 -1
  17. package/components/CodeMirror.vue +1 -1
  18. package/components/FilterPanel.vue +8 -1
  19. package/components/IconOrSvg.vue +40 -29
  20. package/components/PaginatedResourceTable.vue +7 -2
  21. package/components/PromptRemove.vue +5 -0
  22. package/components/ResourceDetail/index.vue +1 -0
  23. package/components/ResourceTable.vue +30 -20
  24. package/components/SortableTable/sorting.js +3 -1
  25. package/components/Tabbed/index.vue +5 -5
  26. package/components/form/ResourceTabs/index.vue +37 -18
  27. package/components/form/SecretSelector.vue +6 -2
  28. package/components/nav/Group.vue +29 -9
  29. package/components/nav/Header.vue +6 -8
  30. package/components/nav/NamespaceFilter.vue +1 -1
  31. package/components/nav/TopLevelMenu.helper.ts +47 -20
  32. package/components/nav/TopLevelMenu.vue +44 -14
  33. package/components/nav/Type.vue +0 -5
  34. package/components/nav/__tests__/TopLevelMenu.test.ts +2 -0
  35. package/config/pagination-table-headers.js +10 -2
  36. package/config/product/explorer.js +9 -8
  37. package/config/table-headers.js +9 -0
  38. package/config/uiplugins.js +1 -1
  39. package/core/plugin.ts +33 -9
  40. package/core/types.ts +37 -6
  41. package/detail/provisioning.cattle.io.cluster.vue +1 -0
  42. package/dialog/InstallExtensionDialog.vue +71 -45
  43. package/dialog/UninstallExtensionDialog.vue +2 -1
  44. package/dialog/__tests__/InstallExtensionDialog.test.ts +111 -0
  45. package/edit/auth/oidc.vue +86 -16
  46. package/list/catalog.cattle.io.clusterrepo.vue +2 -2
  47. package/mixins/__tests__/chart.test.ts +1 -1
  48. package/mixins/chart.js +1 -1
  49. package/models/event.js +7 -0
  50. package/models/provisioning.cattle.io.cluster.js +9 -0
  51. package/package.json +2 -2
  52. package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +6 -0
  53. package/pages/c/_cluster/apps/charts/StatusLabel.vue +4 -3
  54. package/pages/c/_cluster/apps/charts/index.vue +12 -11
  55. package/pages/c/_cluster/explorer/EventsTable.vue +3 -6
  56. package/pages/c/_cluster/settings/performance.vue +1 -1
  57. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +159 -62
  58. package/pages/c/_cluster/uiplugins/__tests__/PluginInfoPanel.test.ts +102 -0
  59. package/pages/c/_cluster/uiplugins/__tests__/{index.spec.ts → index.test.ts} +121 -55
  60. package/pages/c/_cluster/uiplugins/index.vue +110 -94
  61. package/plugins/__tests__/subscribe.events.test.ts +194 -0
  62. package/plugins/dashboard-store/actions.js +3 -0
  63. package/plugins/dashboard-store/getters.js +1 -1
  64. package/plugins/dashboard-store/resource-class.js +15 -4
  65. package/plugins/steve/__tests__/subscribe.spec.ts +27 -24
  66. package/plugins/steve/index.js +18 -10
  67. package/plugins/steve/mutations.js +2 -2
  68. package/plugins/steve/resourceWatcher.js +2 -2
  69. package/plugins/steve/steve-pagination-utils.ts +26 -31
  70. package/plugins/steve/subscribe.js +113 -85
  71. package/plugins/subscribe-events.ts +211 -0
  72. package/rancher-components/BadgeState/BadgeState.vue +8 -6
  73. package/rancher-components/Banner/Banner.vue +2 -1
  74. package/rancher-components/Form/Checkbox/Checkbox.vue +3 -3
  75. package/rancher-components/Form/Radio/RadioButton.vue +3 -3
  76. package/scripts/test-plugins-build.sh +4 -5
  77. package/scripts/typegen.sh +2 -0
  78. package/store/auth.js +2 -2
  79. package/store/index.js +12 -22
  80. package/types/extension-manager.ts +8 -1
  81. package/types/resources/settings.d.ts +24 -17
  82. package/types/shell/index.d.ts +534 -336
  83. package/types/store/subscribe-events.types.ts +70 -0
  84. package/types/store/subscribe.types.ts +6 -22
  85. package/types/store/vuex.d.ts +2 -1
  86. package/types/vue-shim.d.ts +2 -5
  87. package/utils/pagination-utils.ts +98 -30
  88. package/utils/pagination-wrapper.ts +6 -8
  89. package/utils/sort.js +5 -0
  90. package/utils/unit-tests/pagination-utils.spec.ts +283 -0
  91. package/utils/validators/formRules/__tests__/index.test.ts +7 -0
  92. package/utils/validators/formRules/index.ts +2 -2
package/core/types.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { ProductFunction } from './plugin';
2
2
  import { RouteRecordRaw } from 'vue-router';
3
3
  import type { ExtensionManager } from '@shell/types/extension-manager';
4
+ import { PaginationSettingsStores } from '@shell/types/resources/settings';
4
5
 
5
6
  // Cluster Provisioning types
6
7
  export * from './types-provisioning';
@@ -130,9 +131,6 @@ export type Card = {
130
131
  component: Function;
131
132
  };
132
133
 
133
- // Duplication of HeaderOptions?
134
- export type TableColumn = any;
135
-
136
134
  /** Definition of a tab (options that can be passed when defining an extension tab enhancement) */
137
135
  export type Tab = {
138
136
  name: string;
@@ -281,6 +279,9 @@ export interface ProductOptions {
281
279
  // typeStoreMap: string;
282
280
  }
283
281
 
282
+ /**
283
+ * Configuration required to show a header in a ResourceTable
284
+ */
284
285
  export interface HeaderOptions {
285
286
  /**
286
287
  * Name of the header. This should be unique.
@@ -305,7 +306,7 @@ export interface HeaderOptions {
305
306
  /**
306
307
  * A string which represents the path to access the value from the row object which we'll use to sort i.e. `row.meta.value`
307
308
  */
308
- sort?: string | string[];
309
+ sort?: string | string[] | boolean;
309
310
 
310
311
  /**
311
312
  * A string which represents the path to access the value from the row object which we'll use to search i.e. `row.meta.value`.
@@ -336,6 +337,26 @@ export interface HeaderOptions {
336
337
  getValue?: (row: any) => string | number | null | undefined;
337
338
  }
338
339
 
340
+ /**
341
+ * Configuration required to show a header in a ResourceTable when server-side pagination is enable
342
+ */
343
+ export type PaginationHeaderOptions = Omit<HeaderOptions, 'getValue'>
344
+
345
+ /**
346
+ * External extension configuration for @HeaderOptions
347
+ */
348
+ export type TableColumn = HeaderOptions;
349
+
350
+ /**
351
+ * External extension configuration for @PaginationHeaderOptions
352
+ */
353
+ export type PaginationTableColumn = PaginationHeaderOptions;
354
+
355
+ /**
356
+ * External extension configuration for @PaginationSettingsStores
357
+ */
358
+ export type ServerSidePaginationExtensionConfig = PaginationSettingsStores;
359
+
339
360
  export interface ConfigureTypeOptions {
340
361
  /**
341
362
  * Override for the create button string on a list view
@@ -621,9 +642,17 @@ export interface IPlugin {
621
642
  addCard(where: CardLocation | string, when: LocationConfig | string, action: Card): void;
622
643
 
623
644
  /**
624
- * Adds a new column to the SortableTable component
645
+ * Adds a new column to a ResourceTable
646
+ *
647
+ * @param where
648
+ * @param when
649
+ * @param action
650
+ * @param column
651
+ * The information required to show a header and values for a column in a table
652
+ * @param paginationColumn
653
+ * As per `column`, but is used where server-side pagination is enabled
625
654
  */
626
- addTableColumn(where: TableColumnLocation | string, when: LocationConfig | string, action: TableColumn): void;
655
+ addTableColumn(where: TableColumnLocation | string, when: LocationConfig | string, column: TableColumn, paginationColumn?: TableColumn): void;
627
656
 
628
657
  /**
629
658
  * Set the component to use for the landing home page
@@ -670,6 +699,8 @@ export interface IPlugin {
670
699
  ): void;
671
700
  addNavHooks(hooks: NavHooks): void;
672
701
 
702
+ enableServerSidePagination(config: ServerSidePaginationExtensionConfig): void;
703
+
673
704
  /**
674
705
  * Adds a model extension
675
706
  * @experimental May change or be removed in the future
@@ -89,6 +89,7 @@ export default {
89
89
  },
90
90
 
91
91
  async fetch() {
92
+ await this.$store.dispatch(`management/find`, { type: MANAGEMENT.CLUSTER, id: this.value.mgmtClusterId });
92
93
  await this.value.waitForProvisioner();
93
94
 
94
95
  // Support for the 'provisioner' extension
@@ -3,12 +3,12 @@ import AsyncButton from '@shell/components/AsyncButton';
3
3
  import LabeledSelect from '@shell/components/form/LabeledSelect';
4
4
  import { CATALOG, MANAGEMENT } from '@shell/config/types';
5
5
  import { CATALOG as CATALOG_ANNOTATIONS } from '@shell/config/labels-annotations';
6
- import { UI_PLUGIN_NAMESPACE } from '@shell/config/uiplugins';
6
+ import { UI_PLUGIN_NAMESPACE, isChartVersionHigher } from '@shell/config/uiplugins';
7
7
  import Banner from '@components/Banner/Banner.vue';
8
8
  import { SETTING } from '@shell/config/settings';
9
- import { getPluginChartVersion, getPluginChartVersionLabel } from '@shell/utils/uiplugins';
9
+ import { getPluginChartVersionLabel } from '@shell/utils/uiplugins';
10
10
 
11
- // Note: This dialog handles installation and update of a plugin
11
+ // Note: This dialog handles installation, upgrade and downgrade of a plugin
12
12
 
13
13
  export default {
14
14
  emits: ['close'],
@@ -29,7 +29,14 @@ export default {
29
29
  required: true
30
30
  },
31
31
  /**
32
- * The action to perform (install, update, rollback)
32
+ * The pre-selected version in the dropdown
33
+ */
34
+ initialVersion: {
35
+ type: String,
36
+ default: null
37
+ },
38
+ /**
39
+ * The action to perform (install, upgrade, downgrade)
33
40
  */
34
41
  action: {
35
42
  type: String,
@@ -63,33 +70,32 @@ export default {
63
70
  },
64
71
 
65
72
  async fetch() {
66
- const chartVersion = getPluginChartVersion(this.plugin);
67
-
68
- // Default to latest version on install (this is default on the plugin)
69
- this.version = chartVersion;
70
-
71
- if (this.action === 'update') {
72
- this.currentVersion = chartVersion;
73
-
74
- // Update to latest version, so take the first version
75
- if (this.plugin?.installableVersions?.length > 0) {
76
- this.version = this.plugin?.installableVersions?.[0]?.version;
77
- }
78
- } else if (this.action === 'rollback') {
79
- // Find the newest version once we remove the current version
80
- const versionNames = this.plugin.installableVersions.filter((v) => v.version !== chartVersion);
73
+ // Determine the currently installed version, if any
74
+ if (this.plugin.installed) {
75
+ this.currentVersion = this.plugin.installedVersion;
76
+ }
81
77
 
82
- this.currentVersion = chartVersion;
78
+ // Determine the initial version to select in the dropdown
79
+ if (this.initialVersion) {
80
+ this.version = this.initialVersion;
81
+ } else if (this.action === 'upgrade') {
82
+ // Upgrade to the latest version, so take the first version
83
+ this.version = this.plugin?.installableVersions?.[0]?.version;
84
+ } else if (this.action === 'downgrade') {
85
+ const versions = this.plugin.installableVersions;
86
+ const currentIndex = versions.findIndex((v) => v.version === this.currentVersion);
83
87
 
84
- if (versionNames.length > 0) {
85
- this.version = versionNames[0].version;
88
+ if (currentIndex !== -1 && currentIndex < versions.length - 1) {
89
+ // Select the version just below the current version
90
+ this.version = versions[currentIndex + 1].version;
86
91
  }
92
+ } else {
93
+ // Default to the latest installable version for new installs
94
+ this.version = this.plugin?.installableVersions?.[0]?.version;
87
95
  }
88
96
 
89
- // Make sure we have the version available
90
- const versionChart = this.plugin?.installableVersions?.find((v) => v.version === this.version);
91
-
92
- if (!versionChart) {
97
+ // Fallback if no version could be determined
98
+ if (!this.version) {
93
99
  this.version = this.plugin?.installableVersions?.[0]?.version;
94
100
  }
95
101
 
@@ -119,37 +125,39 @@ export default {
119
125
  },
120
126
 
121
127
  versionOptions() {
122
- if (!this.plugin) {
128
+ if (!this.plugin?.installableVersions) {
123
129
  return [];
124
130
  }
125
131
 
126
- // Don't allow update/rollback to current version
127
- const versions = this.plugin?.installableVersions?.filter((v) => {
128
- if (this.currentVersion) {
129
- return v.version !== this.currentVersion;
130
- }
131
-
132
- return true;
133
- });
132
+ // Don't allow upgrade/downgrade to current version by disabling the option
133
+ return this.plugin.installableVersions.map((v) => {
134
+ const isCurrent = v.version === this.currentVersion;
134
135
 
135
- return versions.map((version) => {
136
136
  return {
137
- label: getPluginChartVersionLabel(version),
138
- value: version.version,
137
+ label: getPluginChartVersionLabel(v) + (isCurrent ? ` (${ this.t('plugins.labels.current') })` : ''),
138
+ value: v.version,
139
+ disabled: isCurrent,
139
140
  };
140
141
  });
141
142
  },
142
143
 
143
144
  buttonMode() {
144
- if (this.action === 'rollback') {
145
- return 'rollback';
145
+ if (this.action === 'install') {
146
+ return 'install';
146
147
  }
147
148
 
148
- if (this.action === 'update') {
149
- return 'update';
149
+ if (this.currentVersion && this.version) {
150
+ if (isChartVersionHigher(this.version, this.currentVersion)) {
151
+ return 'upgrade';
152
+ }
153
+
154
+ if (isChartVersionHigher(this.currentVersion, this.version)) {
155
+ return 'downgrade';
156
+ }
150
157
  }
151
158
 
152
- return 'install';
159
+ // Fallback for safety, though should not be reached if version is selected
160
+ return this.action;
153
161
  },
154
162
 
155
163
  chartVersionLoadsWithoutAuth() {
@@ -158,6 +166,23 @@ export default {
158
166
 
159
167
  returnFocusSelector() {
160
168
  return `[data-testid="extension-card-${ this.action }-btn-${ this.plugin?.name }"]`;
169
+ },
170
+
171
+ buttonIcon() {
172
+ if (this.busy) {
173
+ return '';
174
+ }
175
+
176
+ switch (this.buttonMode) {
177
+ case 'install':
178
+ return 'icon-plus';
179
+ case 'upgrade':
180
+ return 'icon-upgrade-alt';
181
+ case 'downgrade':
182
+ return 'icon-downgrade-alt';
183
+ default:
184
+ return '';
185
+ }
161
186
  }
162
187
  },
163
188
 
@@ -295,12 +320,12 @@ export default {
295
320
  <template>
296
321
  <div class="plugin-install-dialog">
297
322
  <h4 class="mt-10">
298
- {{ t(`plugins.${ action }.title`, { name: plugin?.label }) }}
323
+ {{ t(`plugins.${ buttonMode }.title`, { name: `"${plugin?.label}"` }, true) }}
299
324
  </h4>
300
325
  <div class="custom mt-10">
301
326
  <div class="dialog-panel">
302
327
  <p>
303
- {{ t(`plugins.${ action }.prompt`) }}
328
+ {{ t(`plugins.${ buttonMode }.prompt`) }}
304
329
  </p>
305
330
  <Banner
306
331
  v-if="chartVersionLoadsWithoutAuth"
@@ -335,6 +360,7 @@ export default {
335
360
  </button>
336
361
  <AsyncButton
337
362
  :mode="buttonMode"
363
+ :icon="buttonIcon"
338
364
  data-testid="install-ext-modal-install-btn"
339
365
  @click="install"
340
366
  />
@@ -103,7 +103,7 @@ export default {
103
103
  <template>
104
104
  <div class="plugin-install-dialog">
105
105
  <h4 class="mt-10">
106
- {{ t('plugins.uninstall.title', { name: plugin?.label }) }}
106
+ {{ t('plugins.uninstall.title', { name: `"${plugin?.label}"` }, true) }}
107
107
  </h4>
108
108
  <div class="mt-10 dialog-panel">
109
109
  <div class="dialog-info">
@@ -122,6 +122,7 @@ export default {
122
122
  </button>
123
123
  <AsyncButton
124
124
  mode="uninstall"
125
+ :icon="busy ? '' : 'icon-delete'"
125
126
  data-testid="uninstall-ext-modal-uninstall-btn"
126
127
  @click="uninstall()"
127
128
  />
@@ -0,0 +1,111 @@
1
+ import { shallowMount, VueWrapper } from '@vue/test-utils';
2
+ import InstallExtensionDialog from '@shell/dialog/InstallExtensionDialog.vue';
3
+
4
+ jest.mock('@shell/config/uiplugins', () => ({
5
+ ...jest.requireActual('@shell/config/uiplugins'),
6
+ isChartVersionHigher: jest.fn((v1: string, v2: string) => v1 > v2),
7
+ }));
8
+
9
+ const t = (key: string): string => key;
10
+
11
+ describe('component: InstallExtensionDialog', () => {
12
+ let wrapper: VueWrapper<any>;
13
+
14
+ const mountComponent = (propsData = {}) => {
15
+ const store = { dispatch: () => Promise.resolve() };
16
+
17
+ const defaultProps = {
18
+ plugin: { installableVersions: [] },
19
+ action: 'install',
20
+ updateStatus: jest.fn(),
21
+ closed: jest.fn(),
22
+ };
23
+
24
+ return shallowMount(InstallExtensionDialog, {
25
+ propsData: {
26
+ ...defaultProps,
27
+ ...propsData,
28
+ },
29
+ global: {
30
+ mocks: {
31
+ $store: store,
32
+ t,
33
+ },
34
+ }
35
+ });
36
+ };
37
+
38
+ describe('fetch', () => {
39
+ it('should set currentVersion if plugin is installed', async() => {
40
+ wrapper = mountComponent({ plugin: { installed: true, installedVersion: '1.0.0' } });
41
+ await wrapper.vm.$options.fetch.call(wrapper.vm);
42
+ expect(wrapper.vm.currentVersion).toBe('1.0.0');
43
+ });
44
+
45
+ it('should set version from initialVersion if provided', async() => {
46
+ wrapper = mountComponent({ initialVersion: '1.2.3', plugin: { installed: false } });
47
+ await wrapper.vm.$options.fetch.call(wrapper.vm);
48
+ expect(wrapper.vm.version).toBe('1.2.3');
49
+ });
50
+
51
+ it('should set version to latest for upgrade action', async() => {
52
+ const plugin = { installableVersions: [{ version: '1.1.0' }, { version: '1.0.0' }] };
53
+
54
+ wrapper = mountComponent({ plugin, action: 'upgrade' });
55
+ await wrapper.vm.$options.fetch.call(wrapper.vm);
56
+ expect(wrapper.vm.version).toBe('1.1.0');
57
+ });
58
+
59
+ it('should set version to next oldest for downgrade action', async() => {
60
+ const plugin = {
61
+ installed: true,
62
+ installedVersion: '1.1.0',
63
+ installableVersions: [{ version: '1.1.0' }, { version: '1.0.0' }]
64
+ };
65
+
66
+ wrapper = mountComponent({ plugin, action: 'downgrade' });
67
+ await wrapper.vm.$options.fetch.call(wrapper.vm);
68
+ expect(wrapper.vm.version).toBe('1.0.0');
69
+ });
70
+ });
71
+
72
+ describe('versionOptions', () => {
73
+ it('should include and disable the current version', () => {
74
+ const plugin = {
75
+ installableVersions: [
76
+ { version: '1.1.0' },
77
+ { version: '1.0.0' },
78
+ ]
79
+ };
80
+
81
+ wrapper = mountComponent({ plugin });
82
+ wrapper.vm.currentVersion = '1.0.0';
83
+
84
+ const options = wrapper.vm.versionOptions;
85
+ const currentOption = options.find((o: any) => o.value === '1.0.0');
86
+
87
+ expect(currentOption).toBeDefined();
88
+ expect(currentOption.disabled).toBe(true);
89
+ expect(currentOption.label).toContain('(plugins.labels.current)');
90
+ });
91
+ });
92
+
93
+ describe('buttonMode', () => {
94
+ beforeEach(() => {
95
+ wrapper = mountComponent({ action: 'upgrade' });
96
+ wrapper.vm.currentVersion = '1.0.0';
97
+ });
98
+
99
+ it('should be "upgrade" if selected version is higher', async() => {
100
+ wrapper.vm.version = '1.1.0';
101
+ await wrapper.vm.$nextTick();
102
+ expect(wrapper.vm.buttonMode).toBe('upgrade');
103
+ });
104
+
105
+ it('should be "downgrade" if selected version is lower', async() => {
106
+ wrapper.vm.version = '0.9.0';
107
+ await wrapper.vm.$nextTick();
108
+ expect(wrapper.vm.buttonMode).toBe('downgrade');
109
+ });
110
+ });
111
+ });
@@ -59,11 +59,16 @@ export default {
59
59
  userInfoEndpoint: null,
60
60
  },
61
61
  // TODO #13457: this is duplicated due wrong format
62
- oidcScope: [],
63
- SLO_OPTION_VALUES
62
+ oidcScope: [],
63
+ SLO_OPTION_VALUES,
64
+ addCustomClaims: false,
64
65
  };
65
66
  },
66
67
 
68
+ created() {
69
+ this.registerBeforeHook(this.willSave, 'willSave');
70
+ },
71
+
67
72
  computed: {
68
73
  tArgs() {
69
74
  return {
@@ -140,6 +145,10 @@ export default {
140
145
  return this.model?.id === 'cognito';
141
146
  },
142
147
 
148
+ isGenericOidc() {
149
+ return this.model?.id === 'genericoidc';
150
+ },
151
+
143
152
  isLogoutAllSupported() {
144
153
  return this.model?.logoutAllSupported;
145
154
  },
@@ -220,6 +229,15 @@ export default {
220
229
  this.model.logoutAllForced = false;
221
230
  break;
222
231
  }
232
+ },
233
+
234
+ model: {
235
+ handler(newVal) {
236
+ if (newVal?.nameClaim || newVal?.groupsClaim || newVal?.emailClaim) {
237
+ this.addCustomClaims = true;
238
+ }
239
+ },
240
+ once: true
223
241
  }
224
242
  },
225
243
 
@@ -248,6 +266,14 @@ export default {
248
266
 
249
267
  updateScope() {
250
268
  this.model.scope = this.oidcScope.join(' ');
269
+ },
270
+
271
+ willSave() {
272
+ if (this.isGenericOidc && !this.addCustomClaims) {
273
+ this.model.nameClaim = undefined;
274
+ this.model.groupsClaim = undefined;
275
+ this.model.emailClaim = undefined;
276
+ }
251
277
  }
252
278
  }
253
279
  };
@@ -390,21 +416,60 @@ export default {
390
416
  </div>
391
417
  </div>
392
418
 
393
- <!-- Allow group search -->
394
- <div
395
- v-if="supportsGroupSearch"
396
- class="row mb-20"
397
- >
398
- <div class="col span-6">
399
- <Checkbox
400
- v-model:value="model.groupSearchEnabled"
401
- data-testid="input-group-search"
402
- :label="t('authConfig.oidc.groupSearch.label')"
403
- :tooltip="t('authConfig.oidc.groupSearch.tooltip')"
404
- :mode="mode"
405
- />
419
+ <template v-if="isGenericOidc || supportsGroupSearch">
420
+ <div
421
+ class="row mb-20"
422
+ >
423
+ <div class="col span-6 checkbox-flex">
424
+ <!-- Allow group search -->
425
+ <Checkbox
426
+ v-if="supportsGroupSearch"
427
+ v-model:value="model.groupSearchEnabled"
428
+ data-testid="input-group-search"
429
+ :label="t('authConfig.oidc.groupSearch.label')"
430
+ :tooltip="t('authConfig.oidc.groupSearch.tooltip')"
431
+ :mode="mode"
432
+ />
433
+ <Checkbox
434
+ v-if="isGenericOidc"
435
+ v-model:value="addCustomClaims"
436
+ data-testid="input-add-custom-claims"
437
+ :label="t('authConfig.oidc.customClaims.enable.label')"
438
+ :tooltip="t('authConfig.oidc.customClaims.enable.tooltip')"
439
+ :mode="mode"
440
+ />
441
+ </div>
406
442
  </div>
407
- </div>
443
+ </template>
444
+
445
+ <template v-if="addCustomClaims">
446
+ <h4>{{ t('authConfig.oidc.customClaims.label') }}</h4>
447
+ <div class="row mb-20">
448
+ <div class="col span-6">
449
+ <LabeledInput
450
+ v-model:value="model.nameClaim"
451
+ :label="t(`authConfig.oidc.customClaims.nameClaim.label`)"
452
+ :mode="mode"
453
+ />
454
+ </div>
455
+ <div class="col span-6">
456
+ <LabeledInput
457
+ v-model:value="model.groupsClaim"
458
+ :label="t(`authConfig.oidc.customClaims.groupsClaim.label`)"
459
+ :mode="mode"
460
+ />
461
+ </div>
462
+ </div>
463
+ <div class="row mb-20">
464
+ <div class="col span-6">
465
+ <LabeledInput
466
+ v-model:value="model.emailClaim"
467
+ :label="t(`authConfig.oidc.customClaims.emailClaim.label`)"
468
+ :mode="mode"
469
+ />
470
+ </div>
471
+ </div>
472
+ </template>
408
473
 
409
474
  <!-- Scopes -->
410
475
  <div class="row mb-20">
@@ -608,4 +673,9 @@ export default {
608
673
  margin: 0 3px;
609
674
  }
610
675
  }
676
+
677
+ .checkbox-flex {
678
+ display: flex;
679
+ flex-direction: column;
680
+ }
611
681
  </style>
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import PaginatedResourceTable from '@shell/components/PaginatedResourceTable.vue';
3
3
  import { CATALOG as CATALOG_ANNOTATIONS } from '@shell/config/labels-annotations';
4
- import ClusterRepo from '@shell/models/catalog.cattle.io.clusterrepo';
4
+ import { RancherKubeMetadata } from '@shell/types/kube/kube-api';
5
5
  import { PaginationArgs, PaginationParamFilter } from '@shell/types/store/pagination.types';
6
6
  import { defineComponent } from 'vue';
7
7
 
@@ -25,7 +25,7 @@ export default defineComponent({
25
25
  /**
26
26
  * Filter out hidden repos from list of all repos
27
27
  */
28
- filterRowsLocal(rows: ClusterRepo[]) {
28
+ filterRowsLocal(rows: { metadata: RancherKubeMetadata}[]) {
29
29
  return rows.filter((repo) => !(repo?.metadata?.annotations?.[CATALOG_ANNOTATIONS.HIDDEN_REPO] === 'true'));
30
30
  },
31
31
 
@@ -213,7 +213,7 @@ describe('chartMixin', () => {
213
213
  });
214
214
 
215
215
  expect(wrapper.vm.action).toStrictEqual({
216
- name: 'upgradeVersion',
216
+ name: 'upgrade',
217
217
  tKey: 'upgrade',
218
218
  icon: 'icon-upgrade-alt',
219
219
  });
package/mixins/chart.js CHANGED
@@ -242,7 +242,7 @@ export default {
242
242
 
243
243
  if (compare(this.currentVersion, this.targetVersion) < 0) {
244
244
  return {
245
- name: 'upgradeVersion', tKey: 'upgrade', icon: 'icon-upgrade-alt'
245
+ name: 'upgrade', tKey: 'upgrade', icon: 'icon-upgrade-alt'
246
246
  };
247
247
  }
248
248
 
package/models/event.js CHANGED
@@ -25,6 +25,13 @@ export default class K8sEvent extends SteveModel {
25
25
  return this._type;
26
26
  }
27
27
 
28
+ get firstSeen() {
29
+ const schema = this.$getters['schemaFor'](this.type);
30
+ const rowValueGetter = this.$rootGetters['type-map/rowValueGetter'];
31
+
32
+ return schema && rowValueGetter ? rowValueGetter(schema, 'First Seen')(this) : null;
33
+ }
34
+
28
35
  get lastSeen() {
29
36
  const schema = this.$getters['schemaFor'](this.type);
30
37
  const rowValueGetter = this.$rootGetters['type-map/rowValueGetter'];
@@ -391,6 +391,15 @@ export default class ProvCluster extends SteveModel {
391
391
  const pCluster = this.$rootGetters['management/byId'](CAPI.RANCHER_CLUSTER, this.id);
392
392
  const name = this.status?.clusterName || pCluster?.status?.clusterName;
393
393
 
394
+ try {
395
+ if (name) {
396
+ // Just in case we're not generically watching all mgmt clusters and...
397
+ // thus won't receive new mgmt cluster over socket...
398
+ // fire and forget a request to fetch it (this won't make multiple requests if one is already running)
399
+ this.$dispatch('find', { type: MANAGEMENT.CLUSTER, id: name });
400
+ }
401
+ } catch {}
402
+
394
403
  return name && !!this.$rootGetters['management/byId'](MANAGEMENT.CLUSTER, name);
395
404
  }, this.$rootGetters['i18n/t']('cluster.managementTimeout'), timeout, interval);
396
405
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rancher/shell",
3
- "version": "3.0.5",
3
+ "version": "3.0.7",
4
4
  "description": "Rancher Dashboard Shell",
5
5
  "repository": "https://github.com/rancherlabs/dashboard",
6
6
  "license": "Apache-2.0",
@@ -93,7 +93,7 @@
93
93
  "express": "4.17.1",
94
94
  "file-saver": "2.0.2",
95
95
  "floating-vue": "5.2.2",
96
- "focus-trap": "7.6.2",
96
+ "focus-trap": "7.6.5",
97
97
  "frontmatter-markdown-loader": "3.7.0",
98
98
  "identicon.js": "2.3.3",
99
99
  "intl-messageformat": "7.8.4",
@@ -80,6 +80,12 @@ function onClickItem(type: string, label: string) {
80
80
  &-text {
81
81
  text-transform: capitalize;
82
82
  margin-right: 8px;
83
+ display: -webkit-box;
84
+ -webkit-line-clamp: 1;
85
+ -webkit-box-orient: vertical;
86
+ overflow: hidden;
87
+ text-overflow: ellipsis;
88
+ word-break: break-all;
83
89
  }
84
90
 
85
91
  &-icon {