@rancher/shell 3.0.2-rc.5 → 3.0.2

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 (219) hide show
  1. package/assets/images/providers/nutanix.svg +12 -1
  2. package/assets/styles/base/_basic.scss +2 -1
  3. package/assets/styles/base/_helpers.scss +4 -0
  4. package/assets/styles/base/_variables.scss +2 -0
  5. package/assets/styles/global/_labeled-input.scss +5 -13
  6. package/assets/styles/global/_layout.scss +4 -1
  7. package/assets/styles/global/_select.scss +5 -0
  8. package/assets/styles/themes/_dark.scss +1 -3
  9. package/assets/styles/themes/_light.scss +5 -1
  10. package/assets/translations/en-us.yaml +130 -23
  11. package/assets/translations/zh-hans.yaml +0 -3
  12. package/cloud-credential/azure.vue +1 -1
  13. package/components/ActionMenuShell.vue +105 -0
  14. package/components/AppModal.vue +2 -2
  15. package/components/AsyncButton.vue +2 -0
  16. package/components/ButtonGroup.vue +9 -2
  17. package/components/ClusterBadge.vue +1 -0
  18. package/components/ClusterIconMenu.vue +3 -0
  19. package/components/ClusterProviderIcon.vue +14 -1
  20. package/components/CodeMirror.vue +96 -5
  21. package/components/Collapse.vue +16 -3
  22. package/components/CruResource.vue +9 -0
  23. package/components/CruResourceFooter.vue +1 -1
  24. package/components/ExplorerMembers.vue +2 -1
  25. package/components/FixedBanner.vue +19 -12
  26. package/components/Import.vue +14 -1
  27. package/components/LandingPagePreference.vue +4 -2
  28. package/components/PodSecurityAdmission.vue +8 -6
  29. package/components/PromptChangePassword.vue +1 -0
  30. package/components/PromptRemove.vue +23 -21
  31. package/components/ResourceDetail/Masthead.vue +30 -11
  32. package/components/ResourceDetail/__tests__/Masthead.test.ts +61 -0
  33. package/components/ResourceDetail/index.vue +6 -0
  34. package/components/ResourceTable.vue +6 -1
  35. package/components/ResourceYaml.vue +1 -0
  36. package/components/Setting.vue +115 -0
  37. package/components/SortableTable/THead.vue +2 -0
  38. package/components/SortableTable/index.vue +7 -12
  39. package/components/StatusBadge.vue +71 -0
  40. package/components/Tabbed/index.vue +16 -15
  41. package/components/Wizard.vue +108 -104
  42. package/components/YamlEditor.vue +12 -2
  43. package/components/__tests__/Collapse.test.ts +2 -2
  44. package/components/__tests__/FixedBanner.test.ts +3 -3
  45. package/components/auth/Principal.vue +29 -17
  46. package/components/auth/__tests__/Principal.test.ts +40 -0
  47. package/components/auth/login/ldap.vue +7 -0
  48. package/components/fleet/FleetBundles.vue +1 -1
  49. package/components/fleet/FleetRepos.vue +1 -1
  50. package/components/fleet/FleetResources.vue +0 -2
  51. package/components/fleet/FleetSummary.vue +60 -65
  52. package/components/fleet/ForceDirectedTreeChart/index.vue +5 -1
  53. package/components/fleet/__tests__/FleetSummary.test.ts +49 -9
  54. package/components/form/ArrayList.vue +6 -2
  55. package/components/form/ColorInput.vue +1 -0
  56. package/components/form/KeyValue.vue +11 -12
  57. package/components/form/LabeledSelect.vue +15 -3
  58. package/components/form/Labels.vue +8 -1
  59. package/components/form/Members/MembershipEditor.vue +230 -222
  60. package/components/form/Members/__tests__/MembershipEditor.test.ts +62 -0
  61. package/components/form/Password.vue +3 -0
  62. package/components/form/ProjectMemberEditor.vue +6 -3
  63. package/components/form/ResourceTabs/index.vue +15 -13
  64. package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +5 -4
  65. package/components/form/SchedulingCustomization.vue +85 -0
  66. package/components/form/Select.vue +3 -2
  67. package/components/form/SelectOrCreateAuthSecret.vue +2 -1
  68. package/components/form/UnitInput.vue +3 -4
  69. package/components/form/__tests__/ArrayList.test.ts +9 -6
  70. package/components/form/__tests__/LabeledSelect.test.ts +37 -0
  71. package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +34 -0
  72. package/components/form/__tests__/UnitInput.test.ts +4 -5
  73. package/components/formatter/LiveDate.vue +3 -1
  74. package/components/formatter/ServiceType.vue +12 -4
  75. package/components/formatter/WorkloadHealthScale.vue +2 -1
  76. package/components/nav/Header.vue +35 -2
  77. package/components/nav/HeaderPageActionMenu.vue +11 -40
  78. package/components/nav/Jump.vue +8 -2
  79. package/components/nav/NamespaceFilter.vue +5 -4
  80. package/components/nav/Pinned.vue +1 -1
  81. package/components/nav/TopLevelMenu.helper.ts +5 -5
  82. package/components/nav/TopLevelMenu.vue +1 -12
  83. package/components/nav/WindowManager/ContainerLogs.vue +96 -58
  84. package/components/nav/WindowManager/ContainerShell.vue +99 -18
  85. package/components/nav/WindowManager/index.vue +74 -6
  86. package/components/nav/__tests__/TopLevelMenu.test.ts +0 -40
  87. package/components/templates/default.vue +2 -47
  88. package/config/features.js +1 -0
  89. package/config/labels-annotations.js +11 -1
  90. package/config/router/navigation-guards/index.js +2 -1
  91. package/config/router/navigation-guards/record-last-route.js +24 -0
  92. package/config/settings.ts +66 -98
  93. package/config/version.js +1 -1
  94. package/core/types-provisioning.ts +7 -0
  95. package/detail/fleet.cattle.io.bundle.vue +7 -0
  96. package/detail/fleet.cattle.io.cluster.vue +0 -3
  97. package/detail/fleet.cattle.io.gitrepo.vue +8 -15
  98. package/detail/provisioning.cattle.io.cluster.vue +8 -2
  99. package/dialog/DeactivateDriverDialog.vue +5 -5
  100. package/dialog/GitRepoForceUpdateDialog.vue +132 -0
  101. package/directives/strip-html-aria-label.js +19 -0
  102. package/edit/__tests__/cis.cattle.io.clusterscan.test.ts +87 -0
  103. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +217 -37
  104. package/edit/auth/__tests__/oidc.test.ts +60 -12
  105. package/edit/auth/ldap/__tests__/config.test.ts +40 -0
  106. package/edit/auth/ldap/config.vue +67 -89
  107. package/edit/auth/oidc.vue +16 -2
  108. package/edit/catalog.cattle.io.clusterrepo.vue +12 -8
  109. package/edit/cis.cattle.io.clusterscan.vue +13 -1
  110. package/edit/fleet.cattle.io.gitrepo.vue +198 -72
  111. package/edit/logging-flow/Match.vue +0 -21
  112. package/edit/management.cattle.io.project.vue +1 -1
  113. package/edit/monitoring.coreos.com.prometheusrule/AlertingRule.vue +10 -3
  114. package/edit/monitoring.coreos.com.prometheusrule/RecordingRule.vue +5 -1
  115. package/edit/monitoring.coreos.com.prometheusrule/index.vue +5 -2
  116. package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +8 -1
  117. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +2 -0
  118. package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +0 -2
  119. package/edit/provisioning.cattle.io.cluster/__tests__/CustomCommand.test.ts +55 -15
  120. package/edit/provisioning.cattle.io.cluster/index.vue +28 -30
  121. package/edit/provisioning.cattle.io.cluster/rke2.vue +64 -13
  122. package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +37 -2
  123. package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +3 -2
  124. package/edit/resources.cattle.io.backup.vue +150 -15
  125. package/edit/secret/__tests__/ssh.test.ts +79 -0
  126. package/edit/secret/ssh.vue +7 -1
  127. package/edit/service.vue +0 -3
  128. package/edit/workload/Job.vue +8 -8
  129. package/edit/workload/__tests__/Job.test.ts +0 -1
  130. package/edit/workload/index.vue +3 -1
  131. package/initialize/install-directives.js +2 -0
  132. package/initialize/install-plugins.js +6 -1
  133. package/list/catalog.cattle.io.app.vue +21 -4
  134. package/list/fleet.cattle.io.bundle.vue +1 -1
  135. package/list/management.cattle.io.setting.vue +34 -132
  136. package/list/provisioning.cattle.io.cluster.vue +11 -3
  137. package/machine-config/vmwarevsphere.vue +15 -8
  138. package/mixins/__tests__/auth-config.test.ts +74 -0
  139. package/mixins/__tests__/chart.test.ts +5 -4
  140. package/mixins/__tests__/create-edit-view.test.ts +38 -0
  141. package/mixins/auth-config.js +8 -0
  142. package/mixins/chart.js +2 -2
  143. package/mixins/create-edit-view/impl.js +4 -1
  144. package/mixins/vue-select-overrides.js +10 -0
  145. package/models/__tests__/catalog.cattle.io.app.test.ts +148 -0
  146. package/models/__tests__/fleet.cattle.io.gitrepo.test.ts +157 -0
  147. package/models/__tests__/secret.test.ts +56 -13
  148. package/models/catalog.cattle.io.app.js +112 -37
  149. package/models/cluster.js +11 -0
  150. package/models/fleet.cattle.io.bundle.js +40 -2
  151. package/models/fleet.cattle.io.gitrepo.js +169 -109
  152. package/models/management.cattle.io.fleetworkspace.js +4 -0
  153. package/models/management.cattle.io.kontainerdriver.js +7 -0
  154. package/models/nodedriver.js +4 -1
  155. package/models/provisioning.cattle.io.cluster.js +24 -0
  156. package/models/secret.js +1 -1
  157. package/package.json +5 -5
  158. package/pages/auth/login.vue +5 -11
  159. package/pages/auth/verify.vue +11 -1
  160. package/pages/c/_cluster/apps/charts/index.vue +6 -4
  161. package/pages/c/_cluster/apps/charts/install.vue +1 -1
  162. package/pages/c/_cluster/explorer/ConfigBadge.vue +3 -5
  163. package/pages/c/_cluster/explorer/EventsTable.vue +3 -2
  164. package/pages/c/_cluster/explorer/__tests__/index.test.ts +9 -9
  165. package/pages/c/_cluster/explorer/index.vue +33 -35
  166. package/pages/c/_cluster/explorer/tools/index.vue +3 -3
  167. package/pages/c/_cluster/fleet/index.vue +0 -5
  168. package/pages/c/_cluster/legacy/project/index.vue +1 -1
  169. package/pages/c/_cluster/settings/performance.vue +52 -53
  170. package/pages/c/_cluster/uiplugins/index.vue +19 -22
  171. package/pages/home.vue +17 -12
  172. package/pages/prefs.vue +5 -1
  173. package/plugins/shortkey.js +10 -1
  174. package/plugins/steve/steve-pagination-utils.ts +58 -8
  175. package/promptRemove/management.cattle.io.fleetworkspace.vue +98 -0
  176. package/promptRemove/management.cattle.io.globalrole.vue +1 -1
  177. package/promptRemove/management.cattle.io.project.vue +2 -8
  178. package/promptRemove/management.cattle.io.roletemplate.vue +1 -1
  179. package/promptRemove/mixin/roleDeletionCheck.js +1 -7
  180. package/promptRemove/pod.vue +7 -28
  181. package/rancher-components/Card/Card.vue +9 -1
  182. package/rancher-components/Form/Checkbox/Checkbox.vue +42 -6
  183. package/rancher-components/Form/LabeledInput/LabeledInput.vue +30 -3
  184. package/rancher-components/Form/Radio/RadioButton.vue +18 -3
  185. package/rancher-components/Form/Radio/RadioGroup.vue +39 -5
  186. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +13 -1
  187. package/rancher-components/RcButton/RcButton.test.ts +97 -0
  188. package/rancher-components/RcButton/RcButton.vue +14 -9
  189. package/rancher-components/RcDropdown/RcDropdown.vue +3 -1
  190. package/rancher-components/RcDropdown/RcDropdownItem.vue +8 -2
  191. package/rancher-components/RcDropdown/RcDropdownMenu.vue +66 -0
  192. package/rancher-components/RcDropdown/index.ts +1 -0
  193. package/rancher-components/RcDropdown/types.ts +27 -0
  194. package/rancher-components/RcDropdown/useDropdownContext.ts +5 -2
  195. package/scripts/extension/helm/charts/ui-plugin-server/templates/_helpers.tpl +2 -2
  196. package/scripts/typegen.sh +1 -0
  197. package/store/__tests__/auth.test.ts +120 -0
  198. package/store/action-menu.js +13 -3
  199. package/store/auth.js +14 -9
  200. package/store/aws.js +9 -2
  201. package/store/catalog.js +14 -7
  202. package/store/features.js +1 -0
  203. package/store/prefs.js +9 -28
  204. package/store/type-map.utils.ts +4 -0
  205. package/types/resources/settings.d.ts +27 -20
  206. package/types/shell/index.d.ts +18 -12
  207. package/utils/__tests__/array.test.ts +13 -1
  208. package/utils/__tests__/string.test.ts +80 -1
  209. package/utils/array.ts +13 -0
  210. package/utils/auth.js +4 -0
  211. package/utils/banners.js +0 -45
  212. package/utils/cluster.js +1 -1
  213. package/{edit/monitoring.coreos.com.prometheusrule → utils}/duration.js +5 -3
  214. package/utils/object.js +0 -3
  215. package/utils/pagination-utils.ts +15 -2
  216. package/utils/string.js +31 -7
  217. package/utils/validators/formRules/__tests__/index.test.ts +27 -0
  218. package/utils/validators/formRules/index.ts +16 -0
  219. package/edit/provisioning.cattle.io.cluster/import.vue +0 -198
@@ -1,7 +1,7 @@
1
1
  import { ActionFindPageArgs } from '@shell/types/store/dashboard-store.types';
2
2
  import { PaginationParam, PaginationFilterField, PaginationParamProjectOrNamespace, PaginationParamFilter } from '@shell/types/store/pagination.types';
3
3
  import { NAMESPACE_FILTER_ALL_SYSTEM, NAMESPACE_FILTER_ALL_USER, NAMESPACE_FILTER_P_FULL_PREFIX } from '@shell/utils/namespace-filter';
4
- import Namespace from '@shell/models/namespace';
4
+ import ModelNamespace from '@shell/models/namespace';
5
5
  import { uniq } from '@shell/utils/array';
6
6
  import {
7
7
  CAPI,
@@ -12,10 +12,21 @@ import {
12
12
  SERVICE,
13
13
  INGRESS,
14
14
  WORKLOAD_TYPES,
15
- HPA
15
+ HPA,
16
+ SECRET
16
17
  } from '@shell/config/types';
17
- import { CAPI as CAPI_LABELS, CATTLE_PUBLIC_ENDPOINTS } from '@shell/config/labels-annotations';
18
+ import { CAPI as CAPI_LAB_AND_ANO, CATTLE_PUBLIC_ENDPOINTS } from '@shell/config/labels-annotations';
18
19
  import { Schema } from '@shell/plugins/steve/schema';
20
+ import { PaginationSettingsStore } from '@shell/types/resources/settings';
21
+
22
+ /**
23
+ * This is a workaround for a ts build issue found in check-plugins-build.
24
+ *
25
+ * The build would error on <ns>.name, it somehow doesn't know about the steve model's properties (they are included in typegen)
26
+ */
27
+ interface Namespace extends ModelNamespace {
28
+ name: string;
29
+ }
19
30
 
20
31
  class NamespaceProjectFilters {
21
32
  /**
@@ -141,8 +152,8 @@ class StevePaginationUtils extends NamespaceProjectFilters {
141
152
  { field: 'spec.internal' },
142
153
  { field: 'spec.displayName' },
143
154
  { field: `status.provider` },
144
- { field: `metadata.labels."${ CAPI_LABELS.PROVIDER }"` },
145
-
155
+ { field: `metadata.labels["${ CAPI_LAB_AND_ANO.PROVIDER }]` },
156
+ { field: `status.connected` },
146
157
  ],
147
158
  [CONFIG_MAP]: [
148
159
  { field: 'metadata.labels[harvesterhci.io/cloud-init-template]' }
@@ -171,9 +182,10 @@ class StevePaginationUtils extends NamespaceProjectFilters {
171
182
  { field: 'status.releaseName' },
172
183
  ],
173
184
  [CAPI.RANCHER_CLUSTER]: [
174
- { field: `metadata.labels."${ CAPI_LABELS.PROVIDER }"` },
185
+ { field: `metadata.labels[${ CAPI_LAB_AND_ANO.PROVIDER }]` },
175
186
  { field: `status.provider` },
176
187
  { field: 'status.clusterName' },
188
+ { field: `metadata.annotations[${ CAPI_LAB_AND_ANO.HUMAN_NAME }]` }
177
189
  ],
178
190
  [SERVICE]: [
179
191
  { field: 'spec.type' },
@@ -433,9 +445,14 @@ class StevePaginationUtils extends NamespaceProjectFilters {
433
445
  this.validateField(validateFields, schema, field.field);
434
446
 
435
447
  const value = encodeURIComponent(field.value);
436
- const exactPartial = field.exact ? `'${ value }'` : value;
437
448
 
438
- return `${ this.convertArrayPath(field.field) }${ field.equals ? '=' : '!=' }${ exactPartial }`;
449
+ // = exact match (equals + exact)
450
+ // ~ partial match (equals + !exact)
451
+ // != not exact match (!equals + exact)
452
+ // !~ not partial match (!equals + !exact)
453
+ const operator = `${ field.equals ? '' : '!' }${ field.exact ? '=' : '~' }`;
454
+
455
+ return `${ this.convertArrayPath(field.field) }${ operator }${ value }`;
439
456
  }
440
457
 
441
458
  return field.value;
@@ -460,4 +477,37 @@ class StevePaginationUtils extends NamespaceProjectFilters {
460
477
  }
461
478
  }
462
479
 
480
+ export const PAGINATION_SETTINGS_STORE_DEFAULTS: PaginationSettingsStore = {
481
+ cluster: {
482
+ resources: {
483
+ enableAll: false,
484
+ enableSome: {
485
+ // if a resource list is shown by a custom resource list component or has specific list headers then it's not generically shown
486
+ // and must be included here.
487
+ enabled: [
488
+ NODE, EVENT,
489
+ WORKLOAD_TYPES.CRON_JOB, WORKLOAD_TYPES.DAEMON_SET, WORKLOAD_TYPES.DEPLOYMENT, WORKLOAD_TYPES.JOB, WORKLOAD_TYPES.STATEFUL_SET, POD,
490
+ CATALOG.APP, CATALOG.CLUSTER_REPO, CATALOG.OPERATION,
491
+ HPA, INGRESS, SERVICE,
492
+ PV, CONFIG_MAP, STORAGE_CLASS, PVC, SECRET,
493
+ WORKLOAD_TYPES.REPLICA_SET, WORKLOAD_TYPES.REPLICATION_CONTROLLER
494
+ ],
495
+ generic: true,
496
+ }
497
+ }
498
+ },
499
+ management: {
500
+ resources: {
501
+ enableAll: false,
502
+ enableSome: {
503
+ enabled: [
504
+ { resource: CAPI.RANCHER_CLUSTER, context: ['home', 'side-bar'] },
505
+ { resource: MANAGEMENT.CLUSTER, context: ['side-bar'] },
506
+ ],
507
+ generic: false,
508
+ }
509
+ }
510
+ }
511
+ };
512
+
463
513
  export default new StevePaginationUtils();
@@ -0,0 +1,98 @@
1
+ <script>
2
+ import { exceptionToErrorsArray } from '@shell/utils/error';
3
+ import { resourceNames } from '@shell/utils/string';
4
+ import { Banner } from '@components/Banner';
5
+ import { mapGetters, mapState } from 'vuex';
6
+ import { getVendor } from '@shell/config/private-label';
7
+
8
+ export default {
9
+ name: 'PromptRemoveFleetWorkspacesDialog',
10
+
11
+ emits: ['errors'],
12
+
13
+ components: { Banner },
14
+
15
+ props: {
16
+ value: {
17
+ type: Array,
18
+ default: () => {
19
+ return [];
20
+ }
21
+ },
22
+
23
+ names: {
24
+ type: Array,
25
+ default: () => {
26
+ return [];
27
+ }
28
+ },
29
+
30
+ type: {
31
+ type: String,
32
+ required: true
33
+ },
34
+
35
+ close: {
36
+ type: Function,
37
+ required: true
38
+ },
39
+ },
40
+
41
+ data() {
42
+ return {
43
+ vendor: getVendor(),
44
+ errors: []
45
+ };
46
+ },
47
+
48
+ computed: {
49
+ ...mapState('action-menu', ['toRemove']),
50
+ ...mapGetters({ t: 'i18n/t' }),
51
+ },
52
+
53
+ methods: {
54
+ resourceNames,
55
+ async remove(buttonDone) {
56
+ try {
57
+ await Promise.all(this.value.map((resource) => resource.remove()));
58
+
59
+ this.close(buttonDone);
60
+ } catch (err) {
61
+ this.errors = exceptionToErrorsArray(err);
62
+ buttonDone(false);
63
+ }
64
+ }
65
+
66
+ }
67
+ };
68
+ </script>
69
+
70
+ <template>
71
+ <div class="mt-10">
72
+ <div class="mb-10">
73
+ {{ t('promptRemove.attemptingToRemove', { type }) }} <span
74
+ v-clean-html="resourceNames(names, t)"
75
+ class="description"
76
+ />
77
+ </div>
78
+ <Banner
79
+ color="warning"
80
+ class="warning"
81
+ >
82
+ <span v-clean-html="t('fleet.workspaces.remove.warning', {}, true)" />
83
+ </Banner>
84
+ <Banner
85
+ v-for="(error, i) in errors"
86
+ :key="i"
87
+ class=""
88
+ color="error"
89
+ :label="error"
90
+ />
91
+ </div>
92
+ </template>
93
+
94
+ <style lang='scss' scoped>
95
+ .description {
96
+ font-weight: 600;
97
+ }
98
+ </style>
@@ -21,7 +21,7 @@ export default {
21
21
 
22
22
  <template>
23
23
  <div>
24
- {{ t('promptRemove.attemptingToRemove', { type }) }} <span v-clean-html="resourceNames(names, plusMore, t)" />
24
+ {{ t('promptRemove.attemptingToRemove', { type }) }} <span v-clean-html="resourceNames(names, t)" />
25
25
  <div
26
26
  v-if="info"
27
27
  class="text info mb-10 mt-20"
@@ -58,12 +58,6 @@ export default {
58
58
  return [];
59
59
  },
60
60
 
61
- plusMore() {
62
- const remaining = this.filteredNamespaces.length > 5 ? this.filteredNamespaces.length - 5 : 0;
63
-
64
- return this.t('promptRemove.andOthers', { count: remaining });
65
- },
66
-
67
61
  displayName() {
68
62
  return this.currentProject?.spec?.displayName;
69
63
  },
@@ -100,7 +94,7 @@ export default {
100
94
  <template v-if="!canSeeProjectlessNamespaces">
101
95
  <span class="delete-warning"> {{ t('promptRemove.willDeleteAssociatedNamespaces') }}</span> <br>
102
96
  <div
103
- v-clean-html="resourceNames(names, plusMore, t)"
97
+ v-clean-html="resourceNames(names, t)"
104
98
  class="mt-10"
105
99
  />
106
100
  </template>
@@ -114,7 +108,7 @@ export default {
114
108
  :label="t('promptRemove.deleteAssociatedNamespaces')"
115
109
  />
116
110
  <div class="mt-10 ml-20">
117
- <span v-clean-html="resourceNames(names, plusMore, t)" />
111
+ <span v-clean-html="resourceNames(names, t)" />
118
112
  </div>
119
113
  </div>
120
114
  </div>
@@ -22,7 +22,7 @@ export default {
22
22
  <template>
23
23
  <div>
24
24
  {{ t('promptRemove.attemptingToRemove', { type }) }} <span
25
- v-clean-html="resourceNames(names, plusMore, t)"
25
+ v-clean-html="resourceNames(names, t)"
26
26
  />
27
27
  <div
28
28
  v-if="info"
@@ -17,13 +17,7 @@ export default {
17
17
  ...mapGetters({ t: 'i18n/t' }),
18
18
 
19
19
  names() {
20
- return this.toRemove.map((obj) => obj.nameDisplay).slice(0, 5);
21
- },
22
-
23
- plusMore() {
24
- const remaining = this.toRemove.length - this.names.length;
25
-
26
- return this.t('promptRemove.andOthers', { count: remaining });
20
+ return this.toRemove.map((obj) => obj.nameDisplay);
27
21
  },
28
22
  },
29
23
  watch: {
@@ -1,4 +1,5 @@
1
1
  <script>
2
+ import { resourceNames } from '@shell/utils/string';
2
3
  import { Banner } from '@components/Banner';
3
4
  import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
4
5
  import { mapGetters, mapState } from 'vuex';
@@ -55,31 +56,10 @@ export default {
55
56
  computed: {
56
57
  ...mapState('action-menu', ['toRemove']),
57
58
  ...mapGetters({ t: 'i18n/t' }),
58
-
59
- plusMore() {
60
- const count = this.names.length - this.names.length;
61
-
62
- return this.t('promptRemove.andOthers', { count });
63
- },
64
-
65
- podNames() {
66
- return this.names.reduce((res, name, i) => {
67
- if (i >= 5) {
68
- return res;
69
- }
70
- res += `<b>${ name }</b>`;
71
- if (i === this.names.length - 1) {
72
- res += this.plusMore;
73
- } else {
74
- res += i === this.toRemove.length - 2 ? ' and ' : ', ';
75
- }
76
-
77
- return res;
78
- }, '');
79
- },
80
59
  },
81
60
 
82
61
  methods: {
62
+ resourceNames,
83
63
  async remove(confirm) {
84
64
  let goTo;
85
65
 
@@ -118,8 +98,8 @@ export default {
118
98
  <div class="mt-10">
119
99
  <div class="mb-30">
120
100
  {{ t('promptRemove.attemptingToRemove', { type }) }} <span
121
- v-clean-html="podNames"
122
- class="machine-name"
101
+ v-clean-html="resourceNames(names, t)"
102
+ class="body"
123
103
  />
124
104
  </div>
125
105
  <div class="mb-30">
@@ -143,11 +123,10 @@ export default {
143
123
  </template>
144
124
 
145
125
  <style lang='scss' scoped>
126
+ .body {
127
+ font-weight: 600;
128
+ }
146
129
  .actions {
147
130
  text-align: right;
148
131
  }
149
-
150
- .machine-name {
151
- font-weight: 600;
152
- }
153
132
  </style>
@@ -59,7 +59,15 @@ export default defineComponent({
59
59
  },
60
60
  setup(props) {
61
61
  if (props.triggerFocusTrap) {
62
- useBasicSetupFocusTrap('#focus-trap-card-container-element');
62
+ useBasicSetupFocusTrap('#focus-trap-card-container-element', {
63
+ // needs to be false because of import YAML modal from header
64
+ // where the YAML editor itself is a focus trap
65
+ // and we can't have it superseed the "escape key" to blur that UI element
66
+ // In this case the focus trap moves the focus out of the modal
67
+ // correctly once it closes because of the "onBeforeUnmount" trigger
68
+ escapeDeactivates: false,
69
+ allowOutsideClick: true,
70
+ });
63
71
  }
64
72
  }
65
73
  });
@@ -3,6 +3,7 @@ import { PropType, defineComponent } from 'vue';
3
3
  import { _EDIT, _VIEW } from '@shell/config/query-params';
4
4
  import { addObject, removeObject } from '@shell/utils/array';
5
5
  import cloneDeep from 'lodash/cloneDeep';
6
+ import { generateRandomAlphaString } from '@shell/utils/string';
6
7
 
7
8
  export default defineComponent({
8
9
  name: 'Checkbox',
@@ -37,7 +38,7 @@ export default defineComponent({
37
38
  */
38
39
  id: {
39
40
  type: String,
40
- default: String(Math.random() * 1000)
41
+ default: generateRandomAlphaString(12)
41
42
  },
42
43
 
43
44
  /**
@@ -113,7 +114,16 @@ export default defineComponent({
113
114
  primary: {
114
115
  type: Boolean,
115
116
  default: false
116
- }
117
+ },
118
+
119
+ /**
120
+ * Use this for usage of checkboxes that don't present a label.
121
+ * Used for cases such as table checkboxes (group or row)
122
+ */
123
+ alternateLabel: {
124
+ type: String,
125
+ default: undefined
126
+ },
117
127
  },
118
128
 
119
129
  emits: ['update:value'],
@@ -143,6 +153,18 @@ export default defineComponent({
143
153
  hasTooltip(): boolean {
144
154
  return !!this.tooltip || !!this.tooltipKey;
145
155
  },
156
+
157
+ replacementLabel(): string | undefined {
158
+ if (!this.label && !this.labelKey && this.alternateLabel) {
159
+ return this.alternateLabel;
160
+ }
161
+
162
+ return undefined;
163
+ },
164
+
165
+ idForLabel():string {
166
+ return `${ this.id }-label`;
167
+ }
146
168
  },
147
169
 
148
170
  methods: {
@@ -228,17 +250,16 @@ export default defineComponent({
228
250
  <label
229
251
  class="checkbox-container"
230
252
  :class="{ 'disabled': isDisabled}"
231
- :for="id"
232
253
  @keydown.enter.prevent="clicked($event)"
233
254
  @keydown.space.prevent="clicked($event)"
234
255
  @click="clicked($event)"
235
256
  >
236
257
  <input
258
+ :id="id"
237
259
  :checked="isChecked"
238
260
  :value="valueWhenTrue"
239
261
  type="checkbox"
240
262
  tabindex="-1"
241
- :name="id"
242
263
  @click.stop.prevent
243
264
  @keyup.enter.stop.prevent
244
265
  >
@@ -246,8 +267,9 @@ export default defineComponent({
246
267
  class="checkbox-custom"
247
268
  :class="{indeterminate: indeterminate}"
248
269
  :tabindex="isDisabled ? -1 : 0"
249
- :aria-label="label"
270
+ :aria-label="replacementLabel"
250
271
  :aria-checked="!!value"
272
+ :aria-labelledby="labelKey || label ? idForLabel : undefined"
251
273
  role="checkbox"
252
274
  />
253
275
  <span
@@ -258,19 +280,25 @@ export default defineComponent({
258
280
  <slot name="label">
259
281
  <t
260
282
  v-if="labelKey"
283
+ :id="idForLabel"
261
284
  :k="labelKey"
262
285
  :raw="true"
263
286
  />
264
- <template v-else-if="label">{{ label }}</template>
287
+ <span
288
+ v-else-if="label"
289
+ :id="idForLabel"
290
+ >{{ label }}</span>
265
291
  <i
266
292
  v-if="tooltipKey"
267
293
  v-clean-tooltip="{content: t(tooltipKey), triggers: ['hover', 'touch', 'focus']}"
294
+ v-stripped-aria-label="t(tooltipKey)"
268
295
  class="checkbox-info icon icon-info icon-lg"
269
296
  :tabindex="isDisabled ? -1 : 0"
270
297
  />
271
298
  <i
272
299
  v-else-if="tooltip"
273
300
  v-clean-tooltip="{content: tooltip, triggers: ['hover', 'touch', 'focus']}"
301
+ v-stripped-aria-label="tooltip"
274
302
  class="checkbox-info icon icon-info icon-lg"
275
303
  :tabindex="isDisabled ? -1 : 0"
276
304
  />
@@ -289,6 +317,9 @@ export default defineComponent({
289
317
  {{ description }}
290
318
  </template>
291
319
  </div>
320
+ <div class="checkbox-outer-container-extra">
321
+ <slot name="extra" />
322
+ </div>
292
323
  </div>
293
324
  </template>
294
325
 
@@ -305,6 +336,11 @@ $fontColor: var(--input-label);
305
336
  margin-top: 5px;
306
337
  opacity: 0.8;
307
338
  }
339
+ &-extra {
340
+ font-size: 14px;
341
+ margin-left: 19px;
342
+ margin-top: 5px;
343
+ }
308
344
  }
309
345
 
310
346
  // NOTE: SortableTable depends on the names of this class, do not arbitrarily change.
@@ -2,7 +2,7 @@
2
2
  import { defineComponent, inject } from 'vue';
3
3
  import TextAreaAutoGrow from '@components/Form/TextArea/TextAreaAutoGrow.vue';
4
4
  import LabeledTooltip from '@components/LabeledTooltip/LabeledTooltip.vue';
5
- import { escapeHtml } from '@shell/utils/string';
5
+ import { escapeHtml, generateRandomAlphaString } from '@shell/utils/string';
6
6
  import cronstrue from 'cronstrue';
7
7
  import { isValidCron } from 'cron-validator';
8
8
  import { debounce } from 'lodash';
@@ -105,6 +105,15 @@ export default defineComponent({
105
105
  class: {
106
106
  type: String,
107
107
  default: ''
108
+ },
109
+
110
+ /**
111
+ * Optionally use this to comply with a11y IF there's no label
112
+ * associated with the input
113
+ */
114
+ ariaLabel: {
115
+ type: String,
116
+ default: ''
108
117
  }
109
118
  },
110
119
 
@@ -139,6 +148,7 @@ export default defineComponent({
139
148
  return {
140
149
  updated: false,
141
150
  validationErrors: '',
151
+ inputId: `input-${ generateRandomAlphaString(12) }`
142
152
  };
143
153
  },
144
154
 
@@ -240,6 +250,14 @@ export default defineComponent({
240
250
  }
241
251
  },
242
252
 
253
+ mounted() {
254
+ const id = this.$attrs?.id as string | undefined;
255
+
256
+ if (id) {
257
+ this.inputId = id;
258
+ }
259
+ },
260
+
243
261
  created() {
244
262
  /**
245
263
  * Determines if the Labeled Input @input event should be debounced.
@@ -330,7 +348,10 @@ export default defineComponent({
330
348
  }"
331
349
  >
332
350
  <slot name="label">
333
- <label v-if="hasLabel">
351
+ <label
352
+ v-if="hasLabel"
353
+ :for="inputId"
354
+ >
334
355
  <t
335
356
  v-if="labelKey"
336
357
  :k="labelKey"
@@ -349,8 +370,10 @@ export default defineComponent({
349
370
  <slot name="field">
350
371
  <TextAreaAutoGrow
351
372
  v-if="type === 'multiline' || type === 'multiline-password'"
373
+ :id="inputId"
352
374
  ref="value"
353
375
  v-bind="$attrs"
376
+ v-stripped-aria-label="!hasLabel && ariaLabel ? ariaLabel : undefined"
354
377
  :maxlength="_maxlength"
355
378
  :disabled="isDisabled"
356
379
  :value="value || ''"
@@ -363,7 +386,9 @@ export default defineComponent({
363
386
  />
364
387
  <input
365
388
  v-else
389
+ :id="inputId"
366
390
  ref="value"
391
+ v-stripped-aria-label="!hasLabel && ariaLabel ? ariaLabel : undefined"
367
392
  role="textbox"
368
393
  :class="{ 'no-label': !hasLabel }"
369
394
  v-bind="$attrs"
@@ -383,12 +408,14 @@ export default defineComponent({
383
408
  </slot>
384
409
 
385
410
  <slot name="suffix" />
411
+ <!-- informational tooltip about field -->
386
412
  <LabeledTooltip
387
- v-if="hasTooltip && !focused"
413
+ v-if="hasTooltip"
388
414
  :hover="hoverTooltip"
389
415
  :value="tooltipValue"
390
416
  :status="status"
391
417
  />
418
+ <!-- validation tooltip -->
392
419
  <LabeledTooltip
393
420
  v-if="!!validationMessage"
394
421
  :hover="hoverTooltip"
@@ -68,6 +68,14 @@ export default defineComponent({
68
68
  description: {
69
69
  type: String,
70
70
  default: null
71
+ },
72
+
73
+ /**
74
+ * Prevent focus when using radio in the context of a Radio group
75
+ */
76
+ preventFocusOnRadioGroups: {
77
+ type: Boolean,
78
+ default: false
71
79
  }
72
80
  },
73
81
 
@@ -111,7 +119,7 @@ export default defineComponent({
111
119
  watch: {
112
120
  value(neu) {
113
121
  this.isChecked = this.val === neu;
114
- if (this.isChecked) {
122
+ if (this.isChecked && !this.preventFocusOnRadioGroups) {
115
123
  (this.$refs.custom as HTMLElement).focus();
116
124
  }
117
125
  }
@@ -136,7 +144,11 @@ export default defineComponent({
136
144
 
137
145
  <template>
138
146
  <label
139
- :class="{'disabled': isDisabled, 'radio-container': true}"
147
+ :class="{
148
+ 'disabled': isDisabled,
149
+ 'radio-container': true,
150
+ 'radio-button-checked': isChecked
151
+ }"
140
152
  @keydown.enter="clicked($event)"
141
153
  @keydown.space="clicked($event)"
142
154
  @click.stop="clicked($event)"
@@ -146,6 +158,7 @@ export default defineComponent({
146
158
  :disabled="isDisabled"
147
159
  :name="name"
148
160
  :value="''+val"
161
+ :data-testid="label"
149
162
  :checked="isChecked"
150
163
  type="radio"
151
164
  :tabindex="-1"
@@ -154,7 +167,7 @@ export default defineComponent({
154
167
  <span
155
168
  ref="custom"
156
169
  :class="[ isDisabled ? 'text-muted' : '', 'radio-custom']"
157
- :tabindex="isDisabled ? -1 : 0"
170
+ :tabindex="isDisabled || preventFocusOnRadioGroups ? -1 : 0"
158
171
  :aria-label="label"
159
172
  :aria-checked="isChecked"
160
173
  role="radio"
@@ -220,9 +233,11 @@ $fontColor: var(--input-label);
220
233
  display: inline-flex;
221
234
  align-items: flex-start;
222
235
  margin: 0;
236
+ left: -4px;
223
237
  user-select: none;
224
238
  border-radius: var(--border-radius);
225
239
  padding-bottom: 5px;
240
+ padding-left: 4px;
226
241
 
227
242
  &,
228
243
  .radio-label,