@rancher/shell 0.3.13 → 0.3.14
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 +6 -0
- package/components/.DS_Store +0 -0
- package/components/HarvesterServiceAddOnConfig.vue +115 -1
- package/components/__tests__/.DS_Store +0 -0
- package/config/labels-annotations.js +1 -0
- package/creators/app/files/.gitignore +0 -3
- package/creators/pkg/package-lock.json +37 -0
- package/package.json +1 -1
- package/rancher-components/StringList/StringList.test.ts +80 -0
- package/rancher-components/StringList/StringList.vue +593 -0
- package/rancher-components/StringList/index.ts +1 -0
- package/types/shell/index.d.ts +9 -9
- package/yarn-error.log +196 -0
|
Binary file
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
<script>
|
|
2
|
+
import { mapGetters } from 'vuex';
|
|
3
|
+
import semver from 'semver';
|
|
4
|
+
|
|
2
5
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
|
3
6
|
import { _CREATE } from '@shell/config/query-params';
|
|
4
7
|
import { get } from '@shell/utils/object';
|
|
5
8
|
import { HCI as HCI_LABELS_ANNOTATIONS } from '@shell/config/labels-annotations';
|
|
9
|
+
import { SERVICE } from '@shell/config/types';
|
|
10
|
+
import { allHash } from '@shell/utils/promise';
|
|
6
11
|
|
|
7
12
|
const HARVESTER_ADD_ON_CONFIG = [{
|
|
8
13
|
variableName: 'ipam',
|
|
9
14
|
key: HCI_LABELS_ANNOTATIONS.CLOUD_PROVIDER_IPAM,
|
|
10
15
|
default: 'dhcp'
|
|
16
|
+
}, {
|
|
17
|
+
variableName: 'sharedService',
|
|
18
|
+
key: HCI_LABELS_ANNOTATIONS.PRIMARY_SERVICE,
|
|
19
|
+
default: ''
|
|
11
20
|
}];
|
|
12
21
|
|
|
13
22
|
export default {
|
|
@@ -38,6 +47,19 @@ export default {
|
|
|
38
47
|
}
|
|
39
48
|
},
|
|
40
49
|
|
|
50
|
+
async fetch() {
|
|
51
|
+
const inStore = this.$store.getters['currentProduct'].inStore;
|
|
52
|
+
|
|
53
|
+
const hash = {
|
|
54
|
+
rke2Versions: this.$store.dispatch('management/request', { url: '/v1-rke2-release/releases' }),
|
|
55
|
+
services: this.$store.dispatch(`${ inStore }/findAll`, { type: SERVICE }),
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const res = await allHash(hash);
|
|
59
|
+
|
|
60
|
+
this.rke2Versions = res.rke2Versions;
|
|
61
|
+
},
|
|
62
|
+
|
|
41
63
|
data() {
|
|
42
64
|
const harvesterAddOnConfig = {};
|
|
43
65
|
|
|
@@ -45,10 +67,24 @@ export default {
|
|
|
45
67
|
harvesterAddOnConfig[c.variableName] = this.value.metadata.annotations[c.key] || c.default;
|
|
46
68
|
});
|
|
47
69
|
|
|
48
|
-
|
|
70
|
+
let showShareIP;
|
|
71
|
+
|
|
72
|
+
if (this.value.metadata.annotations[HCI_LABELS_ANNOTATIONS.PRIMARY_SERVICE]) {
|
|
73
|
+
showShareIP = true;
|
|
74
|
+
} else {
|
|
75
|
+
showShareIP = false;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
...harvesterAddOnConfig,
|
|
80
|
+
showShareIP,
|
|
81
|
+
rke2Versions: {},
|
|
82
|
+
};
|
|
49
83
|
},
|
|
50
84
|
|
|
51
85
|
computed: {
|
|
86
|
+
...mapGetters(['allowedNamespaces', 'namespaces', 'currentCluster']),
|
|
87
|
+
|
|
52
88
|
ipamOptions() {
|
|
53
89
|
return [{
|
|
54
90
|
label: 'DHCP',
|
|
@@ -64,13 +100,71 @@ export default {
|
|
|
64
100
|
|
|
65
101
|
return ports.filter(p => p.port && p.protocol === 'TCP').map(p => p.port) || [];
|
|
66
102
|
},
|
|
103
|
+
|
|
104
|
+
serviceOptions() {
|
|
105
|
+
const inStore = this.$store.getters['currentProduct'].inStore;
|
|
106
|
+
const services = this.$store.getters[`${ inStore }/all`](SERVICE);
|
|
107
|
+
|
|
108
|
+
const namespaces = this.namespaces();
|
|
109
|
+
|
|
110
|
+
const out = services.filter((s) => {
|
|
111
|
+
const ingress = s?.status?.loadBalancer?.ingress || [];
|
|
112
|
+
|
|
113
|
+
return ingress.length > 0 &&
|
|
114
|
+
!s?.metadata?.annotations?.['cloudprovider.harvesterhci.io/primary-service'] &&
|
|
115
|
+
s.spec?.type === 'LoadBalancer' &&
|
|
116
|
+
namespaces[s.metadata.namespace];
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
return out.map(s => s.id);
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
shareIPEnabled() {
|
|
123
|
+
const kubernetesVersion = this.currentCluster.kubernetesVersion || '';
|
|
124
|
+
const kubernetesVersionExtension = this.currentCluster.kubernetesVersionExtension;
|
|
125
|
+
|
|
126
|
+
if (kubernetesVersionExtension.startsWith('+rke2')) {
|
|
127
|
+
const charts = ((this.rke2Versions?.data || []).find(v => v.id === kubernetesVersion) || {}).charts;
|
|
128
|
+
let ccmVersion = charts?.['harvester-cloud-provider']?.version || '';
|
|
129
|
+
|
|
130
|
+
if (ccmVersion.endsWith('00')) {
|
|
131
|
+
ccmVersion = ccmVersion.slice(0, -2);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return semver.satisfies(ccmVersion, '>=0.2.0');
|
|
135
|
+
} else {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
},
|
|
67
139
|
},
|
|
68
140
|
|
|
69
141
|
methods: {
|
|
70
142
|
willSave() {
|
|
143
|
+
const errors = [];
|
|
144
|
+
|
|
145
|
+
if (this.showShareIP) {
|
|
146
|
+
if (!this.sharedService) {
|
|
147
|
+
errors.push(this.t('validation.required', { key: this.t('servicesPage.harvester.shareIP.label') }, true));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (errors.length > 0) {
|
|
152
|
+
return Promise.reject(errors);
|
|
153
|
+
}
|
|
154
|
+
|
|
71
155
|
HARVESTER_ADD_ON_CONFIG.forEach((c) => {
|
|
72
156
|
this.value.metadata.annotations[c.key] = String(get(this, c.variableName));
|
|
73
157
|
});
|
|
158
|
+
|
|
159
|
+
if (this.showShareIP) {
|
|
160
|
+
delete this.value.metadata.annotations[HCI_LABELS_ANNOTATIONS.CLOUD_PROVIDER_IPAM];
|
|
161
|
+
} else {
|
|
162
|
+
delete this.value.metadata.annotations[HCI_LABELS_ANNOTATIONS.PRIMARY_SERVICE];
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
toggleShareIP() {
|
|
167
|
+
this.showShareIP = !this.showShareIP;
|
|
74
168
|
},
|
|
75
169
|
},
|
|
76
170
|
};
|
|
@@ -81,11 +175,31 @@ export default {
|
|
|
81
175
|
<div class="row mt-30">
|
|
82
176
|
<div class="col span-6">
|
|
83
177
|
<LabeledSelect
|
|
178
|
+
v-if="showShareIP"
|
|
179
|
+
v-model="sharedService"
|
|
180
|
+
:mode="mode"
|
|
181
|
+
:options="serviceOptions"
|
|
182
|
+
:label="t('servicesPage.harvester.shareIP.label')"
|
|
183
|
+
:disabled="mode === 'edit'"
|
|
184
|
+
/>
|
|
185
|
+
<LabeledSelect
|
|
186
|
+
v-else
|
|
84
187
|
v-model="ipam"
|
|
85
188
|
:mode="mode"
|
|
86
189
|
:options="ipamOptions"
|
|
87
190
|
:label="t('servicesPage.harvester.ipam.label')"
|
|
88
191
|
/>
|
|
192
|
+
<div
|
|
193
|
+
v-if="mode === 'create'"
|
|
194
|
+
class="mt-10"
|
|
195
|
+
>
|
|
196
|
+
<a
|
|
197
|
+
role="button"
|
|
198
|
+
@click="toggleShareIP"
|
|
199
|
+
>
|
|
200
|
+
{{ showShareIP ? t('servicesPage.harvester.useIpam.label') : t('servicesPage.harvester.useShareIP.label') }}
|
|
201
|
+
</a>
|
|
202
|
+
</div>
|
|
89
203
|
</div>
|
|
90
204
|
</div>
|
|
91
205
|
</div>
|
|
Binary file
|
|
@@ -138,6 +138,7 @@ export const HCI = {
|
|
|
138
138
|
CLOUD_PROVIDER_NAMESPACE: 'cloudprovider.harvesterhci.io/namespace',
|
|
139
139
|
CLOUD_PROVIDER_NETWORK: 'cloudprovider.harvesterhci.io/network',
|
|
140
140
|
CLOUD_PROVIDER_PROJECT: 'cloudprovider.harvesterhci.io/project',
|
|
141
|
+
PRIMARY_SERVICE: 'cloudprovider.harvesterhci.io/primary-service',
|
|
141
142
|
};
|
|
142
143
|
|
|
143
144
|
// Annotations that can be on management.cattle.io.cluster to configure a custom badge
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rancher/create-pkg",
|
|
3
|
+
"version": "0.1.37",
|
|
4
|
+
"lockfileVersion": 1,
|
|
5
|
+
"requires": true,
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"fs-extra": {
|
|
8
|
+
"version": "10.1.0",
|
|
9
|
+
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
|
|
10
|
+
"integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
|
|
11
|
+
"requires": {
|
|
12
|
+
"graceful-fs": "^4.2.0",
|
|
13
|
+
"jsonfile": "^6.0.1",
|
|
14
|
+
"universalify": "^2.0.0"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"graceful-fs": {
|
|
18
|
+
"version": "4.2.10",
|
|
19
|
+
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
|
|
20
|
+
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
|
|
21
|
+
},
|
|
22
|
+
"jsonfile": {
|
|
23
|
+
"version": "6.1.0",
|
|
24
|
+
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
|
|
25
|
+
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
|
|
26
|
+
"requires": {
|
|
27
|
+
"graceful-fs": "^4.1.6",
|
|
28
|
+
"universalify": "^2.0.0"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"universalify": {
|
|
32
|
+
"version": "2.0.0",
|
|
33
|
+
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
|
34
|
+
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { StringList } from './index';
|
|
3
|
+
|
|
4
|
+
describe('StringList.vue', () => {
|
|
5
|
+
|
|
6
|
+
it('is empty', () => {
|
|
7
|
+
const wrapper = mount(StringList, {
|
|
8
|
+
propsData: { items: [] },
|
|
9
|
+
});
|
|
10
|
+
const box = wrapper.find('[data-testid="div-string-list-box"]').element as HTMLElement;
|
|
11
|
+
|
|
12
|
+
expect(box.children.length).toBe(0);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('is showing one element', () => {
|
|
16
|
+
const wrapper = mount(StringList, {
|
|
17
|
+
propsData: { items: ['test'] },
|
|
18
|
+
});
|
|
19
|
+
const box = wrapper.find('.string-list-box').element as HTMLElement;
|
|
20
|
+
|
|
21
|
+
expect(box.children.length).toBe(1);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('action-buttons are visible', () => {
|
|
25
|
+
const wrapper = mount(StringList, {
|
|
26
|
+
propsData: { items: ['test'] },
|
|
27
|
+
});
|
|
28
|
+
const actionButtons = wrapper.find('[data-testid="div-action-buttons"]').element as HTMLElement;
|
|
29
|
+
|
|
30
|
+
expect(actionButtons).not.toBe(undefined);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('action-buttons are hidden when is view-only mode', () => {
|
|
34
|
+
const wrapper = mount(StringList, {
|
|
35
|
+
propsData: {
|
|
36
|
+
items: ['test'],
|
|
37
|
+
readonly: true,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
const actionButtons = wrapper.find('[data-testid="div-action-buttons"]').element as HTMLElement;
|
|
41
|
+
|
|
42
|
+
expect(actionButtons).toBe(undefined);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('show new item when "items" property change', async () => {
|
|
46
|
+
const items = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k'];
|
|
47
|
+
|
|
48
|
+
const wrapper = mount(StringList, {
|
|
49
|
+
propsData: {
|
|
50
|
+
items,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
const elements = wrapper.findAll('[data-testid^="div-item"]');
|
|
54
|
+
|
|
55
|
+
expect(elements.length).toBe(10);
|
|
56
|
+
|
|
57
|
+
await wrapper.setProps({ items: [ ...items, 'new' ] });
|
|
58
|
+
|
|
59
|
+
const newElements = wrapper.findAll('[data-testid^="div-item"]');
|
|
60
|
+
expect(newElements.length).toBe(11);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('remove item when "items" property change', async () => {
|
|
64
|
+
const items = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k'];
|
|
65
|
+
|
|
66
|
+
const wrapper = mount(StringList, {
|
|
67
|
+
propsData: {
|
|
68
|
+
items,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
const elements = wrapper.findAll('[data-testid^="div-item"]');
|
|
72
|
+
expect(elements.length).toBe(10);
|
|
73
|
+
|
|
74
|
+
await wrapper.setProps({ items: [ ...items.filter(f => f !== 'a') ] });
|
|
75
|
+
|
|
76
|
+
const newElements = wrapper.findAll('[data-testid^="div-item"]');
|
|
77
|
+
expect(newElements.length).toBe(9);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
});
|
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Vue, { PropType } 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 Vue.extend({
|
|
33
|
+
components: { LabeledInput },
|
|
34
|
+
|
|
35
|
+
name: 'StringList',
|
|
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
|
+
data() {
|
|
87
|
+
return {
|
|
88
|
+
value: null as string | null,
|
|
89
|
+
selected: null as string | null,
|
|
90
|
+
editedItem: null as string | null,
|
|
91
|
+
isCreateItem: false,
|
|
92
|
+
errors: { duplicate: false } as Record<Error, boolean>
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
computed: {
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Create an array of error messages, one for each current error
|
|
100
|
+
*/
|
|
101
|
+
errorMessagesArray(): string[] {
|
|
102
|
+
return (Object.keys(this.errors) as Error[])
|
|
103
|
+
.filter(f => this.errors[f] && this.errorMessages[f])
|
|
104
|
+
.map(k => this.errorMessages[k]);
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
watch: {
|
|
109
|
+
/**
|
|
110
|
+
* Shutdown any user actions on the component when it becomes readonly
|
|
111
|
+
*/
|
|
112
|
+
readonly() {
|
|
113
|
+
this.toggleEditMode(false);
|
|
114
|
+
this.toggleCreateMode(false);
|
|
115
|
+
},
|
|
116
|
+
errors: {
|
|
117
|
+
handler(val) {
|
|
118
|
+
this.$emit('errors', val);
|
|
119
|
+
},
|
|
120
|
+
deep: true
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
methods: {
|
|
125
|
+
onChange(value: string) {
|
|
126
|
+
this.value = value;
|
|
127
|
+
|
|
128
|
+
const items = [
|
|
129
|
+
...this.items,
|
|
130
|
+
this.value
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
this.toggleError(
|
|
134
|
+
'duplicate',
|
|
135
|
+
hasDuplicatedStrings(items, this.caseSensitive),
|
|
136
|
+
this.isCreateItem ? INPUT.create : INPUT.edit
|
|
137
|
+
);
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
onSelect(item: string) {
|
|
141
|
+
if (this.readonly || this.isCreateItem || this.editedItem === item) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
this.selected = item;
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
onSelectNext(arrow: Arrow) {
|
|
148
|
+
const index = findStringIndex(
|
|
149
|
+
this.items,
|
|
150
|
+
this.selected as string,
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
if (index !== -1) {
|
|
154
|
+
/**
|
|
155
|
+
* Select next item in the arrow's direction if it exists,
|
|
156
|
+
* else select again this.selected (do nothing)
|
|
157
|
+
*/
|
|
158
|
+
const item = (this.items[index + DIRECTION[arrow]] || this.selected) as string;
|
|
159
|
+
|
|
160
|
+
this.onSelect(item);
|
|
161
|
+
this.moveScrollbar(arrow);
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
onSelectLeave(item?: string) {
|
|
166
|
+
if (item === this.selected) {
|
|
167
|
+
this.selected = null;
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
onClickEmptyBody() {
|
|
172
|
+
if (!this.isCreateItem && !this.editedItem) {
|
|
173
|
+
this.toggleCreateMode(true);
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
onClickPlusButton() {
|
|
178
|
+
this.onSelectLeave();
|
|
179
|
+
this.toggleCreateMode(true);
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
onClickMinusButton() {
|
|
183
|
+
if (this.isCreateItem) {
|
|
184
|
+
this.toggleCreateMode(false);
|
|
185
|
+
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (this.editedItem) {
|
|
189
|
+
this.toggleEditMode(false);
|
|
190
|
+
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (this.selected) {
|
|
194
|
+
const index = findStringIndex(this.items, this.selected, false);
|
|
195
|
+
|
|
196
|
+
if (index !== -1) {
|
|
197
|
+
/**
|
|
198
|
+
* Select the next item in the list when an item is to be deleted.
|
|
199
|
+
*/
|
|
200
|
+
const item = (this.items[index + 1] || this.items[index - 1]);
|
|
201
|
+
|
|
202
|
+
this.onSelect(item);
|
|
203
|
+
this.setFocus(item);
|
|
204
|
+
|
|
205
|
+
this.deleteItem(this.items[index]);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
setFocus(refId: string) {
|
|
211
|
+
this.$nextTick(() => this.getElemByRef(refId)?.focus());
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Move scrollbar when the selected item is over the top or bottom side of the box
|
|
216
|
+
*/
|
|
217
|
+
moveScrollbar(arrow: Arrow, value?: number) {
|
|
218
|
+
const box = this.getElemByRef(BOX);
|
|
219
|
+
const item = this.getElemByRef(this.selected || '');
|
|
220
|
+
|
|
221
|
+
if (box && item && item.className.includes(CLASS.item)) {
|
|
222
|
+
const boxRect = box.getClientRects()[0];
|
|
223
|
+
const itemRect = item.getClientRects()[0];
|
|
224
|
+
|
|
225
|
+
if (
|
|
226
|
+
(arrow === 'down' && itemRect.bottom > boxRect.bottom) ||
|
|
227
|
+
(arrow === 'up' && itemRect.top < boxRect.top)
|
|
228
|
+
) {
|
|
229
|
+
const top = (value ?? itemRect.height) * DIRECTION[arrow];
|
|
230
|
+
|
|
231
|
+
box.scrollBy({ top });
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Set an error and eventually assign an error class to the element
|
|
238
|
+
*/
|
|
239
|
+
toggleError(type: Error, val: boolean, refId?: string) {
|
|
240
|
+
this.errors[type] = val;
|
|
241
|
+
|
|
242
|
+
if (refId) {
|
|
243
|
+
this.toggleErrorClass(refId, val);
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
toggleErrorClass(refId: string, val: boolean) {
|
|
248
|
+
const input = this.getElemByRef(refId)?.$el;
|
|
249
|
+
|
|
250
|
+
if (input) {
|
|
251
|
+
if (val) {
|
|
252
|
+
input.classList.add(CLASS.error);
|
|
253
|
+
} else {
|
|
254
|
+
input.classList.remove(CLASS.error);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Show/Hide the input line to create new item
|
|
261
|
+
*/
|
|
262
|
+
toggleCreateMode(show: boolean) {
|
|
263
|
+
if (this.readonly) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (show) {
|
|
267
|
+
this.toggleEditMode(false);
|
|
268
|
+
this.value = '';
|
|
269
|
+
|
|
270
|
+
this.isCreateItem = true;
|
|
271
|
+
this.setFocus(INPUT.create);
|
|
272
|
+
} else {
|
|
273
|
+
this.value = null;
|
|
274
|
+
this.toggleError('duplicate', false);
|
|
275
|
+
this.onSelectLeave();
|
|
276
|
+
|
|
277
|
+
this.isCreateItem = false;
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Show/Hide the in-line editing to edit an existing item
|
|
283
|
+
*/
|
|
284
|
+
toggleEditMode(show: boolean, item?: string) {
|
|
285
|
+
if (this.readonly) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
if (show) {
|
|
289
|
+
this.toggleCreateMode(false);
|
|
290
|
+
this.value = this.editedItem;
|
|
291
|
+
|
|
292
|
+
this.editedItem = item || '';
|
|
293
|
+
this.setFocus(INPUT.edit);
|
|
294
|
+
} else {
|
|
295
|
+
this.value = null;
|
|
296
|
+
this.toggleError('duplicate', false);
|
|
297
|
+
this.onSelectLeave();
|
|
298
|
+
|
|
299
|
+
this.editedItem = null;
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
|
|
303
|
+
getElemByRef(id: string) {
|
|
304
|
+
const ref = this.$refs[id];
|
|
305
|
+
|
|
306
|
+
return (Array.isArray(ref) ? ref[0] : ref) as any;
|
|
307
|
+
},
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Create a new item and insert in the items list
|
|
311
|
+
*/
|
|
312
|
+
saveItem(closeInput = true) {
|
|
313
|
+
const value = this.value?.trim();
|
|
314
|
+
|
|
315
|
+
if (value) {
|
|
316
|
+
const items = [
|
|
317
|
+
...this.items,
|
|
318
|
+
value,
|
|
319
|
+
];
|
|
320
|
+
|
|
321
|
+
if (!hasDuplicatedStrings(items, this.caseSensitive)) {
|
|
322
|
+
this.updateItems(items);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (closeInput) {
|
|
327
|
+
this.toggleCreateMode(false);
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Update an existing item in the items list
|
|
333
|
+
*/
|
|
334
|
+
updateItem(item: string, closeInput = true) {
|
|
335
|
+
const value = this.value?.trim();
|
|
336
|
+
|
|
337
|
+
if (value) {
|
|
338
|
+
const items = [...this.items];
|
|
339
|
+
const index = findStringIndex(items, item, false);
|
|
340
|
+
|
|
341
|
+
if (index !== -1) {
|
|
342
|
+
items[index] = value;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (!hasDuplicatedStrings(items, this.caseSensitive)) {
|
|
346
|
+
this.updateItems(items);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (closeInput) {
|
|
351
|
+
this.toggleEditMode(false);
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Remove an item from items list
|
|
357
|
+
*/
|
|
358
|
+
deleteItem(item?: string) {
|
|
359
|
+
const items = this.items.filter(f => f !== item);
|
|
360
|
+
|
|
361
|
+
this.updateItems(items);
|
|
362
|
+
},
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Update items list and emit to parent component
|
|
366
|
+
*/
|
|
367
|
+
updateItems(items: string[]) {
|
|
368
|
+
this.$emit('change', items);
|
|
369
|
+
},
|
|
370
|
+
},
|
|
371
|
+
|
|
372
|
+
});
|
|
373
|
+
</script>
|
|
374
|
+
|
|
375
|
+
<template>
|
|
376
|
+
<div
|
|
377
|
+
class="string-list"
|
|
378
|
+
:class="{ readonly }"
|
|
379
|
+
>
|
|
380
|
+
<div
|
|
381
|
+
ref="box"
|
|
382
|
+
data-testid="div-string-list-box"
|
|
383
|
+
class="string-list-box"
|
|
384
|
+
tabindex="0"
|
|
385
|
+
@dblclick="onClickEmptyBody()"
|
|
386
|
+
>
|
|
387
|
+
<div
|
|
388
|
+
v-for="item in items"
|
|
389
|
+
:key="item"
|
|
390
|
+
:ref="item"
|
|
391
|
+
:class="{
|
|
392
|
+
selected: selected === item,
|
|
393
|
+
readonly
|
|
394
|
+
}"
|
|
395
|
+
:data-testid="`div-item-${item}`"
|
|
396
|
+
class="item static"
|
|
397
|
+
tabindex="0"
|
|
398
|
+
@mousedown="onSelect(item)"
|
|
399
|
+
@dblclick.stop="toggleEditMode(true, item)"
|
|
400
|
+
@keydown.down.prevent="onSelectNext('down')"
|
|
401
|
+
@keydown.up.prevent="onSelectNext('up')"
|
|
402
|
+
@blur="onSelectLeave(item)"
|
|
403
|
+
>
|
|
404
|
+
<span
|
|
405
|
+
v-if="!editedItem || editedItem !== item"
|
|
406
|
+
class="label static"
|
|
407
|
+
>
|
|
408
|
+
{{ item }}
|
|
409
|
+
</span>
|
|
410
|
+
<LabeledInput
|
|
411
|
+
v-if="editedItem && editedItem === item"
|
|
412
|
+
ref="item-edit"
|
|
413
|
+
class="edit-input static"
|
|
414
|
+
:value="value != null ? value : item"
|
|
415
|
+
@input="onChange($event)"
|
|
416
|
+
@blur.prevent="updateItem(item)"
|
|
417
|
+
@keydown.native.enter="updateItem(item, !errors.duplicate)"
|
|
418
|
+
/>
|
|
419
|
+
</div>
|
|
420
|
+
<div
|
|
421
|
+
v-if="isCreateItem"
|
|
422
|
+
class="create-field static"
|
|
423
|
+
>
|
|
424
|
+
<LabeledInput
|
|
425
|
+
ref="item-create"
|
|
426
|
+
class="create-input static"
|
|
427
|
+
type="text"
|
|
428
|
+
:value="value"
|
|
429
|
+
:placeholder="placeholder"
|
|
430
|
+
@input="onChange($event)"
|
|
431
|
+
@blur.prevent="saveItem"
|
|
432
|
+
@keydown.native.enter="saveItem(!errors.duplicate)"
|
|
433
|
+
/>
|
|
434
|
+
</div>
|
|
435
|
+
</div>
|
|
436
|
+
<div
|
|
437
|
+
v-if="!readonly"
|
|
438
|
+
class="string-list-footer"
|
|
439
|
+
:class="{[actionsPosition]: true }"
|
|
440
|
+
>
|
|
441
|
+
<div
|
|
442
|
+
data-testid="div-action-buttons"
|
|
443
|
+
class="action-buttons"
|
|
444
|
+
>
|
|
445
|
+
<button
|
|
446
|
+
class="btn btn-sm role-tertiary remove-button"
|
|
447
|
+
:disabled="!selected && !isCreateItem && !editedItem"
|
|
448
|
+
@mousedown.prevent="onClickMinusButton"
|
|
449
|
+
>
|
|
450
|
+
<span class="icon icon-minus icon-sm" />
|
|
451
|
+
</button>
|
|
452
|
+
<button
|
|
453
|
+
class="btn btn-sm role-tertiary add-button"
|
|
454
|
+
:disabled="isCreateItem || editedItem"
|
|
455
|
+
@click.prevent="onClickPlusButton"
|
|
456
|
+
>
|
|
457
|
+
<span class="icon icon-plus icon-sm" />
|
|
458
|
+
</button>
|
|
459
|
+
</div>
|
|
460
|
+
<div class="messages">
|
|
461
|
+
<i v-if="errorMessagesArray.length > 0" class="icon icon-warning icon-lg" />
|
|
462
|
+
<span
|
|
463
|
+
v-for="(msg, idx) in errorMessagesArray"
|
|
464
|
+
:key="idx"
|
|
465
|
+
class="error"
|
|
466
|
+
>
|
|
467
|
+
{{ idx > 0 ? '; ' : '' }}
|
|
468
|
+
{{ msg }}
|
|
469
|
+
</span>
|
|
470
|
+
</div>
|
|
471
|
+
</div>
|
|
472
|
+
</div>
|
|
473
|
+
</template>
|
|
474
|
+
|
|
475
|
+
<style lang="scss" scoped>
|
|
476
|
+
|
|
477
|
+
.string-list {
|
|
478
|
+
display: flex;
|
|
479
|
+
flex-direction: column;
|
|
480
|
+
width: auto;
|
|
481
|
+
|
|
482
|
+
&.readonly {
|
|
483
|
+
cursor: default;
|
|
484
|
+
opacity: 0.4;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
.string-list-box {
|
|
488
|
+
min-height: 200px;
|
|
489
|
+
height: 100%;
|
|
490
|
+
outline: none;
|
|
491
|
+
overflow-y: auto;
|
|
492
|
+
overflow-x: hidden;
|
|
493
|
+
border: solid var(--border-width) var(--input-border);
|
|
494
|
+
padding-top: 3px;
|
|
495
|
+
|
|
496
|
+
.static {
|
|
497
|
+
height: 25px;
|
|
498
|
+
padding: 3px;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
.item {
|
|
502
|
+
outline: none;
|
|
503
|
+
|
|
504
|
+
&.selected {
|
|
505
|
+
background: var(--primary);
|
|
506
|
+
color: var(--primary-hover-text);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
&.readonly {
|
|
510
|
+
pointer-events: none;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
.label {
|
|
514
|
+
display: block;
|
|
515
|
+
width: auto;
|
|
516
|
+
user-select: none;
|
|
517
|
+
overflow: hidden;
|
|
518
|
+
text-overflow: ellipsis;
|
|
519
|
+
padding-top: 1px;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
.create-field {
|
|
524
|
+
padding-top: 1px;
|
|
525
|
+
margin-bottom: 7px;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
.labeled-input {
|
|
529
|
+
padding-top: 0;
|
|
530
|
+
padding-bottom: 0;
|
|
531
|
+
border-radius: 0;
|
|
532
|
+
&.error {
|
|
533
|
+
border: none;
|
|
534
|
+
box-shadow: 0 0 0 var(--outline-width) var(--error);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
.string-list-footer {
|
|
540
|
+
--footer-height: 28px;
|
|
541
|
+
height: var(--footer-height);
|
|
542
|
+
margin-top: 5px;
|
|
543
|
+
display: flex;
|
|
544
|
+
justify-content: space-between;
|
|
545
|
+
gap: 0.5rem;
|
|
546
|
+
|
|
547
|
+
&.left {
|
|
548
|
+
flex-direction: row;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
&.right {
|
|
552
|
+
flex-direction: row-reverse;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
.action-buttons {
|
|
556
|
+
display: flex;
|
|
557
|
+
flex-direction: row-reverse;
|
|
558
|
+
gap: 0.5rem;
|
|
559
|
+
|
|
560
|
+
.btn {
|
|
561
|
+
min-height: var(--footer-height);
|
|
562
|
+
line-height: 0;
|
|
563
|
+
border-radius: 2px;
|
|
564
|
+
|
|
565
|
+
&:disabled {
|
|
566
|
+
cursor: default;
|
|
567
|
+
pointer-events: none;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
.messages {
|
|
573
|
+
line-height: var(--footer-height);
|
|
574
|
+
|
|
575
|
+
.error, .icon-warning {
|
|
576
|
+
color: var(--error);
|
|
577
|
+
line-height: inherit;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
::v-deep {
|
|
584
|
+
.labeled-input INPUT.no-label,
|
|
585
|
+
.labeled-input INPUT:hover.no-label,
|
|
586
|
+
.labeled-input INPUT:focus.no-label {
|
|
587
|
+
padding: 1px 0px 0px 0px;
|
|
588
|
+
}
|
|
589
|
+
.labeled-input.compact-input {
|
|
590
|
+
min-height: 0;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
</style>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as StringList } from './StringList.vue';
|
package/types/shell/index.d.ts
CHANGED
|
@@ -2844,35 +2844,35 @@ export namespace KEY {
|
|
|
2844
2844
|
}
|
|
2845
2845
|
}
|
|
2846
2846
|
|
|
2847
|
-
// @shell/utils/poller
|
|
2847
|
+
// @shell/utils/poller-sequential
|
|
2848
2848
|
|
|
2849
|
-
declare module '@shell/utils/poller' {
|
|
2850
|
-
export default class
|
|
2849
|
+
declare module '@shell/utils/poller-sequential' {
|
|
2850
|
+
export default class PollerSequential {
|
|
2851
2851
|
constructor(fn: any, pollRateMs: any, maxRetries?: number);
|
|
2852
2852
|
fn: any;
|
|
2853
2853
|
pollRateMs: any;
|
|
2854
2854
|
maxRetries: number;
|
|
2855
|
-
|
|
2855
|
+
timeoutId: any;
|
|
2856
2856
|
tryCount: number;
|
|
2857
2857
|
start(): void;
|
|
2858
2858
|
stop(): void;
|
|
2859
|
+
_poll(): void;
|
|
2859
2860
|
_intervalMethod(): Promise<void>;
|
|
2860
2861
|
}
|
|
2861
2862
|
}
|
|
2862
2863
|
|
|
2863
|
-
// @shell/utils/poller
|
|
2864
|
+
// @shell/utils/poller
|
|
2864
2865
|
|
|
2865
|
-
declare module '@shell/utils/poller
|
|
2866
|
-
export default class
|
|
2866
|
+
declare module '@shell/utils/poller' {
|
|
2867
|
+
export default class Poller {
|
|
2867
2868
|
constructor(fn: any, pollRateMs: any, maxRetries?: number);
|
|
2868
2869
|
fn: any;
|
|
2869
2870
|
pollRateMs: any;
|
|
2870
2871
|
maxRetries: number;
|
|
2871
|
-
|
|
2872
|
+
intervalId: any;
|
|
2872
2873
|
tryCount: number;
|
|
2873
2874
|
start(): void;
|
|
2874
2875
|
stop(): void;
|
|
2875
|
-
_poll(): void;
|
|
2876
2876
|
_intervalMethod(): Promise<void>;
|
|
2877
2877
|
}
|
|
2878
2878
|
}
|
package/yarn-error.log
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
Arguments:
|
|
2
|
+
/Users/aalves/.nvm/versions/node/v16.16.0/bin/node /Users/aalves/.nvm/versions/node/v16.16.0/bin/yarn publish . --new-version 0.3.3 --no-git-tag-version --access public
|
|
3
|
+
|
|
4
|
+
PATH:
|
|
5
|
+
/Users/aalves/.nvm/versions/node/v16.16.0/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
|
|
6
|
+
|
|
7
|
+
Yarn version:
|
|
8
|
+
1.22.19
|
|
9
|
+
|
|
10
|
+
Node version:
|
|
11
|
+
16.16.0
|
|
12
|
+
|
|
13
|
+
Platform:
|
|
14
|
+
darwin arm64
|
|
15
|
+
|
|
16
|
+
Trace:
|
|
17
|
+
Error: https://registry.yarnpkg.com/-/user/org.couchdb.user:aalves08: failed to authenticate: Could not authenticate aalves08: bad password
|
|
18
|
+
at Request.params.callback [as _callback] (/Users/aalves/.nvm/versions/node/v16.16.0/lib/node_modules/yarn/lib/cli.js:66145:18)
|
|
19
|
+
at Request.self.callback (/Users/aalves/.nvm/versions/node/v16.16.0/lib/node_modules/yarn/lib/cli.js:140890:22)
|
|
20
|
+
at Request.emit (node:events:527:28)
|
|
21
|
+
at Request.<anonymous> (/Users/aalves/.nvm/versions/node/v16.16.0/lib/node_modules/yarn/lib/cli.js:141862:10)
|
|
22
|
+
at Request.emit (node:events:527:28)
|
|
23
|
+
at IncomingMessage.<anonymous> (/Users/aalves/.nvm/versions/node/v16.16.0/lib/node_modules/yarn/lib/cli.js:141784:12)
|
|
24
|
+
at Object.onceWrapper (node:events:641:28)
|
|
25
|
+
at IncomingMessage.emit (node:events:539:35)
|
|
26
|
+
at endReadableNT (node:internal/streams/readable:1345:12)
|
|
27
|
+
at processTicksAndRejections (node:internal/process/task_queues:83:21)
|
|
28
|
+
|
|
29
|
+
npm manifest:
|
|
30
|
+
{
|
|
31
|
+
"name": "@rancher/shell",
|
|
32
|
+
"version": "0.3.3",
|
|
33
|
+
"description": "Rancher Dashboard Shell",
|
|
34
|
+
"repository": "https://github.com/rancherlabs/dashboard",
|
|
35
|
+
"license": "Apache-2.0",
|
|
36
|
+
"author": "SUSE",
|
|
37
|
+
"private": false,
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=12"
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"**/*"
|
|
43
|
+
],
|
|
44
|
+
"scripts": {
|
|
45
|
+
"clean": "./scripts/clean",
|
|
46
|
+
"lint": "./node_modules/.bin/eslint --max-warnings 0 --ext .ts,.js,.vue .",
|
|
47
|
+
"test": "./node_modules/.bin/nyc ava --serial --verbose",
|
|
48
|
+
"nuxt": "./node_modules/.bin/nuxt",
|
|
49
|
+
"dev": "./node_modules/.bin/nuxt dev",
|
|
50
|
+
"mem-dev": "node --max-old-space-size=8192 ./node_modules/.bin/nuxt dev",
|
|
51
|
+
"docker-dev": "docker run --rm --name dashboard-dev -p 8005:8005 -e API=$API -v $(pwd):/src -v dashboard_node:/src/node_modules rancher/dashboard:dev",
|
|
52
|
+
"build": "./node_modules/.bin/nuxt build --devtools",
|
|
53
|
+
"analyze": "./node_modules/.bin/nuxt build --analyze",
|
|
54
|
+
"start": "./node_modules/.bin/nuxt start",
|
|
55
|
+
"generate": "./node_modules/.bin/nuxt generate",
|
|
56
|
+
"dev-debug": "node --inspect ./node_modules/.bin/nuxt",
|
|
57
|
+
"cy:run": "cypress run",
|
|
58
|
+
"cy:open": "cypress open",
|
|
59
|
+
"e2e:pre": "NODE_ENV=dev yarn build",
|
|
60
|
+
"e2e:run": "NODE_ENV=dev START_SERVER_AND_TEST_INSECURE=1 start-server-and-test start https://localhost:8005/ cy:run",
|
|
61
|
+
"e2e:dev": "start-server-and-test dev https://localhost:8005 cy:open"
|
|
62
|
+
},
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"@aws-sdk/client-ec2": "3.1.0",
|
|
65
|
+
"@aws-sdk/client-eks": "3.1.0",
|
|
66
|
+
"@aws-sdk/client-kms": "3.8.1",
|
|
67
|
+
"@babel/plugin-proposal-optional-chaining": "7.14.5",
|
|
68
|
+
"@babel/plugin-proposal-private-property-in-object": "7.14.5",
|
|
69
|
+
"@babel/preset-typescript": "7.16.7",
|
|
70
|
+
"@innologica/vue-dropdown-menu": "0.1.3",
|
|
71
|
+
"@novnc/novnc": "1.2.0",
|
|
72
|
+
"@nuxt/types": "2.14.6",
|
|
73
|
+
"@nuxt/typescript-build": "2.1.0",
|
|
74
|
+
"@nuxtjs/axios": "5.12.0",
|
|
75
|
+
"@nuxtjs/eslint-config-typescript": "6.0.1",
|
|
76
|
+
"@nuxtjs/eslint-module": "1.2.0",
|
|
77
|
+
"@nuxtjs/proxy": "1.3.3",
|
|
78
|
+
"@nuxtjs/style-resources": "1.2.1",
|
|
79
|
+
"@nuxtjs/webpack-profile": "0.1.0",
|
|
80
|
+
"@popperjs/core": "2.4.4",
|
|
81
|
+
"@types/node": "16.4.3",
|
|
82
|
+
"@typescript-eslint/eslint-plugin": "4.33.0",
|
|
83
|
+
"@typescript-eslint/parser": "4.33.0",
|
|
84
|
+
"@vue/cli-plugin-babel": "4.5.15",
|
|
85
|
+
"@vue/cli-plugin-typescript": "4.5.15",
|
|
86
|
+
"@vue/cli-service": "4.5.15",
|
|
87
|
+
"@vue/test-utils": "1.2.1",
|
|
88
|
+
"@vue/vue2-jest": "27.0.0",
|
|
89
|
+
"add": "2.0.6",
|
|
90
|
+
"ansi_up": "5.0.0",
|
|
91
|
+
"babel-eslint": "10.1.0",
|
|
92
|
+
"babel-plugin-module-resolver": "4.0.0",
|
|
93
|
+
"babel-preset-vue": "2.0.2",
|
|
94
|
+
"browser-env": "3.3.0",
|
|
95
|
+
"cookie": "0.5.0",
|
|
96
|
+
"cookie-universal-nuxt": "2.1.4",
|
|
97
|
+
"core-js": "3.21.1",
|
|
98
|
+
"cron-validator": "1.2.0",
|
|
99
|
+
"cronstrue": "1.95.0",
|
|
100
|
+
"cross-env": "6.0.3",
|
|
101
|
+
"css-loader": "4.3.0",
|
|
102
|
+
"csv-loader": "3.0.3",
|
|
103
|
+
"cypress": "10.3.1",
|
|
104
|
+
"d3": "7.3.0",
|
|
105
|
+
"d3-selection": "1.4.1",
|
|
106
|
+
"dagre-d3": "0.6.4",
|
|
107
|
+
"dayjs": "1.8.29",
|
|
108
|
+
"diff2html": "2.11.2",
|
|
109
|
+
"dompurify": "2.0.12",
|
|
110
|
+
"eslint": "7.32.0",
|
|
111
|
+
"eslint-config-standard": "16.0.3",
|
|
112
|
+
"eslint-import-resolver-node": "0.3.4",
|
|
113
|
+
"eslint-module-utils": "2.6.1",
|
|
114
|
+
"eslint-plugin-cypress": "2.12.1",
|
|
115
|
+
"eslint-plugin-import": "2.23.4",
|
|
116
|
+
"eslint-plugin-jest": "24.4.0",
|
|
117
|
+
"eslint-plugin-n": "15.2.0",
|
|
118
|
+
"eslint-plugin-vue": "7.14.0",
|
|
119
|
+
"event-target-shim": "5.0.1",
|
|
120
|
+
"express": "4.17.1",
|
|
121
|
+
"file-saver": "2.0.2",
|
|
122
|
+
"frontmatter-markdown-loader": "3.7.0",
|
|
123
|
+
"identicon.js": "2.3.3",
|
|
124
|
+
"intl-messageformat": "7.8.4",
|
|
125
|
+
"is-url": "1.2.4",
|
|
126
|
+
"jest": "27.5.1",
|
|
127
|
+
"jest-serializer-vue": "2.0.2",
|
|
128
|
+
"jexl": "2.2.2",
|
|
129
|
+
"jquery": "3.5.1",
|
|
130
|
+
"js-cookie": "2.2.1",
|
|
131
|
+
"js-yaml": "4.1.0",
|
|
132
|
+
"js-yaml-loader": "1.2.2",
|
|
133
|
+
"jsdiff": "1.1.1",
|
|
134
|
+
"jsdom-global": "3.0.2",
|
|
135
|
+
"jsonpath-plus": "6.0.1",
|
|
136
|
+
"jsrsasign": "10.2.0",
|
|
137
|
+
"jszip": "3.7.0",
|
|
138
|
+
"lodash": "4.17.21",
|
|
139
|
+
"marked": "4.0.17",
|
|
140
|
+
"nodemon": "2.0.4",
|
|
141
|
+
"nuxt": "2.15.8",
|
|
142
|
+
"nyc": "15.1.0",
|
|
143
|
+
"papaparse": "5.3.0",
|
|
144
|
+
"portal-vue": "2.1.7",
|
|
145
|
+
"rancher-icons": "rancher/icons#v2.0.13",
|
|
146
|
+
"require-extension-hooks": "0.3.3",
|
|
147
|
+
"require-extension-hooks-babel": "1.0.0",
|
|
148
|
+
"require-extension-hooks-vue": "3.0.0",
|
|
149
|
+
"sass": "1.51.0",
|
|
150
|
+
"sass-loader": "10.2.1",
|
|
151
|
+
"serve-static": "1.14.1",
|
|
152
|
+
"set-cookie-parser": "2.4.6",
|
|
153
|
+
"shell-quote": "1.7.3",
|
|
154
|
+
"sinon": "8.1.1",
|
|
155
|
+
"start-server-and-test": "1.13.1",
|
|
156
|
+
"style-loader": "1.2.1",
|
|
157
|
+
"ts-node": "8.10.2",
|
|
158
|
+
"typescript": "4.1.6",
|
|
159
|
+
"url-parse": "1.5.10",
|
|
160
|
+
"v-tooltip": "2.0.3",
|
|
161
|
+
"vue": "2.6.14",
|
|
162
|
+
"vue-clipboard2": "0.3.1",
|
|
163
|
+
"vue-codemirror": "4.0.6",
|
|
164
|
+
"vue-js-modal": "1.3.35",
|
|
165
|
+
"vue-resize": "0.4.5",
|
|
166
|
+
"vue-select": "3.18.3",
|
|
167
|
+
"vue-server-renderer": "2.6.14",
|
|
168
|
+
"vue-shortkey": "3.1.7",
|
|
169
|
+
"vue-template-compiler": "2.6.14",
|
|
170
|
+
"vue-virtual-scroll-list": "^2.3.4",
|
|
171
|
+
"vue2-transitions": "0.3.0",
|
|
172
|
+
"vuedraggable": "2.24.3",
|
|
173
|
+
"vuex": "3.6.2",
|
|
174
|
+
"webpack-bundle-analyzer": "4.5.0",
|
|
175
|
+
"webpack-virtual-modules": "0.4.3",
|
|
176
|
+
"xterm": "5.0.0",
|
|
177
|
+
"xterm-addon-fit": "0.6.0",
|
|
178
|
+
"xterm-addon-search": "0.10.0",
|
|
179
|
+
"xterm-addon-web-links": "0.7.0",
|
|
180
|
+
"xterm-addon-webgl": "0.13.0",
|
|
181
|
+
"worker-loader": "3.0.8",
|
|
182
|
+
"yarn": "1.22.18"
|
|
183
|
+
},
|
|
184
|
+
"nyc": {
|
|
185
|
+
"extension": [
|
|
186
|
+
".js",
|
|
187
|
+
".vue"
|
|
188
|
+
]
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
yarn manifest:
|
|
193
|
+
No manifest
|
|
194
|
+
|
|
195
|
+
Lockfile:
|
|
196
|
+
No lockfile
|