@rancher/shell 0.3.16 → 0.3.18

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 (174) hide show
  1. package/assets/images/wechat-qr-code.jpg +0 -0
  2. package/assets/translations/en-us.yaml +75 -16
  3. package/assets/translations/zh-hans.yaml +151 -15
  4. package/chart/__tests__/S3.test.ts +50 -0
  5. package/chart/rancher-backup/S3.vue +21 -0
  6. package/chart/rancher-backup/index.vue +4 -0
  7. package/components/AsyncButton.vue +1 -1
  8. package/components/CommunityLinks.vue +1 -0
  9. package/components/FileDiff.vue +92 -85
  10. package/components/Inactivity.vue +10 -0
  11. package/components/LazyImage.vue +2 -2
  12. package/components/PromptRestore.vue +7 -5
  13. package/components/ResourceDetail/Masthead.vue +1 -1
  14. package/components/ResourceDetail/index.vue +8 -14
  15. package/components/ResourceList/index.vue +1 -1
  16. package/components/ResourceTable.vue +50 -2
  17. package/components/YamlEditor.vue +1 -0
  18. package/components/__tests__/PromptRestore.test.ts +72 -0
  19. package/components/auth/AzureWarning.vue +1 -1
  20. package/components/auth/RoleDetailEdit.vue +1 -0
  21. package/components/fleet/FleetResources.vue +3 -64
  22. package/components/form/FileImageSelector.vue +9 -0
  23. package/components/form/FileSelector.vue +2 -1
  24. package/components/form/MatchExpressions.vue +1 -3
  25. package/components/form/NameNsDescription.vue +28 -12
  26. package/components/form/NodeAffinity.vue +2 -2
  27. package/components/form/PodAffinity.vue +2 -2
  28. package/components/form/ResourceTabs/index.vue +8 -2
  29. package/components/form/Select.vue +16 -0
  30. package/components/form/__tests__/FileImageSelector.test.ts +42 -0
  31. package/components/form/__tests__/FileSelector.test.ts +76 -0
  32. package/components/form/__tests__/NodeAffinity.test.ts +38 -0
  33. package/components/form/__tests__/PodAffinity.test.ts +46 -0
  34. package/components/formatter/ClusterLink.vue +8 -4
  35. package/components/formatter/ClusterProvider.vue +3 -1
  36. package/components/formatter/ImageName.vue +23 -0
  37. package/components/formatter/PodImages.vue +7 -1
  38. package/components/formatter/__tests__/ClusterLink.test.ts +101 -0
  39. package/components/formatter/__tests__/ClusterProvider.test.ts +24 -0
  40. package/components/nav/Header.vue +2 -2
  41. package/components/nav/WindowManager/ContainerShell.vue +60 -36
  42. package/components/nav/WindowManager/__tests__/ContainerShell.test.ts +561 -0
  43. package/config/__test__/home-links.test.ts +62 -0
  44. package/config/home-links.js +15 -3
  45. package/config/labels-annotations.js +7 -2
  46. package/config/persistentVolume.ts +108 -0
  47. package/config/product/manager.js +5 -1
  48. package/config/router.js +0 -4
  49. package/config/settings.ts +4 -0
  50. package/config/table-headers.js +6 -5
  51. package/config/types.js +2 -0
  52. package/config/uiplugins.js +50 -5
  53. package/core/plugin-helpers.js +39 -15
  54. package/core/plugin.ts +9 -0
  55. package/core/plugins.js +1 -1
  56. package/core/types-provisioning.ts +253 -0
  57. package/core/types.ts +21 -3
  58. package/detail/autoscaling.horizontalpodautoscaler/index.vue +50 -1
  59. package/detail/fleet.cattle.io.gitrepo.vue +10 -2
  60. package/detail/node.vue +6 -6
  61. package/detail/pod.vue +38 -9
  62. package/detail/provisioning.cattle.io.cluster.vue +46 -7
  63. package/detail/workload/index.vue +49 -18
  64. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +62 -0
  65. package/edit/__tests__/ui.cattle.io.navlink.test.ts +110 -0
  66. package/edit/auth/github.vue +1 -0
  67. package/edit/autoscaling.horizontalpodautoscaler/hpa-scaling-rule.vue +130 -0
  68. package/edit/autoscaling.horizontalpodautoscaler/index.vue +79 -0
  69. package/edit/fleet.cattle.io.clustergroup.vue +14 -3
  70. package/edit/fleet.cattle.io.gitrepo.vue +18 -1
  71. package/edit/namespace.vue +9 -1
  72. package/edit/networking.k8s.io.ingress/RulePath.vue +0 -2
  73. package/edit/persistentvolume/__tests__/persistentvolume.test.ts +82 -0
  74. package/edit/persistentvolume/index.vue +2 -1
  75. package/edit/persistentvolume/plugins/csi.vue +3 -1
  76. package/edit/persistentvolume/plugins/longhorn.vue +12 -12
  77. package/edit/provisioning.cattle.io.cluster/AgentConfiguration.vue +1 -30
  78. package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +15 -11
  79. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +79 -1
  80. package/edit/provisioning.cattle.io.cluster/index.vue +53 -1
  81. package/edit/provisioning.cattle.io.cluster/rke2.vue +335 -151
  82. package/edit/storage.k8s.io.storageclass/index.vue +1 -2
  83. package/edit/ui.cattle.io.navlink.vue +213 -186
  84. package/initialize/App.js +3 -13
  85. package/initialize/layouts.ts +26 -0
  86. package/layouts/default.vue +1 -1
  87. package/list/group.principal.vue +1 -1
  88. package/list/provisioning.cattle.io.cluster.vue +8 -1
  89. package/middleware/authenticated.js +101 -5
  90. package/mixins/brand.js +39 -3
  91. package/mixins/child-hook.js +2 -2
  92. package/mixins/create-edit-view/impl.js +4 -4
  93. package/models/chart.js +1 -1
  94. package/models/fleet.cattle.io.cluster.js +33 -4
  95. package/models/fleet.cattle.io.gitrepo.js +113 -38
  96. package/models/management.cattle.io.kontainerdriver.js +14 -0
  97. package/models/persistentvolume.js +2 -111
  98. package/models/pod.js +30 -0
  99. package/models/provisioning.cattle.io.cluster.js +9 -1
  100. package/models/rke.cattle.io.etcdsnapshot.js +10 -7
  101. package/package.json +2 -2
  102. package/pages/about.vue +8 -2
  103. package/pages/auth/login.vue +1 -1
  104. package/pages/auth/logout.vue +11 -3
  105. package/pages/c/_cluster/apps/charts/index.vue +5 -2
  106. package/pages/c/_cluster/apps/charts/install.vue +5 -0
  107. package/pages/c/_cluster/auth/group.principal/assign-edit.vue +1 -1
  108. package/pages/c/_cluster/auth/roles/index.vue +1 -1
  109. package/pages/c/_cluster/explorer/index.vue +2 -11
  110. package/pages/c/_cluster/manager/cloudCredential/_id.vue +0 -1
  111. package/pages/c/_cluster/manager/cloudCredential/create.vue +0 -1
  112. package/pages/c/_cluster/settings/brand.vue +11 -8
  113. package/pages/c/_cluster/uiplugins/AddExtensionRepos.vue +177 -0
  114. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +19 -3
  115. package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +90 -21
  116. package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +107 -37
  117. package/pages/c/_cluster/uiplugins/index.vue +160 -44
  118. package/pages/docs/_doc.vue +9 -3
  119. package/pages/home.vue +6 -6
  120. package/pages/support/index.vue +10 -4
  121. package/pkg/auto-import.js +1 -1
  122. package/plugins/clean-tooltip-directive.js +1 -1
  123. package/plugins/dashboard-store/__tests__/actions.spec.ts +165 -0
  124. package/plugins/dashboard-store/__tests__/getters.spec.ts +100 -0
  125. package/plugins/dashboard-store/__tests__/{mutations.spec.js → mutations.spec.ts} +2 -2
  126. package/plugins/dashboard-store/actions.js +1 -1
  127. package/plugins/dashboard-store/resource-class.js +39 -2
  128. package/plugins/plugin.js +9 -1
  129. package/plugins/steve/__tests__/getters.spec.ts +93 -0
  130. package/plugins/steve/getters.js +21 -1
  131. package/plugins/steve/subscribe.js +1 -3
  132. package/rancher-components/BadgeState/BadgeState.vue +5 -1
  133. package/rancher-components/Banner/Banner.test.ts +51 -1
  134. package/rancher-components/Banner/Banner.vue +134 -53
  135. package/rancher-components/Card/Card.test.ts +37 -0
  136. package/rancher-components/Card/Card.vue +24 -7
  137. package/rancher-components/Form/Checkbox/Checkbox.test.ts +20 -29
  138. package/rancher-components/Form/Checkbox/Checkbox.vue +45 -20
  139. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +2 -8
  140. package/rancher-components/Form/LabeledInput/LabeledInput.vue +22 -10
  141. package/rancher-components/Form/Radio/RadioButton.test.ts +31 -0
  142. package/rancher-components/Form/Radio/RadioButton.vue +30 -13
  143. package/rancher-components/Form/Radio/RadioGroup.vue +26 -7
  144. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +7 -6
  145. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +25 -38
  146. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +23 -11
  147. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +19 -5
  148. package/rancher-components/StringList/StringList.test.ts +453 -49
  149. package/rancher-components/StringList/StringList.vue +44 -26
  150. package/scripts/extension/publish +2 -2
  151. package/scripts/typegen.sh +11 -2
  152. package/server/server-middleware.js +4 -12
  153. package/store/index.js +14 -3
  154. package/store/prefs.js +0 -3
  155. package/store/store-types.js +2 -0
  156. package/store/type-map.js +17 -29
  157. package/types/api.d.ts +1 -0
  158. package/types/fleet.d.ts +1 -0
  159. package/types/shell/index.d.ts +931 -85
  160. package/types/userPreferences.d.ts +1 -1
  161. package/utils/__mocks__/socket.js +21 -0
  162. package/utils/grafana.js +23 -11
  163. package/utils/kube.js +9 -0
  164. package/utils/object.js +27 -0
  165. package/utils/selector.js +2 -1
  166. package/utils/settings.ts +2 -2
  167. package/utils/validators/formRules/index.ts +3 -3
  168. package/vue.config.js +3 -2
  169. package/components/.DS_Store +0 -0
  170. package/components/__tests__/.DS_Store +0 -0
  171. package/creators/pkg/package-lock.json +0 -37
  172. package/pages/safeMode.vue +0 -17
  173. package/plugins/steve/urloptions.js +0 -47
  174. package/yarn-error.log +0 -196
@@ -0,0 +1,177 @@
1
+ <script>
2
+ import { CATALOG } from '@shell/config/types';
3
+ import Dialog from '@shell/components/Dialog.vue';
4
+ import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
5
+ import {
6
+ UI_PLUGINS_REPO_NAME,
7
+ UI_PLUGINS_REPO_URL,
8
+ UI_PLUGINS_REPO_BRANCH,
9
+ UI_PLUGINS_PARTNERS_REPO_NAME,
10
+ UI_PLUGINS_PARTNERS_REPO_URL,
11
+ UI_PLUGINS_PARTNERS_REPO_BRANCH,
12
+ } from '@shell/config/uiplugins';
13
+
14
+ export default {
15
+ components: {
16
+ Checkbox,
17
+ Dialog,
18
+ },
19
+
20
+ async fetch() {
21
+ if (this.$store.getters['management/schemaFor'](CATALOG.CLUSTER_REPO)) {
22
+ this.repos = await this.$store.dispatch('management/findAll', { type: CATALOG.CLUSTER_REPO, opt: { force: true } });
23
+ }
24
+ },
25
+
26
+ data() {
27
+ return {
28
+ errors: [],
29
+ repos: [],
30
+ addRepos: {
31
+ official: true,
32
+ partners: true
33
+ },
34
+ reposInfo: {
35
+ official: {
36
+ repo: undefined,
37
+ name: UI_PLUGINS_REPO_NAME,
38
+ url: UI_PLUGINS_REPO_URL,
39
+ branch: UI_PLUGINS_REPO_BRANCH,
40
+ },
41
+ partners: {
42
+ repo: undefined,
43
+ name: UI_PLUGINS_PARTNERS_REPO_NAME,
44
+ url: UI_PLUGINS_PARTNERS_REPO_URL,
45
+ branch: UI_PLUGINS_PARTNERS_REPO_BRANCH,
46
+ }
47
+ }
48
+ };
49
+ },
50
+
51
+ computed: {
52
+ hasRancherUIPluginsRepo() {
53
+ return !!this.repos.find((r) => r.urlDisplay === UI_PLUGINS_REPO_URL);
54
+ },
55
+ hasRancherUIPartnersPluginsRepo() {
56
+ return !!this.repos.find((r) => r.urlDisplay === UI_PLUGINS_PARTNERS_REPO_URL);
57
+ },
58
+ isAnyRepoAvailableForInstall() {
59
+ return !this.hasRancherUIPluginsRepo || !this.hasRancherUIPartnersPluginsRepo;
60
+ }
61
+ },
62
+
63
+ methods: {
64
+ showDialog() {
65
+ this.addRepos = {
66
+ official: !this.hasRancherUIPluginsRepo,
67
+ partners: !this.hasRancherUIPartnersPluginsRepo,
68
+ };
69
+ this.$modal.show('add-extensions-repos');
70
+ },
71
+
72
+ async doAddRepos(btnCb) {
73
+ this.errors = [];
74
+ const promises = [];
75
+
76
+ for (const key in this.addRepos) {
77
+ if (this.addRepos[key]) {
78
+ const pluginCR = await this.$store.dispatch('management/create', {
79
+ type: CATALOG.CLUSTER_REPO,
80
+ metadata: { name: this.reposInfo[key].name },
81
+ spec: {
82
+ gitBranch: this.reposInfo[key].branch,
83
+ gitRepo: this.reposInfo[key].url,
84
+ }
85
+ });
86
+
87
+ promises.push(pluginCR.save());
88
+ }
89
+ }
90
+
91
+ if (promises.length) {
92
+ const res = await Promise.allSettled(promises);
93
+
94
+ res.forEach((result) => {
95
+ if (result.status === 'rejected') {
96
+ console.error(result.reason); // eslint-disable-line no-console
97
+
98
+ this.errors.push(result.reason);
99
+ }
100
+ });
101
+ }
102
+
103
+ this.$emit('done');
104
+
105
+ btnCb(true);
106
+ },
107
+ }
108
+ };
109
+ </script>
110
+ <template>
111
+ <Dialog
112
+ name="add-extensions-repos"
113
+ :title="t('plugins.addRepos.title')"
114
+ mode="add"
115
+ data-testid="add-extensions-repos-modal"
116
+ @okay="doAddRepos"
117
+ >
118
+ <template>
119
+ <p class="mb-20">
120
+ {{ t('plugins.addRepos.prompt', {}, true) }}
121
+ </p>
122
+ <!-- Official repo -->
123
+ <div
124
+ class="mb-15"
125
+ >
126
+ <Checkbox
127
+ v-model="addRepos.official"
128
+ :disabled="hasRancherUIPluginsRepo"
129
+ :primary="true"
130
+ label-key="plugins.setup.install.addRancherRepo"
131
+ data-testid="add-extensions-repos-modal-add-official-repo"
132
+ />
133
+ <div
134
+ v-if="hasRancherUIPluginsRepo"
135
+ class="checkbox-info"
136
+ >
137
+ ({{ t('plugins.setup.installed') }})
138
+ </div>
139
+ </div>
140
+ <!-- Partners repo -->
141
+ <div
142
+ class="mb-15"
143
+ >
144
+ <Checkbox
145
+ v-model="addRepos.partners"
146
+ :disabled="hasRancherUIPartnersPluginsRepo"
147
+ :primary="true"
148
+ label-key="plugins.setup.install.addPartnersRancherRepo"
149
+ data-testid="add-extensions-repos-modal-add-partners-repo"
150
+ />
151
+ <div
152
+ v-if="hasRancherUIPartnersPluginsRepo"
153
+ class="checkbox-info"
154
+ >
155
+ ({{ t('plugins.setup.installed') }})
156
+ </div>
157
+ </div>
158
+ </template>
159
+ </Dialog>
160
+ </template>
161
+ <style lang="scss" scoped>
162
+ .enable-plugin-support {
163
+ font-size: 14px;
164
+ margin-top: 20px;
165
+ }
166
+
167
+ .plugin-setup-error {
168
+ font-size: 14px;
169
+ color: var(--error);
170
+ margin: 10px 0 0 0;
171
+ }
172
+
173
+ .checkbox-info {
174
+ margin-left: 20px;
175
+ opacity: 0.7;
176
+ }
177
+ </style>
@@ -66,8 +66,9 @@ export default {
66
66
  const versionName = version || this.info.displayVersion;
67
67
 
68
68
  const isVersionNotCompatibleWithUi = this.info.versions?.find((v) => v.version === versionName && !v.isCompatibleWithUi);
69
+ const isVersionNotCompatibleWithKubeVersion = this.info.versions?.find((v) => v.version === versionName && !v.isCompatibleWithKubeVersion);
69
70
 
70
- if (!this.info.chart || isVersionNotCompatibleWithUi) {
71
+ if (!this.info.chart || isVersionNotCompatibleWithUi || isVersionNotCompatibleWithKubeVersion) {
71
72
  return;
72
73
  }
73
74
 
@@ -103,6 +104,21 @@ export default {
103
104
  this.versionError = true;
104
105
  console.error('Unable to fetch VersionInfo: ', e); // eslint-disable-line no-console
105
106
  }
107
+ },
108
+
109
+ handleVersionBtnTooltip(version) {
110
+ if (version.requiredUiVersion) {
111
+ return this.t('plugins.info.requiresRancherVersion', { version: version.requiredUiVersion });
112
+ }
113
+ if (version.requiredKubeVersion) {
114
+ return this.t('plugins.info.requiresKubeVersion', { version: version.requiredKubeVersion });
115
+ }
116
+
117
+ return '';
118
+ },
119
+
120
+ handleVersionBtnClass(version) {
121
+ return { 'version-active': version.version === this.infoVersion, disabled: !version.isCompatibleWithUi || !version.isCompatibleWithKubeVersion };
106
122
  }
107
123
  }
108
124
  };
@@ -206,9 +222,9 @@ export default {
206
222
  :key="v.version"
207
223
  >
208
224
  <a
209
- v-clean-tooltip="v.requiredUiVersion ? t('plugins.info.requiresVersion', { version: v.requiredUiVersion }) : ''"
225
+ v-clean-tooltip="handleVersionBtnTooltip(v)"
210
226
  class="version-link"
211
- :class="{'version-active': v.version === infoVersion, 'disabled': !v.isCompatibleWithUi}"
227
+ :class="handleVersionBtnClass(v)"
212
228
  @click="loadPluginVersionInfo(v.version)"
213
229
  >
214
230
  {{ v.version }}
@@ -1,13 +1,18 @@
1
1
  <script>
2
+ import { mapGetters } from 'vuex';
2
3
  import { CATALOG, UI_PLUGIN } from '@shell/config/types';
3
4
  import Dialog from '@shell/components/Dialog.vue';
4
5
  import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
5
6
  import {
6
7
  UI_PLUGIN_NAMESPACE,
7
8
  UI_PLUGIN_CHARTS,
9
+ UI_PLUGIN_OPERATOR_CRD_CHART_NAME,
8
10
  UI_PLUGINS_REPO_NAME,
9
11
  UI_PLUGINS_REPO_URL,
10
- UI_PLUGIN_OPERATOR_CRD_CHART_NAME,
12
+ UI_PLUGINS_REPO_BRANCH,
13
+ UI_PLUGINS_PARTNERS_REPO_NAME,
14
+ UI_PLUGINS_PARTNERS_REPO_URL,
15
+ UI_PLUGINS_PARTNERS_REPO_BRANCH,
11
16
  } from '@shell/config/uiplugins';
12
17
 
13
18
  export default {
@@ -18,9 +23,8 @@ export default {
18
23
 
19
24
  async fetch() {
20
25
  if (this.$store.getters['management/schemaFor'](CATALOG.CLUSTER_REPO)) {
21
- const repos = await this.$store.dispatch('management/findAll', { type: CATALOG.CLUSTER_REPO, opt: { force: true } });
22
-
23
- this.defaultRepo = repos.find((r) => r.name === UI_PLUGINS_REPO_NAME && r.spec.gitRepo === UI_PLUGINS_REPO_URL);
26
+ // we need to force the request, so that we know at all times if what's the status of the offical and partners repos (installed or not)
27
+ await this.$store.dispatch('management/findAll', { type: CATALOG.CLUSTER_REPO, opt: { force: true } });
24
28
  }
25
29
 
26
30
  if (this.$store.getters['management/schemaFor'](UI_PLUGIN)) {
@@ -34,14 +38,42 @@ export default {
34
38
 
35
39
  data() {
36
40
  return {
37
- errors: [],
38
- defaultRepo: undefined,
39
- removeRepo: false,
41
+ errors: [],
42
+ removeRepos: {
43
+ official: true,
44
+ partners: true
45
+ },
46
+ reposInfo: {
47
+ official: {
48
+ name: UI_PLUGINS_REPO_NAME,
49
+ url: UI_PLUGINS_REPO_URL,
50
+ branch: UI_PLUGINS_REPO_BRANCH,
51
+ },
52
+ partners: {
53
+ name: UI_PLUGINS_PARTNERS_REPO_NAME,
54
+ url: UI_PLUGINS_PARTNERS_REPO_URL,
55
+ branch: UI_PLUGINS_PARTNERS_REPO_BRANCH,
56
+ }
57
+ },
40
58
  removeCRD: true,
41
59
  hasPluginsInstalled: false,
42
60
  };
43
61
  },
44
62
 
63
+ computed: {
64
+ ...mapGetters({ repos: 'catalog/repos' }),
65
+ officialRepo() {
66
+ const repo = this.repos.find((r) => r.urlDisplay === UI_PLUGINS_REPO_URL);
67
+
68
+ return repo?.id ? repo : undefined;
69
+ },
70
+ partnersRepo() {
71
+ const repo = this.repos.find((r) => r.urlDisplay === UI_PLUGINS_PARTNERS_REPO_URL);
72
+
73
+ return repo?.id ? repo : undefined;
74
+ }
75
+ },
76
+
45
77
  methods: {
46
78
  async removeChart(name) {
47
79
  const apps = await this.$store.dispatch('management/findAll', { type: CATALOG.APP });
@@ -58,7 +90,10 @@ export default {
58
90
  },
59
91
 
60
92
  showDialog() {
61
- this.removeRepo = !!this.defaultRepo;
93
+ this.removeRepos = {
94
+ official: !!this.officialRepo,
95
+ partners: !!this.partnersRepo,
96
+ };
62
97
  this.$modal.show('confirm-uiplugins-remove');
63
98
  },
64
99
 
@@ -83,14 +118,26 @@ export default {
83
118
  }
84
119
  }
85
120
 
86
- if (this.removeRepo && this.defaultRepo) {
87
- try {
88
- await this.defaultRepo.remove();
89
- } catch (e) {
90
- this.errors.push(e.message);
121
+ // remove extension repos that have been picked
122
+ const promises = [];
123
+
124
+ for (const key in this.removeRepos) {
125
+ if (this.removeRepos[key] && this[`${ key }Repo`]) {
126
+ promises.push(this[`${ key }Repo`].remove());
91
127
  }
92
128
  }
93
129
 
130
+ const res = await Promise.allSettled(promises);
131
+
132
+ res.forEach((result) => {
133
+ if (result.status === 'rejected') {
134
+ console.error(result.reason); // eslint-disable-line no-console
135
+
136
+ this.errors.push(result.reason);
137
+ }
138
+ });
139
+
140
+ // forget PLUGINS type from store as it's not needed
94
141
  this.$store.dispatch('management/forgetType', UI_PLUGIN);
95
142
 
96
143
  await new Promise((resolve) => setTimeout(resolve, 5000));
@@ -111,21 +158,43 @@ export default {
111
158
  @okay="doRemove"
112
159
  >
113
160
  <template>
114
- <p>
161
+ <p class="mb-20">
115
162
  {{ t('plugins.setup.remove.prompt') }}
116
163
  </p>
164
+ <!-- Official repo -->
117
165
  <div
118
- v-if="!!defaultRepo"
119
- class="mt-20"
166
+ class="mb-15"
120
167
  >
121
168
  <Checkbox
122
- v-model="removeRepo"
169
+ v-model="removeRepos.official"
123
170
  :primary="true"
124
- label-key="plugins.setup.remove.registry.title"
125
- data-testid="disable-ext-modal-remove-repo"
171
+ :disabled="!officialRepo"
172
+ label-key="plugins.setup.remove.registry.official.title"
173
+ data-testid="disable-ext-modal-remove-official-repo"
126
174
  />
127
- <div class="checkbox-info">
128
- {{ t('plugins.setup.remove.registry.prompt') }}
175
+ <div
176
+ v-if="!officialRepo"
177
+ class="checkbox-info"
178
+ >
179
+ ({{ t('plugins.setup.uninstalled') }})
180
+ </div>
181
+ </div>
182
+ <!-- Partners repo -->
183
+ <div
184
+ class="mb-15"
185
+ >
186
+ <Checkbox
187
+ v-model="removeRepos.partners"
188
+ :primary="true"
189
+ :disabled="!partnersRepo"
190
+ label-key="plugins.setup.remove.registry.partners.title"
191
+ data-testid="disable-ext-modal-remove-partners-repo"
192
+ />
193
+ <div
194
+ v-if="!partnersRepo"
195
+ class="checkbox-info"
196
+ >
197
+ ({{ t('plugins.setup.uninstalled') }})
129
198
  </div>
130
199
  </div>
131
200
  <div
@@ -1,10 +1,12 @@
1
1
  <script>
2
+ import { mapGetters } from 'vuex';
2
3
  import AsyncButton, { ASYNC_BUTTON_STATES } from '@shell/components/AsyncButton';
3
4
  import IconMessage from '@shell/components/IconMessage.vue';
4
5
  import { CATALOG, MANAGEMENT } from '@shell/config/types';
5
6
  import { CATALOG as CATALOG_ANNOTATIONS } from '@shell/config/labels-annotations';
6
7
  import Dialog from '@shell/components/Dialog.vue';
7
8
  import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
9
+ import Banner from '@components/Banner/Banner.vue';
8
10
 
9
11
  import {
10
12
  UI_PLUGIN_NAMESPACE,
@@ -13,12 +15,16 @@ import {
13
15
  UI_PLUGINS_REPO_NAME,
14
16
  UI_PLUGINS_REPO_URL,
15
17
  UI_PLUGINS_REPO_BRANCH,
18
+ UI_PLUGINS_PARTNERS_REPO_NAME,
19
+ UI_PLUGINS_PARTNERS_REPO_URL,
20
+ UI_PLUGINS_PARTNERS_REPO_BRANCH,
16
21
  } from '@shell/config/uiplugins';
17
22
 
18
23
  export default {
19
24
  components: {
20
25
  AsyncButton,
21
26
  Checkbox,
27
+ Banner,
22
28
  IconMessage,
23
29
  Dialog,
24
30
  },
@@ -43,7 +49,8 @@ export default {
43
49
  this.installCharts = found;
44
50
 
45
51
  if (this.$store.getters['management/schemaFor'](CATALOG.CLUSTER_REPO)) {
46
- await this.$store.dispatch('management/findAll', { type: CATALOG.CLUSTER_REPO });
52
+ // we need to force the request, so that we know at all times if what's the status of the offical and partners repos (installed or not)
53
+ await this.$store.dispatch('management/findAll', { type: CATALOG.CLUSTER_REPO, opt: { force: true } });
47
54
  }
48
55
  }
49
56
 
@@ -57,22 +64,41 @@ export default {
57
64
 
58
65
  data() {
59
66
  return {
60
- loading: true,
61
- haveCharts: false,
62
- installCharts: [],
63
- errors: [],
64
- addRepo: true,
67
+ loading: true,
68
+ haveCharts: false,
69
+ installCharts: [],
70
+ errors: [],
71
+ addRepos: {
72
+ official: true,
73
+ partners: true,
74
+ },
75
+ reposInfo: {
76
+ official: {
77
+ name: UI_PLUGINS_REPO_NAME,
78
+ url: UI_PLUGINS_REPO_URL,
79
+ branch: UI_PLUGINS_REPO_BRANCH,
80
+ },
81
+ partners: {
82
+ name: UI_PLUGINS_PARTNERS_REPO_NAME,
83
+ url: UI_PLUGINS_PARTNERS_REPO_URL,
84
+ branch: UI_PLUGINS_PARTNERS_REPO_BRANCH,
85
+ }
86
+ },
65
87
  buttonState: ASYNC_BUTTON_STATES.ACTION,
66
88
  defaultRegistrySetting: null,
67
89
  };
68
90
  },
69
91
 
70
92
  computed: {
93
+ ...mapGetters({ repos: 'catalog/repos' }),
71
94
  hasRancherUIPluginsRepo() {
72
- // Look to see if the Rancher UI Plugins repository is already installed
73
- const repos = this.$store.getters['catalog/repos'];
74
-
75
- return !!repos.find((r) => r.name === UI_PLUGINS_REPO_NAME);
95
+ return !!this.repos.find((r) => r.urlDisplay === UI_PLUGINS_REPO_URL);
96
+ },
97
+ hasRancherUIPartnersPluginsRepo() {
98
+ return !!this.repos.find((r) => r.urlDisplay === UI_PLUGINS_PARTNERS_REPO_URL);
99
+ },
100
+ isAnyRepoAvailableForInstall() {
101
+ return !this.hasRancherUIPluginsRepo || !this.hasRancherUIPartnersPluginsRepo;
76
102
  }
77
103
  },
78
104
 
@@ -121,11 +147,17 @@ export default {
121
147
  });
122
148
  },
123
149
 
124
- enable() {
150
+ async enable() {
125
151
  this.errors = [];
126
152
 
127
- // Reset checkbox bsed on if the repo is already installed
128
- this.addRepo = !this.hasRancherUIPluginsRepo;
153
+ // force update of cluster repos so that modal have the correct information about the official and partners repo
154
+ this.$emit('refreshCharts');
155
+
156
+ // Reset checkbox based on if the repo is already installed
157
+ this.addRepos = {
158
+ official: !this.hasRancherUIPluginsRepo,
159
+ partners: !this.hasRancherUIPartnersPluginsRepo,
160
+ };
129
161
 
130
162
  this.$modal.show('confirm-uiplugins-setup');
131
163
  },
@@ -137,8 +169,8 @@ export default {
137
169
  if (ok) {
138
170
  this.buttonState = ASYNC_BUTTON_STATES.WAITING;
139
171
 
140
- if (this.addRepo) {
141
- await this.addDefaultHelmRepository();
172
+ if (Object.values(this.addRepos).find((v) => v)) {
173
+ await this.addDefaultHelmRepositories();
142
174
  }
143
175
 
144
176
  await this.installPluginCharts();
@@ -151,25 +183,33 @@ export default {
151
183
  }
152
184
  },
153
185
 
154
- async addDefaultHelmRepository() {
155
- const name = UI_PLUGINS_REPO_NAME;
186
+ async addDefaultHelmRepositories() {
187
+ const promises = [];
188
+
189
+ for (const key in this.addRepos) {
190
+ if (this.addRepos[key]) {
191
+ const pluginCR = await this.$store.dispatch('management/create', {
192
+ type: CATALOG.CLUSTER_REPO,
193
+ metadata: { name: this.reposInfo[key].name },
194
+ spec: {
195
+ gitBranch: this.reposInfo[key].branch,
196
+ gitRepo: this.reposInfo[key].url,
197
+ }
198
+ });
199
+
200
+ promises.push(pluginCR.save());
201
+ }
202
+ }
156
203
 
157
- try {
158
- const pluginCR = await this.$store.dispatch('management/create', {
159
- type: CATALOG.CLUSTER_REPO,
160
- metadata: { name },
161
- spec: {
162
- gitBranch: UI_PLUGINS_REPO_BRANCH,
163
- gitRepo: UI_PLUGINS_REPO_URL,
164
- }
165
- });
204
+ const res = await Promise.allSettled(promises);
166
205
 
167
- return pluginCR.save();
168
- } catch (e) {
169
- console.error(e); // eslint-disable-line no-console
206
+ res.forEach((result) => {
207
+ if (result.status === 'rejected') {
208
+ console.error(result.reason); // eslint-disable-line no-console
170
209
 
171
- this.errors.push(e.message);
172
- }
210
+ this.errors.push(result.reason);
211
+ }
212
+ });
173
213
  },
174
214
 
175
215
  async installPluginCharts() {
@@ -234,20 +274,50 @@ export default {
234
274
  @closed="dialogClosed"
235
275
  >
236
276
  <template>
237
- <p>
277
+ <p class="mb-20">
238
278
  {{ t('plugins.setup.install.prompt') }}
239
279
  </p>
280
+ <Banner
281
+ v-if="isAnyRepoAvailableForInstall"
282
+ color="info"
283
+ class="mb-20"
284
+ >
285
+ {{ t('plugins.setup.install.airgap') }}
286
+ </Banner>
287
+ <!-- Official rancher repo -->
240
288
  <div
241
- v-if="!hasRancherUIPluginsRepo"
242
- class="mt-20"
289
+ class="mb-15"
243
290
  >
244
291
  <Checkbox
245
- v-model="addRepo"
292
+ v-model="addRepos.official"
293
+ :disabled="hasRancherUIPluginsRepo"
246
294
  :primary="true"
247
295
  label-key="plugins.setup.install.addRancherRepo"
296
+ data-testid="extension-enable-operator-official-repo"
297
+ />
298
+ <div
299
+ v-if="hasRancherUIPluginsRepo"
300
+ class="checkbox-info"
301
+ >
302
+ ({{ t('plugins.setup.installed') }})
303
+ </div>
304
+ </div>
305
+ <!-- Partners rancher repo -->
306
+ <div
307
+ class="mb-15"
308
+ >
309
+ <Checkbox
310
+ v-model="addRepos.partners"
311
+ :disabled="hasRancherUIPartnersPluginsRepo"
312
+ :primary="true"
313
+ label-key="plugins.setup.install.addPartnersRancherRepo"
314
+ data-testid="extension-enable-operator-partners-repo"
248
315
  />
249
- <div class="checkbox-info">
250
- {{ t('plugins.setup.install.airgap') }}
316
+ <div
317
+ v-if="hasRancherUIPartnersPluginsRepo"
318
+ class="checkbox-info"
319
+ >
320
+ ({{ t('plugins.setup.installed') }})
251
321
  </div>
252
322
  </div>
253
323
  </template>