@rancher/shell 3.0.2-rc.3 → 3.0.2-rc.5
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/styles/base/_basic.scss +2 -1
- package/assets/styles/global/_form.scss +2 -1
- package/assets/styles/themes/_dark.scss +1 -1
- package/assets/translations/en-us.yaml +35 -4
- package/assets/translations/zh-hans.yaml +2 -3
- package/components/AppModal.vue +50 -0
- package/components/ButtonGroup.vue +8 -1
- package/components/ButtonMultiAction.vue +5 -1
- package/components/Carousel.vue +54 -47
- package/components/CopyToClipboardText.vue +6 -1
- package/components/Dialog.vue +20 -1
- package/components/ExplorerProjectsNamespaces.vue +7 -0
- package/components/PromptChangePassword.vue +3 -0
- package/components/ResourceDetail/Masthead.vue +1 -1
- package/components/ResourceTable.vue +1 -14
- package/components/SelectIconGrid.vue +2 -0
- package/components/SortableTable/index.vue +32 -3
- package/components/Tabbed/index.vue +4 -7
- package/components/__tests__/Carousel.test.ts +56 -27
- package/components/form/LabeledSelect.vue +2 -1
- package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +192 -0
- package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +104 -0
- package/components/form/SSHKnownHosts/index.vue +101 -0
- package/components/form/Select.vue +2 -1
- package/components/form/SelectOrCreateAuthSecret.vue +43 -11
- package/components/form/__tests__/SSHKnownHosts.test.ts +59 -0
- package/components/nav/WindowManager/ContainerLogs.vue +13 -3
- package/components/nav/WindowManager/index.vue +14 -3
- package/composables/focusTrap.ts +68 -0
- package/config/home-links.js +1 -1
- package/detail/secret.vue +25 -0
- package/edit/fleet.cattle.io.gitrepo.vue +27 -22
- package/edit/provisioning.cattle.io.cluster/index.vue +18 -9
- package/edit/secret/index.vue +1 -1
- package/edit/secret/ssh.vue +21 -3
- package/list/management.cattle.io.setting.vue +5 -2
- package/list/provisioning.cattle.io.cluster.vue +1 -0
- package/mixins/auth-config.js +1 -1
- package/models/fleet.cattle.io.gitrepo.js +2 -2
- package/models/provisioning.cattle.io.cluster.js +2 -12
- package/models/secret.js +5 -0
- package/package.json +1 -1
- package/pages/account/index.vue +4 -0
- package/pages/c/_cluster/apps/charts/chart.vue +1 -0
- package/pages/c/_cluster/explorer/ConfigBadge.vue +5 -4
- package/pages/c/_cluster/explorer/tools/index.vue +14 -1
- package/pages/c/_cluster/uiplugins/AddExtensionRepos.vue +3 -1
- package/pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue +3 -0
- package/pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue +7 -1
- package/pages/c/_cluster/uiplugins/CatalogList/index.vue +3 -1
- package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +10 -7
- package/pages/c/_cluster/uiplugins/InstallDialog.vue +7 -0
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +181 -106
- package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +2 -0
- package/pages/c/_cluster/uiplugins/UninstallDialog.vue +9 -1
- package/pages/c/_cluster/uiplugins/index.vue +52 -12
- package/rancher-components/Card/Card.vue +7 -21
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +1 -0
- package/rancher-components/RcDropdown/RcDropdown.vue +11 -0
- package/rancher-components/RcDropdown/RcDropdownItem.vue +0 -12
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +2 -3
- package/rancher-components/RcDropdown/useDropdownCollection.ts +1 -0
- package/rancher-components/RcDropdown/useDropdownContext.ts +28 -1
|
@@ -61,13 +61,13 @@ BODY {
|
|
|
61
61
|
INPUT,
|
|
62
62
|
SELECT,
|
|
63
63
|
TEXTAREA,
|
|
64
|
-
.labeled-input,
|
|
65
64
|
.checkbox-custom {
|
|
66
65
|
&:focus, &.focused {
|
|
67
66
|
@include form-focus;
|
|
68
67
|
}
|
|
69
68
|
}
|
|
70
69
|
|
|
70
|
+
.labeled-input,
|
|
71
71
|
.radio-custom,
|
|
72
72
|
.labeled-select,
|
|
73
73
|
.unlabeled-select {
|
|
@@ -76,6 +76,7 @@ TEXTAREA,
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
.labeled-input,
|
|
79
80
|
.labeled-select,
|
|
80
81
|
.unlabeled-select {
|
|
81
82
|
&.focused {
|
|
@@ -27,7 +27,8 @@ TEXTAREA,
|
|
|
27
27
|
|
|
28
28
|
@include input-status-color;
|
|
29
29
|
|
|
30
|
-
&:focus:not(.
|
|
30
|
+
&:focus:not(.labeled-input):not(.unlabeled-select):not(.labeled-select),
|
|
31
|
+
&.focused:not(.labeled-input):not(.unlabeled-select):not(.labeled-select) {
|
|
31
32
|
@include form-focus;
|
|
32
33
|
}
|
|
33
34
|
|
|
@@ -16,6 +16,8 @@ generic:
|
|
|
16
16
|
comingSoon: Coming Soon
|
|
17
17
|
comma: ', '
|
|
18
18
|
copy: Copy
|
|
19
|
+
copyToClipboard: Copy text to Clipboard
|
|
20
|
+
copiedToClipboard: Text copied to Clipboard
|
|
19
21
|
create: Create
|
|
20
22
|
created: Created
|
|
21
23
|
customize: Customize
|
|
@@ -949,6 +951,7 @@ catalog:
|
|
|
949
951
|
experimentalWarning: '{chartName} has been marked as experimental. Use caution when installing this helm chart as it might not function as expected.'
|
|
950
952
|
deprecatedAndExperimentalWarning: '{chartName} has been marked as deprecated and experimental. Use caution when installing this helm chart as it might be removed in the future and might not function as expected.'
|
|
951
953
|
charts:
|
|
954
|
+
iconAlt: Icon for {app} card/grid item
|
|
952
955
|
refresh: refresh charts
|
|
953
956
|
all: All
|
|
954
957
|
categories:
|
|
@@ -1132,6 +1135,7 @@ catalog:
|
|
|
1132
1135
|
label: Refresh Interval
|
|
1133
1136
|
placeholder: 'default: {hours}'
|
|
1134
1137
|
tools:
|
|
1138
|
+
iconAlt: Icon for {app} Cluster Tool
|
|
1135
1139
|
header: Cluster Tools
|
|
1136
1140
|
noTools: "No Cluster Tools found"
|
|
1137
1141
|
action:
|
|
@@ -2440,6 +2444,7 @@ fleet:
|
|
|
2440
2444
|
resources: Resources
|
|
2441
2445
|
unready: Non-Ready
|
|
2442
2446
|
auth:
|
|
2447
|
+
title: Authentication
|
|
2443
2448
|
label: Authentication
|
|
2444
2449
|
git: Git Authentication
|
|
2445
2450
|
helm: Helm Authentication
|
|
@@ -2450,20 +2455,20 @@ fleet:
|
|
|
2450
2455
|
label: Paths
|
|
2451
2456
|
placeholder: e.g. /directory/in/your/repo
|
|
2452
2457
|
addLabel: Add Path
|
|
2453
|
-
empty: The root of the repo is used by default.
|
|
2458
|
+
empty: The root of the repo is used by default. Multiple different directories can be provided.
|
|
2454
2459
|
repo:
|
|
2460
|
+
title: Source
|
|
2455
2461
|
label: Repository URL
|
|
2456
2462
|
placeholder: e.g. https://github.com/rancher/fleet-examples.git or git@github.com:rancher/fleet-examples.git
|
|
2457
2463
|
addRepo: Add Repository
|
|
2458
2464
|
noRepos: No repositories have been added
|
|
2459
2465
|
noWorkspaces: There are no workspaces. <br/> Please create a workspace before adding repositories
|
|
2460
|
-
protocolBanner: Enter a valid HTTPS or SSH URL to a git repository.
|
|
2461
2466
|
resources:
|
|
2462
2467
|
label: 'Resource Handling'
|
|
2463
2468
|
keepResources: Always Keep Resources
|
|
2464
|
-
|
|
2469
|
+
keepResourcesTooltip: When enabled, resources will be kept when deleting a GitRepo or Bundle - only Helm release secrets will be deleted.
|
|
2465
2470
|
correctDrift: Enable Self-Healing
|
|
2466
|
-
|
|
2471
|
+
correctDriftTooltip: When enabled, Fleet will ensure that the cluster resources are kept in sync with the git repository. All resource changes made on the cluster will be lost.
|
|
2467
2472
|
add:
|
|
2468
2473
|
steps:
|
|
2469
2474
|
repoInfo:
|
|
@@ -4374,12 +4379,15 @@ inactivity:
|
|
|
4374
4379
|
|
|
4375
4380
|
# Rancher Extensions
|
|
4376
4381
|
plugins:
|
|
4382
|
+
altIcon: Icon for {extension} extension card
|
|
4377
4383
|
incompatibleRancherVersion: "The latest version of this extension ({ version }) is not compatible with the current Rancher version ({ required })."
|
|
4378
4384
|
incompatibleKubeVersion: "The latest version of this extension ({ version }) is not compatible with the current Kube version ({ required })."
|
|
4379
4385
|
incompatibleUiExtensionsApiVersionMissing: 'The latest version of this extension ({ version }) is missing the mandatory annotation catalog.cattle.io/ui-extensions-version from Rancher 2.10 and onwards.'
|
|
4380
4386
|
incompatibleUiExtensionsApiVersion: "The latest version of this extension ({ version }) is not compatible with the current Extensions API version ({ required })."
|
|
4381
4387
|
incompatibleHost: 'The latest version of this extension ({ version }) has a host of "{ required }" which is not compatible with this application "{ mainHost }".'
|
|
4382
4388
|
currentInstalledVersionBlockedByKubeVersion: "This version is not compatible with the current Kubernetes version ({ kubeVersion } Vs { kubeVersionToCheck })."
|
|
4389
|
+
closePluginPanel: Close plugin description panel
|
|
4390
|
+
viewVersionDetails: View extension {name} version {version} details/Readme
|
|
4383
4391
|
labels:
|
|
4384
4392
|
builtin: Built-in
|
|
4385
4393
|
experimental: Experimental
|
|
@@ -4387,6 +4395,8 @@ plugins:
|
|
|
4387
4395
|
image: Image
|
|
4388
4396
|
installing: Installing ...
|
|
4389
4397
|
uninstalling: Uninstalling ...
|
|
4398
|
+
menu: Extensions menu
|
|
4399
|
+
reloadRancher: Reload Rancher
|
|
4390
4400
|
descriptions:
|
|
4391
4401
|
experimental: This Extension is marked as experimental
|
|
4392
4402
|
third-party: This Extension is provided by a Third-Party
|
|
@@ -4705,6 +4715,7 @@ projectMembers:
|
|
|
4705
4715
|
workloadsView: View Workloads
|
|
4706
4716
|
|
|
4707
4717
|
projectNamespaces:
|
|
4718
|
+
tableActionsLabel: More actions for project { resource }
|
|
4708
4719
|
createNamespace: Create Namespace
|
|
4709
4720
|
createProject: Create Project
|
|
4710
4721
|
label: Projects/Namespaces
|
|
@@ -5139,10 +5150,22 @@ secret:
|
|
|
5139
5150
|
username: Username
|
|
5140
5151
|
ssh:
|
|
5141
5152
|
keys: Keys
|
|
5153
|
+
keysAndHosts: Keys and Known Hosts
|
|
5142
5154
|
public: Public Key
|
|
5143
5155
|
publicPlaceholder: "Paste in your public key"
|
|
5144
5156
|
private: Private Key
|
|
5145
5157
|
privatePlaceholder: "Paste in your private key"
|
|
5158
|
+
knownHosts: Known Hosts
|
|
5159
|
+
knownHostsPlaceholder: "Known hosts metadata, one per line"
|
|
5160
|
+
editKnownHosts:
|
|
5161
|
+
title: SSH Known Hosts Configuration
|
|
5162
|
+
entries: |-
|
|
5163
|
+
{entries, plural,
|
|
5164
|
+
=0 {Empty}
|
|
5165
|
+
=1 {1 Entry}
|
|
5166
|
+
other {{entries} Entries}
|
|
5167
|
+
}
|
|
5168
|
+
|
|
5146
5169
|
serviceAcct:
|
|
5147
5170
|
ca: CA Certificate
|
|
5148
5171
|
token: Token
|
|
@@ -5368,6 +5391,8 @@ setup:
|
|
|
5368
5391
|
welcome: Welcome to {vendor}!
|
|
5369
5392
|
|
|
5370
5393
|
sortableTable:
|
|
5394
|
+
tableActionsLabel: More actions - { resource }
|
|
5395
|
+
tableActionsImgAlt: More actions icon
|
|
5371
5396
|
bulkActions:
|
|
5372
5397
|
collapsed:
|
|
5373
5398
|
label: Actions
|
|
@@ -6182,6 +6207,8 @@ wm:
|
|
|
6182
6207
|
disconnected: Disconnected
|
|
6183
6208
|
error: Error
|
|
6184
6209
|
containerLogs:
|
|
6210
|
+
options: Additional container logs options
|
|
6211
|
+
expand: Expand additional container logs options
|
|
6185
6212
|
clear: Clear
|
|
6186
6213
|
containerName: "Container: {label}"
|
|
6187
6214
|
download: Download
|
|
@@ -6208,6 +6235,9 @@ wm:
|
|
|
6208
6235
|
timestamps: Show Timestamps
|
|
6209
6236
|
wrap: Wrap Lines
|
|
6210
6237
|
containerShell:
|
|
6238
|
+
resizeShellWindow: Resize Shell window
|
|
6239
|
+
tabIcon: Shell tab icon
|
|
6240
|
+
closeShellTab: Close Shell tab - {tab}
|
|
6211
6241
|
clear: Clear
|
|
6212
6242
|
containerName: "Container: {label}"
|
|
6213
6243
|
failed: "Unable to open a shell to the container (none of the shell commands succeeded)\n\r"
|
|
@@ -7480,6 +7510,7 @@ advancedSettings:
|
|
|
7480
7510
|
none: None
|
|
7481
7511
|
modified: Modified
|
|
7482
7512
|
edit:
|
|
7513
|
+
moreActions: More actions for setting - { setting }
|
|
7483
7514
|
label: Edit Setting
|
|
7484
7515
|
changeSetting: "Change Setting:"
|
|
7485
7516
|
trueOption: "True"
|
|
@@ -2153,13 +2153,12 @@ fleet:
|
|
|
2153
2153
|
addRepo: 添加仓库
|
|
2154
2154
|
noRepos: 未添加任何仓库
|
|
2155
2155
|
noWorkspaces: 没有工作空间。<br/>请在添加仓库之前创建一个工作空间
|
|
2156
|
-
protocolBanner: 输入指向 git 仓库的有效 HTTPS 或 SSH URL。
|
|
2157
2156
|
resources:
|
|
2158
2157
|
label: '资源处理'
|
|
2159
2158
|
keepResources: 永远保留资源
|
|
2160
|
-
|
|
2159
|
+
keepResourcesTooltip: 启用时,删除 GitRepo 或 Bundle 后将保留资源,只会删除 Helm Release Secret。
|
|
2161
2160
|
correctDrift: 启用自我修复
|
|
2162
|
-
|
|
2161
|
+
correctDriftTooltip: 启用后,Fleet 将确保集群资源与 Git 仓库保持同步。在 ecluster 上进行的所有资源更改都将丢失。
|
|
2163
2162
|
add:
|
|
2164
2163
|
steps:
|
|
2165
2164
|
repoInfo:
|
package/components/AppModal.vue
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { defineComponent } from 'vue';
|
|
3
|
+
import { DEFAULT_FOCUS_TRAP_OPTS, useBasicSetupFocusTrap, getFirstFocusableElement } from '@shell/composables/focusTrap';
|
|
4
|
+
|
|
5
|
+
export const DEFAULT_ITERABLE_NODE_SELECTOR = 'body;';
|
|
3
6
|
|
|
4
7
|
export default defineComponent({
|
|
5
8
|
name: 'AppModal',
|
|
@@ -56,6 +59,27 @@ export default defineComponent({
|
|
|
56
59
|
name: {
|
|
57
60
|
type: String,
|
|
58
61
|
default: '',
|
|
62
|
+
},
|
|
63
|
+
/**
|
|
64
|
+
* trigger focus trap
|
|
65
|
+
*/
|
|
66
|
+
triggerFocusTrap: {
|
|
67
|
+
type: Boolean,
|
|
68
|
+
default: false,
|
|
69
|
+
},
|
|
70
|
+
/**
|
|
71
|
+
* forcefully set return focus element based on this selector
|
|
72
|
+
*/
|
|
73
|
+
returnFocusSelector: {
|
|
74
|
+
type: String,
|
|
75
|
+
default: '',
|
|
76
|
+
},
|
|
77
|
+
/**
|
|
78
|
+
* will return focus to the first iterable node of this container select
|
|
79
|
+
*/
|
|
80
|
+
returnFocusFirstIterableNodeSelector: {
|
|
81
|
+
type: String,
|
|
82
|
+
default: DEFAULT_ITERABLE_NODE_SELECTOR,
|
|
59
83
|
}
|
|
60
84
|
},
|
|
61
85
|
computed: {
|
|
@@ -85,6 +109,31 @@ export default defineComponent({
|
|
|
85
109
|
};
|
|
86
110
|
}
|
|
87
111
|
},
|
|
112
|
+
setup(props) {
|
|
113
|
+
if (props.triggerFocusTrap) {
|
|
114
|
+
let opts:any = DEFAULT_FOCUS_TRAP_OPTS;
|
|
115
|
+
|
|
116
|
+
// if we have a "returnFocusFirstIterableNodeSelector" on top of "returnFocusSelector"
|
|
117
|
+
// then we will use "returnFocusFirstIterableNodeSelector" as a fallback of "returnFocusSelector"
|
|
118
|
+
if (props.returnFocusFirstIterableNodeSelector && props.returnFocusFirstIterableNodeSelector !== DEFAULT_ITERABLE_NODE_SELECTOR && props.returnFocusSelector) {
|
|
119
|
+
opts = {
|
|
120
|
+
...DEFAULT_FOCUS_TRAP_OPTS,
|
|
121
|
+
setReturnFocus: () => {
|
|
122
|
+
return document.querySelector(props.returnFocusSelector) ? props.returnFocusSelector : getFirstFocusableElement(document.querySelector(props.returnFocusFirstIterableNodeSelector));
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
// otherwise, if we are sure of permanent existance of "returnFocusSelector"
|
|
126
|
+
// we just return to that element
|
|
127
|
+
} else if (props.returnFocusSelector) {
|
|
128
|
+
opts = {
|
|
129
|
+
...DEFAULT_FOCUS_TRAP_OPTS,
|
|
130
|
+
setReturnFocus: props.returnFocusSelector
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
useBasicSetupFocusTrap('#modal-container-element', opts);
|
|
135
|
+
}
|
|
136
|
+
},
|
|
88
137
|
mounted() {
|
|
89
138
|
document.addEventListener('keydown', this.handleEscapeKey);
|
|
90
139
|
},
|
|
@@ -134,6 +183,7 @@ export default defineComponent({
|
|
|
134
183
|
>
|
|
135
184
|
<div
|
|
136
185
|
v-bind="$attrs"
|
|
186
|
+
id="modal-container-element"
|
|
137
187
|
ref="modalRef"
|
|
138
188
|
:class="customClass"
|
|
139
189
|
class="modal-container"
|
|
@@ -64,6 +64,12 @@ export default {
|
|
|
64
64
|
methods: {
|
|
65
65
|
change(value) {
|
|
66
66
|
this.$emit('update:value', value);
|
|
67
|
+
},
|
|
68
|
+
actionDescription(opt) {
|
|
69
|
+
const tooltip = opt.tooltipKey ? this.t(opt.tooltipKey) : opt.tooltip;
|
|
70
|
+
const label = opt.labelKey ? this.t(opt.labelKey) : opt.label;
|
|
71
|
+
|
|
72
|
+
return tooltip || label || '';
|
|
67
73
|
}
|
|
68
74
|
}
|
|
69
75
|
};
|
|
@@ -83,7 +89,7 @@ export default {
|
|
|
83
89
|
:class="opt.class"
|
|
84
90
|
:disabled="disabled || opt.disabled"
|
|
85
91
|
role="button"
|
|
86
|
-
:aria-label="
|
|
92
|
+
:aria-label="actionDescription(opt)"
|
|
87
93
|
@click="change(opt.value)"
|
|
88
94
|
>
|
|
89
95
|
<slot
|
|
@@ -94,6 +100,7 @@ export default {
|
|
|
94
100
|
<i
|
|
95
101
|
v-if="opt.icon"
|
|
96
102
|
:class="{icon: true, [opt.icon]: true, [`icon-${iconSize}`]: !!iconSize }"
|
|
103
|
+
:alt="actionDescription(opt)"
|
|
97
104
|
/>
|
|
98
105
|
<t
|
|
99
106
|
v-if="opt.labelKey"
|
|
@@ -22,10 +22,14 @@ const buttonClass = computed(() => {
|
|
|
22
22
|
<button
|
|
23
23
|
type="button"
|
|
24
24
|
class="btn btn-sm role-multi-action actions"
|
|
25
|
+
role="button"
|
|
25
26
|
:class="buttonClass"
|
|
26
27
|
@click="(e: Event) => $emit('click', e)"
|
|
27
28
|
>
|
|
28
|
-
<i
|
|
29
|
+
<i
|
|
30
|
+
class="icon icon-actions"
|
|
31
|
+
:alt="t('sortableTable.tableActionsImgAlt')"
|
|
32
|
+
/>
|
|
29
33
|
</button>
|
|
30
34
|
</template>
|
|
31
35
|
|
package/components/Carousel.vue
CHANGED
|
@@ -43,24 +43,29 @@ export default {
|
|
|
43
43
|
activeItemId: 0,
|
|
44
44
|
autoScroll: true,
|
|
45
45
|
autoScrollSlideInterval: null,
|
|
46
|
+
isTransitionning: false, // prevents showing empty spaces caused by aggressive clicking
|
|
47
|
+
shouldDisableTransition: false // smoothes the move from the first/last slides to the previous/next slide
|
|
46
48
|
};
|
|
47
49
|
},
|
|
48
50
|
|
|
49
51
|
computed: {
|
|
50
52
|
...mapGetters(['clusterId']),
|
|
51
53
|
trackStyle() {
|
|
52
|
-
let sliderItem = ( this.activeItemId + 1) * 100 / (this.slider.length + 2);
|
|
53
|
-
const width = 60 * (this.slider.length + 2);
|
|
54
|
-
|
|
55
54
|
if (this.slider.length === 1) {
|
|
56
|
-
|
|
55
|
+
return `
|
|
56
|
+
width: 100%;
|
|
57
|
+
left: 0%;
|
|
58
|
+
`;
|
|
57
59
|
}
|
|
58
60
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
const width = 60 * (this.slider.length + 2);
|
|
62
|
+
const left = -(40 + this.activeItemId * 60);
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
return `
|
|
65
|
+
width: ${ width }%;
|
|
66
|
+
left: ${ left }%;
|
|
67
|
+
transition: ${ this.shouldDisableTransition ? 'none' : '700ms ease-in-out' };
|
|
68
|
+
`;
|
|
64
69
|
}
|
|
65
70
|
},
|
|
66
71
|
|
|
@@ -77,10 +82,14 @@ export default {
|
|
|
77
82
|
},
|
|
78
83
|
|
|
79
84
|
nextPrev(direction) {
|
|
80
|
-
this.
|
|
81
|
-
|
|
85
|
+
if (this.isTransitionning) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
82
88
|
|
|
83
|
-
|
|
89
|
+
this.isTransitionning = true;
|
|
90
|
+
this.autoScroll = false;
|
|
91
|
+
this.shouldDisableTransition = false;
|
|
92
|
+
const slideTrack = this.$refs.slider;
|
|
84
93
|
|
|
85
94
|
direction !== 'prev' ? (this.activeItemId++) : (this.activeItemId--);
|
|
86
95
|
|
|
@@ -88,21 +97,27 @@ export default {
|
|
|
88
97
|
},
|
|
89
98
|
|
|
90
99
|
slideTransition() {
|
|
91
|
-
const slideTrack = document.getElementById('slide-track');
|
|
92
100
|
const slidesArray = this.slider.length + 2;
|
|
93
101
|
|
|
94
102
|
if (this.activeItemId === -1) {
|
|
95
|
-
|
|
103
|
+
this.shouldDisableTransition = true;
|
|
96
104
|
this.activeItemId = this.slider.length - 1;
|
|
97
105
|
}
|
|
106
|
+
|
|
98
107
|
if (this.activeItemId === slidesArray - 2) {
|
|
99
|
-
|
|
108
|
+
this.shouldDisableTransition = true;
|
|
100
109
|
this.activeItemId = 0;
|
|
101
110
|
}
|
|
111
|
+
|
|
112
|
+
this.isTransitionning = false;
|
|
102
113
|
},
|
|
103
114
|
|
|
104
115
|
autoScrollSlide() {
|
|
105
|
-
if (this.
|
|
116
|
+
if (!this.autoScroll) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (this.activeItemId < (this.slider.length + 1)) {
|
|
106
121
|
this.activeItemId++;
|
|
107
122
|
}
|
|
108
123
|
|
|
@@ -120,23 +135,21 @@ export default {
|
|
|
120
135
|
},
|
|
121
136
|
|
|
122
137
|
mounted() {
|
|
123
|
-
const slideTrack =
|
|
138
|
+
const slideTrack = this.$refs.slider;
|
|
124
139
|
|
|
125
|
-
if (this.slider.length
|
|
126
|
-
|
|
127
|
-
} else {
|
|
128
|
-
const node = document.getElementById('slide0');
|
|
140
|
+
if (this.slider.length > 1) {
|
|
141
|
+
const firstSlide = this.$refs['slide0']?.[0];
|
|
129
142
|
|
|
130
|
-
if (
|
|
131
|
-
const clone =
|
|
143
|
+
if (firstSlide) {
|
|
144
|
+
const clone = firstSlide.cloneNode(true);
|
|
132
145
|
|
|
133
146
|
slideTrack.appendChild(clone);
|
|
134
147
|
}
|
|
135
148
|
|
|
136
|
-
const
|
|
149
|
+
const lastSlide = this.$refs[`slide${ this.slider.length - 1 }`]?.[0];
|
|
137
150
|
|
|
138
|
-
if (
|
|
139
|
-
const cloneLast =
|
|
151
|
+
if (lastSlide) {
|
|
152
|
+
const cloneLast = lastSlide.cloneNode(true);
|
|
140
153
|
|
|
141
154
|
slideTrack.insertBefore(cloneLast, slideTrack.children[0]);
|
|
142
155
|
}
|
|
@@ -159,7 +172,7 @@ export default {
|
|
|
159
172
|
<template>
|
|
160
173
|
<div
|
|
161
174
|
class="slider"
|
|
162
|
-
:class="{'
|
|
175
|
+
:class="{'disabled': sliders.length === 1}"
|
|
163
176
|
>
|
|
164
177
|
<div
|
|
165
178
|
id="slide-track"
|
|
@@ -170,8 +183,8 @@ export default {
|
|
|
170
183
|
<component
|
|
171
184
|
:is="asLink ? 'a' : 'div'"
|
|
172
185
|
v-for="(slide, i) in sliders"
|
|
173
|
-
:id="`slide`
|
|
174
|
-
ref="slide"
|
|
186
|
+
:id="`slide${i}`"
|
|
187
|
+
:ref="`slide${i}`"
|
|
175
188
|
:key="get(slide, keyField)"
|
|
176
189
|
class="slide"
|
|
177
190
|
:class="{'singleSlide': sliders.length === 1}"
|
|
@@ -187,7 +200,7 @@ export default {
|
|
|
187
200
|
<div class="slide-content-right">
|
|
188
201
|
<BadgeState
|
|
189
202
|
:label="slide.repoName"
|
|
190
|
-
color="
|
|
203
|
+
color="slide-badge mb-20"
|
|
191
204
|
/>
|
|
192
205
|
<h1>{{ slide.chartNameDisplay }}</h1>
|
|
193
206
|
<p>{{ slide.chartDescription }}</p>
|
|
@@ -196,12 +209,11 @@ export default {
|
|
|
196
209
|
</component>
|
|
197
210
|
</div>
|
|
198
211
|
<div
|
|
199
|
-
ref="prev"
|
|
200
212
|
role="button"
|
|
201
213
|
class="prev"
|
|
202
214
|
:aria-label="t('carousel.previous')"
|
|
203
215
|
:aria-disabled="sliders.length === 1"
|
|
204
|
-
:class="{'
|
|
216
|
+
:class="{'disabled': sliders.length === 1}"
|
|
205
217
|
tabindex="0"
|
|
206
218
|
@click="nextPrev('prev')"
|
|
207
219
|
@keyup.enter.space="nextPrev('prev')"
|
|
@@ -211,12 +223,11 @@ export default {
|
|
|
211
223
|
/>
|
|
212
224
|
</div>
|
|
213
225
|
<div
|
|
214
|
-
ref="next"
|
|
215
226
|
role="button"
|
|
216
227
|
class="next"
|
|
217
228
|
:aria-label="t('carousel.next')"
|
|
218
229
|
:aria-disabled="sliders.length === 1"
|
|
219
|
-
:class="{'
|
|
230
|
+
:class="{'disabled': sliders.length === 1}"
|
|
220
231
|
tabindex="0"
|
|
221
232
|
@click="nextPrev('next')"
|
|
222
233
|
@keyup.enter.space="nextPrev('next')"
|
|
@@ -226,8 +237,8 @@ export default {
|
|
|
226
237
|
/>
|
|
227
238
|
</div>
|
|
228
239
|
<div
|
|
240
|
+
v-if="sliders.length > 1"
|
|
229
241
|
class="controls"
|
|
230
|
-
:class="{'disable': sliders.length === 1}"
|
|
231
242
|
>
|
|
232
243
|
<div
|
|
233
244
|
v-for="(slide, i) in slider"
|
|
@@ -252,23 +263,21 @@ export default {
|
|
|
252
263
|
place-items: center;
|
|
253
264
|
overflow: hidden;
|
|
254
265
|
margin-bottom: 30px;
|
|
255
|
-
|
|
266
|
+
height: 245px;
|
|
256
267
|
|
|
257
|
-
&.
|
|
258
|
-
&.
|
|
268
|
+
&.disabled::before,
|
|
269
|
+
&.disabled::after {
|
|
259
270
|
display: none;
|
|
260
271
|
}
|
|
261
272
|
}
|
|
262
273
|
|
|
263
274
|
.slide-track {
|
|
264
275
|
display: flex;
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
transition: 1s ease-in-out;
|
|
268
|
-
left: 21%;
|
|
276
|
+
position: absolute;
|
|
277
|
+
top: 0;
|
|
269
278
|
}
|
|
270
279
|
|
|
271
|
-
.
|
|
280
|
+
.slide-badge {
|
|
272
281
|
background: var(--app-partner-accent);
|
|
273
282
|
color: var(--body-bg);
|
|
274
283
|
}
|
|
@@ -333,7 +342,7 @@ export default {
|
|
|
333
342
|
.slider::before {
|
|
334
343
|
left: 0;
|
|
335
344
|
top: 0;
|
|
336
|
-
&.
|
|
345
|
+
&.disabled {
|
|
337
346
|
display: none;
|
|
338
347
|
}
|
|
339
348
|
}
|
|
@@ -344,15 +353,13 @@ export default {
|
|
|
344
353
|
}
|
|
345
354
|
|
|
346
355
|
.controls {
|
|
356
|
+
position: absolute;
|
|
357
|
+
bottom: 0;
|
|
347
358
|
width: 100%;
|
|
348
359
|
display: flex;
|
|
349
360
|
justify-content: center;
|
|
350
361
|
margin-top: 10px;
|
|
351
362
|
|
|
352
|
-
&.disable {
|
|
353
|
-
display: none;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
363
|
.control-item {
|
|
357
364
|
width: 10px;
|
|
358
365
|
height: 10px;
|
|
@@ -48,13 +48,18 @@ export default {
|
|
|
48
48
|
<a
|
|
49
49
|
v-if="text"
|
|
50
50
|
class="copy-to-clipboard-text"
|
|
51
|
+
role="button"
|
|
52
|
+
:aria-label="t('generic.copyToClipboard')"
|
|
51
53
|
:class="{ 'copied': copied, 'plain': plain}"
|
|
52
54
|
href="#"
|
|
53
55
|
@click="clicked"
|
|
56
|
+
@keyup.space="clicked"
|
|
54
57
|
>
|
|
55
|
-
{{ text }}
|
|
58
|
+
{{ text }}
|
|
59
|
+
<i
|
|
56
60
|
class="icon"
|
|
57
61
|
:class="{ 'icon-copy': !copied, 'icon-checkmark': copied}"
|
|
62
|
+
:alt="!copied ? t('generic.copyToClipboard') : t('generic.copiedToClipboard')"
|
|
58
63
|
/>
|
|
59
64
|
</a>
|
|
60
65
|
</template>
|
package/components/Dialog.vue
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import AsyncButton from '@shell/components/AsyncButton';
|
|
3
|
-
import AppModal from '@shell/components/AppModal.vue';
|
|
3
|
+
import AppModal, { DEFAULT_ITERABLE_NODE_SELECTOR } from '@shell/components/AppModal.vue';
|
|
4
4
|
|
|
5
5
|
export default {
|
|
6
6
|
emits: ['okay', 'closed'],
|
|
@@ -21,6 +21,22 @@ export default {
|
|
|
21
21
|
mode: {
|
|
22
22
|
type: String,
|
|
23
23
|
default: '',
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* forcefully set return focus element based on this selector
|
|
28
|
+
*/
|
|
29
|
+
returnFocusSelector: {
|
|
30
|
+
type: String,
|
|
31
|
+
default: '',
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* will return focus to the first iterable node of this container select
|
|
36
|
+
*/
|
|
37
|
+
returnFocusFirstIterableNodeSelector: {
|
|
38
|
+
type: String,
|
|
39
|
+
default: DEFAULT_ITERABLE_NODE_SELECTOR,
|
|
24
40
|
}
|
|
25
41
|
},
|
|
26
42
|
|
|
@@ -60,6 +76,9 @@ export default {
|
|
|
60
76
|
:name="name"
|
|
61
77
|
height="auto"
|
|
62
78
|
:scrollable="true"
|
|
79
|
+
:trigger-focus-trap="true"
|
|
80
|
+
:return-focus-selector="returnFocusSelector"
|
|
81
|
+
:return-focus-first-iterable-node-selector="returnFocusFirstIterableNodeSelector"
|
|
63
82
|
@close="closeDialog(false)"
|
|
64
83
|
@before-open="beforeOpen"
|
|
65
84
|
>
|
|
@@ -368,6 +368,12 @@ export default {
|
|
|
368
368
|
return project?.description;
|
|
369
369
|
},
|
|
370
370
|
|
|
371
|
+
projectResource(group) {
|
|
372
|
+
const row = group.rows[0];
|
|
373
|
+
|
|
374
|
+
return row.nameDisplay || row.id || '';
|
|
375
|
+
},
|
|
376
|
+
|
|
371
377
|
clearSelection() {
|
|
372
378
|
this.$refs.table.clearSelection();
|
|
373
379
|
},
|
|
@@ -462,6 +468,7 @@ export default {
|
|
|
462
468
|
<ButtonMultiAction
|
|
463
469
|
class="project-action mr-10"
|
|
464
470
|
:borderless="true"
|
|
471
|
+
:aria-label="t('projectNamespaces.tableActionsLabel', { resource: projectResource(group.group) })"
|
|
465
472
|
:invisible="!showProjectActionButton(group.group)"
|
|
466
473
|
@click="showProjectAction($event, group.group)"
|
|
467
474
|
/>
|
|
@@ -43,6 +43,7 @@ export default {
|
|
|
43
43
|
name="password-modal"
|
|
44
44
|
:width="500"
|
|
45
45
|
:height="465"
|
|
46
|
+
:trigger-focus-trap="true"
|
|
46
47
|
@close="show(false)"
|
|
47
48
|
>
|
|
48
49
|
<Card
|
|
@@ -68,6 +69,8 @@ export default {
|
|
|
68
69
|
<!-- type reset is required by lastpass -->
|
|
69
70
|
<button
|
|
70
71
|
class="btn role-secondary"
|
|
72
|
+
role="button"
|
|
73
|
+
:aria-label="t('changePassword.cancel')"
|
|
71
74
|
type="reset"
|
|
72
75
|
@click="show(false)"
|
|
73
76
|
>
|