@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
@@ -381,21 +381,21 @@ export default {
381
381
  }
382
382
 
383
383
  &.active {
384
- color: var(--primary-hover-text);
385
- background-color: var(--primary-hover-bg);
384
+ color: var(--on-active, var(--primary-hover-text));
385
+ background-color: var(--active-nav, var(--primary-hover-bg));
386
386
 
387
387
  h6 {
388
388
  padding: 8px 0 8px 16px;
389
389
  font-weight: bold;
390
- color: var(--primary-hover-text);
390
+ color: var(--on-active, var(--primary-hover-text));
391
391
  }
392
392
 
393
393
  &:hover {
394
- background-color: var(--primary-hover-bg);
394
+ background-color: var(--nav-active-hover, var(--primary-hover-bg));
395
395
  }
396
396
 
397
397
  ~ I {
398
- color: var(--primary-hover-text);
398
+ color: var(--on-active, var(--primary-hover-text));
399
399
  }
400
400
  }
401
401
  &:hover:not(.active) {
@@ -433,8 +433,24 @@ export default {
433
433
  margin-left: 0;
434
434
  }
435
435
 
436
+ .child:hover {
437
+ background: var(--nav-hover, var(--nav-active));
438
+ }
439
+
436
440
  &.group-highlight {
437
- background: var(--nav-active);
441
+ background: var(--category-active, var(--nav-active));
442
+
443
+ .active.header {
444
+ &:hover {
445
+ background-color: var(--nav-active-hover)
446
+ }
447
+ }
448
+
449
+ .child, .header {
450
+ &:hover {
451
+ background: var(--category-active-hover, var(--primary));
452
+ }
453
+ }
438
454
  }
439
455
  }
440
456
 
@@ -480,13 +496,17 @@ export default {
480
496
  padding: 0;
481
497
 
482
498
  A, A I {
483
- color: var(--primary-hover-text);
499
+ color: var(--on-active, var(--primary-hover-text));
484
500
  }
485
501
 
486
502
  A {
487
- color: var(--primary-hover-text);
488
- background-color: var(--primary-hover-bg);
503
+ color: var(--on-active, var(--primary-hover-text));
504
+ background-color: var(--active-nav, var(--primary-hover-bg));
489
505
  font-weight: bold;
506
+
507
+ &:hover {
508
+ background: var(--nav-active-hover);
509
+ }
490
510
  }
491
511
  }
492
512
 
@@ -843,16 +843,14 @@ export default {
843
843
  align-items: center;
844
844
  display: flex;
845
845
  margin-right: 8px;
846
- height: 55px;
847
- margin-left: 5px;
848
846
  max-width: 200px;
849
847
  padding: 12px 0;
850
848
  }
851
849
 
852
850
  .side-menu-logo-img {
853
851
  object-fit: contain;
854
- height: 21px;
855
852
  max-width: 200px;
853
+ height: 36px;
856
854
  }
857
855
 
858
856
  > * {
@@ -933,8 +931,8 @@ export default {
933
931
  :deep() div .btn.role-tertiary {
934
932
  border: 1px solid var(--header-btn-bg);
935
933
  border: none;
936
- background: var(--header-btn-bg);
937
- color: var(--header-btn-text);
934
+ background: var(--tertiary-header, var(--header-btn-bg));
935
+ color: var(--on-tertiary-header, var(--header-btn-text));
938
936
  padding: 0 10px;
939
937
  line-height: 32px;
940
938
  min-height: 32px;
@@ -945,8 +943,8 @@ export default {
945
943
  }
946
944
 
947
945
  &:hover {
948
- background: var(--primary);
949
- color: #fff;
946
+ background: var(--tertiary-header-hover, var(--primary));
947
+ color: var(--on-tertiary-header-hover, #fff);
950
948
  }
951
949
 
952
950
  &[disabled=disabled] {
@@ -1079,7 +1077,7 @@ export default {
1079
1077
  .user-name {
1080
1078
  display: flex;
1081
1079
  align-items: center;
1082
- color: var(--secondary);
1080
+ color: var(--body-text, var(--secondary));
1083
1081
  }
1084
1082
 
1085
1083
  .user-menu {
@@ -1069,7 +1069,7 @@ export default {
1069
1069
  &.ns-selected:not(:hover) {
1070
1070
  .ns-item {
1071
1071
  > * {
1072
- color: var(--primary);
1072
+ color: var(--link);
1073
1073
  }
1074
1074
  }
1075
1075
 
@@ -139,12 +139,6 @@ export abstract class BaseTopLevelMenuHelper {
139
139
  this.$store = $store;
140
140
 
141
141
  this.hasProvCluster = this.$store.getters[`management/schemaFor`](CAPI.RANCHER_CLUSTER);
142
-
143
- // Reduce flicker when component is recreated on a different layout
144
- const { clustersPinned = [], clustersOthers = [] } = this.$store.getters['sideNavCache'] || {};
145
-
146
- this.clustersPinned.push(...clustersPinned);
147
- this.clustersOthers.push(...clustersOthers);
148
142
  }
149
143
 
150
144
  protected convertToCluster(mgmtCluster: MgmtCluster, provCluster: ProvCluster): TopLevelMenuCluster {
@@ -163,10 +157,6 @@ export abstract class BaseTopLevelMenuHelper {
163
157
  clusterRoute: { name: 'c-cluster-explorer', params: { cluster: mgmtCluster.id } }
164
158
  };
165
159
  }
166
-
167
- protected cacheClusters() {
168
- this.$store.dispatch('setSideNavCache', { clustersPinned: this.clustersPinned, clustersOthers: this.clustersOthers });
169
- }
170
160
  }
171
161
 
172
162
  /**
@@ -202,9 +192,9 @@ export class TopLevelMenuHelperPagination extends BaseTopLevelMenuHelper impleme
202
192
  this.clustersOthersWrapper = new PaginationWrapper({
203
193
  $store,
204
194
  id: 'tlm-unpinned-clusters',
205
- onChange: () => {
195
+ onChange: async() => {
206
196
  if (this.args) {
207
- this.update(this.args);
197
+ await this.update(this.args);
208
198
  }
209
199
  },
210
200
  enabledFor: {
@@ -220,9 +210,9 @@ export class TopLevelMenuHelperPagination extends BaseTopLevelMenuHelper impleme
220
210
  this.provClusterWrapper = new PaginationWrapper({
221
211
  $store,
222
212
  id: 'tlm-prov-clusters',
223
- onChange: () => {
213
+ onChange: async() => {
224
214
  if (this.args) {
225
- this.update(this.args);
215
+ await this.update(this.args);
226
216
  }
227
217
  },
228
218
  enabledFor: {
@@ -276,8 +266,6 @@ export class TopLevelMenuHelperPagination extends BaseTopLevelMenuHelper impleme
276
266
 
277
267
  this.clustersPinned.push(..._clustersPinned);
278
268
  this.clustersOthers.push(..._clustersNotPinned);
279
-
280
- this.cacheClusters();
281
269
  }
282
270
 
283
271
  async destroy() {
@@ -390,7 +378,6 @@ export class TopLevelMenuHelperPagination extends BaseTopLevelMenuHelper impleme
390
378
  private async updateProvCluster(notPinned: MgmtCluster[], pinned: MgmtCluster[]): Promise<ProvCluster[]> {
391
379
  return this.provClusterWrapper.request({
392
380
  pagination: {
393
-
394
381
  filters: [
395
382
  PaginationParamFilter.createMultipleFields(
396
383
  [...notPinned, ...pinned]
@@ -399,7 +386,6 @@ export class TopLevelMenuHelperPagination extends BaseTopLevelMenuHelper impleme
399
386
  }))
400
387
  )
401
388
  ],
402
-
403
389
  page: 1,
404
390
  sort: [],
405
391
  projectsOrNamespaces: []
@@ -432,8 +418,6 @@ export class TopLevelMenuHelperLegacy extends BaseTopLevelMenuHelper implements
432
418
 
433
419
  this.clustersPinned.push(..._clustersPinned);
434
420
  this.clustersOthers.push(..._clustersNotPinned);
435
-
436
- this.cacheClusters();
437
421
  }
438
422
 
439
423
  async destroy() {
@@ -581,3 +565,46 @@ export class TopLevelMenuHelperLegacy extends BaseTopLevelMenuHelper implements
581
565
  return sorted;
582
566
  }
583
567
  }
568
+
569
+ /**
570
+ * Retain state of the side nav, no matter when the TopLevelMenu component is created/deleted (on layout change)
571
+ *
572
+ * This means there's no flickering when the user changes pages and the side nav component re-renders
573
+ *
574
+ * Also it means we're not unwatching then watching the clusters
575
+ */
576
+ class TopLevelMenuHelperService {
577
+ private _helper?: TopLevelMenuHelper;
578
+ public init($store: VuexStore) {
579
+ if (this._helper) {
580
+ return;
581
+ }
582
+
583
+ const canPagination = $store.getters[`management/paginationEnabled`]({
584
+ id: MANAGEMENT.CLUSTER,
585
+ context: 'side-bar',
586
+ }) && $store.getters[`management/paginationEnabled`]({
587
+ id: CAPI.RANCHER_CLUSTER,
588
+ context: 'side-bar',
589
+ });
590
+
591
+ this._helper = canPagination ? new TopLevelMenuHelperPagination({ $store }) : new TopLevelMenuHelperLegacy({ $store });
592
+ }
593
+
594
+ public async reset() {
595
+ await this._helper?.destroy();
596
+ delete this._helper;
597
+ }
598
+
599
+ get helper(): TopLevelMenuHelper {
600
+ if (!this._helper) {
601
+ throw new Error('Unable to use the side nav cluster helper (not initialised)');
602
+ }
603
+
604
+ return this._helper;
605
+ }
606
+ }
607
+
608
+ const instance = new TopLevelMenuHelperService();
609
+
610
+ export default instance;
@@ -14,7 +14,7 @@ import { SETTING } from '@shell/config/settings';
14
14
  import { getProductFromRoute } from '@shell/utils/router';
15
15
  import { isRancherPrime } from '@shell/config/version';
16
16
  import Pinned from '@shell/components/nav/Pinned';
17
- import { TopLevelMenuHelperPagination, TopLevelMenuHelperLegacy } from '@shell/components/nav/TopLevelMenu.helper';
17
+ import sideNavService from '@shell/components/nav/TopLevelMenu.helper';
18
18
  import { debounce } from 'lodash';
19
19
  import { sameContents } from '@shell/utils/array';
20
20
 
@@ -27,6 +27,8 @@ export default {
27
27
  },
28
28
 
29
29
  data() {
30
+ sideNavService.init(this.$store);
31
+
30
32
  const { displayVersion, fullVersion } = getVersionInfo(this.$store);
31
33
  const hasProvCluster = this.$store.getters[`management/schemaFor`](CAPI.RANCHER_CLUSTER);
32
34
 
@@ -37,7 +39,7 @@ export default {
37
39
  id: CAPI.RANCHER_CLUSTER,
38
40
  context: 'side-bar',
39
41
  });
40
- const helper = canPagination ? new TopLevelMenuHelperPagination({ $store: this.$store }) : new TopLevelMenuHelperLegacy({ $store: this.$store });
42
+ const helper = sideNavService.helper;
41
43
  const provClusters = !canPagination && hasProvCluster ? this.$store.getters[`management/all`](CAPI.RANCHER_CLUSTER) : [];
42
44
  const mgmtClusters = !canPagination ? this.$store.getters[`management/all`](MANAGEMENT.CLUSTER) : [];
43
45
 
@@ -327,7 +329,6 @@ export default {
327
329
 
328
330
  beforeUnmount() {
329
331
  document.removeEventListener('keyup', this.handler);
330
- this.helper?.destroy();
331
332
  },
332
333
 
333
334
  methods: {
@@ -1073,6 +1074,14 @@ export default {
1073
1074
  width: 300px;
1074
1075
  overflow: auto;
1075
1076
 
1077
+ & .category {
1078
+ & a.router-link-active {
1079
+ &:hover {
1080
+ color: var(--on-active, var(--default));
1081
+ }
1082
+ }
1083
+ }
1084
+
1076
1085
  .option {
1077
1086
  align-items: center;
1078
1087
  cursor: pointer;
@@ -1119,6 +1128,15 @@ export default {
1119
1128
  }
1120
1129
  }
1121
1130
 
1131
+ &:not(.active-menu-link) {
1132
+ &:hover {
1133
+ .pin {
1134
+ display: block;
1135
+ color: var(--body-text-hover);
1136
+ }
1137
+ }
1138
+ }
1139
+
1122
1140
  &:hover {
1123
1141
  text-decoration: none;
1124
1142
 
@@ -1178,19 +1196,31 @@ export default {
1178
1196
  outline-offset: -4px;
1179
1197
  }
1180
1198
 
1181
- background: var(--primary-hover-bg);
1182
- color: var(--primary-hover-text);
1199
+ background: var(--active-nav, var(--primary-hover-bg));
1200
+ color: var(--on-active, var(--primary-hover-text));
1183
1201
 
1184
1202
  svg {
1185
- fill: var(--primary-hover-text);
1203
+ fill: var(--on-active, var(--primary-hover-text));
1186
1204
  }
1187
1205
 
1188
1206
  i {
1189
- color: var(--primary-hover-text);
1207
+ color: var(--on-active, var(--primary-hover-text));
1190
1208
  }
1191
1209
 
1192
1210
  div .description {
1193
- color: var(--default);
1211
+ color: var(--on-active, var(--default));
1212
+ }
1213
+
1214
+ &:hover {
1215
+ background: var(--active-hover, var(--primary-hover-bg));
1216
+
1217
+ div {
1218
+ color: var(--on-active, var(--default));
1219
+ }
1220
+
1221
+ svg {
1222
+ fill: var(--on-active, var(--primary-hover-text));
1223
+ }
1194
1224
  }
1195
1225
  }
1196
1226
 
@@ -1201,8 +1231,8 @@ export default {
1201
1231
  }
1202
1232
 
1203
1233
  &:hover {
1204
- color: var(--primary-hover-text);
1205
- background: var(--primary-hover-bg);
1234
+ color: var(--tertiary-hover-app-bar, var(--primary-hover-text));
1235
+ background: var(--nav-hover-top-level, var(--primary-hover-bg));
1206
1236
  > div {
1207
1237
  color: var(--primary-hover-text);
1208
1238
 
@@ -1211,10 +1241,10 @@ export default {
1211
1241
  }
1212
1242
  }
1213
1243
  svg {
1214
- fill: var(--primary-hover-text);
1244
+ fill: var(--tertiary-hover-app-bar, var(--primary-hover-text));
1215
1245
  }
1216
1246
  div {
1217
- color: var(--primary-hover-text);
1247
+ color: var(--tertiary-hover-app-bar, var(--primary-hover-text));
1218
1248
  }
1219
1249
  &.disabled {
1220
1250
  background: transparent;
@@ -1549,8 +1579,8 @@ export default {
1549
1579
  overflow: hidden;
1550
1580
  & IMG {
1551
1581
  object-fit: contain;
1552
- height: 21px;
1553
1582
  max-width: 200px;
1583
+ height: 36px;
1554
1584
  }
1555
1585
  }
1556
1586
 
@@ -1592,7 +1622,7 @@ export default {
1592
1622
  padding: 8px 20px;
1593
1623
 
1594
1624
  &:hover {
1595
- background-color: var(--primary-hover-bg);
1625
+ background-color: var(--active-hover, var(--primary-hover-bg));
1596
1626
  color: var(--primary-hover-text);
1597
1627
  text-decoration: none;
1598
1628
  }
@@ -249,12 +249,7 @@ export default {
249
249
  height: 33px;
250
250
 
251
251
  &:hover {
252
- background: var(--nav-hover);
253
252
  text-decoration: none;
254
-
255
- :deep() .icon {
256
- color: var(--body-text);
257
- }
258
253
  }
259
254
  }
260
255
 
@@ -3,6 +3,7 @@ import { mount, Wrapper } from '@vue/test-utils';
3
3
  import { CAPI, COUNT, MANAGEMENT } from '@shell/config/types';
4
4
  import { PINNED_CLUSTERS } from '@shell/store/prefs';
5
5
  import { nextTick } from 'vue';
6
+ import sideNavService from '@shell/components/nav/TopLevelMenu.helper';
6
7
 
7
8
  /**
8
9
  * `clusters` doubles up as both mgmt and prov clusters (don't shoot the messenger)
@@ -53,6 +54,7 @@ const waitForIt = async() => {
53
54
  describe('topLevelMenu', () => {
54
55
  beforeEach(() => {
55
56
  jest.useFakeTimers();
57
+ sideNavService.reset();
56
58
  });
57
59
 
58
60
  afterEach(() => {
@@ -3,7 +3,8 @@ import {
3
3
  STATE, NAME as NAME_COL, NAMESPACE as NAMESPACE_COL, AGE, OBJECT,
4
4
  EVENT_LAST_SEEN_TIME,
5
5
  EVENT_TYPE,
6
- SECRET_CLONE
6
+ SECRET_CLONE,
7
+ EVENT_FIRST_SEEN_TIME
7
8
  } from '@shell/config/table-headers';
8
9
 
9
10
  // This file contains table headers
@@ -56,10 +57,17 @@ export const STEVE_EVENT_OBJECT = {
56
57
  search: 'involvedObject.kind',
57
58
  };
58
59
 
60
+ export const STEVE_EVENT_FIRST_SEEN = {
61
+ ...EVENT_FIRST_SEEN_TIME,
62
+
63
+ value: 'metadata.fields.7',
64
+ sort: 'metadata.fields.7:desc',
65
+ };
66
+
59
67
  export const STEVE_EVENT_LAST_SEEN = {
60
68
  ...EVENT_LAST_SEEN_TIME,
61
69
  value: 'metadata.fields.0',
62
- sort: 'metadata.fields.0',
70
+ sort: 'metadata.fields.0:desc',
63
71
  };
64
72
 
65
73
  export const STEVE_EVENT_TYPE = {
@@ -22,11 +22,12 @@ import {
22
22
  ACCESS_KEY, DESCRIPTION, EXPIRES, EXPIRY_STATE, LAST_USED, SUB_TYPE, AGE_NORMAN, SCOPE_NORMAN, PERSISTENT_VOLUME_CLAIM, RECLAIM_POLICY, PV_REASON, WORKLOAD_HEALTH_SCALE, POD_RESTARTS,
23
23
  DURATION, MESSAGE, REASON, EVENT_TYPE, OBJECT, ROLE, ROLES, VERSION, INTERNAL_EXTERNAL_IP, KUBE_NODE_OS, CPU, RAM, SECRET_DATA,
24
24
  EVENT_LAST_SEEN_TIME,
25
+ EVENT_FIRST_SEEN_TIME,
25
26
  } from '@shell/config/table-headers';
26
27
 
27
28
  import { DSL } from '@shell/store/type-map';
28
29
  import {
29
- STEVE_AGE_COL, STEVE_EVENT_LAST_SEEN, STEVE_EVENT_OBJECT, STEVE_EVENT_TYPE, STEVE_LIST_GROUPS, STEVE_NAMESPACE_COL, STEVE_NAME_COL, STEVE_STATE_COL
30
+ STEVE_AGE_COL, STEVE_EVENT_FIRST_SEEN, STEVE_EVENT_LAST_SEEN, STEVE_EVENT_OBJECT, STEVE_EVENT_TYPE, STEVE_LIST_GROUPS, STEVE_NAMESPACE_COL, STEVE_NAME_COL, STEVE_STATE_COL
30
31
  } from '@shell/config/pagination-table-headers';
31
32
 
32
33
  import { COLUMN_BREAKPOINTS } from '@shell/types/store/type-map';
@@ -294,7 +295,7 @@ export function init(store) {
294
295
  STEVE_NAMESPACE_COL,
295
296
  {
296
297
  ...INGRESS_TARGET,
297
- sort: 'spec.rules[0].host', // Pending API Support - BUG - https://github.com/rancher/rancher/issues/50526
298
+ sort: 'spec.rules[0].host',
298
299
  search: false, // This is broken in normal world, so disable here
299
300
  },
300
301
  {
@@ -337,7 +338,7 @@ export function init(store) {
337
338
  );
338
339
 
339
340
  headers(EVENT,
340
- [STATE, EVENT_LAST_SEEN_TIME, EVENT_TYPE, REASON, OBJECT, 'Subobject', 'Source', MESSAGE, 'First Seen', 'Count', NAME_COL, NAMESPACE_COL],
341
+ [STATE, EVENT_LAST_SEEN_TIME, EVENT_TYPE, REASON, OBJECT, 'Subobject', 'Source', MESSAGE, EVENT_FIRST_SEEN_TIME, 'Count', NAME_COL, NAMESPACE_COL],
341
342
  [
342
343
  STEVE_STATE_COL,
343
344
  STEVE_EVENT_LAST_SEEN,
@@ -347,7 +348,7 @@ export function init(store) {
347
348
  'Subobject',
348
349
  'Source',
349
350
  MESSAGE,
350
- 'First Seen',
351
+ STEVE_EVENT_FIRST_SEEN,
351
352
  'Count',
352
353
  STEVE_NAME_COL,
353
354
  STEVE_NAMESPACE_COL,
@@ -359,10 +360,10 @@ export function init(store) {
359
360
  STEVE_STATE_COL,
360
361
  STEVE_NAME_COL,
361
362
  STEVE_NAMESPACE_COL,
362
- HPA_REFERENCE, // Pending API Support - BUG - https://github.com/rancher/rancher/issues/50527
363
- MIN_REPLICA, // Pending API Support - BUG - https://github.com/rancher/rancher/issues/50527
364
- MAX_REPLICA, // Pending API Support - BUG - https://github.com/rancher/rancher/issues/50527
365
- CURRENT_REPLICA, // Pending API Support - BUG - https://github.com/rancher/rancher/issues/50527
363
+ HPA_REFERENCE,
364
+ MIN_REPLICA,
365
+ MAX_REPLICA,
366
+ CURRENT_REPLICA,
366
367
  STEVE_AGE_COL
367
368
  ]
368
369
  );
@@ -541,6 +541,15 @@ export const LAST_SEEN_TIME = {
541
541
  tooltip: 'tableHeaders.lastSeenTooltip'
542
542
  };
543
543
 
544
+ export const EVENT_FIRST_SEEN_TIME = {
545
+ name: 'firstSeen',
546
+ labelKey: 'tableHeaders.firstSeen',
547
+ tooltip: 'tableHeaders.firstSeenTooltip',
548
+
549
+ value: 'firstSeen',
550
+ sort: 'firstSeen:desc',
551
+ };
552
+
544
553
  export const EVENT_LAST_SEEN_TIME = {
545
554
  ...LAST_SEEN_TIME,
546
555
  defaultSort: true,
@@ -107,7 +107,7 @@ export function uiPluginAnnotation(chart, name) {
107
107
  /**
108
108
  * Parse the Rancher version string
109
109
  */
110
- function parseRancherVersion(v) {
110
+ export function parseRancherVersion(v) {
111
111
  let parsedVersion = semver.coerce(v)?.version;
112
112
  const splitArr = parsedVersion?.split('.');
113
113
 
package/core/plugin.ts CHANGED
@@ -16,24 +16,32 @@ import {
16
16
  ModelExtensionConstructor,
17
17
  PluginRouteRecordRaw, RegisterStore, UnregisterStore, CoreStoreSpecifics, CoreStoreConfig,
18
18
  NavHooks, OnNavToPackage, OnNavAwayFromPackage, OnLogIn, OnLogOut,
19
- ExtensionEnvironment
19
+ PaginationTableColumn,
20
+ ExtensionEnvironment,
21
+ ServerSidePaginationExtensionConfig
20
22
  } from './types';
21
23
  import coreStore, { coreStoreModule, coreStoreState } from '@shell/plugins/dashboard-store';
22
24
  import { defineAsyncComponent, markRaw, Component } from 'vue';
23
25
  import { getVersionData, CURRENT_RANCHER_VERSION } from '@shell/config/version';
26
+ import { ExtensionManagerTypes } from '@shell/types/extension-manager';
24
27
 
25
- // Registration IDs used for different extension points in the extensions catalog
28
+ /** Registration IDs used for different extension points in the extensions catalog */
26
29
  export const EXT_IDS = {
27
- MODELS: 'models',
28
- MODEL_EXTENSION: 'model-extension',
29
- };
30
+ MODELS: 'models',
31
+ MODEL_EXTENSION: 'model-extension',
32
+ /**
33
+ * Extension can provide resources that use server-side-pagination
34
+ */
35
+ SERVER_SIDE_PAGINATION_RESOURCES: 'server-side-pagination',
36
+ } as const;
37
+ export type EXT_IDS_VALUES = (typeof EXT_IDS)[keyof typeof EXT_IDS];
30
38
 
31
39
  export type ProductFunction = (plugin: IPlugin, store: any) => void;
32
40
 
33
41
  export class Plugin implements IPlugin {
34
42
  public id: string;
35
43
  public name: string;
36
- public types: any = {};
44
+ public types: ExtensionManagerTypes = {};
37
45
  public l10n: { [key: string]: Function[] } = {};
38
46
  public modelExtensions: { [key: string]: Function[] } = {};
39
47
  public locales: { locale: string, label: string}[] = [];
@@ -247,10 +255,21 @@ export class Plugin implements IPlugin {
247
255
  }
248
256
 
249
257
  /**
250
- * Adds a new column to a table on the UI
258
+ * Adds a new column to a ResourceTable
259
+ *
260
+ * @param where
261
+ * @param when
262
+ * @param action
263
+ * @param column
264
+ * The information required to show a header and values for a column in a table
265
+ * @param paginationColumn
266
+ * As per `column`, but is used where server-side pagination is enabled
251
267
  */
252
- addTableColumn(where: string, when: LocationConfig | string, column: TableColumn): void {
253
- this._addUIConfig(ExtensionPoint.TABLE_COL, where, when, column);
268
+ addTableColumn(where: string, when: LocationConfig | string, column: TableColumn, paginationColumn?: PaginationTableColumn): void {
269
+ this._addUIConfig(ExtensionPoint.TABLE_COL, where, when, {
270
+ column,
271
+ paginationColumn
272
+ });
254
273
  }
255
274
 
256
275
  setHomePage(component: any) {
@@ -348,6 +367,11 @@ export class Plugin implements IPlugin {
348
367
  }
349
368
  }
350
369
 
370
+ public enableServerSidePagination(config: ServerSidePaginationExtensionConfig) {
371
+ console.info(`Extension "${ this.name || this.id }" is enabling server-side pagination for some resources`, config); // eslint-disable-line no-console
372
+ this.register(EXT_IDS.SERVER_SIDE_PAGINATION_RESOURCES, this.id, () => config);
373
+ }
374
+
351
375
  public async onLogOut(store: any) {
352
376
  await Promise.all(this.stores.map((s: any) => store.dispatch(`${ s.storeName }/onLogout`)));
353
377