@rancher/shell 2.0.0 → 2.0.1
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/translations/en-us.yaml +18 -3
- package/components/AlertTable.vue +17 -7
- package/components/GrafanaDashboard.vue +6 -4
- package/components/PromptRemove.vue +1 -0
- package/components/form/KeyValue.vue +1 -0
- package/components/form/Taints.vue +13 -7
- package/components/form/__tests__/Taints.test.ts +70 -0
- package/components/nav/Header.vue +1 -1
- package/components/nav/TopLevelMenu.vue +1 -4
- package/config/product/auth.js +1 -1
- package/config/router/navigation-guards/i18n.js +13 -0
- package/config/router/navigation-guards/index.js +2 -1
- package/creators/app/app.package.json +2 -1
- package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +42 -0
- package/detail/provisioning.cattle.io.cluster.vue +4 -4
- package/dialog/DeactivateDriverDialog.vue +30 -11
- package/edit/auth/__tests__/oidc.test.ts +2 -2
- package/edit/token.vue +2 -1
- package/initialize/entry-helpers.js +10 -13
- package/list/management.cattle.io.feature.vue +4 -2
- package/middleware/authenticated.js +0 -19
- package/mixins/auth-config.js +1 -1
- package/models/driver.js +3 -2
- package/models/kontainerdriver.js +30 -13
- package/models/management.cattle.io.authconfig.js +2 -2
- package/models/nodedriver.js +30 -13
- package/package.json +3 -2
- package/pages/c/_cluster/apps/charts/install.vue +3 -2
- package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +0 -3
- package/pages/c/_cluster/manager/drivers/nodeDriver/index.vue +1 -4
- package/pages/c/_cluster/uiplugins/InstallDialog.vue +2 -1
- package/promptRemove/pod.vue +15 -7
- package/scripts/publish-shell.sh +1 -0
- package/store/auth.js +1 -1
- package/store/index.js +1 -1
- package/utils/__tests__/kontainer.test.ts +89 -1
- package/utils/auth.js +1 -1
- package/utils/kontainer.ts +5 -1
- package/utils/version.js +2 -1
- package/rancher-components/components/Accordion/Accordion.test.ts +0 -45
- package/rancher-components/components/Accordion/Accordion.vue +0 -86
- package/rancher-components/components/Accordion/index.ts +0 -1
- package/rancher-components/components/BadgeState/BadgeState.test.ts +0 -12
- package/rancher-components/components/BadgeState/BadgeState.vue +0 -111
- package/rancher-components/components/BadgeState/index.ts +0 -1
- package/rancher-components/components/Banner/Banner.test.ts +0 -59
- package/rancher-components/components/Banner/Banner.vue +0 -244
- package/rancher-components/components/Banner/index.ts +0 -1
- package/rancher-components/components/Card/Card.test.ts +0 -37
- package/rancher-components/components/Card/Card.vue +0 -167
- package/rancher-components/components/Card/index.ts +0 -1
- package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +0 -68
- package/rancher-components/components/Form/Checkbox/Checkbox.vue +0 -421
- package/rancher-components/components/Form/Checkbox/index.ts +0 -1
- package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +0 -40
- package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +0 -402
- package/rancher-components/components/Form/LabeledInput/index.ts +0 -1
- package/rancher-components/components/Form/Radio/RadioButton.test.ts +0 -33
- package/rancher-components/components/Form/Radio/RadioButton.vue +0 -293
- package/rancher-components/components/Form/Radio/RadioGroup.test.ts +0 -30
- package/rancher-components/components/Form/Radio/RadioGroup.vue +0 -259
- package/rancher-components/components/Form/Radio/index.ts +0 -2
- package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +0 -172
- package/rancher-components/components/Form/TextArea/index.ts +0 -1
- package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +0 -94
- package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +0 -152
- package/rancher-components/components/Form/ToggleSwitch/index.ts +0 -1
- package/rancher-components/components/Form/index.ts +0 -5
- package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +0 -156
- package/rancher-components/components/LabeledTooltip/index.ts +0 -1
- package/rancher-components/components/StringList/StringList.test.ts +0 -754
- package/rancher-components/components/StringList/StringList.vue +0 -650
- package/rancher-components/components/StringList/index.ts +0 -1
|
@@ -1,650 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import Vue, { PropType, defineComponent } from 'vue';
|
|
3
|
-
|
|
4
|
-
import LabeledInput from '@components/Form/LabeledInput/LabeledInput.vue';
|
|
5
|
-
import { findStringIndex, hasDuplicatedStrings } from '@shell/utils/array';
|
|
6
|
-
|
|
7
|
-
type Error = 'duplicate';
|
|
8
|
-
type ErrorMessages = Record<Error, string>;
|
|
9
|
-
|
|
10
|
-
type Arrow = 'up' | 'down';
|
|
11
|
-
|
|
12
|
-
const DIRECTION: Record<Arrow, number> = {
|
|
13
|
-
up: -1,
|
|
14
|
-
down: 1,
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const INPUT = {
|
|
18
|
-
create: 'item-create',
|
|
19
|
-
edit: 'item-edit',
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const BOX = 'box';
|
|
23
|
-
|
|
24
|
-
const CLASS = {
|
|
25
|
-
item: 'item',
|
|
26
|
-
error: 'error',
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Manage a list of strings
|
|
31
|
-
*/
|
|
32
|
-
export default defineComponent({
|
|
33
|
-
|
|
34
|
-
name: 'StringList',
|
|
35
|
-
components: { LabeledInput },
|
|
36
|
-
|
|
37
|
-
props: {
|
|
38
|
-
/**
|
|
39
|
-
* The items source
|
|
40
|
-
*/
|
|
41
|
-
items: {
|
|
42
|
-
type: Array as PropType<string[]>,
|
|
43
|
-
default() {
|
|
44
|
-
return [];
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
/**
|
|
48
|
-
* Determines if items with same text will be treated differently, depending on the letters case
|
|
49
|
-
* It is used to compare items during create/edit actions and detect duplicates.
|
|
50
|
-
*/
|
|
51
|
-
caseSensitive: {
|
|
52
|
-
type: Boolean,
|
|
53
|
-
default: false,
|
|
54
|
-
},
|
|
55
|
-
/**
|
|
56
|
-
* Determines if the list of items is editable or view-only
|
|
57
|
-
*/
|
|
58
|
-
readonly: {
|
|
59
|
-
type: Boolean,
|
|
60
|
-
default: false,
|
|
61
|
-
},
|
|
62
|
-
/**
|
|
63
|
-
* The placeholder to show in input field when create or edit items
|
|
64
|
-
*/
|
|
65
|
-
placeholder: {
|
|
66
|
-
type: String,
|
|
67
|
-
default: null,
|
|
68
|
-
},
|
|
69
|
-
/**
|
|
70
|
-
* Determines the action buttons position at the bottom of the main box
|
|
71
|
-
*/
|
|
72
|
-
actionsPosition: {
|
|
73
|
-
type: String,
|
|
74
|
-
default: 'right',
|
|
75
|
-
},
|
|
76
|
-
/**
|
|
77
|
-
* Custom Error messages
|
|
78
|
-
*/
|
|
79
|
-
errorMessages: {
|
|
80
|
-
type: Object as PropType<ErrorMessages>,
|
|
81
|
-
default() {
|
|
82
|
-
return {} as ErrorMessages;
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
/**
|
|
86
|
-
* Enables bulk addition and defines the delimiter to split the input string.
|
|
87
|
-
*/
|
|
88
|
-
bulkAdditionDelimiter: {
|
|
89
|
-
type: RegExp,
|
|
90
|
-
default: null,
|
|
91
|
-
}
|
|
92
|
-
},
|
|
93
|
-
data() {
|
|
94
|
-
return {
|
|
95
|
-
value: undefined as string | undefined,
|
|
96
|
-
selected: null as string | null,
|
|
97
|
-
editedItem: undefined as string | undefined,
|
|
98
|
-
isCreateItem: false,
|
|
99
|
-
errors: { duplicate: false } as Record<Error, boolean>
|
|
100
|
-
};
|
|
101
|
-
},
|
|
102
|
-
|
|
103
|
-
computed: {
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Create an array of error messages, one for each current error
|
|
107
|
-
*/
|
|
108
|
-
errorMessagesArray(): string[] {
|
|
109
|
-
return (Object.keys(this.errors) as Error[])
|
|
110
|
-
.filter((f) => this.errors[f] && this.errorMessages[f])
|
|
111
|
-
.map((k) => this.errorMessages[k]);
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
|
|
115
|
-
watch: {
|
|
116
|
-
/**
|
|
117
|
-
* Shutdown any user actions on the component when it becomes readonly
|
|
118
|
-
*/
|
|
119
|
-
readonly() {
|
|
120
|
-
this.toggleEditMode(false);
|
|
121
|
-
this.toggleCreateMode(false);
|
|
122
|
-
},
|
|
123
|
-
value(val) {
|
|
124
|
-
this.$emit('type:item', val);
|
|
125
|
-
},
|
|
126
|
-
errors: {
|
|
127
|
-
handler(val) {
|
|
128
|
-
this.$emit('errors', val);
|
|
129
|
-
},
|
|
130
|
-
deep: true
|
|
131
|
-
}
|
|
132
|
-
},
|
|
133
|
-
|
|
134
|
-
methods: {
|
|
135
|
-
onChange(value: string, index?: number) {
|
|
136
|
-
this.value = value;
|
|
137
|
-
const items = this.addValueToItems(this.items, value, index);
|
|
138
|
-
|
|
139
|
-
this.toggleError(
|
|
140
|
-
'duplicate',
|
|
141
|
-
hasDuplicatedStrings(items, this.caseSensitive),
|
|
142
|
-
this.isCreateItem ? INPUT.create : INPUT.edit
|
|
143
|
-
);
|
|
144
|
-
},
|
|
145
|
-
|
|
146
|
-
onSelect(item: string) {
|
|
147
|
-
if (this.readonly || this.isCreateItem || this.editedItem === item) {
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
this.selected = item;
|
|
151
|
-
},
|
|
152
|
-
|
|
153
|
-
onSelectNext(arrow: Arrow) {
|
|
154
|
-
const index = findStringIndex(
|
|
155
|
-
this.items,
|
|
156
|
-
this.selected as string,
|
|
157
|
-
);
|
|
158
|
-
|
|
159
|
-
if (index !== -1) {
|
|
160
|
-
/**
|
|
161
|
-
* Select next item in the arrow's direction if it exists,
|
|
162
|
-
* else select again this.selected (do nothing)
|
|
163
|
-
*/
|
|
164
|
-
const item = (this.items[index + DIRECTION[arrow]] || this.selected) as string;
|
|
165
|
-
|
|
166
|
-
this.onSelect(item);
|
|
167
|
-
this.moveScrollbar(arrow);
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
|
-
|
|
171
|
-
onSelectLeave(item?: string) {
|
|
172
|
-
if (item === this.selected) {
|
|
173
|
-
this.selected = null;
|
|
174
|
-
}
|
|
175
|
-
},
|
|
176
|
-
|
|
177
|
-
onClickEmptyBody() {
|
|
178
|
-
if (!this.isCreateItem && !this.editedItem) {
|
|
179
|
-
this.toggleCreateMode(true);
|
|
180
|
-
}
|
|
181
|
-
},
|
|
182
|
-
|
|
183
|
-
onClickPlusButton() {
|
|
184
|
-
this.onSelectLeave();
|
|
185
|
-
this.toggleCreateMode(true);
|
|
186
|
-
},
|
|
187
|
-
|
|
188
|
-
onClickMinusButton() {
|
|
189
|
-
if (this.isCreateItem) {
|
|
190
|
-
this.toggleCreateMode(false);
|
|
191
|
-
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
if (this.editedItem) {
|
|
195
|
-
this.deleteAndSelectNext(this.editedItem);
|
|
196
|
-
this.toggleEditMode(false);
|
|
197
|
-
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
if (this.selected) {
|
|
201
|
-
this.deleteAndSelectNext(this.selected);
|
|
202
|
-
}
|
|
203
|
-
},
|
|
204
|
-
|
|
205
|
-
deleteAndSelectNext(currItem: string) {
|
|
206
|
-
const index = findStringIndex(this.items, currItem, false);
|
|
207
|
-
|
|
208
|
-
if (index !== -1) {
|
|
209
|
-
/**
|
|
210
|
-
* Select the next item in the list.
|
|
211
|
-
*/
|
|
212
|
-
const item = (this.items[index + 1] || this.items[index - 1]);
|
|
213
|
-
|
|
214
|
-
this.onSelect(item);
|
|
215
|
-
this.setFocus(item);
|
|
216
|
-
|
|
217
|
-
this.deleteItem(this.items[index]);
|
|
218
|
-
}
|
|
219
|
-
},
|
|
220
|
-
|
|
221
|
-
setFocus(refId: string) {
|
|
222
|
-
this.$nextTick(() => (this.getElemByRef(refId) as Vue & HTMLElement)?.focus());
|
|
223
|
-
},
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Move scrollbar when the selected item is over the top or bottom side of the box
|
|
227
|
-
*/
|
|
228
|
-
moveScrollbar(arrow: Arrow, value?: number) {
|
|
229
|
-
const box = this.getElemByRef(BOX) as HTMLElement;
|
|
230
|
-
const item = this.getElemByRef(this.selected || '') as HTMLElement;
|
|
231
|
-
|
|
232
|
-
if (box && item && item.className.includes(CLASS.item)) {
|
|
233
|
-
const boxRect = box.getClientRects()[0];
|
|
234
|
-
const itemRect = item.getClientRects()[0];
|
|
235
|
-
|
|
236
|
-
if (
|
|
237
|
-
(arrow === 'down' && itemRect.bottom > boxRect.bottom) ||
|
|
238
|
-
(arrow === 'up' && itemRect.top < boxRect.top)
|
|
239
|
-
) {
|
|
240
|
-
const top = (value ?? itemRect.height) * DIRECTION[arrow];
|
|
241
|
-
|
|
242
|
-
box.scrollBy({ top });
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
},
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Set an error and eventually assign an error class to the element
|
|
249
|
-
*/
|
|
250
|
-
toggleError(type: Error, val: boolean, refId?: string) {
|
|
251
|
-
this.errors[type] = val;
|
|
252
|
-
|
|
253
|
-
if (refId) {
|
|
254
|
-
this.toggleErrorClass(refId, val);
|
|
255
|
-
}
|
|
256
|
-
},
|
|
257
|
-
|
|
258
|
-
toggleErrorClass(refId: string, val: boolean) {
|
|
259
|
-
const input = (this.getElemByRef(refId) as Vue)?.$el;
|
|
260
|
-
|
|
261
|
-
if (input) {
|
|
262
|
-
if (val) {
|
|
263
|
-
input.classList.add(CLASS.error);
|
|
264
|
-
} else {
|
|
265
|
-
input.classList.remove(CLASS.error);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
},
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Show/Hide the input line to create new item
|
|
272
|
-
*/
|
|
273
|
-
toggleCreateMode(show: boolean) {
|
|
274
|
-
if (this.readonly) {
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
if (show) {
|
|
278
|
-
this.toggleEditMode(false);
|
|
279
|
-
this.value = '';
|
|
280
|
-
|
|
281
|
-
this.isCreateItem = true;
|
|
282
|
-
this.setFocus(INPUT.create);
|
|
283
|
-
} else {
|
|
284
|
-
this.value = undefined;
|
|
285
|
-
this.toggleError('duplicate', false);
|
|
286
|
-
this.onSelectLeave();
|
|
287
|
-
|
|
288
|
-
this.isCreateItem = false;
|
|
289
|
-
}
|
|
290
|
-
},
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Show/Hide the in-line editing to edit an existing item
|
|
294
|
-
*/
|
|
295
|
-
toggleEditMode(show: boolean, item?: string) {
|
|
296
|
-
if (this.readonly) {
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
if (show) {
|
|
300
|
-
this.toggleCreateMode(false);
|
|
301
|
-
this.value = this.editedItem;
|
|
302
|
-
|
|
303
|
-
this.editedItem = item || '';
|
|
304
|
-
this.setFocus(INPUT.edit);
|
|
305
|
-
} else {
|
|
306
|
-
this.value = undefined;
|
|
307
|
-
this.toggleError('duplicate', false);
|
|
308
|
-
this.onSelectLeave();
|
|
309
|
-
|
|
310
|
-
this.editedItem = undefined;
|
|
311
|
-
}
|
|
312
|
-
},
|
|
313
|
-
|
|
314
|
-
getElemByRef(id: string) {
|
|
315
|
-
const ref = this.$refs[id];
|
|
316
|
-
|
|
317
|
-
return Array.isArray(ref) ? ref[0] : ref;
|
|
318
|
-
},
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* Create a new item and insert in the items list
|
|
322
|
-
*/
|
|
323
|
-
saveItem(closeInput = true) {
|
|
324
|
-
const value = this.value?.trim();
|
|
325
|
-
|
|
326
|
-
if (value) {
|
|
327
|
-
const items = this.addValueToItems(this.items, value);
|
|
328
|
-
|
|
329
|
-
if (!hasDuplicatedStrings(items, this.caseSensitive)) {
|
|
330
|
-
this.updateItems(items);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
if (closeInput) {
|
|
335
|
-
this.toggleCreateMode(false);
|
|
336
|
-
}
|
|
337
|
-
},
|
|
338
|
-
|
|
339
|
-
/**
|
|
340
|
-
* Update an existing item in the items list
|
|
341
|
-
*/
|
|
342
|
-
updateItem(item: string, closeInput = true) {
|
|
343
|
-
const value = this.value?.trim();
|
|
344
|
-
|
|
345
|
-
if (value) {
|
|
346
|
-
const index = findStringIndex(this.items, item, false);
|
|
347
|
-
const items = index !== -1 ? this.addValueToItems(this.items, value, index) : this.items;
|
|
348
|
-
|
|
349
|
-
if (!hasDuplicatedStrings(items, this.caseSensitive)) {
|
|
350
|
-
this.updateItems(items);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
if (closeInput) {
|
|
355
|
-
this.toggleEditMode(false);
|
|
356
|
-
}
|
|
357
|
-
},
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* Add a new or update an exiting item in the items list.
|
|
361
|
-
*
|
|
362
|
-
* @param items The current items list.
|
|
363
|
-
* @param value The new value to be added.
|
|
364
|
-
* @param index The list index of the item to be updated (optional).
|
|
365
|
-
* @returns Updated items list.
|
|
366
|
-
*/
|
|
367
|
-
addValueToItems(items: string[], value: string, index?: number): string[] {
|
|
368
|
-
const updatedItems = [...items];
|
|
369
|
-
|
|
370
|
-
// Add new item
|
|
371
|
-
if (index === undefined) {
|
|
372
|
-
if (this.bulkAdditionDelimiter && value.search(this.bulkAdditionDelimiter) >= 0) {
|
|
373
|
-
updatedItems.push(...this.splitBulkValue(value));
|
|
374
|
-
} else {
|
|
375
|
-
updatedItems.push(value);
|
|
376
|
-
}
|
|
377
|
-
} else { // Update existing item
|
|
378
|
-
if (this.bulkAdditionDelimiter && value.search(this.bulkAdditionDelimiter) >= 0) {
|
|
379
|
-
updatedItems.splice(index, 1, ...this.splitBulkValue(value));
|
|
380
|
-
} else {
|
|
381
|
-
updatedItems[index] = value;
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
return updatedItems;
|
|
386
|
-
},
|
|
387
|
-
|
|
388
|
-
/**
|
|
389
|
-
* Split the value by the defined delimiter and remove empty strings.
|
|
390
|
-
*
|
|
391
|
-
* @param value The value to be split.
|
|
392
|
-
* @returns Array containing split values.
|
|
393
|
-
*/
|
|
394
|
-
splitBulkValue(value: string): string[] {
|
|
395
|
-
return value
|
|
396
|
-
.split(this.bulkAdditionDelimiter)
|
|
397
|
-
.filter((item) => {
|
|
398
|
-
return item.trim().length > 0;
|
|
399
|
-
});
|
|
400
|
-
},
|
|
401
|
-
|
|
402
|
-
/**
|
|
403
|
-
* Remove an item from items list
|
|
404
|
-
*/
|
|
405
|
-
deleteItem(item?: string) {
|
|
406
|
-
const items = this.items.filter((f) => f !== item);
|
|
407
|
-
|
|
408
|
-
this.updateItems(items);
|
|
409
|
-
},
|
|
410
|
-
|
|
411
|
-
/**
|
|
412
|
-
* Update items list and emit to parent component
|
|
413
|
-
*/
|
|
414
|
-
updateItems(items: string[]) {
|
|
415
|
-
this.$emit('change', items);
|
|
416
|
-
},
|
|
417
|
-
},
|
|
418
|
-
|
|
419
|
-
});
|
|
420
|
-
</script>
|
|
421
|
-
|
|
422
|
-
<template>
|
|
423
|
-
<div
|
|
424
|
-
class="string-list"
|
|
425
|
-
:class="{ readonly }"
|
|
426
|
-
>
|
|
427
|
-
<div
|
|
428
|
-
ref="box"
|
|
429
|
-
data-testid="div-string-list-box"
|
|
430
|
-
class="string-list-box"
|
|
431
|
-
tabindex="0"
|
|
432
|
-
@dblclick="onClickEmptyBody()"
|
|
433
|
-
>
|
|
434
|
-
<div
|
|
435
|
-
v-for="(item, index) in items"
|
|
436
|
-
:key="item"
|
|
437
|
-
:ref="item"
|
|
438
|
-
:class="{
|
|
439
|
-
selected: selected === item,
|
|
440
|
-
readonly
|
|
441
|
-
}"
|
|
442
|
-
:data-testid="`div-item-${item}`"
|
|
443
|
-
class="item static"
|
|
444
|
-
tabindex="0"
|
|
445
|
-
@mousedown="onSelect(item)"
|
|
446
|
-
@dblclick.stop="toggleEditMode(true, item)"
|
|
447
|
-
@keydown.down.prevent="onSelectNext('down')"
|
|
448
|
-
@keydown.up.prevent="onSelectNext('up')"
|
|
449
|
-
@blur="onSelectLeave(item)"
|
|
450
|
-
>
|
|
451
|
-
<span
|
|
452
|
-
v-if="!editedItem || editedItem !== item"
|
|
453
|
-
class="label static"
|
|
454
|
-
>
|
|
455
|
-
{{ item }}
|
|
456
|
-
</span>
|
|
457
|
-
<LabeledInput
|
|
458
|
-
v-if="editedItem && editedItem === item"
|
|
459
|
-
ref="item-edit"
|
|
460
|
-
:data-testid="`item-edit-${item}`"
|
|
461
|
-
class="edit-input static"
|
|
462
|
-
:value="value != null ? value : item"
|
|
463
|
-
@input="onChange($event, index)"
|
|
464
|
-
@blur.prevent="updateItem(item)"
|
|
465
|
-
@keydown.native.enter="updateItem(item, !errors.duplicate)"
|
|
466
|
-
/>
|
|
467
|
-
</div>
|
|
468
|
-
<div
|
|
469
|
-
v-if="isCreateItem"
|
|
470
|
-
class="create-field static"
|
|
471
|
-
>
|
|
472
|
-
<LabeledInput
|
|
473
|
-
ref="item-create"
|
|
474
|
-
data-testid="item-create"
|
|
475
|
-
class="create-input static"
|
|
476
|
-
type="text"
|
|
477
|
-
:value="value"
|
|
478
|
-
:placeholder="placeholder"
|
|
479
|
-
@input="onChange($event)"
|
|
480
|
-
@blur.prevent="saveItem"
|
|
481
|
-
@keydown.native.enter="saveItem(!errors.duplicate)"
|
|
482
|
-
/>
|
|
483
|
-
</div>
|
|
484
|
-
</div>
|
|
485
|
-
<div
|
|
486
|
-
v-if="!readonly"
|
|
487
|
-
class="string-list-footer"
|
|
488
|
-
:class="{[actionsPosition]: true }"
|
|
489
|
-
>
|
|
490
|
-
<div
|
|
491
|
-
data-testid="div-action-buttons"
|
|
492
|
-
class="action-buttons"
|
|
493
|
-
>
|
|
494
|
-
<button
|
|
495
|
-
data-testid="button-remove"
|
|
496
|
-
class="btn btn-sm role-tertiary remove-button"
|
|
497
|
-
:disabled="!selected && !isCreateItem && !editedItem"
|
|
498
|
-
@mousedown.prevent="onClickMinusButton"
|
|
499
|
-
>
|
|
500
|
-
<span class="icon icon-minus icon-sm" />
|
|
501
|
-
</button>
|
|
502
|
-
<button
|
|
503
|
-
data-testid="button-add"
|
|
504
|
-
class="btn btn-sm role-tertiary add-button"
|
|
505
|
-
:disabled="!!isCreateItem || !!editedItem"
|
|
506
|
-
@click.prevent="onClickPlusButton"
|
|
507
|
-
>
|
|
508
|
-
<span class="icon icon-plus icon-sm" />
|
|
509
|
-
</button>
|
|
510
|
-
</div>
|
|
511
|
-
<div class="messages">
|
|
512
|
-
<i
|
|
513
|
-
v-if="errorMessagesArray.length > 0"
|
|
514
|
-
data-testid="i-warning-icon"
|
|
515
|
-
class="icon icon-warning icon-lg"
|
|
516
|
-
/>
|
|
517
|
-
<span
|
|
518
|
-
v-for="(msg, idx) in errorMessagesArray"
|
|
519
|
-
:key="idx"
|
|
520
|
-
:data-testid="`span-error-message-${msg}`"
|
|
521
|
-
class="error"
|
|
522
|
-
>
|
|
523
|
-
{{ idx > 0 ? '; ' : '' }}
|
|
524
|
-
{{ msg }}
|
|
525
|
-
</span>
|
|
526
|
-
</div>
|
|
527
|
-
</div>
|
|
528
|
-
</div>
|
|
529
|
-
</template>
|
|
530
|
-
|
|
531
|
-
<style lang="scss" scoped>
|
|
532
|
-
|
|
533
|
-
.string-list {
|
|
534
|
-
display: flex;
|
|
535
|
-
flex-direction: column;
|
|
536
|
-
width: auto;
|
|
537
|
-
|
|
538
|
-
&.readonly {
|
|
539
|
-
cursor: default;
|
|
540
|
-
opacity: 0.4;
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
.string-list-box {
|
|
544
|
-
min-height: 200px;
|
|
545
|
-
height: 100%;
|
|
546
|
-
outline: none;
|
|
547
|
-
overflow-y: auto;
|
|
548
|
-
overflow-x: hidden;
|
|
549
|
-
border: solid var(--border-width) var(--input-border);
|
|
550
|
-
padding-top: 3px;
|
|
551
|
-
|
|
552
|
-
.static {
|
|
553
|
-
height: 25px;
|
|
554
|
-
padding: 3px;
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
.item {
|
|
558
|
-
outline: none;
|
|
559
|
-
|
|
560
|
-
&.selected {
|
|
561
|
-
background: var(--primary);
|
|
562
|
-
color: var(--primary-hover-text);
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
&.readonly {
|
|
566
|
-
pointer-events: none;
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
.label {
|
|
570
|
-
display: block;
|
|
571
|
-
width: auto;
|
|
572
|
-
user-select: none;
|
|
573
|
-
overflow: hidden;
|
|
574
|
-
white-space: no-wrap;
|
|
575
|
-
text-overflow: ellipsis;
|
|
576
|
-
padding-top: 1px;
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
.create-field {
|
|
581
|
-
padding-top: 1px;
|
|
582
|
-
margin-bottom: 7px;
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
.labeled-input {
|
|
586
|
-
padding-top: 0;
|
|
587
|
-
padding-bottom: 0;
|
|
588
|
-
border-radius: 0;
|
|
589
|
-
&.error {
|
|
590
|
-
border: none;
|
|
591
|
-
box-shadow: 0 0 0 var(--outline-width) var(--error);
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
.string-list-footer {
|
|
597
|
-
--footer-height: 28px;
|
|
598
|
-
height: var(--footer-height);
|
|
599
|
-
margin-top: 5px;
|
|
600
|
-
display: flex;
|
|
601
|
-
justify-content: space-between;
|
|
602
|
-
gap: 0.5rem;
|
|
603
|
-
|
|
604
|
-
&.left {
|
|
605
|
-
flex-direction: row;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
&.right {
|
|
609
|
-
flex-direction: row-reverse;
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
.action-buttons {
|
|
613
|
-
display: flex;
|
|
614
|
-
flex-direction: row-reverse;
|
|
615
|
-
gap: 0.5rem;
|
|
616
|
-
|
|
617
|
-
.btn {
|
|
618
|
-
min-height: var(--footer-height);
|
|
619
|
-
line-height: 0;
|
|
620
|
-
border-radius: 2px;
|
|
621
|
-
|
|
622
|
-
&:disabled {
|
|
623
|
-
cursor: default;
|
|
624
|
-
pointer-events: none;
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
.messages {
|
|
630
|
-
line-height: var(--footer-height);
|
|
631
|
-
|
|
632
|
-
.error, .icon-warning {
|
|
633
|
-
color: var(--error);
|
|
634
|
-
line-height: inherit;
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
::v-deep {
|
|
641
|
-
.labeled-input INPUT.no-label,
|
|
642
|
-
.labeled-input INPUT:hover.no-label,
|
|
643
|
-
.labeled-input INPUT:focus.no-label {
|
|
644
|
-
padding: 1px 0px 0px 0px;
|
|
645
|
-
}
|
|
646
|
-
.labeled-input.compact-input {
|
|
647
|
-
min-height: 0;
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
</style>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default as StringList } from './StringList.vue';
|