@rancher/shell 3.0.2-rc.4 → 3.0.2-rc.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/images/providers/nutanix.svg +12 -1
- package/assets/styles/base/_basic.scss +2 -1
- package/assets/styles/base/_helpers.scss +4 -0
- package/assets/styles/base/_variables.scss +2 -0
- package/assets/styles/global/_labeled-input.scss +5 -13
- package/assets/styles/global/_layout.scss +1 -0
- package/assets/styles/global/_select.scss +5 -0
- package/assets/styles/themes/_dark.scss +1 -3
- package/assets/styles/themes/_light.scss +5 -1
- package/assets/translations/en-us.yaml +142 -22
- package/assets/translations/zh-hans.yaml +0 -3
- package/cloud-credential/azure.vue +1 -1
- package/components/ActionMenuShell.vue +105 -0
- package/components/AppModal.vue +2 -2
- package/components/AsyncButton.vue +2 -0
- package/components/ButtonGroup.vue +15 -1
- package/components/ButtonMultiAction.vue +5 -1
- package/components/ClusterBadge.vue +1 -0
- package/components/ClusterIconMenu.vue +3 -0
- package/components/ClusterProviderIcon.vue +14 -1
- package/components/CodeMirror.vue +96 -5
- package/components/Collapse.vue +16 -3
- package/components/CopyToClipboardText.vue +3 -1
- package/components/CruResource.vue +9 -0
- package/components/CruResourceFooter.vue +1 -1
- package/components/ExplorerMembers.vue +2 -1
- package/components/ExplorerProjectsNamespaces.vue +7 -0
- package/components/Import.vue +14 -1
- package/components/LandingPagePreference.vue +4 -2
- package/components/PodSecurityAdmission.vue +8 -6
- package/components/PromptChangePassword.vue +1 -0
- package/components/PromptRemove.vue +23 -21
- package/components/ResourceDetail/Masthead.vue +30 -11
- package/components/ResourceDetail/__tests__/Masthead.test.ts +61 -0
- package/components/ResourceDetail/index.vue +6 -0
- package/components/ResourceTable.vue +6 -14
- package/components/ResourceYaml.vue +1 -0
- package/components/SelectIconGrid.vue +2 -0
- package/components/Setting.vue +115 -0
- package/components/SortableTable/THead.vue +2 -0
- package/components/SortableTable/index.vue +38 -14
- package/components/Tabbed/index.vue +16 -15
- package/components/Wizard.vue +108 -104
- package/components/YamlEditor.vue +12 -2
- package/components/__tests__/Collapse.test.ts +2 -2
- package/components/auth/Principal.vue +29 -17
- package/components/auth/__tests__/Principal.test.ts +40 -0
- package/components/auth/login/ldap.vue +7 -0
- package/components/fleet/FleetBundles.vue +1 -1
- package/components/fleet/FleetRepos.vue +1 -1
- package/components/fleet/FleetResources.vue +0 -2
- package/components/fleet/FleetSummary.vue +60 -65
- package/components/fleet/ForceDirectedTreeChart/index.vue +5 -1
- package/components/fleet/__tests__/FleetSummary.test.ts +49 -9
- package/components/form/ArrayList.vue +6 -2
- package/components/form/ColorInput.vue +1 -0
- package/components/form/KeyValue.vue +11 -12
- package/components/form/LabeledSelect.vue +16 -3
- package/components/form/Labels.vue +8 -1
- package/components/form/Members/MembershipEditor.vue +230 -222
- package/components/form/Members/__tests__/MembershipEditor.test.ts +62 -0
- package/components/form/Password.vue +3 -0
- package/components/form/ProjectMemberEditor.vue +6 -3
- package/components/form/ResourceTabs/index.vue +15 -13
- package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +5 -4
- package/components/form/SchedulingCustomization.vue +85 -0
- package/components/form/Select.vue +4 -2
- package/components/form/SelectOrCreateAuthSecret.vue +2 -1
- package/components/form/UnitInput.vue +1 -2
- package/components/form/__tests__/ArrayList.test.ts +9 -6
- package/components/form/__tests__/LabeledSelect.test.ts +37 -0
- package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +34 -0
- package/components/formatter/LiveDate.vue +3 -1
- package/components/formatter/ServiceType.vue +12 -4
- package/components/formatter/WorkloadHealthScale.vue +2 -1
- package/components/nav/Header.vue +35 -2
- package/components/nav/HeaderPageActionMenu.vue +11 -40
- package/components/nav/Jump.vue +8 -2
- package/components/nav/NamespaceFilter.vue +5 -4
- package/components/nav/Pinned.vue +1 -1
- package/components/nav/TopLevelMenu.helper.ts +5 -5
- package/components/nav/WindowManager/ContainerLogs.vue +97 -49
- package/components/nav/WindowManager/ContainerShell.vue +99 -18
- package/components/nav/WindowManager/index.vue +85 -6
- package/components/templates/default.vue +2 -47
- package/config/features.js +1 -0
- package/config/home-links.js +1 -1
- package/config/labels-annotations.js +11 -1
- package/config/router/navigation-guards/index.js +2 -1
- package/config/router/navigation-guards/record-last-route.js +24 -0
- package/config/settings.ts +66 -98
- package/config/version.js +1 -1
- package/core/types-provisioning.ts +7 -0
- package/detail/fleet.cattle.io.bundle.vue +7 -0
- package/detail/fleet.cattle.io.cluster.vue +0 -3
- package/detail/fleet.cattle.io.gitrepo.vue +8 -15
- package/detail/provisioning.cattle.io.cluster.vue +8 -2
- package/dialog/DeactivateDriverDialog.vue +5 -5
- package/dialog/GitRepoForceUpdateDialog.vue +132 -0
- package/directives/strip-html-aria-label.js +19 -0
- package/edit/__tests__/cis.cattle.io.clusterscan.test.ts +87 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +217 -37
- package/edit/auth/__tests__/oidc.test.ts +26 -9
- package/edit/auth/ldap/__tests__/config.test.ts +40 -0
- package/edit/auth/ldap/config.vue +67 -89
- package/edit/auth/oidc.vue +15 -1
- package/edit/catalog.cattle.io.clusterrepo.vue +12 -8
- package/edit/cis.cattle.io.clusterscan.vue +13 -1
- package/edit/fleet.cattle.io.gitrepo.vue +198 -72
- package/edit/logging-flow/Match.vue +0 -21
- package/edit/management.cattle.io.project.vue +1 -1
- package/edit/monitoring.coreos.com.prometheusrule/AlertingRule.vue +10 -3
- package/edit/monitoring.coreos.com.prometheusrule/RecordingRule.vue +5 -1
- package/edit/monitoring.coreos.com.prometheusrule/index.vue +5 -2
- package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +8 -1
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +2 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/CustomCommand.test.ts +55 -15
- package/edit/provisioning.cattle.io.cluster/index.vue +39 -39
- package/edit/provisioning.cattle.io.cluster/rke2.vue +63 -12
- package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +37 -2
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +3 -2
- package/edit/resources.cattle.io.backup.vue +150 -15
- package/edit/secret/__tests__/ssh.test.ts +79 -0
- package/edit/secret/ssh.vue +7 -1
- package/edit/workload/Job.vue +2 -2
- package/edit/workload/index.vue +3 -1
- package/initialize/install-directives.js +2 -0
- package/initialize/install-plugins.js +6 -1
- package/list/catalog.cattle.io.app.vue +21 -4
- package/list/fleet.cattle.io.bundle.vue +1 -1
- package/list/management.cattle.io.setting.vue +34 -129
- package/list/provisioning.cattle.io.cluster.vue +11 -3
- package/machine-config/vmwarevsphere.vue +15 -8
- package/mixins/__tests__/auth-config.test.ts +74 -0
- package/mixins/__tests__/chart.test.ts +5 -4
- package/mixins/__tests__/create-edit-view.test.ts +38 -0
- package/mixins/auth-config.js +9 -1
- package/mixins/chart.js +2 -2
- package/mixins/create-edit-view/impl.js +4 -1
- package/mixins/vue-select-overrides.js +10 -0
- package/models/__tests__/catalog.cattle.io.app.test.ts +148 -0
- package/models/__tests__/fleet.cattle.io.gitrepo.test.ts +157 -0
- package/models/__tests__/secret.test.ts +56 -13
- package/models/catalog.cattle.io.app.js +112 -37
- package/models/cluster.js +11 -0
- package/models/fleet.cattle.io.bundle.js +40 -2
- package/models/fleet.cattle.io.gitrepo.js +169 -109
- package/models/management.cattle.io.fleetworkspace.js +4 -0
- package/models/management.cattle.io.kontainerdriver.js +7 -0
- package/models/nodedriver.js +4 -1
- package/models/provisioning.cattle.io.cluster.js +24 -0
- package/models/secret.js +1 -1
- package/package.json +4 -4
- package/pages/auth/login.vue +4 -2
- package/pages/auth/verify.vue +11 -1
- package/pages/c/_cluster/apps/charts/chart.vue +1 -0
- package/pages/c/_cluster/apps/charts/index.vue +6 -4
- package/pages/c/_cluster/apps/charts/install.vue +1 -1
- package/pages/c/_cluster/explorer/ConfigBadge.vue +3 -5
- package/pages/c/_cluster/explorer/EventsTable.vue +3 -2
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +9 -9
- package/pages/c/_cluster/explorer/index.vue +33 -35
- package/pages/c/_cluster/explorer/tools/index.vue +17 -4
- package/pages/c/_cluster/fleet/index.vue +0 -5
- package/pages/c/_cluster/legacy/project/index.vue +1 -1
- package/pages/c/_cluster/settings/performance.vue +52 -53
- package/pages/c/_cluster/uiplugins/index.vue +21 -22
- package/pages/home.vue +17 -12
- package/pages/prefs.vue +5 -1
- package/plugins/shortkey.js +10 -1
- package/plugins/steve/steve-pagination-utils.ts +58 -8
- package/promptRemove/management.cattle.io.fleetworkspace.vue +98 -0
- package/promptRemove/management.cattle.io.globalrole.vue +1 -1
- package/promptRemove/management.cattle.io.project.vue +2 -8
- package/promptRemove/management.cattle.io.roletemplate.vue +1 -1
- package/promptRemove/mixin/roleDeletionCheck.js +1 -7
- package/promptRemove/pod.vue +7 -28
- package/rancher-components/Card/Card.vue +9 -1
- package/rancher-components/Form/Checkbox/Checkbox.vue +42 -6
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +30 -3
- package/rancher-components/Form/Radio/RadioButton.vue +18 -3
- package/rancher-components/Form/Radio/RadioGroup.vue +39 -5
- package/rancher-components/LabeledTooltip/LabeledTooltip.vue +13 -1
- package/rancher-components/RcButton/RcButton.test.ts +97 -0
- package/rancher-components/RcButton/RcButton.vue +14 -9
- package/rancher-components/RcDropdown/RcDropdown.vue +3 -1
- package/rancher-components/RcDropdown/RcDropdownItem.vue +8 -14
- package/rancher-components/RcDropdown/RcDropdownMenu.vue +66 -0
- package/rancher-components/RcDropdown/index.ts +1 -0
- package/rancher-components/RcDropdown/types.ts +27 -0
- package/rancher-components/RcDropdown/useDropdownContext.ts +5 -2
- package/scripts/typegen.sh +1 -0
- package/store/__tests__/auth.test.ts +120 -0
- package/store/action-menu.js +13 -3
- package/store/auth.js +14 -9
- package/store/catalog.js +14 -7
- package/store/features.js +1 -0
- package/store/prefs.js +9 -28
- package/store/type-map.utils.ts +4 -0
- package/types/resources/settings.d.ts +27 -20
- package/types/shell/index.d.ts +18 -2
- package/utils/__tests__/array.test.ts +13 -1
- package/utils/__tests__/string.test.ts +80 -1
- package/utils/array.ts +13 -0
- package/utils/auth.js +4 -0
- package/utils/cluster.js +1 -1
- package/{edit/monitoring.coreos.com.prometheusrule → utils}/duration.js +5 -3
- package/utils/pagination-utils.ts +15 -2
- package/utils/string.js +31 -7
- package/utils/validators/formRules/__tests__/index.test.ts +27 -0
- package/utils/validators/formRules/index.ts +16 -0
- package/edit/provisioning.cattle.io.cluster/import.vue +0 -198
|
@@ -229,17 +229,17 @@ export default defineComponent({
|
|
|
229
229
|
@update:value="updateLabels()"
|
|
230
230
|
/>
|
|
231
231
|
<p v-else>
|
|
232
|
-
<t
|
|
232
|
+
<t
|
|
233
|
+
:id="`psa-label-for-level-${ level }`"
|
|
234
|
+
:k="`podSecurityAdmission.labels.${level}`"
|
|
235
|
+
/>
|
|
233
236
|
</p>
|
|
234
237
|
</span>
|
|
235
238
|
|
|
236
|
-
<span
|
|
237
|
-
class="
|
|
238
|
-
col
|
|
239
|
-
span-4"
|
|
240
|
-
>
|
|
239
|
+
<span class="col span-4">
|
|
241
240
|
<LabeledSelect
|
|
242
241
|
v-model:value="psaControl.level"
|
|
242
|
+
:aria-labelledby="`psa-label-for-level-${ level }`"
|
|
243
243
|
:data-testid="componentTestid + '--psaControl-' + i + '-level'"
|
|
244
244
|
:disabled="isPsaControlDisabled(psaControl.active)"
|
|
245
245
|
:options="options"
|
|
@@ -256,6 +256,7 @@ export default defineComponent({
|
|
|
256
256
|
:options="options"
|
|
257
257
|
:placeholder="t('podSecurityAdmission.version.placeholder', { psaControl: mode })"
|
|
258
258
|
:mode="mode"
|
|
259
|
+
:aria-label="`${t(`podSecurityAdmission.labels.${level}`)} - ${t('podSecurityAdmission.version.placeholder', { psaControl: mode })}`"
|
|
259
260
|
@update:value="updateLabels()"
|
|
260
261
|
/>
|
|
261
262
|
</span>
|
|
@@ -295,6 +296,7 @@ export default defineComponent({
|
|
|
295
296
|
:options="options"
|
|
296
297
|
:placeholder="t('podSecurityAdmission.exemptions.placeholder', { psaExemptionsControl: dimension })"
|
|
297
298
|
:mode="mode"
|
|
299
|
+
:aria-label="`${t(`podSecurityAdmission.labels.${ dimension }`)} - ${t('podSecurityAdmission.exemptions.placeholder', { psaExemptionsControl: dimension })}`"
|
|
298
300
|
@update:value="updateExemptions()"
|
|
299
301
|
/>
|
|
300
302
|
</span>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script>
|
|
2
|
+
import { shallowRef } from 'vue';
|
|
2
3
|
import { mapState, mapGetters } from 'vuex';
|
|
3
4
|
import { get, isEmpty } from '@shell/utils/object';
|
|
4
5
|
import { escapeHtml, resourceNames } from '@shell/utils/string';
|
|
@@ -38,7 +39,7 @@ export default {
|
|
|
38
39
|
error: '',
|
|
39
40
|
warning: '',
|
|
40
41
|
preventDelete: false,
|
|
41
|
-
removeComponent: this.$store.getters['type-map/importCustomPromptRemove'](resource),
|
|
42
|
+
removeComponent: shallowRef(this.$store.getters['type-map/importCustomPromptRemove'](resource)),
|
|
42
43
|
chartsToRemoveIsApp: false,
|
|
43
44
|
chartsDeleteCrd: false,
|
|
44
45
|
showModal: false,
|
|
@@ -46,7 +47,7 @@ export default {
|
|
|
46
47
|
},
|
|
47
48
|
computed: {
|
|
48
49
|
names() {
|
|
49
|
-
return this.toRemove.map((obj) => obj.nameDisplay)
|
|
50
|
+
return this.toRemove.map((obj) => obj.nameDisplay);
|
|
50
51
|
},
|
|
51
52
|
|
|
52
53
|
nameToMatchPosition() {
|
|
@@ -92,12 +93,6 @@ export default {
|
|
|
92
93
|
return first?.confirmRemove;
|
|
93
94
|
},
|
|
94
95
|
|
|
95
|
-
plusMore() {
|
|
96
|
-
const remaining = this.toRemove.length - this.names.length;
|
|
97
|
-
|
|
98
|
-
return this.t('promptRemove.andOthers', { count: remaining });
|
|
99
|
-
},
|
|
100
|
-
|
|
101
96
|
// if the current route ends with the ID of the resource being deleted, whatever page this is wont be valid after successful deletion: navigate away
|
|
102
97
|
doneLocation() {
|
|
103
98
|
// if deleting more than one resource, this is happening in list view and shouldn't redirect anywhere
|
|
@@ -167,7 +162,7 @@ export default {
|
|
|
167
162
|
if (show) {
|
|
168
163
|
const selected = this.toRemove[0];
|
|
169
164
|
|
|
170
|
-
if (this.currentRouter?.currentRoute?.name === 'c-cluster-explorer-tools' &&
|
|
165
|
+
if (this.currentRouter?.currentRoute?.value?.name === 'c-cluster-explorer-tools' &&
|
|
171
166
|
selected.type === CATALOG.APP &&
|
|
172
167
|
selected.spec?.chart?.metadata?.annotations[CATALOG_ANNOTATIONS.AUTO_INSTALL]) {
|
|
173
168
|
this.chartsToRemoveIsApp = true;
|
|
@@ -183,7 +178,7 @@ export default {
|
|
|
183
178
|
|
|
184
179
|
this.hasCustomRemove = this.$store.getters['type-map/hasCustomPromptRemove'](resource);
|
|
185
180
|
|
|
186
|
-
this.removeComponent = this.$store.getters['type-map/importCustomPromptRemove'](resource);
|
|
181
|
+
this.removeComponent = shallowRef(this.$store.getters['type-map/importCustomPromptRemove'](resource));
|
|
187
182
|
} else {
|
|
188
183
|
this.showModal = false;
|
|
189
184
|
}
|
|
@@ -359,7 +354,7 @@ export default {
|
|
|
359
354
|
<div class="mb-10">
|
|
360
355
|
<template v-if="!hasCustomRemove">
|
|
361
356
|
{{ t('promptRemove.attemptingToRemove', { type }) }} <span
|
|
362
|
-
v-clean-html="resourceNames(names,
|
|
357
|
+
v-clean-html="resourceNames(names, t)"
|
|
363
358
|
/>
|
|
364
359
|
</template>
|
|
365
360
|
|
|
@@ -368,7 +363,7 @@ export default {
|
|
|
368
363
|
v-if="hasCustomRemove"
|
|
369
364
|
ref="customPrompt"
|
|
370
365
|
v-model:value="toRemove"
|
|
371
|
-
v-bind="
|
|
366
|
+
v-bind="$data"
|
|
372
367
|
:close="close"
|
|
373
368
|
:needs-confirm="needsConfirm"
|
|
374
369
|
:value="toRemove"
|
|
@@ -394,6 +389,7 @@ export default {
|
|
|
394
389
|
v-focus
|
|
395
390
|
:data-testid="componentTestid + '-input'"
|
|
396
391
|
type="text"
|
|
392
|
+
:aria-label="t('promptRemove.confirmName', { nameToMatch: escapeHtml(nameToMatch) })"
|
|
397
393
|
>
|
|
398
394
|
<div class="text-warning mb-10 mt-10">
|
|
399
395
|
{{ warning }}
|
|
@@ -407,22 +403,28 @@ export default {
|
|
|
407
403
|
>
|
|
408
404
|
{{ protip }}
|
|
409
405
|
</div>
|
|
410
|
-
<Checkbox
|
|
411
|
-
v-if="chartsToRemoveIsApp"
|
|
412
|
-
v-model:value="chartsDeleteCrd"
|
|
413
|
-
label-key="promptRemoveApp.removeCrd"
|
|
414
|
-
class="mt-10 type"
|
|
415
|
-
@update:value="chartAddCrdToRemove"
|
|
416
|
-
/>
|
|
417
406
|
</LabeledInput>
|
|
418
407
|
<div v-else-if="!hasCustomRemove">
|
|
419
|
-
<div
|
|
408
|
+
<div
|
|
409
|
+
v-if="warning"
|
|
410
|
+
class="text-warning mb-10 mt-10"
|
|
411
|
+
>
|
|
420
412
|
{{ warning }}
|
|
421
413
|
</div>
|
|
422
|
-
<div
|
|
414
|
+
<div
|
|
415
|
+
v-if="error"
|
|
416
|
+
class="text-error mb-10 mt-10"
|
|
417
|
+
>
|
|
423
418
|
{{ error }}
|
|
424
419
|
</div>
|
|
425
420
|
</div>
|
|
421
|
+
<Checkbox
|
|
422
|
+
v-if="chartsToRemoveIsApp"
|
|
423
|
+
v-model:value="chartsDeleteCrd"
|
|
424
|
+
label-key="promptRemoveApp.removeCrd"
|
|
425
|
+
class="mt-10 type"
|
|
426
|
+
@update:value="chartAddCrdToRemove"
|
|
427
|
+
/>
|
|
426
428
|
</template>
|
|
427
429
|
<template #actions>
|
|
428
430
|
<button
|
|
@@ -504,10 +504,32 @@ export default {
|
|
|
504
504
|
{{ namespace }}
|
|
505
505
|
</span>
|
|
506
506
|
</span>
|
|
507
|
-
<span v-if="parent.showAge">
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
507
|
+
<span v-if="parent.showAge">
|
|
508
|
+
{{ t("resourceDetail.masthead.age") }}:
|
|
509
|
+
<LiveDate
|
|
510
|
+
class="live-date"
|
|
511
|
+
:value="value.creationTimestamp"
|
|
512
|
+
/>
|
|
513
|
+
</span>
|
|
514
|
+
<span
|
|
515
|
+
v-if="value.showCreatedBy"
|
|
516
|
+
data-testid="masthead-subheader-createdBy"
|
|
517
|
+
>
|
|
518
|
+
{{ t("resourceDetail.masthead.createdBy") }}:
|
|
519
|
+
<router-link
|
|
520
|
+
v-if="value.createdBy.location"
|
|
521
|
+
:to="value.createdBy.location"
|
|
522
|
+
data-testid="masthead-subheader-createdBy-link"
|
|
523
|
+
>
|
|
524
|
+
{{ value.createdBy.displayName }}
|
|
525
|
+
</router-link>
|
|
526
|
+
<span
|
|
527
|
+
v-else
|
|
528
|
+
data-testid="masthead-subheader-createdBy_plain-text"
|
|
529
|
+
>
|
|
530
|
+
{{ value.createdBy.displayName }}
|
|
531
|
+
</span>
|
|
532
|
+
</span>
|
|
511
533
|
<span v-if="value.showPodRestarts">{{ t("resourceDetail.masthead.restartCount") }}:<span class="live-data"> {{ value.restartCount }}</span></span>
|
|
512
534
|
</div>
|
|
513
535
|
</div>
|
|
@@ -587,11 +609,8 @@ export default {
|
|
|
587
609
|
}
|
|
588
610
|
|
|
589
611
|
HEADER {
|
|
590
|
-
margin: 0
|
|
591
|
-
|
|
592
|
-
.title {
|
|
593
|
-
overflow-x: hidden;
|
|
594
|
-
}
|
|
612
|
+
margin: 0;
|
|
613
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
595
614
|
}
|
|
596
615
|
|
|
597
616
|
.primaryheader {
|
|
@@ -600,14 +619,13 @@ export default {
|
|
|
600
619
|
align-items: center;
|
|
601
620
|
|
|
602
621
|
h1 {
|
|
603
|
-
margin: 0;
|
|
622
|
+
margin: 0 0 0 -5px;
|
|
604
623
|
overflow-x: hidden;
|
|
605
624
|
display: flex;
|
|
606
625
|
flex-direction: row;
|
|
607
626
|
align-items: center;
|
|
608
627
|
|
|
609
628
|
.masthead-resource-title {
|
|
610
|
-
padding: 0 8px;
|
|
611
629
|
text-overflow: ellipsis;
|
|
612
630
|
overflow: hidden;
|
|
613
631
|
white-space: nowrap;
|
|
@@ -638,6 +656,7 @@ export default {
|
|
|
638
656
|
}
|
|
639
657
|
|
|
640
658
|
.masthead-state {
|
|
659
|
+
margin-left: 8px;
|
|
641
660
|
font-size: initial;
|
|
642
661
|
}
|
|
643
662
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { mount, RouterLinkStub } from '@vue/test-utils';
|
|
2
|
+
import { _VIEW } from '@shell/config/query-params';
|
|
3
|
+
import Masthead from '@shell/components/ResourceDetail/Masthead.vue';
|
|
4
|
+
|
|
5
|
+
const mockedStore = () => {
|
|
6
|
+
return {
|
|
7
|
+
getters: {
|
|
8
|
+
currentStore: () => 'current_store',
|
|
9
|
+
currentProduct: { inStore: 'cluster' },
|
|
10
|
+
isExplorer: false,
|
|
11
|
+
currentCluster: {},
|
|
12
|
+
'type-map/labelFor': jest.fn(),
|
|
13
|
+
'type-map/optionsFor': jest.fn(),
|
|
14
|
+
'current_store/schemaFor': jest.fn(),
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const requiredSetup = () => {
|
|
20
|
+
return {
|
|
21
|
+
stubs: {
|
|
22
|
+
'router-link': RouterLinkStub,
|
|
23
|
+
LiveDate: true
|
|
24
|
+
},
|
|
25
|
+
mocks: { $store: mockedStore() }
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
describe('component: Masthead', () => {
|
|
30
|
+
it.each([
|
|
31
|
+
['hidden', '', false, { displayName: 'admin', location: { id: 'resource-id' } }, false, false],
|
|
32
|
+
['plain-text', 'admin', true, { displayName: 'admin', location: null }, false, true],
|
|
33
|
+
['link', 'foo', true, { displayName: 'foo', location: { id: 'resource-id' } }, true, false],
|
|
34
|
+
])('"Created By" should be %p, with text: %p', (
|
|
35
|
+
_,
|
|
36
|
+
text,
|
|
37
|
+
showCreatedBy,
|
|
38
|
+
createdBy,
|
|
39
|
+
showLink,
|
|
40
|
+
showPlainText,
|
|
41
|
+
) => {
|
|
42
|
+
const wrapper = mount(Masthead, {
|
|
43
|
+
props: {
|
|
44
|
+
mode: _VIEW,
|
|
45
|
+
value: {
|
|
46
|
+
showCreatedBy,
|
|
47
|
+
createdBy,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
global: { ...requiredSetup() }
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const container = wrapper.find('[data-testid="masthead-subheader-createdBy"]');
|
|
54
|
+
const link = wrapper.find('[data-testid="masthead-subheader-createdBy-link"]');
|
|
55
|
+
const plainText = wrapper.find('[data-testid="masthead-subheader-createdBy_plain-text"]');
|
|
56
|
+
|
|
57
|
+
expect(link.exists()).toBe(showLink);
|
|
58
|
+
expect(plainText.exists()).toBe(showPlainText);
|
|
59
|
+
expect(showLink || showPlainText ? container.element.textContent : '').toContain(text);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -71,6 +71,11 @@ export default {
|
|
|
71
71
|
default: null,
|
|
72
72
|
},
|
|
73
73
|
|
|
74
|
+
flexContent: {
|
|
75
|
+
type: Boolean,
|
|
76
|
+
default: false,
|
|
77
|
+
},
|
|
78
|
+
|
|
74
79
|
/**
|
|
75
80
|
* Inherited global identifier prefix for tests
|
|
76
81
|
* Define a term based on the parent component to avoid conflicts on multiple components
|
|
@@ -484,6 +489,7 @@ export default {
|
|
|
484
489
|
:initial-value="initialModel"
|
|
485
490
|
:live-value="liveModel"
|
|
486
491
|
:real-mode="realMode"
|
|
492
|
+
:class="{'flex-content': flexContent}"
|
|
487
493
|
@update:value="$emit('input', $event)"
|
|
488
494
|
@set-subtype="setSubtype"
|
|
489
495
|
/>
|
|
@@ -188,20 +188,11 @@ export default {
|
|
|
188
188
|
type: Number,
|
|
189
189
|
default: null, // Default comes from the user preference
|
|
190
190
|
},
|
|
191
|
-
},
|
|
192
|
-
|
|
193
|
-
mounted() {
|
|
194
|
-
/**
|
|
195
|
-
* v-shortkey prevents the event's propagation:
|
|
196
|
-
* https://github.com/fgr-araujo/vue-shortkey/blob/55d802ea305cadcc2ea970b55a3b8b86c7b44c05/src/index.js#L156-L157
|
|
197
|
-
*
|
|
198
|
-
* 'Enter' key press is handled via event listener in order to allow the event propagation
|
|
199
|
-
*/
|
|
200
|
-
window.addEventListener('keyup', this.handleEnterKeyPress);
|
|
201
|
-
},
|
|
202
191
|
|
|
203
|
-
|
|
204
|
-
|
|
192
|
+
hideGroupingControls: {
|
|
193
|
+
type: Boolean,
|
|
194
|
+
default: false
|
|
195
|
+
}
|
|
205
196
|
},
|
|
206
197
|
|
|
207
198
|
data() {
|
|
@@ -602,9 +593,10 @@ export default {
|
|
|
602
593
|
:mandatory-sort="_mandatorySort"
|
|
603
594
|
@clickedActionButton="handleActionButtonClick"
|
|
604
595
|
@group-value-change="group = $event"
|
|
596
|
+
@enter="handleEnterKeyPress"
|
|
605
597
|
>
|
|
606
598
|
<template
|
|
607
|
-
v-if="showGrouping"
|
|
599
|
+
v-if="!hideGroupingControls && showGrouping"
|
|
608
600
|
#header-middle
|
|
609
601
|
>
|
|
610
602
|
<slot name="more-header-middle" />
|
|
@@ -148,10 +148,12 @@ export default {
|
|
|
148
148
|
<i
|
|
149
149
|
v-if="r.iconClass"
|
|
150
150
|
:class="r.iconClass"
|
|
151
|
+
:alt="t('catalog.charts.iconAlt', { app: get(r, nameField) })"
|
|
151
152
|
/>
|
|
152
153
|
<LazyImage
|
|
153
154
|
v-else
|
|
154
155
|
:src="get(r, iconField)"
|
|
156
|
+
:alt="t('catalog.charts.iconAlt', { app: get(r, nameField) })"
|
|
155
157
|
/>
|
|
156
158
|
</div>
|
|
157
159
|
<h4 class="name">
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import ActionMenu from '@shell/components/ActionMenuShell.vue';
|
|
3
|
+
import { mapGetters } from 'vuex';
|
|
4
|
+
export default {
|
|
5
|
+
name: 'Setting',
|
|
6
|
+
components: { ActionMenu },
|
|
7
|
+
props: {
|
|
8
|
+
value: {
|
|
9
|
+
type: Object,
|
|
10
|
+
required: true,
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
computed: {
|
|
14
|
+
...mapGetters({ t: 'i18n/t' }),
|
|
15
|
+
...mapGetters({ options: 'action-menu/optionsArray' }),
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<div
|
|
22
|
+
class="advanced-setting mb-20"
|
|
23
|
+
:data-testid="`advanced-setting__option-${value.id}`"
|
|
24
|
+
>
|
|
25
|
+
<div class="header">
|
|
26
|
+
<div class="title">
|
|
27
|
+
<h1>
|
|
28
|
+
{{ value.id }}
|
|
29
|
+
<span
|
|
30
|
+
v-if="value.fromEnv"
|
|
31
|
+
class="modified"
|
|
32
|
+
>{{ t('advancedSettings.setEnv') }}</span>
|
|
33
|
+
<span
|
|
34
|
+
v-else-if="value.customized"
|
|
35
|
+
class="modified"
|
|
36
|
+
>{{ t('advancedSettings.modified') }}</span>
|
|
37
|
+
</h1>
|
|
38
|
+
<h2>{{ t(`advancedSettings.descriptions.${value.id}`) }}</h2>
|
|
39
|
+
</div>
|
|
40
|
+
<div
|
|
41
|
+
v-if="value.hasActions"
|
|
42
|
+
class="action"
|
|
43
|
+
>
|
|
44
|
+
<action-menu
|
|
45
|
+
:resource="value.data"
|
|
46
|
+
:button-aria-label="t('advancedSettings.edit.label')"
|
|
47
|
+
data-testid="action-button"
|
|
48
|
+
button-role="tertiary"
|
|
49
|
+
/>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
<div value>
|
|
53
|
+
<div v-if="value.canHide">
|
|
54
|
+
<button
|
|
55
|
+
class="btn btn-sm role-primary"
|
|
56
|
+
role="button"
|
|
57
|
+
:aria-label="t('advancedSettings.hideShow')"
|
|
58
|
+
@click="value.hide = !value.hide"
|
|
59
|
+
>
|
|
60
|
+
{{ value.hide ? t('advancedSettings.show') : t('advancedSettings.hide') }} {{ value.id }}
|
|
61
|
+
</button>
|
|
62
|
+
</div>
|
|
63
|
+
<div
|
|
64
|
+
v-show="!value.canHide || (value.canHide && !value.hide)"
|
|
65
|
+
class="settings-value"
|
|
66
|
+
>
|
|
67
|
+
<pre v-if="value.kind === 'json'">{{ value.json }}</pre>
|
|
68
|
+
<pre v-else-if="value.kind === 'multiline'">{{ value.data.value || value.data.default }}</pre>
|
|
69
|
+
<pre v-else-if="value.kind === 'enum'">{{ t(value.enum) }}</pre>
|
|
70
|
+
<pre v-else-if="value.data.value || value.data.default">{{ value.data.value || value.data.default }}</pre>
|
|
71
|
+
<pre
|
|
72
|
+
v-else
|
|
73
|
+
class="text-muted"
|
|
74
|
+
><{{ t('advancedSettings.none') }}></pre>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
</template>
|
|
79
|
+
|
|
80
|
+
<style lang='scss' scoped>
|
|
81
|
+
.settings-value pre {
|
|
82
|
+
margin: 0;
|
|
83
|
+
}
|
|
84
|
+
.advanced-setting {
|
|
85
|
+
border: 1px solid var(--border);
|
|
86
|
+
padding: 20px;
|
|
87
|
+
border-radius: var(--border-radius);
|
|
88
|
+
|
|
89
|
+
h1 {
|
|
90
|
+
font-size: 14px;
|
|
91
|
+
}
|
|
92
|
+
h2 {
|
|
93
|
+
font-size: 12px;
|
|
94
|
+
margin-bottom: 0;
|
|
95
|
+
opacity: 0.8;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.header {
|
|
100
|
+
display: flex;
|
|
101
|
+
margin-bottom: 20px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.title {
|
|
105
|
+
flex: 1;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.modified {
|
|
109
|
+
margin-left: 10px;
|
|
110
|
+
border: 1px solid var(--primary);
|
|
111
|
+
border-radius: 5px;
|
|
112
|
+
padding: 2px 10px;
|
|
113
|
+
font-size: 12px;
|
|
114
|
+
}
|
|
115
|
+
</style>
|
|
@@ -230,6 +230,7 @@ export default {
|
|
|
230
230
|
data-testid="sortable-table_check_select_all"
|
|
231
231
|
:indeterminate="isIndeterminate"
|
|
232
232
|
:disabled="noRows || noResults"
|
|
233
|
+
:alternate-label="t('sortableTable.genericGroupCheckbox')"
|
|
233
234
|
/>
|
|
234
235
|
</th>
|
|
235
236
|
<th
|
|
@@ -269,6 +270,7 @@ export default {
|
|
|
269
270
|
<div
|
|
270
271
|
v-if="col.sort"
|
|
271
272
|
class="sort"
|
|
273
|
+
aria-hidden="true"
|
|
272
274
|
>
|
|
273
275
|
<i
|
|
274
276
|
v-show="hasAdvancedFiltering && !col.isFilter"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { mapGetters } from 'vuex';
|
|
3
|
-
import { defineAsyncComponent } from 'vue';
|
|
3
|
+
import { defineAsyncComponent, useTemplateRef, onMounted, onBeforeUnmount } from 'vue';
|
|
4
4
|
import day from 'dayjs';
|
|
5
5
|
import isEmpty from 'lodash/isEmpty';
|
|
6
6
|
import { dasherize, ucFirst } from '@shell/utils/string';
|
|
@@ -23,6 +23,7 @@ import LabeledSelect from '@shell/components/form/LabeledSelect';
|
|
|
23
23
|
import { getParent } from '@shell/utils/dom';
|
|
24
24
|
import { FORMATTERS } from '@shell/components/SortableTable/sortable-config';
|
|
25
25
|
import ButtonMultiAction from '@shell/components/ButtonMultiAction.vue';
|
|
26
|
+
import ActionMenu from '@shell/components/ActionMenuShell.vue';
|
|
26
27
|
|
|
27
28
|
// Uncomment for table performance debugging
|
|
28
29
|
// import tableDebug from './debug';
|
|
@@ -42,7 +43,14 @@ import ButtonMultiAction from '@shell/components/ButtonMultiAction.vue';
|
|
|
42
43
|
export default {
|
|
43
44
|
name: 'SortableTable',
|
|
44
45
|
|
|
45
|
-
emits: [
|
|
46
|
+
emits: [
|
|
47
|
+
'clickedActionButton',
|
|
48
|
+
'pagination-changed',
|
|
49
|
+
'group-value-change',
|
|
50
|
+
'selection',
|
|
51
|
+
'rowClick',
|
|
52
|
+
'enter',
|
|
53
|
+
],
|
|
46
54
|
|
|
47
55
|
components: {
|
|
48
56
|
THead,
|
|
@@ -51,6 +59,7 @@ export default {
|
|
|
51
59
|
ActionDropdown,
|
|
52
60
|
LabeledSelect,
|
|
53
61
|
ButtonMultiAction,
|
|
62
|
+
ActionMenu,
|
|
54
63
|
},
|
|
55
64
|
mixins: [
|
|
56
65
|
filtering,
|
|
@@ -518,6 +527,23 @@ export default {
|
|
|
518
527
|
immediate: true
|
|
519
528
|
},
|
|
520
529
|
},
|
|
530
|
+
setup(_props, { emit }) {
|
|
531
|
+
const table = useTemplateRef('table');
|
|
532
|
+
|
|
533
|
+
const handleEnterKey = (event) => {
|
|
534
|
+
if (event.key === 'Enter' && !event.target?.classList?.contains('checkbox-custom')) {
|
|
535
|
+
emit('enter', event);
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
onMounted(() => {
|
|
540
|
+
table.value.addEventListener('keyup', handleEnterKey);
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
onBeforeUnmount(() => {
|
|
544
|
+
table.value.removeEventListener('keyup', handleEnterKey);
|
|
545
|
+
});
|
|
546
|
+
},
|
|
521
547
|
|
|
522
548
|
created() {
|
|
523
549
|
this.debouncedRefreshTableData = debounce(this.refreshTableData, 500);
|
|
@@ -1056,6 +1082,7 @@ export default {
|
|
|
1056
1082
|
:disabled="!act.enabled"
|
|
1057
1083
|
:data-testid="componentTestid + '-' + act.action"
|
|
1058
1084
|
@click="applyTableAction(act, null, $event)"
|
|
1085
|
+
@keydown.enter.stop
|
|
1059
1086
|
@mouseover="setBulkActionOfInterest(act)"
|
|
1060
1087
|
@mouseleave="setBulkActionOfInterest(null)"
|
|
1061
1088
|
>
|
|
@@ -1221,6 +1248,7 @@ export default {
|
|
|
1221
1248
|
</div>
|
|
1222
1249
|
</div>
|
|
1223
1250
|
<table
|
|
1251
|
+
ref="table"
|
|
1224
1252
|
class="sortable-table"
|
|
1225
1253
|
:class="classObject"
|
|
1226
1254
|
width="100%"
|
|
@@ -1299,6 +1327,7 @@ export default {
|
|
|
1299
1327
|
v-for="(groupedRows) in displayRows"
|
|
1300
1328
|
v-else
|
|
1301
1329
|
:key="groupedRows.key"
|
|
1330
|
+
tabindex="-1"
|
|
1302
1331
|
:class="{ group: groupBy }"
|
|
1303
1332
|
>
|
|
1304
1333
|
<slot
|
|
@@ -1350,11 +1379,13 @@ export default {
|
|
|
1350
1379
|
class="row-check"
|
|
1351
1380
|
align="middle"
|
|
1352
1381
|
>
|
|
1353
|
-
{{ row.mainRowKey }}
|
|
1382
|
+
{{ row.mainRowKey }}
|
|
1383
|
+
<Checkbox
|
|
1354
1384
|
class="selection-checkbox"
|
|
1355
1385
|
:data-node-id="row.key"
|
|
1356
1386
|
:data-testid="componentTestid + '-' + i + '-checkbox'"
|
|
1357
1387
|
:value="selectedRows.includes(row.row)"
|
|
1388
|
+
:alternate-label="t('sortableTable.genericRowCheckbox', { item: row && row.row ? row.row.id : '' })"
|
|
1358
1389
|
/>
|
|
1359
1390
|
</td>
|
|
1360
1391
|
<td
|
|
@@ -1440,22 +1471,16 @@ export default {
|
|
|
1440
1471
|
</template>
|
|
1441
1472
|
<td
|
|
1442
1473
|
v-if="rowActions"
|
|
1443
|
-
align="middle"
|
|
1444
1474
|
>
|
|
1445
1475
|
<slot
|
|
1446
1476
|
name="row-actions"
|
|
1447
1477
|
:row="row.row"
|
|
1478
|
+
:index="i"
|
|
1448
1479
|
>
|
|
1449
|
-
<
|
|
1450
|
-
:
|
|
1451
|
-
:ref="`actionButton${i}`"
|
|
1452
|
-
aria-haspopup="true"
|
|
1453
|
-
aria-expanded="false"
|
|
1480
|
+
<ActionMenu
|
|
1481
|
+
:resource="row.row"
|
|
1454
1482
|
:data-testid="componentTestid + '-' + i + '-action-button'"
|
|
1455
|
-
:
|
|
1456
|
-
@click="handleActionButtonClick(i, $event)"
|
|
1457
|
-
@keyup.enter="handleActionButtonClick(i, $event)"
|
|
1458
|
-
@keyup.space="handleActionButtonClick(i, $event)"
|
|
1483
|
+
:button-aria-label="t('sortableTable.tableActionsLabel', { resource: row?.row?.id || '' })"
|
|
1459
1484
|
/>
|
|
1460
1485
|
</slot>
|
|
1461
1486
|
</td>
|
|
@@ -1753,7 +1778,6 @@ export default {
|
|
|
1753
1778
|
min-width: 400px;
|
|
1754
1779
|
border-radius: 5px 5px 0 0;
|
|
1755
1780
|
outline: 1px solid var(--border);
|
|
1756
|
-
overflow: hidden;
|
|
1757
1781
|
background: var(--sortable-table-bg);
|
|
1758
1782
|
border-radius: 4px;
|
|
1759
1783
|
|