@rancher/shell 0.3.29 → 0.5.0

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 (301) hide show
  1. package/assets/images/providers/ovhcloudmks.svg +122 -0
  2. package/assets/images/providers/ovhcloudpubliccloud.svg +122 -0
  3. package/assets/styles/global/_layout.scss +99 -0
  4. package/assets/translations/en-us.yaml +31 -6
  5. package/assets/translations/zh-hans.yaml +2 -2
  6. package/babel.config.js +7 -1
  7. package/chart/monitoring/alerting/index.vue +7 -21
  8. package/chart/monitoring/grafana/index.vue +55 -0
  9. package/chart/monitoring/index.vue +51 -17
  10. package/chart/monitoring/prometheus/index.vue +37 -43
  11. package/chart/rancher-backup/index.vue +2 -1
  12. package/cloud-credential/azure.vue +4 -17
  13. package/components/AsyncButton.vue +17 -5
  14. package/components/Certificates.vue +164 -0
  15. package/components/CodeMirror.vue +19 -21
  16. package/components/CopyCode.vue +6 -2
  17. package/components/CopyToClipboard.vue +2 -1
  18. package/components/CopyToClipboardText.vue +14 -9
  19. package/components/CruResource.vue +1 -0
  20. package/components/DraggableZone.vue +2 -2
  21. package/components/EtcdInfoBanner.vue +5 -5
  22. package/components/ExplorerProjectsNamespaces.vue +25 -1
  23. package/components/IconOrSvg.vue +1 -1
  24. package/components/LandingPagePreference.vue +1 -4
  25. package/components/Markdown.vue +16 -12
  26. package/components/PodSecurityAdmission.vue +2 -2
  27. package/components/Questions/index.vue +1 -1
  28. package/components/ResourceDetail/Masthead.vue +25 -9
  29. package/components/ResourceTable.vue +14 -2
  30. package/components/ResourceYaml.vue +5 -0
  31. package/components/SideNav.vue +1 -1
  32. package/components/SingleClusterInfo.vue +1 -4
  33. package/components/StatusTable.vue +5 -1
  34. package/components/Tabbed/index.vue +12 -0
  35. package/components/__tests__/CopyCode.test.ts +5 -4
  36. package/components/fleet/FleetBundles.vue +5 -11
  37. package/components/fleet/FleetRepos.vue +62 -27
  38. package/components/fleet/FleetResources.vue +6 -1
  39. package/components/fleet/FleetSummary.vue +3 -3
  40. package/components/fleet/__tests__/FleetSummary.test.ts +316 -0
  41. package/components/form/ArrayListSelect.vue +10 -0
  42. package/components/form/Error.vue +3 -3
  43. package/components/form/Footer.vue +2 -2
  44. package/components/form/GitPicker.vue +83 -38
  45. package/components/form/KeyValue.vue +4 -0
  46. package/components/form/LabeledSelect.vue +4 -0
  47. package/components/form/Password.vue +3 -1
  48. package/components/formatter/Checked.vue +11 -3
  49. package/components/formatter/FleetClusterSummaryGraph.vue +27 -0
  50. package/components/formatter/FleetSummaryGraph.vue +23 -11
  51. package/components/formatter/LiveDuration.vue +1 -1
  52. package/components/formatter/PercentageBar.vue +1 -1
  53. package/components/formatter/__tests__/Checked.test.ts +19 -0
  54. package/components/nav/Group.vue +2 -2
  55. package/components/nav/Header.vue +1 -2
  56. package/components/nav/TopLevelMenu.vue +36 -6
  57. package/components/nav/Type.vue +1 -3
  58. package/components/nav/WindowManager/ContainerLogs.vue +101 -3
  59. package/components/nav/WindowManager/ContainerShell.vue +6 -1
  60. package/components/nav/WindowManager/__tests__/ContainerLogs.test.ts +186 -0
  61. package/components/nav/WindowManager/index.vue +11 -10
  62. package/components/nav/__tests__/TopLevelMenu.test.ts +33 -0
  63. package/components/nav/__tests__/Type.test.ts +1 -1
  64. package/components/nuxt/nuxt-child.js +14 -78
  65. package/components/nuxt/nuxt.js +1 -1
  66. package/{layouts → components/templates}/blank.vue +1 -1
  67. package/{layouts → components/templates}/default.vue +8 -98
  68. package/{layouts → components/templates}/error.vue +10 -19
  69. package/{layouts → components/templates}/home.vue +4 -1
  70. package/{layouts → components/templates}/plain.vue +4 -1
  71. package/{layouts → components/templates}/standalone.vue +1 -1
  72. package/{layouts → components/templates}/unauthenticated.vue +1 -1
  73. package/composables/useCompactInput.test.ts +36 -0
  74. package/composables/useCompactInput.ts +20 -0
  75. package/composables/useLabeledFormElement.test.ts +135 -0
  76. package/composables/useLabeledFormElement.ts +138 -0
  77. package/config/harvester-manager-types.js +2 -0
  78. package/config/home-links.js +1 -1
  79. package/config/private-label.js +22 -0
  80. package/config/product/explorer.js +3 -0
  81. package/config/product/fleet.js +6 -1
  82. package/config/product/manager.js +8 -2
  83. package/config/query-params.js +1 -0
  84. package/config/router.js +385 -364
  85. package/config/settings.ts +1 -0
  86. package/config/store.js +1 -1
  87. package/config/system-namespaces.js +3 -0
  88. package/config/table-headers.js +47 -0
  89. package/core/plugin-helpers.js +3 -5
  90. package/core/plugin-routes.ts +56 -114
  91. package/core/plugin.ts +16 -10
  92. package/core/plugins-loader.js +7 -9
  93. package/core/plugins.js +0 -3
  94. package/creators/app/files/.gitlab-ci.yml +14 -0
  95. package/creators/app/init +19 -0
  96. package/detail/fleet.cattle.io.cluster.vue +11 -1
  97. package/detail/provisioning.cattle.io.cluster.vue +4 -3
  98. package/dialog/ScaleMachineDownDialog.vue +34 -17
  99. package/edit/__tests__/service.test.ts +89 -0
  100. package/edit/auth/googleoauth.vue +1 -5
  101. package/edit/cloudcredential.vue +2 -0
  102. package/edit/configmap.vue +2 -1
  103. package/edit/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +2 -2
  104. package/edit/monitoring.coreos.com.prometheusrule/AlertingRule.vue +12 -3
  105. package/edit/monitoring.coreos.com.prometheusrule/GroupRules.vue +2 -1
  106. package/edit/networking.k8s.io.networkpolicy/__tests__/PolicyRuleTarget.spec.ts +1 -1
  107. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +15 -7
  108. package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +112 -0
  109. package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +473 -0
  110. package/edit/provisioning.cattle.io.cluster/__tests__/{CustomCommand.tests.ts → CustomCommand.test.ts} +6 -0
  111. package/edit/provisioning.cattle.io.cluster/__tests__/DrainOptions.test.ts +1 -1
  112. package/edit/provisioning.cattle.io.cluster/__tests__/index.test.ts +73 -0
  113. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +7 -1
  114. package/edit/provisioning.cattle.io.cluster/__tests__/utils/cluster.ts +386 -0
  115. package/edit/provisioning.cattle.io.cluster/import.vue +2 -2
  116. package/edit/provisioning.cattle.io.cluster/index.vue +92 -36
  117. package/edit/provisioning.cattle.io.cluster/rke2.vue +171 -583
  118. package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +137 -0
  119. package/edit/provisioning.cattle.io.cluster/tabs/Advanced.vue +157 -0
  120. package/edit/provisioning.cattle.io.cluster/{Basics.vue → tabs/Basics.vue} +94 -19
  121. package/edit/provisioning.cattle.io.cluster/{MachinePool.vue → tabs/MachinePool.vue} +1 -0
  122. package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +135 -0
  123. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +189 -0
  124. package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +144 -0
  125. package/edit/provisioning.cattle.io.cluster/tabs/upgrade/index.vue +76 -0
  126. package/edit/service.vue +12 -0
  127. package/edit/workload/Upgrading.vue +3 -2
  128. package/edit/workload/mixins/workload.js +1 -1
  129. package/edit/workload/storage/persistentVolumeClaim/persistentvolumeclaim.vue +2 -1
  130. package/initialize/App.js +25 -71
  131. package/initialize/client.js +21 -162
  132. package/initialize/index.js +47 -124
  133. package/list/management.cattle.io.feature.vue +1 -7
  134. package/list/node.vue +1 -0
  135. package/machine-config/__tests__/vmwarevsphere.test.ts +100 -21
  136. package/machine-config/vmwarevsphere.vue +73 -51
  137. package/middleware/authenticated.js +10 -17
  138. package/mixins/auth-config.js +2 -7
  139. package/mixins/brand.js +29 -41
  140. package/mixins/create-edit-view/index.js +2 -2
  141. package/mixins/labeled-form-element.ts +6 -1
  142. package/models/__tests__/management.cattle.io.cluster.test.ts +4 -0
  143. package/models/__tests__/management.cattle.io.node.ts +85 -0
  144. package/models/__tests__/management.cattle.io.nodepool.ts +83 -0
  145. package/models/__tests__/namespace.test.ts +49 -9
  146. package/models/__tests__/workload.test.ts +91 -0
  147. package/models/cluster/node.js +4 -4
  148. package/models/cluster.x-k8s.io.machinedeployment.js +14 -0
  149. package/models/fleet.cattle.io.cluster.js +4 -0
  150. package/models/fleet.cattle.io.gitrepo.js +56 -13
  151. package/models/management.cattle.io.cluster.js +7 -3
  152. package/models/management.cattle.io.kontainerdriver.js +1 -1
  153. package/models/management.cattle.io.node.js +18 -14
  154. package/models/management.cattle.io.nodepool.js +17 -0
  155. package/models/namespace.js +1 -1
  156. package/models/pod.js +20 -0
  157. package/models/provisioning.cattle.io.cluster.js +39 -4
  158. package/models/secret.js +117 -18
  159. package/models/workload.js +16 -0
  160. package/models/workload.service.js +18 -0
  161. package/package.json +11 -10
  162. package/pages/about.vue +0 -1
  163. package/pages/account/create-key.vue +0 -1
  164. package/pages/account/index.vue +0 -1
  165. package/pages/auth/login.vue +0 -1
  166. package/pages/auth/logout.vue +0 -2
  167. package/pages/auth/setup.vue +0 -4
  168. package/pages/auth/verify.vue +14 -8
  169. package/pages/c/_cluster/apps/charts/index.vue +64 -43
  170. package/pages/c/_cluster/apps/charts/install.vue +4 -4
  171. package/pages/c/_cluster/apps/index.vue +0 -2
  172. package/pages/c/_cluster/auth/index.vue +0 -2
  173. package/pages/c/_cluster/ecm/index.vue +0 -2
  174. package/pages/c/_cluster/explorer/index.vue +28 -2
  175. package/pages/c/_cluster/fleet/index.vue +1 -1
  176. package/pages/c/_cluster/index.vue +0 -2
  177. package/pages/c/_cluster/settings/banners.vue +0 -2
  178. package/pages/c/_cluster/settings/brand.vue +0 -2
  179. package/pages/c/_cluster/settings/index.vue +0 -2
  180. package/pages/c/_cluster/settings/links.vue +0 -1
  181. package/pages/c/_cluster/settings/performance.vue +0 -1
  182. package/pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue +2 -1
  183. package/pages/c/_cluster/uiplugins/CatalogList/index.vue +10 -46
  184. package/pages/c/_cluster/uiplugins/index.vue +0 -2
  185. package/pages/diagnostic.vue +1 -2
  186. package/pages/fail-whale.vue +0 -1
  187. package/pages/prefs.vue +0 -1
  188. package/pages/support/index.vue +2 -8
  189. package/pkg/auto-import.js +1 -1
  190. package/plugins/axios.js +0 -36
  191. package/plugins/back-button.js +3 -5
  192. package/plugins/clean-html-directive.js +1 -19
  193. package/plugins/clean-html.js +53 -0
  194. package/plugins/clean-tooltip-directive.js +1 -1
  195. package/plugins/codemirror-loader.js +1 -1
  196. package/plugins/codemirror.js +41 -0
  197. package/plugins/dashboard-store/__tests__/{mutations.spec.ts → mutations.test.ts} +1 -1
  198. package/plugins/dashboard-store/__tests__/resource-class.test.ts +49 -0
  199. package/plugins/dashboard-store/__tests__/utils/store-mocks.ts +7 -0
  200. package/plugins/dashboard-store/actions.js +30 -4
  201. package/plugins/dashboard-store/classify.js +1 -18
  202. package/plugins/dashboard-store/getters.js +10 -5
  203. package/plugins/dashboard-store/index.js +0 -12
  204. package/plugins/dashboard-store/mutations.js +0 -4
  205. package/plugins/dashboard-store/resource-class.js +59 -18
  206. package/plugins/index.js +11 -0
  207. package/plugins/steve/__tests__/steve-class.spec.ts +59 -0
  208. package/plugins/steve/__tests__/utils/steve-mocks.ts +31 -0
  209. package/plugins/steve/getters.js +4 -1
  210. package/plugins/steve/norman-class.js +19 -0
  211. package/plugins/steve/steve-class.js +22 -0
  212. package/plugins/steve/subscribe.js +4 -10
  213. package/rancher-components/Accordion/Accordion.test.ts +45 -0
  214. package/rancher-components/Accordion/Accordion.vue +86 -0
  215. package/rancher-components/Accordion/index.ts +1 -0
  216. package/rancher-components/BadgeState/BadgeState.vue +3 -3
  217. package/rancher-components/Banner/Banner.vue +2 -2
  218. package/rancher-components/Card/Card.vue +3 -3
  219. package/rancher-components/Form/Checkbox/Checkbox.vue +3 -3
  220. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +18 -1
  221. package/rancher-components/Form/LabeledInput/LabeledInput.vue +65 -24
  222. package/rancher-components/Form/Radio/RadioButton.test.ts +7 -3
  223. package/rancher-components/Form/Radio/RadioButton.vue +13 -7
  224. package/rancher-components/Form/Radio/RadioGroup.test.ts +30 -0
  225. package/rancher-components/Form/Radio/RadioGroup.vue +8 -3
  226. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +6 -4
  227. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +7 -4
  228. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +9 -4
  229. package/rancher-components/StringList/StringList.test.ts +270 -0
  230. package/rancher-components/StringList/StringList.vue +65 -26
  231. package/rancher-components/components/Accordion/Accordion.test.ts +45 -0
  232. package/rancher-components/components/Accordion/Accordion.vue +86 -0
  233. package/rancher-components/components/Accordion/index.ts +1 -0
  234. package/rancher-components/components/BadgeState/BadgeState.vue +3 -3
  235. package/rancher-components/components/Banner/Banner.vue +2 -2
  236. package/rancher-components/components/Card/Card.vue +3 -3
  237. package/rancher-components/components/Form/Checkbox/Checkbox.vue +3 -3
  238. package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +18 -1
  239. package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +57 -24
  240. package/rancher-components/components/Form/Radio/RadioButton.vue +13 -7
  241. package/rancher-components/components/Form/Radio/RadioGroup.vue +4 -3
  242. package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +6 -4
  243. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +7 -4
  244. package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +9 -4
  245. package/rancher-components/components/StringList/StringList.vue +8 -8
  246. package/scripts/.gitlab/workflows/build-extension-catalog.gitlab-ci.yml +50 -0
  247. package/scripts/extension/bundle +19 -7
  248. package/scripts/extension/helm/scripts/package +11 -3
  249. package/scripts/extension/parse-tag-name +2 -2
  250. package/scripts/extension/publish +20 -9
  251. package/scripts/publish-shell.sh +10 -0
  252. package/scripts/test-plugins-build.sh +85 -9
  253. package/server/har-file.js +183 -0
  254. package/store/catalog.js +1 -1
  255. package/store/features.js +1 -0
  256. package/store/i18n.js +11 -0
  257. package/store/index.js +13 -15
  258. package/store/prefs.js +33 -35
  259. package/store/type-map.js +8 -7
  260. package/tsconfig.json +35 -9
  261. package/tsconfig.paths.json +21 -0
  262. package/types/shell/index.d.ts +433 -234
  263. package/types/vue-shim.d.ts +42 -0
  264. package/utils/__tests__/create-yaml.test.ts +60 -0
  265. package/utils/axios.js +0 -19
  266. package/utils/azure.js +24 -0
  267. package/utils/clipboard.js +5 -0
  268. package/utils/create-yaml.js +17 -10
  269. package/utils/git.ts +1 -1
  270. package/utils/monitoring.js +1 -1
  271. package/utils/nuxt.js +18 -39
  272. package/utils/object.js +14 -0
  273. package/utils/router.scrollBehavior.js +12 -14
  274. package/utils/time.js +1 -1
  275. package/utils/url.ts +1 -1
  276. package/vue.config.js +23 -2
  277. package/.DS_Store +0 -0
  278. package/assets/images/providers/aks-black.svg +0 -28
  279. package/assets/images/providers/aks.svg +0 -31
  280. package/edit/provisioning.cattle.io.cluster/__tests__/Basics.tests.ts +0 -234
  281. package/initialize/layouts.ts +0 -26
  282. package/mixins/fetch.server.js +0 -73
  283. package/pages/c/index.vue +0 -9
  284. package/pages/rio/mesh.vue +0 -508
  285. package/plugins/transitions.js +0 -4
  286. package/plugins/vue-clipboard2.js +0 -4
  287. package/tsconfig.default.json +0 -46
  288. package/yarn-error.log +0 -200
  289. /package/components/form/__tests__/{NameNsDescription.ts → NameNsDescription.test.ts} +0 -0
  290. /package/edit/networking.k8s.io.networkpolicy/__tests__/utils/{selectors.ts → selectors.test.ts} +0 -0
  291. /package/edit/provisioning.cattle.io.cluster/{AgentConfiguration.vue → tabs/AgentConfiguration.vue} +0 -0
  292. /package/edit/provisioning.cattle.io.cluster/{MemberRoles.vue → tabs/MemberRoles.vue} +0 -0
  293. /package/edit/provisioning.cattle.io.cluster/{S3Config.vue → tabs/etcd/S3Config.vue} +0 -0
  294. /package/edit/provisioning.cattle.io.cluster/{ACE.vue → tabs/networking/ACE.vue} +0 -0
  295. /package/edit/provisioning.cattle.io.cluster/{RegistryConfigs.vue → tabs/registries/RegistryConfigs.vue} +0 -0
  296. /package/edit/provisioning.cattle.io.cluster/{RegistryMirrors.vue → tabs/registries/RegistryMirrors.vue} +0 -0
  297. /package/edit/provisioning.cattle.io.cluster/{DrainOptions.vue → tabs/upgrade/DrainOptions.vue} +0 -0
  298. /package/plugins/dashboard-store/__tests__/{actions.spec.ts → actions.test.ts} +0 -0
  299. /package/plugins/dashboard-store/__tests__/{getters.spec.ts → getters.test.ts} +0 -0
  300. /package/rancher-components/BadgeState/{BadgeState.spec.ts → BadgeState.test.ts} +0 -0
  301. /package/rancher-components/components/BadgeState/{BadgeState.spec.ts → BadgeState.test.ts} +0 -0
@@ -10,7 +10,6 @@ import { isRancherPrime } from '@shell/config/version';
10
10
  import { hasCspAdapter } from 'mixins/brand';
11
11
 
12
12
  export default {
13
- layout: 'home',
14
13
 
15
14
  components: {
16
15
  BannerGraphic,
@@ -82,13 +81,8 @@ export default {
82
81
  },
83
82
 
84
83
  serverUrl() {
85
- if (process.client) {
86
- // Client-side rendered: use the current window location
87
- return window.location.origin;
88
- }
89
-
90
- // Server-side rendered
91
- return this.serverSetting?.value || '';
84
+ // Client-side rendered: use the current window location
85
+ return window.location.origin;
92
86
  },
93
87
 
94
88
  supportConfigLink() {
@@ -1,6 +1,6 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
- const contextFolders = ['chart', 'cloud-credential', 'content', 'detail', 'edit', 'layouts', 'list', 'machine-config', 'models', 'promptRemove', 'l10n', 'windowComponents', 'dialog', 'formatters', 'login'];
3
+ const contextFolders = ['chart', 'cloud-credential', 'content', 'detail', 'edit', 'list', 'machine-config', 'models', 'promptRemove', 'l10n', 'windowComponents', 'dialog', 'formatters', 'login'];
4
4
  const contextMap = contextFolders.reduce((map, obj) => {
5
5
  map[obj] = true;
6
6
 
package/plugins/axios.js CHANGED
@@ -1,7 +1,5 @@
1
1
  import https from 'https';
2
2
  import { CSRF } from '@shell/config/cookies';
3
- import { parse as setCookieParser } from 'set-cookie-parser';
4
- import pkg from '../package.json';
5
3
 
6
4
  export default function({
7
5
  $axios, $cookies, isDev, req
@@ -15,42 +13,8 @@ export default function({
15
13
  if ( csrf ) {
16
14
  config.headers['x-api-csrf'] = csrf;
17
15
  }
18
-
19
- if ( process.server ) {
20
- config.headers.common['access-control-expose-headers'] = `set-cookie`;
21
- config.headers.common['user-agent'] = `Dashboard (Mozilla) v${ pkg.version }`;
22
-
23
- if ( req.headers.cookie ) {
24
- config.headers.common['cookies'] = req.headers.cookie;
25
- }
26
-
27
- if ( config.url.startsWith('/') ) {
28
- config.baseURL = `${ req.protocol || 'https' }://${ req.headers.host }`;
29
- }
30
- }
31
16
  });
32
17
 
33
- if ( process.server ) {
34
- $axios.onResponse((res) => {
35
- const parsed = setCookieParser(res.headers['set-cookie'] || []);
36
-
37
- for ( const opt of parsed ) {
38
- const key = opt.name;
39
- const value = opt.value;
40
-
41
- delete opt.name;
42
- delete opt.value;
43
-
44
- opt.encode = (x) => x;
45
- opt.sameSite = true;
46
- opt.path = '/';
47
- opt.secure = true;
48
-
49
- $cookies.set(key, value, opt);
50
- }
51
- });
52
- }
53
-
54
18
  if ( isDev ) {
55
19
  // https://github.com/nuxt-community/axios-module/blob/dev/lib/module.js#L78
56
20
  // forces localhost to http, for no obvious reason.
@@ -1,5 +1,3 @@
1
- if ( process.client ) {
2
- window.addEventListener('popstate', () => {
3
- window._popStateDetected = true;
4
- });
5
- }
1
+ window.addEventListener('popstate', () => {
2
+ window._popStateDetected = true;
3
+ });
@@ -1,23 +1,5 @@
1
1
  import Vue from 'vue';
2
- import DOMPurify from 'dompurify';
3
-
4
- const ALLOWED_TAGS = [
5
- 'code',
6
- 'li',
7
- 'a',
8
- 'p',
9
- 'b',
10
- 'br',
11
- 'ul',
12
- 'pre',
13
- 'span',
14
- 'div',
15
- 'i',
16
- 'em',
17
- 'strong',
18
- ];
19
-
20
- export const purifyHTML = (value) => DOMPurify.sanitize(value, { ALLOWED_TAGS });
2
+ import { purifyHTML } from './clean-html';
21
3
 
22
4
  export const cleanHtmlDirective = {
23
5
  inserted(el, binding) {
@@ -0,0 +1,53 @@
1
+ import DOMPurify from 'dompurify';
2
+ import { uniq } from '@shell/utils/array';
3
+
4
+ const ALLOWED_TAGS = [
5
+ 'code',
6
+ 'li',
7
+ 'a',
8
+ 'p',
9
+ 'b',
10
+ 'br',
11
+ 'ul',
12
+ 'pre',
13
+ 'span',
14
+ 'div',
15
+ 'i',
16
+ 'em',
17
+ 'strong',
18
+ 'h1',
19
+ 'h2',
20
+ 'h3',
21
+ 'h4',
22
+ 'h5',
23
+ 'h6',
24
+ 'table',
25
+ 'thead',
26
+ 'tr',
27
+ 'th',
28
+ 'tbody',
29
+ 'td',
30
+ 'blockquote'
31
+ ];
32
+
33
+ // Allow 'A' tags to keep the target=_blank attribute if they have it
34
+ DOMPurify.addHook('uponSanitizeAttribute', (node, data) => {
35
+ if (node.tagName === 'A' && data.attrName === 'target' && data.attrValue === '_blank') {
36
+ data.forceKeepAttr = true;
37
+ }
38
+ });
39
+
40
+ // Ensure if an 'A' tag has target=_blank that we add noopener, noreferrer and nofollow to the 'rel' attribute
41
+ DOMPurify.addHook('afterSanitizeAttributes', (node) => {
42
+ if (node.tagName === 'A' && node?.target === '_blank') {
43
+ const rel = ['noopener', 'noreferrer', 'nofollow'];
44
+ const existingRel = node.rel?.length ? node.rel.split(' ') : [];
45
+ const combined = uniq([...rel, ...existingRel]);
46
+
47
+ node.setAttribute('rel', combined.join(' '));
48
+ }
49
+ });
50
+
51
+ export const purifyHTML = (value, options = { ALLOWED_TAGS }) => {
52
+ return DOMPurify.sanitize(value, options);
53
+ };
@@ -1,6 +1,6 @@
1
1
  import Vue from 'vue';
2
2
  import { VTooltip } from 'v-tooltip';
3
- import { purifyHTML } from './clean-html-directive';
3
+ import { purifyHTML } from './clean-html';
4
4
 
5
5
  function purifyContent(value) {
6
6
  const type = typeof value;
@@ -1,5 +1,5 @@
1
1
  // Share codemirror with plugins
2
2
 
3
- if ( process.client && !window.__codeMirrorLoader ) {
3
+ if ( !window.__codeMirrorLoader ) {
4
4
  window.__codeMirrorLoader = () => import(/* webpackChunkName: "codemirror" */ '@shell/plugins/codemirror');
5
5
  }
@@ -125,6 +125,47 @@ CodeMirror.defineExtension('foldLinesMatching', function(regex) {
125
125
  });
126
126
  });
127
127
 
128
+ function countSpaces(line) {
129
+ for (let i = 0; i < line.length; i++) {
130
+ if (line[i] !== ' ') {
131
+ return i;
132
+ }
133
+ }
134
+
135
+ return line.length;
136
+ }
137
+
138
+ CodeMirror.defineExtension('foldYaml', function(path) {
139
+ this.operation(() => {
140
+ let elements = [];
141
+
142
+ for (let i = this.firstLine(), e = this.lastLine(); i <= e; i++) {
143
+ const line = this.getLine(i);
144
+ const index = countSpaces(line);
145
+ const trimmed = line.trim();
146
+
147
+ if (trimmed.endsWith(':') || trimmed.endsWith(': >-')) {
148
+ const name = trimmed.split(':')[0].substr(0, trimmed.length - 1);
149
+
150
+ // Remove all elements of the same are greater index
151
+ elements = elements.filter((e) => e.index < index);
152
+
153
+ // Add on this one
154
+ elements.push({
155
+ index,
156
+ name
157
+ });
158
+
159
+ const currentPath = elements.map((e) => e.name).join('.');
160
+
161
+ if (currentPath === path) {
162
+ this.foldCode(CodeMirror.Pos(i, 0), null, 'fold');
163
+ }
164
+ }
165
+ }
166
+ });
167
+ });
168
+
128
169
  CodeMirror.registerHelper('fold', 'yamlcomments', (cm, start) => {
129
170
  if ( !isLineComment(cm, start.line) ) {
130
171
  return;
@@ -1,4 +1,4 @@
1
- import { batchChanges } from '@shell/plugins/dashboard-store/mutations';
1
+ import { batchChanges } from '@shell/plugins/dashboard-store/mutations.js';
2
2
  import { POD, WORKLOAD_TYPES } from '@shell/config/types';
3
3
  import Resource from '@shell/plugins/dashboard-store/resource-class';
4
4
 
@@ -0,0 +1,49 @@
1
+ import Resource from '@shell/plugins/dashboard-store/resource-class.js';
2
+ import { resourceClassJunkObject } from '@shell/plugins/dashboard-store/__tests__/utils/store-mocks';
3
+
4
+ describe('class: Resource', () => {
5
+ describe('given custom resource keys', () => {
6
+ const customResource = resourceClassJunkObject;
7
+
8
+ it('should keep internal keys', () => {
9
+ const resource = new Resource(customResource, {
10
+ getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
11
+ dispatch: jest.fn(),
12
+ rootGetters: { 'i18n/t': jest.fn() },
13
+ });
14
+
15
+ expect({ ...resource }).toStrictEqual(customResource);
16
+ });
17
+
18
+ describe('method: save', () => {
19
+ it('should remove all the internal keys', async() => {
20
+ const dispatch = jest.fn();
21
+ const resource = new Resource(customResource, {
22
+ getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
23
+ dispatch,
24
+ rootGetters: { 'i18n/t': jest.fn() },
25
+ });
26
+
27
+ const expectation = { type: customResource.type };
28
+
29
+ await resource.save();
30
+
31
+ const opt = {
32
+ data: expectation,
33
+ headers: {
34
+ accept: 'application/json',
35
+ 'content-type': 'application/json',
36
+ },
37
+ method: 'post',
38
+ url: undefined,
39
+ };
40
+
41
+ // Data sent should have been cleaned
42
+ expect(dispatch).toHaveBeenCalledWith('request', { opt, type: customResource.type });
43
+
44
+ // Original workload model should remain unchanged
45
+ expect({ ...resource }).toStrictEqual(customResource);
46
+ });
47
+ });
48
+ });
49
+ });
@@ -0,0 +1,7 @@
1
+ const customType = 'dsaf';
2
+
3
+ export const resourceClassJunkObject = {
4
+ type: customType,
5
+ __rehydrate: 'whatever',
6
+ __clone: 'whatever',
7
+ };
@@ -15,7 +15,8 @@ export const _ALL_IF_AUTHED = 'allIfAuthed';
15
15
  export const _NONE = 'none';
16
16
 
17
17
  const SCHEMA_CHECK_RETRIES = 15;
18
- const SCHEMA_CHECK_RETRY_LOG = 10;
18
+ const HAVE_ALL_CHECK_RETRIES = 15;
19
+ const RETRY_LOG = 10;
19
20
 
20
21
  export async function handleSpoofedRequest(rootGetters, schemaStore, opt, product) {
21
22
  // Handle spoofed types instead of making an actual request
@@ -70,6 +71,10 @@ export async function loadSchemas(ctx, watch = true) {
70
71
  return all;
71
72
  }
72
73
 
74
+ const findAllGetter = (getters, type, opt) => {
75
+ return opt.namespaced ? getters.matching(type, null, opt.namespaced, { skipSelector: true }) : getters.all(type);
76
+ };
77
+
73
78
  export default {
74
79
  request() {
75
80
  throw new Error('Not Implemented');
@@ -163,7 +168,7 @@ export default {
163
168
  dispatch('watch', args);
164
169
  }
165
170
 
166
- return getters.all(type);
171
+ return findAllGetter(getters, type, opt);
167
172
  }
168
173
 
169
174
  let load = (opt.load === undefined ? _ALL : opt.load);
@@ -328,7 +333,7 @@ export default {
328
333
  dispatch('watch', args);
329
334
  }
330
335
 
331
- const all = getters.all(type);
336
+ const all = findAllGetter(getters, type, opt);
332
337
 
333
338
  if (!opt.incremental && opt.hasManualRefresh) {
334
339
  dispatch('resource-fetch/updateManualRefreshIsLoading', false, { root: true });
@@ -613,7 +618,7 @@ export default {
613
618
  schema = getters['schemaFor'](type);
614
619
 
615
620
  if (!schema) {
616
- if (tries === SCHEMA_CHECK_RETRY_LOG) {
621
+ if (tries === RETRY_LOG) {
617
622
  console.warn(`Schema for ${ type } not available... retrying...`); // eslint-disable-line no-console
618
623
  }
619
624
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -628,6 +633,27 @@ export default {
628
633
  }
629
634
  },
630
635
 
636
+ async waitForHaveAll({ getters }, { type, throwError = false, attempts = HAVE_ALL_CHECK_RETRIES }) {
637
+ let tries = attempts;
638
+ let haveAll = null;
639
+
640
+ while (!haveAll && tries > 0) {
641
+ haveAll = getters['haveAll'](type);
642
+
643
+ if (!haveAll) {
644
+ if (tries === RETRY_LOG) {
645
+ console.warn(`wait for all of ${ type } continuing...`); // eslint-disable-line no-console
646
+ }
647
+ await new Promise((resolve) => setTimeout(resolve, 1000));
648
+ tries--;
649
+ }
650
+ }
651
+
652
+ if (tries === 0 && throwError) {
653
+ throw new Error(`Failed to wait for all of ${ type }`);
654
+ }
655
+ },
656
+
631
657
  incrementLoadCounter({ commit }, resource) {
632
658
  commit('incrementLoadCounter', resource);
633
659
  },
@@ -12,24 +12,7 @@ export function classify(ctx, obj, isClone = false) {
12
12
 
13
13
  const customModel = ctx.getters['classify'](obj);
14
14
 
15
- const out = new customModel(obj, ctx, (process.server ? ctx.state.config.namespace : null), isClone);
16
-
17
- if ( process.server ) {
18
- Object.defineProperty(obj, '__rehydrate', {
19
- value: ctx.state.config.namespace,
20
- enumerable: true,
21
- configurable: true
22
- });
23
-
24
- if ( isClone ) {
25
- Object.defineProperty(obj, '__clone', {
26
- value: true,
27
- enumerable: true,
28
- configurable: true,
29
- writable: true
30
- });
31
- }
32
- }
15
+ const out = new customModel(obj, ctx, null, isClone);
33
16
 
34
17
  return out;
35
18
  }
@@ -64,19 +64,24 @@ export default {
64
64
  return state.types[type].list;
65
65
  },
66
66
 
67
- matching: (state, getters, rootState) => (type, selector, namespace) => {
68
- let all = getters['all'](type);
67
+ matching: (state, getters, rootState) => (type, selector, namespace, config = { skipSelector: false }) => {
68
+ let matching = getters['all'](type);
69
69
 
70
70
  // Filter first by namespace if one is provided, since this is efficient
71
- if (namespace) {
72
- all = all.filter((obj) => obj.namespace === namespace);
71
+ if (namespace && typeof namespace === 'string') {
72
+ matching = matching.filter((obj) => obj.namespace === namespace);
73
73
  }
74
74
 
75
75
  garbageCollect.gcUpdateLastAccessed({
76
76
  state, getters, rootState
77
77
  }, type);
78
78
 
79
- return all.filter((obj) => {
79
+ // Looks like a falsy selector is a thing, so if we're not interested in filtering by the selector... explicitly avoid it
80
+ if (config.skipSelector) {
81
+ return matching;
82
+ }
83
+
84
+ return matching.filter((obj) => {
80
85
  return matches(obj, selector);
81
86
  });
82
87
  },
@@ -33,21 +33,9 @@ export default (vuexModule, config, init) => {
33
33
  const namespace = config.namespace || '';
34
34
 
35
35
  return function(store) {
36
- // const inst = SteveFactory(namespace, config.baseUrl);
37
-
38
36
  store.registerModule(namespace, vuexModule);
39
37
  store.commit(`${ namespace }/applyConfig`, config);
40
38
 
41
- if ( !process.client ) {
42
- return;
43
- }
44
-
45
- // store.subscribe(({ type }, state) => {
46
- // if ( type === 'auth/loggedOut' ) {
47
- // store.dispatch(`${ namespace }/unsubscribe`);
48
- // }
49
- // });
50
-
51
39
  const module = store._modules.root._children[namespace];
52
40
  const fromServer = window.__NUXT__;
53
41
 
@@ -23,10 +23,6 @@ function registerType(state, type) {
23
23
  // Not enumerable so they don't get sent back to the client for SSR
24
24
  Object.defineProperty(cache, 'map', { value: new Map() });
25
25
 
26
- if ( process.server && !cache.list.__rehydrateAll ) {
27
- Object.defineProperty(cache.list, '__rehydrateAll', { value: `${ state.config.namespace }/${ type }`, enumerable: true });
28
- }
29
-
30
26
  Vue.set(state.types, type, cache);
31
27
  }
32
28
 
@@ -105,6 +105,7 @@ export const STATES_ENUM = {
105
105
  ERRORING: 'erroring',
106
106
  ERRORS: 'errors',
107
107
  EXPIRED: 'expired',
108
+ EXPIRING: 'expiring',
108
109
  FAIL: 'fail',
109
110
  FAILED: 'failed',
110
111
  HEALTHY: 'healthy',
@@ -167,6 +168,13 @@ export const STATES_ENUM = {
167
168
  WARNING: 'warning',
168
169
  };
169
170
 
171
+ export function mapStateToEnum(statusString) {
172
+ // e.g. in fleet Status is Capitalized. This function will map it to the enum
173
+ return Object.values(STATES_ENUM).find((val) => {
174
+ return val.toLowerCase() === statusString.toLocaleLowerCase();
175
+ });
176
+ }
177
+
170
178
  export const STATES = {
171
179
  [STATES_ENUM.IN_USE]: {
172
180
  color: 'success', icon: 'dot-open', label: 'In Use', compoundIcon: 'checkmark'
@@ -253,7 +261,10 @@ export const STATES = {
253
261
  color: 'error', icon: 'error', label: 'Errors', compoundIcon: 'error'
254
262
  },
255
263
  [STATES_ENUM.EXPIRED]: {
256
- color: 'warning', icon: 'error', label: 'Expired', compoundIcon: 'warning'
264
+ color: 'error', icon: 'error', label: 'Expired', compoundIcon: 'warning'
265
+ },
266
+ [STATES_ENUM.EXPIRING]: {
267
+ color: 'warning', icon: 'error', label: 'Expiring', compoundIcon: 'error'
257
268
  },
258
269
  [STATES_ENUM.FAIL]: {
259
270
  color: 'error', icon: 'error', label: 'Fail', compoundIcon: 'error'
@@ -512,6 +523,28 @@ export function stateDisplay(state) {
512
523
  return key.split(/-/).map(ucFirst).join('-');
513
524
  }
514
525
 
526
+ export function primaryDisplayStatusFromCount(status) {
527
+ const statusOrder = [
528
+ STATES_ENUM.ERROR,
529
+ STATES_ENUM.FAILED,
530
+ STATES_ENUM.WARNING,
531
+ STATES_ENUM.MODIFIED,
532
+ STATES_ENUM.WAIT_APPLIED,
533
+ STATES_ENUM.ORPHANED,
534
+ STATES_ENUM.MISSING,
535
+ STATES_ENUM.UNKNOWN,
536
+ STATES_ENUM.NOT_READY,
537
+ STATES_ENUM.READY,
538
+ ];
539
+
540
+ // sort status by order of statusOrder
541
+ const existingStatuses = Object.keys(status).filter((key) => {
542
+ return status[key] > 0 && statusOrder.includes(key.toLowerCase());
543
+ }).sort((a, b) => statusOrder.indexOf(a.toLowerCase()) - statusOrder.indexOf(b.toLowerCase()));
544
+
545
+ return existingStatuses[0] ? existingStatuses[0] : STATES_ENUM.UNKNOWN;
546
+ }
547
+
515
548
  export function stateSort(color, display) {
516
549
  color = color.replace(/^(text|bg)-/, '');
517
550
 
@@ -1089,6 +1122,16 @@ export default class Resource {
1089
1122
  return this._save(...arguments);
1090
1123
  }
1091
1124
 
1125
+ /**
1126
+ * Remove any unwanted properties from the object that will be saved
1127
+ */
1128
+ cleanForSave(data, forNew) {
1129
+ delete data.__rehydrate;
1130
+ delete data.__clone;
1131
+
1132
+ return data;
1133
+ }
1134
+
1092
1135
  /**
1093
1136
  * Allow to handle the response of the save request
1094
1137
  * @param {*} res Full request response
@@ -1096,9 +1139,6 @@ export default class Resource {
1096
1139
  processSaveResponse(res) { }
1097
1140
 
1098
1141
  async _save(opt = {}) {
1099
- delete this.__rehydrate;
1100
- delete this.__clone;
1101
-
1102
1142
  const forNew = !this.id;
1103
1143
 
1104
1144
  const errors = await this.validationErrors(this, opt.ignoreFields);
@@ -1145,22 +1185,24 @@ export default class Resource {
1145
1185
  // @TODO remove this once the API maps steve _type <-> k8s type in both directions
1146
1186
  opt.data = this.toSave() || { ...this };
1147
1187
 
1148
- if (opt?.data._type) {
1188
+ if (opt.data._type) {
1149
1189
  opt.data.type = opt.data._type;
1150
1190
  }
1151
1191
 
1152
- if (opt?.data._name) {
1192
+ if (opt.data._name) {
1153
1193
  opt.data.name = opt.data._name;
1154
1194
  }
1155
1195
 
1156
- if (opt?.data._labels) {
1196
+ if (opt.data._labels) {
1157
1197
  opt.data.labels = opt.data._labels;
1158
1198
  }
1159
1199
 
1160
- if (opt?.data._annotations) {
1200
+ if (opt.data._annotations) {
1161
1201
  opt.data.annotations = opt.data._annotations;
1162
1202
  }
1163
1203
 
1204
+ opt.data = this.cleanForSave(opt.data, forNew);
1205
+
1164
1206
  // handle "replace" opt as a query param _replace=true for norman PUT requests
1165
1207
  if (opt?.replace && opt.method === 'put') {
1166
1208
  const argParam = opt.url.includes('?') ? '&' : '?';
@@ -1218,19 +1260,11 @@ export default class Resource {
1218
1260
  // ------------------------------------------------------------------
1219
1261
 
1220
1262
  currentRoute() {
1221
- if ( process.server ) {
1222
- return this.$rootState.$route;
1223
- } else {
1224
- return window.$nuxt.$route;
1225
- }
1263
+ return window.$nuxt.$route;
1226
1264
  }
1227
1265
 
1228
1266
  currentRouter() {
1229
- if ( process.server ) {
1230
- return this.$rootState.$router;
1231
- } else {
1232
- return window.$nuxt.$router;
1233
- }
1267
+ return window.$nuxt.$router;
1234
1268
  }
1235
1269
 
1236
1270
  get listLocation() {
@@ -1931,4 +1965,11 @@ export default class Resource {
1931
1965
  get creationTimestamp() {
1932
1966
  return this.metadata?.creationTimestamp;
1933
1967
  }
1968
+
1969
+ /**
1970
+ * Allows model to specify JSON Paths that should be folded in the YAML editor by default
1971
+ */
1972
+ get yamlFolding() {
1973
+ return [];
1974
+ }
1934
1975
  }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Load the directives
3
+ *
4
+ * These are included in a function that can be explictly called, so that we can be sure
5
+ * of the execution order, rather than importing them at the top of a file.
6
+ */
7
+ export function loadDirectives() {
8
+ import('./clean-html-directive');
9
+ import('./clean-tooltip-directive');
10
+ import('./directives');
11
+ }