@rancher/shell 0.3.19 → 0.3.21
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 +4 -1
- package/components/PromptModal.vue +4 -0
- package/components/Questions/Array.vue +2 -2
- package/components/Questions/Boolean.vue +7 -1
- package/components/Questions/CloudCredential.vue +1 -0
- package/components/Questions/Enum.vue +21 -2
- package/components/Questions/Float.vue +8 -3
- package/components/Questions/Int.vue +8 -3
- package/components/Questions/Question.js +72 -0
- package/components/Questions/QuestionMap.vue +2 -1
- package/components/Questions/Radio.vue +33 -0
- package/components/Questions/Reference.vue +2 -0
- package/components/Questions/String.vue +8 -3
- package/components/Questions/Yaml.vue +46 -0
- package/components/Questions/__tests__/Boolean.test.ts +123 -0
- package/components/Questions/__tests__/Float.test.ts +123 -0
- package/components/Questions/__tests__/Int.test.ts +123 -0
- package/components/Questions/__tests__/String.test.ts +123 -0
- package/components/Questions/__tests__/Yaml.test.ts +123 -0
- package/components/Questions/index.vue +8 -1
- package/components/ResourceTable.vue +10 -13
- package/components/SideNav.vue +634 -0
- package/components/__tests__/NamespaceFilter.test.ts +3 -4
- package/components/form/UnitInput.vue +1 -0
- package/components/form/__tests__/KeyValue.test.ts +2 -1
- package/components/form/__tests__/UnitInput.test.ts +2 -2
- package/components/formatter/LinkName.vue +12 -1
- package/components/nav/WorkspaceSwitcher.vue +4 -1
- package/core/plugin-helpers.js +4 -1
- package/core/types.ts +25 -1
- package/detail/node.vue +2 -2
- package/edit/fleet.cattle.io.gitrepo.vue +7 -0
- package/layouts/default.vue +11 -597
- package/middleware/authenticated.js +2 -14
- package/models/fleet.cattle.io.gitrepo.js +3 -1
- package/package.json +1 -1
- package/pages/auth/login.vue +1 -1
- package/pages/c/_cluster/fleet/index.vue +4 -0
- package/pages/c/_cluster/uiplugins/index.vue +3 -3
- package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +8 -0
- package/rancher-components/components/Form/Radio/RadioButton.test.ts +7 -3
- package/store/auth.js +2 -0
- package/types/shell/index.d.ts +2 -0
- package/utils/auth.js +17 -0
- package/utils/object.js +0 -1
- package/utils/validators/__tests__/cidr.test.ts +33 -0
- package/utils/validators/cidr.js +5 -0
|
@@ -15,6 +15,7 @@ import dynamicPluginLoader from '@shell/pkg/dynamic-plugin-loader';
|
|
|
15
15
|
import { AFTER_LOGIN_ROUTE, WORKSPACE } from '@shell/store/prefs';
|
|
16
16
|
import { BACK_TO } from '@shell/config/local-storage';
|
|
17
17
|
import { NAME as FLEET_NAME } from '@shell/config/product/fleet.js';
|
|
18
|
+
import { canViewResource } from '@shell/utils/auth';
|
|
18
19
|
|
|
19
20
|
const getPackageFromRoute = (route) => {
|
|
20
21
|
if (!route?.meta) {
|
|
@@ -133,20 +134,7 @@ function invalidResource(store, to, redirect) {
|
|
|
133
134
|
return false;
|
|
134
135
|
}
|
|
135
136
|
|
|
136
|
-
|
|
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) {
|
|
143
|
-
return false;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Resource is valid if a schema exists for it (standard resource, spoofed resource) or it's a virtual resource
|
|
147
|
-
const validResource = schemaFor(resource) || store.getters['type-map/isVirtual'](resource);
|
|
148
|
-
|
|
149
|
-
if (validResource) {
|
|
137
|
+
if (canViewResource(store, resource)) {
|
|
150
138
|
return false;
|
|
151
139
|
}
|
|
152
140
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import Vue from 'vue';
|
|
1
2
|
import { convert, matching, convertSelectorObj } from '@shell/utils/selector';
|
|
2
3
|
import jsyaml from 'js-yaml';
|
|
3
4
|
import { escapeHtml, randomStr } from '@shell/utils/string';
|
|
@@ -32,7 +33,8 @@ export default class GitRepo extends SteveModel {
|
|
|
32
33
|
|
|
33
34
|
spec.paths = spec.paths || [];
|
|
34
35
|
spec.clientSecretName = spec.clientSecretName || null;
|
|
35
|
-
|
|
36
|
+
|
|
37
|
+
Vue.set(spec, 'correctDrift', { enabled: false });
|
|
36
38
|
|
|
37
39
|
set(this, 'spec', spec);
|
|
38
40
|
set(this, 'metadata', meta);
|
package/package.json
CHANGED
package/pages/auth/login.vue
CHANGED
|
@@ -377,6 +377,7 @@ export default {
|
|
|
377
377
|
:title="`${t('resourceDetail.masthead.workspace')}: ${ws.nameDisplay}`"
|
|
378
378
|
:is-collapsed="isCollapsed[ws.id]"
|
|
379
379
|
:is-title-clickable="true"
|
|
380
|
+
:data-testid="`collapsible-card-${ ws.id }`"
|
|
380
381
|
@toggleCollapse="toggleCollapse($event, ws.id)"
|
|
381
382
|
@titleClick="setWorkspaceFilterAndLinkToGitRepo(ws.id)"
|
|
382
383
|
>
|
|
@@ -411,6 +412,7 @@ export default {
|
|
|
411
412
|
<span v-if="ws.type === 'namespace'"> - </span>
|
|
412
413
|
<CompoundStatusBadge
|
|
413
414
|
v-else
|
|
415
|
+
data-testid="clusters-ready"
|
|
414
416
|
:tooltip-text="getTooltipInfo('clusters', row)"
|
|
415
417
|
:badge-class="getStatusInfo('clusters', row).badgeClass"
|
|
416
418
|
:icon="getStatusInfo('clusters', row).icon"
|
|
@@ -421,6 +423,7 @@ export default {
|
|
|
421
423
|
<span v-if="ws.type === 'namespace'"> - </span>
|
|
422
424
|
<CompoundStatusBadge
|
|
423
425
|
v-else
|
|
426
|
+
data-testid="bundles-ready"
|
|
424
427
|
:tooltip-text="getTooltipInfo('bundles', row)"
|
|
425
428
|
:badge-class="getStatusInfo('bundles', row).badgeClass"
|
|
426
429
|
:icon="getStatusInfo('bundles', row).icon"
|
|
@@ -429,6 +432,7 @@ export default {
|
|
|
429
432
|
</template>
|
|
430
433
|
<template #cell:resourcesReady="{row}">
|
|
431
434
|
<CompoundStatusBadge
|
|
435
|
+
data-testid="resources-ready"
|
|
432
436
|
:tooltip-text="getTooltipInfo('resources', row)"
|
|
433
437
|
:badge-class="getStatusInfo('resources', row).badgeClass"
|
|
434
438
|
:icon="getStatusInfo('resources', row).icon"
|
|
@@ -243,9 +243,9 @@ export default {
|
|
|
243
243
|
|
|
244
244
|
all = all.map((chart) => {
|
|
245
245
|
// Label can be overridden by chart annotation
|
|
246
|
-
const label = uiPluginAnnotation(UI_PLUGIN_CHART_ANNOTATIONS.DISPLAY_NAME) || chart.chartNameDisplay;
|
|
246
|
+
const label = uiPluginAnnotation(chart, UI_PLUGIN_CHART_ANNOTATIONS.DISPLAY_NAME) || chart.chartNameDisplay;
|
|
247
247
|
const item = {
|
|
248
|
-
name: chart.
|
|
248
|
+
name: chart.chartName,
|
|
249
249
|
label,
|
|
250
250
|
description: chart.chartDescription,
|
|
251
251
|
id: chart.id,
|
|
@@ -305,7 +305,7 @@ export default {
|
|
|
305
305
|
if (!chart) {
|
|
306
306
|
// A plugin is loaded, but there is no chart, so add an item so that it shows up
|
|
307
307
|
const rancher = typeof p.metadata?.rancher === 'object' ? p.metadata.rancher : {};
|
|
308
|
-
const label = rancher[UI_PLUGIN_CHART_ANNOTATIONS.DISPLAY_NAME] || p.name;
|
|
308
|
+
const label = rancher.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.DISPLAY_NAME] || p.name;
|
|
309
309
|
const item = {
|
|
310
310
|
name: p.name,
|
|
311
311
|
label,
|
|
@@ -206,6 +206,13 @@ export default (
|
|
|
206
206
|
}
|
|
207
207
|
},
|
|
208
208
|
|
|
209
|
+
/**
|
|
210
|
+
* Emit on input change
|
|
211
|
+
*/
|
|
212
|
+
onChange(event: Event): void {
|
|
213
|
+
this.$emit('change', event);
|
|
214
|
+
},
|
|
215
|
+
|
|
209
216
|
/**
|
|
210
217
|
* Emit on input with delay. Note: Arrow function is avoided due context
|
|
211
218
|
* binding.
|
|
@@ -299,6 +306,7 @@ export default (
|
|
|
299
306
|
@input="onInput($event.target.value)"
|
|
300
307
|
@focus="onFocus"
|
|
301
308
|
@blur="onBlur"
|
|
309
|
+
@change="onChange"
|
|
302
310
|
>
|
|
303
311
|
</slot>
|
|
304
312
|
|
|
@@ -4,7 +4,7 @@ import { cleanHtmlDirective } from '@shell/plugins/clean-html-directive';
|
|
|
4
4
|
|
|
5
5
|
describe('radioButton.vue', () => {
|
|
6
6
|
it('renders label slot contents', () => {
|
|
7
|
-
const wrapper = shallowMount(RadioButton, { slots: { label: 'Test Label' } });
|
|
7
|
+
const wrapper = shallowMount(RadioButton, { slots: { label: 'Test Label' }, propsData: { val: {}, value: {} } });
|
|
8
8
|
|
|
9
9
|
expect(wrapper.find('.radio-label').text()).toBe('Test Label');
|
|
10
10
|
});
|
|
@@ -14,7 +14,9 @@ describe('radioButton.vue', () => {
|
|
|
14
14
|
RadioButton,
|
|
15
15
|
{
|
|
16
16
|
directives: { cleanHtmlDirective },
|
|
17
|
-
propsData: {
|
|
17
|
+
propsData: {
|
|
18
|
+
label: 'Test Label', val: {}, value: {}
|
|
19
|
+
}
|
|
18
20
|
});
|
|
19
21
|
|
|
20
22
|
expect(wrapper.find('.radio-label').text()).toBe('Test Label');
|
|
@@ -23,7 +25,9 @@ describe('radioButton.vue', () => {
|
|
|
23
25
|
it('renders slot contents when both slot and label prop are provided', () => {
|
|
24
26
|
const wrapper = shallowMount(RadioButton, {
|
|
25
27
|
slots: { label: 'Test Label - Slot' },
|
|
26
|
-
propsData: {
|
|
28
|
+
propsData: {
|
|
29
|
+
label: 'Test Label - Props', val: {}, value: {}
|
|
30
|
+
},
|
|
27
31
|
});
|
|
28
32
|
|
|
29
33
|
expect(wrapper.find('.radio-label').text()).toBe('Test Label - Slot');
|
package/store/auth.js
CHANGED
|
@@ -334,6 +334,8 @@ export const actions = {
|
|
|
334
334
|
} catch (err) {
|
|
335
335
|
if (err._status === 401) {
|
|
336
336
|
return Promise.reject(LOGIN_ERRORS.CLIENT_UNAUTHORIZED);
|
|
337
|
+
} else if (err.message) {
|
|
338
|
+
return Promise.reject(err.message);
|
|
337
339
|
} else if ( err._status >= 400 && err._status <= 499 ) {
|
|
338
340
|
return Promise.reject(LOGIN_ERRORS.CLIENT);
|
|
339
341
|
}
|
package/types/shell/index.d.ts
CHANGED
|
@@ -3029,6 +3029,7 @@ export function authProvidersInfo(store: any): Promise<{
|
|
|
3029
3029
|
}>;
|
|
3030
3030
|
export function checkSchemasForFindAllHash(types: any, store: any): any;
|
|
3031
3031
|
export function checkPermissions(types: any, getters: any): any;
|
|
3032
|
+
export function canViewResource(store: any, resource: any): boolean;
|
|
3032
3033
|
}
|
|
3033
3034
|
|
|
3034
3035
|
// @shell/utils/aws
|
|
@@ -4060,6 +4061,7 @@ export default _default;
|
|
|
4060
4061
|
|
|
4061
4062
|
declare module '@shell/utils/validators/cidr' {
|
|
4062
4063
|
export function isValidCIDR(cidr: any): boolean;
|
|
4064
|
+
export function isValidIP(ip: any): boolean;
|
|
4063
4065
|
export function isValidMac(value: any): boolean;
|
|
4064
4066
|
}
|
|
4065
4067
|
|
package/utils/auth.js
CHANGED
|
@@ -144,3 +144,20 @@ export const checkPermissions = (types, getters) => {
|
|
|
144
144
|
|
|
145
145
|
return allHash(hash);
|
|
146
146
|
};
|
|
147
|
+
|
|
148
|
+
export const canViewResource = (store, resource) => {
|
|
149
|
+
// Note - don't use the current products store... because products can override stores for resources with `typeStoreMap`
|
|
150
|
+
const inStore = store.getters['currentStore'](resource);
|
|
151
|
+
// There's a chance we're in an extension's product who's store could be anything, so confirm schemaFor exists
|
|
152
|
+
const schemaFor = store.getters[`${ inStore }/schemaFor`];
|
|
153
|
+
|
|
154
|
+
// In order to check a resource is valid we need these
|
|
155
|
+
if (!inStore || !schemaFor) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Resource is valid if a schema exists for it (standard resource, spoofed resource) or it's a virtual resource
|
|
160
|
+
const validResource = schemaFor(resource) || store.getters['type-map/isVirtual'](resource);
|
|
161
|
+
|
|
162
|
+
return !!validResource;
|
|
163
|
+
};
|
package/utils/object.js
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isValidCIDR, isValidIP, isValidMac } from '@shell/utils/validators/cidr';
|
|
2
|
+
|
|
3
|
+
describe('fx: isValidCIDR', () => {
|
|
4
|
+
it('should be valid', () => {
|
|
5
|
+
expect(isValidCIDR('10.42.0.0/8')).toBe(true);
|
|
6
|
+
});
|
|
7
|
+
it('should be invalid', () => {
|
|
8
|
+
expect(isValidCIDR('10.42.0.0')).toBe(false);
|
|
9
|
+
expect(isValidCIDR('10.42.0.0/500')).toBe(false);
|
|
10
|
+
expect(isValidCIDR('300.42.0.0/8')).toBe(false);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('fx: isValidIP', () => {
|
|
15
|
+
it('should be valid', () => {
|
|
16
|
+
expect(isValidIP('10.42.0.1')).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
it('should be invalid', () => {
|
|
19
|
+
expect(isValidIP('10.42.0.0/8')).toBe(false);
|
|
20
|
+
expect(isValidIP('300.42.0.0')).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('fx: isValidMac', () => {
|
|
25
|
+
it('should be valid', () => {
|
|
26
|
+
expect(isValidMac('00-08-20-83-53-D1')).toBe(true);
|
|
27
|
+
expect(isValidMac('00-08-20-83-53-d1')).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
it('should be invalid', () => {
|
|
30
|
+
expect(isValidMac('invalid')).toBe(false);
|
|
31
|
+
expect(isValidMac('00-08-20-83-53')).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
package/utils/validators/cidr.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
const validCIDRregex = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\/(3[0-2]|2[0-9]|1[0-9]|[0-9])$/;
|
|
2
|
+
const validIPRegex = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
|
2
3
|
|
|
3
4
|
export function isValidCIDR(cidr) {
|
|
4
5
|
return !!cidr.match(validCIDRregex);
|
|
5
6
|
}
|
|
6
7
|
|
|
8
|
+
export function isValidIP(ip) {
|
|
9
|
+
return !!ip.match(validIPRegex);
|
|
10
|
+
}
|
|
11
|
+
|
|
7
12
|
export function isValidMac(value) {
|
|
8
13
|
return /^[A-Fa-f0-9]{2}(-[A-Fa-f0-9]{2}){5}$|^[A-Fa-f0-9]{2}(:[A-Fa-f0-9]{2}){5}$/.test(value);
|
|
9
14
|
}
|