@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
@@ -15,6 +15,7 @@ import Tab from '@shell/components/Tabbed/Tab';
15
15
 
16
16
  import { allHash } from '@shell/utils/promise';
17
17
  import { STORAGE_CLASS, PVC, SECRET, WORKLOAD_TYPES } from '@shell/config/types';
18
+ import { CATTLE_MONITORING_NAMESPACE } from '@shell/utils/monitoring';
18
19
 
19
20
  export default {
20
21
  components: {
@@ -52,17 +53,40 @@ export default {
52
53
  async fetch() {
53
54
  const { $store } = this;
54
55
 
55
- const hash = await allHash({
56
- namespaces: $store.getters['namespaces'](),
57
- pvcs: $store.dispatch('cluster/findAll', { type: PVC }),
58
- secrets: $store.dispatch('cluster/findAll', { type: SECRET }),
56
+ // Fetch all the resources required for all the tabs asyncronously up front
57
+ const hashPromises = {
58
+ namespaces: $store.getters['namespaces'](),
59
+ pvcs: $store.dispatch('cluster/findAll', { type: PVC }),
60
+ // Used in Alerting tab
61
+ monitoringSecrets: $store.dispatch('cluster/findAll', {
62
+ type: SECRET,
63
+ opt: { namespaced: CATTLE_MONITORING_NAMESPACE }
64
+ }),
59
65
  storageClasses: $store.dispatch('cluster/findAll', { type: STORAGE_CLASS }),
66
+ };
67
+
68
+ // Are we editing an existing chart?
69
+ // (ported from shell/chart/monitoring/prometheus/index.vue)
70
+ const { existing = false } = this.$attrs;
71
+
72
+ // If needed, fetch all the workloads that have prometheus operator like containers
73
+ this.workloadTypes = !existing ? Object.values(WORKLOAD_TYPES) : [];
74
+
75
+ this.workloadTypes.forEach((type) => {
76
+ // We'll use a filter to fetch the results. Atm there's no neat way to differentiate between ALL results and JUST filtered
77
+ // So to avoid calls to all getting these filtered (and vice-versa) forget type before and after
78
+ $store.dispatch('cluster/forgetType', type);
79
+ hashPromises[type] = $store.dispatch('cluster/findAll', {
80
+ type,
81
+ opt: {
82
+ watch: false,
83
+ // We're only interested in images with operator like names (note: these will match partial strings)
84
+ filter: { 'spec.template.spec.containers.image': ['quay.io/coreos/prometheus-operator', 'rancher/coreos-prometheus-operator'] }
85
+ }
86
+ });
60
87
  });
61
88
 
62
- await Promise.all(
63
- Object.values(WORKLOAD_TYPES).map((type) => this.$store.dispatch('cluster/findAll', { type })
64
- )
65
- );
89
+ const hash = await allHash(hashPromises);
66
90
 
67
91
  this.targetNamespace = hash.namespaces[this.chart.targetNamespace] || false;
68
92
 
@@ -74,9 +98,21 @@ export default {
74
98
  this.pvcs = hash.pvcs;
75
99
  }
76
100
 
77
- if (!isEmpty(hash.secrets)) {
78
- this.secrets = hash.secrets;
101
+ if (!isEmpty(hash.monitoringSecrets)) {
102
+ this.monitoringSecrets = hash.monitoringSecrets;
79
103
  }
104
+
105
+ this.workloadTypes.forEach((type) => {
106
+ if (hash[type]) {
107
+ this.filteredWorkloads.push(...hash[type]);
108
+ }
109
+ });
110
+ },
111
+
112
+ beforeDestroy() {
113
+ this.workloadTypes.forEach((type) => {
114
+ this.$store.dispatch('cluster/forgetType', type);
115
+ });
80
116
  },
81
117
 
82
118
  data() {
@@ -99,9 +135,11 @@ export default {
99
135
  disableAggregateRoles: false,
100
136
  prometheusResources: [],
101
137
  pvcs: [],
102
- secrets: [],
138
+ monitoringSecrets: [],
103
139
  storageClasses: [],
104
140
  targetNamespace: null,
141
+ filteredWorkloads: [],
142
+ workloadTypes: []
105
143
  };
106
144
  },
107
145
 
@@ -110,10 +148,6 @@ export default {
110
148
  provider() {
111
149
  return this.currentCluster.status.provider.toLowerCase();
112
150
  },
113
- workloads() {
114
- return Object.values(WORKLOAD_TYPES).flatMap((type) => this.$store.getters['cluster/all'](type)
115
- );
116
- },
117
151
  },
118
152
 
119
153
  watch: {
@@ -278,7 +312,7 @@ export default {
278
312
  :mode="mode"
279
313
  :storage-classes="storageClasses"
280
314
  :prometheus-pods="prometheusResources"
281
- :workloads="workloads"
315
+ :filteredWorkloads="filteredWorkloads"
282
316
  />
283
317
  </div>
284
318
  </Tab>
@@ -291,7 +325,7 @@ export default {
291
325
  <Alerting
292
326
  v-model="value"
293
327
  :mode="mode"
294
- :secrets="secrets"
328
+ :monitoringSecrets="monitoringSecrets"
295
329
  />
296
330
  </div>
297
331
  </Tab>
@@ -1,5 +1,4 @@
1
1
  <script>
2
- import isEmpty from 'lodash/isEmpty';
3
2
  import { mapGetters } from 'vuex';
4
3
 
5
4
  import { Banner } from '@components/Banner';
@@ -51,21 +50,19 @@ export default {
51
50
  default: () => ({}),
52
51
  },
53
52
 
54
- workloads: {
53
+ filteredWorkloads: {
55
54
  type: Array,
56
55
  default: () => ([]),
57
56
  },
58
57
  },
59
58
 
60
59
  data() {
61
- return {
62
- enablePersistentStorage: !!this.value?.prometheus?.prometheusSpec?.storageSpec?.volumeClaimTemplate?.spec,
63
- warnUser: false,
64
- };
60
+ return { enablePersistentStorage: !!this.value?.prometheus?.prometheusSpec?.storageSpec?.volumeClaimTemplate?.spec };
65
61
  },
66
62
 
67
63
  computed: {
68
64
  ...mapGetters(['currentCluster']),
65
+
69
66
  matchExpressions: {
70
67
  get() {
71
68
  const selector = this.value?.prometheus?.prometheusSpec?.storageSpec?.volumeClaimTemplate?.spec?.selector;
@@ -80,42 +77,21 @@ export default {
80
77
  }
81
78
  }
82
79
  },
83
- filteredWorkloads() {
84
- let { workloads } = this;
85
- const { existing = false } = this.$attrs;
86
-
87
- if (!existing) {
88
- workloads = workloads.filter((workload) => {
89
- if (
90
- !isEmpty(workload?.spec?.template?.spec?.containers) &&
91
- (workload.spec.template.spec.containers.find((c) => c.image.includes('quay.io/coreos/prometheus-operator') ||
92
- c.image.includes('rancher/coreos-prometheus-operator'))
93
- )
94
- ) {
95
- if (!this.warnUser) {
96
- this.warnUser = true;
97
- }
98
80
 
99
- return workload;
100
- }
101
- });
102
- }
103
-
104
- return workloads.map((wl) => {
105
- return {
106
- label: wl.id,
107
- link: {
108
- name: 'c-cluster-product-resource-namespace-id',
109
- params: {
110
- cluster: this.currentCluster.id,
111
- product: 'explorer',
112
- resource: wl.type,
113
- namespace: wl.metadata.namespace,
114
- id: wl.metadata.name
115
- },
116
- }
117
- };
118
- });
81
+ mappedFilteredWorkloads() {
82
+ return this.filteredWorkloads.map((wl) => ({
83
+ label: wl.id,
84
+ link: {
85
+ name: 'c-cluster-product-resource-namespace-id',
86
+ params: {
87
+ cluster: this.currentCluster.id,
88
+ product: 'explorer',
89
+ resource: wl.type,
90
+ namespace: wl.metadata.namespace,
91
+ id: wl.metadata.name
92
+ },
93
+ }
94
+ }));
119
95
  },
120
96
 
121
97
  podsAndNamespaces() {
@@ -179,6 +155,23 @@ export default {
179
155
 
180
156
  this.$set(storageSpec.selector, 'matchLabels', matchLabels);
181
157
  this.$set(storageSpec.selector, 'matchExpressions', matchExpressions);
158
+
159
+ // Remove an empty selector object if present
160
+ // User can add a selector and then remove the selector - this will leave an empty structure as above
161
+ // We want to ensure we remove .selector.matchExpressions, .selector.matchLabels, and .selector if empty
162
+ // See: https://github.com/rancher/dashboard/issues/10016
163
+
164
+ if (storageSpec.selector.matchExpressions?.length === 0) {
165
+ delete storageSpec.selector.matchExpressions;
166
+ }
167
+
168
+ if (storageSpec.selector.matchLabels && Object.keys(storageSpec.selector.matchLabels).length === 0) {
169
+ delete storageSpec.selector.matchLabels;
170
+ }
171
+
172
+ if (Object.keys(storageSpec.selector).length === 0) {
173
+ delete storageSpec.selector;
174
+ }
182
175
  },
183
176
  },
184
177
  };
@@ -189,8 +182,9 @@ export default {
189
182
  <div class="title">
190
183
  <h3>{{ t('monitoring.prometheus.title') }}</h3>
191
184
  </div>
185
+ <!-- https://github.com/rancher/dashboard/issues/1167 -->
192
186
  <Banner
193
- v-if="filteredWorkloads && warnUser"
187
+ v-if="mappedFilteredWorkloads.length"
194
188
  color="warning"
195
189
  >
196
190
  <template #default>
@@ -199,7 +193,7 @@ export default {
199
193
  :raw="true"
200
194
  />
201
195
  <div
202
- v-for="wl in filteredWorkloads"
196
+ v-for="wl in mappedFilteredWorkloads"
203
197
  :key="wl.id"
204
198
  class="mt-10"
205
199
  >
@@ -65,7 +65,7 @@ export default {
65
65
 
66
66
  computed: {
67
67
  defaultStorageClass() {
68
- return this.storageClasses.filter((sc) => sc.metadata.annotations[STORAGE.DEFAULT_STORAGE_CLASS] && sc.metadata.annotations[STORAGE.DEFAULT_STORAGE_CLASS] !== 'false' )[0] || '';
68
+ return this.storageClasses.filter((sc) => sc.metadata.annotations?.[STORAGE.DEFAULT_STORAGE_CLASS] && sc.metadata.annotations[STORAGE.DEFAULT_STORAGE_CLASS] !== 'false' )[0] || '';
69
69
  },
70
70
 
71
71
  availablePVs() {
@@ -200,6 +200,7 @@ export default {
200
200
  :status="reclaimWarning ? 'warning' : null"
201
201
  :options="storageClasses"
202
202
  :hover-tooltip="true"
203
+ data-testid="backup-chart-select-existing-storage-class"
203
204
  />
204
205
  </div>
205
206
  <div class="col span-6">
@@ -2,11 +2,9 @@
2
2
  import CreateEditView from '@shell/mixins/create-edit-view';
3
3
  import { LabeledInput } from '@components/Form/LabeledInput';
4
4
  import { azureEnvironments } from '@shell/machine-config/azure';
5
+ import { parseAzureError } from '@shell/utils/azure';
5
6
  import LabeledSelect from '@shell/components/form/LabeledSelect';
6
7
 
7
- const AZURE_ERROR_MSG_REGEX = /^.*Message=\"(.*)\"$/;
8
- const AZURE_ERROR_JSON_REGEX = /^.*Response body: ({.*})/;
9
-
10
8
  export default {
11
9
  components: { LabeledInput, LabeledSelect },
12
10
  mixins: [CreateEditView],
@@ -59,21 +57,10 @@ export default {
59
57
  return true;
60
58
  } catch (e) {
61
59
  if (e.error) {
62
- // Try and parse the response from Azure a couple of ways
63
- const msgMatch = e.error.match(AZURE_ERROR_MSG_REGEX);
64
-
65
- if (msgMatch?.length === 2) {
66
- return { errors: [msgMatch[1]] };
67
- } else {
68
- const jsonMatch = e.error.match(AZURE_ERROR_JSON_REGEX);
69
-
70
- if (jsonMatch?.length === 2) {
71
- try {
72
- const errorObj = JSON.parse(jsonMatch[1]);
60
+ const parsed = parseAzureError(e.error);
73
61
 
74
- return { errors: [errorObj.error_description] };
75
- } catch (e) {}
76
- }
62
+ if (parsed) {
63
+ return { errors: [parsed] };
77
64
  }
78
65
  }
79
66
 
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import Vue from 'vue';
2
+ import { defineComponent, PropType, inject } from 'vue';
3
3
  import typeHelper from '@shell/utils/type-helpers';
4
4
 
5
5
  export const ASYNC_BUTTON_STATES = {
@@ -14,7 +14,13 @@ const TOOLTIP = 'tooltip';
14
14
 
15
15
  export type AsyncButtonCallback = (success: boolean) => void;
16
16
 
17
- export default Vue.extend<{ phase: string}, any, any, any>({
17
+ interface NonReactiveProps {
18
+ timer: NodeJS.Timeout | undefined;
19
+ }
20
+
21
+ const provideProps: NonReactiveProps = { timer: undefined };
22
+
23
+ export default defineComponent({
18
24
  props: {
19
25
  /**
20
26
  * Mode maps to keys in asyncButton.* translations
@@ -37,7 +43,7 @@ export default Vue.extend<{ phase: string}, any, any, any>({
37
43
  default: false,
38
44
  },
39
45
  type: {
40
- type: String,
46
+ type: String as PropType<'button' | 'submit' | 'reset' | undefined>,
41
47
  default: 'button'
42
48
  },
43
49
  tabIndex: {
@@ -113,7 +119,13 @@ export default Vue.extend<{ phase: string}, any, any, any>({
113
119
 
114
120
  },
115
121
 
116
- data(): { phase: string, timer?: NodeJS.Timeout} {
122
+ setup() {
123
+ const timer = inject('timer', provideProps.timer);
124
+
125
+ return { timer };
126
+ },
127
+
128
+ data() {
117
129
  return { phase: this.currentPhase };
118
130
  },
119
131
 
@@ -245,7 +257,7 @@ export default Vue.extend<{ phase: string}, any, any, any>({
245
257
  this.phase = (success ? ASYNC_BUTTON_STATES.SUCCESS : ASYNC_BUTTON_STATES.ERROR );
246
258
  this.timer = setTimeout(() => {
247
259
  this.timerDone();
248
- }, this.delay );
260
+ }, this.delay);
249
261
  }
250
262
  },
251
263
 
@@ -0,0 +1,164 @@
1
+ <script lang="ts">
2
+ import { defineComponent } from 'vue';
3
+ import { mapGetters } from 'vuex';
4
+ import ResourceTable from '@shell/components/ResourceTable.vue';
5
+ import { SECRET } from '@shell/config/types';
6
+ import { NAME as NAME_COL, NAMESPACE as NAMESPACE_COL, AGE, STATE } from '@shell/config/table-headers';
7
+ import Secret, { TYPES } from '@shell/models/secret';
8
+ import { Banner } from '@components/Banner';
9
+ import { STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
10
+ import { BadgeState } from '@components/BadgeState';
11
+
12
+ interface Data {
13
+ schema: Object,
14
+ headers: Object[],
15
+ certs: Secret[],
16
+ pagingParams: {
17
+ pluralLabel: string,
18
+ singularLabel: string
19
+ }
20
+ }
21
+
22
+ export default defineComponent({
23
+ components: {
24
+ ResourceTable, Banner, BadgeState
25
+ },
26
+
27
+ async fetch() {
28
+ // We're fetching secrets with a filter, this will clash with secrets in other contexts
29
+ this.$store.dispatch('cluster/forgetType', SECRET);
30
+
31
+ this.certs = await this.$store.dispatch('cluster/findAll', {
32
+ type: SECRET,
33
+ opt: {
34
+ watch: false,
35
+ // Note - urlOptions handles filter in a weird way
36
+ filter: { 'metadata.fields.1': TYPES.TLS }
37
+ }
38
+ });
39
+ },
40
+
41
+ data(): Data {
42
+ return {
43
+ schema: this.$store.getters['cluster/schemaFor'](SECRET),
44
+ headers: [
45
+ {
46
+ ...STATE,
47
+ formatter: null,
48
+ name: 'certState',
49
+ sort: ['certState', 'nameSort'],
50
+ value: 'certState',
51
+ },
52
+ NAME_COL,
53
+ NAMESPACE_COL,
54
+ {
55
+ name: 'cn',
56
+ labelKey: 'secret.certificate.cn',
57
+ value: (row: Secret) => {
58
+ if (!row.cn) {
59
+ return;
60
+ }
61
+
62
+ return row.cn + (row.unrepeatedSans.length ? ` ${ this.t('secret.certificate.plusMore', { n: row.unrepeatedSans.length }) }` : '');
63
+ },
64
+ sort: ['cn'],
65
+ search: ['cn'],
66
+ }, {
67
+ name: 'cert-expires2',
68
+ labelKey: 'secret.certificate.expiresDuration',
69
+ value: (row: Secret) => row.timeTilExpirationDate,
70
+ formatter: 'LiveDate',
71
+ sort: ['timeTilExpiration'],
72
+ search: ['timeTilExpiration'],
73
+ defaultSort: true,
74
+ width: 100
75
+ }, {
76
+ name: 'cert-expires',
77
+ labelKey: 'secret.certificate.expiresOn',
78
+ value: 'cachedCertInfo.notAfter',
79
+ formatter: 'Date',
80
+ sort: ['cachedCertInfo.notAfter'],
81
+ search: ['cachedCertInfo.notAfter'],
82
+ }, {
83
+ name: 'cert-lifetime',
84
+ labelKey: 'secret.certificate.lifetime',
85
+ value: (row: Secret) => row.certLifetime,
86
+ sort: ['certLifetime'],
87
+ search: ['certLifetime'],
88
+ },
89
+ AGE
90
+ ],
91
+ certs: [],
92
+ pagingParams: {
93
+ pluralLabel: this.t('secret.certificate.certificates'),
94
+ singularLabel: this.t('secret.certificate.certificate')
95
+ }
96
+ };
97
+ },
98
+
99
+ computed: {
100
+ ...mapGetters(['isAllNamespaces']),
101
+
102
+ expiredData(): any {
103
+ let expiring = 0;
104
+ let expired = 0;
105
+
106
+ for (let i = 0; i < this.certs.length; i++) {
107
+ const cert = this.certs[i];
108
+
109
+ if (cert.certState === STATES_ENUM.EXPIRING) {
110
+ expiring++;
111
+ }
112
+ if (cert.certState === STATES_ENUM.EXPIRED) {
113
+ expired++;
114
+ }
115
+ }
116
+
117
+ const filterWarning = !this.isAllNamespaces ? this.t('secret.certificate.warnings.filtered') : '';
118
+
119
+ return {
120
+ expiring: expiring ? this.t('secret.certificate.warnings.expiring', { count: expiring, filtered: !this.isAllNamespaces }) + filterWarning : '',
121
+ expired: expired ? this.t('secret.certificate.warnings.expired', { count: expired, filtered: !this.isAllNamespaces }) + filterWarning : '',
122
+ };
123
+ }
124
+ },
125
+
126
+ beforeDestroy() {
127
+ // We're fetching secrets with a filter, clear it so as to not clash with other contexts
128
+ this.$store.dispatch('cluster/forgetType', SECRET);
129
+ },
130
+
131
+ });
132
+ </script>
133
+
134
+ <template>
135
+ <div>
136
+ <Banner
137
+ v-if="expiredData.expiring"
138
+ color="warning"
139
+ :label="expiredData.expiring"
140
+ />
141
+ <Banner
142
+ v-if="expiredData.expired"
143
+ color="error"
144
+ :label="expiredData.expired"
145
+ />
146
+ <ResourceTable
147
+ :loading="$fetchState.pending"
148
+ :schema="schema"
149
+ :headers="headers"
150
+ :rows="certs"
151
+ :paging-label="'secret.certificate.paging'"
152
+ :paging-params="pagingParams"
153
+ >
154
+ <template #col:certState="{row}">
155
+ <td>
156
+ <BadgeState
157
+ :color="row.certStateBackground"
158
+ :label="row.certStateDisplay"
159
+ />
160
+ </td>
161
+ </template>
162
+ </ResourceTable>
163
+ </div>
164
+ </template>
@@ -130,28 +130,26 @@ export default {
130
130
  </script>
131
131
 
132
132
  <template>
133
- <client-only placeholder=" Loading...">
134
- <div
135
- class="code-mirror"
136
- :class="{['as-text-area']: asTextArea}"
137
- >
138
- <codemirror
139
- v-if="loaded"
140
- ref="codeMirrorRef"
141
- :value="value"
142
- :options="combinedOptions"
143
- :disabled="isDisabled"
144
- @ready="onReady"
145
- @input="onInput"
146
- @changes="onChanges"
147
- @focus="onFocus"
148
- @blur="onBlur"
149
- />
150
- <div v-else>
151
- Loading...
152
- </div>
133
+ <div
134
+ class="code-mirror"
135
+ :class="{['as-text-area']: asTextArea}"
136
+ >
137
+ <codemirror
138
+ v-if="loaded"
139
+ ref="codeMirrorRef"
140
+ :value="value"
141
+ :options="combinedOptions"
142
+ :disabled="isDisabled"
143
+ @ready="onReady"
144
+ @input="onInput"
145
+ @changes="onChanges"
146
+ @focus="onFocus"
147
+ @blur="onBlur"
148
+ />
149
+ <div v-else>
150
+ Loading...
153
151
  </div>
154
- </client-only>
152
+ </div>
155
153
  </template>
156
154
 
157
155
  <style lang="scss">
@@ -1,5 +1,7 @@
1
1
  <script>
2
2
  import { isArray } from '@shell/utils/array';
3
+ import { copyTextToClipboard } from '@shell/utils/clipboard';
4
+ import { exceptionToErrorsArray } from '@shell/utils/error';
3
5
 
4
6
  function flatten(node) {
5
7
  if ( node.text ) {
@@ -27,14 +29,16 @@ export default {
27
29
 
28
30
  const content = flatten(this.$slots.default).trim();
29
31
 
30
- this.$copyText(content).then(() => {
32
+ copyTextToClipboard(content).then(() => {
31
33
  this.copied = true;
32
34
 
33
35
  setTimeout(() => {
34
36
  this.copied = false;
35
37
  }, 2000);
38
+ this.$emit('copied');
39
+ }).catch((e) => {
40
+ this.$emit('error', exceptionToErrorsArray(e));
36
41
  });
37
- this.$emit('copied');
38
42
  },
39
43
  },
40
44
 
@@ -1,5 +1,6 @@
1
1
  <script>
2
2
  import AsyncButton from '@shell/components/AsyncButton';
3
+ import { copyTextToClipboard } from '@shell/utils/clipboard';
3
4
 
4
5
  export default {
5
6
  components: { AsyncButton },
@@ -18,7 +19,7 @@ export default {
18
19
 
19
20
  methods: {
20
21
  clicked(buttonCb) {
21
- this.$copyText(this.text).then(() => {
22
+ copyTextToClipboard(this.text).then(() => {
22
23
  buttonCb(true);
23
24
  }).catch(() => {
24
25
  buttonCb(false);
@@ -1,4 +1,6 @@
1
1
  <script>
2
+ import { copyTextToClipboard } from '@shell/utils/clipboard';
3
+ import { exceptionToErrorsArray } from '@shell/utils/error';
2
4
  export default {
3
5
  props: {
4
6
  text: {
@@ -20,17 +22,20 @@ export default {
20
22
  clicked(event) {
21
23
  if (!this.copied) {
22
24
  event.preventDefault();
23
- this.$copyText(this.text);
24
- this.copied = true;
25
+ copyTextToClipboard(this.text).then(() => {
26
+ this.copied = true;
25
27
 
26
- let t = event.target;
28
+ let t = event.target;
27
29
 
28
- if (t.tagName === 'I') {
29
- t = t.parentElement || t;
30
- }
31
- setTimeout(() => {
32
- this.copied = false;
33
- }, 500);
30
+ if (t.tagName === 'I') {
31
+ t = t.parentElement || t;
32
+ }
33
+ setTimeout(() => {
34
+ this.copied = false;
35
+ }, 500);
36
+ }).catch((e) => {
37
+ this.$emit('error', exceptionToErrorsArray(e));
38
+ });
34
39
  }
35
40
  },
36
41
  }
@@ -435,6 +435,7 @@ export default {
435
435
  v-for="(err, i) in errors"
436
436
  :key="i"
437
437
  color="error"
438
+ :data-testid="`error-banner${i}`"
438
439
  :label="stringify(mappedErrors[err].message)"
439
440
  :icon="mappedErrors[err].icon"
440
441
  :closable="true"
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import Vue from 'vue';
2
+ import { defineComponent } from 'vue';
3
3
  import { mapState } from 'vuex';
4
4
  import { BOTTOM, CENTER, LEFT, RIGHT } from '@shell/utils/position';
5
5
 
@@ -14,7 +14,7 @@ interface Data {
14
14
  drag: Drag;
15
15
  }
16
16
 
17
- export default Vue.extend({
17
+ export default defineComponent({
18
18
  data(): Data {
19
19
  return {
20
20
  drag: {