@rancher/shell 0.3.4 → 0.3.6

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 (289) hide show
  1. package/assets/images/providers/outscale.svg +19 -0
  2. package/assets/styles/app.scss +1 -1
  3. package/assets/styles/base/_basic.scss +18 -0
  4. package/assets/styles/base/_mixins.scss +0 -11
  5. package/assets/styles/base/_variables.scss +2 -4
  6. package/assets/styles/fonts/_fontstack.scss +11 -11
  7. package/assets/styles/global/_button.scss +12 -2
  8. package/assets/styles/vendor/vue-js-modal.scss +3 -3
  9. package/assets/translations/en-us.yaml +113 -22
  10. package/assets/translations/zh-hans.yaml +113 -24
  11. package/babel.config.js +13 -0
  12. package/chart/gatekeeper.vue +78 -0
  13. package/chart/istio.vue +135 -112
  14. package/chart/logging/index.vue +13 -4
  15. package/chart/monitoring/index.vue +15 -5
  16. package/chart/monitoring/steps/uninstall-v1.vue +2 -2
  17. package/chart/rancher-backup/index.vue +10 -3
  18. package/cloud-credential/aws.vue +1 -1
  19. package/cloud-credential/digitalocean.vue +1 -1
  20. package/cloud-credential/gcp.vue +1 -1
  21. package/cloud-credential/generic.vue +2 -2
  22. package/cloud-credential/linode.vue +1 -1
  23. package/cloud-credential/pnap.vue +1 -1
  24. package/components/ActionMenu.vue +3 -4
  25. package/components/AssignTo.vue +1 -1
  26. package/components/AsyncButton.vue +1 -1
  27. package/components/BannerGraphic.vue +1 -1
  28. package/components/BrandImage.vue +1 -4
  29. package/components/ButtonDropdown.vue +2 -3
  30. package/components/Carousel.vue +85 -37
  31. package/components/ChartPsp.vue +76 -0
  32. package/components/CruResource.vue +6 -2
  33. package/components/DashboardMetrics.vue +12 -10
  34. package/components/DetailText.vue +1 -1
  35. package/components/DisableAuthProviderModal.vue +1 -1
  36. package/components/EmberPage.vue +1 -1
  37. package/components/EtcdInfoBanner.vue +12 -7
  38. package/components/ExplorerMembers.vue +101 -6
  39. package/components/ExplorerProjectsNamespaces.vue +46 -3
  40. package/components/FileDiff.vue +6 -7
  41. package/components/GrafanaDashboard.vue +27 -23
  42. package/components/LazyImage.vue +10 -12
  43. package/components/LogItem.vue +1 -1
  44. package/components/Markdown.vue +1 -1
  45. package/components/PromptRemove.vue +2 -2
  46. package/components/PromptRestore.vue +1 -1
  47. package/components/ResourceDetail/Masthead.vue +16 -0
  48. package/components/ResourceDetail/index.vue +21 -4
  49. package/components/ResourceList/index.vue +1 -1
  50. package/components/ResourceTable.vue +4 -1
  51. package/components/SingleClusterInfo.vue +2 -2
  52. package/components/SortableTable/THead.vue +1 -1
  53. package/components/SortableTable/index.vue +28 -13
  54. package/components/SortableTable/selection.js +58 -50
  55. package/components/Wizard.vue +4 -2
  56. package/components/__tests__/AsyncButton.test.ts +3 -1
  57. package/components/__tests__/ChartPsp.test.ts +75 -0
  58. package/components/__tests__/CruResource.test.ts +3 -1
  59. package/components/auth/Principal.vue +1 -1
  60. package/components/auth/RoleDetailEdit.vue +2 -2
  61. package/components/fleet/FleetBundles.vue +3 -1
  62. package/components/fleet/FleetClusters.vue +1 -2
  63. package/components/fleet/FleetIntro.vue +9 -1
  64. package/components/fleet/FleetNoWorkspaces.vue +62 -0
  65. package/components/fleet/FleetSummary.vue +7 -1
  66. package/components/form/HookOption.vue +14 -10
  67. package/components/form/LabeledSelect.vue +14 -11
  68. package/components/form/Labels.vue +32 -27
  69. package/components/form/MatchExpressions.vue +19 -4
  70. package/components/form/Members/ClusterPermissionsEditor.vue +32 -7
  71. package/components/form/NameNsDescription.vue +32 -46
  72. package/components/form/ProjectMemberEditor.vue +46 -21
  73. package/components/form/ResourceSelector.vue +1 -1
  74. package/components/form/SecretSelector.vue +5 -1
  75. package/components/form/ServiceNameSelect.vue +1 -1
  76. package/components/form/SimpleSecretSelector.vue +9 -9
  77. package/components/form/Tolerations.vue +4 -1
  78. package/components/form/ValueFromResource.vue +14 -9
  79. package/components/form/WorkloadPorts.vue +2 -2
  80. package/components/form/__tests__/LabeledSelect.test.ts +138 -0
  81. package/components/form/__tests__/NameNsDescription.ts +59 -0
  82. package/components/formatter/InternalExternalIP.vue +6 -0
  83. package/components/formatter/InvolvedObjectLink.vue +54 -0
  84. package/components/formatter/Link.vue +20 -4
  85. package/components/formatter/LinkName.vue +6 -1
  86. package/components/formatter/ServiceTargets.vue +1 -1
  87. package/components/formatter/WorkloadHealthScale.vue +8 -2
  88. package/components/nav/Group.vue +2 -2
  89. package/components/nav/NamespaceFilter.vue +23 -11
  90. package/components/nav/TopLevelMenu.vue +2 -4
  91. package/components/nav/Type.vue +1 -1
  92. package/components/nav/WorkspaceSwitcher.vue +46 -5
  93. package/components/nuxt/nuxt-build-indicator.vue +143 -0
  94. package/components/nuxt/nuxt-child.js +122 -0
  95. package/components/nuxt/nuxt-error.vue +98 -0
  96. package/components/nuxt/nuxt-link.client.js +98 -0
  97. package/components/nuxt/nuxt-link.server.js +16 -0
  98. package/components/nuxt/nuxt-loading.vue +154 -0
  99. package/components/nuxt/nuxt.js +101 -0
  100. package/config/labels-annotations.js +17 -0
  101. package/config/middleware.js +12 -0
  102. package/config/product/auth.js +3 -2
  103. package/config/product/explorer.js +34 -6
  104. package/config/product/fleet.js +2 -0
  105. package/config/query-params.js +1 -0
  106. package/config/router.js +414 -0
  107. package/config/store.js +181 -0
  108. package/config/table-headers.js +54 -12
  109. package/config/types.js +18 -8
  110. package/config/uiplugins.js +30 -0
  111. package/content/docs/en-us/whats-new.md +10 -0
  112. package/content/docs/zh-hans/whats-new.md +11 -1
  113. package/core/plugin-routes.ts +23 -0
  114. package/core/plugin.ts +4 -2
  115. package/core/types.ts +258 -1
  116. package/creators/app/app.package.json +2 -1
  117. package/creators/app/files/.eslintrc.js +1 -1
  118. package/creators/app/files/babel.config.js +1 -18
  119. package/creators/app/files/tsconfig.json +0 -1
  120. package/creators/app/files/vue.config.js +6 -0
  121. package/creators/app/init +5 -5
  122. package/creators/pkg/files/.github/workflows/build-extension.yml +110 -0
  123. package/creators/pkg/files/tsconfig.json +0 -1
  124. package/creators/pkg/init +35 -4
  125. package/creators/pkg/pkg.package.json +3 -3
  126. package/creators/update/init +1 -1
  127. package/detail/constraints.gatekeeper.sh.constraint.vue +34 -17
  128. package/detail/fleet.cattle.io.clustergroup.vue +7 -1
  129. package/detail/fleet.cattle.io.gitrepo.vue +19 -11
  130. package/detail/harvesterhci.io.management.cluster.vue +3 -3
  131. package/detail/provisioning.cattle.io.cluster.vue +54 -12
  132. package/detail/workload/index.vue +3 -3
  133. package/dialog/AddClusterMemberDialog.vue +1 -1
  134. package/dialog/AddProjectMemberDialog.vue +2 -2
  135. package/dialog/AddonConfigConfirmationDialog.vue +27 -15
  136. package/dialog/DiagnosticTimingsDialog.vue +1 -1
  137. package/dialog/ForceMachineRemoveDialog.vue +1 -1
  138. package/dialog/GenericPrompt.vue +18 -6
  139. package/dialog/RotateEncryptionKeyDialog.vue +1 -1
  140. package/dialog/SaveAsRKETemplateDialog.vue +1 -1
  141. package/dialog/ScaleMachineDownDialog.vue +1 -1
  142. package/edit/auth/github.vue +8 -8
  143. package/edit/auth/googleoauth.vue +5 -5
  144. package/edit/auth/ldap/index.vue +1 -1
  145. package/edit/auth/oidc.vue +1 -1
  146. package/edit/auth/saml.vue +1 -1
  147. package/edit/cis.cattle.io.clusterscan.vue +1 -1
  148. package/edit/fleet.cattle.io.clustergroup.vue +6 -4
  149. package/edit/fleet.cattle.io.gitrepo.vue +32 -4
  150. package/edit/helm.cattle.io.projecthelmchart.vue +5 -1
  151. package/edit/logging.banzaicloud.io.output/index.vue +18 -5
  152. package/edit/logging.banzaicloud.io.output/providers/loki.vue +1 -0
  153. package/edit/management.cattle.io.fleetworkspace.vue +141 -6
  154. package/edit/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +4 -1
  155. package/edit/management.cattle.io.setting.vue +1 -1
  156. package/edit/monitoring.coreos.com.alertmanagerconfig/types/webhook.vue +2 -2
  157. package/edit/monitoring.coreos.com.receiver/tls.vue +18 -18
  158. package/edit/monitoring.coreos.com.receiver/types/webhook.banner.vue +4 -4
  159. package/edit/monitoring.coreos.com.receiver/types/webhook.vue +1 -1
  160. package/edit/namespace.vue +14 -10
  161. package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +126 -45
  162. package/edit/networking.k8s.io.networkpolicy/index.vue +1 -1
  163. package/edit/provisioning.cattle.io.cluster/MachinePool.vue +21 -4
  164. package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +1 -0
  165. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +202 -2
  166. package/edit/provisioning.cattle.io.cluster/import.vue +23 -25
  167. package/edit/provisioning.cattle.io.cluster/rke2.vue +344 -102
  168. package/edit/resources.cattle.io.backup.vue +1 -1
  169. package/edit/service.vue +1 -1
  170. package/edit/storage.k8s.io.storageclass/provisioners/driver.harvesterhci.io.vue +2 -2
  171. package/edit/workload/__tests__/Job.test.ts +3 -1
  172. package/edit/workload/index.vue +8 -3
  173. package/edit/workload/mixins/workload.js +22 -7
  174. package/edit/workload/storage/Mount.vue +3 -3
  175. package/initialize/App.js +206 -0
  176. package/initialize/client.js +863 -0
  177. package/initialize/index.js +364 -0
  178. package/layouts/default.vue +7 -3
  179. package/layouts/standalone.vue +13 -0
  180. package/list/catalog.cattle.io.clusterrepo.vue +1 -0
  181. package/list/fleet.cattle.io.bundle.vue +6 -3
  182. package/list/fleet.cattle.io.clusterregistrationtoken.vue +3 -1
  183. package/list/fleet.cattle.io.gitrepo.vue +44 -5
  184. package/list/management.cattle.io.fleetworkspace.vue +45 -0
  185. package/list/node.vue +69 -16
  186. package/list/provisioning.cattle.io.cluster.vue +30 -1
  187. package/list/rbac.authorization.k8s.io.clusterrolebinding.vue +48 -0
  188. package/list/workload.vue +6 -4
  189. package/machine-config/azure.vue +97 -38
  190. package/middleware/authenticated.js +34 -0
  191. package/mixins/chart.js +101 -2
  192. package/mixins/fetch.client.js +95 -0
  193. package/mixins/fetch.server.js +73 -0
  194. package/mixins/labeled-form-element.ts +2 -2
  195. package/mixins/resource-fetch.js +2 -2
  196. package/models/apps.statefulset.js +28 -0
  197. package/models/cluster/node.js +23 -2
  198. package/models/cluster.x-k8s.io.machine.js +4 -2
  199. package/models/clusterroletemplatebinding.js +7 -0
  200. package/models/constraints.gatekeeper.sh.constraint.js +46 -0
  201. package/models/fleet.cattle.io.cluster.js +19 -10
  202. package/models/fleet.cattle.io.gitrepo.js +7 -2
  203. package/models/management.cattle.io.cluster.js +1 -1
  204. package/models/management.cattle.io.fleetworkspace.js +12 -0
  205. package/models/management.cattle.io.gitreporestriction.js +5 -0
  206. package/models/management.cattle.io.podsecurityadmissionconfigurationtemplate.js +3 -0
  207. package/models/pod.js +4 -0
  208. package/models/provisioning.cattle.io.cluster.js +7 -5
  209. package/models/rbac.authorization.k8s.io.clusterrolebinding.js +16 -0
  210. package/models/rbac.authorization.k8s.io.rolebinding.js +16 -0
  211. package/package.json +13 -21
  212. package/pages/auth/setup.vue +2 -2
  213. package/pages/c/_cluster/apps/charts/__tests__/install.helper.test.ts +33 -0
  214. package/pages/c/_cluster/apps/charts/chart.vue +4 -4
  215. package/pages/c/_cluster/apps/charts/install.helpers.js +26 -0
  216. package/pages/c/_cluster/apps/charts/install.vue +98 -102
  217. package/pages/c/_cluster/explorer/EventsTable.vue +5 -19
  218. package/pages/c/_cluster/explorer/index.vue +29 -25
  219. package/pages/c/_cluster/explorer/tools/index.vue +8 -8
  220. package/pages/c/_cluster/fleet/index.vue +95 -34
  221. package/pages/c/_cluster/gatekeeper/index.vue +1 -1
  222. package/pages/c/_cluster/istio/index.vue +5 -5
  223. package/pages/c/_cluster/manager/cloudCredential/index.vue +1 -1
  224. package/pages/c/_cluster/monitoring/index.vue +7 -0
  225. package/pages/c/_cluster/uiplugins/InstallDialog.vue +8 -8
  226. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +20 -7
  227. package/pages/c/_cluster/uiplugins/index.vue +49 -17
  228. package/pages/diagnostic.vue +32 -25
  229. package/pages/home.vue +9 -4
  230. package/pages/index.vue +10 -1
  231. package/pages/rio/mesh.vue +1 -2
  232. package/pkg/tsconfig.json +0 -1
  233. package/plugins/clean-html-directive.js +34 -0
  234. package/plugins/dashboard-store/actions.js +32 -9
  235. package/plugins/dashboard-store/index.js +1 -1
  236. package/plugins/dashboard-store/mutations.js +5 -2
  237. package/plugins/dashboard-store/resource-class.js +8 -1
  238. package/plugins/plugin.js +0 -14
  239. package/plugins/portal-vue.js +4 -0
  240. package/plugins/steve/mutations.js +3 -2
  241. package/plugins/steve/steve-description-class.js +5 -1
  242. package/plugins/steve/subscribe.js +63 -54
  243. package/plugins/steve-create-worker.js +14 -0
  244. package/promptRemove/management.cattle.io.globalrole.vue +2 -2
  245. package/promptRemove/management.cattle.io.project.vue +2 -2
  246. package/promptRemove/management.cattle.io.roletemplate.vue +2 -2
  247. package/promptRemove/pod.vue +1 -1
  248. package/public/index.html +65 -0
  249. package/rancher-components/components/Banner/Banner.test.ts +7 -1
  250. package/rancher-components/components/Banner/Banner.vue +2 -1
  251. package/rancher-components/components/Form/Checkbox/Checkbox.vue +2 -0
  252. package/rancher-components/components/Form/Radio/RadioButton.test.ts +31 -0
  253. package/rancher-components/components/Form/Radio/RadioButton.vue +14 -3
  254. package/scripts/build-pkg.sh +1 -0
  255. package/scripts/clean +6 -0
  256. package/scripts/extension/bundle +58 -0
  257. package/scripts/extension/helmpatch +89 -0
  258. package/scripts/extension/publish +333 -0
  259. package/scripts/serve-pkgs +6 -2
  260. package/scripts/test-plugins-build.sh +4 -0
  261. package/store/__tests__/index.test.ts +110 -0
  262. package/store/index.js +145 -58
  263. package/store/type-map.js +6 -2
  264. package/tsconfig.default.json +36 -0
  265. package/tsconfig.json +23 -0
  266. package/types/rancher/index.d.ts +2 -0
  267. package/types/shell/index.d.ts +466 -320
  268. package/utils/__tests__/grafana.test.ts +44 -0
  269. package/utils/__tests__/string.test.ts +12 -0
  270. package/utils/auth.js +65 -0
  271. package/utils/axios.js +190 -0
  272. package/utils/cookie-universal-nuxt.js +10 -0
  273. package/utils/dom.js +15 -0
  274. package/utils/grafana.js +35 -16
  275. package/utils/monitoring.js +2 -1
  276. package/utils/nuxt.js +659 -0
  277. package/utils/position.js +5 -8
  278. package/utils/router.scrollBehavior.js +80 -0
  279. package/utils/select.js +1 -3
  280. package/utils/socket.js +1 -0
  281. package/utils/string.js +13 -0
  282. package/utils/time.js +9 -0
  283. package/vue.config.js +690 -0
  284. package/chart/rancher-alerting-drivers.vue +0 -53
  285. package/chart/rancher-gatekeeper.vue +0 -37
  286. package/creators/app/files/nuxt.config.js +0 -6
  287. package/models/management.cattle.io.podsecurityadmissionconfigurationtemplate.ts +0 -4
  288. package/nuxt.config.js +0 -798
  289. package/plugins/dashboard-store/extensions.js +0 -22
@@ -21,6 +21,7 @@ import Socket, {
21
21
  EVENT_DISCONNECT_ERROR,
22
22
  NO_WATCH,
23
23
  NO_SCHEMA,
24
+ REVISION_TOO_OLD
24
25
  } from '@shell/utils/socket';
25
26
  import { normalizeType } from '@shell/plugins/dashboard-store/normalize';
26
27
  import day from 'dayjs';
@@ -29,8 +30,6 @@ import { escapeHtml } from '@shell/utils/string';
29
30
  import { keyForSubscribe } from '@shell/plugins/steve/resourceWatcher';
30
31
  import { waitFor } from '@shell/utils/async';
31
32
 
32
- // eslint-disable-next-line
33
- import storeWorker from './worker/index.js';
34
33
  import { BLANK_CLUSTER } from '@shell/store/index.js';
35
34
 
36
35
  // minimum length of time a disconnect notification is shown
@@ -97,7 +96,7 @@ export async function createWorker(store, ctx) {
97
96
 
98
97
  if (!store.$workers[storeName]) {
99
98
  const workerMode = advancedWorker ? 'advanced' : 'basic';
100
- const worker = storeWorker(workerMode);
99
+ const worker = store.steveCreateWorker(workerMode);
101
100
 
102
101
  store.$workers[storeName] = worker;
103
102
 
@@ -307,8 +306,13 @@ const sharedActions = {
307
306
  }
308
307
 
309
308
  // If socket is in error don't try to watch.... unless we `force` it
310
- if ( !stop && !force && !getters.canWatch(params) ) {
311
- console.error(`Cannot Watch [${ getters.storeName }]`, JSON.stringify(params)); // eslint-disable-line no-console
309
+ const inError = getters.inError(params);
310
+
311
+ if ( !stop && !force && inError ) {
312
+ // REVISION_TOO_OLD is a temporary state and will be handled when `resyncWatch` completes
313
+ if (inError !== REVISION_TOO_OLD) {
314
+ console.error(`Aborting Watch Request [${ getters.storeName }]. Watcher in error (${ inError })`, JSON.stringify(params)); // eslint-disable-line no-console
315
+ }
312
316
 
313
317
  return;
314
318
  }
@@ -316,7 +320,10 @@ const sharedActions = {
316
320
  if ( !stop && getters.watchStarted({
317
321
  type, id, selector, namespace
318
322
  }) ) {
319
- state.debugSocket && console.debug(`Already Watching [${ getters.storeName }]`, JSON.stringify(params)); // eslint-disable-line no-console
323
+ // eslint-disable-next-line no-console
324
+ state.debugSocket && console.debug(`Already Watching [${ getters.storeName }]`, {
325
+ type, id, selector, namespace
326
+ });
320
327
 
321
328
  return;
322
329
  }
@@ -347,7 +354,7 @@ const sharedActions = {
347
354
  msg.selector = selector;
348
355
  }
349
356
 
350
- const worker = this.$workers[getters.storeName] || {};
357
+ const worker = this.$workers?.[getters.storeName] || {};
351
358
 
352
359
  if (worker.mode === 'advanced') {
353
360
  if ( force ) {
@@ -362,12 +369,17 @@ const sharedActions = {
362
369
  return dispatch('send', msg);
363
370
  },
364
371
 
365
- unwatch(ctx, type) {
372
+ unwatch(ctx, {
373
+ type, id, namespace, selector
374
+ }) {
366
375
  const { commit, getters, dispatch } = ctx;
367
376
 
368
377
  if (getters['schemaFor'](type)) {
369
378
  const obj = {
370
379
  type,
380
+ id,
381
+ namespace,
382
+ selector,
371
383
  stop: true, // Stops the watch on a type
372
384
  };
373
385
 
@@ -675,14 +687,30 @@ const defaultActions = {
675
687
  /**
676
688
  * Steve only event
677
689
  */
678
- 'ws.resource.start'({ state, getters, commit }, msg) {
690
+ 'ws.resource.start'({
691
+ state, getters, commit, dispatch
692
+ }, msg) {
679
693
  state.debugSocket && console.info(`Resource start: [${ getters.storeName }]`, msg); // eslint-disable-line no-console
680
- commit('setWatchStarted', {
694
+
695
+ const newWatch = {
681
696
  type: msg.resourceType,
682
697
  namespace: msg.namespace,
683
698
  id: msg.id,
684
699
  selector: msg.selector
700
+ };
701
+
702
+ state.started.filter((entry) => {
703
+ if (
704
+ entry.type === newWatch.type &&
705
+ entry.namespace !== newWatch.namespace
706
+ ) {
707
+ return true;
708
+ }
709
+ }).forEach((entry) => {
710
+ dispatch('unwatch', entry);
685
711
  });
712
+
713
+ commit('setWatchStarted', newWatch);
686
714
  },
687
715
 
688
716
  'ws.resource.error'({ getters, commit, dispatch }, msg) {
@@ -695,6 +723,10 @@ const defaultActions = {
695
723
  } else if ( err.includes('failed to find schema') ) {
696
724
  commit('setInError', { type: msg.resourceType, reason: NO_SCHEMA });
697
725
  } else if ( err.includes('too old') ) {
726
+ // Set an error for (all) subs of this type. This..
727
+ // 1) blocks attempts by resource.stop to resub (as type is in error)
728
+ // 2) will be cleared when resyncWatch --> watch (with force) --> resource.start completes
729
+ commit('setInError', { type: msg.resourceType, reason: REVISION_TOO_OLD });
698
730
  dispatch('resyncWatch', msg);
699
731
  }
700
732
  },
@@ -702,12 +734,15 @@ const defaultActions = {
702
734
  /**
703
735
  * Steve only event
704
736
  *
705
- * Steve only seems to send out `resource.stop` messages for two reasons
706
- * - We have requested that the resource watch should be stopped and we receive this event as confirmation
707
- * - Steve tells us that the resource is no longer watched
708
- *
737
+ * Steve has stopped watching this resource. This happens for a couple of reasons
738
+ * - We have requested that the resource watch should be stopped (and we receive this event as confirmation)
739
+ * - Steve tells us that the resource watch has been stopped. Possible reasons
740
+ * - The rancher <--> k8s socket closed (happens every ~30 mins on mgmt socket)
741
+ * - Permissions has changed for the subscribed resource, so rancher closes socket
709
742
  */
710
- 'ws.resource.stop'({ getters, commit, dispatch }, msg) {
743
+ 'ws.resource.stop'({
744
+ state, getters, commit, dispatch
745
+ }, msg) {
711
746
  const type = msg.resourceType;
712
747
  const obj = {
713
748
  type,
@@ -716,51 +751,23 @@ const defaultActions = {
716
751
  selector: msg.selector
717
752
  };
718
753
 
719
- // console.warn(`Resource stop: [${ getters.storeName }]`, msg); // eslint-disable-line no-console
754
+ state.debugSocket && console.info(`Resource Stop [${ getters.storeName }]`, type, msg); // eslint-disable-line no-console
755
+
756
+ if (!type) {
757
+ console.error(`Resource Stop [${ getters.storeName }]. Received resource.stop with an empty resourceType, aborting`, msg); // eslint-disable-line no-console
758
+
759
+ return;
760
+ }
720
761
 
721
762
  // If we're trying to watch this event, attempt to re-watch
722
763
  if ( getters['schemaFor'](type) && getters['watchStarted'](obj) ) {
723
764
  commit('setWatchStopped', obj);
724
-
725
- // In summary, we need to re-watch but with a reliable `revision` (to avoid `too old` message kicking off a full re-fetch of all
726
- // resources). To get a reliable `revision` go out and fetch the latest for that resource type, in theory our local cache should be
727
- // up to date with that revision.
728
-
729
- const revisionExisting = getters.nextResourceVersion(type, obj.id);
730
-
731
- let revisionLatest;
732
-
733
- if (revisionExisting) {
734
- // Attempt to fetch the latest revision at the time the resource watch was stopped, in theory our local cache should be up to
735
- // date with this
736
- // Ideally we shouldn't need to fetch here and supply `0`, `-1` or `null` to start watching from the latest revision, however steve
737
- // will send the current state of each resource via a `resource.created` event.
738
- const opt = { limit: 1 };
739
-
740
- opt.url = getters.urlFor(type, null, opt);
741
- revisionLatest = dispatch('request', { opt, type } )
742
- .then(res => res.revision)
743
- .catch((err) => {
744
- // For some reason we can't fetch a reasonable revision, so force a re-fetch
745
- console.warn(`Resource error retrieving resourceVersion, forcing re-fetch`, type, ':', err); // eslint-disable-line no-console
746
- dispatch('resyncWatch', msg);
747
- throw err;
748
- });
749
- } else {
750
- // Some v1 resource types don't have revisions (either at the collection or resource level), so we avoided making an API request
751
- // for them
752
- revisionLatest = Promise.resolve(null); // Null to ensure we don't go through `nextResourceVersion` again
753
- }
754
-
755
- setTimeout(() => {
756
- // Delay a bit so that immediate start/error/stop causes
757
- // only a slow infinite loop instead of a tight one.
758
- revisionLatest.then(revision => dispatch('watch', { ...obj, revision }));
759
- }, 5000);
765
+ dispatch('watch', obj);
760
766
  }
761
767
  },
762
768
 
763
769
  'ws.resource.create'(ctx, msg) {
770
+ ctx.state.debugSocket && console.info(`Resource Create [${ ctx.getters.storeName }]`, msg.resourceType, msg); // eslint-disable-line no-console
764
771
  queueChange(ctx, msg, true, 'Create');
765
772
  },
766
773
 
@@ -811,6 +818,8 @@ const defaultActions = {
811
818
  const data = msg.data;
812
819
  const type = data.type;
813
820
 
821
+ ctx.state.debugSocket && console.info(`Resource Remove [${ ctx.getters.storeName }]`, type, msg); // eslint-disable-line no-console
822
+
814
823
  if (type === SCHEMA) {
815
824
  const worker = (this.$workers || {})[ctx.getters.storeName];
816
825
 
@@ -914,8 +923,8 @@ const defaultMutations = {
914
923
  * Getters that cover cases 1 & 2 (see file description)
915
924
  */
916
925
  const defaultGetters = {
917
- canWatch: state => (obj) => {
918
- return !state.inError[keyForSubscribe(obj)];
926
+ inError: state => (obj) => {
927
+ return state.inError[keyForSubscribe(obj)];
919
928
  },
920
929
 
921
930
  watchStarted: state => (obj) => {
@@ -0,0 +1,14 @@
1
+ import createWorker from './steve/worker/index.js';
2
+
3
+ /**
4
+ * Link the steve worker creator to the store
5
+ *
6
+ * This is done to allow disassociate (no import chain) access to the steve worker file.
7
+ * Without this third party plugins (in given scenarios / harvester) will fail to build
8
+ * due to missing web worker specific build config
9
+ *
10
+ * Note - When rancher/steve store is spun out in to a extension this also needs to move out
11
+ */
12
+ export default function({ store }) {
13
+ store.steveCreateWorker = createWorker;
14
+ }
@@ -23,14 +23,14 @@ export default {
23
23
  <div>
24
24
  <template>
25
25
  {{ t('promptRemove.attemptingToRemove', { type }) }} <span
26
- v-html="resourceNames(names, plusMore, t)"
26
+ v-clean-html="resourceNames(names, plusMore, t)"
27
27
  />
28
28
  </template>
29
29
  <div
30
30
  v-if="info"
31
31
  class="text info mb-10 mt-20"
32
32
  >
33
- <span v-html="info" />
33
+ <span v-clean-html="info" />
34
34
  </div>
35
35
  <div
36
36
  v-if="warning"
@@ -100,8 +100,8 @@ export default {
100
100
  <template v-if="!canSeeProjectlessNamespaces">
101
101
  <span class="delete-warning"> {{ t('promptRemove.willDeleteAssociatedNamespaces') }}</span> <br>
102
102
  <div
103
+ v-clean-html="resourceNames(names, plusMore, t)"
103
104
  class="mt-10"
104
- v-html="resourceNames(names, plusMore, t)"
105
105
  />
106
106
  </template>
107
107
  </div>
@@ -114,7 +114,7 @@ export default {
114
114
  :label="t('promptRemove.deleteAssociatedNamespaces')"
115
115
  />
116
116
  <div class="mt-10 ml-20">
117
- <span v-html="resourceNames(names, plusMore, t)" />
117
+ <span v-clean-html="resourceNames(names, plusMore, t)" />
118
118
  </div>
119
119
  </div>
120
120
  </div>
@@ -23,14 +23,14 @@ export default {
23
23
  <div>
24
24
  <template>
25
25
  {{ t('promptRemove.attemptingToRemove', { type }) }} <span
26
- v-html="resourceNames(names, plusMore, t)"
26
+ v-clean-html="resourceNames(names, plusMore, t)"
27
27
  />
28
28
  </template>
29
29
  <div
30
30
  v-if="info"
31
31
  class="text info mb-10 mt-20"
32
32
  >
33
- <span v-html="info" />
33
+ <span v-clean-html="info" />
34
34
  </div>
35
35
  <div
36
36
  v-if="warning"
@@ -108,8 +108,8 @@ export default {
108
108
  <div class="mt-10">
109
109
  <div class="mb-30">
110
110
  {{ t('promptRemove.attemptingToRemove', { type }) }} <span
111
+ v-clean-html="podNames"
111
112
  class="machine-name"
112
- v-html="podNames"
113
113
  />
114
114
  </div>
115
115
  <div class="mb-30">
@@ -0,0 +1,65 @@
1
+ <!DOCTYPE html>
2
+ <html lang="">
3
+
4
+ <head>
5
+ <meta charset="utf-8">
6
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
7
+ <meta name="viewport" content="width=device-width,initial-scale=1.0">
8
+ <link rel="shortcut icon" type="image/x-icon" href="/public/favicon.png">
9
+ <title>Rancher</title>
10
+ </head>
11
+
12
+ <body>
13
+ <div id="app">
14
+ <script>
15
+ (() => {
16
+ const isDark = document.cookie.includes('R_PCS=dark');
17
+ const color = isDark ? '#1b1c21' : '#FFF';
18
+ const style = document.createElement('style');
19
+ style.innerHTML = ':root { --loading-bg-color: ' + color + ';}';
20
+ document.getElementsByTagName('head')[0].prepend(style);
21
+ })();
22
+ </script>
23
+ <style>
24
+ .initial-load-spinner-container {
25
+ align-items: center;
26
+ background-color: var(--loading-bg-color);
27
+ display: flex;
28
+ justify-content: center;
29
+ height: 100vh;
30
+ left: 0;
31
+ position: absolute;
32
+ top: 0;
33
+ width: 100vw;
34
+ }
35
+
36
+ .initial-load-spinner {
37
+ animation: initial-load-animate 1s infinite linear;
38
+ background-color: var(--loading-bg-color);
39
+ box-sizing: border-box;
40
+ border: 5px solid #008ACF;
41
+ border-radius: 50%;
42
+ border-top-color: #00B2E2;
43
+ display: inline-block;
44
+ height: 80px;
45
+ margin: 0 auto;
46
+ width: 80px;
47
+ }
48
+
49
+ @keyframes initial-load-animate {
50
+ 0% {
51
+ transform: rotate(0deg);
52
+ }
53
+
54
+ 100% {
55
+ transform: rotate(359deg);
56
+ }
57
+ }
58
+ </style>
59
+ <div class="initial-load-spinner-container">
60
+ <i class="initial-load-spinner"></i>
61
+ </div>
62
+ </div>
63
+ </body>
64
+
65
+ </html>
@@ -1,10 +1,16 @@
1
1
  import { mount } from '@vue/test-utils';
2
2
  import { Banner } from './index';
3
+ import { cleanHtmlDirective } from '@shell/plugins/clean-html-directive';
3
4
 
4
5
  describe('component: Banner', () => {
5
6
  it('should display text based on label', () => {
6
7
  const label = 'test';
7
- const wrapper = mount(Banner, { propsData: { label } });
8
+ const wrapper = mount(
9
+ Banner,
10
+ {
11
+ directives: { cleanHtmlDirective },
12
+ propsData: { label }
13
+ });
8
14
 
9
15
  const element = wrapper.find('span').element;
10
16
 
@@ -95,7 +95,7 @@ export default Vue.extend({
95
95
  <span v-else-if="messageLabel">{{ messageLabel }}</span>
96
96
  <span
97
97
  v-else
98
- v-html="nlToBr(label)"
98
+ v-clean-html="nlToBr(label)"
99
99
  />
100
100
  </slot>
101
101
  <div
@@ -164,6 +164,7 @@ $icon-size: 24px;
164
164
  width: 100%;
165
165
  border-left: solid $left-border-size transparent;
166
166
  display: flex;
167
+ gap: 3px;
167
168
 
168
169
  .primary & {
169
170
  background: var(--primary);
@@ -5,6 +5,8 @@ import { addObject, removeObject } from '@shell/utils/array';
5
5
  import cloneDeep from 'lodash/cloneDeep';
6
6
 
7
7
  export default Vue.extend({
8
+ name: 'Checkbox',
9
+
8
10
  props: {
9
11
  /**
10
12
  * The checkbox value.
@@ -0,0 +1,31 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import { RadioButton } from './index';
3
+ import { cleanHtmlDirective } from '@shell/plugins/clean-html-directive';
4
+
5
+ describe('RadioButton.vue', () => {
6
+ it('renders label slot contents', () => {
7
+ const wrapper = shallowMount(RadioButton, { slots: { label: 'Test Label' } });
8
+
9
+ expect(wrapper.find('.radio-label').text()).toBe('Test Label');
10
+ });
11
+
12
+ it('renders label prop contents', () => {
13
+ const wrapper = shallowMount(
14
+ RadioButton,
15
+ {
16
+ directives: { cleanHtmlDirective },
17
+ propsData: { label: 'Test Label' }
18
+ });
19
+
20
+ expect(wrapper.find('.radio-label').text()).toBe('Test Label');
21
+ });
22
+
23
+ it('renders slot contents when both slot and label prop are provided', () => {
24
+ const wrapper = shallowMount(RadioButton, {
25
+ slots: { label: 'Test Label - Slot' },
26
+ propsData: { label: 'Test Label - Props' },
27
+ });
28
+
29
+ expect(wrapper.find('.radio-label').text()).toBe('Test Label - Slot');
30
+ });
31
+ });
@@ -96,6 +96,10 @@ export default Vue.extend({
96
96
  hasDescriptionSlot(): boolean {
97
97
  return !!this.$slots.description;
98
98
  },
99
+
100
+ hasLabelSlot(): boolean {
101
+ return !!this.$slots.label || !!this.$scopedSlots.label;
102
+ }
99
103
  },
100
104
 
101
105
  watch: {
@@ -149,12 +153,19 @@ export default Vue.extend({
149
153
  />
150
154
  <div class="labeling">
151
155
  <label
152
- v-if="label"
153
156
  :class="[ muteLabel ? 'text-muted' : '', 'radio-label', 'm-0']"
154
157
  :for="name"
155
- v-html="label"
156
158
  >
157
- <slot name="label">{{ label }}</slot>
159
+ <slot
160
+ v-if="hasLabelSlot"
161
+ name="label"
162
+ >
163
+ <!-- slot content -->
164
+ </slot>
165
+ <span
166
+ v-else-if="label"
167
+ v-clean-html="label"
168
+ />
158
169
  </label>
159
170
  <div
160
171
  v-if="descriptionKey || description"
@@ -40,6 +40,7 @@ if [ -d "${BASE_DIR}/pkg/${1}" ]; then
40
40
  echo " Package name: ${NAME}"
41
41
  echo " Package version: ${VERSION}"
42
42
  echo " Output formats: ${FORMATS}"
43
+ echo " Output directory: ${PKG_DIST}"
43
44
  rm -rf ${PKG_DIST}
44
45
  mkdir -p ${PKG_DIST}
45
46
 
package/scripts/clean ADDED
@@ -0,0 +1,6 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ cd $(dirname $0)/..
5
+
6
+ rm -rf dist .nuxt* node_modules/.cache
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env bash
2
+
3
+ BASE_DIR="$(pwd)"
4
+
5
+ CYAN="\033[96m"
6
+ RED="\033[91m"
7
+ RESET="\033[0m"
8
+ BOLD="\033[1m"
9
+
10
+ TMP=${BASE_DIR}/tmp
11
+ CHART_TEMPLATE=${TMP}/ui-plugin-server
12
+
13
+ PKG="${1}"
14
+ PKG_VERSION="${2}"
15
+ REGISTRY="${3}"
16
+ REGISTRY_ORG="${4}"
17
+ IMAGE_PREFIX="${5}"
18
+ PUSH="${6}"
19
+
20
+ PKG_NAME="${PKG}-${PKG_VERSION}"
21
+
22
+ # --------------------------------------------------------------------------------
23
+ # Create the container image
24
+ # --------------------------------------------------------------------------------
25
+ mkdir -p ${TMP}/container
26
+ cp -R ${CHART_TEMPLATE}/* ${TMP}/container/
27
+
28
+ # Copy the plugin assets
29
+ rm -rf ${TMP}/container/plugin
30
+ mkdir ${TMP}/container/plugin
31
+
32
+ cp -R ${BASE_DIR}/dist-pkg/${PKG_NAME}/* ${TMP}/container/plugin
33
+ rm -f ${TMP}/container/plugin/report.html
34
+
35
+ # Build the docker image
36
+ pushd ${TMP}/container > /dev/null
37
+ echo -e "${CYAN}Building container image ...${RESET}"
38
+
39
+ if [ ! -z "${REGISTRY}" ]; then
40
+ REGISTRY=${REGISTRY} ORG=${REGISTRY_ORG} REPO=${IMAGE_PREFIX}${PKG} TAG=${PKG_VERSION} ./scripts/package
41
+
42
+ if [ "${PUSH}" == "--push" ]; then
43
+ echo -e "${CYAN}Pushing container image ...${RESET}"
44
+
45
+ # Ensure that you do not overwrite production images
46
+ if [[ "${REGISTRY_ORG}" == "rancher" ]]; then
47
+ IMAGE=${REGISTRY}${REGISTRY_ORG}/${IMAGE_PREFIX}${PKG}:${PKG_VERSION}
48
+ if docker manifest inspect 2>&1 1>/dev/null; then
49
+ echo -e "${RED}${BOLD}Cannot overwrite production image ${IMAGE_PREFIX}${PKG} since it already exists${RESET}"
50
+ exit 1
51
+ fi
52
+ fi
53
+
54
+ docker push ${REGISTRY}${REGISTRY_ORG}/${IMAGE_PREFIX}${PKG}:${PKG_VERSION}
55
+ fi
56
+ fi
57
+
58
+ popd > /dev/null
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Update Chart.yaml and values.yaml files
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const yaml = require('js-yaml');
8
+
9
+ // TODO: Should already be in the template
10
+ // const UI_PLUGIN_ANNOTATION_NAME = 'catalog.cattle.io/ui-component';
11
+ // const UI_PLUGIN_ANNOTATION_VALUE = 'plugins';
12
+
13
+ console.log('Helm file update');
14
+
15
+ if (process.argv.length !== 5) {
16
+ console.log('Incorrect number of arguments');
17
+ process.exit(1);
18
+ }
19
+
20
+ const destFolder = process.argv[2];
21
+ const pkgFilePath = process.argv[3];
22
+ const image = process.argv[4];
23
+
24
+ const pkgFile = JSON.parse(fs.readFileSync(pkgFilePath, 'utf8'));
25
+
26
+ const chartFolder = destFolder;
27
+ const chartFile = path.join(chartFolder, 'Chart.yaml');
28
+ const valuesFile = path.join(chartFolder, 'values.yaml');
29
+
30
+ if (!fs.existsSync(chartFolder)) {
31
+ console.log('Charts folder does not exist');
32
+ process.exit(1);
33
+ }
34
+
35
+ // --------------------------------------------------------------------------------
36
+ // Chart.yaml
37
+ // --------------------------------------------------------------------------------
38
+ const chart = yaml.load(fs.readFileSync(chartFile, 'utf8'));
39
+ let updated = false;
40
+
41
+ // Add in annotations to match any rules in the package file
42
+ if (pkgFile.rancher && typeof pkgFile.rancher === 'object') {
43
+ // See if there are any annotations and merge them in, if there are
44
+ if (pkgFile.rancher.annotations) {
45
+ chart.annotations = chart.annotations || {};
46
+ Object.keys(pkgFile.rancher.annotations).forEach((key) => {
47
+ chart.annotations[key] = pkgFile.rancher.annotations[key];
48
+ updated = true;
49
+ });
50
+ }
51
+ }
52
+
53
+ if (updated ){
54
+ // Write out updated file
55
+ const str = yaml.dump(chart);
56
+
57
+ fs.writeFileSync(chartFile, str, 'utf8');
58
+ }
59
+
60
+ // chart.name = pkgFile.name;
61
+ // chart.appVersion = pkgFile.version;
62
+ // chart.version = pkgFile.version;
63
+ // chart.description = pkgFile.description || `${pkgFile.name} ui plugin `;
64
+ // chart.annotations[UI_PLUGIN_ANNOTATION_NAME] = UI_PLUGIN_ANNOTATION_VALUE;
65
+
66
+ // if (pkgFile.icon) {
67
+ // chart.icon = pkgFile.icon;
68
+ // }
69
+
70
+ // if (pkgFile.keywords) {
71
+ // chart.keywords = pkgFile.keywords;
72
+ // } else {
73
+ // chart.keywords = [];
74
+ // }
75
+
76
+ // if (pkgFile.homepage) {
77
+ // chart.home = pkgFile.homepage;
78
+ // }
79
+
80
+ // --------------------------------------------------------------------------------
81
+ // values.yaml
82
+ // --------------------------------------------------------------------------------
83
+
84
+ const values = yaml.load(fs.readFileSync(valuesFile, 'utf8'));
85
+
86
+ values.pluginServer.image.repository = `${image}`;
87
+
88
+ const valuesYaml = yaml.dump(values, {quotingType: '"' });
89
+ fs.writeFileSync(valuesFile, valuesYaml, 'utf8');