@rancher/shell 3.0.2-rc.4 → 3.0.2-rc.6
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/images/providers/nutanix.svg +12 -1
- package/assets/styles/base/_basic.scss +2 -1
- package/assets/styles/base/_helpers.scss +4 -0
- package/assets/styles/base/_variables.scss +2 -0
- package/assets/styles/global/_labeled-input.scss +5 -13
- package/assets/styles/global/_layout.scss +1 -0
- package/assets/styles/global/_select.scss +5 -0
- package/assets/styles/themes/_dark.scss +1 -3
- package/assets/styles/themes/_light.scss +5 -1
- package/assets/translations/en-us.yaml +142 -22
- package/assets/translations/zh-hans.yaml +0 -3
- package/cloud-credential/azure.vue +1 -1
- package/components/ActionMenuShell.vue +105 -0
- package/components/AppModal.vue +2 -2
- package/components/AsyncButton.vue +2 -0
- package/components/ButtonGroup.vue +15 -1
- package/components/ButtonMultiAction.vue +5 -1
- package/components/ClusterBadge.vue +1 -0
- package/components/ClusterIconMenu.vue +3 -0
- package/components/ClusterProviderIcon.vue +14 -1
- package/components/CodeMirror.vue +96 -5
- package/components/Collapse.vue +16 -3
- package/components/CopyToClipboardText.vue +3 -1
- package/components/CruResource.vue +9 -0
- package/components/CruResourceFooter.vue +1 -1
- package/components/ExplorerMembers.vue +2 -1
- package/components/ExplorerProjectsNamespaces.vue +7 -0
- package/components/Import.vue +14 -1
- package/components/LandingPagePreference.vue +4 -2
- package/components/PodSecurityAdmission.vue +8 -6
- package/components/PromptChangePassword.vue +1 -0
- package/components/PromptRemove.vue +23 -21
- package/components/ResourceDetail/Masthead.vue +30 -11
- package/components/ResourceDetail/__tests__/Masthead.test.ts +61 -0
- package/components/ResourceDetail/index.vue +6 -0
- package/components/ResourceTable.vue +6 -14
- package/components/ResourceYaml.vue +1 -0
- package/components/SelectIconGrid.vue +2 -0
- package/components/Setting.vue +115 -0
- package/components/SortableTable/THead.vue +2 -0
- package/components/SortableTable/index.vue +38 -14
- package/components/Tabbed/index.vue +16 -15
- package/components/Wizard.vue +108 -104
- package/components/YamlEditor.vue +12 -2
- package/components/__tests__/Collapse.test.ts +2 -2
- package/components/auth/Principal.vue +29 -17
- package/components/auth/__tests__/Principal.test.ts +40 -0
- package/components/auth/login/ldap.vue +7 -0
- package/components/fleet/FleetBundles.vue +1 -1
- package/components/fleet/FleetRepos.vue +1 -1
- package/components/fleet/FleetResources.vue +0 -2
- package/components/fleet/FleetSummary.vue +60 -65
- package/components/fleet/ForceDirectedTreeChart/index.vue +5 -1
- package/components/fleet/__tests__/FleetSummary.test.ts +49 -9
- package/components/form/ArrayList.vue +6 -2
- package/components/form/ColorInput.vue +1 -0
- package/components/form/KeyValue.vue +11 -12
- package/components/form/LabeledSelect.vue +16 -3
- package/components/form/Labels.vue +8 -1
- package/components/form/Members/MembershipEditor.vue +230 -222
- package/components/form/Members/__tests__/MembershipEditor.test.ts +62 -0
- package/components/form/Password.vue +3 -0
- package/components/form/ProjectMemberEditor.vue +6 -3
- package/components/form/ResourceTabs/index.vue +15 -13
- package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +5 -4
- package/components/form/SchedulingCustomization.vue +85 -0
- package/components/form/Select.vue +4 -2
- package/components/form/SelectOrCreateAuthSecret.vue +2 -1
- package/components/form/UnitInput.vue +1 -2
- package/components/form/__tests__/ArrayList.test.ts +9 -6
- package/components/form/__tests__/LabeledSelect.test.ts +37 -0
- package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +34 -0
- package/components/formatter/LiveDate.vue +3 -1
- package/components/formatter/ServiceType.vue +12 -4
- package/components/formatter/WorkloadHealthScale.vue +2 -1
- package/components/nav/Header.vue +35 -2
- package/components/nav/HeaderPageActionMenu.vue +11 -40
- package/components/nav/Jump.vue +8 -2
- package/components/nav/NamespaceFilter.vue +5 -4
- package/components/nav/Pinned.vue +1 -1
- package/components/nav/TopLevelMenu.helper.ts +5 -5
- package/components/nav/WindowManager/ContainerLogs.vue +97 -49
- package/components/nav/WindowManager/ContainerShell.vue +99 -18
- package/components/nav/WindowManager/index.vue +85 -6
- package/components/templates/default.vue +2 -47
- package/config/features.js +1 -0
- package/config/home-links.js +1 -1
- package/config/labels-annotations.js +11 -1
- package/config/router/navigation-guards/index.js +2 -1
- package/config/router/navigation-guards/record-last-route.js +24 -0
- package/config/settings.ts +66 -98
- package/config/version.js +1 -1
- package/core/types-provisioning.ts +7 -0
- package/detail/fleet.cattle.io.bundle.vue +7 -0
- package/detail/fleet.cattle.io.cluster.vue +0 -3
- package/detail/fleet.cattle.io.gitrepo.vue +8 -15
- package/detail/provisioning.cattle.io.cluster.vue +8 -2
- package/dialog/DeactivateDriverDialog.vue +5 -5
- package/dialog/GitRepoForceUpdateDialog.vue +132 -0
- package/directives/strip-html-aria-label.js +19 -0
- package/edit/__tests__/cis.cattle.io.clusterscan.test.ts +87 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +217 -37
- package/edit/auth/__tests__/oidc.test.ts +26 -9
- package/edit/auth/ldap/__tests__/config.test.ts +40 -0
- package/edit/auth/ldap/config.vue +67 -89
- package/edit/auth/oidc.vue +15 -1
- package/edit/catalog.cattle.io.clusterrepo.vue +12 -8
- package/edit/cis.cattle.io.clusterscan.vue +13 -1
- package/edit/fleet.cattle.io.gitrepo.vue +198 -72
- package/edit/logging-flow/Match.vue +0 -21
- package/edit/management.cattle.io.project.vue +1 -1
- package/edit/monitoring.coreos.com.prometheusrule/AlertingRule.vue +10 -3
- package/edit/monitoring.coreos.com.prometheusrule/RecordingRule.vue +5 -1
- package/edit/monitoring.coreos.com.prometheusrule/index.vue +5 -2
- package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +8 -1
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +2 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/CustomCommand.test.ts +55 -15
- package/edit/provisioning.cattle.io.cluster/index.vue +39 -39
- package/edit/provisioning.cattle.io.cluster/rke2.vue +63 -12
- package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +37 -2
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +3 -2
- package/edit/resources.cattle.io.backup.vue +150 -15
- package/edit/secret/__tests__/ssh.test.ts +79 -0
- package/edit/secret/ssh.vue +7 -1
- package/edit/workload/Job.vue +2 -2
- package/edit/workload/index.vue +3 -1
- package/initialize/install-directives.js +2 -0
- package/initialize/install-plugins.js +6 -1
- package/list/catalog.cattle.io.app.vue +21 -4
- package/list/fleet.cattle.io.bundle.vue +1 -1
- package/list/management.cattle.io.setting.vue +34 -129
- package/list/provisioning.cattle.io.cluster.vue +11 -3
- package/machine-config/vmwarevsphere.vue +15 -8
- package/mixins/__tests__/auth-config.test.ts +74 -0
- package/mixins/__tests__/chart.test.ts +5 -4
- package/mixins/__tests__/create-edit-view.test.ts +38 -0
- package/mixins/auth-config.js +9 -1
- package/mixins/chart.js +2 -2
- package/mixins/create-edit-view/impl.js +4 -1
- package/mixins/vue-select-overrides.js +10 -0
- package/models/__tests__/catalog.cattle.io.app.test.ts +148 -0
- package/models/__tests__/fleet.cattle.io.gitrepo.test.ts +157 -0
- package/models/__tests__/secret.test.ts +56 -13
- package/models/catalog.cattle.io.app.js +112 -37
- package/models/cluster.js +11 -0
- package/models/fleet.cattle.io.bundle.js +40 -2
- package/models/fleet.cattle.io.gitrepo.js +169 -109
- package/models/management.cattle.io.fleetworkspace.js +4 -0
- package/models/management.cattle.io.kontainerdriver.js +7 -0
- package/models/nodedriver.js +4 -1
- package/models/provisioning.cattle.io.cluster.js +24 -0
- package/models/secret.js +1 -1
- package/package.json +4 -4
- package/pages/auth/login.vue +4 -2
- package/pages/auth/verify.vue +11 -1
- package/pages/c/_cluster/apps/charts/chart.vue +1 -0
- package/pages/c/_cluster/apps/charts/index.vue +6 -4
- package/pages/c/_cluster/apps/charts/install.vue +1 -1
- package/pages/c/_cluster/explorer/ConfigBadge.vue +3 -5
- package/pages/c/_cluster/explorer/EventsTable.vue +3 -2
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +9 -9
- package/pages/c/_cluster/explorer/index.vue +33 -35
- package/pages/c/_cluster/explorer/tools/index.vue +17 -4
- package/pages/c/_cluster/fleet/index.vue +0 -5
- package/pages/c/_cluster/legacy/project/index.vue +1 -1
- package/pages/c/_cluster/settings/performance.vue +52 -53
- package/pages/c/_cluster/uiplugins/index.vue +21 -22
- package/pages/home.vue +17 -12
- package/pages/prefs.vue +5 -1
- package/plugins/shortkey.js +10 -1
- package/plugins/steve/steve-pagination-utils.ts +58 -8
- package/promptRemove/management.cattle.io.fleetworkspace.vue +98 -0
- package/promptRemove/management.cattle.io.globalrole.vue +1 -1
- package/promptRemove/management.cattle.io.project.vue +2 -8
- package/promptRemove/management.cattle.io.roletemplate.vue +1 -1
- package/promptRemove/mixin/roleDeletionCheck.js +1 -7
- package/promptRemove/pod.vue +7 -28
- package/rancher-components/Card/Card.vue +9 -1
- package/rancher-components/Form/Checkbox/Checkbox.vue +42 -6
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +30 -3
- package/rancher-components/Form/Radio/RadioButton.vue +18 -3
- package/rancher-components/Form/Radio/RadioGroup.vue +39 -5
- package/rancher-components/LabeledTooltip/LabeledTooltip.vue +13 -1
- package/rancher-components/RcButton/RcButton.test.ts +97 -0
- package/rancher-components/RcButton/RcButton.vue +14 -9
- package/rancher-components/RcDropdown/RcDropdown.vue +3 -1
- package/rancher-components/RcDropdown/RcDropdownItem.vue +8 -14
- package/rancher-components/RcDropdown/RcDropdownMenu.vue +66 -0
- package/rancher-components/RcDropdown/index.ts +1 -0
- package/rancher-components/RcDropdown/types.ts +27 -0
- package/rancher-components/RcDropdown/useDropdownContext.ts +5 -2
- package/scripts/typegen.sh +1 -0
- package/store/__tests__/auth.test.ts +120 -0
- package/store/action-menu.js +13 -3
- package/store/auth.js +14 -9
- package/store/catalog.js +14 -7
- package/store/features.js +1 -0
- package/store/prefs.js +9 -28
- package/store/type-map.utils.ts +4 -0
- package/types/resources/settings.d.ts +27 -20
- package/types/shell/index.d.ts +18 -2
- package/utils/__tests__/array.test.ts +13 -1
- package/utils/__tests__/string.test.ts +80 -1
- package/utils/array.ts +13 -0
- package/utils/auth.js +4 -0
- package/utils/cluster.js +1 -1
- package/{edit/monitoring.coreos.com.prometheusrule → utils}/duration.js +5 -3
- package/utils/pagination-utils.ts +15 -2
- package/utils/string.js +31 -7
- package/utils/validators/formRules/__tests__/index.test.ts +27 -0
- package/utils/validators/formRules/index.ts +16 -0
- package/edit/provisioning.cattle.io.cluster/import.vue +0 -198
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { mount, type VueWrapper } from '@vue/test-utils';
|
|
2
|
+
import cisEditor from '@shell/edit/cis.cattle.io.clusterscan.vue';
|
|
3
|
+
|
|
4
|
+
describe('view: cisEditor', () => {
|
|
5
|
+
let wrapper: VueWrapper<any, any>;
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
wrapper = mount(cisEditor, {
|
|
9
|
+
props: {
|
|
10
|
+
value: {
|
|
11
|
+
spec: { scanProfileName: null, canBeScheduled: () => true },
|
|
12
|
+
canBeScheduled: () => true,
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
global: {
|
|
16
|
+
mocks: {
|
|
17
|
+
$fetchState: { pending: false },
|
|
18
|
+
$route: {
|
|
19
|
+
name: 'whatever',
|
|
20
|
+
query: { AS: 'whatever' },
|
|
21
|
+
},
|
|
22
|
+
$store: {
|
|
23
|
+
getters: {
|
|
24
|
+
'i18n/t': (text: string) => text,
|
|
25
|
+
currentStore: () => 'whatever',
|
|
26
|
+
'whatever/schemaFor': jest.fn(),
|
|
27
|
+
},
|
|
28
|
+
dispatch: jest.fn(),
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
stubs: { AsyncButton: true }
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('renders the component', () => {
|
|
37
|
+
expect(wrapper.exists()).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe('should prevent to save', () => {
|
|
41
|
+
it('given no Profile name', () => {
|
|
42
|
+
const saveButton = wrapper.find('[data-testid="form-save"]');
|
|
43
|
+
|
|
44
|
+
expect(saveButton.attributes().disabled).toStrictEqual('true');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('given a wrong schedule format', async() => {
|
|
48
|
+
wrapper.vm.value.spec.scanProfileName = 'this is valid';
|
|
49
|
+
wrapper.vm.value.spec.scheduledScanConfig = { cronSchedule: 'this is not', scanAlertRule: { } };
|
|
50
|
+
wrapper.vm.isScheduled = true; // Not assigned by fetch()
|
|
51
|
+
wrapper.vm.scheduledScanConfig = { cronSchedule: 'this is not', scanAlertRule: { } }; // Not assigned by fetch()
|
|
52
|
+
wrapper.vm.scanAlertRule = {}; // Not assigned by fetch()
|
|
53
|
+
await wrapper.vm.$nextTick();
|
|
54
|
+
|
|
55
|
+
const saveButton = wrapper.find('[data-testid="form-save"]');
|
|
56
|
+
|
|
57
|
+
expect(saveButton.attributes().disabled).toStrictEqual('true');
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('should allow to save', () => {
|
|
62
|
+
it('given a scanProfileName', async() => {
|
|
63
|
+
wrapper.vm.value.spec.scanProfileName = 'this is valid';
|
|
64
|
+
await wrapper.vm.$nextTick();
|
|
65
|
+
|
|
66
|
+
const saveButton = wrapper.find('[data-testid="form-save"]');
|
|
67
|
+
|
|
68
|
+
expect(saveButton.attributes().disabled).toStrictEqual('false');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it.each([
|
|
72
|
+
'0 * * * *',
|
|
73
|
+
'@daily'
|
|
74
|
+
])('given a scanProfileName and a schedule %p', async(cronSchedule) => {
|
|
75
|
+
wrapper.vm.value.spec.scanProfileName = 'this is valid';
|
|
76
|
+
wrapper.vm.value.spec.scheduledScanConfig = { cronSchedule, scanAlertRule: { } };
|
|
77
|
+
wrapper.vm.scheduledScanConfig = { cronSchedule, scanAlertRule: {} }; // Not assigned by fetch()
|
|
78
|
+
wrapper.vm.scanAlertRule = {}; // Not assigned by fetch()
|
|
79
|
+
wrapper.vm.isScheduled = true; // Not assigned by fetch()
|
|
80
|
+
await wrapper.vm.$nextTick();
|
|
81
|
+
|
|
82
|
+
const saveButton = wrapper.find('[data-testid="form-save"]');
|
|
83
|
+
|
|
84
|
+
expect(saveButton.attributes().disabled).toStrictEqual('false');
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -1,59 +1,104 @@
|
|
|
1
1
|
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { _CREATE, _EDIT, _VIEW } from '@shell/config/query-params';
|
|
2
3
|
import GitRepo from '@shell/edit/fleet.cattle.io.gitrepo.vue';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
5
|
+
const mockStore = {
|
|
6
|
+
dispatch: jest.fn(),
|
|
7
|
+
getters: {
|
|
8
|
+
'i18n/t': (text: string) => text,
|
|
9
|
+
'i18n/exists': jest.fn(),
|
|
10
|
+
t: (text: string) => text,
|
|
11
|
+
currentStore: () => 'current_store',
|
|
12
|
+
'current_store/schemaFor': jest.fn(),
|
|
13
|
+
'current_store/all': jest.fn(),
|
|
14
|
+
workspace: jest.fn(),
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const mocks = {
|
|
18
|
+
$store: mockStore,
|
|
19
|
+
$fetchState: { pending: false },
|
|
20
|
+
$route: {
|
|
21
|
+
query: { AS: '' },
|
|
22
|
+
name: {
|
|
23
|
+
endsWith: () => {
|
|
24
|
+
return false;
|
|
25
25
|
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
const mockComputed = {
|
|
30
|
+
...GitRepo.computed,
|
|
31
|
+
steps: () => [{
|
|
32
|
+
name: 'stepAdvanced',
|
|
33
|
+
title: 'title',
|
|
34
|
+
label: 'label',
|
|
35
|
+
subtext: 'subtext',
|
|
36
|
+
descriptionKey: 'description',
|
|
37
|
+
ready: true,
|
|
38
|
+
weight: 1,
|
|
39
|
+
}],
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const values = {
|
|
43
|
+
metadata: { namespace: 'test' },
|
|
44
|
+
spec: {
|
|
45
|
+
template: {},
|
|
46
|
+
correctDrift: { enabled: false },
|
|
47
|
+
},
|
|
48
|
+
targetInfo: { mode: 'all' },
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
describe('view: fleet.cattle.io.gitrepo, mode: view - should', () => {
|
|
52
|
+
it('hide advanced options banner', () => {
|
|
53
|
+
const wrapper = mount(GitRepo, {
|
|
54
|
+
props: { value: values, mode: _VIEW },
|
|
55
|
+
computed: mockComputed,
|
|
56
|
+
global: { mocks }
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const advancedInfoBanner = wrapper.find('[data-testid="gitrepo-advanced-info"]');
|
|
60
|
+
|
|
61
|
+
expect(advancedInfoBanner.exists()).toBeFalsy();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe.each([
|
|
66
|
+
_CREATE,
|
|
67
|
+
_EDIT,
|
|
68
|
+
])('view: fleet.cattle.io.gitrepo, mode: %p - should', (mode) => {
|
|
31
69
|
const wrapper = mount(GitRepo, {
|
|
32
|
-
props:
|
|
33
|
-
|
|
70
|
+
props: { value: values, mode },
|
|
71
|
+
computed: mockComputed,
|
|
72
|
+
global: { mocks }
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('show advanced options banner', () => {
|
|
76
|
+
const advancedInfoBanner = wrapper.find('[data-testid="gitrepo-advanced-info"]');
|
|
77
|
+
|
|
78
|
+
expect(advancedInfoBanner.exists()).toBeTruthy();
|
|
34
79
|
});
|
|
35
80
|
|
|
36
|
-
it('
|
|
37
|
-
const correctDriftCheckbox = wrapper.find('[data-testid="
|
|
38
|
-
const tooltip = wrapper.find('[data-testid="
|
|
81
|
+
it('have self-healing checkbox and tooltip', () => {
|
|
82
|
+
const correctDriftCheckbox = wrapper.find('[data-testid="gitRepo-correctDrift-checkbox"]');
|
|
83
|
+
const tooltip = wrapper.find('[data-testid="gitRepo-correctDrift-checkbox"]');
|
|
39
84
|
|
|
40
85
|
expect(tooltip.element.classList).toContain('v-popper--has-tooltip');
|
|
41
86
|
expect(correctDriftCheckbox.exists()).toBeTruthy();
|
|
42
87
|
expect(correctDriftCheckbox.attributes().value).toBeFalsy();
|
|
43
88
|
});
|
|
44
89
|
|
|
45
|
-
it('
|
|
46
|
-
const correctDriftCheckbox = wrapper.find('[data-testid="
|
|
47
|
-
const tooltip = wrapper.find('[data-testid="
|
|
90
|
+
it('have keep-resources checkbox and tooltip', () => {
|
|
91
|
+
const correctDriftCheckbox = wrapper.find('[data-testid="gitRepo-keepResources-checkbox"]');
|
|
92
|
+
const tooltip = wrapper.find('[data-testid="gitRepo-keepResources-checkbox"]');
|
|
48
93
|
|
|
49
94
|
expect(tooltip.element.classList).toContain('v-popper--has-tooltip');
|
|
50
95
|
expect(correctDriftCheckbox.exists()).toBeTruthy();
|
|
51
96
|
expect(correctDriftCheckbox.attributes().value).toBeFalsy();
|
|
52
97
|
});
|
|
53
98
|
|
|
54
|
-
it('
|
|
55
|
-
const correctDriftCheckbox = wrapper.findComponent('[data-testid="
|
|
56
|
-
const correctDriftContainer = wrapper.find('[data-testid="
|
|
99
|
+
it('enable drift if self-healing is checked', async() => {
|
|
100
|
+
const correctDriftCheckbox = wrapper.findComponent('[data-testid="gitRepo-correctDrift-checkbox"]') as any;
|
|
101
|
+
const correctDriftContainer = wrapper.find('[data-testid="gitRepo-correctDrift-checkbox"] .checkbox-container');
|
|
57
102
|
|
|
58
103
|
expect(correctDriftContainer.exists()).toBeTruthy();
|
|
59
104
|
|
|
@@ -63,4 +108,139 @@ describe('view: fleet.cattle.io.gitrepo should', () => {
|
|
|
63
108
|
expect(correctDriftCheckbox.emitted('update:value')![0][0]).toBe(true);
|
|
64
109
|
expect(correctDriftCheckbox.props().value).toBeTruthy();
|
|
65
110
|
});
|
|
111
|
+
|
|
112
|
+
it.each([
|
|
113
|
+
['show Polling Interval and warnings', 'enabled', undefined, true],
|
|
114
|
+
['show Polling Interval and warnings', 'enabled', false, true],
|
|
115
|
+
['hide Polling Interval and warnings', 'disabled', true, false],
|
|
116
|
+
])('show Enable Polling checkbox and %p if %p, with spec.disablePolling: %p', (
|
|
117
|
+
descr1,
|
|
118
|
+
descr2,
|
|
119
|
+
disablePolling,
|
|
120
|
+
enabled
|
|
121
|
+
) => {
|
|
122
|
+
const wrapper = mount(GitRepo, {
|
|
123
|
+
props: {
|
|
124
|
+
value: {
|
|
125
|
+
...values,
|
|
126
|
+
spec: {
|
|
127
|
+
disablePolling,
|
|
128
|
+
pollingInterval: 10
|
|
129
|
+
},
|
|
130
|
+
status: { webhookCommit: 'sha' },
|
|
131
|
+
},
|
|
132
|
+
realMode: mode
|
|
133
|
+
},
|
|
134
|
+
computed: mockComputed,
|
|
135
|
+
global: { mocks },
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const pollingCheckbox = wrapper.findComponent('[data-testid="gitRepo-enablePolling-checkbox"]') as any;
|
|
139
|
+
const pollingIntervalInput = wrapper.find('[data-testid="gitRepo-pollingInterval-input"]');
|
|
140
|
+
const pollingIntervalMinimumValueWarning = wrapper.find('[data-testid="gitRepo-pollingInterval-minimumValueWarning"]');
|
|
141
|
+
const pollingIntervalWebhookWarning = wrapper.find('[data-testid="gitRepo-pollingInterval-webhookWarning"]');
|
|
142
|
+
|
|
143
|
+
expect(pollingIntervalMinimumValueWarning.exists()).toBe(enabled);
|
|
144
|
+
expect(pollingIntervalWebhookWarning.exists()).toBe(enabled);
|
|
145
|
+
expect(pollingCheckbox.exists()).toBeTruthy();
|
|
146
|
+
expect(pollingCheckbox.vm.value).toBe(enabled);
|
|
147
|
+
expect(pollingIntervalInput.exists()).toBe(enabled);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const defaultPollingInterval = mode === _CREATE ? '60' : '15';
|
|
151
|
+
|
|
152
|
+
it.each([
|
|
153
|
+
['null', `default ${ defaultPollingInterval } seconds`, null, defaultPollingInterval],
|
|
154
|
+
['0', `default ${ defaultPollingInterval } seconds`, 0, defaultPollingInterval],
|
|
155
|
+
['1', 'custom 1 second', 1, '1'],
|
|
156
|
+
['60', 'custom 60 seconds', 60, '60'],
|
|
157
|
+
['15', 'custom 15 seconds', 15, '15'],
|
|
158
|
+
['0s', `default ${ defaultPollingInterval } seconds`, 0, defaultPollingInterval],
|
|
159
|
+
['1s', 'custom 1 second', '1s', '1'],
|
|
160
|
+
['60s', 'custom 60 seconds', '1m', '60'],
|
|
161
|
+
['1m3s', 'custom 63 seconds', '1m3s', '63'],
|
|
162
|
+
['1h2m3s', 'custom 3723 seconds', '1h2m3s', '3723'],
|
|
163
|
+
['15', 'custom 15 seconds', '15s', '15'],
|
|
164
|
+
])('show Polling Interval input with source: %p, value: %p', async(
|
|
165
|
+
descr1,
|
|
166
|
+
descr2,
|
|
167
|
+
pollingInterval,
|
|
168
|
+
unitValue,
|
|
169
|
+
) => {
|
|
170
|
+
const wrapper = mount(GitRepo, {
|
|
171
|
+
props: {
|
|
172
|
+
value: {
|
|
173
|
+
...values,
|
|
174
|
+
spec: { pollingInterval }
|
|
175
|
+
},
|
|
176
|
+
realMode: mode
|
|
177
|
+
},
|
|
178
|
+
computed: mockComputed,
|
|
179
|
+
global: { mocks },
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
const pollingIntervalInput = wrapper.find('[data-testid="gitRepo-pollingInterval-input"]').element as any;
|
|
183
|
+
|
|
184
|
+
expect(pollingIntervalInput).toBeDefined();
|
|
185
|
+
expect(pollingIntervalInput.value).toBe(unitValue);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it.each([
|
|
189
|
+
['hide', 'source: null, value: equal to 60', null, false],
|
|
190
|
+
['hide', 'source: 0, value: equal to 60', 0, false],
|
|
191
|
+
['hide', 'source: 15, value: equal to 15', 15, false],
|
|
192
|
+
['hide', 'source: 60, value: equal to 60', 60, false],
|
|
193
|
+
['hide', 'source: 16, value: higher than 15', 16, false],
|
|
194
|
+
['show', 'source: 1, value: lower than 15', 1, true],
|
|
195
|
+
])('%p Polling Interval warning if %p', async(
|
|
196
|
+
descr1,
|
|
197
|
+
descr2,
|
|
198
|
+
pollingInterval,
|
|
199
|
+
visible,
|
|
200
|
+
) => {
|
|
201
|
+
const wrapper = mount(GitRepo, {
|
|
202
|
+
props: {
|
|
203
|
+
value: {
|
|
204
|
+
...values,
|
|
205
|
+
spec: { pollingInterval }
|
|
206
|
+
},
|
|
207
|
+
realMode: mode
|
|
208
|
+
},
|
|
209
|
+
computed: mockComputed,
|
|
210
|
+
global: { mocks },
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
const pollingIntervalMinimumValueWarning = wrapper.find('[data-testid="gitRepo-pollingInterval-minimumValueWarning"]');
|
|
214
|
+
|
|
215
|
+
expect(pollingIntervalMinimumValueWarning.exists()).toBe(visible);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it.each([
|
|
219
|
+
['hide', 'disabled', null, false],
|
|
220
|
+
['hide', 'disabled', false, false],
|
|
221
|
+
['hide', 'disabled', '', false],
|
|
222
|
+
['show', 'enabled', 'sha', true],
|
|
223
|
+
])('%p Webhook configured warning if webhook is %p', (
|
|
224
|
+
descr1,
|
|
225
|
+
descr2,
|
|
226
|
+
webhookCommit,
|
|
227
|
+
visible
|
|
228
|
+
) => {
|
|
229
|
+
const wrapper = mount(GitRepo, {
|
|
230
|
+
props: {
|
|
231
|
+
value: {
|
|
232
|
+
...values,
|
|
233
|
+
spec: { pollingInterval: 60 },
|
|
234
|
+
status: { webhookCommit },
|
|
235
|
+
},
|
|
236
|
+
realMode: mode
|
|
237
|
+
},
|
|
238
|
+
computed: mockComputed,
|
|
239
|
+
global: { mocks },
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const pollingIntervalWebhookWarning = wrapper.find('[data-testid="gitRepo-pollingInterval-webhookWarning"]');
|
|
243
|
+
|
|
244
|
+
expect(pollingIntervalWebhookWarning.exists()).toBe(visible);
|
|
245
|
+
});
|
|
66
246
|
});
|
|
@@ -19,15 +19,16 @@ const validAuthEndpoint = 'http://localhost:8080/realms/rancherrealm/protocol/op
|
|
|
19
19
|
const validScope = 'openid profile email';
|
|
20
20
|
|
|
21
21
|
const mockModel = {
|
|
22
|
-
enabled:
|
|
23
|
-
id:
|
|
24
|
-
rancherUrl:
|
|
25
|
-
issuer:
|
|
26
|
-
authEndpoint:
|
|
27
|
-
scope:
|
|
28
|
-
clientId:
|
|
29
|
-
clientSecret:
|
|
30
|
-
type:
|
|
22
|
+
enabled: false,
|
|
23
|
+
id: 'genericoidc',
|
|
24
|
+
rancherUrl: validRancherUrl,
|
|
25
|
+
issuer: validIssuer,
|
|
26
|
+
authEndpoint: validAuthEndpoint,
|
|
27
|
+
scope: validScope,
|
|
28
|
+
clientId: validClientId,
|
|
29
|
+
clientSecret: validClientSecret,
|
|
30
|
+
type: 'genericOIDCConfig',
|
|
31
|
+
groupSearchEnabled: false,
|
|
31
32
|
};
|
|
32
33
|
|
|
33
34
|
describe('oidc.vue', () => {
|
|
@@ -131,4 +132,20 @@ describe('oidc.vue', () => {
|
|
|
131
132
|
|
|
132
133
|
expect(wrapper.vm.model.issuer).toBe(`${ validUrl }/realms/${ validRealm }`);
|
|
133
134
|
});
|
|
135
|
+
|
|
136
|
+
it('`groupSearchEnabled` defaults to false', async() => {
|
|
137
|
+
const groupSearchCheckbox = wrapper.getComponent('[data-testid="input-group-search"]');
|
|
138
|
+
|
|
139
|
+
expect(groupSearchCheckbox.isVisible()).toBe(true);
|
|
140
|
+
expect(wrapper.vm.model.groupSearchEnabled).toBe(false);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('`groupSearchEnabled` updates when checkbox is clicked', async() => {
|
|
144
|
+
const groupSearchCheckbox = wrapper.getComponent('[data-testid="input-group-search"]');
|
|
145
|
+
|
|
146
|
+
await groupSearchCheckbox.find('[role="checkbox"]').trigger('click');
|
|
147
|
+
|
|
148
|
+
expect(groupSearchCheckbox.isVisible()).toBe(true);
|
|
149
|
+
expect(wrapper.vm.model.groupSearchEnabled).toBe(true);
|
|
150
|
+
});
|
|
134
151
|
});
|
|
@@ -15,4 +15,44 @@ describe('lDAP config', () => {
|
|
|
15
15
|
|
|
16
16
|
expect(checkbox).toBeDefined();
|
|
17
17
|
});
|
|
18
|
+
|
|
19
|
+
it('updates user login filter when value is entered', async() => {
|
|
20
|
+
const wrapper = mount(
|
|
21
|
+
LDAPConfig,
|
|
22
|
+
{
|
|
23
|
+
props: {
|
|
24
|
+
value: {},
|
|
25
|
+
type: 'openldap',
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const userLoginFilter = wrapper.find('[data-testid="user-login-filter"]');
|
|
30
|
+
|
|
31
|
+
await userLoginFilter.setValue('Test Filter');
|
|
32
|
+
|
|
33
|
+
const expectedValue = 'Test Filter';
|
|
34
|
+
|
|
35
|
+
expect(userLoginFilter.exists()).toBe(true);
|
|
36
|
+
expect(userLoginFilter.element.value).toBe(expectedValue);
|
|
37
|
+
expect(wrapper.vm.model.userLoginFilter).toBe(expectedValue);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('defaults to undefined for user login filter', () => {
|
|
41
|
+
const wrapper = mount(
|
|
42
|
+
LDAPConfig,
|
|
43
|
+
{
|
|
44
|
+
props: {
|
|
45
|
+
value: {},
|
|
46
|
+
type: 'openldap',
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const userLoginFilter = wrapper.find('[data-testid="user-login-filter"]');
|
|
51
|
+
|
|
52
|
+
const expectedValue = '';
|
|
53
|
+
|
|
54
|
+
expect(userLoginFilter.exists()).toBe(true);
|
|
55
|
+
expect(userLoginFilter.element.value).toBe(expectedValue);
|
|
56
|
+
expect(wrapper.vm.model.userLoginFilter).toBeUndefined();
|
|
57
|
+
});
|
|
18
58
|
});
|
|
@@ -279,147 +279,125 @@ export default {
|
|
|
279
279
|
color="info"
|
|
280
280
|
label-key="authConfig.ldap.oktaSchema"
|
|
281
281
|
/>
|
|
282
|
-
<div class="
|
|
283
|
-
<div class="
|
|
282
|
+
<div class="schema-container">
|
|
283
|
+
<div class="schema-column">
|
|
284
284
|
<h4>{{ t('authConfig.ldap.users') }}</h4>
|
|
285
|
-
</div>
|
|
286
|
-
<div class="col span-6">
|
|
287
|
-
<h4>{{ t('authConfig.ldap.groups') }}</h4>
|
|
288
|
-
</div>
|
|
289
|
-
</div>
|
|
290
|
-
<div class="row mb-20">
|
|
291
|
-
<div class="col span-6">
|
|
292
285
|
<LabeledInput
|
|
293
286
|
v-model:value="model.userObjectClass"
|
|
294
287
|
:mode="mode"
|
|
295
288
|
:label="t('authConfig.ldap.objectClass')"
|
|
296
289
|
/>
|
|
297
|
-
</div>
|
|
298
|
-
<div class="col span-6">
|
|
299
|
-
<LabeledInput
|
|
300
|
-
v-model:value="model.groupObjectClass"
|
|
301
|
-
:mode="mode"
|
|
302
|
-
:label="t('authConfig.ldap.objectClass')"
|
|
303
|
-
/>
|
|
304
|
-
</div>
|
|
305
|
-
</div>
|
|
306
|
-
<div class="row mb-20">
|
|
307
|
-
<div class="col span-6">
|
|
308
290
|
<LabeledInput
|
|
309
291
|
v-model:value="model.userNameAttribute"
|
|
310
292
|
:mode="mode"
|
|
311
293
|
:label="t('authConfig.ldap.usernameAttribute')"
|
|
312
294
|
/>
|
|
313
|
-
</div>
|
|
314
|
-
<div class="col span-6">
|
|
315
|
-
<LabeledInput
|
|
316
|
-
v-model:value="model.groupNameAttribute"
|
|
317
|
-
:mode="mode"
|
|
318
|
-
:label="t('authConfig.ldap.nameAttribute')"
|
|
319
|
-
/>
|
|
320
|
-
</div>
|
|
321
|
-
</div>
|
|
322
|
-
<div class="row mb-20">
|
|
323
|
-
<div class="col span-6">
|
|
324
295
|
<LabeledInput
|
|
325
296
|
v-model:value="model.userLoginAttribute"
|
|
326
297
|
:mode="mode"
|
|
327
298
|
:label="t('authConfig.ldap.loginAttribute')"
|
|
328
299
|
/>
|
|
329
|
-
</div>
|
|
330
|
-
<div class="col span-6">
|
|
331
|
-
<LabeledInput
|
|
332
|
-
v-model:value="model.groupMemberUserAttribute"
|
|
333
|
-
:mode="mode"
|
|
334
|
-
:label="t('authConfig.ldap.groupMemberUserAttribute')"
|
|
335
|
-
/>
|
|
336
|
-
</div>
|
|
337
|
-
</div>
|
|
338
|
-
<div class="row mb-20">
|
|
339
|
-
<div class="col span-6">
|
|
340
300
|
<LabeledInput
|
|
341
301
|
v-model:value="model.userMemberAttribute"
|
|
342
302
|
:mode="mode"
|
|
343
303
|
:label="t('authConfig.ldap.userMemberAttribute')"
|
|
344
304
|
/>
|
|
345
|
-
</div>
|
|
346
|
-
<div class="col span-6">
|
|
347
305
|
<LabeledInput
|
|
348
|
-
v-model:value="model.
|
|
306
|
+
v-model:value="model.userLoginFilter"
|
|
307
|
+
data-testid="user-login-filter"
|
|
349
308
|
:mode="mode"
|
|
350
|
-
:label="t('authConfig.ldap.
|
|
309
|
+
:label="t('authConfig.ldap.userLoginFilter')"
|
|
351
310
|
/>
|
|
352
|
-
</div>
|
|
353
|
-
</div>
|
|
354
|
-
<div class="row mb-20">
|
|
355
|
-
<div class="col span-6">
|
|
356
311
|
<LabeledInput
|
|
357
312
|
v-model:value="model.userSearchAttribute"
|
|
358
313
|
:mode="mode"
|
|
359
314
|
:label="t('authConfig.ldap.searchAttribute')"
|
|
360
315
|
/>
|
|
361
|
-
</div>
|
|
362
|
-
<div class="col span-6">
|
|
363
316
|
<LabeledInput
|
|
364
|
-
v-model:value="model.
|
|
317
|
+
v-model:value="model.userSearchFilter"
|
|
365
318
|
:mode="mode"
|
|
366
319
|
:label="t('authConfig.ldap.searchFilter')"
|
|
367
320
|
/>
|
|
368
|
-
</div>
|
|
369
|
-
</div>
|
|
370
|
-
<div class="row mb-20">
|
|
371
|
-
<div class="col span-6">
|
|
372
321
|
<LabeledInput
|
|
373
|
-
v-model:value="model.
|
|
322
|
+
v-model:value="model.userEnabledAttribute"
|
|
374
323
|
:mode="mode"
|
|
375
|
-
:label="t('authConfig.ldap.
|
|
324
|
+
:label="t('authConfig.ldap.userEnabledAttribute')"
|
|
376
325
|
/>
|
|
377
|
-
</div>
|
|
378
|
-
<div class="col span-6">
|
|
379
326
|
<LabeledInput
|
|
380
|
-
v-model:value="model.
|
|
327
|
+
v-model:value="model.disabledStatusBitmask"
|
|
381
328
|
:mode="mode"
|
|
382
|
-
:label="t('authConfig.ldap.
|
|
329
|
+
:label="t('authConfig.ldap.disabledStatusBitmask')"
|
|
383
330
|
/>
|
|
384
331
|
</div>
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
<div class="col span-6">
|
|
332
|
+
<div class="schema-column">
|
|
333
|
+
<h4>{{ t('authConfig.ldap.groups') }}</h4>
|
|
388
334
|
<LabeledInput
|
|
389
|
-
v-model:value="model.
|
|
335
|
+
v-model:value="model.groupObjectClass"
|
|
390
336
|
:mode="mode"
|
|
391
|
-
:label="t('authConfig.ldap.
|
|
337
|
+
:label="t('authConfig.ldap.objectClass')"
|
|
392
338
|
/>
|
|
393
|
-
</div>
|
|
394
|
-
<div class="col span-6">
|
|
395
339
|
<LabeledInput
|
|
396
|
-
v-model:value="model.
|
|
340
|
+
v-model:value="model.groupNameAttribute"
|
|
397
341
|
:mode="mode"
|
|
398
|
-
:label="t('authConfig.ldap.
|
|
342
|
+
:label="t('authConfig.ldap.nameAttribute')"
|
|
399
343
|
/>
|
|
400
|
-
</div>
|
|
401
|
-
</div>
|
|
402
|
-
<div class="row mb-20">
|
|
403
|
-
<div class="col span-6">
|
|
404
344
|
<LabeledInput
|
|
405
|
-
v-model:value="model.
|
|
345
|
+
v-model:value="model.groupMemberUserAttribute"
|
|
406
346
|
:mode="mode"
|
|
407
|
-
:label="t('authConfig.ldap.
|
|
347
|
+
:label="t('authConfig.ldap.groupMemberUserAttribute')"
|
|
408
348
|
/>
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
v-if="!isSamlProvider"
|
|
412
|
-
class=" col span-6"
|
|
413
|
-
>
|
|
414
|
-
<RadioGroup
|
|
415
|
-
v-model:value="model.nestedGroupMembershipEnabled"
|
|
349
|
+
<LabeledInput
|
|
350
|
+
v-model:value="model.groupSearchAttribute"
|
|
416
351
|
:mode="mode"
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
:
|
|
352
|
+
:label="t('authConfig.ldap.searchAttribute')"
|
|
353
|
+
/>
|
|
354
|
+
<LabeledInput
|
|
355
|
+
v-model:value="model.groupSearchFilter"
|
|
356
|
+
:mode="mode"
|
|
357
|
+
:label="t('authConfig.ldap.searchFilter')"
|
|
421
358
|
/>
|
|
359
|
+
<LabeledInput
|
|
360
|
+
v-model:value="model.groupMemberMappingAttribute"
|
|
361
|
+
:mode="mode"
|
|
362
|
+
:label="t('authConfig.ldap.groupMemberMappingAttribute')"
|
|
363
|
+
/>
|
|
364
|
+
<LabeledInput
|
|
365
|
+
v-model:value="model.groupDNAttribute"
|
|
366
|
+
:mode="mode"
|
|
367
|
+
:label="t('authConfig.ldap.groupDNAttribute')"
|
|
368
|
+
/>
|
|
369
|
+
<template
|
|
370
|
+
v-if="!isSamlProvider"
|
|
371
|
+
>
|
|
372
|
+
<RadioGroup
|
|
373
|
+
v-model:value="model.nestedGroupMembershipEnabled"
|
|
374
|
+
:mode="mode"
|
|
375
|
+
name="nested"
|
|
376
|
+
class="full-height"
|
|
377
|
+
:options="[true, false]"
|
|
378
|
+
:labels="[t('authConfig.ldap.nestedGroupMembership.options.nested'), t('authConfig.ldap.nestedGroupMembership.options.direct')]"
|
|
379
|
+
/>
|
|
380
|
+
</template>
|
|
422
381
|
</div>
|
|
423
382
|
</div>
|
|
424
383
|
</div>
|
|
425
384
|
</template>
|
|
385
|
+
|
|
386
|
+
<style lang="scss" scoped>
|
|
387
|
+
.schema-container {
|
|
388
|
+
display: flex;
|
|
389
|
+
gap: 1.75%;
|
|
390
|
+
flex-wrap: wrap;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.schema-column {
|
|
394
|
+
flex: 1;
|
|
395
|
+
display: flex;
|
|
396
|
+
flex-direction: column;
|
|
397
|
+
min-width: 16rem;
|
|
398
|
+
|
|
399
|
+
> :not(:first-child) {
|
|
400
|
+
margin-bottom: 20px;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
</style>
|