@rancher/shell 0.1.3 → 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 (245) hide show
  1. package/assets/brand/suse/dark/rancher-logo.svg +1 -148
  2. package/assets/brand/suse/favicon.png +0 -0
  3. package/assets/brand/suse/rancher-logo.svg +1 -130
  4. package/assets/images/featured/img1.jpg +0 -0
  5. package/assets/images/featured.jpg +0 -0
  6. package/assets/images/generic-plugin.svg +1 -0
  7. package/assets/styles/themes/_dark.scss +3 -0
  8. package/assets/styles/themes/_light.scss +3 -0
  9. package/assets/styles/themes/_suse.scss +1 -1
  10. package/assets/translations/en-us.yaml +219 -47
  11. package/assets/translations/zh-hans.yaml +21 -24
  12. package/components/AsyncButton.vue +17 -2
  13. package/components/ButtonDropdown.vue +4 -0
  14. package/components/Carousel.vue +291 -0
  15. package/components/CommunityLinks.vue +64 -22
  16. package/components/CruResource.vue +11 -3
  17. package/components/Dialog.vue +102 -0
  18. package/components/ExplorerMembers.vue +2 -4
  19. package/components/ExplorerProjectsNamespaces.vue +25 -9
  20. package/components/IconMessage.vue +9 -1
  21. package/components/LazyImage.vue +21 -8
  22. package/components/LocaleSelector.vue +62 -29
  23. package/components/PromptRemove.vue +2 -2
  24. package/components/ResourceList/Masthead.vue +21 -1
  25. package/components/ResourceList/ResourceLoadingIndicator.vue +0 -8
  26. package/components/ResourceList/index.vue +9 -23
  27. package/components/ResourceTable.vue +7 -2
  28. package/components/SimpleBox.vue +6 -4
  29. package/components/SortableTable/index.vue +18 -25
  30. package/components/Tabbed/Tab.vue +5 -0
  31. package/components/Tabbed/index.vue +54 -9
  32. package/components/TypeDescription.vue +10 -1
  33. package/components/auth/Principal.vue +1 -0
  34. package/components/fleet/FleetBundles.vue +8 -3
  35. package/components/fleet/FleetClusters.vue +6 -0
  36. package/components/fleet/FleetRepos.vue +7 -1
  37. package/components/fleet/FleetSummary.vue +6 -0
  38. package/components/form/Command.vue +5 -0
  39. package/components/form/EnvVars.vue +5 -0
  40. package/components/form/KeyValue.vue +80 -58
  41. package/components/form/NameNsDescription.vue +13 -5
  42. package/components/form/NodeScheduling.vue +6 -1
  43. package/components/form/PodAffinity.vue +5 -0
  44. package/components/form/ResourceTabs/index.vue +5 -1
  45. package/components/form/ServiceNameSelect.vue +5 -0
  46. package/components/form/ValueFromResource.vue +7 -1
  47. package/components/formatter/ClusterLink.vue +3 -7
  48. package/components/nav/NamespaceFilter.vue +3 -3
  49. package/components/nav/TopLevelMenu.vue +12 -29
  50. package/config/home-links.js +155 -0
  51. package/config/labels-annotations.js +2 -1
  52. package/config/private-label.js +1 -1
  53. package/config/product/explorer.js +5 -4
  54. package/config/product/legacy.js +0 -47
  55. package/config/product/manager.js +0 -2
  56. package/config/product/multi-cluster-apps.js +0 -12
  57. package/config/product/settings.js +12 -1
  58. package/config/product/uiplugins.js +17 -0
  59. package/config/settings.js +23 -2
  60. package/config/types.js +5 -1
  61. package/config/uiplugins.js +117 -0
  62. package/config/version.js +17 -0
  63. package/content/docs/en-us/getting-started.md +1 -26
  64. package/core/plugin.ts +12 -0
  65. package/core/plugins.js +38 -2
  66. package/core/types.ts +6 -0
  67. package/creators/app/{.eslintignore → files/.eslintignore} +0 -0
  68. package/creators/app/{.eslintrc.js → files/.eslintrc.js} +0 -0
  69. package/creators/app/{.vscode → files/.vscode}/settings.json +0 -0
  70. package/creators/app/{babel.config.js → files/babel.config.js} +0 -0
  71. package/creators/app/{nuxt.config.js → files/nuxt.config.js} +0 -0
  72. package/creators/app/{tsconfig.json → files/tsconfig.json} +2 -1
  73. package/creators/app/init +16 -17
  74. package/creators/app/package.json +6 -0
  75. package/creators/pkg/{babel.config.js → files/babel.config.js} +0 -0
  76. package/creators/pkg/{index.ts → files/index.ts} +0 -0
  77. package/creators/pkg/{tsconfig.json → files/tsconfig.json} +13 -12
  78. package/creators/pkg/{vue.config.js → files/vue.config.js} +0 -0
  79. package/creators/pkg/init +1 -1
  80. package/creators/update/init +54 -0
  81. package/creators/update/package.json +20 -0
  82. package/creators/update/upgrade +56 -0
  83. package/creators/update/yarn-error.log +54 -0
  84. package/detail/provisioning.cattle.io.cluster.vue +3 -3
  85. package/detail/workload/index.vue +3 -2
  86. package/dialog/DiagnosticTimingsDialog.vue +116 -0
  87. package/dialog/RotateCertificatesDialog.vue +9 -3
  88. package/edit/auth/azuread.vue +28 -9
  89. package/edit/networking.k8s.io.ingress/index.vue +2 -2
  90. package/edit/persistentvolume/index.vue +51 -13
  91. package/edit/persistentvolumeclaim.vue +31 -13
  92. package/edit/pod.vue +27 -0
  93. package/edit/provisioning.cattle.io.cluster/rke2.vue +103 -24
  94. package/edit/service.vue +7 -5
  95. package/edit/workload/__tests__/Upgrading.test.ts +1 -0
  96. package/edit/workload/index.vue +32 -10
  97. package/edit/workload/mixins/workload.js +121 -126
  98. package/edit/workload/storage/ContainerMountPaths.vue +240 -0
  99. package/edit/workload/storage/Mount.vue +1 -0
  100. package/edit/workload/storage/awsElasticBlockStore.vue +20 -1
  101. package/edit/workload/storage/azureDisk.vue +22 -2
  102. package/edit/workload/storage/azureFile.vue +20 -2
  103. package/edit/workload/storage/csi/index.vue +23 -1
  104. package/edit/workload/storage/gcePersistentDisk.vue +20 -2
  105. package/edit/workload/storage/index.vue +33 -65
  106. package/edit/workload/storage/persistentVolumeClaim/index.vue +5 -0
  107. package/edit/workload/storage/secret.vue +6 -1
  108. package/edit/workload/storage/vsphereVolume.vue +11 -1
  109. package/layouts/default.vue +14 -8
  110. package/layouts/home.vue +9 -4
  111. package/layouts/plain.vue +10 -5
  112. package/list/catalog.cattle.io.app.vue +10 -9
  113. package/list/catalog.cattle.io.clusterrepo.vue +6 -61
  114. package/list/cis.cattle.io.clusterscan.vue +12 -12
  115. package/list/fleet.cattle.io.bundle.vue +33 -28
  116. package/list/fleet.cattle.io.cluster.vue +26 -22
  117. package/list/fleet.cattle.io.clustergroup.vue +6 -0
  118. package/list/fleet.cattle.io.clusterregistrationtoken.vue +28 -24
  119. package/list/fleet.cattle.io.gitrepo.vue +25 -14
  120. package/list/helm.cattle.io.projecthelmchart.vue +52 -33
  121. package/list/logging.banzaicloud.io.clusterflow.vue +7 -12
  122. package/list/logging.banzaicloud.io.flow.vue +7 -14
  123. package/list/management.cattle.io.cluster.vue +26 -15
  124. package/list/management.cattle.io.feature.vue +13 -8
  125. package/list/management.cattle.io.setting.vue +3 -3
  126. package/list/management.cattle.io.user.vue +38 -19
  127. package/list/monitoring.coreos.com.alertmanagerconfig.vue +8 -15
  128. package/list/namespace.vue +14 -1
  129. package/list/node.vue +13 -16
  130. package/list/persistentvolume.vue +16 -9
  131. package/list/persistentvolumeclaim.vue +5 -8
  132. package/list/provisioning.cattle.io.cluster.vue +35 -9
  133. package/list/service.vue +24 -12
  134. package/list/ui.cattle.io.navlink.vue +6 -0
  135. package/list/workload.vue +2 -2
  136. package/machine-config/harvester.vue +5 -3
  137. package/middleware/authenticated.js +6 -0
  138. package/mixins/resource-fetch.js +12 -18
  139. package/mixins/resource-manager.js +126 -0
  140. package/models/catalog.cattle.io.uiplugin.js +38 -0
  141. package/models/cluster/node.js +25 -2
  142. package/models/fleet.cattle.io.bundle.js +1 -1
  143. package/models/harvesterhci.io.management.cluster.js +11 -5
  144. package/models/pod.js +15 -5
  145. package/models/provisioning.cattle.io.cluster.js +16 -6
  146. package/models/workload.js +5 -3
  147. package/models/workload.service.js +10 -0
  148. package/nuxt.config.js +70 -25
  149. package/package.json +108 -109
  150. package/pages/auth/login.vue +11 -1
  151. package/pages/auth/verify.vue +9 -0
  152. package/pages/c/_cluster/apps/charts/index.vue +46 -1
  153. package/pages/c/_cluster/apps/charts/install.vue +10 -9
  154. package/pages/c/_cluster/explorer/index.vue +72 -9
  155. package/pages/c/_cluster/explorer/tools/index.vue +12 -5
  156. package/pages/c/_cluster/mcapps/index.vue +1 -1
  157. package/pages/c/_cluster/settings/DefaultLinksEditor.vue +108 -0
  158. package/pages/c/_cluster/settings/brand.vue +0 -40
  159. package/pages/c/_cluster/settings/links.vue +152 -0
  160. package/pages/c/_cluster/settings/performance.vue +90 -7
  161. package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +232 -0
  162. package/pages/c/_cluster/uiplugins/InstallDialog.vue +293 -0
  163. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +300 -0
  164. package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +125 -0
  165. package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +261 -0
  166. package/pages/c/_cluster/uiplugins/UninstallDialog.vue +122 -0
  167. package/pages/c/_cluster/uiplugins/index.vue +808 -0
  168. package/pages/diagnostic.vue +185 -101
  169. package/pages/docs/_doc.vue +3 -1
  170. package/pages/home.vue +21 -56
  171. package/pages/prefs.vue +108 -88
  172. package/pages/safeMode.vue +17 -0
  173. package/pages/support/index.vue +34 -137
  174. package/pkg/dynamic-importer.lib.js +4 -0
  175. package/plugins/dashboard-store/actions.js +19 -0
  176. package/plugins/dashboard-store/getters.js +20 -3
  177. package/plugins/dashboard-store/mutations.js +13 -7
  178. package/plugins/dashboard-store/resource-class.js +2 -2
  179. package/plugins/formatters.js +15 -0
  180. package/plugins/plugin.js +61 -6
  181. package/plugins/steve/getters.js +12 -0
  182. package/plugins/steve/mutations.js +1 -1
  183. package/plugins/steve/subscribe.js +94 -72
  184. package/plugins/steve/web-worker.steve-sub-worker.js +24 -15
  185. package/plugins/version.js +21 -0
  186. package/promptRemove/management.cattle.io.globalrole.vue +47 -0
  187. package/promptRemove/management.cattle.io.roletemplate.vue +47 -0
  188. package/promptRemove/mixin/roleDeletionCheck.js +97 -0
  189. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +6 -7
  190. package/rancher-components/components/BadgeState/BadgeState.spec.ts +12 -0
  191. package/rancher-components/components/BadgeState/BadgeState.vue +107 -0
  192. package/rancher-components/components/BadgeState/index.ts +1 -0
  193. package/rancher-components/components/Banner/Banner.test.ts +13 -0
  194. package/rancher-components/components/Banner/Banner.vue +163 -0
  195. package/rancher-components/components/Banner/index.ts +1 -0
  196. package/rancher-components/components/Card/Card.vue +150 -0
  197. package/rancher-components/components/Card/index.ts +1 -0
  198. package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +77 -0
  199. package/rancher-components/components/Form/Checkbox/Checkbox.vue +395 -0
  200. package/rancher-components/components/Form/Checkbox/index.ts +1 -0
  201. package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +29 -0
  202. package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +343 -0
  203. package/rancher-components/components/Form/LabeledInput/index.ts +1 -0
  204. package/rancher-components/components/Form/Radio/RadioButton.vue +270 -0
  205. package/rancher-components/components/Form/Radio/RadioGroup.vue +235 -0
  206. package/rancher-components/components/Form/Radio/index.ts +2 -0
  207. package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +168 -0
  208. package/rancher-components/components/Form/TextArea/index.ts +1 -0
  209. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +107 -0
  210. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +137 -0
  211. package/rancher-components/components/Form/ToggleSwitch/index.ts +1 -0
  212. package/rancher-components/components/Form/index.ts +5 -0
  213. package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +137 -0
  214. package/rancher-components/components/LabeledTooltip/index.ts +1 -0
  215. package/scripts/publish-shell.sh +40 -7
  216. package/scripts/record-deps.js +37 -0
  217. package/scripts/sync-shell-deps +37 -0
  218. package/scripts/test-plugins-build.sh +8 -5
  219. package/scripts/typegen.sh +84 -0
  220. package/store/auth.js +3 -0
  221. package/store/catalog.js +9 -8
  222. package/store/i18n.js +10 -1
  223. package/store/index.js +12 -3
  224. package/store/prefs.js +16 -0
  225. package/store/type-map.js +32 -5
  226. package/store/uiplugins.ts +15 -61
  227. package/types/shell/index.d.ts +3046 -0
  228. package/utils/__tests__/object.test.ts +0 -24
  229. package/utils/__tests__/selector.test.ts +1 -1
  230. package/utils/dynamic-importer.js +4 -0
  231. package/utils/favicon.js +8 -2
  232. package/utils/gc/gc-interval.ts +40 -0
  233. package/utils/gc/gc-root-store.js +76 -0
  234. package/utils/gc/gc-route-changed.ts +44 -0
  235. package/utils/gc/gc-types.ts +21 -0
  236. package/utils/gc/gc.ts +282 -0
  237. package/utils/grafana.js +2 -6
  238. package/utils/socket.js +41 -20
  239. package/utils/string.js +1 -7
  240. package/utils/validators/formRules/__tests__/index.test.ts +108 -0
  241. package/utils/validators/formRules/index.ts +9 -1
  242. package/config/footer.js +0 -19
  243. package/creators/pkg/nuxt.config.js +0 -6
  244. package/pages/plugins.vue +0 -387
  245. package/server/verdaccio-middleware.js +0 -56
@@ -3,18 +3,19 @@ import { addObject, addObjects, clear, removeObject } from '@shell/utils/array';
3
3
  import { SCHEMA } from '@shell/config/types';
4
4
  import { normalizeType } from '@shell/plugins/dashboard-store/normalize';
5
5
  import { classify } from '@shell/plugins/dashboard-store/classify';
6
+ import garbageCollect from '@shell/utils/gc/gc';
6
7
 
7
8
  function registerType(state, type) {
8
9
  let cache = state.types[type];
9
10
 
10
11
  if ( !cache ) {
11
12
  cache = {
12
- list: [],
13
- haveAll: false,
14
- haveSelector: {},
15
- revision: 0, // The highest known resourceVersion from the server for this type
16
- generation: 0, // Updated every time something is loaded for this type
17
- loadCounter: 0, // Used to cancel incremental loads if the page changes during load
13
+ list: [],
14
+ haveAll: false,
15
+ haveSelector: {},
16
+ revision: 0, // The highest known resourceVersion from the server for this type
17
+ generation: 0, // Updated every time something is loaded for this type
18
+ loadCounter: 0, // Used to cancel incremental loads if the page changes during load
18
19
  };
19
20
 
20
21
  // Not enumerable so they don't get sent back to the client for SSR
@@ -120,6 +121,8 @@ export function forgetType(state, type) {
120
121
  cache.map.clear();
121
122
  delete state.types[type];
122
123
 
124
+ garbageCollect.gcResetType(state, type);
125
+
123
126
  return true;
124
127
  }
125
128
  }
@@ -131,6 +134,8 @@ export function resetStore(state, commit) {
131
134
  for ( const type of Object.keys(state.types) ) {
132
135
  commit(`${ state.config.namespace }/forgetType`, type);
133
136
  }
137
+
138
+ garbageCollect.gcResetStore(state);
134
139
  }
135
140
 
136
141
  export function remove(state, obj, getters) {
@@ -308,5 +313,6 @@ export default {
308
313
  if (typeData) {
309
314
  typeData.loadCounter++;
310
315
  }
311
- }
316
+ },
317
+
312
318
  };
@@ -9,7 +9,7 @@ import {
9
9
  AS,
10
10
  MODE
11
11
  } from '@shell/config/query-params';
12
- import { DEV } from '@shell/store/prefs';
12
+ import { VIEW_IN_API } from '@shell/store/prefs';
13
13
  import { addObject, addObjects, findBy, removeAt } from '@shell/utils/array';
14
14
  import CustomValidators from '@shell/utils/custom-validators';
15
15
  import { downloadFile, generateZip } from '@shell/utils/download';
@@ -966,7 +966,7 @@ export default class Resource {
966
966
  }
967
967
 
968
968
  get canViewInApi() {
969
- return this.hasLink('self') && this.$rootGetters['prefs/get'](DEV);
969
+ return this.hasLink('self') && this.$rootGetters['prefs/get'](VIEW_IN_API);
970
970
  }
971
971
 
972
972
  get canYaml() {
@@ -0,0 +1,15 @@
1
+ // This registers all of the built-in formatters into the SortableTable cache
2
+
3
+ // We do it here to keep it away from plugins
4
+ // It was in SortableTable itself, but this causes plugins to pull in all formatters and their dependencies
5
+
6
+ import { FORMATTERS } from '@shell/components/SortableTable';
7
+
8
+ const components = require.context('@shell/components/formatter', false, /[A-Z]\w+\.(vue)$/);
9
+
10
+ components.keys().forEach((fileName) => {
11
+ const componentConfig = components(fileName);
12
+ const componentName = fileName.split('/').pop().split('.')[0];
13
+
14
+ FORMATTERS[componentName] = componentConfig.default || componentConfig;
15
+ });
package/plugins/plugin.js CHANGED
@@ -1,10 +1,11 @@
1
- // This plugin loads any extensions at app load time
2
-
3
- import { allHash } from '@shell/utils/promise';
1
+ // This plugin loads any UI Plugins at app load time
2
+ import { allHashSettled } from '@shell/utils/promise';
3
+ import { shouldNotLoadPlugin, UI_PLUGIN_BASE_URL } from '@shell/config/uiplugins';
4
4
 
5
5
  const META_NAME_PREFIX = 'app-autoload-';
6
6
 
7
- export default async(context) => {
7
+ export default async function(context) {
8
+ // UI Plugins declared in the HTML head
8
9
  const meta = context.app?.head?.meta || [];
9
10
  const hash = {};
10
11
 
@@ -18,5 +19,59 @@ export default async(context) => {
18
19
  }
19
20
  });
20
21
 
21
- await allHash(hash);
22
- };
22
+ // Provide a mechanism to load the UI without the plugins loaded - in case there is a problem
23
+ let loadPlugins = true;
24
+
25
+ if (context.route?.path.endsWith('/safeMode')) {
26
+ loadPlugins = false;
27
+ console.warn('Safe Mode - plugins will not be loaded'); // eslint-disable-line no-console
28
+ }
29
+
30
+ if (loadPlugins) {
31
+ // TODO: Get rancher version using the new API (can't use setting as we have not loading the store)
32
+ const rancherVersion = undefined;
33
+
34
+ // Fetch list of installed plugins from endpoint
35
+ try {
36
+ const res = await context.store.dispatch('management/request', {
37
+ url: `${ UI_PLUGIN_BASE_URL }/index.json`,
38
+ method: 'GET',
39
+ headers: { accept: 'application/json' },
40
+ redirectUnauthorized: false,
41
+ });
42
+
43
+ if (res) {
44
+ const entries = res.entries || res.Entries || {};
45
+
46
+ Object.values(entries).forEach((plugin) => {
47
+ const shouldNotLoad = shouldNotLoadPlugin(plugin, rancherVersion); // Error key string or false
48
+
49
+ if (!shouldNotLoad) {
50
+ hash[plugin.name] = context.$plugin.loadPluginAsync(plugin);
51
+ } else {
52
+ context.store.dispatch('uiplugins/setError', { name: plugin.name, error: shouldNotLoad });
53
+ }
54
+ });
55
+ }
56
+ } catch (e) {
57
+ console.error('Could not load UI Plugin list', e); // eslint-disable-line no-console
58
+ }
59
+
60
+ // Load all of the plugins
61
+ const pluginLoads = await allHashSettled(hash);
62
+
63
+ // Some pluigns may have failed to load - store this
64
+ Object.keys(pluginLoads).forEach((name) => {
65
+ const res = pluginLoads[name];
66
+
67
+ if (res?.status === 'rejected') {
68
+ console.error(`Failed to load plugin: ${ name }`); // eslint-disable-line no-console
69
+
70
+ // Record error in the uiplugins store, so that we can show this to the user
71
+ context.store.dispatch('uiplugins/setError', { name, error: 'plugins.error.load' });
72
+ }
73
+ });
74
+ }
75
+
76
+ return true;
77
+ }
@@ -1,6 +1,7 @@
1
1
  import { isArray } from '@shell/utils/array';
2
2
  import { BY_TYPE } from '@shell/plugins/dashboard-store/classify';
3
3
  import { lookup } from '@shell/plugins/dashboard-store/model-loader';
4
+ import { NAMESPACE, SCHEMA, COUNT, UI } from '@shell/config/types';
4
5
 
5
6
  import SteveModel from './steve-class';
6
7
  import HybridModel, { cleanHybridResources } from './hybrid-class';
@@ -12,6 +13,13 @@ export const STEVE_MODEL_TYPES = {
12
13
  BY_TYPE: 'byType'
13
14
  };
14
15
 
16
+ const GC_IGNORE_TYPES = {
17
+ [COUNT]: true,
18
+ [NAMESPACE]: true,
19
+ [SCHEMA]: true,
20
+ [UI.NAV_LINK]: true,
21
+ };
22
+
15
23
  export default {
16
24
  urlOptions: () => (url, opt) => {
17
25
  opt = opt || {};
@@ -110,4 +118,8 @@ export default {
110
118
  return map?.list || [];
111
119
  },
112
120
 
121
+ gcIgnoreTypes: () => {
122
+ return GC_IGNORE_TYPES;
123
+ }
124
+
113
125
  };
@@ -64,7 +64,7 @@ export default {
64
64
 
65
65
  if (worker) {
66
66
  // Store raw json objects, not the proxies
67
- worker.loadSchema(data);
67
+ worker.postMessage({ loadSchemas: data });
68
68
  }
69
69
  }
70
70
  },
@@ -1,7 +1,7 @@
1
1
  import { addObject, clear, removeObject } from '@shell/utils/array';
2
2
  import { get } from '@shell/utils/object';
3
- import { COUNT, MANAGEMENT, SCHEMA } from '@shell/config/types';
4
- import { SETTING } from '@shell/config/settings';
3
+ import { COUNT, SCHEMA } from '@shell/config/types';
4
+ import { getPerformanceSetting } from '@shell/config/settings';
5
5
  import Socket, {
6
6
  EVENT_CONNECTED,
7
7
  EVENT_DISCONNECTED,
@@ -16,8 +16,7 @@ import { DATE_FORMAT, TIME_FORMAT } from '@shell/store/prefs';
16
16
  import { escapeHtml } from '@shell/utils/string';
17
17
 
18
18
  // eslint-disable-next-line
19
- import Worker from './web-worker.steve-sub-worker.js'
20
- import * as Comlink from 'comlink';
19
+ import webworker from './web-worker.steve-sub-worker.js';
21
20
 
22
21
  export const NO_WATCH = 'NO_WATCH';
23
22
  export const NO_SCHEMA = 'NO_SCHEMA';
@@ -25,9 +24,6 @@ export const NO_SCHEMA = 'NO_SCHEMA';
25
24
  // minimum length of time a disconnect notification is shown
26
25
  const MINIMUM_TIME_NOTIFIED = 3000;
27
26
 
28
- // minimum time a socket must be disconnected for before sending a growl
29
- const MINIMUM_TIME_DISCONNECTED = 10000;
30
-
31
27
  // We only create a worker for the cluster store
32
28
  export function createWorker(store, ctx) {
33
29
  const { getters } = ctx;
@@ -39,16 +35,33 @@ export function createWorker(store, ctx) {
39
35
  return;
40
36
  }
41
37
 
42
- function callback(resource) {
43
- queueChange(ctx, resource, true, 'Change');
44
- }
38
+ const workerActions = {
39
+ load: (resource) => {
40
+ queueChange(ctx, resource, true, 'Change');
41
+ },
42
+ destroyWorker: () => {
43
+ if (store.$workers) {
44
+ delete store.$workers[storeName];
45
+ }
46
+ }
47
+ };
45
48
 
46
49
  if (!store.$workers[storeName]) {
47
- const worker = Comlink.wrap(new Worker());
50
+ const worker = new webworker();
48
51
 
49
52
  store.$workers[storeName] = worker;
50
53
 
51
- worker.initWorker(storeName, Comlink.proxy(callback));
54
+ worker.postMessage({ initWorker: { storeName } });
55
+
56
+ store.$workers[storeName].onmessage = (e) => {
57
+ /* on the off chance there's more than key in the message, we handle them in the order that they "keys" method provides which is
58
+ // good enough for now considering that we never send more than one message action at a time right now */
59
+ const messageActions = Object.keys(e?.data);
60
+
61
+ messageActions.forEach((action) => {
62
+ workerActions[action](e?.data[action]);
63
+ });
64
+ };
52
65
  }
53
66
  }
54
67
 
@@ -119,6 +132,10 @@ function queueChange({ getters, state }, { data, revision }, load, label) {
119
132
  }
120
133
  }
121
134
 
135
+ function growlsDisabled(rootGetters) {
136
+ return getPerformanceSetting(rootGetters)?.disableWebsocketNotification;
137
+ }
138
+
122
139
  export const actions = {
123
140
  subscribe(ctx, opt) {
124
141
  const {
@@ -145,7 +162,9 @@ export const actions = {
145
162
  socket.setAutoReconnect(true);
146
163
  socket.setUrl(url);
147
164
  } else {
148
- socket = new Socket(`${ state.config.baseUrl }/subscribe`);
165
+ const maxTries = growlsDisabled(rootGetters) ? null : 3;
166
+
167
+ socket = new Socket(`${ state.config.baseUrl }/subscribe`, true, null, null, maxTries);
149
168
 
150
169
  commit('setSocket', socket);
151
170
  socket.addEventListener(EVENT_CONNECTED, (e) => {
@@ -177,24 +196,17 @@ export const actions = {
177
196
  });
178
197
  }
179
198
 
180
- socket.connect(get(opt, 'metadata'));
199
+ socket.connect(get(opt, 'metadata') );
181
200
  },
182
201
 
183
- unsubscribe({ state, commit, getters }) {
202
+ unsubscribe({ commit, getters, state }) {
184
203
  const socket = state.socket;
185
204
  const worker = (this.$workers || {})[getters.storeName];
186
205
 
187
206
  commit('setWantSocket', false);
188
207
 
189
208
  if (worker) {
190
- try {
191
- worker.destroyWorker();
192
- worker[Comlink.releaseProxy]();
193
- } catch (e) {
194
- console.error(e); // eslint-disable-line no-console
195
- }
196
-
197
- delete this.$workers[getters.storeName];
209
+ worker.postMessage({ destroyWorker: true }); // we're only passing the boolean here because the key needs to be something truthy to ensure it's passed on the object.
198
210
  }
199
211
 
200
212
  if ( socket ) {
@@ -396,8 +408,10 @@ export const actions = {
396
408
  commit, dispatch, state, getters, rootGetters
397
409
  }, event) {
398
410
  state.debugSocket && console.info(`WebSocket Opened [${ getters.storeName }]`); // eslint-disable-line no-console
399
-
400
411
  const socket = event.currentTarget;
412
+ const tries = event?.detail?.tries; // have to pull it off of the event because the socket's tries is already reset to 0
413
+ const t = rootGetters['i18n/t'];
414
+ const disableGrowl = growlsDisabled(rootGetters);
401
415
 
402
416
  this.$socket = socket;
403
417
 
@@ -420,19 +434,16 @@ export const actions = {
420
434
  if ( socket.hasReconnected ) {
421
435
  await dispatch('reconnectWatches');
422
436
  // Check for disconnect notifications and clear them
423
- const growlErr = rootGetters['growl/find']({ key: 'url', val: this.$socket.url });
437
+ const growlErr = rootGetters['growl/find']({ key: 'url', val: socket.url });
424
438
 
425
439
  if (growlErr) {
426
- const now = Date.now();
427
-
428
- // even if the socket reconnected, keep the error growl for at least a few seconds to ensure its readable
429
- if (now >= growlErr.earliestClose) {
430
- dispatch('growl/remove', growlErr.id, { root: true });
431
- } else {
432
- setTimeout(() => {
433
- dispatch('growl/remove', growlErr.id, { root: true });
434
- }, growlErr.earliestClose - now);
435
- }
440
+ dispatch('growl/remove', growlErr.id, { root: true });
441
+ }
442
+ if (tries > 1 && !disableGrowl) {
443
+ dispatch('growl/success', {
444
+ title: t('growl.reconnected.title'),
445
+ message: t('growl.reconnected.message', { url: this.$socket.url, tries }),
446
+ }, { root: true });
436
447
  }
437
448
  }
438
449
 
@@ -456,42 +467,53 @@ export const actions = {
456
467
  }, e) {
457
468
  clearTimeout(state.queueTimer);
458
469
  state.queueTimer = null;
459
- if (e.type === EVENT_DISCONNECT_ERROR) {
460
- // determine if websocket notifications are disabled
461
- const perfSetting = rootGetters['management/byId'](MANAGEMENT.SETTING, SETTING.UI_PERFORMANCE);
462
- let disableGrowl = false;
463
470
 
464
- if ( perfSetting?.value ) {
465
- disableGrowl = JSON.parse(perfSetting.value).disableWebsocketNotification || false;
466
- }
471
+ // determine if websocket notifications are disabled
472
+ const disableGrowl = growlsDisabled(rootGetters);
467
473
 
468
- if ( !disableGrowl ) {
469
- // do not send a growl notification unless the socket stays disconnected for more than MINIMUM_TIME_DISCONNECTED
470
- setTimeout(() => {
471
- if (state.socket.isConnected()) {
472
- return;
473
- }
474
- const dateFormat = escapeHtml( rootGetters['prefs/get'](DATE_FORMAT));
475
- const timeFormat = escapeHtml( rootGetters['prefs/get'](TIME_FORMAT));
476
- const time = e?.srcElement?.disconnectedAt || Date.now();
477
-
478
- const timeFormatted = `${ day(time).format(`${ dateFormat } ${ timeFormat }`) }`;
479
- const url = e?.srcElement?.url;
480
-
481
- const t = rootGetters['i18n/t'];
482
-
483
- dispatch('growl/error', {
484
- title: t('growl.disconnected.title'),
485
- message: t('growl.disconnected.message', { url, time: timeFormatted }, { raw: true }),
486
- icon: 'error',
487
- earliestClose: time + MINIMUM_TIME_NOTIFIED + MINIMUM_TIME_DISCONNECTED,
488
- url
489
- }, { root: true });
490
- }, MINIMUM_TIME_DISCONNECTED);
474
+ if (!disableGrowl) {
475
+ const dateFormat = escapeHtml( rootGetters['prefs/get'](DATE_FORMAT));
476
+ const timeFormat = escapeHtml( rootGetters['prefs/get'](TIME_FORMAT));
477
+ const time = e?.srcElement?.disconnectedAt || Date.now();
478
+
479
+ const timeFormatted = `${ day(time).format(`${ dateFormat } ${ timeFormat }`) }`;
480
+ const url = e?.srcElement?.url;
481
+ const tries = state?.socket?.tries;
482
+
483
+ const t = rootGetters['i18n/t'];
484
+
485
+ const growlErr = rootGetters['growl/find']({ key: 'url', val: url });
486
+
487
+ if (e.type === EVENT_CONNECT_ERROR) { // if this occurs, then we're at least retrying to connect
488
+ if (growlErr) {
489
+ dispatch('growl/remove', growlErr.id, { root: true });
490
+ }
491
+ dispatch('growl/error', {
492
+ title: t('growl.connectError.title'),
493
+ message: t('growl.connectError.message', {
494
+ url, time: timeFormatted, tries
495
+ }, { raw: true }),
496
+ icon: 'error',
497
+ earliestClose: time + MINIMUM_TIME_NOTIFIED,
498
+ url
499
+ }, { root: true });
500
+ } else if (e.type === EVENT_DISCONNECT_ERROR) { // if this occurs, we've given up on trying to reconnect
501
+ if (growlErr) {
502
+ dispatch('growl/remove', growlErr.id, { root: true });
503
+ }
504
+ dispatch('growl/error', {
505
+ title: t('growl.disconnectError.title'),
506
+ message: t('growl.disconnectError.message', {
507
+ url, time: timeFormatted, tries
508
+ }, { raw: true }),
509
+ icon: 'error',
510
+ earliestClose: time + MINIMUM_TIME_NOTIFIED,
511
+ url
512
+ }, { root: true });
513
+ } else {
514
+ // if the error is not a connect error or disconnect error, the socket never worked: log whether the current browser is safari
515
+ console.error(`WebSocket Connection Error [${ getters.storeName }]`, e.detail); // eslint-disable-line no-console
491
516
  }
492
- } else {
493
- // if the error is not a disconnect error, the socket never worked: log whether the current browser is safari
494
- console.error(`WebSocket Connection Error [${ getters.storeName }]`, e.detail); // eslint-disable-line no-console
495
517
  }
496
518
  },
497
519
 
@@ -583,7 +605,7 @@ export const actions = {
583
605
  const worker = (this.$workers || {})[ctx.getters.storeName];
584
606
 
585
607
  if (worker) {
586
- worker.countsUpdate(msg);
608
+ worker.postMessage({ countsUpdate: msg });
587
609
 
588
610
  // No further processing - let the web worker debounce the counts
589
611
  return;
@@ -596,7 +618,7 @@ export const actions = {
596
618
  const worker = (this.$workers || {})[ctx.getters.storeName];
597
619
 
598
620
  if (worker) {
599
- worker.updateSchema(data);
621
+ worker.postMessage({ updateSchema: data });
600
622
 
601
623
  // No further processing - let the web worker check the schema updates
602
624
  return;
@@ -631,7 +653,7 @@ export const actions = {
631
653
  const worker = (this.$workers || {})[ctx.getters.storeName];
632
654
 
633
655
  if (worker) {
634
- worker.removeSchema(data.id);
656
+ worker.postMessage({ removeSchema: data.id });
635
657
  }
636
658
  }
637
659
 
@@ -712,7 +734,7 @@ export const mutations = {
712
734
  clear(state.started);
713
735
  clear(state.pendingFrames);
714
736
  clear(state.queue);
715
- clearInterval(state.queueTimer);
737
+ clearTimeout(state.queueTimer);
716
738
  state.deferredRequests = {};
717
739
  state.queueTimer = null;
718
740
  }
@@ -1,4 +1,3 @@
1
- import * as Comlink from 'comlink';
2
1
  import { SCHEMA } from '@shell/config/types';
3
2
 
4
3
  const COUNTS_FLUSH_TIMEOUT = 5000;
@@ -6,7 +5,6 @@ const SCHEMA_FLUSH_TIMEOUT = 2500;
6
5
 
7
6
  const state = {
8
7
  store: '', // Store name
9
- load: undefined, // Load callback to load a resource into the store
10
8
  counts: [], // Buffer of count resources recieved in a given window
11
9
  countTimer: undefined, // Tiemr to flush the count buffer
12
10
  flushTimer: undefined, // Timer to flush the schema chaneg queue
@@ -61,22 +59,33 @@ state.flushTimer = setTimeout(flush, SCHEMA_FLUSH_TIMEOUT);
61
59
 
62
60
  // Callback to the store's load function (in the main thread) to process a load
63
61
  function load(data) {
64
- if (state.load) {
65
- state.load(data);
66
- }
62
+ self.postMessage({ load: data });
67
63
  }
68
64
 
69
- // Web Worker API
70
- const fns = {
71
- initWorker(storeName, loadFn) {
65
+ const workerActions = {
66
+ onmessage: (e) => {
67
+ /* on the off chance there's more than key in the message, we handle them in the order that they "keys" method provides which is
68
+ // good enough for now considering that we never send more than one message action at a time right now */
69
+ const messageActions = Object.keys(e?.data);
70
+
71
+ messageActions.forEach((action) => {
72
+ if (workerActions[action]) {
73
+ workerActions[action](e?.data[action]);
74
+ } else {
75
+ console.warn('no associated action for:', action); // eslint-disable-line no-console
76
+ }
77
+ });
78
+ },
79
+ initWorker: ({ storeName }) => {
72
80
  state.store = storeName;
73
- state.load = loadFn;
74
81
  },
75
82
 
76
- destroyWorker() {
83
+ destroyWorker: () => {
77
84
  clearTimeout(state.countTimer);
78
85
  clearTimeout(state.flushTimer);
79
86
 
87
+ self.postMessage({ destroyWorker: true }); // we're only passing the boolean here because the key needs to be something truthy to ensure it's passed on the object.
88
+
80
89
  // Web worker global function to terminate the web worker
81
90
  close();
82
91
  },
@@ -98,7 +107,7 @@ const fns = {
98
107
  },
99
108
 
100
109
  // Called to load schema
101
- loadSchema(schemas) {
110
+ loadSchemas: (schemas) => {
102
111
  schemas.forEach((schema) => {
103
112
  // These properties are added to the object, but aren't on the raw object, so remove them
104
113
  // otherwise our comparison will show changes when there aren't any
@@ -107,16 +116,17 @@ const fns = {
107
116
 
108
117
  state.schemas[schema.id] = hashObj(schema);
109
118
  });
119
+ // console.log(JSON.parse(JSON.stringify(state.resources.schemas)));
110
120
  },
111
121
 
112
122
  // Called when schema is updated
113
- updateSchema(schema) {
123
+ updateSchema: (schema) => {
114
124
  // Add the schema to the queue to be checked to see if the schema really changed
115
125
  state.queue.push(schema);
116
126
  },
117
127
 
118
128
  // Remove the cached schema
119
- removeSchema(id) {
129
+ removeSchema: (id) => {
120
130
  // Remove anything in the queue related to the schema - we don't want to send any pending updates later for a schema that has been removed
121
131
  state.queue = state.queue.filter(schema => schema.id !== id);
122
132
 
@@ -125,5 +135,4 @@ const fns = {
125
135
  }
126
136
  };
127
137
 
128
- // Expose the Web Worker API - see: https://github.com/GoogleChromeLabs/comlink
129
- Comlink.expose(fns);
138
+ onmessage = workerActions.onmessage; // bind everything to the worker's onmessage handler via the workerAction
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Fetch version metadata from backend /rancherversion API and store it
3
+ *
4
+ * This metadata does not change for an installation of Rancher
5
+ */
6
+
7
+ import { setVersionData } from '@shell/config/version';
8
+
9
+ export default async function({ store }) {
10
+ try {
11
+ const response = await store.dispatch('rancher/request', {
12
+ url: '/rancherversion',
13
+ method: 'get',
14
+ redirectUnauthorized: false
15
+ });
16
+
17
+ setVersionData(response);
18
+ } catch (e) {
19
+ console.warn('Failed to fetch Rancher version metadata', e); // eslint-disable-line no-console
20
+ }
21
+ }
@@ -0,0 +1,47 @@
1
+ <script>
2
+ import RoleDeletionCheck from '@shell/promptRemove/mixin/roleDeletionCheck';
3
+ export default {
4
+ name: 'GlobalRolePromptRemove',
5
+ mixins: [RoleDeletionCheck],
6
+ props: {
7
+ value: {
8
+ type: Array,
9
+ default: () => {
10
+ return [];
11
+ }
12
+ },
13
+
14
+ type: {
15
+ type: String,
16
+ required: true
17
+ }
18
+ },
19
+ };
20
+ </script>
21
+
22
+ <template>
23
+ <div>
24
+ <template>
25
+ {{ t('promptRemove.attemptingToRemove', { type }) }} <span
26
+ v-html="resourceNames(names, plusMore, t)"
27
+ ></span>
28
+ </template>
29
+ <div v-if="info" class="text info mb-10 mt-20">
30
+ <span v-html="info" />
31
+ </div>
32
+ <div v-if="warning" class="text-warning mb-10 mt-20">
33
+ {{ warning }}
34
+ </div>
35
+ </div>
36
+ </template>
37
+
38
+ <style lang="scss" scoped>
39
+ .text.info {
40
+ display: flex;
41
+ align-items: center;
42
+
43
+ > span {
44
+ margin-right: 5px;
45
+ }
46
+ }
47
+ </style>