@rancher/shell 0.1.2 → 0.1.3

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 (258) hide show
  1. package/assets/translations/en-us.yaml +27 -769
  2. package/assets/translations/zh-hans.yaml +8 -769
  3. package/components/ActionMenu.vue +3 -3
  4. package/components/CodeMirror.vue +6 -8
  5. package/components/CommunityLinks.vue +1 -1
  6. package/components/ContainerResourceLimit.vue +14 -0
  7. package/components/ExplorerMembers.vue +123 -0
  8. package/components/ExplorerProjectsNamespaces.vue +405 -0
  9. package/components/GrafanaDashboard.vue +17 -2
  10. package/components/LocaleSelector.vue +81 -0
  11. package/components/PromptModal.vue +2 -3
  12. package/components/ResourceList/index.vue +1 -1
  13. package/components/ResourceTable.vue +3 -6
  14. package/components/SingleClusterInfo.vue +1 -1
  15. package/components/SortableTable/index.vue +23 -20
  16. package/components/SortableTable/selection.js +1 -0
  17. package/components/auth/AzureWarning.vue +5 -1
  18. package/components/auth/Principal.vue +1 -1
  19. package/components/auth/RoleDetailEdit.vue +18 -11
  20. package/components/fleet/FleetRepos.vue +0 -2
  21. package/components/form/NameNsDescription.vue +4 -6
  22. package/components/form/NodeScheduling.vue +1 -1
  23. package/components/form/WorkloadPorts.vue +1 -1
  24. package/components/formatter/WorkloadHealthScale.vue +1 -1
  25. package/components/nav/Header.vue +9 -9
  26. package/components/nav/NamespaceFilter.vue +7 -4
  27. package/components/nav/TopLevelMenu.vue +6 -43
  28. package/components/nav/WindowManager/ContainerLogs.vue +1 -1
  29. package/config/product/harvester-manager.js +64 -2
  30. package/config/product/manager.js +9 -0
  31. package/config/settings.js +17 -71
  32. package/config/table-headers.js +0 -1
  33. package/config/types.js +5 -25
  34. package/core/plugin-routes.ts +34 -22
  35. package/core/plugin.ts +15 -3
  36. package/core/plugins-loader.js +2 -0
  37. package/core/plugins.js +79 -36
  38. package/core/types.ts +7 -1
  39. package/detail/provisioning.cattle.io.cluster.vue +13 -0
  40. package/detail/workload/index.vue +11 -5
  41. package/{components/dialog → dialog}/AddClusterMemberDialog.vue +0 -0
  42. package/{components/dialog → dialog}/AddCustomBadgeDialog.vue +0 -0
  43. package/{components/dialog → dialog}/AddProjectMemberDialog.vue +0 -0
  44. package/{components/dialog → dialog}/AddonConfigConfirmationDialog.vue +0 -0
  45. package/{components/dialog → dialog}/DrainNode.vue +0 -0
  46. package/{components/dialog → dialog}/ForceMachineRemoveDialog.vue +0 -0
  47. package/{components/dialog → dialog}/GenericPrompt.vue +0 -0
  48. package/{components/dialog → dialog}/RollbackWorkloadDialog.vue +0 -0
  49. package/{components/dialog → dialog}/RotateCertificatesDialog.vue +0 -0
  50. package/{components/dialog → dialog}/RotateEncryptionKeyDialog.vue +0 -0
  51. package/{components/dialog → dialog}/SaveAsRKETemplateDialog.vue +0 -0
  52. package/{components/dialog → dialog}/ScaleMachineDownDialog.vue +0 -0
  53. package/edit/auth/azuread.vue +20 -1
  54. package/edit/management.cattle.io.project.vue +2 -2
  55. package/edit/namespace.vue +17 -10
  56. package/edit/persistentvolumeclaim.vue +1 -0
  57. package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +1 -1
  58. package/edit/provisioning.cattle.io.cluster/MachinePool.vue +33 -5
  59. package/edit/service.vue +1 -1
  60. package/edit/workload/index.vue +363 -15
  61. package/edit/workload/mixins/workload.js +62 -7
  62. package/edit/workload/storage/persistentVolumeClaim/persistentvolumeclaim.vue +1 -0
  63. package/layouts/default.vue +52 -27
  64. package/layouts/error.vue +5 -1
  65. package/layouts/home.vue +6 -2
  66. package/list/harvesterhci.io.management.cluster.vue +74 -33
  67. package/list/namespace.vue +3 -5
  68. package/machine-config/amazonec2.vue +2 -0
  69. package/machine-config/harvester.vue +96 -49
  70. package/middleware/authenticated.js +56 -52
  71. package/mixins/form-validation.js +1 -1
  72. package/mixins/resource-fetch.js +3 -1
  73. package/models/fleet.cattle.io.bundle.js +26 -19
  74. package/models/harvesterhci.io.management.cluster.js +194 -5
  75. package/models/management.cattle.io.cluster.js +1 -1
  76. package/models/management.cattle.io.clusterroletemplatebinding.js +9 -0
  77. package/models/management.cattle.io.project.js +23 -2
  78. package/models/namespace.js +19 -3
  79. package/models/pod.js +19 -2
  80. package/models/provisioning.cattle.io.cluster.js +4 -0
  81. package/models/workload.js +4 -243
  82. package/models/workload.service.js +314 -0
  83. package/nuxt.config.js +11 -9
  84. package/package.json +3 -3
  85. package/pages/auth/login.vue +11 -2
  86. package/pages/auth/setup.vue +1 -1
  87. package/pages/c/_cluster/_product/members/index.vue +3 -93
  88. package/pages/c/_cluster/_product/projectsnamespaces.vue +6 -403
  89. package/pages/c/_cluster/settings/performance.vue +19 -16
  90. package/pages/fail-whale.vue +1 -10
  91. package/pages/index.vue +18 -4
  92. package/pages/plugins.vue +2 -2
  93. package/pages/prefs.vue +8 -6
  94. package/pkg/auto-import.js +44 -7
  95. package/pkg/dynamic-plugin-loader.js +28 -0
  96. package/pkg/import.js +2 -2
  97. package/pkg/model-loader-require.lib.js +3 -0
  98. package/pkg/vue.config.js +9 -6
  99. package/plugins/dashboard-store/model-loader-require.js +12 -0
  100. package/plugins/dashboard-store/model-loader.js +4 -1
  101. package/plugins/dashboard-store/resource-class.js +10 -3
  102. package/plugins/steve/actions.js +1 -1
  103. package/plugins/steve/index.js +6 -4
  104. package/plugins/steve/subscribe.js +34 -23
  105. package/rancher-components/Form/Checkbox/Checkbox.test.ts +77 -0
  106. package/rancher-components/Form/Checkbox/Checkbox.vue +12 -2
  107. package/scripts/build-pkg.sh +48 -2
  108. package/scripts/drone-build-pkg.sh +31 -0
  109. package/scripts/publish-shell.sh +10 -11
  110. package/scripts/serve-pkgs +17 -10
  111. package/store/catalog.js +3 -1
  112. package/store/i18n.js +16 -11
  113. package/store/index.js +4 -181
  114. package/store/prefs.js +30 -2
  115. package/store/type-map.js +16 -29
  116. package/utils/cluster.js +1 -1
  117. package/utils/custom-validators.js +1 -12
  118. package/utils/dynamic-importer.js +1 -1
  119. package/utils/validators/setting.js +0 -35
  120. package/components/FilterLabel.vue +0 -254
  121. package/components/HarvesterUpgradeProgressBarList.vue +0 -109
  122. package/components/VMConsoleBar.vue +0 -87
  123. package/components/dialog/harvester/AddHotplugModal.vue +0 -159
  124. package/components/dialog/harvester/BackupModal.vue +0 -117
  125. package/components/dialog/harvester/CloneTemplate.vue +0 -125
  126. package/components/dialog/harvester/EjectCDROMDialog.vue +0 -157
  127. package/components/dialog/harvester/ExportImageDialog.vue +0 -152
  128. package/components/dialog/harvester/MaintenanceDialog.vue +0 -94
  129. package/components/dialog/harvester/MigrationDialog.vue +0 -154
  130. package/components/dialog/harvester/RestoreDialog.vue +0 -153
  131. package/components/dialog/harvester/SupportBundle.vue +0 -217
  132. package/components/dialog/harvester/UnplugVolume.vue +0 -108
  133. package/components/form/SerialConsole/index.vue +0 -267
  134. package/components/formatter/AttachVMWithName.vue +0 -46
  135. package/components/formatter/CloudInitType.vue +0 -27
  136. package/components/formatter/HarvesterBackupTargetValidation.vue +0 -43
  137. package/components/formatter/HarvesterCPUUsed.vue +0 -122
  138. package/components/formatter/HarvesterDiskState.vue +0 -66
  139. package/components/formatter/HarvesterHostName.vue +0 -66
  140. package/components/formatter/HarvesterIpAddress.vue +0 -90
  141. package/components/formatter/HarvesterMemoryUsed.vue +0 -140
  142. package/components/formatter/HarvesterMigrationState.vue +0 -85
  143. package/components/formatter/HarvesterNodeName.vue +0 -49
  144. package/components/formatter/HarvesterStorageUsed.vue +0 -194
  145. package/components/formatter/HarvesterVmState.vue +0 -123
  146. package/components/nav/HarvesterUpgrade.vue +0 -232
  147. package/components/novnc/NovncConsole.vue +0 -93
  148. package/components/novnc/NovncConsoleItem.vue +0 -89
  149. package/components/novnc/NovncConsoleWrapper.vue +0 -243
  150. package/config/harvester-map.js +0 -44
  151. package/config/harvester-table-headers.js +0 -27
  152. package/config/product/harvester.js +0 -305
  153. package/detail/harvesterhci.io.host/HarvesterHostBasic.vue +0 -364
  154. package/detail/harvesterhci.io.host/HarvesterHostDisk.vue +0 -200
  155. package/detail/harvesterhci.io.host/HarvesterHostNetwork.vue +0 -89
  156. package/detail/harvesterhci.io.host/VirtualMachineInstance.vue +0 -134
  157. package/detail/harvesterhci.io.host/index.vue +0 -243
  158. package/detail/harvesterhci.io.virtualmachinebackup/index.vue +0 -221
  159. package/detail/harvesterhci.io.virtualmachineimage.vue +0 -118
  160. package/detail/kubevirt.io.virtualmachine/VirtualMachineTabs/VirtualMachineBasics.vue +0 -279
  161. package/detail/kubevirt.io.virtualmachine/VirtualMachineTabs/VirtualMachineEvents.vue +0 -75
  162. package/detail/kubevirt.io.virtualmachine/VirtualMachineTabs/VirtualMachineKeypairs.vue +0 -114
  163. package/detail/kubevirt.io.virtualmachine/VirtualMachineTabs/VirtualMachineMigration.vue +0 -79
  164. package/detail/kubevirt.io.virtualmachine/index.vue +0 -213
  165. package/edit/harvesterhci.io.cloudtemplate.vue +0 -123
  166. package/edit/harvesterhci.io.host/HarvesterDisk.vue +0 -262
  167. package/edit/harvesterhci.io.host/index.vue +0 -533
  168. package/edit/harvesterhci.io.keypair.vue +0 -112
  169. package/edit/harvesterhci.io.managedchart/index.vue +0 -25
  170. package/edit/harvesterhci.io.managedchart/rancher-monitoring.vue +0 -172
  171. package/edit/harvesterhci.io.networkattachmentdefinition.vue +0 -210
  172. package/edit/harvesterhci.io.setting/additional-ca.vue +0 -36
  173. package/edit/harvesterhci.io.setting/backup-target.vue +0 -182
  174. package/edit/harvesterhci.io.setting/http-proxy.vue +0 -79
  175. package/edit/harvesterhci.io.setting/index.vue +0 -201
  176. package/edit/harvesterhci.io.setting/overcommit-config.vue +0 -94
  177. package/edit/harvesterhci.io.setting/ssl-certificates.vue +0 -117
  178. package/edit/harvesterhci.io.setting/ssl-parameters.vue +0 -161
  179. package/edit/harvesterhci.io.setting/support-bundle-image.vue +0 -134
  180. package/edit/harvesterhci.io.setting/support-bundle-namespaces.vue +0 -73
  181. package/edit/harvesterhci.io.setting/vip-pools.vue +0 -244
  182. package/edit/harvesterhci.io.setting/vm-force-reset-policy.vue +0 -81
  183. package/edit/harvesterhci.io.virtualmachinebackup.vue +0 -256
  184. package/edit/harvesterhci.io.virtualmachineimage.vue +0 -364
  185. package/edit/harvesterhci.io.virtualmachinetemplateversion.vue +0 -340
  186. package/edit/harvesterhci.io.volume.vue +0 -195
  187. package/edit/kubevirt.io.virtualmachine/VirtualMachineAccessCredentials/AccessCredentialsUsers.vue +0 -190
  188. package/edit/kubevirt.io.virtualmachine/VirtualMachineAccessCredentials/index.vue +0 -212
  189. package/edit/kubevirt.io.virtualmachine/VirtualMachineAccessCredentials/type/basicAuth.vue +0 -94
  190. package/edit/kubevirt.io.virtualmachine/VirtualMachineAccessCredentials/type/sshkey.vue +0 -85
  191. package/edit/kubevirt.io.virtualmachine/VirtualMachineCloudConfig/DataTemplate.vue +0 -153
  192. package/edit/kubevirt.io.virtualmachine/VirtualMachineCloudConfig/index.vue +0 -279
  193. package/edit/kubevirt.io.virtualmachine/VirtualMachineCpuMemory.vue +0 -113
  194. package/edit/kubevirt.io.virtualmachine/VirtualMachineNetwork/__tests__/HarvesterEditNetwork.test.ts +0 -41
  195. package/edit/kubevirt.io.virtualmachine/VirtualMachineNetwork/base.vue +0 -281
  196. package/edit/kubevirt.io.virtualmachine/VirtualMachineNetwork/index.vue +0 -142
  197. package/edit/kubevirt.io.virtualmachine/VirtualMachineReserved.vue +0 -54
  198. package/edit/kubevirt.io.virtualmachine/VirtualMachineSSHKey.vue +0 -256
  199. package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/index.vue +0 -391
  200. package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditContainer.test.ts +0 -40
  201. package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditExisting.test.ts +0 -102
  202. package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditVMImage.test.ts +0 -117
  203. package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditVolume.test.ts +0 -74
  204. package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/container.vue +0 -132
  205. package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/existing.vue +0 -303
  206. package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/vmImage.vue +0 -285
  207. package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/volume.vue +0 -188
  208. package/edit/kubevirt.io.virtualmachine/index.vue +0 -642
  209. package/edit/network.harvesterhci.io.clusternetwork/index.vue +0 -19
  210. package/edit/network.harvesterhci.io.clusternetwork/vlan.vue +0 -134
  211. package/edit/workload/types/Deployment.vue +0 -377
  212. package/edit/workload/types/Generic.vue +0 -295
  213. package/list/harvesterhci.io.cloudtemplate.vue +0 -78
  214. package/list/harvesterhci.io.dashboard/HarvesterUpgrade.vue +0 -211
  215. package/list/harvesterhci.io.dashboard/UpgradeInfo.vue +0 -40
  216. package/list/harvesterhci.io.dashboard/index.vue +0 -752
  217. package/list/harvesterhci.io.host/index.vue +0 -186
  218. package/list/harvesterhci.io.networkattachmentdefinition.vue +0 -167
  219. package/list/harvesterhci.io.setting.vue +0 -241
  220. package/list/harvesterhci.io.virtualmachinebackup.vue +0 -172
  221. package/list/harvesterhci.io.virtualmachineimage.vue +0 -80
  222. package/list/harvesterhci.io.virtualmachinetemplateversion.vue +0 -173
  223. package/list/harvesterhci.io.volume.vue +0 -122
  224. package/list/kubevirt.io.virtualmachine.vue +0 -193
  225. package/mixins/harvester-vm/impl.js +0 -267
  226. package/mixins/harvester-vm/index.js +0 -1357
  227. package/models/harvester/configmap.js +0 -32
  228. package/models/harvester/harvesterhci.io.blockdevice.js +0 -55
  229. package/models/harvester/harvesterhci.io.keypair.js +0 -12
  230. package/models/harvester/harvesterhci.io.setting.js +0 -127
  231. package/models/harvester/harvesterhci.io.supportbundle.js +0 -35
  232. package/models/harvester/harvesterhci.io.upgrade.js +0 -226
  233. package/models/harvester/harvesterhci.io.virtualmachinebackup.js +0 -116
  234. package/models/harvester/harvesterhci.io.virtualmachineimage.js +0 -255
  235. package/models/harvester/harvesterhci.io.virtualmachinerestore.js +0 -43
  236. package/models/harvester/harvesterhci.io.virtualmachinetemplate.js +0 -69
  237. package/models/harvester/harvesterhci.io.virtualmachinetemplateversion.js +0 -227
  238. package/models/harvester/k8s.cni.cncf.io.networkattachmentdefinition.js +0 -32
  239. package/models/harvester/kubevirt.io.virtualmachine.js +0 -850
  240. package/models/harvester/kubevirt.io.virtualmachineinstance.js +0 -142
  241. package/models/harvester/management.cattle.io.managedchart.js +0 -191
  242. package/models/harvester/management.cattle.io.setting.js +0 -40
  243. package/models/harvester/network.harvesterhci.io.clusternetwork.js +0 -100
  244. package/models/harvester/network.harvesterhci.io.nodenetwork.js +0 -34
  245. package/models/harvester/node.js +0 -255
  246. package/models/harvester/persistentvolumeclaim.js +0 -166
  247. package/models/harvester/pod.js +0 -185
  248. package/pages/c/_cluster/harvester/airgapupgrade/index.vue +0 -309
  249. package/pages/c/_cluster/harvester/console/_uid/serial.vue +0 -51
  250. package/pages/c/_cluster/harvester/console/_uid/vnc.vue +0 -52
  251. package/pages/c/_cluster/harvester/index.vue +0 -24
  252. package/pages/c/_cluster/harvester/support/index.vue +0 -154
  253. package/pkg/model-loader.lib.js +0 -3
  254. package/promptRemove/kubevirt.io.virtualmachine.vue +0 -164
  255. package/store/harvester-common.js +0 -126
  256. package/utils/validators/vm-datavolumes.js +0 -38
  257. package/utils/validators/vm-image.js +0 -32
  258. package/utils/validators/vm.js +0 -221
package/core/plugins.js CHANGED
@@ -12,10 +12,12 @@ export default function({
12
12
  redirect
13
13
  }, inject) {
14
14
  const dynamic = {};
15
+ const validators = {};
15
16
  let _lastLoaded = 0;
16
17
 
17
18
  // Track which plugin loaded what, so we can unload stuff
18
19
  const plugins = {};
20
+
19
21
  const pluginRoutes = new PluginRoutes(app.router);
20
22
 
21
23
  inject('plugin', {
@@ -43,44 +45,69 @@ export default function({
43
45
  element.type = 'text/javascript';
44
46
  element.async = true;
45
47
 
46
- element.onload = () => {
47
- element.parentElement.removeChild(element);
48
+ // id is `<product>-<version>`.
49
+ const oldPlugin = Object.values(plugins).find(p => id.startsWith(p.name));
48
50
 
49
- if (!window[id]) {
50
- return reject(new Error('Could not load plugin code'));
51
- }
51
+ let removed = Promise.resolve();
52
+
53
+ if (oldPlugin) {
54
+ // Uninstall existing plugin if there is one. This ensures that last loaded plugin is not always used
55
+ // (nav harv1-->harv2-->harv1 and harv2 would be shown)
56
+ removed = this.removePlugin(oldPlugin.name).then(() => {
57
+ delete window[oldPlugin.id];
58
+
59
+ delete plugins[oldPlugin.id];
60
+ });
61
+ }
62
+
63
+ removed.then(() => {
64
+ element.onload = () => {
65
+ element.parentElement.removeChild(element);
66
+
67
+ if (!window[id]) {
68
+ return reject(new Error('Could not load plugin code'));
69
+ }
70
+
71
+ // Update the timestamp that new plugins were loaded - may be needed
72
+ // to update caches when new plugins are loaded
73
+ _lastLoaded = new Date().getTime();
74
+
75
+ // name is the name of the plugin, including the version number
76
+ const plugin = new Plugin(id);
52
77
 
53
- // Update the timestamp that new plugins were loaded - may be needed
54
- // to update caches when new plugins are loaded
55
- _lastLoaded = new Date().getTime();
78
+ plugins[id] = plugin;
56
79
 
57
- // TODO: Error if we are loading a plugin already loaded?
58
- // name is the name of the plugin, including the version number
59
- const plugin = new Plugin(id);
80
+ // Initialize the plugin
81
+ window[id].default(plugin, this.internal());
60
82
 
61
- plugins[id] = plugin;
83
+ // Uninstall existing plugin if there is one
84
+ this.removePlugin(plugin.name); // Removing this causes the plugin to not load on refresh
62
85
 
63
- // Initialize the plugin
64
- window[id].default(plugin, this.internal());
86
+ // Load all of the types etc from the plugin
87
+ this.applyPlugin(plugin);
65
88
 
66
- // Uninstall existing plugin if there is one
67
- this.removePlugin(plugin.name);
89
+ // Add the plugin to the store
90
+ store.dispatch('uiplugins/addPlugin', plugin);
68
91
 
69
- // Load all of the types etc from the plugin
70
- this.applyPlugin(plugin);
92
+ resolve();
93
+ };
71
94
 
72
- // Add the plugin to the store
73
- store.dispatch('uiplugins/addPlugin', plugin);
95
+ element.onerror = (e) => {
96
+ element.parentElement.removeChild(element);
97
+ // Massage the error into something useful
98
+ const errorMessage = `Failed to load script from '${ e.target.src }'`;
74
99
 
75
- resolve();
76
- };
100
+ console.error(errorMessage, e); // eslint-disable-line no-console
101
+ reject(new Error(errorMessage)); // This is more useful where it's used
102
+ };
77
103
 
78
- element.onerror = (e) => {
79
- element.parentElement.removeChild(element);
80
- reject(e);
81
- };
104
+ document.head.appendChild(element);
105
+ }).catch((e) => {
106
+ const errorMessage = `Failed to unload old plugin${ oldPlugin?.id }`;
82
107
 
83
- document.head.appendChild(element);
108
+ console.error(errorMessage, e); // eslint-disable-line no-console
109
+ reject(new Error(errorMessage)); // This is more useful where it's used
110
+ });
84
111
  });
85
112
  },
86
113
 
@@ -114,15 +141,17 @@ export default function({
114
141
  },
115
142
 
116
143
  // Remove the plugin
117
- removePlugin(name) {
144
+ async removePlugin(name) {
118
145
  const plugin = Object.values(plugins).find(p => p.name === name);
119
146
 
120
147
  if (!plugin) {
121
148
  return;
122
149
  }
123
150
 
151
+ const promises = [];
152
+
124
153
  plugin.productNames.forEach((product) => {
125
- store.dispatch('type-map/removeProduct', { product, plugin });
154
+ promises.push(store.dispatch('type-map/removeProduct', { product, plugin }));
126
155
  });
127
156
 
128
157
  // Remove all of the types
@@ -138,13 +167,13 @@ export default function({
138
167
 
139
168
  // Remove locales
140
169
  plugin.locales.forEach((localeObj) => {
141
- store.dispatch('i18n/removeLocale', localeObj);
170
+ promises.push(store.dispatch('i18n/removeLocale', localeObj));
142
171
  });
143
172
 
144
173
  if (plugin.types.models) {
145
174
  // Ask the Steve stores to forget any data it has for models that we are removing
146
- this.removeTypeFromStore(store, 'rancher', Object.keys(plugin.types.models));
147
- this.removeTypeFromStore(store, 'management', Object.keys(plugin.types.models));
175
+ promises.push(...this.removeTypeFromStore(store, 'rancher', Object.keys(plugin.types.models)));
176
+ promises.push(...this.removeTypeFromStore(store, 'management', Object.keys(plugin.types.models)));
148
177
  }
149
178
 
150
179
  // Uninstall routes
@@ -154,19 +183,24 @@ export default function({
154
183
  plugin.uninstallHooks.forEach(fn => fn(plugin, this.internal()));
155
184
 
156
185
  // Remove the plugin itself
157
- store.dispatch('uiplugins/removePlugin', name);
186
+ promises.push( store.dispatch('uiplugins/removePlugin', name));
158
187
 
159
188
  // Unregister vuex stores
160
189
  plugin.stores.forEach(pStore => pStore.unregister(store));
161
190
 
191
+ // Remove validators
192
+ Object.keys(plugin.validators).forEach((key) => {
193
+ delete validators[key];
194
+ });
195
+
196
+ await Promise.all(promises);
197
+
162
198
  // Update last load since we removed a plugin
163
199
  _lastLoaded = new Date().getTime();
164
200
  },
165
201
 
166
202
  removeTypeFromStore(store, storeName, types) {
167
- (types || []).forEach((type) => {
168
- store.commit(`${ storeName }/forgetType`, type);
169
- });
203
+ return (types || []).map(type => store.commit(`${ storeName }/forgetType`, type));
170
204
  },
171
205
 
172
206
  // Apply the plugin based on its metadata
@@ -200,6 +234,11 @@ export default function({
200
234
 
201
235
  // Routes
202
236
  pluginRoutes.addRoutes(plugin, plugin.routes);
237
+
238
+ // Validators
239
+ Object.keys(plugin.validators).forEach((key) => {
240
+ validators[key] = plugin.validators[key];
241
+ });
203
242
  },
204
243
 
205
244
  /**
@@ -252,6 +291,10 @@ export default function({
252
291
  return dynamic[typeName]?.[name];
253
292
  },
254
293
 
294
+ getValidator(name) {
295
+ return validators[name];
296
+ },
297
+
255
298
  // Timestamp that a UI package was last loaded
256
299
  // Typically used to invalidate caches (e.g. i18n) when new plugins are loaded
257
300
  get lastLoad() {
package/core/types.ts CHANGED
@@ -18,6 +18,7 @@ export interface PackageMetadata {
18
18
  export type VuexStoreObject = { [key: string]: any }
19
19
  export type CoreStoreSpecifics = { state: () => VuexStoreObject, getters: VuexStoreObject, mutations: VuexStoreObject, actions: VuexStoreObject }
20
20
  export type CoreStoreConfig = { namespace: string, baseUrl?: string, modelBaseClass?: string, supportsStream?: boolean, isClusterStore?: boolean }
21
+ export type CoreStoreInit = (store: any, ctx: any) => void;
21
22
  export type RegisterStore = () => (store: any) => void
22
23
  export type UnregisterStore = (store: any) => void
23
24
 
@@ -56,6 +57,11 @@ export interface IPlugin {
56
57
  */
57
58
  metadata: PackageMetadata;
58
59
 
60
+ /**
61
+ * Validators used in the same manner as shell/utils/custom-validators
62
+ */
63
+ validators: {[key: string]: Function};
64
+
59
65
  /**
60
66
  * Add a module contains localisations for a specific locale
61
67
  */
@@ -91,7 +97,7 @@ export interface IPlugin {
91
97
  * actions, will eventually call a `request` action which will make the raw http request. This is a pkg specific feature so needs the
92
98
  * `request` action needs to be supplied in the `storeSpecifics`
93
99
  */
94
- addDashboardStore(storeName: string, storeSpecifics: CoreStoreSpecifics, config: CoreStoreConfig): void;
100
+ addDashboardStore(storeName: string, storeSpecifics: CoreStoreSpecifics, config: CoreStoreConfig, init?: CoreStoreInit): void;
95
101
 
96
102
  /**
97
103
  * Add hooks that will execute when a user navigates
@@ -321,6 +321,18 @@ export default {
321
321
  return false;
322
322
  },
323
323
 
324
+ showEksNodeGroupWarning() {
325
+ if ( this.value.isEKS ) {
326
+ const desiredTotal = this.value.eksNodeGroups.filter(g => g.desiredSize === 0);
327
+
328
+ if ( desiredTotal.length === this.value.eksNodeGroups.length ) {
329
+ return true;
330
+ }
331
+ }
332
+
333
+ return false;
334
+ },
335
+
324
336
  machineHeaders() {
325
337
  return [
326
338
  STATE,
@@ -585,6 +597,7 @@ export default {
585
597
  <Loading v-if="$fetchState.pending" />
586
598
  <div v-else>
587
599
  <Banner v-if="showWindowsWarning" color="error" :label="t('cluster.banner.os', { newOS: 'Windows', existingOS: 'Linux' })" />
600
+ <Banner v-if="showEksNodeGroupWarning" color="error" :label="t('cluster.banner.desiredNodeGroupWarning')" />
588
601
 
589
602
  <Banner v-if="$fetchState.error" color="error" :label="$fetchState.error" />
590
603
  <ResourceTabs v-model="value" :default-tab="defaultTab">
@@ -120,6 +120,10 @@ export default {
120
120
  return this.value.type === WORKLOAD_TYPES.CRON_JOB;
121
121
  },
122
122
 
123
+ isPod() {
124
+ return this.value.type === WORKLOAD_TYPES.POD;
125
+ },
126
+
123
127
  podSchema() {
124
128
  return this.$store.getters['cluster/schemaFor'](POD);
125
129
  },
@@ -133,13 +137,15 @@ export default {
133
137
  },
134
138
 
135
139
  podTemplateSpec() {
136
- const isCronJob = this.value.type === WORKLOAD_TYPES.CRON_JOB;
137
-
138
- if ( isCronJob ) {
140
+ if ( this.value.type === WORKLOAD_TYPES.CRON_JOB ) {
139
141
  return this.value.spec.jobTemplate.spec.template.spec;
140
- } else {
141
- return this.value.spec?.template?.spec;
142
142
  }
143
+
144
+ if ( this.value.type === WORKLOAD_TYPES.POD ) {
145
+ return this.value;
146
+ }
147
+
148
+ return this.value.spec?.template?.spec;
143
149
  },
144
150
 
145
151
  container() {
File without changes
File without changes
@@ -67,6 +67,10 @@ export default {
67
67
 
68
68
  async fetch() {
69
69
  await this.reloadModel();
70
+
71
+ if ( this.value?.graphEndpoint ) {
72
+ this.setInitialEndpoint(this.value.graphEndpoint);
73
+ }
70
74
  },
71
75
 
72
76
  data() {
@@ -171,6 +175,16 @@ export default {
171
175
  }
172
176
  },
173
177
 
178
+ setInitialEndpoint(endpoint) {
179
+ const endpointKey = Object.keys(ENDPOINT_MAPPING).find(key => ENDPOINT_MAPPING[key].graphEndpoint === endpoint);
180
+
181
+ if ( endpointKey ) {
182
+ this.endpoint = endpointKey;
183
+ } else {
184
+ this.endpoint = 'custom';
185
+ }
186
+ },
187
+
174
188
  getNewApplicationSecret() {
175
189
  const applicationSecretOrId =
176
190
  this.model.applicationSecret || this.applicationSecret;
@@ -291,7 +305,7 @@ export default {
291
305
  <InfoBox v-if="!model.enabled" id="reply-info" class="mt-20 mb-20 p-10">
292
306
  {{ t('authConfig.azuread.reply.info') }}
293
307
  <br />
294
- <label>{{ t('authConfig.azuread.reply.label') }} </label>
308
+ <label class="reply-url">{{ t('authConfig.azuread.reply.label') }} </label>
295
309
  <CopyToClipboardText :plain="true" :text="replyUrl" />
296
310
  </InfoBox>
297
311
 
@@ -387,4 +401,9 @@ export default {
387
401
  #reply-info {
388
402
  flex-grow: 0;
389
403
  }
404
+
405
+ .reply-url {
406
+ color: inherit;
407
+ font-weight: 700;
408
+ }
390
409
  </style>
@@ -16,7 +16,7 @@ import { NAME } from '@shell/config/product/explorer';
16
16
  import { PROJECT_ID, _VIEW, _CREATE, _EDIT } from '@shell/config/query-params';
17
17
  import ProjectMembershipEditor from '@shell/components/form/Members/ProjectMembershipEditor';
18
18
  import { canViewProjectMembershipEditor } from '@shell/components/form/Members/ProjectMembershipEditor.vue';
19
- import { NAME as HARVESTER } from '@shell/config/product/harvester';
19
+ import { HARVESTER_NAME as HARVESTER } from '@shell/config/product/harvester-manager';
20
20
  import { Banner } from '@components/Banner';
21
21
 
22
22
  export default {
@@ -188,7 +188,7 @@ export default {
188
188
  <template>
189
189
  <CruResource
190
190
  class="project"
191
- :done-route="'c-cluster-product-projectsnamespaces'"
191
+ :done-route="value.listLocation"
192
192
  :errors="fvUnreportedValidationErrors"
193
193
  :mode="mode"
194
194
  :resource="value"
@@ -15,7 +15,7 @@ import MoveModal from '@shell/components/MoveModal';
15
15
  import ResourceQuota from '@shell/components/form/ResourceQuota/Namespace';
16
16
  import Loading from '@shell/components/Loading';
17
17
  import { HARVESTER_TYPES, RANCHER_TYPES } from '@shell/components/form/ResourceQuota/shared';
18
- import { NAME as HARVESTER } from '@shell/config/product/harvester';
18
+ import { HARVESTER_NAME as HARVESTER } from '@shell/config/product/harvester-manager';
19
19
 
20
20
  export default {
21
21
  components: {
@@ -34,9 +34,11 @@ export default {
34
34
  mixins: [CreateEditView],
35
35
 
36
36
  async fetch() {
37
- this.projects = await this.$store.dispatch('management/findAll', { type: MANAGEMENT.PROJECT });
37
+ if (this.$store.getters['management/schemaFor'](MANAGEMENT.PROJECT)) {
38
+ this.projects = await this.$store.dispatch('management/findAll', { type: MANAGEMENT.PROJECT });
38
39
 
39
- this.project = this.projects.find(p => p.id.includes(this.projectName));
40
+ this.project = this.projects.find(p => p.id.includes(this.projectName));
41
+ }
40
42
  },
41
43
 
42
44
  data() {
@@ -62,8 +64,9 @@ export default {
62
64
 
63
65
  computed: {
64
66
  ...mapGetters(['isSingleProduct']),
65
- isHarvester() {
66
- return this.$store.getters['currentProduct'].inStore === HARVESTER;
67
+
68
+ isSingleHarvester() {
69
+ return this.$store.getters['currentProduct'].inStore === HARVESTER && this.isSingleProduct;
67
70
  },
68
71
 
69
72
  projectOpts() {
@@ -93,7 +96,11 @@ export default {
93
96
  },
94
97
 
95
98
  showResourceQuota() {
96
- return Object.keys(this.project?.spec?.resourceQuota?.limit || {}).length > 0;
99
+ return !this.isSingleHarvester && Object.keys(this.project?.spec?.resourceQuota?.limit || {}).length > 0;
100
+ },
101
+
102
+ showContainerResourceLimit() {
103
+ return !this.isSingleHarvester;
97
104
  }
98
105
  },
99
106
 
@@ -160,13 +167,13 @@ export default {
160
167
  :namespaced="false"
161
168
  :mode="mode"
162
169
  >
163
- <template v-if="!isSingleProduct" #project-col>
170
+ <template v-if="project" #project-col>
164
171
  <LabeledSelect v-model="projectName" :label="t('namespace.project.label')" :options="projectOpts" />
165
172
  </template>
166
173
  </NameNsDescription>
167
174
 
168
175
  <Tabbed :side-tabs="true">
169
- <Tab v-if="!isSingleProduct && showResourceQuota" :weight="1" name="container-resource-quotas" :label="t('namespace.resourceQuotas')">
176
+ <Tab v-if="showResourceQuota" :weight="1" name="container-resource-quotas" :label="t('namespace.resourceQuotas')">
170
177
  <div class="row">
171
178
  <div class="col span-12">
172
179
  <p class="helper-text mb-10">
@@ -177,7 +184,7 @@ export default {
177
184
  </div>
178
185
  <ResourceQuota v-model="value" :mode="mode" :project="project" :types="isHarvester ? HARVESTER_TYPES : RANCHER_TYPES" />
179
186
  </Tab>
180
- <Tab v-if="!isSingleProduct" :weight="0" name="container-resource-limit" :label="t('namespace.containerResourceLimit')">
187
+ <Tab v-if="showContainerResourceLimit" :weight="0" name="container-resource-limit" :label="t('namespace.containerResourceLimit')">
181
188
  <ContainerResourceLimit
182
189
  :key="JSON.stringify(containerResourceLimits)"
183
190
  :value="containerResourceLimits"
@@ -200,6 +207,6 @@ export default {
200
207
  />
201
208
  </Tab>
202
209
  </Tabbed>
203
- <MoveModal />
210
+ <MoveModal v-if="projects" />
204
211
  </CruResource>
205
212
  </template>
@@ -269,6 +269,7 @@ export default {
269
269
  :output-modifier="true"
270
270
  :increment="1024"
271
271
  :min="1"
272
+ :required="true"
272
273
  />
273
274
  <Banner v-if="isEdit && !value.expandable" color="info" class="mt-10">
274
275
  {{ t('persistentVolumeClaim.expand.notSupported') }}
@@ -71,7 +71,7 @@ export default {
71
71
  const e = sanitizeValue(t.effect);
72
72
 
73
73
  if ( k && v && e ) {
74
- out.push(`--taint ${ k }=${ v }:${ e }`);
74
+ out.push(`--taints ${ k }=${ v }:${ e }`);
75
75
  }
76
76
  }
77
77
 
@@ -1,5 +1,4 @@
1
1
  <script>
2
-
3
2
  import { LabeledInput } from '@components/Form/LabeledInput';
4
3
  import { Checkbox } from '@components/Form/Checkbox';
5
4
  import { _EDIT } from '@shell/config/query-params';
@@ -64,11 +63,40 @@ export default {
64
63
 
65
64
  data() {
66
65
  const parseDuration = (duration) => {
67
- // The back end stores the timeout in Duration format, for example, "10m".
68
- // Here we convert that string to an integer.
69
- const numberString = duration.split('m')[0];
66
+ // The back end stores the timeout in Duration format, for example, "42d31h10m30s".
67
+ // Here we convert that string to an integer and return the duration as seconds.
68
+ const splitStr = duration.split(/([a-z])/);
69
+
70
+ const durationsAsSeconds = splitStr.reduce((old, neu, idx) => {
71
+ const parsed = parseInt(neu);
72
+
73
+ if ( isNaN(parsed) ) {
74
+ return old;
75
+ }
76
+
77
+ const interval = splitStr[(idx + 1)];
78
+
79
+ switch (interval) {
80
+ case 'd':
81
+ old.push(parsed * 24 * 60 * 60);
82
+ break;
83
+ case 'h':
84
+ old.push(parsed * 60 * 60);
85
+ break;
86
+ case 'm':
87
+ old.push(parsed * 60);
88
+ break;
89
+ case 's':
90
+ old.push(parsed);
91
+ break;
92
+ default:
93
+ break;
94
+ }
95
+
96
+ return old;
97
+ }, []);
70
98
 
71
- return parseInt(numberString, 10);
99
+ return durationsAsSeconds.reduce((old, neu) => old + neu);
72
100
  };
73
101
 
74
102
  return {
package/edit/service.vue CHANGED
@@ -22,7 +22,7 @@ import HarvesterServiceAddOnConfig from '@shell/components/HarvesterServiceAddOn
22
22
  import { clone } from '@shell/utils/object';
23
23
  import { POD, CAPI } from '@shell/config/types';
24
24
  import { matching } from '@shell/utils/selector';
25
- import { NAME as HARVESTER } from '@shell/config/product/harvester';
25
+ import { HARVESTER_NAME as HARVESTER } from '@shell/config/product/harvester-manager';
26
26
  import { allHash } from '@shell/utils/promise';
27
27
  import { isHarvesterSatisfiesVersion } from '@shell/utils/cluster';
28
28
  import { Port } from '@shell/utils/validators/formRules';