@rancher/shell 0.3.1 → 0.3.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 (44) hide show
  1. package/assets/styles/global/_gauges.scss +1 -1
  2. package/assets/styles/global/_layout.scss +4 -0
  3. package/assets/styles/themes/_dark.scss +1 -0
  4. package/assets/translations/en-us.yaml +4 -0
  5. package/assets/translations/zh-hans.yaml +175 -44
  6. package/components/ActionMenu.vue +28 -7
  7. package/components/DetailTop.vue +14 -1
  8. package/components/ExtensionPanel.vue +42 -0
  9. package/components/IconOrSvg.vue +31 -2
  10. package/components/ResourceDetail/Masthead.vue +16 -3
  11. package/components/ResourceList/index.vue +15 -2
  12. package/components/ResourceTable.vue +3 -1
  13. package/components/SortableTable/THead.vue +6 -9
  14. package/components/SortableTable/filtering.js +1 -1
  15. package/components/SortableTable/selection.js +15 -3
  16. package/components/Tabbed/Tab.vue +1 -1
  17. package/components/form/ResourceTabs/index.vue +23 -0
  18. package/components/nav/Header.vue +69 -5
  19. package/config/product/backup.js +1 -1
  20. package/config/query-params.js +1 -0
  21. package/config/uiplugins.js +3 -3
  22. package/core/plugin-helpers.js +171 -0
  23. package/core/plugin.ts +61 -1
  24. package/core/plugins.js +33 -0
  25. package/core/types.ts +128 -2
  26. package/edit/catalog.cattle.io.clusterrepo.vue +3 -0
  27. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +14 -2
  28. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +3 -0
  29. package/edit/provisioning.cattle.io.cluster/rke2.vue +21 -18
  30. package/package.json +1 -1
  31. package/pages/c/_cluster/apps/charts/index.vue +17 -0
  32. package/pages/c/_cluster/explorer/index.vue +39 -0
  33. package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +2 -0
  34. package/pages/c/_cluster/uiplugins/InstallDialog.vue +3 -0
  35. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +8 -1
  36. package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +2 -0
  37. package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +1 -0
  38. package/pages/c/_cluster/uiplugins/UninstallDialog.vue +2 -0
  39. package/pages/c/_cluster/uiplugins/index.vue +14 -1
  40. package/plugins/dashboard-store/resource-class.js +16 -1
  41. package/rancher-components/components/Banner/Banner.vue +1 -0
  42. package/store/action-menu.js +4 -3
  43. package/store/type-map.js +26 -0
  44. package/types/shell/index.d.ts +1 -0
@@ -40,6 +40,9 @@ import { isEmpty } from '@shell/utils/object';
40
40
  import ConfigBadge from './ConfigBadge';
41
41
  import EventsTable from './EventsTable';
42
42
  import { fetchClusterResources } from './explorer-utils';
43
+ import SimpleBox from '@shell/components/SimpleBox';
44
+ import { ExtensionPoint, CardLocation } from '@shell/core/types';
45
+ import { getApplicableExtensionEnhancements } from '@shell/core/plugin-helpers';
43
46
 
44
47
  export const RESOURCES = [NAMESPACE, INGRESS, PV, WORKLOAD_TYPES.DEPLOYMENT, WORKLOAD_TYPES.STATEFUL_SET, WORKLOAD_TYPES.JOB, WORKLOAD_TYPES.DAEMON_SET, SERVICE];
45
48
 
@@ -71,6 +74,7 @@ export default {
71
74
  EmberPage,
72
75
  ConfigBadge,
73
76
  EventsTable,
77
+ SimpleBox,
74
78
  },
75
79
 
76
80
  mixins: [metricPoller],
@@ -126,6 +130,7 @@ export default {
126
130
  ETCD_METRICS_SUMMARY_URL,
127
131
  clusterCounts,
128
132
  selectedTab: 'cluster-events',
133
+ extensionCards: getApplicableExtensionEnhancements(this, ExtensionPoint.CARD, CardLocation.CLUSTER_DASHBOARD_CARD, this.$route),
129
134
  };
130
135
  },
131
136
 
@@ -492,6 +497,27 @@ export default {
492
497
  />
493
498
  </div>
494
499
 
500
+ <!-- extension cards -->
501
+ <div
502
+ v-if="extensionCards.length"
503
+ class="extension-card-container mt-20"
504
+ >
505
+ <SimpleBox
506
+ v-for="item, i in extensionCards"
507
+ :key="`extensionCards${i}`"
508
+ class="extension-card"
509
+ :style="item.style"
510
+ >
511
+ <h3>
512
+ {{ item.label }}
513
+ </h3>
514
+ <component
515
+ :is="item.component"
516
+ :resource="currentCluster"
517
+ />
518
+ </SimpleBox>
519
+ </div>
520
+
495
521
  <h3
496
522
  v-if="!hasV1Monitoring && hasStats"
497
523
  class="mt-40"
@@ -631,6 +657,19 @@ export default {
631
657
  </template>
632
658
 
633
659
  <style lang="scss" scoped>
660
+ .extension-card-container {
661
+ display: grid;
662
+ grid-template-columns: repeat(auto-fit, minmax(calc((100%/3) - 40px), 1fr));
663
+ grid-column-gap: 15px;
664
+ grid-row-gap: 20px;
665
+ }
666
+
667
+ @media only screen and (max-width: map-get($breakpoints, "--viewport-9")) {
668
+ .extension-card-container {
669
+ grid-template-columns: 1fr !important;
670
+ }
671
+ }
672
+
634
673
  .cluster-dashboard-glance {
635
674
  border-top: 1px solid var(--border);
636
675
  border-bottom: 1px solid var(--border);
@@ -181,12 +181,14 @@ export default {
181
181
  <div class="dialog-buttons mt-20">
182
182
  <button
183
183
  class="btn role-secondary"
184
+ data-testid="dev-install-ext-modal-cancel-btn"
184
185
  @click="closeDialog()"
185
186
  >
186
187
  {{ t('generic.cancel') }}
187
188
  </button>
188
189
  <AsyncButton
189
190
  mode="load"
191
+ data-testid="dev-install-ext-modal-install-btn"
190
192
  @click="loadPlugin"
191
193
  />
192
194
  </div>
@@ -243,6 +243,7 @@ export default {
243
243
  label-key="plugins.install.version"
244
244
  :options="versionOptions"
245
245
  class="version-selector mt-10"
246
+ data-testid="install-ext-modal-select-version"
246
247
  />
247
248
  <div v-else>
248
249
  {{ t('plugins.install.version') }} {{ version }}
@@ -252,12 +253,14 @@ export default {
252
253
  <button
253
254
  :disabled="busy"
254
255
  class="btn role-secondary"
256
+ data-testid="install-ext-modal-cancel-btn"
255
257
  @click="closeDialog(false)"
256
258
  >
257
259
  {{ t('generic.cancel') }}
258
260
  </button>
259
261
  <AsyncButton
260
262
  :mode="buttonMode"
263
+ data-testid="install-ext-modal-install-btn"
261
264
  @click="install"
262
265
  />
263
266
  </div>
@@ -113,10 +113,12 @@ export default {
113
113
  <div
114
114
  v-if="showSlideIn"
115
115
  class="glass"
116
+ data-testid="extension-details-bg"
116
117
  @click="hide()"
117
118
  />
118
119
  <div
119
120
  class="slideIn"
121
+ data-testid="extension-details"
120
122
  :class="{'hide': false, 'slideIn__show': showSlideIn}"
121
123
  >
122
124
  <div
@@ -142,7 +144,10 @@ export default {
142
144
  >
143
145
  </div>
144
146
  <div class="plugin-title">
145
- <h2 class="slideIn__header">
147
+ <h2
148
+ class="slideIn__header"
149
+ data-testid="extension-details-title"
150
+ >
146
151
  {{ info.name }}
147
152
  </h2>
148
153
  <p class="plugin-description">
@@ -153,6 +158,7 @@ export default {
153
158
  <div class="slideIn__header__buttons">
154
159
  <div
155
160
  class="slideIn__header__button"
161
+ data-testid="extension-details-close"
156
162
  @click="showSlideIn = false"
157
163
  >
158
164
  <i class="icon icon-close" />
@@ -236,6 +242,7 @@ export default {
236
242
  position: fixed;
237
243
  top: 0;
238
244
  left: 0;
245
+ z-index: 1;
239
246
 
240
247
  $slideout-width: 35%;
241
248
  $title-height: 50px;
@@ -107,6 +107,7 @@ export default {
107
107
  name="confirm-uiplugins-remove"
108
108
  :title="t('plugins.setup.remove.title')"
109
109
  mode="disable"
110
+ data-testid="disable-ext-modal"
110
111
  @okay="doRemove"
111
112
  >
112
113
  <template>
@@ -121,6 +122,7 @@ export default {
121
122
  v-model="removeRepo"
122
123
  :primary="true"
123
124
  label-key="plugins.setup.remove.registry.title"
125
+ data-testid="disable-ext-modal-remove-repo"
124
126
  />
125
127
  <div class="checkbox-info">
126
128
  {{ t('plugins.setup.remove.registry.prompt') }}
@@ -214,6 +214,7 @@ export default {
214
214
  :manual="true"
215
215
  :current-phase="buttonState"
216
216
  class="enable-plugin-support"
217
+ data-testid="extension-enable-operator"
217
218
  @click="enable"
218
219
  />
219
220
  </div>
@@ -84,12 +84,14 @@ export default {
84
84
  <button
85
85
  :disabled="busy"
86
86
  class="btn role-secondary"
87
+ data-testid="uninstall-ext-modal-cancel-btn"
87
88
  @click="closeDialog(false)"
88
89
  >
89
90
  {{ t('generic.cancel') }}
90
91
  </button>
91
92
  <AsyncButton
92
93
  mode="uninstall"
94
+ data-testid="uninstall-ext-modal-uninstall-btn"
93
95
  @click="uninstall()"
94
96
  />
95
97
  </div>
@@ -492,10 +492,13 @@ export default {
492
492
  <template>
493
493
  <div class="plugins">
494
494
  <div class="plugin-header">
495
- <h2>{{ t('plugins.title') }}</h2>
495
+ <h2 data-testid="extensions-page-title">
496
+ {{ t('plugins.title') }}
497
+ </h2>
496
498
  <div
497
499
  v-if="reloadRequired"
498
500
  class="plugin-reload-banner mr-20"
501
+ data-testid="extension-reload-banner"
499
502
  >
500
503
  <i class="icon icon-checkmark mr-10" />
501
504
  <span>
@@ -503,6 +506,7 @@ export default {
503
506
  </span>
504
507
  <button
505
508
  class="ml-10 btn btn-sm role-primary"
509
+ data-testid="extension-reload-banner-reload-btn"
506
510
  @click="reload()"
507
511
  >
508
512
  {{ t('generic.reload') }}
@@ -514,6 +518,7 @@ export default {
514
518
  aria-haspopup="true"
515
519
  type="button"
516
520
  class="btn actions role-secondary"
521
+ data-testid="extensions-page-menu"
517
522
  @click="setMenu"
518
523
  >
519
524
  <i class="icon icon-actions" />
@@ -555,15 +560,18 @@ export default {
555
560
  <Tabbed
556
561
  ref="tabs"
557
562
  :tabs-only="true"
563
+ data-testid="extension-tabs"
558
564
  @changed="filterChanged"
559
565
  >
560
566
  <Tab
561
567
  name="installed"
568
+ data-testid="extension-tab-installed"
562
569
  label-key="plugins.tabs.installed"
563
570
  :weight="20"
564
571
  />
565
572
  <Tab
566
573
  name="available"
574
+ data-testid="extension-tab-available"
567
575
  label-key="plugins.tabs.available"
568
576
  :weight="19"
569
577
  />
@@ -606,6 +614,7 @@ export default {
606
614
  v-for="plugin in list"
607
615
  :key="plugin.name"
608
616
  class="plugin"
617
+ :data-testid="`extension-card-${plugin.name}`"
609
618
  @click="showPluginDetail(plugin)"
610
619
  >
611
620
  <div
@@ -709,6 +718,7 @@ export default {
709
718
  <button
710
719
  v-if="!plugin.builtin"
711
720
  class="btn role-secondary"
721
+ :data-testid="`extension-card-uninstall-btn-${plugin.name}`"
712
722
  @click="showUninstallDialog(plugin, $event)"
713
723
  >
714
724
  {{ t('plugins.uninstall.label') }}
@@ -716,6 +726,7 @@ export default {
716
726
  <button
717
727
  v-if="plugin.upgrade"
718
728
  class="btn role-secondary"
729
+ :data-testid="`extension-card-update-btn-${plugin.name}`"
719
730
  @click="showInstallDialog(plugin, 'update', $event)"
720
731
  >
721
732
  {{ t('plugins.update.label') }}
@@ -723,6 +734,7 @@ export default {
723
734
  <button
724
735
  v-if="!plugin.upgrade && plugin.versions.length > 1"
725
736
  class="btn role-secondary"
737
+ :data-testid="`extension-card-rollback-btn-${plugin.name}`"
726
738
  @click="showInstallDialog(plugin, 'rollback', $event)"
727
739
  >
728
740
  {{ t('plugins.rollback.label') }}
@@ -734,6 +746,7 @@ export default {
734
746
  >
735
747
  <button
736
748
  class="btn role-secondary"
749
+ :data-testid="`extension-card-install-btn-${plugin.name}`"
737
750
  @click="showInstallDialog(plugin, 'install', $event)"
738
751
  >
739
752
  {{ t('plugins.install.label') }}
@@ -37,6 +37,9 @@ import Vue from 'vue';
37
37
 
38
38
  import { normalizeType } from './normalize';
39
39
 
40
+ import { ExtensionPoint, ActionLocation } from '@shell/core/types';
41
+ import { getApplicableExtensionEnhancements } from '@shell/core/plugin-helpers';
42
+
40
43
  const STRING_LIKE_TYPES = [
41
44
  'string',
42
45
  'date',
@@ -851,7 +854,11 @@ export default class Resource {
851
854
 
852
855
  // You can add custom actions by overriding your own availableActions (and probably reading super._availableActions)
853
856
  get _availableActions() {
854
- const all = [
857
+ // get menu actions available by plugins configuration
858
+ const currentRoute = this.currentRouter().app._route;
859
+ const extensionMenuActions = getApplicableExtensionEnhancements(this.$rootState, ExtensionPoint.ACTION, ActionLocation.TABLE, currentRoute, this);
860
+
861
+ let all = [
855
862
  { divider: true },
856
863
  {
857
864
  action: this.canUpdate ? 'goToEdit' : 'goToViewConfig',
@@ -899,6 +906,13 @@ export default class Resource {
899
906
  },
900
907
  ];
901
908
 
909
+ // Extension actions get added to the end, so add a divider if there are any
910
+ if (extensionMenuActions.length) {
911
+ // Add a divider first
912
+ all.push({ divider: true });
913
+ all = all.concat(extensionMenuActions);
914
+ }
915
+
902
916
  return all;
903
917
  }
904
918
 
@@ -1051,6 +1065,7 @@ export default class Resource {
1051
1065
  async _save(opt = {}) {
1052
1066
  delete this.__rehydrate;
1053
1067
  delete this.__clone;
1068
+
1054
1069
  const forNew = !this.id;
1055
1070
 
1056
1071
  const errors = await this.validationErrors(this, opt.ignoreFields);
@@ -121,6 +121,7 @@ $icon-size: 24px;
121
121
  margin: 15px 0;
122
122
  position: relative;
123
123
  width: 100%;
124
+ color: var(--body-text);
124
125
 
125
126
  &__icon {
126
127
  width: $icon-size * 2;
@@ -22,9 +22,10 @@ export const state = function() {
22
22
  };
23
23
 
24
24
  export const getters = {
25
- showing: state => state.show,
26
- elem: state => state.elem,
27
- event: state => state.event,
25
+ showing: state => state.show,
26
+ elem: state => state.elem,
27
+ event: state => state.event,
28
+ resources: state => state.resources,
28
29
 
29
30
  options(state) {
30
31
  let selected = state.resources;
package/store/type-map.js CHANGED
@@ -148,6 +148,8 @@ import { sortBy } from '@shell/utils/sort';
148
148
  import { haveV1Monitoring, haveV2Monitoring } from '@shell/utils/monitoring';
149
149
  import { NEU_VECTOR_NAMESPACE } from '@shell/config/product/neuvector';
150
150
 
151
+ import { ExtensionPoint, TableColumnLocation } from '@shell/core/types';
152
+
151
153
  export const NAMESPACED = 'namespaced';
152
154
  export const CLUSTER_LEVEL = 'cluster';
153
155
  export const BOTH = 'both';
@@ -222,6 +224,30 @@ export function DSL(store, product, module = 'type-map') {
222
224
  },
223
225
 
224
226
  headers(type, headers) {
227
+ const extensionCols = store.$plugin.getUIConfig(ExtensionPoint.TABLE_COL, TableColumnLocation.RESOURCE);
228
+
229
+ // Try and insert the columns before the Age column, if that is the last column
230
+ let insertPosition = headers.length;
231
+
232
+ if (headers.length > 0) {
233
+ const lastColumn = headers[headers.length - 1];
234
+
235
+ if (lastColumn?.name === AGE.name) {
236
+ insertPosition--;
237
+ }
238
+ }
239
+
240
+ // adding extension defined cols to the correct header config
241
+ extensionCols.forEach((col) => {
242
+ if (col.locationConfig.resource) {
243
+ col.locationConfig.resource.forEach((resource) => {
244
+ if (resource && type === resource) {
245
+ headers.splice(insertPosition, 0, col);
246
+ }
247
+ });
248
+ }
249
+ });
250
+
225
251
  headers.forEach((header) => {
226
252
  // If on the client, then use the value getter if there is one
227
253
  if (header.getValue) {
@@ -47,6 +47,7 @@ export const MODE: "mode";
47
47
  export const _CREATE: "create";
48
48
  export const _VIEW: "view";
49
49
  export const _EDIT: "edit";
50
+ export const _LIST: "list";
50
51
  export const _CLONE: "clone";
51
52
  export const _STAGE: "stage";
52
53
  export const _IMPORT: "import";