dashboard-shell-shell 1.0.111 → 1.0.113

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 (180) hide show
  1. package/.DS_Store +0 -0
  2. package/assets/icons/demo.css +539 -0
  3. package/assets/icons/demo_index.html +1131 -0
  4. package/assets/icons/iconfont.css +200 -0
  5. package/assets/icons/iconfont.js +1 -0
  6. package/assets/icons/iconfont.json +296 -0
  7. package/assets/icons/iconfont.ttf +0 -0
  8. package/assets/icons/iconfont.woff +0 -0
  9. package/assets/icons/iconfont.woff2 +0 -0
  10. package/assets/images/API.svg +3 -0
  11. package/assets/images/login/password.svg +20 -0
  12. package/assets/images/login/user.svg +6 -0
  13. package/assets/images/login-bg.png +0 -0
  14. package/assets/images/login-left.png +0 -0
  15. package/assets/images/login-logo.svg +19 -0
  16. package/assets/images/logo.png +0 -0
  17. package/assets/images/pl/harvester.png +0 -0
  18. package/assets/images/promp-yellow.svg +5 -0
  19. package/assets/images/user.png +0 -0
  20. package/assets/styles/all.scss +63 -0
  21. package/assets/styles/app.scss +2 -0
  22. package/assets/styles/base/_basic.scss +8 -2
  23. package/assets/styles/base/_helpers.scss +4 -0
  24. package/assets/styles/base/_typography.scss +2 -1
  25. package/assets/styles/base/_variables.scss +10 -2
  26. package/assets/styles/global/_button.scss +37 -25
  27. package/assets/styles/global/_columns.scss +3 -1
  28. package/assets/styles/global/_form.scss +45 -13
  29. package/assets/styles/global/_labeled-input.scss +50 -25
  30. package/assets/styles/global/_layout.scss +9 -3
  31. package/assets/styles/global/_select.scss +20 -13
  32. package/assets/styles/global/_table.scss +1 -1
  33. package/assets/styles/global/_tooltip.scss +47 -6
  34. package/assets/styles/themes/_dark.scss +1 -0
  35. package/assets/styles/themes/_light.scss +59 -46
  36. package/assets/styles/themes/_suse.scss +1 -0
  37. package/assets/styles/vendor/vue-select.scss +18 -7
  38. package/assets/translations/en-us.yaml +93 -12
  39. package/assets/translations/zh-hans.yaml +278 -141
  40. package/components/ActionDropdown.vue +1 -1
  41. package/components/ActionDropdownShell.vue +71 -0
  42. package/components/ActionMenu.vue +2 -2
  43. package/components/ActionMenuShell.vue +1 -0
  44. package/components/AppModal.vue +78 -6
  45. package/components/AssignTo.vue +25 -11
  46. package/components/AsyncButton.vue +24 -7
  47. package/components/BannerGraphic.vue +1 -0
  48. package/components/ButtonDropdown.vue +26 -4
  49. package/components/ButtonGroup.vue +4 -0
  50. package/components/ButtonMultiAction.vue +1 -0
  51. package/components/CommunityLinks.vue +3 -3
  52. package/components/ConsumptionGauge.vue +24 -5
  53. package/components/CopyToClipboardText.vue +2 -1
  54. package/components/CruResource.vue +12 -7
  55. package/components/CruResourceFooter.vue +2 -2
  56. package/components/DashboardOptions.vue +21 -15
  57. package/components/DetailText.vue +5 -0
  58. package/components/DisableAuthProviderModal.vue +1 -0
  59. package/components/DotState.vue +84 -0
  60. package/components/ExplorerMembers.vue +1 -1
  61. package/components/ExplorerProjectsNamespaces.vue +56 -14
  62. package/components/FixedBanner.vue +19 -12
  63. package/components/GlobalRoleBindings.vue +5 -1
  64. package/components/GrafanaDashboard.vue +4 -4
  65. package/components/GrowlManager.vue +4 -1
  66. package/components/HardwareResourceGauge.vue +39 -3
  67. package/components/InfoBox.vue +3 -3
  68. package/components/InputOrDisplay.vue +28 -2
  69. package/components/LabelValue.vue +16 -1
  70. package/components/LandingPagePreference.vue +5 -3
  71. package/components/LocaleSelector.vue +39 -93
  72. package/components/ModalManager.vue +55 -0
  73. package/components/ModalWithCard.vue +2 -0
  74. package/components/MoveModal.vue +1 -0
  75. package/components/PromptChangePassword.vue +1 -1
  76. package/components/PromptModal.vue +15 -2
  77. package/components/PromptRemove.vue +28 -8
  78. package/components/PromptRestore.vue +1 -0
  79. package/components/ResourceCancelModal.vue +1 -0
  80. package/components/ResourceDetail/Masthead.vue +188 -43
  81. package/components/ResourceDetail/__tests__/Masthead.test.ts +5 -1
  82. package/components/ResourceDetail/index.vue +49 -14
  83. package/components/ResourceList/Masthead.vue +80 -18
  84. package/components/ResourceTable.vue +60 -19
  85. package/components/SideNav.vue +32 -12
  86. package/components/SlideInPanelManager.vue +126 -0
  87. package/components/SortableTable/THead.vue +34 -5
  88. package/components/SortableTable/actions.js +1 -1
  89. package/components/SortableTable/index.vue +649 -142
  90. package/components/SortableTable/paging.js +36 -28
  91. package/components/SortableTable/selection.js +0 -11
  92. package/components/StatusBadge.vue +77 -0
  93. package/components/Tabbed/Tab.vue +3 -3
  94. package/components/Tabbed/index.vue +44 -26
  95. package/components/Wizard.vue +2 -2
  96. package/components/__tests__/AsyncButton.test.ts +2 -2
  97. package/components/__tests__/FixedBanner.test.ts +3 -3
  98. package/components/__tests__/ModalManager.spec.ts +176 -0
  99. package/components/__tests__/SlideInPanelManager.spec.ts +166 -0
  100. package/components/auth/Principal.vue +10 -3
  101. package/components/auth/__tests__/RoleDetailEdit.test.ts +3 -2
  102. package/components/form/ArrayList.vue +123 -85
  103. package/components/form/ArrayListGrouped.vue +10 -2
  104. package/components/form/Command.vue +6 -15
  105. package/components/form/EnvVars.vue +16 -8
  106. package/components/form/Footer.vue +8 -5
  107. package/components/form/HealthCheck.vue +3 -3
  108. package/components/form/HookOption.vue +11 -16
  109. package/components/form/KeyValue.vue +16 -7
  110. package/components/form/LabeledSelect.vue +59 -76
  111. package/components/form/LifecycleHooks.vue +3 -3
  112. package/components/form/MatchExpressions.vue +35 -12
  113. package/components/form/NameNsDescription.vue +147 -115
  114. package/components/form/Networking.vue +20 -12
  115. package/components/form/NodeAffinity.vue +31 -23
  116. package/components/form/NodeScheduling.vue +13 -3
  117. package/components/form/Password.vue +11 -5
  118. package/components/form/PodAffinity.vue +43 -44
  119. package/components/form/Probe.vue +68 -66
  120. package/components/form/ResourceQuota/Project.vue +5 -1
  121. package/components/form/ResourceSelector.vue +7 -9
  122. package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +6 -3
  123. package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +12 -1
  124. package/components/form/SSHKnownHosts/index.vue +16 -2
  125. package/components/form/Security.vue +54 -56
  126. package/components/form/Select.vue +41 -7
  127. package/components/form/ShellInput.vue +5 -1
  128. package/components/form/Tolerations.vue +5 -1
  129. package/components/form/UnitInput.vue +2 -2
  130. package/components/form/ValueFromResource.vue +134 -121
  131. package/components/form/WorkloadPorts.vue +18 -18
  132. package/components/form/__tests__/ArrayList.test.ts +5 -2
  133. package/components/form/__tests__/MatchExpressions.test.ts +12 -12
  134. package/components/form/__tests__/NameNsDescription.test.ts +115 -14
  135. package/components/form/__tests__/Probe.test.ts +12 -8
  136. package/components/form/__tests__/SSHKnownHosts.test.ts +11 -0
  137. package/components/form/__tests__/Select.test.ts +37 -0
  138. package/components/form/__tests__/UnitInput.test.ts +4 -5
  139. package/components/formatter/BadgeStateFormatter.vue +8 -5
  140. package/components/formatter/InternalExternalIP.vue +2 -0
  141. package/components/formatter/SecretData.vue +20 -7
  142. package/components/nav/Favorite.vue +5 -1
  143. package/components/nav/Group.vue +60 -27
  144. package/components/nav/Header.vue +39 -13
  145. package/components/nav/Jump.vue +7 -0
  146. package/components/nav/NamespaceFilter.vue +14 -8
  147. package/components/nav/Pinned.vue +1 -1
  148. package/components/nav/TopLevelMenu.vue +5 -17
  149. package/components/nav/Type.vue +32 -35
  150. package/components/nav/__tests__/TopLevelMenu.test.ts +0 -40
  151. package/components/templates/blank.vue +4 -1
  152. package/components/templates/default.vue +8 -0
  153. package/components/templates/home.vue +10 -1
  154. package/components/templates/plain.vue +10 -1
  155. package/package.json +1 -1
  156. package/rancher-components/Banner/Banner.vue +6 -4
  157. package/rancher-components/Card/Card.vue +6 -4
  158. package/rancher-components/Form/Checkbox/Checkbox.vue +20 -1
  159. package/rancher-components/Form/LabeledInput/LabeledInput.vue +46 -5
  160. package/rancher-components/Form/Radio/RadioButton.vue +32 -8
  161. package/rancher-components/Form/Radio/RadioGroup.vue +31 -24
  162. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +17 -0
  163. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +8 -3
  164. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +15 -3
  165. package/rancher-components/RcButton/RcButton.vue +1 -0
  166. package/rancher-components/RcButton/types.ts +1 -0
  167. package/rancher-components/RcDropdown/RcDropdown.vue +54 -15
  168. package/rancher-components/RcDropdown/RcDropdownItem.vue +5 -4
  169. package/rancher-components/RcDropdown/RcDropdownMenu.vue +11 -7
  170. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +12 -2
  171. package/rancher-components/RcDropdown/useDropdownCollection.ts +8 -0
  172. package/rancher-components/RcDropdown/useDropdownContext.ts +9 -3
  173. package/rancher-components/StringList/StringList.vue +1 -1
  174. package/store/type-map.js +29 -2
  175. package/utils/error.js +30 -8
  176. package/utils/errorTranslate.json +916 -0
  177. package/vue.config.js +1 -1
  178. package/components/formatter/ExtensionCache.vue +0 -74
  179. package/components/formatter/Port.vue +0 -24
  180. package/components/formatter/SecretType.vue +0 -41
@@ -84,53 +84,14 @@ export default {
84
84
  },
85
85
 
86
86
  data() {
87
- if (!this.value[this.field]) {
88
- this.value[this.field] = {};
89
- }
90
- const { podAffinity = {}, podAntiAffinity = {} } = this.value[this.field];
91
- const allAffinityTerms = [...(podAffinity.preferredDuringSchedulingIgnoredDuringExecution || []), ...(podAffinity.requiredDuringSchedulingIgnoredDuringExecution || [])].map((term) => {
92
- let out = clone(term);
93
-
94
- out._id = randomStr(4);
95
- out._anti = false;
96
- if (term.podAffinityTerm) {
97
- Object.assign(out, term.podAffinityTerm);
98
- out = this.parsePodAffinityTerm(out);
99
-
100
- delete out.podAffinityTerm;
101
- } else {
102
- out = this.parsePodAffinityTerm(out);
103
- }
104
-
105
- return out;
106
- });
107
- const allAntiTerms = [...(podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution || []), ...(podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecution || [])].map((term) => {
108
- let out = clone(term);
109
-
110
- out._id = randomStr(4);
111
- out._anti = true;
112
- if (term.podAffinityTerm) {
113
- Object.assign(out, term.podAffinityTerm);
114
- out = this.parsePodAffinityTerm(out);
115
-
116
- delete out.podAffinityTerm;
117
- } else {
118
- out = this.parsePodAffinityTerm(out);
119
- }
120
-
121
- return out;
122
- });
123
-
124
- const allSelectorTerms = [...allAffinityTerms, ...allAntiTerms];
125
-
126
87
  return {
127
- allSelectorTerms,
128
- defaultWeight: 1,
88
+ allSelectorTerms: [],
89
+ defaultWeight: 1,
129
90
  // rules in MatchExpressions.vue can not catch changes what happens on parent component
130
91
  // we need re-render it via key changing
131
- rerenderNums: randomStr(4),
92
+ rerenderNums: randomStr(4),
132
93
  NAMESPACE_SELECTION_OPTION_VALUES,
133
- defaultAddValue: {
94
+ defaultAddValue: {
134
95
  _namespaceOption: NAMESPACE_SELECTION_OPTION_VALUES.POD,
135
96
  matchExpressions: [],
136
97
  namespaces: null,
@@ -138,6 +99,7 @@ export default {
138
99
  }
139
100
  };
140
101
  },
102
+
141
103
  computed: {
142
104
  ...mapGetters({ t: 'i18n/t' }),
143
105
  isView() {
@@ -226,6 +188,44 @@ export default {
226
188
  },
227
189
 
228
190
  created() {
191
+ if (!this.value[this.field]) {
192
+ this.value[this.field] = {};
193
+ }
194
+ const { podAffinity = {}, podAntiAffinity = {} } = this.value[this.field];
195
+ const allAffinityTerms = [...(podAffinity.preferredDuringSchedulingIgnoredDuringExecution || []), ...(podAffinity.requiredDuringSchedulingIgnoredDuringExecution || [])].map((term) => {
196
+ let out = clone(term);
197
+
198
+ out._id = randomStr(4);
199
+ out._anti = false;
200
+ if (term.podAffinityTerm) {
201
+ Object.assign(out, term.podAffinityTerm);
202
+ out = this.parsePodAffinityTerm(out);
203
+
204
+ delete out.podAffinityTerm;
205
+ } else {
206
+ out = this.parsePodAffinityTerm(out);
207
+ }
208
+
209
+ return out;
210
+ });
211
+ const allAntiTerms = [...(podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution || []), ...(podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecution || [])].map((term) => {
212
+ let out = clone(term);
213
+
214
+ out._id = randomStr(4);
215
+ out._anti = true;
216
+ if (term.podAffinityTerm) {
217
+ Object.assign(out, term.podAffinityTerm);
218
+ out = this.parsePodAffinityTerm(out);
219
+
220
+ delete out.podAffinityTerm;
221
+ } else {
222
+ out = this.parsePodAffinityTerm(out);
223
+ }
224
+
225
+ return out;
226
+ });
227
+
228
+ this.allSelectorTerms = [...allAffinityTerms, ...allAntiTerms];
229
229
  this.queueUpdate = debounce(this.update, 500);
230
230
  },
231
231
 
@@ -364,7 +364,6 @@ export default {
364
364
  <div class="col span-12">
365
365
  <ArrayListGrouped
366
366
  v-model:value="allSelectorTerms"
367
- class="mt-20"
368
367
  :default-add-value="defaultAddValue"
369
368
  :mode="mode"
370
369
  :add-label="addLabel"
@@ -6,6 +6,7 @@ import { LabeledInput } from '@components/Form/LabeledInput';
6
6
  import LabeledSelect from '@shell/components/form/LabeledSelect';
7
7
  import ShellInput from '@shell/components/form/ShellInput';
8
8
  import KeyValue from '@shell/components/form/KeyValue';
9
+ import { computed, ref, watch } from 'vue';
9
10
 
10
11
  const KINDS = [
11
12
  'none',
@@ -43,29 +44,29 @@ export default {
43
44
  },
44
45
  },
45
46
 
46
- data() {
47
- let kind = 'none';
48
- let probe = null;
49
- let exec = null;
50
- let httpGet = null;
51
- let tcpSocket = null;
52
-
53
- if ( this.value ) {
54
- probe = clone(this.value);
55
-
56
- if ( probe.exec ) {
57
- kind = 'exec';
58
- } else if ( probe.httpGet ) {
59
- if ( (probe.httpGet.scheme || '').toLowerCase() === 'https' ) {
60
- kind = 'HTTPS';
47
+ setup(props, { emit }) {
48
+ const kind = ref('none');
49
+ const probe = ref(null);
50
+ const exec = ref(null);
51
+ const httpGet = ref(null);
52
+ const tcpSocket = ref(null);
53
+
54
+ if ( props.value ) {
55
+ probe.value = clone(props.value);
56
+
57
+ if ( probe.value.exec ) {
58
+ kind.value = 'exec';
59
+ } else if ( probe.value.httpGet ) {
60
+ if ( (probe.value.httpGet.scheme || '').toLowerCase() === 'https' ) {
61
+ kind.value = 'HTTPS';
61
62
  } else {
62
- kind = 'HTTP';
63
+ kind.value = 'HTTP';
63
64
  }
64
- } else if ( probe.tcpSocket ) {
65
- kind = 'tcp';
65
+ } else if ( probe.value.tcpSocket ) {
66
+ kind.value = 'tcp';
66
67
  }
67
68
  } else {
68
- probe = {
69
+ probe.value = {
69
70
  failureThreshold: 3,
70
71
  successThreshold: 1,
71
72
  initialDelaySeconds: 0,
@@ -77,68 +78,68 @@ export default {
77
78
  };
78
79
  }
79
80
 
80
- exec = probe.exec || {};
81
- httpGet = probe.httpGet || {};
82
- tcpSocket = probe.tcpSocket || {};
81
+ exec.value = probe.value.exec || {};
82
+ httpGet.value = probe.value.httpGet || {};
83
+ tcpSocket.value = probe.value.tcpSocket || {};
83
84
 
84
- return {
85
- probe, kind, exec, httpGet, tcpSocket
86
- };
87
- },
88
-
89
- computed: {
90
- isView() {
91
- return this.mode === _VIEW;
92
- },
93
-
94
- isNone() {
95
- return this.kind === 'none';
96
- },
85
+ const isNone = computed(() => {
86
+ return kind.value === 'none';
87
+ });
97
88
 
98
- kindOptions() {
99
- return KINDS.map((k) => {
100
- return { label: this.t(`workload.container.healthCheck.kind.${ k }`), value: k };
101
- });
102
- }
103
- },
104
-
105
- watch: {
106
- kind() {
107
- this.update();
108
- }
109
- },
110
-
111
- methods: {
112
- update() {
113
- const probe = this.probe;
114
-
115
- if ( this.isNone ) {
116
- this.$emit('update:value', null);
89
+ const update = () => {
90
+ if ( isNone.value ) {
91
+ emit('update:value', null);
117
92
 
118
93
  return;
119
94
  }
120
95
 
121
- switch ( this.kind ) {
96
+ switch ( kind.value ) {
122
97
  case 'HTTP':
123
98
  case 'HTTPS':
124
- this.httpGet.scheme = this.kind;
125
- probe.httpGet = this.httpGet;
126
- probe.tcpSocket = null;
127
- probe.exec = null;
99
+ httpGet.value.scheme = kind.value;
100
+ probe.value.httpGet = httpGet.value;
101
+ probe.value.tcpSocket = null;
102
+ probe.value.exec = null;
128
103
  break;
129
104
  case 'tcp':
130
- probe.httpGet = null;
131
- probe.tcpSocket = this.tcpSocket;
132
- probe.exec = null;
105
+ probe.value.httpGet = null;
106
+ probe.value.tcpSocket = tcpSocket.value;
107
+ probe.value.exec = null;
133
108
  break;
134
109
  case 'exec':
135
- probe.httpGet = null;
136
- probe.tcpSocket = null;
137
- probe.exec = this.exec;
110
+ probe.value.httpGet = null;
111
+ probe.value.tcpSocket = null;
112
+ probe.value.exec = exec.value;
138
113
  break;
139
114
  }
140
115
 
141
- this.$emit('update:value', probe);
116
+ emit('update:value', probe.value);
117
+ };
118
+
119
+ watch(kind, () => {
120
+ update();
121
+ });
122
+
123
+ return {
124
+ probe,
125
+ kind,
126
+ exec,
127
+ httpGet,
128
+ tcpSocket,
129
+ update,
130
+ isNone,
131
+ };
132
+ },
133
+
134
+ computed: {
135
+ isView() {
136
+ return this.mode === _VIEW;
137
+ },
138
+
139
+ kindOptions() {
140
+ return KINDS.map((k) => {
141
+ return { label: this.t(`workload.container.healthCheck.kind.${ k }`), value: k };
142
+ });
142
143
  }
143
144
  },
144
145
  };
@@ -244,6 +245,7 @@ export default {
244
245
  v-if="kind && kind!=='none'"
245
246
  :style="{'position':'relative', 'margin':'0px'}"
246
247
  class="vertical"
248
+ role="none"
247
249
  >
248
250
  </div>
249
251
 
@@ -28,11 +28,15 @@ export default {
28
28
  },
29
29
 
30
30
  data() {
31
+ return { typeValues: null };
32
+ },
33
+
34
+ created() {
31
35
  this.value['spec'] = this.value.spec || {};
32
36
  this.value.spec['namespaceDefaultResourceQuota'] = this.value.spec.namespaceDefaultResourceQuota || { limit: {} };
33
37
  this.value.spec['resourceQuota'] = this.value.spec.resourceQuota || { limit: {} };
34
38
 
35
- return { typeValues: Object.keys(this.value.spec.resourceQuota.limit) };
39
+ this.typeValues = Object.keys(this.value.spec.resourceQuota.limit);
36
40
  },
37
41
 
38
42
  computed: { ...QUOTA_COMPUTED },
@@ -45,16 +45,14 @@ export default {
45
45
  },
46
46
 
47
47
  data() {
48
- const matchingResources = {
49
- matched: 0,
50
- matches: [],
51
- none: true,
52
- sample: null,
53
- total: 0,
54
- };
55
-
56
48
  return {
57
- matchingResources,
49
+ matchingResources: {
50
+ matched: 0,
51
+ matches: [],
52
+ none: true,
53
+ sample: null,
54
+ total: 0,
55
+ },
58
56
  allResources: [],
59
57
  allResourcesInScope: [],
60
58
  tableHeaders: this.$store.getters['type-map/headersFor'](
@@ -22,7 +22,7 @@ export default {
22
22
  mode: {
23
23
  type: String,
24
24
  default: _EDIT
25
- },
25
+ }
26
26
  },
27
27
 
28
28
  data() {
@@ -40,8 +40,9 @@ export default {
40
40
 
41
41
  return {
42
42
  codeMirrorOptions,
43
- text: this.value,
44
- showModal: false,
43
+ text: this.value,
44
+ showModal: false,
45
+ returnFocusSelector: '#known-ssh-hosts-trigger'
45
46
  };
46
47
  },
47
48
 
@@ -83,6 +84,8 @@ export default {
83
84
  data-testid="sshKnownHostsDialog"
84
85
  height="auto"
85
86
  :scrollable="true"
87
+ :trigger-focus-trap="true"
88
+ :return-focus-selector="returnFocusSelector"
86
89
  @close="closeDialog(false)"
87
90
  >
88
91
  <div
@@ -14,6 +14,17 @@ const requiredSetup = () => {
14
14
  return { global: { mocks: { $store: mockedStore() } } };
15
15
  };
16
16
 
17
+ jest.mock('focus-trap', () => {
18
+ return {
19
+ createFocusTrap: jest.fn().mockImplementation(() => {
20
+ return {
21
+ activate: jest.fn(),
22
+ deactivate: jest.fn(),
23
+ };
24
+ }),
25
+ };
26
+ });
27
+
17
28
  describe('component: KnownHostsEditDialog', () => {
18
29
  beforeEach(() => {
19
30
  document.body.innerHTML = '<div id="modals"></div>';
@@ -21,7 +32,7 @@ describe('component: KnownHostsEditDialog', () => {
21
32
  attachTo: document.body,
22
33
  props: {
23
34
  mode: _EDIT,
24
- value: 'line1\nline2\n',
35
+ value: 'line1\nline2\n'
25
36
  },
26
37
  ...requiredSetup(),
27
38
  });
@@ -65,12 +65,18 @@ export default defineComponent({
65
65
  </div>
66
66
  <template v-if="!isViewMode">
67
67
  <button
68
+ id="known-ssh-hosts-trigger"
68
69
  ref="button"
70
+ role="button"
71
+ :aria-label="t('secret.ssh.editKnownHosts.title')"
69
72
  data-testid="input-known-ssh-hosts_open-dialog"
70
73
  class="show-dialog-btn btn"
71
74
  @click="openDialog"
72
75
  >
73
- <i class="icon icon-edit" />
76
+ <i
77
+ class="icon icon-edit"
78
+ :alt="t('secret.ssh.editKnownHosts.title')"
79
+ />
74
80
  </button>
75
81
 
76
82
  <KnownHostsEditDialog
@@ -94,8 +100,16 @@ export default defineComponent({
94
100
  }
95
101
 
96
102
  .show-dialog-btn {
97
- display: contents;
98
103
  background-color: transparent;
104
+ padding: 4px;
105
+ height: 22px;
106
+ margin: -3px -3px 0 0;
107
+ min-height: unset;
108
+
109
+ &:focus-visible {
110
+ @include focus-outline;
111
+ outline-offset: 1px;
112
+ }
99
113
  }
100
114
  }
101
115
  </style>
@@ -5,6 +5,45 @@ import { _VIEW } from '@shell/config/query-params';
5
5
  import { mapGetters } from 'vuex';
6
6
  import LabeledSelect from '@shell/components/form/LabeledSelect';
7
7
 
8
+ const allCapabilities = ['ALL',
9
+ 'AUDIT_CONTROL',
10
+ 'AUDIT_WRITE',
11
+ 'BLOCK_SUSPEND',
12
+ 'CHOWN',
13
+ 'DAC_OVERRIDE',
14
+ 'DAC_READ_SEARCH',
15
+ 'FOWNER',
16
+ 'FSETID',
17
+ 'IPC_LOCK',
18
+ 'IPC_OWNER',
19
+ 'KILL',
20
+ 'LEASE',
21
+ 'LINUX_IMMUTABLE',
22
+ 'MAC_ADMIN',
23
+ 'MAC_OVERRIDE',
24
+ 'MKNOD',
25
+ 'NET_ADMIN',
26
+ 'NET_BIND_SERVICE',
27
+ 'NET_BROADCAST',
28
+ 'NET_RAW',
29
+ 'SETFCAP',
30
+ 'SETGID',
31
+ 'SETPCAP',
32
+ 'SETUID',
33
+ 'SYSLOG',
34
+ 'SYS_ADMIN',
35
+ 'SYS_BOOT',
36
+ 'SYS_CHROOT',
37
+ 'SYS_MODULE',
38
+ 'SYS_NICE',
39
+ 'SYS_PACCT',
40
+ 'SYS_PTRACE',
41
+ 'SYS_RAWIO',
42
+ 'SYS_RESOURCE',
43
+ 'SYS_TIME',
44
+ 'SYS_TTY_CONFIG',
45
+ 'WAKE_ALARM'];
46
+
8
47
  export default {
9
48
  emits: ['update:value'],
10
49
 
@@ -25,68 +64,27 @@ export default {
25
64
  },
26
65
 
27
66
  data() {
28
- const allCapabilities = ['ALL',
29
- 'AUDIT_CONTROL',
30
- 'AUDIT_WRITE',
31
- 'BLOCK_SUSPEND',
32
- 'CHOWN',
33
- 'DAC_OVERRIDE',
34
- 'DAC_READ_SEARCH',
35
- 'FOWNER',
36
- 'FSETID',
37
- 'IPC_LOCK',
38
- 'IPC_OWNER',
39
- 'KILL',
40
- 'LEASE',
41
- 'LINUX_IMMUTABLE',
42
- 'MAC_ADMIN',
43
- 'MAC_OVERRIDE',
44
- 'MKNOD',
45
- 'NET_ADMIN',
46
- 'NET_BIND_SERVICE',
47
- 'NET_BROADCAST',
48
- 'NET_RAW',
49
- 'SETFCAP',
50
- 'SETGID',
51
- 'SETPCAP',
52
- 'SETUID',
53
- 'SYSLOG',
54
- 'SYS_ADMIN',
55
- 'SYS_BOOT',
56
- 'SYS_CHROOT',
57
- 'SYS_MODULE',
58
- 'SYS_NICE',
59
- 'SYS_PACCT',
60
- 'SYS_PTRACE',
61
- 'SYS_RAWIO',
62
- 'SYS_RESOURCE',
63
- 'SYS_TIME',
64
- 'SYS_TTY_CONFIG',
65
- 'WAKE_ALARM'];
67
+ return {
68
+ privileged: this.value.privileged || false,
69
+ allowPrivilegeEscalation: this.value.allowPrivilegeEscalation || false,
70
+ allCapabilities,
71
+ runAsNonRoot: this.value.runAsNonRoot || false,
72
+ readOnlyRootFilesystem: this.value.readOnlyRootFilesystem || false,
73
+ add: [],
74
+ drop: [],
75
+ runAsUser: this.value.runAsUser
76
+ };
77
+ },
66
78
 
67
- const {
68
- capabilities = {},
69
- runAsNonRoot = false,
70
- readOnlyRootFilesystem = false,
71
- privileged = false,
72
- allowPrivilegeEscalation = false,
73
- runAsUser
74
- } = this.value;
79
+ created() {
80
+ const { capabilities = {} } = this.value;
75
81
  const {
76
82
  add = [],
77
83
  drop = []
78
84
  } = capabilities;
79
85
 
80
- return {
81
- privileged,
82
- allowPrivilegeEscalation,
83
- allCapabilities,
84
- runAsNonRoot,
85
- readOnlyRootFilesystem,
86
- add,
87
- drop,
88
- runAsUser
89
- };
86
+ this.add = add;
87
+ this.drop = drop;
90
88
  },
91
89
 
92
90
  computed: {
@@ -2,11 +2,12 @@
2
2
  import { get } from '@shell/utils/object';
3
3
  import LabeledFormElement from '@shell/mixins/labeled-form-element';
4
4
  import VueSelectOverrides from '@shell/mixins/vue-select-overrides';
5
+ import { generateRandomAlphaString } from '@shell/utils/string';
5
6
  import { LabeledTooltip } from '@components/LabeledTooltip';
6
7
  import { onClickOption, calculatePosition } from '@shell/utils/select';
7
8
 
8
9
  export default {
9
- emits: ['update:value', 'createdListItem'],
10
+ emits: ['update:value', 'createdListItem', 'on-open', 'on-close'],
10
11
 
11
12
  components: { LabeledTooltip },
12
13
  mixins: [
@@ -87,8 +88,17 @@ export default {
87
88
  type: Boolean,
88
89
  default: null
89
90
  },
91
+ isLangSelect: {
92
+ type: Boolean,
93
+ default: false
94
+ }
95
+ },
96
+ data() {
97
+ return {
98
+ isOpen: false,
99
+ generatedUid: `s-uid-${ generateRandomAlphaString(12) }`
100
+ };
90
101
  },
91
-
92
102
  methods: {
93
103
  // resizeHandler = in mixin
94
104
  getOptionLabel(option) {
@@ -187,14 +197,26 @@ export default {
187
197
  return Math.random(100000);
188
198
  }
189
199
  },
200
+
190
201
  report(e) {
191
202
  alert(e);
192
203
  },
204
+
193
205
  handleDropdownOpen(args) {
194
206
  // function that prevents the "opening dropdown on focus"
195
207
  // default behaviour of v-select
196
208
  return args.noDrop || args.disabled ? false : args.open;
197
- }
209
+ },
210
+ onOpen() {
211
+ this.isOpen = true;
212
+ this.$emit('on-open');
213
+ this.resizeHandler();
214
+ },
215
+
216
+ onClose() {
217
+ this.isOpen = false;
218
+ this.$emit('on-close');
219
+ },
198
220
  },
199
221
  computed: {
200
222
  requiredField() {
@@ -255,6 +277,10 @@ export default {
255
277
  [$attrs.class]: $attrs.class
256
278
  }"
257
279
  :tabindex="disabled || isView ? -1 : 0"
280
+ role="combobox"
281
+ :aria-expanded="isOpen"
282
+ :aria-label="$attrs['aria-label'] || undefined"
283
+ :aria-describedby="$attrs['aria-describedby'] || undefined"
258
284
  @click="focusSearch"
259
285
  @keydown.enter="focusSearch"
260
286
  @keydown.down.prevent="focusSearch"
@@ -282,15 +308,23 @@ export default {
282
308
  :modelValue="value != null ? value : ''"
283
309
  :dropdownShouldOpen="handleDropdownOpen"
284
310
  :tabindex="-1"
285
- role="listbox"
311
+ role="listitem"
312
+ :uid="generatedUid"
313
+ :aria-label="'-'"
286
314
  @update:modelValue="$emit('update:value', $event)"
287
315
  @search:blur="onBlur"
288
316
  @search:focus="onFocus"
289
- @open="resizeHandler"
317
+ @open="onOpen"
318
+ @close="onClose"
290
319
  @option:created="(e) => $emit('createdListItem', e)"
291
320
  >
292
- <template #option="option">
293
- <div @mousedown="(e) => onClickOption(option, e)">
321
+ <template
322
+ #option="option"
323
+ >
324
+ <div
325
+ :lang="isLangSelect ? option.value : undefined"
326
+ @mousedown="(e) => onClickOption(option, e)"
327
+ >
294
328
  {{ getOptionLabel(option.label) }}
295
329
  </div>
296
330
  </template>
@@ -21,6 +21,10 @@ export default {
21
21
  causes $emit 'input' of ["-c", "sleep 600"]
22
22
  */
23
23
  data() {
24
+ return { userValue: '' };
25
+ },
26
+
27
+ created() {
24
28
  let userValue = '';
25
29
 
26
30
  if ( this.value ) {
@@ -36,7 +40,7 @@ export default {
36
40
  }, '').trim();
37
41
  }
38
42
 
39
- return { userValue };
43
+ this.userValue = userValue;
40
44
  },
41
45
 
42
46
  methods: {