@rancher/shell 3.0.2-rc.2 → 3.0.2-rc.4
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/styles/base/_basic.scss +7 -8
- package/assets/styles/global/_button.scss +10 -0
- package/assets/styles/global/_form.scss +2 -1
- package/assets/styles/global/_tooltip.scss +2 -2
- package/assets/styles/themes/_dark.scss +15 -3
- package/assets/styles/themes/_light.scss +7 -2
- package/assets/styles/vendor/vue-select.scss +4 -0
- package/assets/translations/en-us.yaml +66 -9
- package/assets/translations/zh-hans.yaml +2 -3
- package/components/AppModal.vue +50 -0
- package/components/BannerGraphic.vue +0 -42
- package/components/ButtonMultiAction.vue +1 -1
- package/components/Carousel.vue +88 -74
- package/components/CommunityLinks.vue +6 -1
- package/components/CopyToClipboardText.vue +3 -0
- package/components/Dialog.vue +20 -1
- package/components/GrowlManager.vue +9 -2
- package/components/LocaleSelector.vue +8 -1
- package/components/PaginatedResourceTable.vue +4 -7
- package/components/ProgressBarMulti.vue +14 -0
- package/components/PromptChangePassword.vue +3 -0
- package/components/Questions/Reference.vue +57 -28
- package/components/ResourceDetail/Masthead.vue +1 -1
- package/components/SelectIconGrid.vue +12 -1
- package/components/SideNav.vue +12 -38
- package/components/SortableTable/index.vue +1 -0
- package/components/Tabbed/index.vue +9 -1
- package/components/YamlEditor.vue +1 -0
- package/components/__tests__/Carousel.test.ts +56 -27
- package/components/auth/Principal.vue +5 -3
- package/components/fleet/FleetClusters.vue +82 -1
- package/components/fleet/FleetRepos.vue +13 -30
- package/components/fleet/ForceDirectedTreeChart/index.vue +2 -2
- package/components/form/ChangePassword.vue +2 -0
- package/components/form/ColorInput.vue +24 -1
- package/components/form/FileSelector.vue +2 -0
- package/components/form/KeyValue.vue +230 -160
- package/components/form/LabeledSelect.vue +2 -2
- package/components/form/PlusMinus.vue +14 -2
- package/components/form/ResourceLabeledSelect.vue +13 -53
- package/components/form/ResourceSelector.vue +1 -0
- package/components/form/ResourceTabs/index.vue +79 -36
- package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +192 -0
- package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +104 -0
- package/components/form/SSHKnownHosts/index.vue +101 -0
- package/components/form/SecretSelector.vue +2 -2
- package/components/form/Select.vue +1 -1
- package/components/form/SelectOrCreateAuthSecret.vue +43 -11
- package/components/form/__tests__/KeyValue.test.ts +1 -1
- package/components/form/__tests__/SSHKnownHosts.test.ts +59 -0
- package/components/formatter/FleetClusterSummaryGraph.vue +2 -2
- package/components/formatter/FleetSummaryGraph.vue +6 -7
- package/components/formatter/WorkloadHealthScale.vue +7 -0
- package/components/nav/Group.vue +30 -4
- package/components/nav/Header.vue +82 -114
- package/components/nav/HeaderPageActionMenu.vue +27 -131
- package/components/nav/NamespaceFilter.vue +1 -1
- package/components/nav/Type.vue +15 -0
- package/composables/focusTrap.ts +68 -0
- package/config/home-links.js +21 -13
- package/config/labels-annotations.js +2 -0
- package/config/page-actions.js +1 -0
- package/config/pagination-table-headers.js +15 -1
- package/config/product/explorer.js +7 -17
- package/config/table-headers.js +6 -0
- package/config/version.js +5 -1
- package/core/plugin.ts +41 -1
- package/core/plugins.js +125 -72
- package/core/types-provisioning.ts +91 -2
- package/core/types.ts +55 -0
- package/detail/__tests__/autoscaling.horizontalpodautoscaler.test.ts +12 -3
- package/detail/catalog.cattle.io.app.vue +1 -1
- package/detail/fleet.cattle.io.cluster.vue +3 -3
- package/detail/namespace.vue +13 -19
- package/detail/networking.k8s.io.ingress.vue +13 -53
- package/detail/provisioning.cattle.io.cluster.vue +12 -1
- package/detail/secret.vue +25 -0
- package/detail/workload/index.vue +3 -3
- package/dialog/AddCustomBadgeDialog.vue +5 -1
- package/edit/auth/ldap/__tests__/config.test.ts +18 -0
- package/edit/auth/ldap/config.vue +24 -0
- package/edit/auth/saml.vue +8 -6
- package/edit/fleet.cattle.io.gitrepo.vue +34 -23
- package/edit/logging-flow/index.vue +4 -19
- package/edit/networking.k8s.io.ingress/index.vue +18 -65
- package/edit/networking.k8s.io.networkpolicy/index.vue +4 -5
- package/edit/provisioning.cattle.io.cluster/index.vue +27 -8
- package/edit/provisioning.cattle.io.cluster/rke2.vue +31 -115
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +2 -2
- package/edit/provisioning.cattle.io.cluster/tabs/networking/ACE.vue +14 -28
- package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +25 -12
- package/edit/secret/index.vue +1 -1
- package/edit/secret/ssh.vue +21 -3
- package/edit/service.vue +1 -2
- package/list/networking.k8s.io.ingress.vue +1 -1
- package/list/node.vue +15 -8
- package/list/persistentvolume.vue +12 -4
- package/list/provisioning.cattle.io.cluster.vue +1 -0
- package/list/service.vue +1 -1
- package/list/workload.vue +4 -0
- package/mixins/chart.js +4 -1
- package/models/catalog.cattle.io.app.js +3 -1
- package/models/catalog.cattle.io.clusterrepo.js +56 -7
- package/models/fleet.cattle.io.bundle.js +0 -11
- package/models/fleet.cattle.io.cluster.js +17 -1
- package/models/fleet.cattle.io.gitrepo.js +88 -52
- package/models/provisioning.cattle.io.cluster.js +36 -1
- package/models/secret.js +5 -0
- package/models/service.js +1 -0
- package/models/workload.js +19 -1
- package/package.json +5 -4
- package/pages/account/index.vue +4 -0
- package/pages/c/_cluster/apps/charts/index.vue +4 -0
- package/pages/c/_cluster/explorer/ConfigBadge.vue +4 -2
- package/pages/c/_cluster/explorer/index.vue +13 -6
- package/pages/c/_cluster/fleet/GitRepoGraphConfig.js +3 -3
- package/pages/c/_cluster/fleet/index.vue +75 -89
- package/pages/c/_cluster/settings/links.vue +2 -2
- package/pages/c/_cluster/uiplugins/AddExtensionRepos.vue +3 -1
- package/pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue +3 -0
- package/pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue +7 -1
- package/pages/c/_cluster/uiplugins/CatalogList/index.vue +3 -1
- package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +10 -7
- package/pages/c/_cluster/uiplugins/InstallDialog.vue +7 -0
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +181 -106
- package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +2 -0
- package/pages/c/_cluster/uiplugins/UninstallDialog.vue +9 -1
- package/pages/c/_cluster/uiplugins/index.vue +50 -12
- package/pages/diagnostic.vue +17 -15
- package/pages/home.vue +32 -6
- package/plugins/clean-html.js +50 -0
- package/plugins/dashboard-store/resource-class.js +4 -0
- package/plugins/plugin.js +54 -49
- package/plugins/steve/mutations.js +1 -1
- package/plugins/steve/steve-class.js +8 -0
- package/plugins/steve/steve-pagination-utils.ts +3 -1
- package/rancher-components/Accordion/Accordion.vue +4 -4
- package/rancher-components/BadgeState/BadgeState.vue +7 -0
- package/rancher-components/Card/Card.vue +12 -0
- package/rancher-components/Form/Checkbox/Checkbox.vue +9 -2
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +18 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +19 -1
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +39 -2
- package/rancher-components/RcButton/RcButton.vue +90 -0
- package/rancher-components/RcButton/index.ts +2 -0
- package/rancher-components/RcButton/types.ts +17 -0
- package/rancher-components/RcDropdown/RcDropdown.vue +122 -0
- package/rancher-components/RcDropdown/RcDropdownItem.vue +127 -0
- package/rancher-components/RcDropdown/RcDropdownSeparator.vue +6 -0
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +42 -0
- package/rancher-components/RcDropdown/index.ts +4 -0
- package/rancher-components/RcDropdown/types.ts +22 -0
- package/rancher-components/RcDropdown/useDropdownCollection.ts +46 -0
- package/rancher-components/RcDropdown/useDropdownContext.ts +110 -0
- package/scripts/test-plugins-build.sh +2 -0
- package/scripts/typegen.sh +2 -0
- package/store/catalog.js +1 -1
- package/tsconfig.json +2 -1
- package/types/components/paginatedResourceTable.ts +25 -0
- package/types/components/resourceLabeledSelect.ts +48 -0
- package/types/resources/fleet.d.ts +17 -0
- package/types/shell/index.d.ts +61 -0
- package/utils/auth.js +5 -1
- package/utils/cluster.js +106 -0
- package/utils/fleet.ts +35 -3
- package/utils/ingress.ts +64 -0
- package/utils/uiplugins.ts +56 -44
- package/utils/validators/cron-schedule.js +7 -2
- package/utils/validators/formRules/__tests__/index.test.ts +53 -17
- package/utils/validators/formRules/index.ts +20 -5
- package/vue.config.js +1 -1
- package/components/RelatedWorkloadsTable.vue +0 -50
|
@@ -27,22 +27,6 @@ describe('formRules', () => {
|
|
|
27
27
|
expect(formRuleResult).toStrictEqual(expectedResult);
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
it('"cronSchedule" : returns undefined when valid cron string value supplied', () => {
|
|
31
|
-
const testValue = '0 * * * *';
|
|
32
|
-
const formRuleResult = formRules.cronSchedule(testValue);
|
|
33
|
-
|
|
34
|
-
expect(formRuleResult).toBeUndefined();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('"cronSchedule" : returns the correct message when invalid cron string value supplied', () => {
|
|
38
|
-
// specific logic of what constitutes a cron string is in the "cronstrue" function in an external library and not tested here
|
|
39
|
-
const testValue = '0 * * **';
|
|
40
|
-
const formRuleResult = formRules.cronSchedule(testValue);
|
|
41
|
-
const expectedResult = JSON.stringify({ message: 'validation.invalidCron' });
|
|
42
|
-
|
|
43
|
-
expect(formRuleResult).toStrictEqual(expectedResult);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
30
|
it('"https" : returns undefined when valid https url value is supplied', () => {
|
|
47
31
|
const testValue = 'https://url.com';
|
|
48
32
|
const formRuleResult = formRules.https(testValue);
|
|
@@ -103,6 +87,45 @@ describe('formRules', () => {
|
|
|
103
87
|
);
|
|
104
88
|
});
|
|
105
89
|
|
|
90
|
+
describe('gitRepository', () => {
|
|
91
|
+
const message = JSON.stringify({ message: 'validation.git.repository' });
|
|
92
|
+
const testCases = [
|
|
93
|
+
// Valid HTTP(s)
|
|
94
|
+
['https://github.com/rancher/dashboard.git', undefined],
|
|
95
|
+
['http://github.com/rancher/dashboard.git', undefined],
|
|
96
|
+
['https://github.com/rancher/dashboard', undefined],
|
|
97
|
+
['https://github.com/rancher/dashboard/', undefined],
|
|
98
|
+
|
|
99
|
+
// Valid SSH
|
|
100
|
+
['git@github.com:rancher/dashboard.git', undefined],
|
|
101
|
+
['git@github.com:rancher/dashboard', undefined],
|
|
102
|
+
['git@github.com:rancher/dashboard/', undefined],
|
|
103
|
+
|
|
104
|
+
// Not valid HTTP(s)
|
|
105
|
+
['https://github.com/rancher/ dashboard.git', message],
|
|
106
|
+
['http://github.com/rancher/ dashboard.git', message],
|
|
107
|
+
['https://github.com/rancher/dashboard ', message],
|
|
108
|
+
['foo://github.com/rancher/dashboard/', message],
|
|
109
|
+
['github.com/rancher/dashboard/', message],
|
|
110
|
+
|
|
111
|
+
// Not valid SSH
|
|
112
|
+
['git@github.com:rancher/ dashboard.git', message],
|
|
113
|
+
['git@github.com:rancher/dashboard ', message],
|
|
114
|
+
['git@github.comrancher/dashboard', message],
|
|
115
|
+
|
|
116
|
+
[undefined, undefined]
|
|
117
|
+
];
|
|
118
|
+
|
|
119
|
+
it.each(testCases)(
|
|
120
|
+
'should return undefined or correct message based on the provided Git url: %p',
|
|
121
|
+
(url, expected) => {
|
|
122
|
+
const formRuleResult = formRules.gitRepository(url);
|
|
123
|
+
|
|
124
|
+
expect(formRuleResult).toStrictEqual(expected);
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
});
|
|
128
|
+
|
|
106
129
|
describe('alphanumeric', () => {
|
|
107
130
|
const message = JSON.stringify({ message: 'validation.alphanumeric', key: 'testDisplayKey' });
|
|
108
131
|
const testCases = [
|
|
@@ -1112,6 +1135,13 @@ describe('formRules', () => {
|
|
|
1112
1135
|
expect(formRuleResult).toStrictEqual(expectedResult);
|
|
1113
1136
|
});
|
|
1114
1137
|
|
|
1138
|
+
/**
|
|
1139
|
+
* Test all factory validators
|
|
1140
|
+
* @param rule - the name of the factory validator
|
|
1141
|
+
* @param argument - the value to validate
|
|
1142
|
+
* @param correctValues - an array of values that should pass the validation
|
|
1143
|
+
* @param wrongValues - an array of values that should fail the validation
|
|
1144
|
+
*/
|
|
1115
1145
|
describe.each([
|
|
1116
1146
|
['minValue', 2, [3], [1]],
|
|
1117
1147
|
['maxValue', 256, [1], [300]],
|
|
@@ -1133,12 +1163,18 @@ describe('formRules', () => {
|
|
|
1133
1163
|
});
|
|
1134
1164
|
});
|
|
1135
1165
|
|
|
1166
|
+
/**
|
|
1167
|
+
* Test all standard validators
|
|
1168
|
+
* @param rule - the name of the standard validator
|
|
1169
|
+
* @param correctValues - an array of values that should pass the validation
|
|
1170
|
+
* @param wrongValues - an array of values that should fail the validation
|
|
1171
|
+
*/
|
|
1136
1172
|
describe.each([
|
|
1137
1173
|
['requiredInt', [2, 2.2], ['e']],
|
|
1138
1174
|
['isInteger', ['2', 2, 0], [2.2, 'e', '1.0']],
|
|
1139
1175
|
['isPositive', ['0', 1], [-1]],
|
|
1140
1176
|
['isOctal', ['0', 0, 10], ['01']],
|
|
1141
|
-
|
|
1177
|
+
['cronSchedule', ['0 * * * *', '@daily'], ['0 * * **']],
|
|
1142
1178
|
])('given validator %p', (rule, correctValues, wrongValues) => {
|
|
1143
1179
|
it.each(wrongValues as [])('should return error for value %p', (wrong) => {
|
|
1144
1180
|
const formRuleResult = (formRules as any)[rule](wrong);
|
|
@@ -4,14 +4,26 @@ import isEmpty from 'lodash/isEmpty';
|
|
|
4
4
|
import has from 'lodash/has';
|
|
5
5
|
import isUrl from 'is-url';
|
|
6
6
|
// import uniq from 'lodash/uniq';
|
|
7
|
-
import cronstrue from 'cronstrue';
|
|
8
7
|
import { Translation } from '@shell/types/t';
|
|
9
8
|
import { isHttps, isLocalhost, hasTrailingForwardSlash } from '@shell/utils/validators/setting';
|
|
9
|
+
import { cronScheduleRule } from '@shell/utils/validators/cron-schedule';
|
|
10
10
|
|
|
11
11
|
// import uniq from 'lodash/uniq';
|
|
12
|
-
export type Validator<T = undefined | string> = (val: any, arg?: any) => T;
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Fixed validation rule which require only the value to be evaluated
|
|
15
|
+
* @param value
|
|
16
|
+
* @returns { string | undefined }
|
|
17
|
+
*/
|
|
18
|
+
export type Validator<T = undefined | string> = (value: any, arg?: any) => T;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Factory function which returns a validation rule
|
|
22
|
+
* @param arg Argument used as part of the validation rule process, not necessarily as parameter of the validation rule
|
|
23
|
+
* @param value Value to be evaluated
|
|
24
|
+
* @returns { Validator }
|
|
25
|
+
*/
|
|
26
|
+
export type ValidatorFactory = (arg: any, value?: any) => Validator
|
|
15
27
|
|
|
16
28
|
type ServicePort = {
|
|
17
29
|
name?: string,
|
|
@@ -131,9 +143,9 @@ export default function(t: Translation, { key = 'Value' }: ValidationOptions): {
|
|
|
131
143
|
|
|
132
144
|
const cronSchedule: Validator = (val: string) => {
|
|
133
145
|
try {
|
|
134
|
-
|
|
146
|
+
cronScheduleRule.validation(val);
|
|
135
147
|
} catch (e) {
|
|
136
|
-
return t(
|
|
148
|
+
return t(cronScheduleRule.message);
|
|
137
149
|
}
|
|
138
150
|
};
|
|
139
151
|
|
|
@@ -145,6 +157,8 @@ export default function(t: Translation, { key = 'Value' }: ValidationOptions): {
|
|
|
145
157
|
|
|
146
158
|
const url: Validator = (val: string) => val && !isUrl(val) ? t('validation.setting.serverUrl.url') : undefined;
|
|
147
159
|
|
|
160
|
+
const gitRepository: Validator = (val: string) => val && !/^((http|git|ssh|http(s)|file|\/?)|(git@[\w\.]+))(:(\/\/)?)([\w\.@\:\/\-]+)([\d\/\w.-]+?)(.git){0,1}(\/)?$/gm.test(val) ? t('validation.git.repository') : undefined;
|
|
161
|
+
|
|
148
162
|
const alphanumeric: Validator = (val: string) => val && !/^[a-zA-Z0-9]+$/.test(val) ? t('validation.alphanumeric', { key }) : undefined;
|
|
149
163
|
|
|
150
164
|
const interval: Validator = (val: string) => !/^\d+[hms]$/.test(val) ? t('validation.monitoring.route.interval', { key }) : undefined;
|
|
@@ -474,6 +488,7 @@ export default function(t: Translation, { key = 'Value' }: ValidationOptions): {
|
|
|
474
488
|
dnsLabelRestricted,
|
|
475
489
|
externalName,
|
|
476
490
|
fileRequired,
|
|
491
|
+
gitRepository,
|
|
477
492
|
groupsAreValid,
|
|
478
493
|
hostname,
|
|
479
494
|
imageUrl,
|
package/vue.config.js
CHANGED
|
@@ -323,7 +323,7 @@ const getVirtualModules = (dir, includePkg) => {
|
|
|
323
323
|
|
|
324
324
|
// Package file must have rancher field to be a plugin
|
|
325
325
|
if (includePkg(name) && library.rancher) {
|
|
326
|
-
reqs += `$plugin.
|
|
326
|
+
reqs += `$plugin.registerBuiltinExtension('${ name }', require(\'~/pkg/${ name }\')); `;
|
|
327
327
|
}
|
|
328
328
|
});
|
|
329
329
|
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import {
|
|
3
|
-
STATE, NAME, WORKLOAD_IMAGES, WORKLOAD_ENDPOINTS, TYPE, AGE
|
|
4
|
-
} from '@shell/config/table-headers';
|
|
5
|
-
import { WORKLOAD_TYPES } from '@shell/config/types';
|
|
6
|
-
import ResourceTable from '@shell/components/ResourceTable';
|
|
7
|
-
|
|
8
|
-
export default {
|
|
9
|
-
components: { ResourceTable },
|
|
10
|
-
props: {
|
|
11
|
-
filter: {
|
|
12
|
-
type: Function,
|
|
13
|
-
required: true
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
async fetch() {
|
|
17
|
-
// Enumerating instead of using Object.values() because it looks like we don't want to include replica sets for this.
|
|
18
|
-
const types = [
|
|
19
|
-
WORKLOAD_TYPES.DEPLOYMENT,
|
|
20
|
-
WORKLOAD_TYPES.CRON_JOB,
|
|
21
|
-
WORKLOAD_TYPES.DAEMON_SET,
|
|
22
|
-
WORKLOAD_TYPES.JOB,
|
|
23
|
-
WORKLOAD_TYPES.STATEFUL_SET
|
|
24
|
-
];
|
|
25
|
-
const allWorkloadsNested = await Promise.all(types.map((type) => this.$store.dispatch('cluster/findAll', { type })));
|
|
26
|
-
const allWorkloads = allWorkloadsNested.flat();
|
|
27
|
-
|
|
28
|
-
this.relatedWorkloadRows = allWorkloads.filter(this.filter);
|
|
29
|
-
},
|
|
30
|
-
data() {
|
|
31
|
-
const relatedWorkloadHeaders = [STATE, NAME, WORKLOAD_IMAGES, WORKLOAD_ENDPOINTS, TYPE, AGE];
|
|
32
|
-
|
|
33
|
-
return {
|
|
34
|
-
relatedWorkloadRows: [],
|
|
35
|
-
relatedWorkloadHeaders,
|
|
36
|
-
schema: this.$store.getters['cluster/schemaFor'](WORKLOAD_TYPES.DEPLOYMENT)
|
|
37
|
-
};
|
|
38
|
-
},
|
|
39
|
-
};
|
|
40
|
-
</script>
|
|
41
|
-
|
|
42
|
-
<template>
|
|
43
|
-
<div>
|
|
44
|
-
<ResourceTable
|
|
45
|
-
:schema="schema"
|
|
46
|
-
:rows="relatedWorkloadRows"
|
|
47
|
-
:headers="relatedWorkloadHeaders"
|
|
48
|
-
/>
|
|
49
|
-
</div>
|
|
50
|
-
</template>
|