@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
@@ -8,17 +8,35 @@ import { MODE, _IMPORT } from '@shell/config/query-params';
8
8
  import { filterOnlyKubernetesClusters, filterHiddenLocalCluster } from '@shell/utils/cluster';
9
9
  import { mapFeature, HARVESTER as HARVESTER_FEATURE } from '@shell/store/features';
10
10
  import { NAME as EXPLORER } from '@shell/config/product/explorer';
11
+ import ResourceFetch from '@shell/mixins/resource-fetch';
11
12
 
12
13
  export default {
13
14
  components: {
14
15
  Banner, ResourceTable, Masthead
15
16
  },
17
+ mixins: [ResourceFetch],
18
+ props: {
19
+ loadResources: {
20
+ type: Array,
21
+ default: () => []
22
+ },
23
+
24
+ loadIndeterminate: {
25
+ type: Boolean,
26
+ default: false
27
+ },
28
+
29
+ incrementalLoadingIndicator: {
30
+ type: Boolean,
31
+ default: false
32
+ },
33
+ },
16
34
 
17
35
  async fetch() {
18
36
  const hash = {
37
+ rancherClusters: this.$fetchType(CAPI.RANCHER_CLUSTER),
19
38
  normanClusters: this.$store.dispatch('rancher/findAll', { type: NORMAN.CLUSTER }),
20
39
  mgmtClusters: this.$store.dispatch('management/findAll', { type: MANAGEMENT.CLUSTER }),
21
- rancherClusters: this.$store.dispatch('management/findAll', { type: CAPI.RANCHER_CLUSTER }),
22
40
  };
23
41
 
24
42
  if ( this.$store.getters['management/canList'](SNAPSHOT) ) {
@@ -50,7 +68,6 @@ export default {
50
68
  const res = await allHash(hash);
51
69
 
52
70
  this.mgmtClusters = res.mgmtClusters;
53
- this.rancherClusters = res.rancherClusters;
54
71
  },
55
72
 
56
73
  data() {
@@ -58,19 +75,18 @@ export default {
58
75
  resource: CAPI.RANCHER_CLUSTER,
59
76
  schema: this.$store.getters['management/schemaFor'](CAPI.RANCHER_CLUSTER),
60
77
  mgmtClusters: [],
61
- rancherClusters: [],
62
78
  };
63
79
  },
64
80
 
65
81
  computed: {
66
- rows() {
82
+ filteredRows() {
67
83
  // If Harvester feature is enabled, hide Harvester Clusters
68
84
  if (this.harvesterEnabled) {
69
- return filterHiddenLocalCluster(filterOnlyKubernetesClusters(this.rancherClusters), this.$store);
85
+ return filterHiddenLocalCluster(filterOnlyKubernetesClusters(this.rows), this.$store);
70
86
  }
71
87
 
72
88
  // Otherwise, show Harvester clusters - these will be shown with a warning
73
- return filterHiddenLocalCluster(this.rancherClusters, this.$store);
89
+ return filterHiddenLocalCluster(this.rows, this.$store);
74
90
  },
75
91
 
76
92
  hiddenHarvesterCount() {
@@ -82,7 +98,7 @@ export default {
82
98
  return 0;
83
99
  }
84
100
 
85
- return this.rancherClusters.length - filterOnlyKubernetesClusters(this.rancherClusters).length;
101
+ return this.rows.length - filterOnlyKubernetesClusters(this.rows).length;
86
102
  },
87
103
 
88
104
  createLocation() {
@@ -115,6 +131,13 @@ export default {
115
131
  harvesterEnabled: mapFeature(HARVESTER_FEATURE),
116
132
  },
117
133
 
134
+ $loadingResources() {
135
+ return {
136
+ loadResources: [CAPI.RANCHER_CLUSTER],
137
+ loadIndeterminate: true, // results are filtered so we wouldn't get the correct count on indicator...
138
+ };
139
+ },
140
+
118
141
  mounted() {
119
142
  window.c = this;
120
143
  },
@@ -130,6 +153,9 @@ export default {
130
153
  :resource="resource"
131
154
  :create-location="createLocation"
132
155
  component-testid="cluster-manager-list"
156
+ :show-incremental-loading-indicator="incrementalLoadingIndicator"
157
+ :load-resources="loadResources"
158
+ :load-indeterminate="loadIndeterminate"
133
159
  >
134
160
  <template v-if="canImport" slot="extraActions">
135
161
  <n-link
@@ -142,7 +168,7 @@ export default {
142
168
  </template>
143
169
  </Masthead>
144
170
 
145
- <ResourceTable :schema="schema" :rows="rows" :namespaced="false" :loading="$fetchState.pending">
171
+ <ResourceTable :schema="schema" :rows="filteredRows" :namespaced="false" :loading="loading">
146
172
  <template #cell:summary="{row}">
147
173
  <span v-if="!row.stateParts.length">{{ row.nodes.length }}</span>
148
174
  </template>
package/list/service.vue CHANGED
@@ -1,12 +1,25 @@
1
1
  <script>
2
2
  import ResourceTable from '@shell/components/ResourceTable';
3
- import Loading from '@shell/components/Loading';
4
3
  import { NODE } from '@shell/config/types';
5
4
  import { allHash } from '@shell/utils/promise';
5
+ import ResourceFetch from '@shell/mixins/resource-fetch';
6
6
 
7
7
  export default {
8
8
  name: 'ListService',
9
- components: { Loading, ResourceTable },
9
+ components: { ResourceTable },
10
+ mixins: [ResourceFetch],
11
+ props: {
12
+ resource: {
13
+ type: String,
14
+ required: true,
15
+ },
16
+
17
+ schema: {
18
+ type: Object,
19
+ required: true,
20
+ },
21
+ },
22
+
10
23
  // fetch nodes before loading this page, as they may be referenced in the Target table column
11
24
  async fetch() {
12
25
  const store = this.$store;
@@ -21,23 +34,22 @@ export default {
21
34
  }
22
35
  } catch {}
23
36
 
24
- const hash = { rows: store.dispatch(`${ inStore }/findAll`, { type: this.$attrs.resource }) };
37
+ const hash = { rows: this.$fetchType(this.resource) };
25
38
 
26
39
  if (hasNodes) {
27
40
  hash.nodes = store.dispatch(`${ inStore }/findAll`, { type: NODE });
28
41
  }
29
- const res = await allHash(hash);
30
-
31
- this.rows = res.rows;
32
- },
33
-
34
- data() {
35
- return { rows: [] };
42
+ await allHash(hash);
36
43
  }
37
44
  };
38
45
  </script>
39
46
 
40
47
  <template>
41
- <Loading v-if="$fetchState.pending" />
42
- <ResourceTable v-else :schema="$attrs.schema" :rows="rows" :headers="$attrs.headers" :group-by="$attrs.groupBy" />
48
+ <ResourceTable
49
+ :schema="schema"
50
+ :rows="rows"
51
+ :headers="$attrs.headers"
52
+ :group-by="$attrs.groupBy"
53
+ :loading="loading"
54
+ />
43
55
  </template>
@@ -16,6 +16,11 @@ export default {
16
16
  type: Array,
17
17
  required: true,
18
18
  },
19
+
20
+ loading: {
21
+ type: Boolean,
22
+ required: false,
23
+ },
19
24
  },
20
25
 
21
26
  computed: { ...mapGetters(['clusterId']) }
@@ -26,6 +31,7 @@ export default {
26
31
  <ResourceTable
27
32
  :schema="schema"
28
33
  :rows="rows"
34
+ :loading="loading"
29
35
  >
30
36
  <template #cell:to="{row}">
31
37
  <template v-if="row.spec && row.spec.toService">
package/list/workload.vue CHANGED
@@ -76,7 +76,7 @@ export default {
76
76
  return schema;
77
77
  },
78
78
 
79
- rows() {
79
+ filteredRows() {
80
80
  const out = [];
81
81
 
82
82
  for ( const typeRows of this.resources ) {
@@ -151,5 +151,5 @@ export default {
151
151
  </script>
152
152
 
153
153
  <template>
154
- <ResourceTable :loading="$fetchState.pending" :schema="schema" :rows="rows" :overflow-y="true" />
154
+ <ResourceTable :loading="$fetchState.pending" :schema="schema" :rows="filteredRows" :overflow-y="true" />
155
155
  </template>
@@ -234,6 +234,8 @@ export default async function({
234
234
  }
235
235
  }
236
236
  }
237
+
238
+ store.dispatch('gcStartIntervals');
237
239
  }
238
240
 
239
241
  if (!process.server) {
@@ -245,6 +247,10 @@ export default async function({
245
247
  window.location.href = backTo;
246
248
  }
247
249
  }
250
+
251
+ // GC should be notified of route change before any find/get request is made that might be used for that page
252
+ store.dispatch('gcRouteChanged', route);
253
+
248
254
  // Load stuff
249
255
  await applyProducts(store, $plugin);
250
256
  // Setup a beforeEach hook once to keep track of the current product
@@ -1,26 +1,10 @@
1
1
  import { mapGetters } from 'vuex';
2
- import {
3
- COUNT, MANAGEMENT, POD, WORKLOAD_TYPES, WORKLOAD, SECRET
4
- } from '@shell/config/types';
2
+ import { COUNT, MANAGEMENT } from '@shell/config/types';
5
3
  import { SETTING, DEFAULT_PERF_SETTING } from '@shell/config/settings';
6
4
 
7
5
  // Number of pages to fetch when loading incrementally
8
6
  const PAGES = 4;
9
7
 
10
- // restrict advanced features of manual refresh and incremental loading to these resource types
11
- export const TYPES_RESTRICTED = [
12
- SECRET,
13
- POD,
14
- WORKLOAD_TYPES.DEPLOYMENT,
15
- WORKLOAD_TYPES.CRON_JOB,
16
- WORKLOAD_TYPES.DAEMON_SET,
17
- WORKLOAD_TYPES.JOB,
18
- WORKLOAD_TYPES.STATEFUL_SET,
19
- WORKLOAD_TYPES.REPLICA_SET,
20
- WORKLOAD_TYPES.REPLICATION_CONTROLLER,
21
- WORKLOAD
22
- ];
23
-
24
8
  export default {
25
9
  data() {
26
10
  // fetching the settings related to manual refresh from global settings
@@ -66,7 +50,17 @@ export default {
66
50
  }
67
51
  },
68
52
 
69
- computed: { ...mapGetters({ refreshFlag: 'resource-fetch/refreshFlag' }) },
53
+ computed: {
54
+ ...mapGetters({ refreshFlag: 'resource-fetch/refreshFlag' }),
55
+ rows() {
56
+ const inStore = this.$store.getters['currentStore'](this.resource);
57
+
58
+ return this.$store.getters[`${ inStore }/all`](this.resource);
59
+ },
60
+ loading() {
61
+ return this.rows.length ? false : this.$fetchState.pending;
62
+ },
63
+ },
70
64
  watch: {
71
65
  refreshFlag(neu) {
72
66
  // this is where the data assignment will trigger the update of the list view...
@@ -0,0 +1,126 @@
1
+ import { mapGetters } from 'vuex';
2
+ import { allHashSettled } from '@shell/utils/promise';
3
+
4
+ export default {
5
+ computed: { ...mapGetters(['currentCluster']) },
6
+ data() {
7
+ return { isLoadingSecondaryResources: false };
8
+ },
9
+ methods: {
10
+ /**
11
+ *
12
+ * Function resourceManagerFetchSecondaryResources
13
+ * This method is used to fetch what is called "secondary resources", which can be defined as resources that are needed to populate
14
+ * the page/component itself (ex: used as options on a Select) but don't need to be put into Vuex store or watched to get constant updates.
15
+ * This method allows to fetch resources for a given namespace to reduce the amount of results instead of needing to fetch all and filtering afterwards.
16
+ *
17
+ *
18
+ * @param {String} resourceData.namespace - Namespace identifier
19
+ * @param {Object} resourceData.data - Object containing info about the data needed to be fetched and how it should be parsed. Note: The KEY NEEDS to be the resource TYPE!
20
+ * @param {Array} resourceData.data[TYPE].applyTo - The array of operations needed to be performed for the specific data TYPE
21
+ * @param {String} resourceData.data[TYPE].applyTo[x].var - The 'this' property name that should be populated with the data fetched
22
+ * @param {Boolean} resourceData.data[TYPE].applyTo[x].classify - Whether the data fetched should have a model applied to it
23
+ * @param {Function} resourceData.data[TYPE].applyTo[x].parsingFunc - Optional parsing function if the fetched data needs to be parsed
24
+ * @param {Boolean} onlyNamespaced - Only fetch namespaced resources
25
+ */
26
+ async resourceManagerFetchSecondaryResources(resourceData, onlyNamespaced = false) {
27
+ const requests = {};
28
+ const namespace = resourceData.namespace;
29
+
30
+ // Only fetch types if the user is allowed to...
31
+ Object.keys(resourceData.data).forEach((type) => {
32
+ const schema = this.$store.getters['cluster/schemaFor'](type);
33
+
34
+ if (schema) {
35
+ let url = schema.links.collection;
36
+
37
+ if (schema?.attributes?.namespaced && namespace) {
38
+ const parts = url.split('/');
39
+
40
+ parts.splice(parts.length - 2, 0, `api`);
41
+ parts.splice(parts.length - 1, 0, `namespaces/${ namespace }`);
42
+ url = parts.join('/');
43
+ } else if (onlyNamespaced) {
44
+ // Type isn't namespaced and we've been requested to only fetch namespaced types
45
+ return;
46
+ }
47
+
48
+ requests[type] = this.$store.dispatch('cluster/request', { url });
49
+ }
50
+ });
51
+
52
+ if (Object.keys(requests).length) {
53
+ // this is the flag/variable that we need to apply to all places that rely on this data. Ex: LabeledSelect
54
+ this.isLoadingSecondaryResources = true;
55
+ const hash = await allHashSettled(requests);
56
+ const types = Object.keys(hash);
57
+
58
+ for (let i = 0; i < types.length; i++) {
59
+ const type = types[i];
60
+ const status = hash[type].status;
61
+ // if it's namespaced, we get the data on 'items' prop, for non-namespaced it's 'data' prop...
62
+ const requestData = hash[type].value.items || hash[type].value.data || hash[type].value;
63
+ const schema = this.$store.getters['cluster/schemaFor'](type);
64
+
65
+ if (status === 'fulfilled' && resourceData.data[type] && resourceData.data[type].applyTo?.length) {
66
+ for (let y = 0; y < resourceData.data[type].applyTo.length; y++) {
67
+ const apply = resourceData.data[type].applyTo[y];
68
+ let resources = requestData;
69
+
70
+ if (schema?.attributes?.namespaced) {
71
+ // The resources returned when requesting namespaced types do not contain id, type and links properties.
72
+ // This isn't perfect, or universally applicable, but will work for the current set of use cases
73
+ // To make this more generic
74
+ // - id param = this.$store.getters['cluster/keyFieldForType'](type)
75
+ // - id value = new dashboard-store getter, overwritten by steve store getter
76
+ requestData.forEach((item) => {
77
+ item.type = type;
78
+ item.id = `${ item.metadata.namespace }/${ item.metadata.name }`;
79
+ });
80
+ }
81
+
82
+ if (apply.classify) {
83
+ resources = await this.$store.dispatch('cluster/createMany', requestData);
84
+ }
85
+
86
+ if (apply.parsingFunc) {
87
+ this[apply.var] = apply.parsingFunc(resources);
88
+ } else {
89
+ this[apply.var] = resources;
90
+ }
91
+ }
92
+ } else if (status === 'rejected') {
93
+ console.error(`Resource Manager - secondary data request for type ${ type } has failed`, status.error); // eslint-disable-line no-console
94
+ }
95
+ }
96
+
97
+ this.isLoadingSecondaryResources = false;
98
+ }
99
+ },
100
+
101
+ /**
102
+ * Clear the cached secondary resources
103
+ *
104
+ * @param {*} resourceData See resourceManagerFetchSecondaryResources
105
+ * @param {*} onlyNamespaced Clear only namespaced resources
106
+ */
107
+ resourceManagerClearSecondaryResources(resourceData, onlyNamespaced = false) {
108
+ Object.keys(resourceData.data).forEach((type) => {
109
+ const schema = this.$store.getters['cluster/schemaFor'](type);
110
+
111
+ if (schema) {
112
+ if (!schema?.attributes?.namespaced && onlyNamespaced) {
113
+ // resource isn't namespaced and we're only interested in namespaced resources
114
+ return;
115
+ }
116
+
117
+ for (let y = 0; y < resourceData.data[type].applyTo.length; y++) {
118
+ const apply = resourceData.data[type].applyTo[y];
119
+
120
+ this[apply.var] = [];
121
+ }
122
+ }
123
+ });
124
+ }
125
+ },
126
+ };
@@ -31,4 +31,8 @@ export default class UIPlugin extends SteveModel {
31
31
  get isDeveloper() {
32
32
  return this.pluginMetadata?.developer === 'true';
33
33
  }
34
+
35
+ get plugin() {
36
+ return this.spec?.plugin || {};
37
+ }
34
38
  }
package/models/pod.js CHANGED
@@ -182,19 +182,29 @@ export default class Pod extends WorkloadService {
182
182
  }
183
183
 
184
184
  save() {
185
+ const prev = { ...this };
186
+
185
187
  const { metadata, spec } = this.spec.template;
186
188
 
187
189
  this.spec = {
188
190
  ...this.spec,
189
- metadata: {
190
- ...this.metadata,
191
- ...metadata
192
- },
193
191
  ...spec
194
192
  };
195
193
 
194
+ this.metadata = {
195
+ ...this.metadata,
196
+ ...metadata
197
+ };
198
+
196
199
  delete this.spec.template;
197
200
 
198
- return this._save(...arguments);
201
+ // IF there is an error POD world model get overwritten
202
+ // For the workloads this need be reset back
203
+ return this._save(...arguments).catch((e) => {
204
+ this.spec = prev.spec;
205
+ this.metadata = prev.metadata;
206
+
207
+ return Promise.reject(e);
208
+ });
199
209
  }
200
210
  }
@@ -679,6 +679,10 @@ export default class ProvCluster extends SteveModel {
679
679
  }
680
680
 
681
681
  get supportsWindows() {
682
+ if (this.isK3s || this.isImportedK3s) {
683
+ return false;
684
+ }
685
+
682
686
  if ( this.isRke1 ) {
683
687
  return this.mgmt?.spec?.windowsPreferedCluster || false;
684
688
  }
@@ -123,6 +123,11 @@ export default class WorkloadService extends SteveModel {
123
123
 
124
124
  return containers;
125
125
  }
126
+
127
+ if ( this.spec.containers ) {
128
+ return this.spec.containers;
129
+ }
130
+
126
131
  const { spec:{ template:{ spec:{ containers } } } } = this;
127
132
 
128
133
  return containers;
@@ -135,6 +140,11 @@ export default class WorkloadService extends SteveModel {
135
140
 
136
141
  return initContainers;
137
142
  }
143
+
144
+ if (this.spec.initContainers) {
145
+ return this.spec.initContainers;
146
+ }
147
+
138
148
  const { spec:{ template:{ spec:{ initContainers } } } } = this;
139
149
 
140
150
  return initContainers;
package/nuxt.config.js CHANGED
@@ -582,6 +582,7 @@ export default function(dir, _appConfig) {
582
582
  { src: path.join(NUXT_SHELL, 'plugins/plugin'), ssr: false }, // Load dyanmic plugins
583
583
  { src: path.join(NUXT_SHELL, 'plugins/codemirror-loader'), ssr: false },
584
584
  { src: path.join(NUXT_SHELL, 'plugins/formatters'), ssr: false }, // Populate formatters cache for sorted table
585
+ { src: path.join(NUXT_SHELL, 'plugins/version'), ssr: false }, // Makes a fetch to the backend to get version metadata
585
586
  ],
586
587
 
587
588
  // Proxy: https://github.com/nuxt-community/proxy-module#options
@@ -595,8 +596,8 @@ export default function(dir, _appConfig) {
595
596
  '/v3-public': proxyOpts(api), // Rancher Unauthed API
596
597
  '/api-ui': proxyOpts(api), // Browser API UI
597
598
  '/meta': proxyMetaOpts(api), // Browser API UI
598
- '/rancherversion': proxyPrimeOpts(api), // Rancher version endpoint
599
599
  '/v1-*': proxyOpts(api), // SAML, KDM, etc
600
+ '/rancherversion': proxyPrimeOpts(api), // Rancher version endpoint
600
601
  // These are for Ember embedding
601
602
  '/c/*/edit': proxyOpts('https://127.0.0.1:8000'), // Can't proxy all of /c because that's used by Vue too
602
603
  '/k/': proxyOpts('https://127.0.0.1:8000'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rancher/shell",
3
- "version": "0.1.4",
3
+ "version": "0.1.21",
4
4
  "description": "Rancher Dashboard Shell",
5
5
  "repository": "https://github.com/rancherlabs/dashboard",
6
6
  "license": "Apache-2.0",
@@ -26,6 +26,7 @@ import {
26
26
  setBrand,
27
27
  setVendor
28
28
  } from '@shell/config/private-label';
29
+ import loadPlugins from '@shell/plugins/plugin';
29
30
 
30
31
  export default {
31
32
  name: 'Login',
@@ -255,6 +256,15 @@ export default {
255
256
  this.$cookies.remove(USERNAME);
256
257
  }
257
258
 
259
+ // User logged with local login - we don't do any redirect/reload, so the boot-time plugin will not run again to laod the plugins
260
+ // so we manually load them here - other SSO auth providers bounce out and back to the Dashboard, so on the bounce-back
261
+ // the plugins will load via the boot-time plugin
262
+ await loadPlugins({
263
+ app: this.$store.app,
264
+ store: this.$store,
265
+ $plugin: this.$store.$plugin
266
+ });
267
+
258
268
  if (this.firstLogin || user[0]?.mustChangePassword) {
259
269
  this.$store.dispatch('auth/setInitialPass', this.password);
260
270
  this.$router.push({ name: 'auth-setup' });
@@ -2,6 +2,8 @@
2
2
  import { GITHUB_CODE, GITHUB_NONCE, BACK_TO } from '@shell/config/query-params';
3
3
  import { get } from '@shell/utils/object';
4
4
  import { base64Decode } from '@shell/utils/crypto';
5
+ import loadPlugins from '@shell/plugins/plugin';
6
+
5
7
  const samlProviders = ['ping', 'adfs', 'keycloak', 'okta', 'shibboleth'];
6
8
 
7
9
  function reply(err, code) {
@@ -60,6 +62,13 @@ export default {
60
62
  if ( res._status === 200) {
61
63
  const backTo = route.query[BACK_TO] || '/';
62
64
 
65
+ // Load plugins
66
+ await loadPlugins({
67
+ app: store.app,
68
+ store,
69
+ $plugin: store.$plugin
70
+ });
71
+
63
72
  redirect(backTo);
64
73
  } else {
65
74
  redirect(`/auth/login?err=${ escape(res) }`);
@@ -0,0 +1,108 @@
1
+ <script>
2
+ import Vue from 'vue';
3
+
4
+ import { _VIEW } from '@shell/config/query-params';
5
+ import { Checkbox } from '@components/Form/Checkbox';
6
+
7
+ export default {
8
+ name: 'DefaultLinksEditor',
9
+
10
+ components: { Checkbox },
11
+
12
+ props: {
13
+ // Array of objects with key, label, value and enabled properties
14
+ value: {
15
+ type: Array,
16
+ default: () => [],
17
+ },
18
+
19
+ mode: {
20
+ type: String,
21
+ required: true
22
+ },
23
+ },
24
+
25
+ computed: {
26
+ isView() {
27
+ return this.mode === _VIEW;
28
+ }
29
+ },
30
+
31
+ methods: {
32
+ showhide(row, i, e) {
33
+ const value = this.value[i];
34
+
35
+ Vue.set(value, 'enabled', !!value.enabled);
36
+ this.$emit('input', this.value);
37
+ },
38
+ }
39
+ };
40
+ </script>
41
+
42
+ <template>
43
+ <div class="key-value">
44
+ <div class="clearfix">
45
+ <h3>
46
+ {{ t('customLinks.settings.default') }}
47
+ </h3>
48
+ </div>
49
+
50
+ <div class="kv-container">
51
+ <label class="text-label">
52
+ {{ t('customLinks.settings.keyLabel') }}
53
+ </label>
54
+ <label class="text-label">
55
+ {{ t('customLinks.settings.valueLabel') }}
56
+ </label>
57
+ <label class="text-label">
58
+ </label>
59
+
60
+ <template v-for="(row,i) in value">
61
+ <div :key="i+'key'" class="kv-item key" :class="{'link-hidden': !row.enabled}">
62
+ <span>{{ row.label }}</span>
63
+ </div>
64
+
65
+ <div :key="i+'value'" class="kv-item value" :class="{'link-hidden': !row.enabled}">
66
+ <span>{{ row.value }}</span>
67
+ </div>
68
+
69
+ <div v-if="!row.readonly && !isView" :key="i+'show'">
70
+ <Checkbox v-if="!isView" v-model="row.enabled" label-key="customLinks.settings.showLabel" @input="showhide(row, i, $event)" />
71
+ </div>
72
+ <div v-else :key="i+'show'"></div>
73
+ </template>
74
+ </div>
75
+ </div>
76
+ </template>
77
+
78
+ <style lang="scss" scoped>
79
+ .key-value {
80
+ width: 100%;
81
+
82
+ .kv-container {
83
+ display: grid;
84
+ align-items: center;
85
+ grid-template-columns: 1fr 1fr 50px;
86
+ column-gap: $column-gutter;
87
+
88
+ .kv-item {
89
+ background-color: var(--disabled-bg);
90
+ border: 1px solid var(--border);
91
+ border-radius: 5px;
92
+ width: 100%;
93
+ margin: 10px 0px 10px 0px;
94
+ height: 40px;
95
+ line-height: 40px;
96
+ padding: 0 10px;
97
+
98
+ &.link-hidden {
99
+ color: var(--disabled-text);
100
+ }
101
+
102
+ &.key {
103
+ align-self: flex-start;
104
+ }
105
+ }
106
+ }
107
+ }
108
+ </style>