@rancher/shell 3.0.12-rc.1 → 3.0.12-rc.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.
- package/assets/images/providers/entraid-black.svg +4 -0
- package/assets/images/providers/entraid.svg +9 -0
- package/assets/images/vendor/entraid.svg +9 -0
- package/assets/styles/app.scss +0 -1
- package/assets/translations/en-us.yaml +19 -17
- package/assets/translations/zh-hans.yaml +4 -8
- package/chart/__tests__/S3.test.ts +10 -3
- package/components/CountBox.vue +20 -0
- package/components/CreateDriver.vue +0 -12
- package/components/DetailText.vue +12 -3
- package/components/SelectIconGrid.vue +5 -0
- package/components/__tests__/CountBox.test.ts +72 -0
- package/components/__tests__/DetailText.test.ts +113 -0
- package/components/fleet/FleetClusterTargets/index.vue +18 -1
- package/components/form/InputWithSelect.vue +18 -10
- package/components/form/KeyValue.vue +17 -1
- package/components/form/LabeledSelect.vue +82 -24
- package/components/form/Select.vue +73 -56
- package/components/form/ServiceNameSelect.vue +13 -11
- package/components/form/__tests__/KeyValue.test.ts +66 -0
- package/components/form/__tests__/NodeScheduling.test.ts +9 -0
- package/components/form/labeled-select-utils/useLabeledSelectPagination.ts +138 -0
- package/components/nav/Group.vue +7 -6
- package/components/nav/Header.vue +24 -3
- package/components/nav/NotificationCenter/Notification.vue +4 -1
- package/components/nav/NotificationCenter/NotificationHeader.vue +20 -8
- package/components/nav/NotificationCenter/__tests__/NotificationHeader.test.ts +80 -0
- package/components/nav/Type.vue +8 -7
- package/components/nav/WindowManager/index.vue +2 -1
- package/components/nav/WorkspaceSwitcher.vue +13 -0
- package/components/nav/__tests__/Group.test.ts +67 -0
- package/components/nav/__tests__/Header.test.ts +235 -0
- package/components/nav/__tests__/Type.test.ts +20 -3
- package/components/templates/default.vue +34 -4
- package/components/templates/home.vue +12 -25
- package/components/templates/plain.vue +13 -26
- package/composables/useLabeledFormElement.ts +10 -2
- package/composables/useLabeledSelect.ts +60 -0
- package/composables/useUserRetentionValidation.ts +1 -49
- package/config/cookies.js +0 -1
- package/config/labels-annotations.js +1 -0
- package/config/query-params.js +1 -0
- package/config/router/routes.js +0 -8
- package/core/__tests__/plugin-products.test.ts +616 -25
- package/core/plugin-products-base.ts +31 -14
- package/core/plugin-products-helpers.ts +5 -4
- package/core/plugin-types.ts +18 -3
- package/core/types.ts +3 -1
- package/detail/__tests__/management.cattle.io.fleetworkspace.test.ts +128 -0
- package/detail/management.cattle.io.fleetworkspace.vue +49 -0
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +9 -0
- package/edit/__tests__/kontainerDriver.test.ts +0 -13
- package/edit/__tests__/nodeDriver.test.ts +5 -11
- package/edit/__tests__/resources.cattle.io.restore.test.ts +9 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
- package/edit/auth/__tests__/oidc.test.ts +54 -0
- package/edit/auth/azuread.vue +1 -1
- package/edit/auth/oidc.vue +8 -0
- package/edit/kontainerDriver.vue +1 -2
- package/edit/nodeDriver.vue +0 -2
- package/edit/provisioning.cattle.io.cluster/AgentEnv.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/AgentEnv.test.ts +25 -0
- package/edit/provisioning.cattle.io.cluster/index.vue +70 -99
- package/initialize/App.vue +29 -2
- package/initialize/install-plugins.js +0 -2
- package/list/__tests__/management.cattle.io.feature.test.ts +105 -0
- package/list/catalog.cattle.io.app.vue +25 -5
- package/list/management.cattle.io.feature.vue +1 -1
- package/list/management.cattle.io.fleetworkspace.vue +8 -0
- package/machine-config/amazonec2.vue +1 -0
- package/mixins/chart.js +40 -9
- package/models/__tests__/catalog.cattle.io.app.test.ts +15 -1
- package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +84 -0
- package/models/__tests__/chart.test.ts +99 -6
- package/models/__tests__/management.cattle.io.feature.test.ts +131 -0
- package/models/__tests__/monitoring.coreos.com.alertmanagerconfig.test.ts +98 -0
- package/models/catalog.cattle.io.app.js +21 -17
- package/models/catalog.cattle.io.clusterrepo.js +39 -11
- package/models/chart.js +33 -19
- package/models/fleet-application.js +1 -1
- package/models/fleet.cattle.io.bundle.js +1 -1
- package/models/kontainerdriver.js +11 -0
- package/models/management.cattle.io.authconfig.js +5 -1
- package/models/management.cattle.io.cluster.js +0 -53
- package/models/management.cattle.io.feature.js +3 -3
- package/models/management.cattle.io.kontainerdriver.js +1 -26
- package/models/monitoring.coreos.com.alertmanagerconfig.js +31 -17
- package/models/nodedriver.js +7 -0
- package/package.json +13 -12
- package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +189 -0
- package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +55 -0
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +53 -0
- package/pages/c/_cluster/apps/charts/chart.vue +217 -33
- package/pages/c/_cluster/apps/charts/index.vue +2 -2
- package/pages/c/_cluster/apps/charts/install.vue +8 -3
- package/pages/c/_cluster/auth/user.retention/index.vue +55 -22
- package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +5 -7
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +39 -2
- package/pages/c/_cluster/uiplugins/__tests__/PluginInfoPanel.test.ts +61 -0
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +15 -10
- package/pages/c/_cluster/uiplugins/index.vue +23 -25
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +205 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +82 -4
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +1 -1
- package/scripts/test-plugins-build.sh +5 -2
- package/server/server-middleware.js +2 -2
- package/static/humans.txt +1 -0
- package/static/robots.txt +34 -0
- package/static/welcome-cow.svg +18 -0
- package/store/__tests__/catalog.test.ts +161 -11
- package/store/auth.js +0 -3
- package/store/catalog.js +60 -8
- package/types/shell/index.d.ts +26 -22
- package/utils/__tests__/git.test.ts +270 -0
- package/utils/__tests__/inactivity.test.ts +316 -0
- package/utils/__tests__/object.test.ts +77 -0
- package/utils/__tests__/time.test.ts +14 -1
- package/utils/__tests__/url.test.ts +246 -0
- package/utils/object.js +33 -2
- package/utils/time.ts +5 -0
- package/vue.config.js +0 -9
- package/assets/images/providers/azuread-black.svg +0 -22
- package/assets/images/providers/azuread.svg +0 -25
- package/assets/images/vendor/azuread.svg +0 -18
- package/assets/styles/fonts/_dots.scss +0 -18
- package/components/EmberPage.vue +0 -622
- package/components/EmberPageView.vue +0 -39
- package/components/form/labeled-select-utils/labeled-select-pagination.ts +0 -116
- package/mixins/labeled-form-element.ts +0 -225
- package/pages/c/_cluster/explorer/tools/pages/_page.vue +0 -28
- package/pages/c/_cluster/manager/pages/_page.vue +0 -22
- package/pages/c/_cluster/mcapps/pages/_page.vue +0 -22
- package/plugins/ember-cookie.js +0 -17
- package/utils/ember-page.js +0 -30
|
@@ -778,11 +778,16 @@ export default {
|
|
|
778
778
|
@onInput="onInputMarkdownMultiline(i, $event)"
|
|
779
779
|
@onFocus="onFocusMarkdownMultiline(i, $event)"
|
|
780
780
|
/>
|
|
781
|
+
<div
|
|
782
|
+
v-else-if="valueConcealed"
|
|
783
|
+
class="concealed-value conceal"
|
|
784
|
+
data-testid="concealed-value"
|
|
785
|
+
:aria-label="t('generic.ariaLabel.value', {index: i+1})"
|
|
786
|
+
/>
|
|
781
787
|
<TextAreaAutoGrow
|
|
782
788
|
v-else-if="valueMultiline && row[valueName] !== undefined"
|
|
783
789
|
v-model:value="row[valueName]"
|
|
784
790
|
data-testid="value-multiline"
|
|
785
|
-
:class="{'conceal': valueConcealed}"
|
|
786
791
|
:disabled="disabled"
|
|
787
792
|
:mode="mode"
|
|
788
793
|
:placeholder="_valuePlaceholder"
|
|
@@ -809,6 +814,7 @@ export default {
|
|
|
809
814
|
class="btn btn-sm role-secondary file-selector"
|
|
810
815
|
:label="t('generic.upload')"
|
|
811
816
|
:include-file-name="true"
|
|
817
|
+
:accept="readAccept"
|
|
812
818
|
:aria-label="t('generic.ariaLabel.value', {index: i+1})"
|
|
813
819
|
@selected="onValueFileSelected(i, $event)"
|
|
814
820
|
/>
|
|
@@ -896,6 +902,7 @@ export default {
|
|
|
896
902
|
class="role-tertiary"
|
|
897
903
|
:label="t('generic.readFromFile')"
|
|
898
904
|
:include-file-name="true"
|
|
905
|
+
:accept="readAccept"
|
|
899
906
|
data-testid="read_all_key_value_button"
|
|
900
907
|
@selected="onFileSelected"
|
|
901
908
|
/>
|
|
@@ -941,6 +948,15 @@ export default {
|
|
|
941
948
|
padding: 10px 10px 10px 10px;
|
|
942
949
|
}
|
|
943
950
|
|
|
951
|
+
.concealed-value {
|
|
952
|
+
padding: 10px;
|
|
953
|
+
min-height: 40px;
|
|
954
|
+
user-select: none;
|
|
955
|
+
&::before {
|
|
956
|
+
content: '••••••••••••••••••••';
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
|
|
944
960
|
.text-monospace:not(.conceal) {
|
|
945
961
|
font-family: monospace, monospace;
|
|
946
962
|
}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import CompactInput from '@shell/mixins/compact-input';
|
|
3
|
-
import LabeledFormElement from '@shell/mixins/labeled-form-element';
|
|
4
3
|
import { get } from '@shell/utils/object';
|
|
5
4
|
import { LabeledTooltip } from '@components/LabeledTooltip';
|
|
6
5
|
import VueSelectOverrides from '@shell/mixins/vue-select-overrides';
|
|
7
6
|
import { calculatePosition } from '@shell/utils/select';
|
|
8
7
|
import { generateRandomAlphaString } from '@shell/utils/string';
|
|
9
|
-
import
|
|
8
|
+
import { useLabeledSelectPagination, labeledSelectPaginationProps } from '@shell/components/form/labeled-select-utils/useLabeledSelectPagination';
|
|
10
9
|
import { LABEL_SELECT_NOT_OPTION_KINDS } from '@shell/types/components/labeledSelect';
|
|
11
10
|
import { mapGetters } from 'vuex';
|
|
12
11
|
import { _VIEW } from '@shell/config/query-params';
|
|
13
12
|
import { useClickOutside } from '@shell/composables/useClickOutside';
|
|
13
|
+
import { useLabeledFormElement, labeledFormElementProps } from '@shell/composables/useLabeledFormElement';
|
|
14
|
+
import { useLabeledSelect } from '@shell/composables/useLabeledSelect';
|
|
14
15
|
import { ref } from 'vue';
|
|
15
16
|
|
|
16
17
|
export default {
|
|
@@ -21,14 +22,18 @@ export default {
|
|
|
21
22
|
components: { LabeledTooltip },
|
|
22
23
|
mixins: [
|
|
23
24
|
CompactInput,
|
|
24
|
-
LabeledFormElement,
|
|
25
25
|
VueSelectOverrides,
|
|
26
|
-
LabeledSelectPagination
|
|
27
26
|
],
|
|
28
27
|
|
|
29
|
-
emits: ['on-open', 'on-close', 'selecting', 'deselecting', 'search', 'update:validation', 'update:value'],
|
|
28
|
+
emits: ['on-open', 'on-close', 'on-focus', 'on-blur', 'selecting', 'deselecting', 'search', 'update:validation', 'update:value'],
|
|
30
29
|
|
|
31
30
|
props: {
|
|
31
|
+
...labeledFormElementProps,
|
|
32
|
+
...labeledSelectPaginationProps,
|
|
33
|
+
value: {
|
|
34
|
+
default: null,
|
|
35
|
+
type: [String, Object, Number, Array, Boolean]
|
|
36
|
+
},
|
|
32
37
|
appendToBody: {
|
|
33
38
|
default: true,
|
|
34
39
|
type: Boolean,
|
|
@@ -37,14 +42,6 @@ export default {
|
|
|
37
42
|
default: false,
|
|
38
43
|
type: Boolean
|
|
39
44
|
},
|
|
40
|
-
disabled: {
|
|
41
|
-
default: false,
|
|
42
|
-
type: Boolean
|
|
43
|
-
},
|
|
44
|
-
required: {
|
|
45
|
-
default: false,
|
|
46
|
-
type: Boolean
|
|
47
|
-
},
|
|
48
45
|
hoverTooltip: {
|
|
49
46
|
default: true,
|
|
50
47
|
type: Boolean
|
|
@@ -99,14 +96,18 @@ export default {
|
|
|
99
96
|
default: null,
|
|
100
97
|
type: [String, Object]
|
|
101
98
|
},
|
|
102
|
-
value: {
|
|
103
|
-
default: null,
|
|
104
|
-
type: [String, Object, Number, Array, Boolean]
|
|
105
|
-
},
|
|
106
99
|
options: {
|
|
107
100
|
type: Array,
|
|
108
101
|
default: () => ([])
|
|
109
102
|
},
|
|
103
|
+
searchable: {
|
|
104
|
+
default: false,
|
|
105
|
+
type: Boolean
|
|
106
|
+
},
|
|
107
|
+
filterable: {
|
|
108
|
+
default: true,
|
|
109
|
+
type: Boolean
|
|
110
|
+
},
|
|
110
111
|
closeOnSelect: {
|
|
111
112
|
type: Boolean,
|
|
112
113
|
default: true
|
|
@@ -117,7 +118,7 @@ export default {
|
|
|
117
118
|
}
|
|
118
119
|
},
|
|
119
120
|
|
|
120
|
-
setup() {
|
|
121
|
+
setup(props, { emit }) {
|
|
121
122
|
const select = ref(null);
|
|
122
123
|
const isOpen = ref(false);
|
|
123
124
|
|
|
@@ -125,7 +126,67 @@ export default {
|
|
|
125
126
|
isOpen.value = false;
|
|
126
127
|
});
|
|
127
128
|
|
|
128
|
-
|
|
129
|
+
const {
|
|
130
|
+
raised,
|
|
131
|
+
focused,
|
|
132
|
+
blurred,
|
|
133
|
+
empty,
|
|
134
|
+
isView,
|
|
135
|
+
onFocusLabeled,
|
|
136
|
+
onBlurLabeled,
|
|
137
|
+
isDisabled,
|
|
138
|
+
validationMessage,
|
|
139
|
+
requiredField
|
|
140
|
+
} = useLabeledFormElement(props, emit);
|
|
141
|
+
|
|
142
|
+
const {
|
|
143
|
+
canPaginate,
|
|
144
|
+
canLoadMore,
|
|
145
|
+
optionCounts,
|
|
146
|
+
_options,
|
|
147
|
+
pages,
|
|
148
|
+
totalResults,
|
|
149
|
+
paginating,
|
|
150
|
+
loadMore,
|
|
151
|
+
setPaginationFilter,
|
|
152
|
+
} = useLabeledSelectPagination(props);
|
|
153
|
+
|
|
154
|
+
const {
|
|
155
|
+
isSearchable,
|
|
156
|
+
isFilterable,
|
|
157
|
+
resizeHandler: resizeHandlerFn
|
|
158
|
+
} = useLabeledSelect(props, canPaginate);
|
|
159
|
+
|
|
160
|
+
const resizeHandler = () => {
|
|
161
|
+
resizeHandlerFn(select);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
isOpen,
|
|
166
|
+
select,
|
|
167
|
+
raised,
|
|
168
|
+
focused,
|
|
169
|
+
blurred,
|
|
170
|
+
empty,
|
|
171
|
+
isView,
|
|
172
|
+
onFocusLabeled,
|
|
173
|
+
onBlurLabeled,
|
|
174
|
+
isDisabled,
|
|
175
|
+
validationMessage,
|
|
176
|
+
requiredField,
|
|
177
|
+
isSearchable,
|
|
178
|
+
isFilterable,
|
|
179
|
+
resizeHandler,
|
|
180
|
+
canPaginate,
|
|
181
|
+
canLoadMore,
|
|
182
|
+
optionCounts,
|
|
183
|
+
_options,
|
|
184
|
+
pages,
|
|
185
|
+
totalResults,
|
|
186
|
+
paginating,
|
|
187
|
+
loadMore,
|
|
188
|
+
setPaginationFilter,
|
|
189
|
+
};
|
|
129
190
|
},
|
|
130
191
|
|
|
131
192
|
data() {
|
|
@@ -148,11 +209,6 @@ export default {
|
|
|
148
209
|
return this.canPaginate ? !!this._options.find((o) => o.kind === 'group' && !!o.icon) : false;
|
|
149
210
|
},
|
|
150
211
|
|
|
151
|
-
_options() {
|
|
152
|
-
// If we're paginated show the page as provided by `paginate`. See label-select-pagination mixin
|
|
153
|
-
return this.canPaginate ? this.page : this.options;
|
|
154
|
-
},
|
|
155
|
-
|
|
156
212
|
filteredAttrs() {
|
|
157
213
|
const {
|
|
158
214
|
class: _class,
|
|
@@ -207,11 +263,13 @@ export default {
|
|
|
207
263
|
},
|
|
208
264
|
|
|
209
265
|
onFocus() {
|
|
266
|
+
this.$emit('on-focus');
|
|
210
267
|
this.selectedVisibility = 'hidden';
|
|
211
268
|
this.onFocusLabeled();
|
|
212
269
|
},
|
|
213
270
|
|
|
214
271
|
onBlur() {
|
|
272
|
+
this.$emit('on-blur');
|
|
215
273
|
this.selectedVisibility = 'visible';
|
|
216
274
|
this.onBlurLabeled();
|
|
217
275
|
},
|
|
@@ -1,39 +1,38 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { get } from '@shell/utils/object';
|
|
3
|
-
import LabeledFormElement from '@shell/mixins/labeled-form-element';
|
|
4
3
|
import VueSelectOverrides from '@shell/mixins/vue-select-overrides';
|
|
5
4
|
import { generateRandomAlphaString } from '@shell/utils/string';
|
|
6
5
|
import { LabeledTooltip } from '@components/LabeledTooltip';
|
|
7
6
|
import { calculatePosition } from '@shell/utils/select';
|
|
8
7
|
import { _VIEW } from '@shell/config/query-params';
|
|
9
8
|
import { useClickOutside } from '@shell/composables/useClickOutside';
|
|
9
|
+
import { useLabeledFormElement, labeledFormElementProps } from '@shell/composables/useLabeledFormElement';
|
|
10
|
+
import { useLabeledSelect } from '@shell/composables/useLabeledSelect';
|
|
10
11
|
import { ref } from 'vue';
|
|
11
12
|
|
|
12
13
|
export default {
|
|
13
|
-
|
|
14
|
+
inheritAttrs: false,
|
|
15
|
+
|
|
16
|
+
emits: ['update:value', 'createdListItem', 'on-open', 'on-close', 'on-focus', 'on-blur', 'update:validation'],
|
|
14
17
|
|
|
15
18
|
components: { LabeledTooltip },
|
|
16
19
|
mixins: [
|
|
17
|
-
LabeledFormElement,
|
|
18
20
|
VueSelectOverrides,
|
|
19
21
|
],
|
|
20
22
|
props: {
|
|
23
|
+
...labeledFormElementProps,
|
|
24
|
+
value: {
|
|
25
|
+
default: null,
|
|
26
|
+
type: [String, Object, Number, Array, Boolean],
|
|
27
|
+
},
|
|
21
28
|
appendToBody: {
|
|
22
29
|
default: true,
|
|
23
30
|
type: Boolean,
|
|
24
31
|
},
|
|
25
|
-
disabled: {
|
|
26
|
-
default: false,
|
|
27
|
-
type: Boolean,
|
|
28
|
-
},
|
|
29
32
|
getKeyForOption: {
|
|
30
33
|
default: null,
|
|
31
34
|
type: Function
|
|
32
35
|
},
|
|
33
|
-
mode: {
|
|
34
|
-
default: 'edit',
|
|
35
|
-
type: String,
|
|
36
|
-
},
|
|
37
36
|
optionKey: {
|
|
38
37
|
default: null,
|
|
39
38
|
type: String,
|
|
@@ -46,10 +45,6 @@ export default {
|
|
|
46
45
|
default: null,
|
|
47
46
|
type: String,
|
|
48
47
|
},
|
|
49
|
-
placeholder: {
|
|
50
|
-
type: String,
|
|
51
|
-
default: '',
|
|
52
|
-
},
|
|
53
48
|
popperOverride: {
|
|
54
49
|
type: Function,
|
|
55
50
|
default: null,
|
|
@@ -78,10 +73,6 @@ export default {
|
|
|
78
73
|
type: String,
|
|
79
74
|
default: null,
|
|
80
75
|
},
|
|
81
|
-
value: {
|
|
82
|
-
default: null,
|
|
83
|
-
type: [String, Object, Number, Array, Boolean],
|
|
84
|
-
},
|
|
85
76
|
closeOnSelect: {
|
|
86
77
|
type: Boolean,
|
|
87
78
|
default: true,
|
|
@@ -99,8 +90,20 @@ export default {
|
|
|
99
90
|
default: false,
|
|
100
91
|
type: Boolean
|
|
101
92
|
},
|
|
93
|
+
options: {
|
|
94
|
+
type: Array,
|
|
95
|
+
default: () => ([])
|
|
96
|
+
},
|
|
97
|
+
searchable: {
|
|
98
|
+
default: false,
|
|
99
|
+
type: Boolean
|
|
100
|
+
},
|
|
101
|
+
filterable: {
|
|
102
|
+
default: true,
|
|
103
|
+
type: Boolean
|
|
104
|
+
},
|
|
102
105
|
},
|
|
103
|
-
setup() {
|
|
106
|
+
setup(props, { emit }) {
|
|
104
107
|
const select = ref(null);
|
|
105
108
|
const isOpen = ref(false);
|
|
106
109
|
|
|
@@ -108,13 +111,61 @@ export default {
|
|
|
108
111
|
isOpen.value = false;
|
|
109
112
|
});
|
|
110
113
|
|
|
111
|
-
|
|
114
|
+
const {
|
|
115
|
+
raised,
|
|
116
|
+
focused,
|
|
117
|
+
blurred,
|
|
118
|
+
empty,
|
|
119
|
+
isView,
|
|
120
|
+
onFocusLabeled,
|
|
121
|
+
onBlurLabeled,
|
|
122
|
+
isDisabled,
|
|
123
|
+
validationMessage,
|
|
124
|
+
requiredField
|
|
125
|
+
} = useLabeledFormElement(props, emit);
|
|
126
|
+
|
|
127
|
+
const onFocus = () => {
|
|
128
|
+
emit('on-focus');
|
|
129
|
+
onFocusLabeled();
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const onBlur = () => {
|
|
133
|
+
emit('on-blur');
|
|
134
|
+
onBlurLabeled();
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const {
|
|
138
|
+
isSearchable,
|
|
139
|
+
isFilterable,
|
|
140
|
+
resizeHandler: resizeHandlerFn
|
|
141
|
+
} = useLabeledSelect(props);
|
|
142
|
+
|
|
143
|
+
const resizeHandler = () => {
|
|
144
|
+
resizeHandlerFn(select);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
isOpen,
|
|
149
|
+
select,
|
|
150
|
+
raised,
|
|
151
|
+
focused,
|
|
152
|
+
blurred,
|
|
153
|
+
empty,
|
|
154
|
+
isView,
|
|
155
|
+
onFocus,
|
|
156
|
+
onBlur,
|
|
157
|
+
isDisabled,
|
|
158
|
+
validationMessage,
|
|
159
|
+
requiredField,
|
|
160
|
+
isSearchable,
|
|
161
|
+
isFilterable,
|
|
162
|
+
resizeHandler
|
|
163
|
+
};
|
|
112
164
|
},
|
|
113
165
|
data() {
|
|
114
166
|
return { generatedUid: `s-uid-${ generateRandomAlphaString(12) }` };
|
|
115
167
|
},
|
|
116
168
|
methods: {
|
|
117
|
-
// resizeHandler = in mixin
|
|
118
169
|
getOptionLabel(option) {
|
|
119
170
|
if (this.$attrs['get-option-label']) {
|
|
120
171
|
return this.$attrs['get-option-label'](option);
|
|
@@ -252,40 +303,6 @@ export default {
|
|
|
252
303
|
},
|
|
253
304
|
},
|
|
254
305
|
computed: {
|
|
255
|
-
requiredField() {
|
|
256
|
-
// using "any" for a type on "rule" here is dirty but the use of the optional chaining operator makes it safe for what we're doing here.
|
|
257
|
-
return (this.required || this.rules.some((rule) => rule?.name === 'required'));
|
|
258
|
-
},
|
|
259
|
-
validationMessage() {
|
|
260
|
-
// we want to grab the required rule passed in if we can but if it's not there then we can just grab it from the formRulesGenerator
|
|
261
|
-
const requiredRule = this.rules.find((rule) => rule?.name === 'required');
|
|
262
|
-
const ruleMessages = [];
|
|
263
|
-
const value = this?.value;
|
|
264
|
-
|
|
265
|
-
if (requiredRule && this.blurred && !this.focused) {
|
|
266
|
-
const message = requiredRule(value);
|
|
267
|
-
|
|
268
|
-
if (!!message) {
|
|
269
|
-
return message;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
for (const rule of this.rules) {
|
|
274
|
-
const message = rule(value);
|
|
275
|
-
|
|
276
|
-
if (!!message && rule.name !== 'required') { // we're catching 'required' above so we can ignore it here
|
|
277
|
-
ruleMessages.push(message);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
if (ruleMessages.length > 0 && (this.blurred || this.focused)) {
|
|
281
|
-
return ruleMessages.join(', ');
|
|
282
|
-
} else {
|
|
283
|
-
return undefined;
|
|
284
|
-
}
|
|
285
|
-
},
|
|
286
|
-
canPaginate() {
|
|
287
|
-
return false;
|
|
288
|
-
},
|
|
289
306
|
deClassedAttrs() {
|
|
290
307
|
const { class: _, ...rest } = this.$attrs;
|
|
291
308
|
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import labeledFormElement from '@shell/mixins/labeled-form-element';
|
|
3
2
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
|
4
3
|
import { Banner } from '@components/Banner';
|
|
5
4
|
import { _VIEW } from '@shell/config/query-params';
|
|
5
|
+
import { computed } from 'vue';
|
|
6
6
|
|
|
7
7
|
export default {
|
|
8
|
+
inheritAttrs: false,
|
|
9
|
+
|
|
8
10
|
emits: ['update:value'],
|
|
9
11
|
|
|
10
12
|
components: { LabeledSelect, Banner },
|
|
11
13
|
|
|
12
|
-
mixins: [labeledFormElement],
|
|
13
|
-
|
|
14
14
|
props: {
|
|
15
15
|
disabled: {
|
|
16
16
|
type: Boolean,
|
|
@@ -66,6 +66,16 @@ export default {
|
|
|
66
66
|
type: Boolean,
|
|
67
67
|
default: false,
|
|
68
68
|
},
|
|
69
|
+
value: {
|
|
70
|
+
type: String,
|
|
71
|
+
default: null
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
setup(props) {
|
|
76
|
+
const isView = computed(() => props.mode === _VIEW);
|
|
77
|
+
|
|
78
|
+
return { isView };
|
|
69
79
|
},
|
|
70
80
|
|
|
71
81
|
data() {
|
|
@@ -73,10 +83,6 @@ export default {
|
|
|
73
83
|
},
|
|
74
84
|
|
|
75
85
|
computed: {
|
|
76
|
-
isView() {
|
|
77
|
-
return this.mode === _VIEW;
|
|
78
|
-
},
|
|
79
|
-
|
|
80
86
|
serviceNameNew() {
|
|
81
87
|
if (!this.selected) {
|
|
82
88
|
return false;
|
|
@@ -88,10 +94,6 @@ export default {
|
|
|
88
94
|
serviceName() {
|
|
89
95
|
return this.reduce(this.selected);
|
|
90
96
|
},
|
|
91
|
-
|
|
92
|
-
canPaginate() {
|
|
93
|
-
return false;
|
|
94
|
-
},
|
|
95
97
|
},
|
|
96
98
|
|
|
97
99
|
methods: {
|
|
@@ -177,6 +177,72 @@ describe('component: KeyValue', () => {
|
|
|
177
177
|
expect(firstValueInput.element.value).toBe('testvalue1');
|
|
178
178
|
});
|
|
179
179
|
|
|
180
|
+
describe('valueConcealed', () => {
|
|
181
|
+
it('should not render actual secret values in the DOM when valueConcealed is true', () => {
|
|
182
|
+
const secretValue = 'super-secret-api-key-12345';
|
|
183
|
+
const wrapper = mount(KeyValue, {
|
|
184
|
+
props: {
|
|
185
|
+
value: { mySecret: secretValue },
|
|
186
|
+
mode: 'view',
|
|
187
|
+
valueConcealed: true,
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
global: {
|
|
191
|
+
mocks: { $store: { getters: { 'i18n/t': jest.fn() } } },
|
|
192
|
+
stubs: { CodeMirror: true },
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
const concealedEl = wrapper.find('[data-testid="concealed-value"]');
|
|
197
|
+
|
|
198
|
+
expect(concealedEl.exists()).toBe(true);
|
|
199
|
+
expect(wrapper.html()).not.toContain(secretValue);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('should render a TextAreaAutoGrow with the real value when valueConcealed is false', () => {
|
|
203
|
+
const secretValue = 'visible-value';
|
|
204
|
+
const wrapper = mount(KeyValue, {
|
|
205
|
+
props: {
|
|
206
|
+
value: { myKey: secretValue },
|
|
207
|
+
mode: 'view',
|
|
208
|
+
valueConcealed: false,
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
global: {
|
|
212
|
+
mocks: { $store: { getters: { 'i18n/t': jest.fn() } } },
|
|
213
|
+
stubs: { CodeMirror: true },
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
const concealedEl = wrapper.find('[data-testid="concealed-value"]');
|
|
218
|
+
|
|
219
|
+
expect(concealedEl.exists()).toBe(false);
|
|
220
|
+
|
|
221
|
+
const multilineEl = wrapper.find('[data-testid="value-multiline"]');
|
|
222
|
+
|
|
223
|
+
expect(multilineEl.exists()).toBe(true);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('should have user-select none on the concealed placeholder to prevent text selection', () => {
|
|
227
|
+
const wrapper = mount(KeyValue, {
|
|
228
|
+
props: {
|
|
229
|
+
value: { mySecret: 'secret' },
|
|
230
|
+
mode: 'view',
|
|
231
|
+
valueConcealed: true,
|
|
232
|
+
},
|
|
233
|
+
|
|
234
|
+
global: {
|
|
235
|
+
mocks: { $store: { getters: { 'i18n/t': jest.fn() } } },
|
|
236
|
+
stubs: { CodeMirror: true },
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
const concealedEl = wrapper.find('[data-testid="concealed-value"]');
|
|
241
|
+
|
|
242
|
+
expect(concealedEl.classes()).toContain('concealed-value');
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
|
|
180
246
|
it('a11y: adding ARIA props should correctly fill out the appropriate fields on the component', async() => {
|
|
181
247
|
const value = [{ key: 'testkey1', value: 'testvalue1' }];
|
|
182
248
|
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import { mount } from '@vue/test-utils';
|
|
2
2
|
import NodeScheduling from '@shell/components/form/NodeScheduling.vue';
|
|
3
3
|
import { _CREATE, _EDIT, _VIEW } from '@shell/config/query-params';
|
|
4
|
+
import { createStore } from 'vuex';
|
|
4
5
|
|
|
5
6
|
const requiredSetup = () => {
|
|
6
7
|
return {
|
|
8
|
+
provide: {
|
|
9
|
+
store: createStore({
|
|
10
|
+
getters: {
|
|
11
|
+
currentStore: () => 'cluster',
|
|
12
|
+
'cluster/paginationEnabled': () => () => false,
|
|
13
|
+
},
|
|
14
|
+
}),
|
|
15
|
+
},
|
|
7
16
|
global: {
|
|
8
17
|
mocks: {
|
|
9
18
|
$fetchState: { pending: false },
|