@rancher/shell 0.3.17 → 0.3.18
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 +7 -5
- package/components/ResourceDetail/Masthead.vue +1 -1
- package/components/ResourceDetail/index.vue +4 -2
- package/components/__tests__/PromptRestore.test.ts +72 -0
- package/components/auth/AzureWarning.vue +1 -1
- 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/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 -187
- 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/fleet.cattle.io.cluster.js +33 -4
- package/models/fleet.cattle.io.gitrepo.js +112 -38
- 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/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/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/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 +695 -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/validators/formRules/index.ts +3 -3
- package/plugins/steve/urloptions.js +0 -47
|
@@ -7,11 +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';
|
|
14
|
-
import { normalizeName } from '@shell/
|
|
11
|
+
import NameNsDescription, { normalizeName } from '@shell/components/form/NameNsDescription';
|
|
12
|
+
import { Banner } from '@components/Banner';
|
|
13
|
+
import FormValidation from '@shell/mixins/form-validation';
|
|
15
14
|
|
|
16
15
|
const LINK_TYPE_URL = 'url';
|
|
17
16
|
const LINK_TYPE_SERVICE = 'service';
|
|
@@ -20,16 +19,15 @@ const LINK_TARGET_BLANK = '_blank';
|
|
|
20
19
|
const LINK_TARGET_SELF = '_self';
|
|
21
20
|
|
|
22
21
|
export default {
|
|
23
|
-
mixins: [CreateEditView],
|
|
22
|
+
mixins: [CreateEditView, FormValidation],
|
|
24
23
|
components: {
|
|
25
24
|
CruResource,
|
|
26
25
|
LabeledInput,
|
|
27
26
|
RadioGroup,
|
|
28
27
|
NameNsDescription,
|
|
29
|
-
Tabbed,
|
|
30
|
-
Tab,
|
|
31
28
|
FileImageSelector,
|
|
32
|
-
LabeledSelect
|
|
29
|
+
LabeledSelect,
|
|
30
|
+
Banner
|
|
33
31
|
},
|
|
34
32
|
data() {
|
|
35
33
|
return {
|
|
@@ -57,12 +55,19 @@ export default {
|
|
|
57
55
|
label: this.t('navLink.tabs.link.type.service')
|
|
58
56
|
}
|
|
59
57
|
],
|
|
60
|
-
currentLinkType:
|
|
61
|
-
targetName:
|
|
62
|
-
currentTarget:
|
|
63
|
-
protocolsOptions:
|
|
64
|
-
services:
|
|
65
|
-
currentService:
|
|
58
|
+
currentLinkType: null,
|
|
59
|
+
targetName: null,
|
|
60
|
+
currentTarget: LINK_TARGET_BLANK,
|
|
61
|
+
protocolsOptions: PROTOCOLS,
|
|
62
|
+
services: [],
|
|
63
|
+
currentService: null,
|
|
64
|
+
imageErrorMessage: '',
|
|
65
|
+
fvFormRuleSets: [
|
|
66
|
+
{ path: 'metadata.name', rules: ['nameRequired'] },
|
|
67
|
+
{ path: 'spec.toURL', rules: ['urlRequired'] },
|
|
68
|
+
{ path: 'spec.toService.namespace', rules: ['serviceNamespaceRequired'] },
|
|
69
|
+
{ path: 'spec.toService.scheme', rules: ['serviceSchemeRequired'] }],
|
|
70
|
+
|
|
66
71
|
};
|
|
67
72
|
},
|
|
68
73
|
props: {
|
|
@@ -113,6 +118,44 @@ export default {
|
|
|
113
118
|
label: id, id, name, namespace
|
|
114
119
|
}) );
|
|
115
120
|
},
|
|
121
|
+
imageError() {
|
|
122
|
+
return !!this.imageErrorMessage && !this.value.spec.iconSrc;
|
|
123
|
+
},
|
|
124
|
+
fvExtraRules() {
|
|
125
|
+
const isLinkTypeUrl = this.currentLinkType === LINK_TYPE_URL;
|
|
126
|
+
const isServiceTypeUrl = this.currentLinkType === LINK_TYPE_SERVICE;
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
nameRequired: () => {
|
|
130
|
+
if (!this.value.metadata.name) {
|
|
131
|
+
return this.getError('navLink.name.label');
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
urlRequired: () => {
|
|
136
|
+
const condition = this.value.spec.toURL;
|
|
137
|
+
|
|
138
|
+
if (isLinkTypeUrl && !condition) {
|
|
139
|
+
return this.getError('navLink.tabs.link.toURL.label');
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
serviceNamespaceRequired: () => {
|
|
143
|
+
const condition = this.value.spec.toService.name && this.value.spec.toService.namespace;
|
|
144
|
+
|
|
145
|
+
if (isServiceTypeUrl && !condition) {
|
|
146
|
+
return this.getError('navLink.tabs.link.toService.service.label');
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
serviceSchemeRequired: () => {
|
|
150
|
+
const condition = this.value.spec.toService.scheme;
|
|
151
|
+
|
|
152
|
+
if (isServiceTypeUrl && !condition) {
|
|
153
|
+
return this.getError('navLink.tabs.link.toService.scheme.label');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
};
|
|
158
|
+
}
|
|
116
159
|
},
|
|
117
160
|
async fetch() {
|
|
118
161
|
this.services = await this.$store
|
|
@@ -215,50 +258,20 @@ export default {
|
|
|
215
258
|
getError(label) {
|
|
216
259
|
return this.$store.getters['i18n/t']('validation.required', { key: this.t(label) });
|
|
217
260
|
},
|
|
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
261
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
}
|
|
239
|
-
break;
|
|
240
|
-
|
|
241
|
-
// no default
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
if (!this.value.metadata.name) {
|
|
245
|
-
errors.push(this.getError('navLink.name.label'));
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
if (errors.length) {
|
|
249
|
-
throw (errors.join('\n'));
|
|
250
|
-
}
|
|
262
|
+
setImageError(e) {
|
|
263
|
+
this.imageErrorMessage = e;
|
|
251
264
|
},
|
|
265
|
+
setIcon(value) {
|
|
266
|
+
this.imageErrorMessage = '';
|
|
267
|
+
this.$emit('update:value.spec.iconSrc ', value);
|
|
268
|
+
}
|
|
252
269
|
},
|
|
253
270
|
created() {
|
|
254
271
|
this.setDefaultValues();
|
|
255
272
|
this.setUrlType();
|
|
256
273
|
this.setTargetOption();
|
|
257
274
|
this.setCurrentService();
|
|
258
|
-
// Validate error presence by allowing or resetting submission process
|
|
259
|
-
if (this.registerBeforeHook) {
|
|
260
|
-
this.registerBeforeHook(this.validate);
|
|
261
|
-
}
|
|
262
275
|
}
|
|
263
276
|
};
|
|
264
277
|
</script>
|
|
@@ -268,8 +281,10 @@ export default {
|
|
|
268
281
|
:can-yaml="!isCreate"
|
|
269
282
|
:mode="mode"
|
|
270
283
|
:resource="value"
|
|
271
|
-
:errors="
|
|
284
|
+
:errors="fvUnreportedValidationErrors"
|
|
272
285
|
:cancel-event="true"
|
|
286
|
+
:validation-passed="fvFormIsValid"
|
|
287
|
+
data-testid="Navlink-CRU"
|
|
273
288
|
@error="e=>errors = e"
|
|
274
289
|
@finish="save"
|
|
275
290
|
@cancel="done()"
|
|
@@ -285,147 +300,158 @@ export default {
|
|
|
285
300
|
name-placeholder="navLink.name.placeholder"
|
|
286
301
|
description-label="navLink.label.label"
|
|
287
302
|
description-placeholder="navLink.label.placeholder"
|
|
303
|
+
data-testid="Navlink-name-field"
|
|
304
|
+
:rules="{ name: fvGetAndReportPathRules('metadata.name'), namespace: [], description: [] }"
|
|
288
305
|
/>
|
|
289
306
|
|
|
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>
|
|
307
|
+
<div class="spacer" />
|
|
308
|
+
<h2 v-t="'navLink.tabs.link.label'" />
|
|
309
|
+
<div class="row mb-20">
|
|
310
|
+
<div class="col span-6">
|
|
311
|
+
<RadioGroup
|
|
312
|
+
v-model="linkType"
|
|
313
|
+
name="type"
|
|
314
|
+
:mode="mode"
|
|
315
|
+
:options="urlTypeOptions"
|
|
316
|
+
data-testid="Navlink-link-radiogroup"
|
|
317
|
+
/>
|
|
318
|
+
</div>
|
|
319
|
+
</div>
|
|
362
320
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
321
|
+
<template v-if="isURL">
|
|
322
|
+
<div class="row mb-20">
|
|
323
|
+
<LabeledInput
|
|
324
|
+
v-model="value.spec.toURL"
|
|
325
|
+
:mode="mode"
|
|
326
|
+
:label="t('navLink.tabs.link.toURL.label')"
|
|
327
|
+
:required="isURL"
|
|
328
|
+
:placeholder="t('navLink.tabs.link.toURL.placeholder')"
|
|
329
|
+
:rules="fvGetAndReportPathRules('spec.toURL')"
|
|
330
|
+
data-testid="Navlink-url-field"
|
|
331
|
+
/>
|
|
332
|
+
</div>
|
|
333
|
+
</template>
|
|
334
|
+
<template v-if="isService">
|
|
335
|
+
<div class="row mb-20">
|
|
336
|
+
<div class="col span-2">
|
|
337
|
+
<LabeledSelect
|
|
338
|
+
v-model="value.spec.toService.scheme"
|
|
339
|
+
:mode="mode"
|
|
340
|
+
:label="t('navLink.tabs.link.toService.scheme.label')"
|
|
341
|
+
:required="isService"
|
|
342
|
+
:options="protocolsOptions"
|
|
343
|
+
:placeholder="t('navLink.tabs.link.toService.scheme.placeholder')"
|
|
344
|
+
:rules="fvGetAndReportPathRules('spec.toService.scheme')"
|
|
345
|
+
data-testid="Navlink-scheme-field"
|
|
346
|
+
/>
|
|
387
347
|
</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>
|
|
348
|
+
<div class="col span-5">
|
|
349
|
+
<LabeledSelect
|
|
350
|
+
v-model="currentService"
|
|
351
|
+
:mode="mode"
|
|
352
|
+
:label="t('navLink.tabs.link.toService.service.label')"
|
|
353
|
+
:options="mappedServices"
|
|
354
|
+
:required="isService"
|
|
355
|
+
:placeholder="t('navLink.tabs.link.toService.service.placeholder')"
|
|
356
|
+
:rules="fvGetAndReportPathRules('spec.toService.namespace')"
|
|
357
|
+
data-testid="Navlink-currentService-field"
|
|
358
|
+
@input="setService"
|
|
359
|
+
/>
|
|
410
360
|
</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>
|
|
361
|
+
<div class="col span-2">
|
|
362
|
+
<LabeledInput
|
|
363
|
+
v-model="value.spec.toService.port"
|
|
364
|
+
:mode="mode"
|
|
365
|
+
:label="t('navLink.tabs.link.toService.port.label')"
|
|
366
|
+
type="number"
|
|
367
|
+
:placeholder="t('navLink.tabs.link.toService.port.placeholder')"
|
|
368
|
+
/>
|
|
427
369
|
</div>
|
|
428
|
-
|
|
429
|
-
|
|
370
|
+
<div class="col span-3">
|
|
371
|
+
<LabeledInput
|
|
372
|
+
v-model="value.spec.toService.path"
|
|
373
|
+
:mode="mode"
|
|
374
|
+
:label="t('navLink.tabs.link.toService.path.label')"
|
|
375
|
+
:placeholder="t('navLink.tabs.link.toService.path.placeholder')"
|
|
376
|
+
/>
|
|
377
|
+
</div>
|
|
378
|
+
</div>
|
|
379
|
+
</template>
|
|
380
|
+
<div class="spacer" />
|
|
381
|
+
<h2 v-t="'navLink.tabs.target.label'" />
|
|
382
|
+
<div class="row mb-20">
|
|
383
|
+
<div class="col span-6">
|
|
384
|
+
<RadioGroup
|
|
385
|
+
v-model="currentTarget"
|
|
386
|
+
name="type"
|
|
387
|
+
:mode="mode"
|
|
388
|
+
:options="targetOptions"
|
|
389
|
+
@input="setTargetValue($event)"
|
|
390
|
+
/>
|
|
391
|
+
</div>
|
|
392
|
+
<div class="col span-6">
|
|
393
|
+
<LabeledInput
|
|
394
|
+
v-if="isNamedWindow"
|
|
395
|
+
v-model="targetName"
|
|
396
|
+
:mode="mode"
|
|
397
|
+
:label="t('navLink.tabs.target.namedValue.label')"
|
|
398
|
+
@input="setTargetValue($event);"
|
|
399
|
+
/>
|
|
400
|
+
</div>
|
|
401
|
+
</div>
|
|
402
|
+
<div class="spacer" />
|
|
403
|
+
<h2 v-t="'navLink.tabs.group.label'" />
|
|
404
|
+
|
|
405
|
+
<div class="row mb-20">
|
|
406
|
+
<div class="col span-6">
|
|
407
|
+
<LabeledInput
|
|
408
|
+
v-model="value.spec.group"
|
|
409
|
+
:mode="mode"
|
|
410
|
+
:tooltip="t('navLink.tabs.group.group.tooltip')"
|
|
411
|
+
:label="t('navLink.tabs.group.group.label')"
|
|
412
|
+
/>
|
|
413
|
+
</div>
|
|
414
|
+
<div class="col span-6">
|
|
415
|
+
<LabeledInput
|
|
416
|
+
v-model="value.spec.sideLabel"
|
|
417
|
+
:mode="mode"
|
|
418
|
+
:label="t('navLink.tabs.group.sideLabel.label')"
|
|
419
|
+
/>
|
|
420
|
+
</div>
|
|
421
|
+
</div>
|
|
422
|
+
|
|
423
|
+
<div class="row mb-20">
|
|
424
|
+
<div class="col span-6">
|
|
425
|
+
<LabeledInput
|
|
426
|
+
v-model="value.spec.description"
|
|
427
|
+
:mode="mode"
|
|
428
|
+
:label="t('navLink.tabs.group.description.label')"
|
|
429
|
+
/>
|
|
430
|
+
</div>
|
|
431
|
+
</div>
|
|
432
|
+
|
|
433
|
+
<h4 v-t="'navLink.tabs.groupImage.label'" />
|
|
434
|
+
<div class="row">
|
|
435
|
+
<label class="text-label">
|
|
436
|
+
{{ t('navLink.tabs.groupImage.iconSrc.tip', {}, true) }}
|
|
437
|
+
</label>
|
|
438
|
+
</div>
|
|
439
|
+
<div class="row">
|
|
440
|
+
<FileImageSelector
|
|
441
|
+
v-model="value.spec.iconSrc"
|
|
442
|
+
:read-as-data-url="true"
|
|
443
|
+
:mode="mode"
|
|
444
|
+
:label="t('navLink.tabs.groupImage.iconSrc.label')"
|
|
445
|
+
accept="image/jpeg,image/png,image/svg+xml"
|
|
446
|
+
@error="setImageError"
|
|
447
|
+
@input="setIcon"
|
|
448
|
+
/>
|
|
449
|
+
</div>
|
|
450
|
+
<Banner
|
|
451
|
+
v-if="imageError"
|
|
452
|
+
color="error"
|
|
453
|
+
>
|
|
454
|
+
{{ imageErrorMessage }}
|
|
455
|
+
</Banner>
|
|
430
456
|
</CruResource>
|
|
431
457
|
</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 {
|
|
@@ -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
|
}
|