@rancher/shell 0.3.0 → 0.3.1

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 (322) hide show
  1. package/assets/styles/global/_button.scss +5 -1
  2. package/assets/styles/global/_columns.scss +4 -0
  3. package/assets/styles/global/_layout.scss +1 -2
  4. package/assets/styles/global/_select.scss +1 -4
  5. package/assets/styles/themes/_dark.scss +4 -4
  6. package/assets/styles/themes/_light.scss +4 -3
  7. package/assets/styles/themes/_suse.scss +1 -1
  8. package/assets/styles/vendor/vue-select.scss +4 -3
  9. package/assets/translations/en-us.yaml +669 -73
  10. package/assets/translations/zh-hans.yaml +547 -165
  11. package/chart/monitoring/steps/uninstall-v1.vue +2 -2
  12. package/cloud-credential/azure.vue +23 -0
  13. package/cloud-credential/harvester.vue +25 -62
  14. package/cloud-credential/pnap.vue +80 -0
  15. package/components/.DS_Store +0 -0
  16. package/components/AdvancedSection.vue +9 -2
  17. package/components/Alert.vue +2 -2
  18. package/components/ButtonDropdown.vue +0 -2
  19. package/components/ButtonGroup.vue +1 -0
  20. package/components/CollapsibleCard.vue +0 -1
  21. package/components/CruResource.vue +41 -4
  22. package/components/DetailTop.vue +58 -3
  23. package/components/DisableAuthProviderModal.vue +106 -0
  24. package/{rancher-components/components/Utils/DraggableZone → components}/DraggableZone.vue +0 -0
  25. package/components/ExplorerMembers.vue +253 -30
  26. package/components/ExplorerProjectsNamespaces.vue +77 -33
  27. package/components/GrowlManager.vue +3 -3
  28. package/components/IconOrSvg.vue +149 -0
  29. package/components/LogItem.vue +69 -0
  30. package/components/PodSecurityAdmission.vue +302 -0
  31. package/components/PromptModal.vue +1 -0
  32. package/components/ResourceDetail/Masthead.vue +54 -2
  33. package/components/ResourceDetail/index.vue +12 -5
  34. package/components/ResourceList/Masthead.vue +11 -1
  35. package/components/ResourceList/ResourceLoadingIndicator.vue +12 -2
  36. package/components/ResourceList/index.vue +53 -12
  37. package/components/ResourceList/resource-list.config.js +7 -0
  38. package/components/ResourceTable.vue +31 -6
  39. package/components/SimpleBox.vue +1 -1
  40. package/components/SortableTable/THead.vue +15 -5
  41. package/components/SortableTable/index.vue +21 -10
  42. package/components/Tabbed/index.vue +20 -15
  43. package/components/__tests__/.DS_Store +0 -0
  44. package/components/__tests__/AsyncButton.test.ts +140 -0
  45. package/components/__tests__/BackLink.test.ts +33 -0
  46. package/components/__tests__/ButtonGroup.test.ts +124 -0
  47. package/components/__tests__/ClusterBadge.test.ts +32 -0
  48. package/components/__tests__/CollapsibleCard.test.ts +64 -0
  49. package/components/__tests__/ConsumptionGauge.test.ts +88 -0
  50. package/components/__tests__/CruResource.test.ts +3 -2
  51. package/components/__tests__/FixedBanner.test.ts +129 -0
  52. package/components/__tests__/GrowlManager.test.ts +147 -0
  53. package/components/__tests__/NamespaceFilter.test.ts +33 -25
  54. package/components/__tests__/PercentageBar.test.ts +32 -0
  55. package/components/__tests__/PodSecurityAdmission.test.ts +398 -0
  56. package/components/auth/AuthBanner.vue +20 -10
  57. package/components/auth/RoleDetailEdit.vue +26 -17
  58. package/components/auth/SelectPrincipal.vue +36 -5
  59. package/components/form/ArrayList.vue +3 -35
  60. package/components/form/ArrayListGrouped.vue +13 -4
  61. package/components/form/ArrayListSelect.vue +5 -5
  62. package/components/form/Error.vue +8 -0
  63. package/components/form/KeyValue.vue +39 -7
  64. package/components/form/LabeledSelect.vue +5 -2
  65. package/components/form/Labels.vue +46 -16
  66. package/components/form/Members/ClusterPermissionsEditor.vue +17 -17
  67. package/components/form/Members/MembershipEditor.vue +12 -12
  68. package/components/form/NameNsDescription.vue +1 -1
  69. package/components/form/NodeScheduling.vue +1 -1
  70. package/components/form/Probe.vue +3 -3
  71. package/components/form/ResourceQuota/Project.vue +6 -6
  72. package/components/form/ResourceTabs/index.vue +1 -6
  73. package/components/form/Security.vue +7 -6
  74. package/components/form/Select.vue +3 -2
  75. package/components/form/SelectOrCreateAuthSecret.vue +22 -29
  76. package/components/form/ServicePorts.vue +8 -0
  77. package/components/form/WorkloadPorts.vue +7 -1
  78. package/components/form/__tests__/ArrayList.test.ts +74 -0
  79. package/components/form/__tests__/ArrayListGrouped.test.ts +6 -4
  80. package/components/formatter/Checked.vue +1 -1
  81. package/components/formatter/ClusterLink.vue +5 -0
  82. package/components/formatter/IconIsDefault.vue +2 -2
  83. package/components/formatter/InternalExternalIP.vue +11 -8
  84. package/components/formatter/LiveDuration.vue +78 -0
  85. package/components/formatter/WorkloadHealthScale.vue +5 -3
  86. package/components/nav/Header.vue +6 -3
  87. package/components/nav/NamespaceFilter.vue +146 -63
  88. package/components/nav/TopLevelMenu.vue +22 -19
  89. package/components/nav/WindowManager/ContainerLogs.vue +83 -126
  90. package/components/nav/WindowManager/ContainerShell.vue +9 -7
  91. package/components/nav/WindowManager/Window.vue +2 -0
  92. package/components/nav/WindowManager/index.vue +10 -0
  93. package/config/elemental-types.js +9 -0
  94. package/config/features.js +2 -0
  95. package/config/home-links.js +4 -1
  96. package/config/pod-security-admission.ts +82 -0
  97. package/config/product/apps.js +1 -1
  98. package/config/product/auth.js +6 -5
  99. package/config/product/explorer.js +6 -6
  100. package/config/product/fleet.js +1 -1
  101. package/config/product/manager.js +6 -2
  102. package/config/secret.js +0 -1
  103. package/config/settings.ts +26 -9
  104. package/config/table-headers.js +22 -11
  105. package/config/types.js +4 -1
  106. package/content/docs/zh-hans/getting-started.md +113 -137
  107. package/content/docs/zh-hans/whats-new.md +8 -46
  108. package/creators/pkg/package-lock.json +37 -0
  109. package/creators/pkg/package.json +1 -1
  110. package/detail/catalog.cattle.io.app.vue +1 -1
  111. package/detail/pod.vue +1 -1
  112. package/detail/provisioning.cattle.io.cluster.vue +35 -9
  113. package/detail/service.vue +2 -9
  114. package/detail/workload/index.vue +0 -1
  115. package/dialog/AddClusterMemberDialog.vue +22 -28
  116. package/dialog/AddProjectMemberDialog.vue +53 -9
  117. package/dialog/DiagnosticTimingsDialog.vue +8 -7
  118. package/dialog/DrainNode.vue +44 -48
  119. package/dialog/ForceMachineRemoveDialog.vue +5 -7
  120. package/dialog/GenericPrompt.vue +15 -20
  121. package/dialog/RollbackWorkloadDialog.vue +15 -46
  122. package/dialog/RotateCertificatesDialog.vue +5 -7
  123. package/dialog/RotateEncryptionKeyDialog.vue +5 -9
  124. package/dialog/SaveAsRKETemplateDialog.vue +5 -13
  125. package/dialog/ScaleMachineDownDialog.vue +1 -1
  126. package/dialog/ScalePoolDownDialog.vue +121 -0
  127. package/edit/__tests__/management.cattle.io.setting.test.ts +3 -3
  128. package/edit/auth/azuread.vue +16 -16
  129. package/edit/auth/github.vue +8 -0
  130. package/edit/auth/googleoauth.vue +10 -1
  131. package/edit/auth/ldap/index.vue +10 -0
  132. package/edit/auth/oidc.vue +10 -0
  133. package/edit/auth/saml.vue +10 -0
  134. package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -1
  135. package/edit/cloudcredential.vue +3 -7
  136. package/edit/logging-flow/Match.vue +39 -8
  137. package/edit/logging-flow/index.vue +27 -4
  138. package/edit/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +107 -0
  139. package/edit/management.cattle.io.project.vue +8 -1
  140. package/edit/management.cattle.io.setting.vue +5 -2
  141. package/edit/management.cattle.io.user.vue +7 -1
  142. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +23 -7
  143. package/edit/monitoring.coreos.com.alertmanagerconfig/types/email.vue +2 -2
  144. package/edit/monitoring.coreos.com.prometheusrule/GroupRules.vue +14 -6
  145. package/edit/namespace.vue +18 -4
  146. package/edit/networking.k8s.io.ingress/Certificate.vue +1 -0
  147. package/edit/networking.k8s.io.ingress/IngressClass.vue +8 -6
  148. package/edit/networking.k8s.io.ingress/RulePath.vue +12 -6
  149. package/edit/networking.k8s.io.ingress/index.vue +8 -6
  150. package/edit/persistentvolume/index.vue +30 -27
  151. package/edit/persistentvolume/plugins/cephfs.vue +29 -29
  152. package/edit/persistentvolume/plugins/csi.vue +102 -62
  153. package/edit/persistentvolume/plugins/fc.vue +19 -19
  154. package/edit/persistentvolume/plugins/iscsi.vue +45 -45
  155. package/edit/persistentvolume/plugins/rbd.vue +39 -39
  156. package/edit/persistentvolumeclaim.vue +78 -75
  157. package/edit/provisioning.cattle.io.cluster/MachinePool.vue +11 -7
  158. package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +10 -1
  159. package/edit/provisioning.cattle.io.cluster/RegistryMirrors.vue +87 -27
  160. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +3 -6
  161. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +93 -0
  162. package/edit/provisioning.cattle.io.cluster/import.vue +1 -1
  163. package/edit/provisioning.cattle.io.cluster/index.vue +29 -6
  164. package/edit/provisioning.cattle.io.cluster/rke2.vue +440 -152
  165. package/edit/secret/index.vue +3 -7
  166. package/edit/service.vue +3 -1
  167. package/edit/storage.k8s.io.storageclass/index.vue +100 -16
  168. package/edit/storage.k8s.io.storageclass/provisioners/driver.harvesterhci.io.vue +114 -0
  169. package/edit/workload/__tests__/index.test.ts +98 -0
  170. package/edit/workload/index.vue +58 -8
  171. package/edit/workload/mixins/workload.js +107 -70
  172. package/edit/workload/storage/ContainerMountPaths.vue +0 -10
  173. package/edit/workload/storage/emptyDir.vue +88 -0
  174. package/edit/workload/storage/ephemeralVolume/index.vue +1 -1
  175. package/edit/workload/storage/index.vue +8 -0
  176. package/edit/workload/storage/persistentVolumeClaim/index.vue +1 -1
  177. package/layouts/default.vue +57 -44
  178. package/list/__tests__/workload.test.ts +5 -2
  179. package/list/catalog.cattle.io.app.vue +1 -0
  180. package/list/cis.cattle.io.clusterscan.vue +1 -0
  181. package/list/fleet.cattle.io.bundle.vue +5 -6
  182. package/list/fleet.cattle.io.cluster.vue +6 -3
  183. package/list/fleet.cattle.io.clusterregistrationtoken.vue +5 -6
  184. package/list/fleet.cattle.io.gitrepo.vue +4 -9
  185. package/list/helm.cattle.io.projecthelmchart.vue +1 -5
  186. package/list/logging.banzaicloud.io.clusterflow.vue +4 -1
  187. package/list/logging.banzaicloud.io.flow.vue +6 -5
  188. package/list/management.cattle.io.cluster.vue +1 -0
  189. package/list/management.cattle.io.feature.vue +3 -4
  190. package/list/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +47 -0
  191. package/list/management.cattle.io.setting.vue +2 -2
  192. package/list/management.cattle.io.user.vue +4 -10
  193. package/list/monitoring.coreos.com.alertmanagerconfig.vue +2 -7
  194. package/list/node.vue +8 -5
  195. package/list/persistentvolume.vue +3 -3
  196. package/list/persistentvolumeclaim.vue +3 -4
  197. package/list/provisioning.cattle.io.cluster.vue +18 -19
  198. package/list/service.vue +6 -14
  199. package/list/workload.vue +43 -38
  200. package/machine-config/azure.vue +429 -60
  201. package/machine-config/pnap.vue +288 -0
  202. package/mixins/auth-config.js +1 -3
  203. package/mixins/browser-tab-visibility.js +8 -14
  204. package/mixins/chart.js +1 -1
  205. package/mixins/create-edit-view/impl.js +4 -0
  206. package/mixins/create-edit-view/index.js +4 -2
  207. package/mixins/resource-fetch-namespaced.js +98 -0
  208. package/mixins/resource-fetch.js +79 -45
  209. package/mixins/resource-manager.js +1 -23
  210. package/models/apps.controllerrevision.js +7 -0
  211. package/models/apps.daemonset.js +18 -0
  212. package/models/apps.deployment.js +44 -0
  213. package/models/apps.replicaset.js +7 -0
  214. package/models/apps.statefulset.js +18 -0
  215. package/models/batch.job.js +7 -14
  216. package/models/cluster/node.js +10 -2
  217. package/models/cluster.x-k8s.io.machine.js +26 -4
  218. package/models/cluster.x-k8s.io.machinedeployment.js +12 -2
  219. package/models/event.js +7 -0
  220. package/models/logging.banzaicloud.io.flow.js +4 -0
  221. package/models/management.cattle.io.cluster.js +1 -1
  222. package/models/management.cattle.io.clusterroletemplatebinding.js +1 -1
  223. package/models/management.cattle.io.globalrole.js +2 -2
  224. package/models/management.cattle.io.node.js +37 -2
  225. package/models/management.cattle.io.podsecurityadmissionconfigurationtemplate.ts +4 -0
  226. package/models/management.cattle.io.project.js +30 -11
  227. package/models/management.cattle.io.setting.js +1 -1
  228. package/models/management.cattle.io.user.js +37 -1
  229. package/models/namespace.js +42 -5
  230. package/models/persistentvolume.js +14 -2
  231. package/models/pod.js +15 -0
  232. package/models/projectroletemplatebinding.js +7 -0
  233. package/models/provisioning.cattle.io.cluster.js +61 -10
  234. package/models/rke-machine.cattle.io.pnapmachinetemplate.js +15 -0
  235. package/models/service.js +14 -13
  236. package/models/storage.k8s.io.storageclass.js +33 -18
  237. package/models/workload.js +38 -7
  238. package/nuxt.config.js +27 -17
  239. package/package.json +7 -7
  240. package/pages/about.vue +14 -2
  241. package/pages/c/_cluster/apps/charts/index.vue +4 -3
  242. package/pages/c/_cluster/apps/charts/install.vue +59 -22
  243. package/pages/c/_cluster/auth/config/_id.vue +6 -0
  244. package/pages/c/_cluster/auth/config/index.vue +8 -6
  245. package/pages/c/_cluster/auth/group.principal/assign-edit.vue +1 -1
  246. package/pages/c/_cluster/auth/roles/index.vue +1 -1
  247. package/pages/c/_cluster/explorer/index.vue +12 -6
  248. package/pages/c/_cluster/longhorn/index.vue +1 -1
  249. package/pages/c/_cluster/monitoring/alertmanagerconfig/_alertmanagerconfigid/receiver.vue +15 -4
  250. package/pages/c/_cluster/monitoring/index.vue +1 -1
  251. package/pages/c/_cluster/neuvector/index.vue +1 -1
  252. package/pages/c/_cluster/settings/performance.vue +48 -2
  253. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +34 -1
  254. package/pages/c/_cluster/uiplugins/index.vue +28 -2
  255. package/pages/diagnostic.vue +5 -4
  256. package/pages/home.vue +105 -30
  257. package/pages/prefs.vue +23 -12
  258. package/pages/rio/mesh.vue +1 -1
  259. package/pkg/dynamic-importer.lib.js +8 -0
  260. package/pkg/vue.config.js +4 -0
  261. package/plugins/dashboard-store/__tests__/mutations.spec.js +406 -0
  262. package/plugins/dashboard-store/actions.js +32 -25
  263. package/plugins/dashboard-store/getters.js +50 -33
  264. package/plugins/dashboard-store/mutations.js +134 -28
  265. package/plugins/dashboard-store/resource-class.js +21 -41
  266. package/plugins/steve/actions.js +30 -0
  267. package/plugins/steve/caches/resourceCache.js +60 -0
  268. package/plugins/steve/getters.js +44 -1
  269. package/plugins/steve/mutations.js +97 -36
  270. package/plugins/steve/resourceWatcher.js +277 -0
  271. package/plugins/steve/schema.utils.js +25 -0
  272. package/plugins/steve/subscribe.js +288 -115
  273. package/plugins/steve/worker/index.js +17 -0
  274. package/plugins/steve/worker/web-worker.advanced.js +302 -0
  275. package/plugins/steve/{web-worker.steve-sub-worker.js → worker/web-worker.basic.js} +3 -44
  276. package/rancher-components/Card/Card.vue +3 -3
  277. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +1 -0
  278. package/rancher-components/StringList/StringList.test.ts +45 -420
  279. package/rancher-components/StringList/StringList.vue +1 -10
  280. package/rancher-components/components/Banner/Banner.test.ts +44 -0
  281. package/rancher-components/components/Banner/Banner.vue +129 -61
  282. package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +13 -22
  283. package/rancher-components/components/Form/Checkbox/Checkbox.vue +8 -6
  284. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +9 -9
  285. package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +0 -1
  286. package/rancher-components/components/StringList/StringList.test.ts +7 -7
  287. package/rancher-components/components/StringList/StringList.vue +21 -15
  288. package/scripts/test-plugins-build.sh +8 -0
  289. package/static/loading-indicator.html +1 -1
  290. package/store/index.js +54 -3
  291. package/store/plugins.js +0 -17
  292. package/store/pnap.js +128 -0
  293. package/store/prefs.js +4 -2
  294. package/store/type-map.js +55 -13
  295. package/types/pod-security-admission.ts +36 -0
  296. package/types/shell/index.d.ts +496 -396
  297. package/utils/__tests__/object.test.ts +17 -1
  298. package/utils/__tests__/pod-security-admission.test.ts +61 -0
  299. package/utils/async.ts +36 -0
  300. package/utils/color.js +45 -0
  301. package/utils/crypto/browserHashUtils.js +18 -0
  302. package/utils/dynamic-importer.js +8 -0
  303. package/utils/install-redirect.js +1 -1
  304. package/utils/object.js +24 -0
  305. package/utils/pod-security-admission.ts +39 -0
  306. package/utils/socket.js +61 -24
  307. package/utils/string.js +2 -0
  308. package/utils/svg-filter.js +301 -0
  309. package/utils/time.js +49 -0
  310. package/utils/validators/cidr.js +4 -0
  311. package/utils/validators/formRules/__tests__/index.test.ts +23 -3
  312. package/utils/validators/formRules/index.ts +14 -0
  313. package/config/product/harvester-manager.js +0 -162
  314. package/edit/harvesterhci.io.management.cluster.vue +0 -153
  315. package/list/harvesterhci.io.management.cluster.vue +0 -241
  316. package/machine-config/harvester.vue +0 -693
  317. package/models/harvesterhci.io.management.cluster.js +0 -228
  318. package/pages/c/_cluster/harvesterManager/index.vue +0 -24
  319. package/rancher-components/Card/Card.test.ts +0 -39
  320. package/rancher-components/Utils/DraggableZone/DraggableZone.vue +0 -181
  321. package/rancher-components/Utils/DraggableZone/index.ts +0 -1
  322. package/rancher-components/components/Utils/DraggableZone/index.ts +0 -1
@@ -4,13 +4,18 @@ import Loading from '@shell/components/Loading';
4
4
  import Masthead from './Masthead';
5
5
  import ResourceLoadingIndicator from './ResourceLoadingIndicator';
6
6
  import ResourceFetch from '@shell/mixins/resource-fetch';
7
+ import IconMessage from '@shell/components/IconMessage.vue';
8
+ import { ResourceListComponentName } from './resource-list.config';
7
9
 
8
10
  export default {
11
+ name: ResourceListComponentName,
12
+
9
13
  components: {
10
14
  Loading,
11
15
  ResourceTable,
12
16
  Masthead,
13
- ResourceLoadingIndicator
17
+ ResourceLoadingIndicator,
18
+ IconMessage
14
19
  },
15
20
  mixins: [ResourceFetch],
16
21
 
@@ -28,19 +33,16 @@ export default {
28
33
  default: false
29
34
  },
30
35
  },
36
+
31
37
  async fetch() {
32
38
  const store = this.$store;
33
39
  const resource = this.resource;
34
40
 
35
- let hasFetch = false;
36
-
37
- const inStore = store.getters['currentStore'](resource);
38
-
39
- const schema = store.getters[`${ inStore }/schemaFor`](resource);
41
+ const schema = this.schema;
40
42
 
41
43
  if ( this.hasListComponent ) {
42
44
  // If you provide your own list then call its asyncData
43
- const importer = store.getters['type-map/importList'](resource);
45
+ const importer = this.listComponent;
44
46
  const component = (await importer())?.default;
45
47
 
46
48
  if ( component?.typeDisplay ) {
@@ -49,7 +51,7 @@ export default {
49
51
 
50
52
  // If your list page has a fetch then it's responsible for populating rows itself
51
53
  if ( component?.fetch ) {
52
- hasFetch = true;
54
+ this.hasFetch = true;
53
55
  }
54
56
 
55
57
  // If the custom component supports it, ask it what resources it loads, so we can
@@ -62,14 +64,17 @@ export default {
62
64
  }
63
65
  }
64
66
 
65
- if ( !hasFetch ) {
67
+ if ( !this.hasFetch ) {
66
68
  if ( !schema ) {
67
69
  store.dispatch('loadingError', new Error(`Type ${ resource } not found, unable to display list`));
68
70
 
69
71
  return;
70
72
  }
71
73
 
72
- await this.$fetchType(resource);
74
+ // See comment for `namespaceFilterRequired` watcher, skip fetch if we don't have a valid NS
75
+ if (!this.namespaceFilterRequired) {
76
+ await this.$fetchType(resource);
77
+ }
73
78
  }
74
79
  },
75
80
 
@@ -91,6 +96,8 @@ export default {
91
96
  hasListComponent,
92
97
  showMasthead: showMasthead === undefined ? true : showMasthead,
93
98
  resource,
99
+ loadResources: [resource], // List of resources that will be loaded, this could be many (`Workloads`)
100
+ hasFetch: false,
94
101
  // manual refresh
95
102
  manualRefreshInit: false,
96
103
  watch: false,
@@ -98,7 +105,6 @@ export default {
98
105
  // Provided by fetch later
99
106
  customTypeDisplay: null,
100
107
  // incremental loading
101
- loadResources: [resource],
102
108
  loadIndeterminate: false,
103
109
  // query param for simple filtering
104
110
  useQueryParamsForSimpleFiltering: true
@@ -124,6 +130,23 @@ export default {
124
130
  }
125
131
  },
126
132
 
133
+ watch: {
134
+ /**
135
+ * When a NS filter is required and the user selects a different one, kick off a new set of API requests
136
+ *
137
+ * ResourceList has two modes
138
+ * 1) ResourceList component handles API request to fetch resources
139
+ * 2) Custom list component handles API request to fetch resources
140
+ *
141
+ * This covers case 1
142
+ */
143
+ namespaceFilter(neu) {
144
+ if (neu && !this.hasFetch) {
145
+ this.$fetchType(this.resource);
146
+ }
147
+ }
148
+ },
149
+
127
150
  created() {
128
151
  let listComponent = false;
129
152
 
@@ -140,7 +163,20 @@ export default {
140
163
  </script>
141
164
 
142
165
  <template>
143
- <div>
166
+ <IconMessage
167
+ v-if="namespaceFilterRequired"
168
+ :vertical="true"
169
+ :subtle="false"
170
+ icon="icon-filter_alt"
171
+ >
172
+ <template #message>
173
+ <span
174
+ class="filter"
175
+ v-html="t('resourceList.nsFiltering', { resource: $store.getters['type-map/labelFor'](schema, 2) || customTypeDisplay }, true)"
176
+ />
177
+ </template>
178
+ </IconMessage>
179
+ <div v-else>
144
180
  <Masthead
145
181
  v-if="showMasthead"
146
182
  :type-display="customTypeDisplay"
@@ -149,6 +185,7 @@ export default {
149
185
  :show-incremental-loading-indicator="showIncrementalLoadingIndicator"
150
186
  :load-resources="loadResources"
151
187
  :load-indeterminate="loadIndeterminate"
188
+ :load-namespace="namespaceFilter"
152
189
  >
153
190
  <template slot="extraActions">
154
191
  <slot name="extraActions" />
@@ -173,6 +210,7 @@ export default {
173
210
  :adv-filter-hide-labels-as-cols="advFilterHideLabelsAsCols"
174
211
  :adv-filter-prevent-filtering-labels="advFilterPreventFilteringLabels"
175
212
  :use-query-params-for-simple-filtering="useQueryParamsForSimpleFiltering"
213
+ :force-update-live-and-delayed="forceUpdateLiveAndDelayed"
176
214
  />
177
215
  </div>
178
216
  </template>
@@ -185,6 +223,9 @@ export default {
185
223
  position: relative;
186
224
  margin: 0 0 20px 0;
187
225
  }
226
+ .filter{
227
+ line-height: 45px;
228
+ }
188
229
  .right-action {
189
230
  position: absolute;
190
231
  top: 10px;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Component name of the `ResourceList`
3
+ *
4
+ * This needs to be a in separate file to avoid circular dependency of
5
+ * index.vue --> resource-fetch mixin --> resource-fetch-namespaced mixin --> index.vue
6
+ */
7
+ export const ResourceListComponentName = 'ResourceList';
@@ -140,9 +140,30 @@ export default {
140
140
  useQueryParamsForSimpleFiltering: {
141
141
  type: Boolean,
142
142
  default: false
143
+ },
144
+ /**
145
+ * Manaul force the update of live and delayed cells. Change this number to kick off the update
146
+ */
147
+ forceUpdateLiveAndDelayed: {
148
+ type: Number,
149
+ default: 0
143
150
  }
144
151
  },
145
152
 
153
+ mounted() {
154
+ /**
155
+ * v-shortkey prevents the event's propagation:
156
+ * https://github.com/fgr-araujo/vue-shortkey/blob/55d802ea305cadcc2ea970b55a3b8b86c7b44c05/src/index.js#L156-L157
157
+ *
158
+ * 'Enter' key press is handled via event listener in order to allow the event propagation
159
+ */
160
+ window.addEventListener('keyup', this.handleEnterKeyPress);
161
+ },
162
+
163
+ beforeDestroy() {
164
+ window.removeEventListener('keyup', this.handleEnterKeyPress);
165
+ },
166
+
146
167
  data() {
147
168
  const options = this.$store.getters[`type-map/optionsFor`](this.schema);
148
169
  const listGroups = options?.listGroups || [];
@@ -232,11 +253,16 @@ export default {
232
253
  return [];
233
254
  }
234
255
 
256
+ const haveAllNamespace = this.$store.getters['haveAllNamespace'];
257
+
235
258
  return this.rows.filter((row) => {
236
259
  if (this.currentProduct?.hideSystemResources && this.isNamespaced) {
237
260
  return !!includedNamespaces[row.metadata.namespace] && !row.isSystemResource;
238
261
  } else if (!this.isNamespaced) {
239
262
  return true;
263
+ } else if (haveAllNamespace) {
264
+ // `rows` only contains resource from a single namespace
265
+ return true;
240
266
  } else {
241
267
  return !!includedNamespaces[row.metadata.namespace];
242
268
  }
@@ -375,8 +401,11 @@ export default {
375
401
 
376
402
  handleActionButtonClick(event) {
377
403
  this.$emit('clickedActionButton', event);
378
- }
404
+ },
379
405
 
406
+ handleEnterKeyPress(event) {
407
+ this.keyAction('detail');
408
+ }
380
409
  }
381
410
  };
382
411
  </script>
@@ -406,6 +435,7 @@ export default {
406
435
  key-field="_key"
407
436
  :sort-generation-fn="safeSortGenerationFn"
408
437
  :use-query-params-for-simple-filtering="useQueryParamsForSimpleFiltering"
438
+ :force-update-live-and-delayed="forceUpdateLiveAndDelayed"
409
439
  @clickedActionButton="handleActionButtonClick"
410
440
  @group-value-change="group = $event"
411
441
  v-on="$listeners"
@@ -447,11 +477,6 @@ export default {
447
477
  </template>
448
478
 
449
479
  <template #shortkeys>
450
- <button
451
- v-shortkey.once="['enter']"
452
- class="hide detail"
453
- @shortkey="keyAction('detail')"
454
- />
455
480
  <button
456
481
  v-shortkey.once="['e']"
457
482
  class="hide"
@@ -74,7 +74,7 @@ export default {
74
74
  justify-content: center;
75
75
  padding: 2px;
76
76
  > i {
77
- font-size: 20px;
77
+ font-size: 14px;
78
78
  opacity: 0.5;
79
79
  }
80
80
  &:hover {
@@ -191,6 +191,16 @@ export default {
191
191
  value
192
192
  });
193
193
  },
194
+
195
+ tooltip(col) {
196
+ if (!col.tooltip) {
197
+ return null;
198
+ }
199
+
200
+ const exists = this.$store.getters['i18n/exists'];
201
+
202
+ return exists(col.tooltip) ? this.t(col.tooltip) : col.tooltip;
203
+ },
194
204
  }
195
205
 
196
206
  };
@@ -230,7 +240,7 @@ export default {
230
240
  >
231
241
  <span
232
242
  v-if="col.sort"
233
- v-tooltip="col.tooltip"
243
+ v-tooltip="tooltip(col)"
234
244
  >
235
245
  <span v-html="labelFor(col)" />
236
246
  <i
@@ -252,7 +262,7 @@ export default {
252
262
  </span>
253
263
  <span
254
264
  v-else
255
- v-tooltip="col.tooltip"
265
+ v-tooltip="tooltip(col)"
256
266
  >{{ labelFor(col) }}</span>
257
267
  </div>
258
268
  </th>
@@ -405,11 +415,11 @@ export default {
405
415
  color: var(--body-text);
406
416
 
407
417
  .table-header-container {
408
- display: flex;
409
- align-items: center;
418
+ display: inherit;
410
419
 
411
420
  > span {
412
- display: contents;
421
+ display: flex;
422
+ align-items: center;
413
423
  }
414
424
 
415
425
  &.not-filterable {
@@ -304,6 +304,13 @@ export default {
304
304
  useQueryParamsForSimpleFiltering: {
305
305
  type: Boolean,
306
306
  default: false
307
+ },
308
+ /**
309
+ * Manaul force the update of live and delayed cells. Change this number to kick off the update
310
+ */
311
+ forceUpdateLiveAndDelayed: {
312
+ type: Number,
313
+ default: 0
307
314
  }
308
315
  },
309
316
 
@@ -389,6 +396,9 @@ export default {
389
396
  page(neu, old) {
390
397
  this.watcherUpdateLiveAndDelayed(neu, old);
391
398
  },
399
+ forceUpdateLiveAndDelayed(neu, old) {
400
+ this.watcherUpdateLiveAndDelayed(neu, old);
401
+ },
392
402
 
393
403
  // Ensure we update live and delayed columns on first load
394
404
  initalLoad: {
@@ -401,16 +411,14 @@ export default {
401
411
  immediate: true
402
412
  },
403
413
 
404
- isManualRefreshLoading: {
414
+ // this is the flag that indicates that manual refresh data has been loaded
415
+ // and we should update the deferred cols
416
+ manualRefreshLoadingFinished: {
405
417
  handler(neu, old) {
406
- this.currentPhase = neu ? ASYNC_BUTTON_STATES.WAITING : ASYNC_BUTTON_STATES.ACTION;
407
-
408
- // setTimeout is needed so that this is pushed further back on the JS computing queue
409
- // because nextTick isn't enough to capture the DOM update for the manual refresh only scenario
410
- if (old && !neu) {
411
- this.manualRefreshTimer = setTimeout(() => {
412
- this.watcherUpdateLiveAndDelayed(neu, old);
413
- }, 1000);
418
+ // this is merely to update the manual refresh button status
419
+ this.currentPhase = !neu ? ASYNC_BUTTON_STATES.WAITING : ASYNC_BUTTON_STATES.ACTION;
420
+ if (neu && neu !== old) {
421
+ this.$nextTick(() => this.updateLiveAndDelayed());
414
422
  }
415
423
  },
416
424
  immediate: true
@@ -432,6 +440,10 @@ export default {
432
440
  return !!(!this.loading && !this._didinit && this.rows?.length);
433
441
  },
434
442
 
443
+ manualRefreshLoadingFinished() {
444
+ return !!(!this.loading && this._didinit && this.rows?.length && !this.isManualRefreshLoading);
445
+ },
446
+
435
447
  fullColspan() {
436
448
  let span = 0;
437
449
 
@@ -1530,7 +1542,6 @@ export default {
1530
1542
  .actions.role-multi-action {
1531
1543
  background-color: transparent;
1532
1544
  border: none;
1533
- font-size: 18px;
1534
1545
  &:hover, &:focus {
1535
1546
  background-color: var(--accent-btn);
1536
1547
  box-shadow: none;
@@ -92,12 +92,12 @@ export default {
92
92
  sortedTabs(tabs) {
93
93
  const {
94
94
  defaultTab,
95
- useHash,
96
- $route: { hash }
95
+ useHash
97
96
  } = this;
98
97
  const activeTab = tabs.find(t => t.active);
99
98
 
100
- const windowHash = hash.slice(1);
99
+ const hash = useHash ? this.$route.hash : undefined;
100
+ const windowHash = useHash ? hash.slice(1) : undefined;
101
101
  const windowHashTabMatch = tabs.find(t => t.name === windowHash && !t.active);
102
102
  const firstTab = head(tabs) || null;
103
103
 
@@ -148,11 +148,7 @@ export default {
148
148
  },
149
149
 
150
150
  select(name/* , event */) {
151
- const {
152
- sortedTabs,
153
- $route: { hash: routeHash },
154
- $router: { currentRoute },
155
- } = this;
151
+ const { sortedTabs } = this;
156
152
 
157
153
  const selected = this.find(name);
158
154
  const hashName = `#${ name }`;
@@ -160,13 +156,22 @@ export default {
160
156
  if ( !selected || selected.disabled) {
161
157
  return;
162
158
  }
159
+ /**
160
+ * Exclude logic with URL anchor (hash) for projects without routing logic (vue-router)
161
+ */
162
+ if ( this.useHash ) {
163
+ const {
164
+ $route: { hash: routeHash },
165
+ $router: { currentRoute },
166
+ } = this;
163
167
 
164
- if (this.useHash && routeHash !== hashName) {
165
- const kurrentRoute = { ...currentRoute };
168
+ if (this.useHash && routeHash !== hashName) {
169
+ const kurrentRoute = { ...currentRoute };
166
170
 
167
- kurrentRoute.hash = hashName;
171
+ kurrentRoute.hash = hashName;
168
172
 
169
- this.$router.replace(kurrentRoute);
173
+ this.$router.replace(kurrentRoute);
174
+ }
170
175
  }
171
176
 
172
177
  for ( const tab of sortedTabs ) {
@@ -251,7 +256,7 @@ export default {
251
256
  <i
252
257
  v-if="hasIcon(tab)"
253
258
  v-tooltip="t('validation.tab')"
254
- class="conditions-alert-icon icon-error icon-lg"
259
+ class="conditions-alert-icon icon-error"
255
260
  />
256
261
  </a>
257
262
  </li>
@@ -274,7 +279,7 @@ export default {
274
279
  class="btn bg-transparent"
275
280
  @click="tabAddClicked"
276
281
  >
277
- <i class="icon icon-plus icon-lg" />
282
+ <i class="icon icon-plus" />
278
283
  </button>
279
284
  <button
280
285
  type="button"
@@ -282,7 +287,7 @@ export default {
282
287
  :disabled="!sortedTabs.length"
283
288
  @click="tabRemoveClicked"
284
289
  >
285
- <i class="icon icon-minus icon-lg" />
290
+ <i class="icon icon-minus" />
286
291
  </button>
287
292
  </li>
288
293
  </ul>
Binary file
@@ -0,0 +1,140 @@
1
+ import { mount, Wrapper } from '@vue/test-utils';
2
+ import AsyncButton, { ASYNC_BUTTON_STATES } from '@shell/components/AsyncButton.vue';
3
+
4
+ describe('component: AsyncButton', () => {
5
+ it('should render appropriately with default config', () => {
6
+ const mockExists = jest.fn().mockReturnValue(true);
7
+ const mockT = jest.fn().mockReturnValue('some-string');
8
+
9
+ const wrapper: Wrapper<InstanceType<typeof AsyncButton> & { [key: string]: any }> = mount(AsyncButton, {
10
+ mocks: {
11
+ $store: {
12
+ getters: {
13
+ 'i18n/exists': mockExists,
14
+ 'i18n/t': mockT
15
+ }
16
+ }
17
+ }
18
+ });
19
+
20
+ const button = wrapper.find('button');
21
+ const icon = wrapper.find('i');
22
+ const span = wrapper.find('span');
23
+
24
+ expect(wrapper.props().currentPhase).toBe(ASYNC_BUTTON_STATES.ACTION);
25
+
26
+ expect(button.exists()).toBe(true);
27
+ expect(button.classes()).toContain('btn');
28
+ expect(button.classes()).toContain('role-primary');
29
+ expect(button.props().name).toBeNull();
30
+ expect(button.props().type).toBe('button');
31
+ expect(button.props().disabled).toBe(false);
32
+ expect(button.props().tabIndex).toBeNull();
33
+ // we are mocking the getters, so it's to expect to find an icon
34
+ expect(icon.exists()).toBe(true);
35
+ expect(icon.classes()).toContain('icon');
36
+ expect(icon.classes()).toContain('icon-lg');
37
+ expect(icon.classes()).toContain('icon-some-string');
38
+ // we are mocking the getters, so it's to expect to find a label
39
+ expect(span.exists()).toBe(true);
40
+ expect(span.text()).toBe('some-string');
41
+ });
42
+
43
+ it('click on async button should emit click with a proper state of waiting, disabled and spinning ::: CB true', () => {
44
+ jest.useFakeTimers();
45
+
46
+ const wrapper: Wrapper<InstanceType<typeof AsyncButton> & { [key: string]: any }> = mount(AsyncButton, {
47
+ mocks: {
48
+ $store: {
49
+ getters: {
50
+ 'i18n/exists': jest.fn(),
51
+ 'i18n/t': jest.fn()
52
+ }
53
+ }
54
+ }
55
+ });
56
+
57
+ const spyDone = jest.spyOn(wrapper.vm, 'done');
58
+
59
+ wrapper.find('button').trigger('click');
60
+
61
+ expect(wrapper.emitted('click')).toHaveLength(1);
62
+ expect(wrapper.vm.phase).toBe(ASYNC_BUTTON_STATES.WAITING);
63
+ expect(wrapper.vm.isSpinning).toBe(true);
64
+ expect(wrapper.vm.isDisabled).toBe(true);
65
+ // testing cb function has been emitted
66
+ expect(typeof wrapper.emitted('click')![0][0]).toBe('function');
67
+
68
+ // trigger the cb function so that we test state changes on AsyncButton
69
+ wrapper.emitted('click')![0][0](true);
70
+
71
+ expect(spyDone).toHaveBeenCalledWith(true);
72
+ expect(wrapper.vm.phase).toBe(ASYNC_BUTTON_STATES.SUCCESS);
73
+
74
+ // wait for button delay to be completed
75
+ jest.runAllTimers();
76
+
77
+ expect(wrapper.vm.phase).toBe(ASYNC_BUTTON_STATES.ACTION);
78
+ });
79
+
80
+ it('click on async button should emit click and update state properly ::: CB false', () => {
81
+ jest.useFakeTimers();
82
+
83
+ const wrapper: Wrapper<InstanceType<typeof AsyncButton> & { [key: string]: any }> = mount(AsyncButton, {
84
+ mocks: {
85
+ $store: {
86
+ getters: {
87
+ 'i18n/exists': jest.fn(),
88
+ 'i18n/t': jest.fn()
89
+ }
90
+ }
91
+ }
92
+ });
93
+
94
+ const spyDone = jest.spyOn(wrapper.vm, 'done');
95
+
96
+ wrapper.find('button').trigger('click');
97
+
98
+ expect(wrapper.emitted('click')).toHaveLength(1);
99
+ // testing cb function has been emitted
100
+ expect(typeof wrapper.emitted('click')![0][0]).toBe('function');
101
+
102
+ // trigger the cb function so that we test state changes on AsyncButton
103
+ wrapper.emitted('click')![0][0](false);
104
+
105
+ expect(spyDone).toHaveBeenCalledWith(false);
106
+ expect(wrapper.vm.phase).toBe(ASYNC_BUTTON_STATES.ERROR);
107
+
108
+ // wait for button delay to be completed
109
+ jest.runAllTimers();
110
+
111
+ expect(wrapper.vm.phase).toBe(ASYNC_BUTTON_STATES.ACTION);
112
+ });
113
+
114
+ it('click on async button should emit click and update state properly ::: CB "cancelled"', () => {
115
+ const wrapper: Wrapper<InstanceType<typeof AsyncButton> & { [key: string]: any }> = mount(AsyncButton, {
116
+ mocks: {
117
+ $store: {
118
+ getters: {
119
+ 'i18n/exists': jest.fn(),
120
+ 'i18n/t': jest.fn()
121
+ }
122
+ }
123
+ }
124
+ });
125
+
126
+ const spyDone = jest.spyOn(wrapper.vm, 'done');
127
+
128
+ wrapper.find('button').trigger('click');
129
+
130
+ expect(wrapper.emitted('click')).toHaveLength(1);
131
+ // testing cb function has been emitted
132
+ expect(typeof wrapper.emitted('click')![0][0]).toBe('function');
133
+
134
+ // trigger the cb function so that we test state changes on AsyncButton
135
+ wrapper.emitted('click')![0][0]('cancelled');
136
+
137
+ expect(spyDone).toHaveBeenCalledWith('cancelled');
138
+ expect(wrapper.vm.phase).toBe(ASYNC_BUTTON_STATES.ACTION);
139
+ });
140
+ });
@@ -0,0 +1,33 @@
1
+ import { shallowMount, RouterLinkStub } from '@vue/test-utils';
2
+ import BackLink from '@shell/components/BackLink.vue';
3
+
4
+ describe('component: BackLink', () => {
5
+ it('should render component with the correct data applied', () => {
6
+ const linkRoute = {
7
+ name: 'some-route-name',
8
+ params: { param1: 'paramval1' },
9
+ query: {
10
+ query1: 'queryval1',
11
+ query2: 'queryval2'
12
+ }
13
+ };
14
+
15
+ const wrapper = shallowMount(BackLink, {
16
+ propsData: { link: linkRoute },
17
+ stubs: { NuxtLink: RouterLinkStub }
18
+ });
19
+
20
+ const link = wrapper.findComponent(RouterLinkStub);
21
+ const icon = wrapper.find('i');
22
+
23
+ expect(link.exists()).toBe(true);
24
+ // assertion regarding the text will have to be pointed to whatever t() returns on the test
25
+ expect(link.text()).toBe('%generic.back%');
26
+ expect(link.classes()).toContain('back-link');
27
+ expect(link.props().to).toBe(linkRoute);
28
+
29
+ expect(icon.exists()).toBe(true);
30
+ expect(icon.classes()).toContain('icon');
31
+ expect(icon.classes()).toContain('icon-chevron-left');
32
+ });
33
+ });