@rancher/shell 0.3.17 → 0.3.19
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 +8 -4
- package/assets/translations/zh-hans.yaml +64 -8
- package/components/AsyncButton.vue +1 -1
- package/components/Inactivity.vue +10 -0
- package/components/LazyImage.vue +2 -2
- package/components/PromptRestore.vue +8 -6
- package/components/ResourceDetail/Masthead.vue +1 -1
- package/components/ResourceDetail/index.vue +4 -2
- package/components/__tests__/PromptRestore.test.ts +142 -0
- package/components/auth/AzureWarning.vue +1 -1
- package/components/auth/RoleDetailEdit.vue +2 -0
- package/components/fleet/FleetResources.vue +3 -64
- package/components/form/FileImageSelector.vue +9 -0
- package/components/form/FileSelector.vue +2 -1
- package/components/form/MatchExpressions.vue +1 -3
- package/components/form/__tests__/FileImageSelector.test.ts +42 -0
- package/components/form/__tests__/FileSelector.test.ts +76 -0
- package/components/formatter/ClusterProvider.vue +3 -1
- package/components/formatter/__tests__/ClusterProvider.test.ts +24 -0
- package/components/nav/WindowManager/ContainerShell.vue +60 -36
- package/components/nav/WindowManager/__tests__/ContainerShell.test.ts +561 -0
- package/config/labels-annotations.js +2 -1
- package/config/persistentVolume.ts +108 -0
- package/config/product/manager.js +5 -1
- package/config/types.js +2 -0
- package/core/plugin-helpers.js +19 -3
- package/core/types.ts +4 -0
- package/detail/fleet.cattle.io.gitrepo.vue +10 -2
- package/detail/pod.vue +36 -3
- package/detail/workload/index.vue +40 -9
- package/dialog/DiagnosticTimingsDialog.vue +1 -0
- package/edit/__tests__/ui.cattle.io.navlink.test.ts +110 -0
- package/edit/fleet.cattle.io.clustergroup.vue +14 -3
- package/edit/persistentvolume/__tests__/persistentvolume.test.ts +82 -0
- package/edit/persistentvolume/index.vue +2 -1
- package/edit/persistentvolume/plugins/csi.vue +3 -1
- package/edit/persistentvolume/plugins/longhorn.vue +12 -12
- package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +15 -11
- package/edit/provisioning.cattle.io.cluster/index.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/rke2.vue +5 -1
- package/edit/storage.k8s.io.storageclass/index.vue +1 -2
- package/edit/ui.cattle.io.navlink.vue +213 -186
- package/layouts/default.vue +1 -1
- package/list/group.principal.vue +1 -1
- package/middleware/authenticated.js +12 -4
- package/mixins/create-edit-view/impl.js +2 -2
- package/models/chart.js +1 -1
- package/models/etcdbackup.js +2 -1
- package/models/fleet.cattle.io.cluster.js +33 -4
- package/models/fleet.cattle.io.gitrepo.js +112 -38
- package/models/management.cattle.io.cluster.js +13 -3
- package/models/management.cattle.io.kontainerdriver.js +14 -0
- package/models/persistentvolume.js +2 -111
- package/models/pod.js +30 -0
- package/models/rke.cattle.io.etcdsnapshot.js +10 -7
- package/package.json +1 -1
- package/pages/c/_cluster/apps/charts/install.vue +74 -25
- package/pages/c/_cluster/auth/group.principal/assign-edit.vue +1 -1
- package/pages/c/_cluster/auth/roles/index.vue +1 -1
- package/pages/c/_cluster/explorer/index.vue +1 -1
- package/pages/c/_cluster/manager/cloudCredential/_id.vue +0 -1
- package/pages/c/_cluster/manager/cloudCredential/create.vue +0 -1
- package/pages/c/_cluster/settings/brand.vue +11 -8
- package/pages/c/_cluster/uiplugins/index.vue +9 -4
- package/pages/diagnostic.vue +5 -3
- package/pages/home.vue +1 -1
- package/plugins/dashboard-store/__tests__/actions.spec.ts +165 -0
- package/plugins/dashboard-store/__tests__/getters.spec.ts +100 -0
- package/plugins/dashboard-store/__tests__/{mutations.spec.js → mutations.spec.ts} +2 -2
- package/plugins/dashboard-store/actions.js +1 -1
- package/plugins/dashboard-store/resource-class.js +4 -0
- package/plugins/steve/__tests__/getters.spec.ts +93 -0
- package/plugins/steve/getters.js +21 -1
- package/plugins/steve/subscribe.js +1 -3
- package/rancher-components/components/BadgeState/BadgeState.spec.ts +12 -0
- package/rancher-components/components/BadgeState/BadgeState.vue +111 -0
- package/rancher-components/components/BadgeState/index.ts +1 -0
- package/rancher-components/components/Banner/Banner.test.ts +63 -0
- package/rancher-components/components/Banner/Banner.vue +244 -0
- package/rancher-components/components/Banner/index.ts +1 -0
- package/rancher-components/components/Card/Card.test.ts +37 -0
- package/rancher-components/components/Card/Card.vue +167 -0
- package/rancher-components/components/Card/index.ts +1 -0
- package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +68 -0
- package/rancher-components/components/Form/Checkbox/Checkbox.vue +420 -0
- package/rancher-components/components/Form/Checkbox/index.ts +1 -0
- package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +23 -0
- package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +355 -0
- package/rancher-components/components/Form/LabeledInput/index.ts +1 -0
- package/rancher-components/components/Form/Radio/RadioButton.test.ts +31 -0
- package/rancher-components/components/Form/Radio/RadioButton.vue +287 -0
- package/rancher-components/components/Form/Radio/RadioGroup.vue +254 -0
- package/rancher-components/components/Form/Radio/index.ts +2 -0
- package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +170 -0
- package/rancher-components/components/Form/TextArea/index.ts +1 -0
- package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +94 -0
- package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +149 -0
- package/rancher-components/components/Form/ToggleSwitch/index.ts +1 -0
- package/rancher-components/components/Form/index.ts +5 -0
- package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +151 -0
- package/rancher-components/components/LabeledTooltip/index.ts +1 -0
- package/rancher-components/components/StringList/StringList.test.ts +484 -0
- package/rancher-components/components/StringList/StringList.vue +611 -0
- package/rancher-components/components/StringList/index.ts +1 -0
- package/scripts/extension/publish +54 -14
- package/scripts/typegen.sh +10 -2
- package/store/index.js +1 -3
- package/store/store-types.js +2 -0
- package/types/api.d.ts +1 -0
- package/types/fleet.d.ts +1 -0
- package/types/shell/index.d.ts +696 -2
- package/types/userPreferences.d.ts +1 -1
- package/utils/__mocks__/socket.js +21 -0
- package/utils/grafana.js +23 -11
- package/utils/selector.js +2 -1
- package/utils/socket.js +1 -0
- package/utils/validators/formRules/index.ts +3 -3
- package/plugins/steve/urloptions.js +0 -47
|
@@ -7,10 +7,10 @@ import CruResource from '@shell/components/CruResource';
|
|
|
7
7
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
|
8
8
|
import { RadioGroup } from '@components/Form/Radio';
|
|
9
9
|
import FileImageSelector from '@shell/components/form/FileImageSelector';
|
|
10
|
-
import NameNsDescription from '@shell/components/form/NameNsDescription';
|
|
11
|
-
import Tab from '@shell/components/Tabbed/Tab';
|
|
12
|
-
import Tabbed from '@shell/components/Tabbed';
|
|
13
10
|
import LabeledSelect from '@shell/components/form/LabeledSelect.vue';
|
|
11
|
+
import NameNsDescription from '@shell/components/form/NameNsDescription';
|
|
12
|
+
import { Banner } from '@components/Banner';
|
|
13
|
+
import FormValidation from '@shell/mixins/form-validation';
|
|
14
14
|
import { normalizeName } from '@shell/utils/kube';
|
|
15
15
|
|
|
16
16
|
const LINK_TYPE_URL = 'url';
|
|
@@ -20,16 +20,15 @@ const LINK_TARGET_BLANK = '_blank';
|
|
|
20
20
|
const LINK_TARGET_SELF = '_self';
|
|
21
21
|
|
|
22
22
|
export default {
|
|
23
|
-
mixins: [CreateEditView],
|
|
23
|
+
mixins: [CreateEditView, FormValidation],
|
|
24
24
|
components: {
|
|
25
25
|
CruResource,
|
|
26
26
|
LabeledInput,
|
|
27
27
|
RadioGroup,
|
|
28
28
|
NameNsDescription,
|
|
29
|
-
Tabbed,
|
|
30
|
-
Tab,
|
|
31
29
|
FileImageSelector,
|
|
32
|
-
LabeledSelect
|
|
30
|
+
LabeledSelect,
|
|
31
|
+
Banner
|
|
33
32
|
},
|
|
34
33
|
data() {
|
|
35
34
|
return {
|
|
@@ -57,12 +56,19 @@ export default {
|
|
|
57
56
|
label: this.t('navLink.tabs.link.type.service')
|
|
58
57
|
}
|
|
59
58
|
],
|
|
60
|
-
currentLinkType:
|
|
61
|
-
targetName:
|
|
62
|
-
currentTarget:
|
|
63
|
-
protocolsOptions:
|
|
64
|
-
services:
|
|
65
|
-
currentService:
|
|
59
|
+
currentLinkType: null,
|
|
60
|
+
targetName: null,
|
|
61
|
+
currentTarget: LINK_TARGET_BLANK,
|
|
62
|
+
protocolsOptions: PROTOCOLS,
|
|
63
|
+
services: [],
|
|
64
|
+
currentService: null,
|
|
65
|
+
imageErrorMessage: '',
|
|
66
|
+
fvFormRuleSets: [
|
|
67
|
+
{ path: 'metadata.name', rules: ['nameRequired'] },
|
|
68
|
+
{ path: 'spec.toURL', rules: ['urlRequired'] },
|
|
69
|
+
{ path: 'spec.toService.namespace', rules: ['serviceNamespaceRequired'] },
|
|
70
|
+
{ path: 'spec.toService.scheme', rules: ['serviceSchemeRequired'] }],
|
|
71
|
+
|
|
66
72
|
};
|
|
67
73
|
},
|
|
68
74
|
props: {
|
|
@@ -113,6 +119,44 @@ export default {
|
|
|
113
119
|
label: id, id, name, namespace
|
|
114
120
|
}) );
|
|
115
121
|
},
|
|
122
|
+
imageError() {
|
|
123
|
+
return !!this.imageErrorMessage && !this.value.spec.iconSrc;
|
|
124
|
+
},
|
|
125
|
+
fvExtraRules() {
|
|
126
|
+
const isLinkTypeUrl = this.currentLinkType === LINK_TYPE_URL;
|
|
127
|
+
const isServiceTypeUrl = this.currentLinkType === LINK_TYPE_SERVICE;
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
nameRequired: () => {
|
|
131
|
+
if (!this.value.metadata.name) {
|
|
132
|
+
return this.getError('navLink.name.label');
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
urlRequired: () => {
|
|
137
|
+
const condition = this.value.spec.toURL;
|
|
138
|
+
|
|
139
|
+
if (isLinkTypeUrl && !condition) {
|
|
140
|
+
return this.getError('navLink.tabs.link.toURL.label');
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
serviceNamespaceRequired: () => {
|
|
144
|
+
const condition = this.value.spec.toService.name && this.value.spec.toService.namespace;
|
|
145
|
+
|
|
146
|
+
if (isServiceTypeUrl && !condition) {
|
|
147
|
+
return this.getError('navLink.tabs.link.toService.service.label');
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
serviceSchemeRequired: () => {
|
|
151
|
+
const condition = this.value.spec.toService.scheme;
|
|
152
|
+
|
|
153
|
+
if (isServiceTypeUrl && !condition) {
|
|
154
|
+
return this.getError('navLink.tabs.link.toService.scheme.label');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
};
|
|
159
|
+
}
|
|
116
160
|
},
|
|
117
161
|
async fetch() {
|
|
118
162
|
this.services = await this.$store
|
|
@@ -215,50 +259,20 @@ export default {
|
|
|
215
259
|
getError(label) {
|
|
216
260
|
return this.$store.getters['i18n/t']('validation.required', { key: this.t(label) });
|
|
217
261
|
},
|
|
218
|
-
/**
|
|
219
|
-
* Verify all fields are fulfilled or display footer notification
|
|
220
|
-
*/
|
|
221
|
-
validate() {
|
|
222
|
-
const errors = [];
|
|
223
|
-
|
|
224
|
-
switch (this.currentLinkType) {
|
|
225
|
-
case LINK_TYPE_URL:
|
|
226
|
-
if (!this.value.spec.toURL) {
|
|
227
|
-
errors.push(this.getError('navLink.tabs.link.toURL.label'));
|
|
228
|
-
}
|
|
229
|
-
break;
|
|
230
|
-
|
|
231
|
-
case LINK_TYPE_SERVICE:
|
|
232
|
-
if (!this.value.spec.toService.name || !this.value.spec.toService.namespace) {
|
|
233
|
-
errors.push(this.getError(`navLink.tabs.link.toService.service.label`));
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (!this.value.spec.toService.scheme) {
|
|
237
|
-
errors.push(this.getError(`navLink.tabs.link.toService.scheme.label`));
|
|
238
|
-
}
|
|
239
|
-
break;
|
|
240
|
-
|
|
241
|
-
// no default
|
|
242
|
-
}
|
|
243
262
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
if (errors.length) {
|
|
249
|
-
throw (errors.join('\n'));
|
|
250
|
-
}
|
|
263
|
+
setImageError(e) {
|
|
264
|
+
this.imageErrorMessage = e;
|
|
251
265
|
},
|
|
266
|
+
setIcon(value) {
|
|
267
|
+
this.imageErrorMessage = '';
|
|
268
|
+
this.$emit('update:value.spec.iconSrc ', value);
|
|
269
|
+
}
|
|
252
270
|
},
|
|
253
271
|
created() {
|
|
254
272
|
this.setDefaultValues();
|
|
255
273
|
this.setUrlType();
|
|
256
274
|
this.setTargetOption();
|
|
257
275
|
this.setCurrentService();
|
|
258
|
-
// Validate error presence by allowing or resetting submission process
|
|
259
|
-
if (this.registerBeforeHook) {
|
|
260
|
-
this.registerBeforeHook(this.validate);
|
|
261
|
-
}
|
|
262
276
|
}
|
|
263
277
|
};
|
|
264
278
|
</script>
|
|
@@ -268,8 +282,10 @@ export default {
|
|
|
268
282
|
:can-yaml="!isCreate"
|
|
269
283
|
:mode="mode"
|
|
270
284
|
:resource="value"
|
|
271
|
-
:errors="
|
|
285
|
+
:errors="fvUnreportedValidationErrors"
|
|
272
286
|
:cancel-event="true"
|
|
287
|
+
:validation-passed="fvFormIsValid"
|
|
288
|
+
data-testid="Navlink-CRU"
|
|
273
289
|
@error="e=>errors = e"
|
|
274
290
|
@finish="save"
|
|
275
291
|
@cancel="done()"
|
|
@@ -285,147 +301,158 @@ export default {
|
|
|
285
301
|
name-placeholder="navLink.name.placeholder"
|
|
286
302
|
description-label="navLink.label.label"
|
|
287
303
|
description-placeholder="navLink.label.placeholder"
|
|
304
|
+
data-testid="Navlink-name-field"
|
|
305
|
+
:rules="{ name: fvGetAndReportPathRules('metadata.name'), namespace: [], description: [] }"
|
|
288
306
|
/>
|
|
289
307
|
|
|
290
|
-
<
|
|
291
|
-
|
|
292
|
-
>
|
|
293
|
-
<
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
:options="urlTypeOptions"
|
|
304
|
-
/>
|
|
305
|
-
</div>
|
|
306
|
-
</div>
|
|
307
|
-
|
|
308
|
-
<template v-if="isURL">
|
|
309
|
-
<div class="row mb-20">
|
|
310
|
-
<LabeledInput
|
|
311
|
-
v-model="value.spec.toURL"
|
|
312
|
-
:mode="mode"
|
|
313
|
-
:label="t('navLink.tabs.link.toURL.label')"
|
|
314
|
-
:required="isURL"
|
|
315
|
-
:placeholder="t('navLink.tabs.link.toURL.placeholder')"
|
|
316
|
-
/>
|
|
317
|
-
</div>
|
|
318
|
-
</template>
|
|
319
|
-
<template v-if="isService">
|
|
320
|
-
<div class="row mb-20">
|
|
321
|
-
<div class="col span-2">
|
|
322
|
-
<LabeledSelect
|
|
323
|
-
v-model="value.spec.toService.scheme"
|
|
324
|
-
:mode="mode"
|
|
325
|
-
:label="t('navLink.tabs.link.toService.scheme.label')"
|
|
326
|
-
:required="isService"
|
|
327
|
-
:options="protocolsOptions"
|
|
328
|
-
:placeholder="t('navLink.tabs.link.toService.scheme.placeholder')"
|
|
329
|
-
/>
|
|
330
|
-
</div>
|
|
331
|
-
<div class="col span-5">
|
|
332
|
-
<LabeledSelect
|
|
333
|
-
v-model="currentService"
|
|
334
|
-
:mode="mode"
|
|
335
|
-
:label="t('navLink.tabs.link.toService.service.label')"
|
|
336
|
-
:options="mappedServices"
|
|
337
|
-
:required="isService"
|
|
338
|
-
:placeholder="t('navLink.tabs.link.toService.service.placeholder')"
|
|
339
|
-
@input="setService"
|
|
340
|
-
/>
|
|
341
|
-
</div>
|
|
342
|
-
<div class="col span-2">
|
|
343
|
-
<LabeledInput
|
|
344
|
-
v-model="value.spec.toService.port"
|
|
345
|
-
:mode="mode"
|
|
346
|
-
:label="t('navLink.tabs.link.toService.port.label')"
|
|
347
|
-
type="number"
|
|
348
|
-
:placeholder="t('navLink.tabs.link.toService.port.placeholder')"
|
|
349
|
-
/>
|
|
350
|
-
</div>
|
|
351
|
-
<div class="col span-3">
|
|
352
|
-
<LabeledInput
|
|
353
|
-
v-model="value.spec.toService.path"
|
|
354
|
-
:mode="mode"
|
|
355
|
-
:label="t('navLink.tabs.link.toService.path.label')"
|
|
356
|
-
:placeholder="t('navLink.tabs.link.toService.path.placeholder')"
|
|
357
|
-
/>
|
|
358
|
-
</div>
|
|
359
|
-
</div>
|
|
360
|
-
</template>
|
|
361
|
-
</Tab>
|
|
308
|
+
<div class="spacer" />
|
|
309
|
+
<h2 v-t="'navLink.tabs.link.label'" />
|
|
310
|
+
<div class="row mb-20">
|
|
311
|
+
<div class="col span-6">
|
|
312
|
+
<RadioGroup
|
|
313
|
+
v-model="linkType"
|
|
314
|
+
name="type"
|
|
315
|
+
:mode="mode"
|
|
316
|
+
:options="urlTypeOptions"
|
|
317
|
+
data-testid="Navlink-link-radiogroup"
|
|
318
|
+
/>
|
|
319
|
+
</div>
|
|
320
|
+
</div>
|
|
362
321
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
322
|
+
<template v-if="isURL">
|
|
323
|
+
<div class="row mb-20">
|
|
324
|
+
<LabeledInput
|
|
325
|
+
v-model="value.spec.toURL"
|
|
326
|
+
:mode="mode"
|
|
327
|
+
:label="t('navLink.tabs.link.toURL.label')"
|
|
328
|
+
:required="isURL"
|
|
329
|
+
:placeholder="t('navLink.tabs.link.toURL.placeholder')"
|
|
330
|
+
:rules="fvGetAndReportPathRules('spec.toURL')"
|
|
331
|
+
data-testid="Navlink-url-field"
|
|
332
|
+
/>
|
|
333
|
+
</div>
|
|
334
|
+
</template>
|
|
335
|
+
<template v-if="isService">
|
|
336
|
+
<div class="row mb-20">
|
|
337
|
+
<div class="col span-2">
|
|
338
|
+
<LabeledSelect
|
|
339
|
+
v-model="value.spec.toService.scheme"
|
|
340
|
+
:mode="mode"
|
|
341
|
+
:label="t('navLink.tabs.link.toService.scheme.label')"
|
|
342
|
+
:required="isService"
|
|
343
|
+
:options="protocolsOptions"
|
|
344
|
+
:placeholder="t('navLink.tabs.link.toService.scheme.placeholder')"
|
|
345
|
+
:rules="fvGetAndReportPathRules('spec.toService.scheme')"
|
|
346
|
+
data-testid="Navlink-scheme-field"
|
|
347
|
+
/>
|
|
387
348
|
</div>
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
:label="t('navLink.tabs.group.group.label')"
|
|
401
|
-
/>
|
|
402
|
-
</div>
|
|
403
|
-
<div class="col span-6">
|
|
404
|
-
<LabeledInput
|
|
405
|
-
v-model="value.spec.sideLabel"
|
|
406
|
-
:mode="mode"
|
|
407
|
-
:label="t('navLink.tabs.group.sideLabel.label')"
|
|
408
|
-
/>
|
|
409
|
-
</div>
|
|
349
|
+
<div class="col span-5">
|
|
350
|
+
<LabeledSelect
|
|
351
|
+
v-model="currentService"
|
|
352
|
+
:mode="mode"
|
|
353
|
+
:label="t('navLink.tabs.link.toService.service.label')"
|
|
354
|
+
:options="mappedServices"
|
|
355
|
+
:required="isService"
|
|
356
|
+
:placeholder="t('navLink.tabs.link.toService.service.placeholder')"
|
|
357
|
+
:rules="fvGetAndReportPathRules('spec.toService.namespace')"
|
|
358
|
+
data-testid="Navlink-currentService-field"
|
|
359
|
+
@input="setService"
|
|
360
|
+
/>
|
|
410
361
|
</div>
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
</div>
|
|
420
|
-
<div class="col span-2">
|
|
421
|
-
<FileImageSelector
|
|
422
|
-
v-model="value.spec.iconSrc"
|
|
423
|
-
:mode="mode"
|
|
424
|
-
:label="t('navLink.tabs.group.iconSrc.label')"
|
|
425
|
-
/>
|
|
426
|
-
</div>
|
|
362
|
+
<div class="col span-2">
|
|
363
|
+
<LabeledInput
|
|
364
|
+
v-model="value.spec.toService.port"
|
|
365
|
+
:mode="mode"
|
|
366
|
+
:label="t('navLink.tabs.link.toService.port.label')"
|
|
367
|
+
type="number"
|
|
368
|
+
:placeholder="t('navLink.tabs.link.toService.port.placeholder')"
|
|
369
|
+
/>
|
|
427
370
|
</div>
|
|
428
|
-
|
|
429
|
-
|
|
371
|
+
<div class="col span-3">
|
|
372
|
+
<LabeledInput
|
|
373
|
+
v-model="value.spec.toService.path"
|
|
374
|
+
:mode="mode"
|
|
375
|
+
:label="t('navLink.tabs.link.toService.path.label')"
|
|
376
|
+
:placeholder="t('navLink.tabs.link.toService.path.placeholder')"
|
|
377
|
+
/>
|
|
378
|
+
</div>
|
|
379
|
+
</div>
|
|
380
|
+
</template>
|
|
381
|
+
<div class="spacer" />
|
|
382
|
+
<h2 v-t="'navLink.tabs.target.label'" />
|
|
383
|
+
<div class="row mb-20">
|
|
384
|
+
<div class="col span-6">
|
|
385
|
+
<RadioGroup
|
|
386
|
+
v-model="currentTarget"
|
|
387
|
+
name="type"
|
|
388
|
+
:mode="mode"
|
|
389
|
+
:options="targetOptions"
|
|
390
|
+
@input="setTargetValue($event)"
|
|
391
|
+
/>
|
|
392
|
+
</div>
|
|
393
|
+
<div class="col span-6">
|
|
394
|
+
<LabeledInput
|
|
395
|
+
v-if="isNamedWindow"
|
|
396
|
+
v-model="targetName"
|
|
397
|
+
:mode="mode"
|
|
398
|
+
:label="t('navLink.tabs.target.namedValue.label')"
|
|
399
|
+
@input="setTargetValue($event);"
|
|
400
|
+
/>
|
|
401
|
+
</div>
|
|
402
|
+
</div>
|
|
403
|
+
<div class="spacer" />
|
|
404
|
+
<h2 v-t="'navLink.tabs.group.label'" />
|
|
405
|
+
|
|
406
|
+
<div class="row mb-20">
|
|
407
|
+
<div class="col span-6">
|
|
408
|
+
<LabeledInput
|
|
409
|
+
v-model="value.spec.group"
|
|
410
|
+
:mode="mode"
|
|
411
|
+
:tooltip="t('navLink.tabs.group.group.tooltip')"
|
|
412
|
+
:label="t('navLink.tabs.group.group.label')"
|
|
413
|
+
/>
|
|
414
|
+
</div>
|
|
415
|
+
<div class="col span-6">
|
|
416
|
+
<LabeledInput
|
|
417
|
+
v-model="value.spec.sideLabel"
|
|
418
|
+
:mode="mode"
|
|
419
|
+
:label="t('navLink.tabs.group.sideLabel.label')"
|
|
420
|
+
/>
|
|
421
|
+
</div>
|
|
422
|
+
</div>
|
|
423
|
+
|
|
424
|
+
<div class="row mb-20">
|
|
425
|
+
<div class="col span-6">
|
|
426
|
+
<LabeledInput
|
|
427
|
+
v-model="value.spec.description"
|
|
428
|
+
:mode="mode"
|
|
429
|
+
:label="t('navLink.tabs.group.description.label')"
|
|
430
|
+
/>
|
|
431
|
+
</div>
|
|
432
|
+
</div>
|
|
433
|
+
|
|
434
|
+
<h4 v-t="'navLink.tabs.groupImage.label'" />
|
|
435
|
+
<div class="row">
|
|
436
|
+
<label class="text-label">
|
|
437
|
+
{{ t('navLink.tabs.groupImage.iconSrc.tip', {}, true) }}
|
|
438
|
+
</label>
|
|
439
|
+
</div>
|
|
440
|
+
<div class="row">
|
|
441
|
+
<FileImageSelector
|
|
442
|
+
v-model="value.spec.iconSrc"
|
|
443
|
+
:read-as-data-url="true"
|
|
444
|
+
:mode="mode"
|
|
445
|
+
:label="t('navLink.tabs.groupImage.iconSrc.label')"
|
|
446
|
+
accept="image/jpeg,image/png,image/svg+xml"
|
|
447
|
+
@error="setImageError"
|
|
448
|
+
@input="setIcon"
|
|
449
|
+
/>
|
|
450
|
+
</div>
|
|
451
|
+
<Banner
|
|
452
|
+
v-if="imageError"
|
|
453
|
+
color="error"
|
|
454
|
+
>
|
|
455
|
+
{{ imageErrorMessage }}
|
|
456
|
+
</Banner>
|
|
430
457
|
</CruResource>
|
|
431
458
|
</template>
|
package/layouts/default.vue
CHANGED
|
@@ -38,7 +38,7 @@ import PageHeaderActions from '@shell/mixins/page-actions';
|
|
|
38
38
|
import BrowserTabVisibility from '@shell/mixins/browser-tab-visibility';
|
|
39
39
|
import { getClusterFromRoute, getProductFromRoute } from '@shell/middleware/authenticated';
|
|
40
40
|
import { BOTTOM } from '@shell/utils/position';
|
|
41
|
-
import { BLANK_CLUSTER } from '@shell/store';
|
|
41
|
+
import { BLANK_CLUSTER } from '@shell/store/store-types.js';
|
|
42
42
|
|
|
43
43
|
const SET_LOGIN_ACTION = 'set-as-login';
|
|
44
44
|
|
package/list/group.principal.vue
CHANGED
|
@@ -8,7 +8,7 @@ import { applyProducts } from '@shell/store/type-map';
|
|
|
8
8
|
import { NAME } from '@shell/config/product/auth';
|
|
9
9
|
import { MODE, _EDIT } from '@shell/config/query-params';
|
|
10
10
|
import { mapState } from 'vuex';
|
|
11
|
-
import { BLANK_CLUSTER } from '@shell/store';
|
|
11
|
+
import { BLANK_CLUSTER } from '@shell/store/store-types.js';
|
|
12
12
|
import { allHash } from '@shell/utils/promise';
|
|
13
13
|
|
|
14
14
|
export default {
|
|
@@ -126,12 +126,20 @@ function setProduct(store, to, redirect) {
|
|
|
126
126
|
*/
|
|
127
127
|
function invalidResource(store, to, redirect) {
|
|
128
128
|
const product = store.getters['currentProduct'];
|
|
129
|
-
const inStore = product?.inStore;
|
|
130
|
-
const schemaFor = store.getters[`${ inStore }/schemaFor`]; // There's a chance we're in an extension's product who's store could be anything
|
|
131
129
|
const resource = getResourceFromRoute(to);
|
|
132
130
|
|
|
133
|
-
// In order to check a resource is valid we need
|
|
134
|
-
if (!product || !
|
|
131
|
+
// In order to check a resource is valid we need these
|
|
132
|
+
if (!product || !resource) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Note - don't use the current products store... because products can override stores for resources with `typeStoreMap`
|
|
137
|
+
const inStore = store.getters['currentStore'](resource);
|
|
138
|
+
// There's a chance we're in an extension's product who's store could be anything, so confirm schemaFor exists
|
|
139
|
+
const schemaFor = store.getters[`${ inStore }/schemaFor`];
|
|
140
|
+
|
|
141
|
+
// In order to check a resource is valid we need these
|
|
142
|
+
if (!inStore || !schemaFor) {
|
|
135
143
|
return false;
|
|
136
144
|
}
|
|
137
145
|
|
|
@@ -65,9 +65,9 @@ export default {
|
|
|
65
65
|
|
|
66
66
|
let name = this.$route.name;
|
|
67
67
|
|
|
68
|
-
if ( name
|
|
68
|
+
if ( name?.endsWith('-id') ) {
|
|
69
69
|
name = name.replace(/(-namespace)?-id$/, '');
|
|
70
|
-
} else if ( name
|
|
70
|
+
} else if ( name?.endsWith('-create') ) {
|
|
71
71
|
name = name.replace(/-create$/, '');
|
|
72
72
|
}
|
|
73
73
|
|
package/models/chart.js
CHANGED
|
@@ -2,7 +2,7 @@ import { compatibleVersionsFor } from '@shell/store/catalog';
|
|
|
2
2
|
import {
|
|
3
3
|
REPO_TYPE, REPO, CHART, VERSION, _FLAGGED, HIDE_SIDE_NAV
|
|
4
4
|
} from '@shell/config/query-params';
|
|
5
|
-
import { BLANK_CLUSTER } from '@shell/store';
|
|
5
|
+
import { BLANK_CLUSTER } from '@shell/store/store-types.js';
|
|
6
6
|
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
7
7
|
|
|
8
8
|
export default class Chart extends SteveModel {
|
package/models/etcdbackup.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import NormanModel from '@shell/plugins/steve/norman-class';
|
|
2
|
+
import { STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
|
|
2
3
|
|
|
3
4
|
export default class Rke1EtcdBackup extends NormanModel {
|
|
4
5
|
get _availableActions() {
|
|
5
6
|
const restore = {
|
|
6
7
|
action: 'promptRestore',
|
|
7
|
-
enabled:
|
|
8
|
+
enabled: this.state === STATES_ENUM.ACTIVE,
|
|
8
9
|
icon: 'icon icon-fw icon-backup-restore',
|
|
9
10
|
label: 'Restore'
|
|
10
11
|
};
|
|
@@ -4,6 +4,7 @@ import { _RKE2 } from '@shell/store/prefs';
|
|
|
4
4
|
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
5
5
|
import { escapeHtml } from '@shell/utils/string';
|
|
6
6
|
import { insertAt } from '@shell/utils/array';
|
|
7
|
+
import jsyaml from 'js-yaml';
|
|
7
8
|
|
|
8
9
|
export default class FleetCluster extends SteveModel {
|
|
9
10
|
get _availableActions() {
|
|
@@ -89,7 +90,7 @@ export default class FleetCluster extends SteveModel {
|
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
get state() {
|
|
92
|
-
if (
|
|
93
|
+
if (this.spec?.paused === true) {
|
|
93
94
|
return 'paused';
|
|
94
95
|
}
|
|
95
96
|
|
|
@@ -124,19 +125,47 @@ export default class FleetCluster extends SteveModel {
|
|
|
124
125
|
return mgmt;
|
|
125
126
|
}
|
|
126
127
|
|
|
127
|
-
get
|
|
128
|
-
const norman = this.$rootGetters['rancher/byId'](NORMAN.CLUSTER, this.metadata
|
|
128
|
+
get basicNorman() {
|
|
129
|
+
const norman = this.$rootGetters['rancher/byId'](NORMAN.CLUSTER, this.metadata?.labels?.[FLEET_LABELS.CLUSTER_NAME]);
|
|
129
130
|
|
|
130
131
|
return norman;
|
|
131
132
|
}
|
|
132
133
|
|
|
134
|
+
get norman() {
|
|
135
|
+
if (this.basicNorman) {
|
|
136
|
+
return this.basicNorman;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// If navigate to YAML view directly, norman is not loaded yet
|
|
140
|
+
return this.$dispatch('rancher/find', { type: NORMAN.CLUSTER, id: this.metadata.labels[FLEET_LABELS.CLUSTER_NAME] }, { root: true });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async normanClone() {
|
|
144
|
+
const norman = await this.norman;
|
|
145
|
+
|
|
146
|
+
return this.$dispatch('rancher/clone', { resource: norman }, { root: true });
|
|
147
|
+
}
|
|
148
|
+
|
|
133
149
|
get groupByLabel() {
|
|
134
150
|
const name = this.metadata.namespace;
|
|
135
151
|
|
|
136
|
-
if (
|
|
152
|
+
if (name) {
|
|
137
153
|
return this.$rootGetters['i18n/t']('resourceTable.groupLabel.workspace', { name: escapeHtml(name) });
|
|
138
154
|
} else {
|
|
139
155
|
return this.$rootGetters['i18n/t']('resourceTable.groupLabel.notInAWorkspace');
|
|
140
156
|
}
|
|
141
157
|
}
|
|
158
|
+
|
|
159
|
+
async saveYaml(yaml) {
|
|
160
|
+
await this._saveYaml(yaml);
|
|
161
|
+
|
|
162
|
+
const parsed = jsyaml.load(yaml);
|
|
163
|
+
|
|
164
|
+
const norman = await this.normanClone();
|
|
165
|
+
|
|
166
|
+
norman.setLabels(parsed.metadata.labels);
|
|
167
|
+
norman.setAnnotations(parsed.metadata.annotations);
|
|
168
|
+
|
|
169
|
+
await norman.save();
|
|
170
|
+
}
|
|
142
171
|
}
|