@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
@@ -38,18 +38,6 @@ describe('fx: get', () => {
38
38
  expect(result).toBeUndefined();
39
39
  expect(() => result).not.toThrow();
40
40
  });
41
-
42
- it.each([
43
- 'key2.nonsense',
44
- 'non.sense',
45
- ])('should catch error and return undefined', (path) => {
46
- const obj = { key1: 'value', key2: { bat: 42, 'with.dots': 43 } };
47
-
48
- const result = get(obj, path);
49
-
50
- expect(result).toBeUndefined();
51
- expect(() => result).not.toThrow();
52
- });
53
41
  });
54
42
 
55
43
  describe('fx: getter', () => {
@@ -95,18 +83,6 @@ describe('fx: getter', () => {
95
83
  expect(result).toBeUndefined();
96
84
  expect(() => result).not.toThrow();
97
85
  });
98
-
99
- it.each([
100
- 'key2.nonsense',
101
- 'non.sense',
102
- ])('should catch error and return undefined', (path) => {
103
- const obj = { key1: 'value', key2: { bat: 42, 'with.dots': 43 } };
104
-
105
- const result = getter(path)(obj);
106
-
107
- expect(result).toBeUndefined();
108
- expect(() => result).not.toThrow();
109
- });
110
86
  });
111
87
  });
112
88
 
@@ -171,7 +171,7 @@ describe('fx: parse', () => {
171
171
  ['!some.prefix/key-bar_baz '],
172
172
  ['! some.prefix/key-bar_baz '],
173
173
  [' ! some.prefix/key-bar_baz '],
174
- ])('should parse expression %p to selector %p', (expression) => {
174
+ ])('should parse expression %p to selector %p using prefixes', (expression) => {
175
175
  const expected = {
176
176
  key: 'some.prefix/key-bar_baz',
177
177
  operator: 'DoesNotExist',
@@ -107,6 +107,10 @@ export function resolveList(key) {
107
107
  return require.resolve(`@shell/list/${ key }`);
108
108
  }
109
109
 
110
+ export function resolveChart(key) {
111
+ return require.resolve(`@shell/chart/${ key }`);
112
+ }
113
+
110
114
  export function resolveEdit(key) {
111
115
  return require.resolve(`@shell/edit/${ key }`);
112
116
  }
package/utils/favicon.js CHANGED
@@ -10,11 +10,17 @@ export function haveSetFavIcon() {
10
10
  export function setFavIcon(store) {
11
11
  const app = store.app;
12
12
  const res = store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.FAVICON);
13
-
13
+ const brandSetting = store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.BRAND);
14
14
  const link = findIconLink(app.head.link);
15
15
 
16
16
  if (link) {
17
- link.href = res?.value || defaultFavIcon;
17
+ let brandImage;
18
+
19
+ if (brandSetting?.value === 'suse') {
20
+ brandImage = require('~shell/assets/brand/suse/favicon.png');
21
+ }
22
+
23
+ link.href = res?.value || brandImage || defaultFavIcon;
18
24
  favIconSet = true;
19
25
  }
20
26
  }
@@ -0,0 +1,40 @@
1
+ import gc from './gc';
2
+
3
+ /**
4
+ * Kick of regular GC
5
+ */
6
+ class GarbageCollectInterval {
7
+ private gcInterval?: NodeJS.Timer;
8
+
9
+ /**
10
+ * Request we start garbage collection at regular intervals
11
+ *
12
+ * If GC is disabled or running return early
13
+ */
14
+ gcStartIntervals(ctx: any) {
15
+ const { enabled, interval } = gc.gcEnabledInterval(ctx);
16
+
17
+ if (!gc.gcEnabledSetting(ctx) || !enabled) {
18
+ return;
19
+ }
20
+
21
+ if (this.gcInterval) {
22
+ return;
23
+ }
24
+
25
+ this.gcInterval = setInterval(() => {
26
+ ctx.dispatch('garbageCollect'); // gc.garbageCollect is per store, so dispatch via central point
27
+ }, interval * 1000);
28
+ }
29
+
30
+ gcStopIntervals() {
31
+ if (this.gcInterval) {
32
+ clearInterval(this.gcInterval);
33
+ delete this.gcInterval;
34
+ }
35
+ }
36
+ }
37
+
38
+ const gci = new GarbageCollectInterval();
39
+
40
+ export default gci;
@@ -0,0 +1,76 @@
1
+ import gc from './gc';
2
+ import gcInterval from './gc-interval';
3
+ import gcRoute from './gc-route-changed';
4
+
5
+ export const gcGetters = {
6
+ /**
7
+ * Fetch all stores that support garbage collection
8
+ */
9
+ gcStores(state) {
10
+ // It would be nice to grab all vuex module stores that we've registered, apparently this is only possible via the
11
+ // internal properties store._modules.root._children.
12
+ // So instead loop through all state entries to find the gc stores
13
+ return Object.entries(state).filter(([storeName, storeState]) => {
14
+ if (typeof (storeState) !== 'object') {
15
+ return;
16
+ }
17
+
18
+ if (!gc.gcEnabledForStore(storeState)) {
19
+ return;
20
+ }
21
+
22
+ return true;
23
+ });
24
+ }
25
+ };
26
+
27
+ export const gcActions = {
28
+ gcPreferencesUpdated({ dispatch }, { previouslyEnabled, newPreferences }) {
29
+ // Always stop the interval
30
+ // - GC Disabled, so it needs to stop
31
+ // - GC Enabled, we need to pick up new settings
32
+ dispatch('gcStopIntervals', { root: true });
33
+
34
+ if (newPreferences.enabled) {
35
+ // Cater for functionality that we get when the app loads
36
+ dispatch('gcStartIntervals', { root: true });
37
+ } else if (previouslyEnabled) {
38
+ // If we're going from enabled --> disabled we should reset any gc state we have stored. This avoids...
39
+ // - Last accessed times are stored
40
+ // - GC disabled so we don't update last accessed times
41
+ // - GC enabled and we have stale accessed times in the store
42
+ dispatch('gcResetStores', { root: true });
43
+ }
44
+ },
45
+
46
+ gcRouteChanged(ctx, to) {
47
+ gcRoute.gcRouteChanged(ctx, to);
48
+ },
49
+
50
+ gcStartIntervals(ctx) {
51
+ gcInterval.gcStartIntervals(ctx);
52
+ },
53
+
54
+ gcStopIntervals(ctx) {
55
+ gcInterval.gcStopIntervals();
56
+ },
57
+
58
+ gcResetStores({ dispatch, getters }) {
59
+ getters.gcStores.forEach(([storeName, storeState]) => {
60
+ dispatch(`${ storeName }/gcResetStore`);
61
+ });
62
+ },
63
+
64
+ /**
65
+ * Kick of a GC in all stores that support it
66
+ */
67
+ garbageCollect({ rootState, dispatch, getters }, ignoreTypes) {
68
+ if (!gc.gcEnabledSetting({ rootState })) {
69
+ return;
70
+ }
71
+
72
+ getters.gcStores.forEach(([storeName, storeState]) => {
73
+ dispatch(`${ storeName }/garbageCollect`, ignoreTypes);
74
+ });
75
+ }
76
+ };
@@ -0,0 +1,44 @@
1
+ import gc from './gc';
2
+
3
+ function getResourceFromRoute(to: any) {
4
+ let resource = to.params?.resource;
5
+
6
+ if ( !resource ) {
7
+ const match = to.name?.match(/^c-cluster-([^-]+)/);
8
+
9
+ if ( match ) {
10
+ resource = match[2];
11
+ }
12
+ }
13
+
14
+ return resource;
15
+ }
16
+
17
+ /**
18
+ * Handle GC on route change (given settings this might be a no-op)
19
+ */
20
+ class GarbageCollectRouteChanged {
21
+ /**
22
+ * A logged in route has changed
23
+ * 1) Track the time this occurred to ensure any resources fetched afterwards are not GCd
24
+ * 2) Kick off a GC
25
+ */
26
+ gcRouteChanged(ctx: any, to: any) {
27
+ gc.gcUpdateRouteChanged();
28
+ // commit(`gcRouteChanged`);
29
+
30
+ if (!gc.gcEnabledSetting(ctx) || !gc.gcEnabledRoute(ctx) || to.name === 'auth-logout') {
31
+ // (auth-logout convenience, no point GC'ing if we've just lost all types)
32
+ return;
33
+ }
34
+
35
+ const resource = getResourceFromRoute(to);
36
+ const ignoreTYpes = !!resource ? { [resource]: true } : {};
37
+
38
+ ctx.dispatch('garbageCollect', ignoreTYpes); // gc.garbageCollect is per store, so dispatch via central point
39
+ }
40
+ }
41
+
42
+ const gcrc = new GarbageCollectRouteChanged();
43
+
44
+ export default gcrc;
@@ -0,0 +1,21 @@
1
+ export type GC_PREFERENCES = {
2
+ enabled: boolean,
3
+ enabledInterval: boolean,
4
+ interval: number,
5
+ enabledOnNavigate: boolean,
6
+ ageThreshold: number,
7
+ countThreshold: number
8
+ }
9
+
10
+ export const GC_DEFAULTS: GC_PREFERENCES = {
11
+ enabled: false,
12
+
13
+ // When GC Runs
14
+ enabledInterval: true,
15
+ interval: 1 * 60 * 5,
16
+ enabledOnNavigate: true,
17
+
18
+ // How GC handles resources when GC'ing
19
+ ageThreshold: 1 * 60 * 2,
20
+ countThreshold: 500,
21
+ };
package/utils/gc/gc.ts ADDED
@@ -0,0 +1,282 @@
1
+ import { SETTING } from '@shell/config/settings';
2
+ import { COUNT, MANAGEMENT } from '@shell/config/types';
3
+ import { GC_DEFAULTS, GC_PREFERENCES } from './gc-types';
4
+
5
+ class GarbageCollect {
6
+ private static ENABLE_DEBUG_LOGGING = false;
7
+
8
+ /**
9
+ * Don't run GC if it's been run within 5 seconds
10
+ */
11
+ private static GC_RE_RUN_GAP = 1000 * 5;
12
+
13
+ private cachedGcPrefs: GC_PREFERENCES = GC_DEFAULTS;
14
+
15
+ private cachedGcPrefsStamp: string = '';
16
+
17
+ private debugLog = (...args: any) => {
18
+ if (GarbageCollect.ENABLE_DEBUG_LOGGING) {
19
+ console.debug('GC', ...args); // eslint-disable-line no-console
20
+ }
21
+ };
22
+
23
+ /**
24
+ * Time the GC last ran
25
+ */
26
+ private gcLastRun: number | null = 0;
27
+
28
+ /**
29
+ * To avoid JSON.parse on the `ui-performance` setting keep a local cache
30
+ */
31
+ private getUiPerfGarbageCollection = (rootState: any) => {
32
+ const uiPerfSetting = rootState.management.types[MANAGEMENT.SETTING].list.find((s: any) => s.id === SETTING.UI_PERFORMANCE);
33
+
34
+ if (!uiPerfSetting || !uiPerfSetting.value) {
35
+ // Could be in the process of logging out
36
+ return undefined;
37
+ }
38
+ const stamp = `${ uiPerfSetting.metadata.generation }-${ uiPerfSetting.metadata.resourceVersion }`;
39
+
40
+ if (this.cachedGcPrefsStamp !== stamp) {
41
+ this.debugLog(`Updating ${ SETTING.UI_PERFORMANCE } cache`);
42
+ this.cachedGcPrefsStamp = stamp;
43
+ const uiPerfSettingParsed = JSON.parse(uiPerfSetting.value);
44
+
45
+ this.cachedGcPrefs = uiPerfSettingParsed.garbageCollection;
46
+ }
47
+
48
+ return this.cachedGcPrefs;
49
+ };
50
+
51
+ /**
52
+ * The last time a resource was accessed by either find or getters style functions
53
+ */
54
+ private lastAccessedCache: {
55
+ [store: string]: {
56
+ [type: string]: number;
57
+ }
58
+ } = {}
59
+
60
+ /**
61
+ * Track when a logged in route changes.
62
+ */
63
+ private lastRouteChange: number = 0;
64
+
65
+ // ------------- GC Enabled ---------------------
66
+
67
+ gcEnabledAll(pseudoCtx: any, type: string) {
68
+ return this.gcEnabledForStore(pseudoCtx.state) && this.gcEnabledSetting(pseudoCtx) && this.gcEnabledForType(pseudoCtx, type);
69
+ }
70
+
71
+ gcEnabledSetting(pseudoCtx: any) {
72
+ const { rootState } = pseudoCtx;
73
+
74
+ // Don't use a getter... as we'll end up triggering ourselves again
75
+ const uiPerfGarbageCollection = this.getUiPerfGarbageCollection(rootState);
76
+
77
+ return uiPerfGarbageCollection?.enabled;
78
+ }
79
+
80
+ gcEnabledForStore(state: any) {
81
+ return state?.config?.supportsGc;
82
+ }
83
+
84
+ /**
85
+ * Store can require certain types are not GC'd (for example `cluster` and `schema`s, `counts`, etc)
86
+ */
87
+ gcEnabledForType(pseudoCtx: any, type: string) {
88
+ const { getters } = pseudoCtx;
89
+
90
+ if (!type || getters.gcIgnoreTypes[type]) {
91
+ return false;
92
+ }
93
+
94
+ return true;
95
+ }
96
+
97
+ gcEnabledInterval(pseudoCtx: any) {
98
+ const { rootState } = pseudoCtx;
99
+
100
+ // Don't use a getter... as we'll end up triggering ourselves again
101
+ const uiPerfGarbageCollection = this.getUiPerfGarbageCollection(rootState);
102
+
103
+ return {
104
+ enabled: uiPerfGarbageCollection?.enabledInterval,
105
+ interval: uiPerfGarbageCollection?.interval || 0
106
+ };
107
+ }
108
+
109
+ gcEnabledRoute(pseudoCtx: any) {
110
+ const { rootState } = pseudoCtx;
111
+
112
+ // Don't use a getter... as we'll end up triggering ourselves again
113
+ const uiPerfGarbageCollection = this.getUiPerfGarbageCollection(rootState);
114
+
115
+ return uiPerfGarbageCollection?.enabledOnNavigate;
116
+ }
117
+
118
+ // ------------- GC (actual) ---------------------
119
+
120
+ /**
121
+ * Remove stale resource types from the store and stop watching them for changes
122
+ */
123
+ garbageCollect(ctx: any, ignoreTypes: {[type: string]: boolean} = {}) {
124
+ const now = new Date().getTime();
125
+
126
+ // Is gc currently running OR has run in the past GC_RE_RUN_GAP return early
127
+ if (this.gcLastRun === null || now - this.gcLastRun < GarbageCollect.GC_RE_RUN_GAP) {
128
+ this.debugLog('Skipping (running or recently run)', this.gcLastRun ? new Date(this.gcLastRun) : 'running');
129
+
130
+ return;
131
+ }
132
+
133
+ this.gcLastRun = null;
134
+ const gcd: {[type: string]: number} = {};
135
+
136
+ try {
137
+ const { getters, rootState, dispatch } = ctx;
138
+
139
+ if (!rootState.clusterReady) {
140
+ this.debugLog('Skipping (cluster not ready)');
141
+ this.gcLastRun = new Date().getTime();
142
+
143
+ return ;
144
+ }
145
+ this.debugLog(`------ Started ------`);
146
+
147
+ const uiPerfGarbageCollection = this.getUiPerfGarbageCollection(rootState);
148
+
149
+ if (!uiPerfGarbageCollection) {
150
+ return ;
151
+ }
152
+ const maxAge = uiPerfGarbageCollection.ageThreshold * 1000;
153
+ const maxCount = uiPerfGarbageCollection.countThreshold;
154
+
155
+ this.debugLog(`Max Age: ${ maxAge }. Max Count: ${ maxCount }`);// , 'Cache', this.lastAccessedCache
156
+
157
+ const store = ctx.state.config.namespace;
158
+
159
+ // this.debugLog('Cache', this.lastAccessedCache);
160
+
161
+ Object.entries((this.lastAccessedCache[store] || {})).forEach(([type, lastAccessed]) => {
162
+ if (!lastAccessed) {
163
+ // There's no last accessed time... gc is probably disabled in another way
164
+ this.debugLog(`${ type }: Skipping (no accessed time)`);
165
+
166
+ return;
167
+ }
168
+
169
+ if (!this.gcEnabledForType(ctx, type)) {
170
+ // This specific store is telling us to ignore the type (for example `cluster` store will not GC schema's, counts, etc)
171
+ this.debugLog(`${ type }: Skipping (type ignored by store)`);
172
+
173
+ return;
174
+ }
175
+
176
+ if (ignoreTypes[type]) {
177
+ // We're going to a place that needs the resource
178
+ this.debugLog(`${ type }: Skipping (navigating to type)`);
179
+
180
+ return;
181
+ }
182
+
183
+ if (now - lastAccessed <= maxAge) {
184
+ // The resource was recently accessed
185
+
186
+ this.debugLog(`${ type }: Skipping (recently accessed)`);
187
+
188
+ return;
189
+ }
190
+
191
+ if (this.lastRouteChange !== undefined && this.lastRouteChange < lastAccessed ) {
192
+ // The resource is being used in the current route/page
193
+ this.debugLog(`${ type }: Skipping (used in current route/page)`);
194
+
195
+ return;
196
+ }
197
+
198
+ const countFromResource = getters.all(COUNT)[0].counts[type]?.summary.count;
199
+ const currentCount = countFromResource ?? 0;
200
+
201
+ if (currentCount === undefined || currentCount < maxCount) {
202
+ // There's too few resources, we might as well keep them to avoid a network request when we need them again
203
+ this.debugLog(`${ type }: Skipping (too few of resource)`);
204
+
205
+ return;
206
+ }
207
+
208
+ this.debugLog(`${ type }: Removing from store`);
209
+ dispatch('forgetType', type);
210
+ gcd[type] = currentCount;
211
+ });
212
+
213
+ this.gcLastRun = new Date().getTime();
214
+ } catch (e) {
215
+ this.debugLog(`: Error`, e);
216
+ this.gcLastRun = new Date().getTime();
217
+ }
218
+
219
+ if (Object.keys(gcd).length > 0) {
220
+ console.info('Garbage Collected Resources', gcd); // eslint-disable-line no-console
221
+ }
222
+
223
+ this.debugLog(`------ Finished ------`);
224
+ }
225
+
226
+ // ------------- GC Update local cache ---------------------
227
+
228
+ /**
229
+ * Update the time that the resource type was accessed
230
+ * This needs to run after any type initialisation (aka registerType)
231
+ */
232
+ gcUpdateLastAccessed(pseudoCtx: any, type: string) {
233
+ if (!this.gcEnabledAll(pseudoCtx, type)) {
234
+ return;
235
+ }
236
+ const store = pseudoCtx.state.config.namespace;
237
+
238
+ if (!this.lastAccessedCache[store]) {
239
+ this.lastAccessedCache[store] = {};
240
+ }
241
+
242
+ this.lastAccessedCache[store][type] = new Date().getTime();
243
+ }
244
+
245
+ /**
246
+ * Update the time the user last changed routes
247
+ */
248
+ gcUpdateRouteChanged() {
249
+ this.lastRouteChange = new Date().getTime();
250
+ }
251
+
252
+ // ------------- GC reset ---------------------
253
+
254
+ /**
255
+ * Remove all cached access times for the given store
256
+ */
257
+ gcResetStore(state: any) {
258
+ const store = state.config.namespace;
259
+
260
+ delete this.lastAccessedCache[store];
261
+
262
+ this.debugLog('Forgetting Store:', store);
263
+ }
264
+
265
+ /**
266
+ * Remove cached access time for the given resource type
267
+ */
268
+ gcResetType(state: any, type: string) {
269
+ const store = state.config.namespace;
270
+
271
+ if (!this.lastAccessedCache[store]) {
272
+ return;
273
+ }
274
+ delete this.lastAccessedCache[store][type];
275
+
276
+ this.debugLog('Forgetting Type:', store, type);
277
+ }
278
+ }
279
+
280
+ const gc = new GarbageCollect();
281
+
282
+ export default gc;
package/utils/grafana.js CHANGED
@@ -1,5 +1,5 @@
1
+ import { haveV2Monitoring } from '@shell/utils/monitoring';
1
2
  import { parse as parseUrl, addParam } from '@shell/utils/url';
2
- import { MONITORING } from '@shell/config/types';
3
3
 
4
4
  export function computeDashboardUrl(embedUrl, clusterId, params) {
5
5
  const url = parseUrl(embedUrl);
@@ -21,7 +21,7 @@ export function computeDashboardUrl(embedUrl, clusterId, params) {
21
21
  }
22
22
 
23
23
  export async function dashboardExists(store, clusterId, embedUrl, storeName = 'cluster') {
24
- if (!isMonitoringInstalled(store.getters, storeName)) {
24
+ if ( !haveV2Monitoring(store.getters) ) {
25
25
  return false;
26
26
  }
27
27
 
@@ -81,7 +81,3 @@ export async function failedProposals(dispatch, clusterId) {
81
81
 
82
82
  return response.data.result[0]?.values?.[0]?.[1] || 0;
83
83
  }
84
-
85
- function isMonitoringInstalled(getters, storeName = 'cluster') {
86
- return !!getters[`${ storeName }/schemaFor`](MONITORING.SERVICEMONITOR);
87
- }