@rancher/shell 0.1.4 → 0.1.21

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 (152) hide show
  1. package/assets/brand/suse/favicon.png +0 -0
  2. package/assets/images/generic-plugin.svg +1 -7
  3. package/assets/translations/en-us.yaml +81 -47
  4. package/components/CommunityLinks.vue +40 -49
  5. package/components/ExplorerProjectsNamespaces.vue +20 -3
  6. package/components/LazyImage.vue +21 -8
  7. package/components/PromptRemove.vue +2 -2
  8. package/components/ResourceList/Masthead.vue +21 -1
  9. package/components/ResourceList/ResourceLoadingIndicator.vue +0 -8
  10. package/components/ResourceList/index.vue +9 -23
  11. package/components/SortableTable/index.vue +13 -10
  12. package/components/Tabbed/index.vue +25 -7
  13. package/components/TypeDescription.vue +10 -1
  14. package/components/fleet/FleetClusters.vue +6 -0
  15. package/components/fleet/FleetRepos.vue +7 -1
  16. package/components/form/Command.vue +5 -0
  17. package/components/form/EnvVars.vue +5 -0
  18. package/components/form/NameNsDescription.vue +3 -1
  19. package/components/form/NodeScheduling.vue +6 -1
  20. package/components/form/PodAffinity.vue +5 -0
  21. package/components/form/ServiceNameSelect.vue +5 -0
  22. package/components/form/ValueFromResource.vue +7 -1
  23. package/components/nav/TopLevelMenu.vue +2 -1
  24. package/config/home-links.js +155 -0
  25. package/config/private-label.js +1 -1
  26. package/config/product/manager.js +0 -2
  27. package/config/product/uiplugins.js +1 -1
  28. package/config/settings.js +3 -1
  29. package/config/uiplugins.js +63 -6
  30. package/config/version.js +17 -0
  31. package/core/plugin.ts +12 -0
  32. package/core/plugins.js +29 -5
  33. package/core/types.ts +6 -0
  34. package/creators/app/{.eslintignore → files/.eslintignore} +0 -0
  35. package/creators/app/{.eslintrc.js → files/.eslintrc.js} +0 -0
  36. package/creators/app/{.vscode → files/.vscode}/settings.json +0 -0
  37. package/creators/app/{babel.config.js → files/babel.config.js} +0 -0
  38. package/creators/app/{nuxt.config.js → files/nuxt.config.js} +0 -0
  39. package/creators/app/{tsconfig.json → files/tsconfig.json} +2 -1
  40. package/creators/app/init +16 -17
  41. package/creators/app/package.json +6 -0
  42. package/creators/pkg/{babel.config.js → files/babel.config.js} +0 -0
  43. package/creators/pkg/{index.ts → files/index.ts} +0 -0
  44. package/creators/pkg/{tsconfig.json → files/tsconfig.json} +13 -12
  45. package/creators/pkg/{vue.config.js → files/vue.config.js} +0 -0
  46. package/creators/pkg/init +1 -1
  47. package/creators/update/init +54 -0
  48. package/creators/update/package.json +20 -0
  49. package/creators/update/upgrade +56 -0
  50. package/creators/update/yarn-error.log +54 -0
  51. package/detail/workload/index.vue +1 -0
  52. package/edit/persistentvolume/index.vue +48 -13
  53. package/edit/persistentvolumeclaim.vue +31 -13
  54. package/edit/provisioning.cattle.io.cluster/rke2.vue +27 -19
  55. package/edit/workload/index.vue +19 -9
  56. package/edit/workload/mixins/workload.js +109 -114
  57. package/edit/workload/storage/index.vue +11 -17
  58. package/edit/workload/storage/persistentVolumeClaim/index.vue +5 -0
  59. package/edit/workload/storage/secret.vue +6 -1
  60. package/list/catalog.cattle.io.app.vue +10 -9
  61. package/list/catalog.cattle.io.clusterrepo.vue +6 -61
  62. package/list/cis.cattle.io.clusterscan.vue +12 -12
  63. package/list/fleet.cattle.io.bundle.vue +33 -28
  64. package/list/fleet.cattle.io.cluster.vue +26 -22
  65. package/list/fleet.cattle.io.clustergroup.vue +6 -0
  66. package/list/fleet.cattle.io.clusterregistrationtoken.vue +28 -24
  67. package/list/fleet.cattle.io.gitrepo.vue +25 -14
  68. package/list/helm.cattle.io.projecthelmchart.vue +52 -33
  69. package/list/logging.banzaicloud.io.clusterflow.vue +7 -12
  70. package/list/logging.banzaicloud.io.flow.vue +7 -14
  71. package/list/management.cattle.io.cluster.vue +26 -15
  72. package/list/management.cattle.io.feature.vue +13 -8
  73. package/list/management.cattle.io.user.vue +38 -19
  74. package/list/monitoring.coreos.com.alertmanagerconfig.vue +8 -15
  75. package/list/namespace.vue +14 -1
  76. package/list/node.vue +13 -16
  77. package/list/persistentvolume.vue +16 -9
  78. package/list/persistentvolumeclaim.vue +5 -8
  79. package/list/provisioning.cattle.io.cluster.vue +34 -8
  80. package/list/service.vue +24 -12
  81. package/list/ui.cattle.io.navlink.vue +6 -0
  82. package/list/workload.vue +2 -2
  83. package/middleware/authenticated.js +6 -0
  84. package/mixins/resource-fetch.js +12 -18
  85. package/mixins/resource-manager.js +126 -0
  86. package/models/catalog.cattle.io.uiplugin.js +4 -0
  87. package/models/pod.js +15 -5
  88. package/models/provisioning.cattle.io.cluster.js +4 -0
  89. package/models/workload.service.js +10 -0
  90. package/nuxt.config.js +2 -1
  91. package/package.json +1 -1
  92. package/pages/auth/login.vue +10 -0
  93. package/pages/auth/verify.vue +9 -0
  94. package/pages/c/_cluster/settings/DefaultLinksEditor.vue +108 -0
  95. package/pages/c/_cluster/settings/links.vue +53 -101
  96. package/pages/c/_cluster/settings/performance.vue +90 -7
  97. package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +3 -3
  98. package/pages/c/_cluster/uiplugins/InstallDialog.vue +71 -20
  99. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +21 -5
  100. package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +2 -7
  101. package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +23 -15
  102. package/pages/c/_cluster/uiplugins/UninstallDialog.vue +11 -4
  103. package/pages/c/_cluster/uiplugins/index.vue +179 -65
  104. package/pages/support/index.vue +31 -142
  105. package/plugins/dashboard-store/actions.js +19 -0
  106. package/plugins/dashboard-store/getters.js +20 -3
  107. package/plugins/dashboard-store/mutations.js +13 -7
  108. package/plugins/plugin.js +18 -15
  109. package/plugins/steve/getters.js +12 -0
  110. package/plugins/version.js +21 -0
  111. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +6 -7
  112. package/rancher-components/components/BadgeState/BadgeState.spec.ts +12 -0
  113. package/rancher-components/components/BadgeState/BadgeState.vue +107 -0
  114. package/rancher-components/components/BadgeState/index.ts +1 -0
  115. package/rancher-components/components/Banner/Banner.test.ts +13 -0
  116. package/rancher-components/components/Banner/Banner.vue +163 -0
  117. package/rancher-components/components/Banner/index.ts +1 -0
  118. package/rancher-components/components/Card/Card.vue +150 -0
  119. package/rancher-components/components/Card/index.ts +1 -0
  120. package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +77 -0
  121. package/rancher-components/components/Form/Checkbox/Checkbox.vue +395 -0
  122. package/rancher-components/components/Form/Checkbox/index.ts +1 -0
  123. package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +29 -0
  124. package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +343 -0
  125. package/rancher-components/components/Form/LabeledInput/index.ts +1 -0
  126. package/rancher-components/components/Form/Radio/RadioButton.vue +270 -0
  127. package/rancher-components/components/Form/Radio/RadioGroup.vue +235 -0
  128. package/rancher-components/components/Form/Radio/index.ts +2 -0
  129. package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +168 -0
  130. package/rancher-components/components/Form/TextArea/index.ts +1 -0
  131. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +107 -0
  132. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +137 -0
  133. package/rancher-components/components/Form/ToggleSwitch/index.ts +1 -0
  134. package/rancher-components/components/Form/index.ts +5 -0
  135. package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +137 -0
  136. package/rancher-components/components/LabeledTooltip/index.ts +1 -0
  137. package/scripts/publish-shell.sh +39 -6
  138. package/scripts/record-deps.js +37 -0
  139. package/scripts/test-plugins-build.sh +8 -5
  140. package/scripts/typegen.sh +84 -0
  141. package/store/auth.js +3 -0
  142. package/store/index.js +12 -3
  143. package/types/shell/index.d.ts +3046 -0
  144. package/utils/favicon.js +8 -2
  145. package/utils/gc/gc-interval.ts +40 -0
  146. package/utils/gc/gc-root-store.js +76 -0
  147. package/utils/gc/gc-route-changed.ts +44 -0
  148. package/utils/gc/gc-types.ts +21 -0
  149. package/utils/gc/gc.ts +282 -0
  150. package/config/footer.js +0 -18
  151. package/creators/pkg/nuxt.config.js +0 -6
  152. package/yarn-error.log +0 -195
@@ -368,16 +368,19 @@ export default {
368
368
  immediate: true
369
369
  },
370
370
 
371
- isManualRefreshLoading(neu, old) {
372
- this.currentPhase = neu ? ASYNC_BUTTON_STATES.WAITING : ASYNC_BUTTON_STATES.ACTION;
373
-
374
- // setTimeout is needed so that this is pushed further back on the JS computing queue
375
- // because nextTick isn't enough to capture the DOM update for the manual refresh only scenario
376
- if (old && !neu) {
377
- this.manualRefreshTimer = setTimeout(() => {
378
- this.watcherUpdateLiveAndDelayed(neu, old);
379
- }, 1000);
380
- }
371
+ isManualRefreshLoading: {
372
+ handler(neu, old) {
373
+ this.currentPhase = neu ? ASYNC_BUTTON_STATES.WAITING : ASYNC_BUTTON_STATES.ACTION;
374
+
375
+ // setTimeout is needed so that this is pushed further back on the JS computing queue
376
+ // because nextTick isn't enough to capture the DOM update for the manual refresh only scenario
377
+ if (old && !neu) {
378
+ this.manualRefreshTimer = setTimeout(() => {
379
+ this.watcherUpdateLiveAndDelayed(neu, old);
380
+ }, 1000);
381
+ }
382
+ },
383
+ immediate: true
381
384
  }
382
385
  },
383
386
 
@@ -40,6 +40,12 @@ export default {
40
40
  default: false,
41
41
  },
42
42
 
43
+ // Remove padding and box-shadow
44
+ flat: {
45
+ type: Boolean,
46
+ default: false,
47
+ },
48
+
43
49
  tabsOnly: {
44
50
  type: Boolean,
45
51
  default: false,
@@ -257,7 +263,13 @@ export default {
257
263
  </ul>
258
264
  <slot name="tab-row-extras" />
259
265
  </ul>
260
- <div :class="{ 'tab-container': !!tabs.length || !!sideTabs, 'no-content': noContent }">
266
+ <div
267
+ :class="{
268
+ 'tab-container': !!tabs.length || !!sideTabs,
269
+ 'no-content': noContent,
270
+ 'tab-container--flat': !!flat,
271
+ }"
272
+ >
261
273
  <slot />
262
274
  </div>
263
275
  </div>
@@ -350,6 +362,15 @@ export default {
350
362
  &.no-content {
351
363
  padding: 0 0 3px 0;
352
364
  }
365
+
366
+ // Example case: Tabbed component within a tabbed component
367
+ &--flat {
368
+ padding: 0;
369
+
370
+ .side-tabs {
371
+ box-shadow: unset;
372
+ }
373
+ }
353
374
  }
354
375
 
355
376
  .tabs-only {
@@ -375,11 +396,6 @@ export default {
375
396
  padding: 20px;
376
397
  }
377
398
 
378
- // Tabbed component within a tabbed component
379
- .tab-container & {
380
- box-shadow: unset;
381
- }
382
-
383
399
  & .tabs {
384
400
  width: $sideways-tabs-width;
385
401
  min-width: $sideways-tabs-width;
@@ -451,7 +467,9 @@ export default {
451
467
  }
452
468
  }
453
469
 
454
- & .tab-container {
470
+ &
471
+
472
+ .tab-container {
455
473
  width: calc(100% - #{$sideways-tabs-width});
456
474
  flex-grow: 1;
457
475
  background-color: var(--body-bg);
@@ -1,7 +1,9 @@
1
1
  <script>
2
+ import { mapGetters } from 'vuex';
2
3
  import { Banner } from '@components/Banner';
3
4
  import { HIDE_DESC, mapPref } from '@shell/store/prefs';
4
5
  import { addObject } from '@shell/utils/array';
6
+ import { CATALOG } from '@shell/config/types';
5
7
 
6
8
  export default {
7
9
  components: { Banner },
@@ -14,10 +16,17 @@ export default {
14
16
  },
15
17
 
16
18
  computed: {
19
+ ...mapGetters(['currentCluster']),
17
20
  hideDescriptions: mapPref(HIDE_DESC),
18
21
 
19
22
  typeDescriptionKey() {
20
- const key = `typeDescription."${ this.resource }"`;
23
+ let key;
24
+
25
+ if (this.resource === CATALOG.CLUSTER_REPO) {
26
+ key = !this.currentCluster || this.currentCluster.isLocal ? 'typeDescription."catalog.cattle.io.clusterrepo.local"' : 'typeDescription."catalog.cattle.io.clusterrepo"';
27
+ } else {
28
+ key = `typeDescription."${ this.resource }"`;
29
+ }
21
30
 
22
31
  if ( this.hideDescriptions.includes(this.resource) || this.hideDescriptions.includes('ALL') ) {
23
32
  return false;
@@ -16,6 +16,11 @@ export default {
16
16
  type: Object,
17
17
  default: null,
18
18
  },
19
+
20
+ loading: {
21
+ type: Boolean,
22
+ default: false,
23
+ },
19
24
  },
20
25
 
21
26
  computed: {
@@ -80,6 +85,7 @@ export default {
80
85
  :schema="schema"
81
86
  :headers="headers"
82
87
  :rows="rows"
88
+ :loading="loading"
83
89
  key-field="_key"
84
90
  v-on="$listeners"
85
91
  >
@@ -28,6 +28,11 @@ export default {
28
28
  type: Object,
29
29
  required: true,
30
30
  },
31
+
32
+ loading: {
33
+ type: Boolean,
34
+ required: false,
35
+ },
31
36
  },
32
37
 
33
38
  computed: {
@@ -89,13 +94,14 @@ export default {
89
94
 
90
95
  <template>
91
96
  <div>
92
- <FleetIntro v-if="noRows" />
97
+ <FleetIntro v-if="noRows && !loading" />
93
98
  <ResourceTable
94
99
  v-if="!noRows"
95
100
  v-bind="$attrs"
96
101
  :schema="schema"
97
102
  :headers="headers"
98
103
  :rows="rows"
104
+ :loading="loading"
99
105
  key-field="_key"
100
106
  v-on="$listeners"
101
107
  >
@@ -36,6 +36,10 @@ export default {
36
36
  return {};
37
37
  },
38
38
  },
39
+ loading: {
40
+ default: false,
41
+ type: Boolean
42
+ },
39
43
  },
40
44
 
41
45
  data() {
@@ -200,6 +204,7 @@ export default {
200
204
  :config-maps="configMaps"
201
205
  :secrets="secrets"
202
206
  :value="value"
207
+ :loading="loading"
203
208
  />
204
209
  </div>
205
210
  </template>
@@ -23,6 +23,10 @@ export default {
23
23
  type: Array,
24
24
  required: true
25
25
  },
26
+ loading: {
27
+ default: false,
28
+ type: Boolean
29
+ },
26
30
  /**
27
31
  * Container spec
28
32
  */
@@ -107,6 +111,7 @@ export default {
107
111
  :all-secrets="secrets"
108
112
  :all-config-maps="configMaps"
109
113
  :mode="mode"
114
+ :loading="loading"
110
115
  @remove="removeRow(i)"
111
116
  @input="updateRow"
112
117
  />
@@ -342,7 +342,7 @@ export default {
342
342
  }
343
343
 
344
344
  if (this.namespaced) {
345
- this.$emit('isNamespaceNew', this.namespaces && !this.namespaces.find(n => n.value === val));
345
+ this.$emit('isNamespaceNew', !val || (this.namespaces && !this.namespaces.find(n => n.value === val)));
346
346
  }
347
347
 
348
348
  if (this.namespaceKey) {
@@ -361,10 +361,12 @@ export default {
361
361
  if (!e || e.value === '') { // The blank value in the dropdown is labeled "Create a New Namespace"
362
362
  this.createNamespace = true;
363
363
  this.$parent.$emit('createNamespace', true);
364
+ this.$emit('isNamespaceNew', true);
364
365
  Vue.nextTick(() => this.$refs.namespace.focus());
365
366
  } else {
366
367
  this.createNamespace = false;
367
368
  this.$parent.$emit('createNamespace', false);
369
+ this.$emit('isNamespaceNew', false);
368
370
  }
369
371
  }
370
372
  },
@@ -31,7 +31,11 @@ export default {
31
31
  mode: {
32
32
  type: String,
33
33
  default: 'create'
34
- }
34
+ },
35
+ loading: {
36
+ default: false,
37
+ type: Boolean
38
+ },
35
39
  },
36
40
 
37
41
  data() {
@@ -177,6 +181,7 @@ export default {
177
181
  :options="nodes || []"
178
182
  :mode="mode"
179
183
  :multiple="false"
184
+ :loading="loading"
180
185
  @input="update"
181
186
  />
182
187
  </div>
@@ -40,6 +40,10 @@ export default {
40
40
  type: Array,
41
41
  default: null
42
42
  },
43
+ loading: {
44
+ default: false,
45
+ type: Boolean
46
+ },
43
47
  },
44
48
 
45
49
  data() {
@@ -305,6 +309,7 @@ export default {
305
309
  :placeholder="t('workload.scheduling.affinity.topologyKey.placeholder')"
306
310
  :options="existingNodeLabels"
307
311
  :disabled="mode==='view'"
312
+ :loading="loading"
308
313
  @input="update"
309
314
  />
310
315
  <LabeledInput
@@ -60,6 +60,10 @@ export default {
60
60
  type: Boolean,
61
61
  default: true,
62
62
  },
63
+ loading: {
64
+ type: Boolean,
65
+ default: false,
66
+ },
63
67
  },
64
68
 
65
69
  data() {
@@ -134,6 +138,7 @@ export default {
134
138
  :option-label="optionLabel"
135
139
  :placement="$attrs.placement ? $attrs.placement : null"
136
140
  :v-bind="$attrs"
141
+ :loading="loading"
137
142
  @input="changeSelected"
138
143
  />
139
144
  <button
@@ -34,7 +34,11 @@ export default {
34
34
  namespaced: {
35
35
  type: Boolean,
36
36
  default: true
37
- }
37
+ },
38
+ loading: {
39
+ default: false,
40
+ type: Boolean
41
+ },
38
42
  },
39
43
 
40
44
  data() {
@@ -300,6 +304,7 @@ export default {
300
304
  :get-option-key="opt=>opt.id|| opt"
301
305
  :mode="mode"
302
306
  :label="sourceLabel"
307
+ :loading="loading"
303
308
  />
304
309
  </div>
305
310
  <div v-if="type!=='secretRef' && type!== 'configMapRef'">
@@ -310,6 +315,7 @@ export default {
310
315
  :mode="mode"
311
316
  option-label="label"
312
317
  :label="t('workload.container.command.fromResource.key.label')"
318
+ :loading="loading"
313
319
  @input="updateRow"
314
320
  />
315
321
  </div>
@@ -12,6 +12,7 @@ import { getVersionInfo } from '@shell/utils/version';
12
12
  import { LEGACY } from '@shell/store/features';
13
13
  import { SETTING } from '@shell/config/settings';
14
14
  import { filterOnlyKubernetesClusters, filterHiddenLocalCluster } from '@shell/utils/cluster';
15
+ import { isRancherPrime } from '@shell/config/version';
15
16
 
16
17
  const UNKNOWN = 'unknown';
17
18
  const UI_VERSION = process.env.VERSION || UNKNOWN;
@@ -162,7 +163,7 @@ export default {
162
163
  },
163
164
 
164
165
  hasSupport() {
165
- return this.$store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.SUPPORTED )?.value === 'true';
166
+ return isRancherPrime() || this.$store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.SUPPORTED )?.value === 'true';
166
167
  },
167
168
  },
168
169
 
@@ -0,0 +1,155 @@
1
+ import { DOCS_BASE } from '@shell/config/private-label';
2
+ import { MANAGEMENT } from '@shell/config/types';
3
+ import { SETTING } from '@shell/config/settings';
4
+ import { allHash } from '@shell/utils/promise';
5
+
6
+ const DEFAULT_LINKS = [
7
+ {
8
+ key: 'docs',
9
+ value: DOCS_BASE,
10
+ enabled: true,
11
+ },
12
+ {
13
+ key: 'forums',
14
+ value: 'https://forums.rancher.com/',
15
+ enabled: true,
16
+ },
17
+ {
18
+ key: 'slack',
19
+ value: 'https://slack.rancher.io/',
20
+ enabled: true,
21
+ },
22
+ {
23
+ key: 'issues',
24
+ value: 'https://github.com/rancher/dashboard/issues/new/choose',
25
+ enabled: true,
26
+ },
27
+ {
28
+ key: 'getStarted',
29
+ value: '/docs/getting-started',
30
+ enabled: true,
31
+ },
32
+ ];
33
+
34
+ const SUPPORT_LINK = {
35
+ key: 'commercialSupport',
36
+ value: '/support',
37
+ enabled: true,
38
+ readonly: true
39
+ };
40
+
41
+ // We add a version attribute to the setting so we know what has been migrated and which version of the setting we have
42
+ export const CUSTOM_LINKS_VERSION = 'v1';
43
+
44
+ // Fetch the settings required for the links, taking into account legacy settings if we have not migrated
45
+ export async function fetchLinks(store, hasSupport, isSupportPage, t) {
46
+ let uiLinks = {};
47
+
48
+ try {
49
+ const uiLinksSetting = await store.dispatch('management/find', { type: MANAGEMENT.SETTING, id: SETTING.UI_CUSTOM_LINKS });
50
+
51
+ uiLinks = JSON.parse(uiLinksSetting.value);
52
+ } catch (e) {
53
+ console.warn('Could not parse custom link settings', e); // eslint-disable-line no-console
54
+ }
55
+
56
+ // If uiLinks is set and has the correct version, then we are okay, otherwise we need to migrate from the old settings
57
+ if (uiLinks?.version === CUSTOM_LINKS_VERSION) {
58
+ // Map out the default settings, as we only store keys of the ones to show
59
+ if (uiLinks.defaults) {
60
+ const defaults = [...DEFAULT_LINKS];
61
+
62
+ // Map the link name stored to the default link, if it exists
63
+ defaults.forEach((link) => {
64
+ const enabled = uiLinks.defaults.find(linkName => linkName === link.key);
65
+
66
+ link.enabled = !!enabled;
67
+ });
68
+
69
+ uiLinks.defaults = defaults;
70
+ }
71
+
72
+ return ensureSupportLink(uiLinks, hasSupport, isSupportPage, t);
73
+ }
74
+
75
+ // No new setting, so return the required structure
76
+ // We don't migrate here, as we may not have permissions to create the setting
77
+ const links = {
78
+ version: CUSTOM_LINKS_VERSION,
79
+ defaults: [...DEFAULT_LINKS],
80
+ custom: []
81
+ };
82
+
83
+ // There are two legacy settings:
84
+ // SETTING.ISSUES - can specify a custom link to use for 'File an issue'
85
+ // SETTING.COMMUNITY_LINKS - can specify whether to hide all of the default links (other than 'File an issue')
86
+ try {
87
+ const { uiIssuesSetting, uiCommunitySetting } = await allHash({
88
+ uiIssuesSetting: store.dispatch('management/find', { type: MANAGEMENT.SETTING, id: SETTING.ISSUES }),
89
+ uiCommunitySetting: store.dispatch('management/find', { type: MANAGEMENT.SETTING, id: SETTING.COMMUNITY_LINKS })
90
+ });
91
+
92
+ // Should we show the default set of links?
93
+ if (uiCommunitySetting?.value === 'false') {
94
+ // Hide all of the default links
95
+ links.defaults.forEach(link => (link.enabled = false));
96
+ }
97
+
98
+ // Do we have a custom 'File an issue' link ?
99
+ if (uiIssuesSetting?.value) {
100
+ links.custom.push({
101
+ label: t ? t('customLinks.defaults.issues') : 'Issues',
102
+ value: uiIssuesSetting.value
103
+ });
104
+
105
+ // Hide the default 'File an issue' link
106
+ const issueLink = links.defaults?.find(link => link.key === 'issues');
107
+
108
+ if (issueLink) {
109
+ issueLink.enabled = false;
110
+ issueLink.readOnly = true;
111
+ }
112
+ }
113
+ } catch (e) {
114
+ console.warn('Could not parse legacy link settings', e); // eslint-disable-line no-console
115
+ }
116
+
117
+ return ensureSupportLink(links, hasSupport, isSupportPage, t);
118
+ }
119
+
120
+ // Ensure the support link is added if needed
121
+ function ensureSupportLink(links, hasSupport, isSupportPage, t) {
122
+ if (!hasSupport && !isSupportPage) {
123
+ const supportLink = links.defaults?.find(link => link.key === 'commercialSupport');
124
+
125
+ if (!supportLink) {
126
+ links.defaults.push(SUPPORT_LINK);
127
+ }
128
+ }
129
+
130
+ // Localise the default links
131
+ links.defaults = links.defaults.map((link) => {
132
+ return {
133
+ ...link,
134
+ label: t(`'customLinks.defaults.${ link.key }`)
135
+ };
136
+ });
137
+
138
+ // Ensure that if any custom links have the same name as a default link, we use the custom link
139
+ const customNamesMap = links.custom.reduce((linkMap, link) => {
140
+ linkMap[link.label] = link;
141
+
142
+ return linkMap;
143
+ }, {});
144
+
145
+ // If any custom links have the same name as a default link, then hide and mark readonly the default link
146
+ // Main use case if the 'File an Issue' link when migrating the old settings
147
+ links.defaults.forEach((link) => {
148
+ if (customNamesMap[link.label]) {
149
+ link.enabled = false;
150
+ link.readonly = true;
151
+ }
152
+ });
153
+
154
+ return links;
155
+ }
@@ -7,7 +7,7 @@ export const DOCS_BASE = 'https://rancher.com/docs/rancher/v2.6/en';
7
7
 
8
8
  const STANDARD_VENDOR = 'Rancher';
9
9
  const STANDARD_PRODUCT = 'Explorer';
10
- const CUSTOM_VENDOR = { suse: 'SUSE Rancher' };
10
+ const CUSTOM_VENDOR = { suse: 'Rancher Prime' };
11
11
 
12
12
  let mode = STANDARD;
13
13
  let vendor = STANDARD_VENDOR;
@@ -120,8 +120,6 @@ export function init(store) {
120
120
  weightType(CAPI.MACHINE, 1, true);
121
121
  weightType(CATALOG.CLUSTER_REPO, 0, true);
122
122
 
123
- configureType(CATALOG.CLUSTER_REPO, { showListMasthead: false });
124
-
125
123
  basicType([
126
124
  CAPI.MACHINE_DEPLOYMENT,
127
125
  CAPI.MACHINE_SET,
@@ -9,7 +9,7 @@ export function init(store) {
9
9
  product({
10
10
  ifHave: IF_HAVE.ADMIN, // Only admins can see the UI Plugin Custom Resource by default
11
11
  inStore: 'management',
12
- icon: 'gear',
12
+ icon: 'extension',
13
13
  removable: false,
14
14
  showClusterSwitcher: false,
15
15
  category: 'configuration',
@@ -1,4 +1,5 @@
1
1
  // Settings
2
+ import { GC_DEFAULTS } from '../utils/gc/gc-types';
2
3
  import { MANAGEMENT } from './types';
3
4
 
4
5
  // Adapted from: https://github.com/rancher/ui/blob/08c379a9529f740666a704b52522a468986c3520/lib/shared/addon/utils/constants.js#L564
@@ -105,7 +106,8 @@ export const DEFAULT_PERF_SETTING = {
105
106
  enabled: false,
106
107
  threshold: 1500,
107
108
  },
108
- disableWebsocketNotification: true
109
+ disableWebsocketNotification: true,
110
+ garbageCollection: GC_DEFAULTS
109
111
  };
110
112
 
111
113
  export const fetchOrCreateSetting = async(store, id, val, save = true) => {
@@ -2,6 +2,7 @@ import semver from 'semver';
2
2
 
3
3
  // Version of the plugin API supported
4
4
  export const UI_PLUGIN_API_VERSION = '1.0.0';
5
+ export const UI_PLUGIN_HOST_APP = 'rancher-manager';
5
6
 
6
7
  export const UI_PLUGIN_BASE_URL = '/api/v1/namespaces/cattle-ui-plugin-system/services/http:ui-plugin-operator:80/proxy';
7
8
 
@@ -28,8 +29,19 @@ export const UI_PLUGINS_REPO_NAME = 'rancher-ui-plugins';
28
29
  export const UI_PLUGINS_REPO_URL = 'https://github.com/rancher/ui-plugin-charts';
29
30
  export const UI_PLUGINS_REPO_BRANCH = 'main';
30
31
 
32
+ // Chart annotations
33
+ export const UI_PLUGIN_CHART_ANNOTATIONS = {
34
+ RANCHER_VERSION: 'catalog.cattle.io/rancher-version',
35
+ EXTENSIONS_VERSION: 'catalog.cattle.io/ui-extenstions-version',
36
+ EXTENSIONS_HOST: 'catalog.cattle.io/ui-extenstions-host',
37
+ };
38
+
31
39
  // Plugin Metadata properties
32
- const UI_PLUGIN_METADATA_API_VERSION = 'apiVersion';
40
+ export const UI_PLUGIN_METADATA = {
41
+ RANCHER_VERSION: 'rancherVersion',
42
+ EXTENSION_VERSION: 'extVersion',
43
+ EXTENSIONS_HOST: 'host',
44
+ };
33
45
 
34
46
  export function isUIPlugin(chart) {
35
47
  return !!chart?.versions.find((v) => {
@@ -44,16 +56,61 @@ export function uiPluginHasAnnotation(chart, name, value) {
44
56
  }
45
57
 
46
58
  // Should we load a plugin, based on the metadata returned by the backend?
47
- export function shouldLoadPlugin(plugin) {
59
+ // Returns error key string or false
60
+ export function shouldNotLoadPlugin(plugin, rancherVersion) {
48
61
  if (!plugin.name || !plugin.version || !plugin.endpoint) {
62
+ return 'plugins.error.generic';
63
+ }
64
+
65
+ // Plugin specified a required extension API version
66
+ const requiredAPI = plugin.metadata?.[UI_PLUGIN_METADATA.EXTENSION_VERSION];
67
+
68
+ if (requiredAPI && !semver.satisfies(UI_PLUGIN_API_VERSION, requiredAPI)) {
69
+ return 'plugins.error.api';
70
+ }
71
+
72
+ // Host application
73
+ const requiredHost = plugin.metadata?.[UI_PLUGIN_METADATA.EXTENSIONS_HOST];
74
+
75
+ if (requiredHost && requiredHost !== UI_PLUGIN_HOST_APP) {
76
+ return 'plugins.error.host';
77
+ }
78
+
79
+ // Rancher version
80
+ if (rancherVersion) {
81
+ const requiredRancherVersion = plugin.metadata?.[UI_PLUGIN_METADATA.RANCHER_VERSION];
82
+
83
+ if (requiredRancherVersion && !semver.satisfies(rancherVersion, requiredRancherVersion)) {
84
+ return 'plugins.error.version';
85
+ }
86
+ }
87
+
88
+ return false;
89
+ }
90
+
91
+ // Can a chart version be used for this Rancher (based on the annotations on the chart)?
92
+ export function isSupportedChartVersion(chartVersion, rancherVersion) {
93
+ // Plugin specified a required extension API version
94
+ const requiredAPI = chartVersion.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.EXTENSIONS_VERSION];
95
+
96
+ if (requiredAPI && !semver.satisfies(UI_PLUGIN_API_VERSION, requiredAPI)) {
97
+ return false;
98
+ }
99
+
100
+ // Host application
101
+ const requiredHost = chartVersion.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.EXTENSIONS_HOST];
102
+
103
+ if (requiredHost && requiredHost !== UI_PLUGIN_HOST_APP) {
49
104
  return false;
50
105
  }
51
106
 
52
- // Plugin specified a required API version
53
- const requiredAPI = plugin.metadata?.[UI_PLUGIN_METADATA_API_VERSION];
107
+ // Rancher version
108
+ if (rancherVersion) {
109
+ const requiredRancherVersion = chartVersion.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.RANCHER_VERSION];
54
110
 
55
- if (requiredAPI) {
56
- return semver.satisfies(UI_PLUGIN_API_VERSION, requiredAPI);
111
+ if (requiredRancherVersion && !semver.satisfies(rancherVersion, requiredRancherVersion)) {
112
+ return false;
113
+ }
57
114
  }
58
115
 
59
116
  return true;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Store version data retrieved from the backend /rancherversion API
3
+ */
4
+ let _versionData = { RancherPrime: 'false' };
5
+
6
+ export function isRancherPrime() {
7
+ return _versionData.RancherPrime?.toLowerCase() === 'true';
8
+ }
9
+
10
+ export function getVersionData() {
11
+ return _versionData;
12
+ }
13
+
14
+ export function setVersionData(v) {
15
+ // Remove any properties on 'v' we don't want
16
+ _versionData = JSON.parse(JSON.stringify(v));
17
+ }
package/core/plugin.ts CHANGED
@@ -45,6 +45,10 @@ export class Plugin implements IPlugin {
45
45
  this.name = this._metadata.name || this.id;
46
46
  }
47
47
 
48
+ get version() {
49
+ return this._metadata.version;
50
+ }
51
+
48
52
  get validators() {
49
53
  return this._validators;
50
54
  }
@@ -104,6 +108,14 @@ export class Plugin implements IPlugin {
104
108
  this.routes.push({ parent, route });
105
109
  }
106
110
 
111
+ setHomePage(component: any) {
112
+ this.addRoute({
113
+ name: 'home',
114
+ path: '/home',
115
+ component
116
+ });
117
+ }
118
+
107
119
  addUninstallHook(hook: Function) {
108
120
  this.uninstallHooks.push(hook);
109
121
  }