dashboard-shell-shell 1.0.111 → 1.0.113
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/.DS_Store +0 -0
- package/assets/icons/demo.css +539 -0
- package/assets/icons/demo_index.html +1131 -0
- package/assets/icons/iconfont.css +200 -0
- package/assets/icons/iconfont.js +1 -0
- package/assets/icons/iconfont.json +296 -0
- package/assets/icons/iconfont.ttf +0 -0
- package/assets/icons/iconfont.woff +0 -0
- package/assets/icons/iconfont.woff2 +0 -0
- package/assets/images/API.svg +3 -0
- package/assets/images/login/password.svg +20 -0
- package/assets/images/login/user.svg +6 -0
- package/assets/images/login-bg.png +0 -0
- package/assets/images/login-left.png +0 -0
- package/assets/images/login-logo.svg +19 -0
- package/assets/images/logo.png +0 -0
- package/assets/images/pl/harvester.png +0 -0
- package/assets/images/promp-yellow.svg +5 -0
- package/assets/images/user.png +0 -0
- package/assets/styles/all.scss +63 -0
- package/assets/styles/app.scss +2 -0
- package/assets/styles/base/_basic.scss +8 -2
- package/assets/styles/base/_helpers.scss +4 -0
- package/assets/styles/base/_typography.scss +2 -1
- package/assets/styles/base/_variables.scss +10 -2
- package/assets/styles/global/_button.scss +37 -25
- package/assets/styles/global/_columns.scss +3 -1
- package/assets/styles/global/_form.scss +45 -13
- package/assets/styles/global/_labeled-input.scss +50 -25
- package/assets/styles/global/_layout.scss +9 -3
- package/assets/styles/global/_select.scss +20 -13
- package/assets/styles/global/_table.scss +1 -1
- package/assets/styles/global/_tooltip.scss +47 -6
- package/assets/styles/themes/_dark.scss +1 -0
- package/assets/styles/themes/_light.scss +59 -46
- package/assets/styles/themes/_suse.scss +1 -0
- package/assets/styles/vendor/vue-select.scss +18 -7
- package/assets/translations/en-us.yaml +93 -12
- package/assets/translations/zh-hans.yaml +278 -141
- package/components/ActionDropdown.vue +1 -1
- package/components/ActionDropdownShell.vue +71 -0
- package/components/ActionMenu.vue +2 -2
- package/components/ActionMenuShell.vue +1 -0
- package/components/AppModal.vue +78 -6
- package/components/AssignTo.vue +25 -11
- package/components/AsyncButton.vue +24 -7
- package/components/BannerGraphic.vue +1 -0
- package/components/ButtonDropdown.vue +26 -4
- package/components/ButtonGroup.vue +4 -0
- package/components/ButtonMultiAction.vue +1 -0
- package/components/CommunityLinks.vue +3 -3
- package/components/ConsumptionGauge.vue +24 -5
- package/components/CopyToClipboardText.vue +2 -1
- package/components/CruResource.vue +12 -7
- package/components/CruResourceFooter.vue +2 -2
- package/components/DashboardOptions.vue +21 -15
- package/components/DetailText.vue +5 -0
- package/components/DisableAuthProviderModal.vue +1 -0
- package/components/DotState.vue +84 -0
- package/components/ExplorerMembers.vue +1 -1
- package/components/ExplorerProjectsNamespaces.vue +56 -14
- package/components/FixedBanner.vue +19 -12
- package/components/GlobalRoleBindings.vue +5 -1
- package/components/GrafanaDashboard.vue +4 -4
- package/components/GrowlManager.vue +4 -1
- package/components/HardwareResourceGauge.vue +39 -3
- package/components/InfoBox.vue +3 -3
- package/components/InputOrDisplay.vue +28 -2
- package/components/LabelValue.vue +16 -1
- package/components/LandingPagePreference.vue +5 -3
- package/components/LocaleSelector.vue +39 -93
- package/components/ModalManager.vue +55 -0
- package/components/ModalWithCard.vue +2 -0
- package/components/MoveModal.vue +1 -0
- package/components/PromptChangePassword.vue +1 -1
- package/components/PromptModal.vue +15 -2
- package/components/PromptRemove.vue +28 -8
- package/components/PromptRestore.vue +1 -0
- package/components/ResourceCancelModal.vue +1 -0
- package/components/ResourceDetail/Masthead.vue +188 -43
- package/components/ResourceDetail/__tests__/Masthead.test.ts +5 -1
- package/components/ResourceDetail/index.vue +49 -14
- package/components/ResourceList/Masthead.vue +80 -18
- package/components/ResourceTable.vue +60 -19
- package/components/SideNav.vue +32 -12
- package/components/SlideInPanelManager.vue +126 -0
- package/components/SortableTable/THead.vue +34 -5
- package/components/SortableTable/actions.js +1 -1
- package/components/SortableTable/index.vue +649 -142
- package/components/SortableTable/paging.js +36 -28
- package/components/SortableTable/selection.js +0 -11
- package/components/StatusBadge.vue +77 -0
- package/components/Tabbed/Tab.vue +3 -3
- package/components/Tabbed/index.vue +44 -26
- package/components/Wizard.vue +2 -2
- package/components/__tests__/AsyncButton.test.ts +2 -2
- package/components/__tests__/FixedBanner.test.ts +3 -3
- package/components/__tests__/ModalManager.spec.ts +176 -0
- package/components/__tests__/SlideInPanelManager.spec.ts +166 -0
- package/components/auth/Principal.vue +10 -3
- package/components/auth/__tests__/RoleDetailEdit.test.ts +3 -2
- package/components/form/ArrayList.vue +123 -85
- package/components/form/ArrayListGrouped.vue +10 -2
- package/components/form/Command.vue +6 -15
- package/components/form/EnvVars.vue +16 -8
- package/components/form/Footer.vue +8 -5
- package/components/form/HealthCheck.vue +3 -3
- package/components/form/HookOption.vue +11 -16
- package/components/form/KeyValue.vue +16 -7
- package/components/form/LabeledSelect.vue +59 -76
- package/components/form/LifecycleHooks.vue +3 -3
- package/components/form/MatchExpressions.vue +35 -12
- package/components/form/NameNsDescription.vue +147 -115
- package/components/form/Networking.vue +20 -12
- package/components/form/NodeAffinity.vue +31 -23
- package/components/form/NodeScheduling.vue +13 -3
- package/components/form/Password.vue +11 -5
- package/components/form/PodAffinity.vue +43 -44
- package/components/form/Probe.vue +68 -66
- package/components/form/ResourceQuota/Project.vue +5 -1
- package/components/form/ResourceSelector.vue +7 -9
- package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +6 -3
- package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +12 -1
- package/components/form/SSHKnownHosts/index.vue +16 -2
- package/components/form/Security.vue +54 -56
- package/components/form/Select.vue +41 -7
- package/components/form/ShellInput.vue +5 -1
- package/components/form/Tolerations.vue +5 -1
- package/components/form/UnitInput.vue +2 -2
- package/components/form/ValueFromResource.vue +134 -121
- package/components/form/WorkloadPorts.vue +18 -18
- package/components/form/__tests__/ArrayList.test.ts +5 -2
- package/components/form/__tests__/MatchExpressions.test.ts +12 -12
- package/components/form/__tests__/NameNsDescription.test.ts +115 -14
- package/components/form/__tests__/Probe.test.ts +12 -8
- package/components/form/__tests__/SSHKnownHosts.test.ts +11 -0
- package/components/form/__tests__/Select.test.ts +37 -0
- package/components/form/__tests__/UnitInput.test.ts +4 -5
- package/components/formatter/BadgeStateFormatter.vue +8 -5
- package/components/formatter/InternalExternalIP.vue +2 -0
- package/components/formatter/SecretData.vue +20 -7
- package/components/nav/Favorite.vue +5 -1
- package/components/nav/Group.vue +60 -27
- package/components/nav/Header.vue +39 -13
- package/components/nav/Jump.vue +7 -0
- package/components/nav/NamespaceFilter.vue +14 -8
- package/components/nav/Pinned.vue +1 -1
- package/components/nav/TopLevelMenu.vue +5 -17
- package/components/nav/Type.vue +32 -35
- package/components/nav/__tests__/TopLevelMenu.test.ts +0 -40
- package/components/templates/blank.vue +4 -1
- package/components/templates/default.vue +8 -0
- package/components/templates/home.vue +10 -1
- package/components/templates/plain.vue +10 -1
- package/package.json +1 -1
- package/rancher-components/Banner/Banner.vue +6 -4
- package/rancher-components/Card/Card.vue +6 -4
- package/rancher-components/Form/Checkbox/Checkbox.vue +20 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +46 -5
- package/rancher-components/Form/Radio/RadioButton.vue +32 -8
- package/rancher-components/Form/Radio/RadioGroup.vue +31 -24
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +17 -0
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +8 -3
- package/rancher-components/LabeledTooltip/LabeledTooltip.vue +15 -3
- package/rancher-components/RcButton/RcButton.vue +1 -0
- package/rancher-components/RcButton/types.ts +1 -0
- package/rancher-components/RcDropdown/RcDropdown.vue +54 -15
- package/rancher-components/RcDropdown/RcDropdownItem.vue +5 -4
- package/rancher-components/RcDropdown/RcDropdownMenu.vue +11 -7
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +12 -2
- package/rancher-components/RcDropdown/useDropdownCollection.ts +8 -0
- package/rancher-components/RcDropdown/useDropdownContext.ts +9 -3
- package/rancher-components/StringList/StringList.vue +1 -1
- package/store/type-map.js +29 -2
- package/utils/error.js +30 -8
- package/utils/errorTranslate.json +916 -0
- package/vue.config.js +1 -1
- package/components/formatter/ExtensionCache.vue +0 -74
- package/components/formatter/Port.vue +0 -24
- package/components/formatter/SecretType.vue +0 -41
|
@@ -15,7 +15,8 @@ export default {
|
|
|
15
15
|
},
|
|
16
16
|
|
|
17
17
|
indexTo() {
|
|
18
|
-
return Math.min(this.totalRows, this.indexFrom + this.perPage - 1);
|
|
18
|
+
// return Math.min(this.totalRows, this.indexFrom + this.perPage - 1);
|
|
19
|
+
return Math.min(this.totalRows, this.indexFrom + Number(this.perPage) - 1);
|
|
19
20
|
},
|
|
20
21
|
|
|
21
22
|
totalPages() {
|
|
@@ -23,17 +24,18 @@ export default {
|
|
|
23
24
|
},
|
|
24
25
|
|
|
25
26
|
showPaging() {
|
|
26
|
-
if (!this.paging) {
|
|
27
|
-
|
|
28
|
-
}
|
|
27
|
+
// if (!this.paging) {
|
|
28
|
+
// return false;
|
|
29
|
+
// }
|
|
29
30
|
|
|
30
|
-
const havePages = this.totalPages > 1;
|
|
31
|
+
// const havePages = this.totalPages > 1;
|
|
31
32
|
|
|
32
|
-
if (this.altLoading) {
|
|
33
|
-
|
|
34
|
-
}
|
|
33
|
+
// if (this.altLoading) {
|
|
34
|
+
// return havePages;
|
|
35
|
+
// }
|
|
35
36
|
|
|
36
|
-
return !this.loading && havePages;
|
|
37
|
+
// return !this.loading && havePages;
|
|
38
|
+
return !this.loading && this.paging && this.totalPages >= 1;
|
|
37
39
|
},
|
|
38
40
|
|
|
39
41
|
pagingDisplay() {
|
|
@@ -61,9 +63,9 @@ export default {
|
|
|
61
63
|
},
|
|
62
64
|
|
|
63
65
|
data() {
|
|
64
|
-
const perPage = this.getPerPage();
|
|
66
|
+
// const perPage = this.getPerPage();
|
|
65
67
|
|
|
66
|
-
return { page: 1, perPage };
|
|
68
|
+
return { page: 1, perPage:10 };
|
|
67
69
|
},
|
|
68
70
|
|
|
69
71
|
watch: {
|
|
@@ -78,31 +80,37 @@ export default {
|
|
|
78
80
|
}
|
|
79
81
|
},
|
|
80
82
|
|
|
81
|
-
page() {
|
|
82
|
-
|
|
83
|
-
},
|
|
83
|
+
// page() {
|
|
84
|
+
// this.debouncedPaginationChanged();
|
|
85
|
+
// },
|
|
84
86
|
|
|
85
|
-
perPage() {
|
|
86
|
-
|
|
87
|
-
},
|
|
87
|
+
// perPage() {
|
|
88
|
+
// this.debouncedPaginationChanged();
|
|
89
|
+
// },
|
|
88
90
|
|
|
89
91
|
},
|
|
90
92
|
|
|
91
93
|
methods: {
|
|
92
|
-
getPerPage() {
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
// getPerPage() {
|
|
95
|
+
// // perPage can not change while the list is displayed
|
|
96
|
+
// let out = this.rowsPerPage || 0;
|
|
95
97
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
// if ( out <= 0 ) {
|
|
99
|
+
// out = parseInt(this.$store.getters['prefs/get'](ROWS_PER_PAGE), 10) || 0;
|
|
100
|
+
// }
|
|
101
|
+
|
|
102
|
+
// // This should ideally never happen, but the preference value could be invalid, so return something...
|
|
103
|
+
// if ( out <= 0 ) {
|
|
104
|
+
// out = 10;
|
|
105
|
+
// }
|
|
106
|
+
|
|
107
|
+
// return out;
|
|
108
|
+
// },
|
|
99
109
|
|
|
100
|
-
// This should ideally never happen, but the preference value could be invalid, so return something...
|
|
101
|
-
if ( out <= 0 ) {
|
|
102
|
-
out = 10;
|
|
103
|
-
}
|
|
104
110
|
|
|
105
|
-
|
|
111
|
+
setgetPerPage(num) {
|
|
112
|
+
this.setPage(1);
|
|
113
|
+
this.perPage = num;
|
|
106
114
|
},
|
|
107
115
|
|
|
108
116
|
setPage(num) {
|
|
@@ -340,17 +340,6 @@ export default {
|
|
|
340
340
|
if ( !isSelected ) {
|
|
341
341
|
this.update([node], this.selectedRows.slice());
|
|
342
342
|
}
|
|
343
|
-
|
|
344
|
-
let resources = this.selectedRows;
|
|
345
|
-
|
|
346
|
-
if ( this.mangleActionResources ) {
|
|
347
|
-
resources = await this.mangleActionResources(resources);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
this.$store.commit(`action-menu/show`, {
|
|
351
|
-
resources,
|
|
352
|
-
event: e,
|
|
353
|
-
});
|
|
354
343
|
},
|
|
355
344
|
|
|
356
345
|
keySelectRow(row, more = false) {
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
|
|
3
|
+
const STATUS = {
|
|
4
|
+
success: {
|
|
5
|
+
color: 'text-success',
|
|
6
|
+
icon: 'icon-checkmark'
|
|
7
|
+
},
|
|
8
|
+
warning: {
|
|
9
|
+
color: 'text-warning',
|
|
10
|
+
icon: 'icon-warning'
|
|
11
|
+
},
|
|
12
|
+
info: {
|
|
13
|
+
color: 'text-info',
|
|
14
|
+
icon: 'icon-info'
|
|
15
|
+
},
|
|
16
|
+
error: {
|
|
17
|
+
color: 'text-error',
|
|
18
|
+
icon: 'icon-error'
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
withDefaults(
|
|
23
|
+
defineProps<{
|
|
24
|
+
status?: 'success' | 'warning' | 'info' | 'error',
|
|
25
|
+
label?: string
|
|
26
|
+
}>(),
|
|
27
|
+
{
|
|
28
|
+
status: 'success',
|
|
29
|
+
label: '',
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
</script>
|
|
34
|
+
<template>
|
|
35
|
+
<div
|
|
36
|
+
class="status-badge"
|
|
37
|
+
>
|
|
38
|
+
<i
|
|
39
|
+
class="status-badge__icon icon"
|
|
40
|
+
:class="{
|
|
41
|
+
[STATUS[status].icon]: true,
|
|
42
|
+
[STATUS[status].color]: true
|
|
43
|
+
}"
|
|
44
|
+
/>
|
|
45
|
+
<div
|
|
46
|
+
v-if="label"
|
|
47
|
+
class="status-badge__label"
|
|
48
|
+
>
|
|
49
|
+
{{ label }}
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</template>
|
|
53
|
+
|
|
54
|
+
<style lang="scss" scoped>
|
|
55
|
+
.status-badge {
|
|
56
|
+
align-items: center;
|
|
57
|
+
display: inline-flex;
|
|
58
|
+
border: 1px solid;
|
|
59
|
+
border-color: var(--border);
|
|
60
|
+
margin-top: 20px;
|
|
61
|
+
|
|
62
|
+
& + & {
|
|
63
|
+
margin-left: 20px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
&__label {
|
|
67
|
+
border-left: 1px solid var(--border);
|
|
68
|
+
padding: 5px 20px;
|
|
69
|
+
color: var(--body-text);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
&__icon {
|
|
73
|
+
text-align: center;
|
|
74
|
+
padding: 5px 10px;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
</style>
|
|
@@ -100,14 +100,14 @@ export default {
|
|
|
100
100
|
v-if="shouldShowHeader"
|
|
101
101
|
class="tab-header"
|
|
102
102
|
>
|
|
103
|
-
<h2>
|
|
103
|
+
<!-- <h2>
|
|
104
104
|
{{ labelDisplay }}
|
|
105
105
|
<i
|
|
106
106
|
v-if="tooltip"
|
|
107
107
|
v-clean-tooltip="tooltip"
|
|
108
108
|
class="icon icon-info icon-lg"
|
|
109
109
|
/>
|
|
110
|
-
</h2>
|
|
110
|
+
</h2> -->
|
|
111
111
|
<slot name="tab-header-right" />
|
|
112
112
|
</div>
|
|
113
113
|
<slot v-bind="{active}" />
|
|
@@ -118,7 +118,7 @@ export default {
|
|
|
118
118
|
.tab-header {
|
|
119
119
|
display: flex;
|
|
120
120
|
justify-content: space-between;
|
|
121
|
-
margin-bottom: 15px;
|
|
121
|
+
/* margin-bottom: 15px; */
|
|
122
122
|
align-items: center;
|
|
123
123
|
|
|
124
124
|
h2 {
|
|
@@ -367,15 +367,6 @@ export default {
|
|
|
367
367
|
margin: 0;
|
|
368
368
|
padding: 0;
|
|
369
369
|
|
|
370
|
-
&:focus-visible {
|
|
371
|
-
outline: none;
|
|
372
|
-
|
|
373
|
-
.tab.active {
|
|
374
|
-
@include focus-outline;
|
|
375
|
-
outline-offset: -2px;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
370
|
&.horizontal {
|
|
380
371
|
border: solid thin var(--border);
|
|
381
372
|
border-bottom: 0;
|
|
@@ -391,8 +382,12 @@ export default {
|
|
|
391
382
|
}
|
|
392
383
|
}
|
|
393
384
|
|
|
394
|
-
&:focus
|
|
395
|
-
|
|
385
|
+
&:focus {
|
|
386
|
+
outline: none;
|
|
387
|
+
|
|
388
|
+
& .tab.active a span {
|
|
389
|
+
text-decoration: none;
|
|
390
|
+
}
|
|
396
391
|
}
|
|
397
392
|
|
|
398
393
|
.tab {
|
|
@@ -409,7 +404,7 @@ export default {
|
|
|
409
404
|
&:hover {
|
|
410
405
|
text-decoration: none;
|
|
411
406
|
span {
|
|
412
|
-
text-decoration:
|
|
407
|
+
text-decoration: none;
|
|
413
408
|
}
|
|
414
409
|
}
|
|
415
410
|
}
|
|
@@ -479,45 +474,68 @@ export default {
|
|
|
479
474
|
|
|
480
475
|
.side-tabs {
|
|
481
476
|
display: flex;
|
|
482
|
-
|
|
477
|
+
flex-direction: column;
|
|
478
|
+
/* box-shadow: 0 0 20px var(--shadow);
|
|
483
479
|
border-radius: calc(var(--border-radius) * 2);
|
|
484
|
-
background-color: var(--tabbed-sidebar-bg);
|
|
485
|
-
|
|
480
|
+
background-color: var(--tabbed-sidebar-bg); */
|
|
481
|
+
margin: 0px -20px;
|
|
486
482
|
.tab-container {
|
|
487
483
|
padding: 20px;
|
|
488
484
|
}
|
|
489
485
|
|
|
490
486
|
& .tabs {
|
|
491
|
-
width: $sideways-tabs-width;
|
|
492
|
-
min-width: $sideways-tabs-width;
|
|
487
|
+
/* width: $sideways-tabs-width; */
|
|
488
|
+
/* min-width: $sideways-tabs-width; */
|
|
493
489
|
display: flex;
|
|
494
|
-
|
|
495
|
-
|
|
490
|
+
border-bottom:1px solid #d7d7d7;
|
|
491
|
+
padding: 0 0 0 20px;
|
|
492
|
+
/* flex: 1 0; */
|
|
493
|
+
/* flex-direction: column; */
|
|
496
494
|
|
|
497
495
|
// &.vertical {
|
|
498
496
|
// .tab.active {
|
|
499
497
|
// background-color: var(--tabbed-container-bg);
|
|
500
498
|
// }
|
|
501
499
|
// }
|
|
502
|
-
|
|
503
500
|
& .tab {
|
|
504
|
-
width: 100%;
|
|
505
|
-
|
|
501
|
+
/* width: 100%; */
|
|
502
|
+
width: 120px;
|
|
503
|
+
height: 36px;
|
|
504
|
+
/* border-top: solid 5px transparent; */
|
|
505
|
+
display: flex;
|
|
506
|
+
justify-content: center;
|
|
507
|
+
padding: 8px 16px;
|
|
508
|
+
box-sizing: border-box;
|
|
509
|
+
border: 1px solid #d7d7d7;
|
|
510
|
+
border-bottom: 0px;
|
|
511
|
+
margin-right: 5px;
|
|
512
|
+
border-radius: 2px;
|
|
506
513
|
|
|
507
514
|
&.toggle A {
|
|
508
515
|
color: var(--primary);
|
|
516
|
+
padding: 0px;
|
|
509
517
|
}
|
|
510
518
|
|
|
511
519
|
A {
|
|
512
|
-
color: var(--
|
|
520
|
+
color: var(--input-label);
|
|
521
|
+
padding: 0px;
|
|
513
522
|
}
|
|
514
523
|
|
|
515
524
|
&.active {
|
|
516
525
|
background-color: var(--body-bg);
|
|
517
|
-
border-
|
|
526
|
+
border-top: solid 2px var(--primary);
|
|
527
|
+
position: relative;
|
|
528
|
+
&.active::before{
|
|
529
|
+
position: absolute;
|
|
530
|
+
right: 0;
|
|
531
|
+
left: 0;
|
|
532
|
+
top: 34px;
|
|
533
|
+
border-bottom: 1px solid #fff;
|
|
534
|
+
content: '';
|
|
518
535
|
|
|
536
|
+
}
|
|
519
537
|
& A {
|
|
520
|
-
color: var(--
|
|
538
|
+
color: var(--primary);
|
|
521
539
|
}
|
|
522
540
|
}
|
|
523
541
|
|
|
@@ -561,7 +579,7 @@ export default {
|
|
|
561
579
|
&
|
|
562
580
|
|
|
563
581
|
.tab-container {
|
|
564
|
-
width: calc(100% - #{$sideways-tabs-width});
|
|
582
|
+
/* width: calc(100% - #{$sideways-tabs-width}); */
|
|
565
583
|
flex-grow: 1;
|
|
566
584
|
background-color: var(--body-bg);
|
|
567
585
|
}
|
package/components/Wizard.vue
CHANGED
|
@@ -426,7 +426,7 @@ export default {
|
|
|
426
426
|
</div>
|
|
427
427
|
<div
|
|
428
428
|
id="wizard-footer-controls"
|
|
429
|
-
class="controls-row
|
|
429
|
+
class="controls-row"
|
|
430
430
|
>
|
|
431
431
|
<slot
|
|
432
432
|
name="cancel"
|
|
@@ -674,7 +674,7 @@ $spacer: 10px;
|
|
|
674
674
|
// We have to account for the absolute position of the .controls-row
|
|
675
675
|
.footer-error {
|
|
676
676
|
margin-top: -40px;
|
|
677
|
-
margin-bottom:
|
|
677
|
+
margin-bottom: calc($footer-height + 10px);
|
|
678
678
|
}
|
|
679
679
|
|
|
680
680
|
.controls-row {
|
|
@@ -42,7 +42,7 @@ describe('component: AsyncButton', () => {
|
|
|
42
42
|
expect(span.text()).toBe('some-string');
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
it('click on async button should emit click with a proper state of waiting, disabled and spinning ::: CB true', () => {
|
|
45
|
+
it('click on async button should emit click with a proper state of waiting, appear disabled and spinning ::: CB true', () => {
|
|
46
46
|
jest.useFakeTimers();
|
|
47
47
|
|
|
48
48
|
const wrapper: VueWrapper<InstanceType<typeof AsyncButton>> = mount(AsyncButton, {
|
|
@@ -65,7 +65,7 @@ describe('component: AsyncButton', () => {
|
|
|
65
65
|
expect(wrapper.emitted('click')).toHaveLength(1);
|
|
66
66
|
expect(wrapper.vm.phase).toBe(ASYNC_BUTTON_STATES.WAITING);
|
|
67
67
|
expect(wrapper.vm.isSpinning).toBe(true);
|
|
68
|
-
expect(wrapper.vm.
|
|
68
|
+
expect(wrapper.vm.appearsDisabled).toBe(true);
|
|
69
69
|
// testing cb function has been emitted
|
|
70
70
|
expect(typeof wrapper.emitted('click')![0][0]).toBe('function');
|
|
71
71
|
|
|
@@ -40,7 +40,7 @@ describe('component: FixedBanner', () => {
|
|
|
40
40
|
expect(wrapper.vm.showHeader).toStrictEqual(true);
|
|
41
41
|
|
|
42
42
|
const bannerElem = wrapper.find('.banner');
|
|
43
|
-
const noArrayTextElem = wrapper.find('.banner
|
|
43
|
+
const noArrayTextElem = wrapper.find('.banner .single-row');
|
|
44
44
|
|
|
45
45
|
expect(bannerElem.exists()).toBe(true);
|
|
46
46
|
expect(bannerElem.classes()).not.toContain('banner-consent');
|
|
@@ -60,7 +60,7 @@ describe('component: FixedBanner', () => {
|
|
|
60
60
|
expect(wrapper.vm.showFooter).toStrictEqual(true);
|
|
61
61
|
|
|
62
62
|
const bannerElem = wrapper.find('.banner');
|
|
63
|
-
const noArrayTextElem = wrapper.find('.banner
|
|
63
|
+
const noArrayTextElem = wrapper.find('.banner .single-row');
|
|
64
64
|
|
|
65
65
|
expect(bannerElem.exists()).toBe(true);
|
|
66
66
|
expect(bannerElem.classes()).not.toContain('banner-consent');
|
|
@@ -84,7 +84,7 @@ describe('component: FixedBanner', () => {
|
|
|
84
84
|
const bannerDialogElem = wrapper.find('.banner-dialog');
|
|
85
85
|
const bannerDialogFrameElem = wrapper.find('.banner-dialog-frame');
|
|
86
86
|
const buttonDialog = wrapper.find('.banner-dialog button');
|
|
87
|
-
const noArrayTextElem = wrapper.find('.banner
|
|
87
|
+
const noArrayTextElem = wrapper.find('.banner .single-row');
|
|
88
88
|
|
|
89
89
|
expect(bannerElem.exists()).toBe(true);
|
|
90
90
|
expect(bannerDialogGlassElem.exists()).toBe(true);
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { createStore, Store } from 'vuex';
|
|
3
|
+
import { nextTick } from 'vue';
|
|
4
|
+
|
|
5
|
+
import ModalManager from '@shell/components/ModalManager.vue';
|
|
6
|
+
|
|
7
|
+
interface ModalManagerMethods {
|
|
8
|
+
registerBackgroundClosing(fn: Function): void;
|
|
9
|
+
close(): void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const MockComponent = {
|
|
13
|
+
template: '<div data-testid="modal-manager-component">Mock Content</div>',
|
|
14
|
+
props: ['someProp', 'resources', 'registerBackgroundClosing']
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
describe('modalManager.vue with Teleport', () => {
|
|
18
|
+
let store: Store<any>;
|
|
19
|
+
let getters: Record<string, () => any>;
|
|
20
|
+
let modalsDiv: HTMLDivElement;
|
|
21
|
+
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
// Create the teleport target container
|
|
24
|
+
modalsDiv = document.createElement('div');
|
|
25
|
+
modalsDiv.setAttribute('id', 'modals');
|
|
26
|
+
document.body.appendChild(modalsDiv);
|
|
27
|
+
|
|
28
|
+
getters = {
|
|
29
|
+
'modal/isOpen': () => true,
|
|
30
|
+
'modal/component': () => MockComponent,
|
|
31
|
+
'modal/componentProps': () => ({ someProp: 'testValue' }),
|
|
32
|
+
'modal/resources': () => ({ data: 'mockData' }),
|
|
33
|
+
'modal/closeOnClickOutside': () => true,
|
|
34
|
+
'modal/modalWidth': () => '500px'
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
store = createStore({
|
|
38
|
+
getters,
|
|
39
|
+
mutations: { 'modal/closeModal': jest.fn() }
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
afterEach(() => {
|
|
44
|
+
// Clean up the teleport container after each test
|
|
45
|
+
document.body.removeChild(modalsDiv);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const factory = () => {
|
|
49
|
+
return mount(ModalManager, {
|
|
50
|
+
attachTo: document.body, // attach so Teleport can work properly
|
|
51
|
+
global: {
|
|
52
|
+
plugins: [store],
|
|
53
|
+
stubs: {
|
|
54
|
+
AppModal: {
|
|
55
|
+
name: 'AppModal',
|
|
56
|
+
template: `<div data-testid="app-modal" @close="$emit('close')" :style="{ '--prompt-modal-width': width }"><slot /></div>`,
|
|
57
|
+
props: ['clickToClose', 'width']
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
it('renders the AppModal and dynamic component when modal is open', async() => {
|
|
65
|
+
factory();
|
|
66
|
+
|
|
67
|
+
await nextTick();
|
|
68
|
+
|
|
69
|
+
// Because Teleport moves content out of the normal wrapper,
|
|
70
|
+
// we query the document for the teleported elements.
|
|
71
|
+
const appModal = document.querySelector('[data-testid="app-modal"]');
|
|
72
|
+
const dynamicComponent = document.querySelector('[data-testid="modal-manager-component"]');
|
|
73
|
+
|
|
74
|
+
expect(appModal).toBeTruthy();
|
|
75
|
+
expect(dynamicComponent).toBeTruthy();
|
|
76
|
+
expect(appModal?.getAttribute('style')).toContain('--prompt-modal-width: 500px');
|
|
77
|
+
|
|
78
|
+
// We assume the mock component is rendered correctly if its markup is found.
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('does not render the AppModal when modal is closed', async() => {
|
|
82
|
+
getters['modal/isOpen'] = () => false;
|
|
83
|
+
store = createStore({
|
|
84
|
+
getters,
|
|
85
|
+
mutations: { 'modal/closeModal': jest.fn() }
|
|
86
|
+
});
|
|
87
|
+
factory();
|
|
88
|
+
await nextTick();
|
|
89
|
+
|
|
90
|
+
const appModal = document.querySelector('[data-testid="app-modal"]');
|
|
91
|
+
|
|
92
|
+
expect(appModal).toBeNull();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('does not render the AppModal when dynamic component is null', async() => {
|
|
96
|
+
getters['modal/component'] = () => null;
|
|
97
|
+
store = createStore({
|
|
98
|
+
getters,
|
|
99
|
+
mutations: { 'modal/closeModal': jest.fn() }
|
|
100
|
+
});
|
|
101
|
+
factory();
|
|
102
|
+
await nextTick();
|
|
103
|
+
|
|
104
|
+
const appModal = document.querySelector('[data-testid="app-modal"]');
|
|
105
|
+
|
|
106
|
+
expect(appModal).toBeNull();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('calls store commit when close is triggered', async() => {
|
|
110
|
+
const closeModalMutation = jest.fn();
|
|
111
|
+
|
|
112
|
+
getters['modal/isOpen'] = () => true;
|
|
113
|
+
store = createStore({
|
|
114
|
+
getters,
|
|
115
|
+
mutations: { 'modal/closeModal': closeModalMutation }
|
|
116
|
+
});
|
|
117
|
+
const wrapper = factory();
|
|
118
|
+
|
|
119
|
+
await nextTick();
|
|
120
|
+
|
|
121
|
+
const appModalWrapper = wrapper.findComponent({ name: 'AppModal' });
|
|
122
|
+
|
|
123
|
+
appModalWrapper.vm.$emit('close');
|
|
124
|
+
await nextTick();
|
|
125
|
+
|
|
126
|
+
expect(closeModalMutation).toHaveBeenCalledWith({}, undefined);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('calls registered background closing function on close', async() => {
|
|
130
|
+
const closeModalMutation = jest.fn();
|
|
131
|
+
|
|
132
|
+
getters['modal/isOpen'] = () => true;
|
|
133
|
+
store = createStore({
|
|
134
|
+
getters,
|
|
135
|
+
mutations: { 'modal/closeModal': closeModalMutation }
|
|
136
|
+
});
|
|
137
|
+
const wrapper = factory();
|
|
138
|
+
|
|
139
|
+
await nextTick();
|
|
140
|
+
|
|
141
|
+
const backgroundFn = jest.fn();
|
|
142
|
+
|
|
143
|
+
(wrapper.vm as unknown as ModalManagerMethods).registerBackgroundClosing(backgroundFn);
|
|
144
|
+
await nextTick();
|
|
145
|
+
|
|
146
|
+
const appModalWrapper = wrapper.findComponent({ name: 'AppModal' });
|
|
147
|
+
|
|
148
|
+
appModalWrapper.vm.$emit('close');
|
|
149
|
+
await nextTick();
|
|
150
|
+
|
|
151
|
+
expect(backgroundFn).toHaveBeenCalledWith();
|
|
152
|
+
expect(closeModalMutation).toHaveBeenCalledWith({}, undefined);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('does nothing if modal is already closed when close is triggered', async() => {
|
|
156
|
+
const closeModalMutation = jest.fn();
|
|
157
|
+
|
|
158
|
+
getters['modal/isOpen'] = () => false;
|
|
159
|
+
store = createStore({
|
|
160
|
+
getters,
|
|
161
|
+
mutations: { 'modal/closeModal': closeModalMutation }
|
|
162
|
+
});
|
|
163
|
+
const wrapper = factory();
|
|
164
|
+
|
|
165
|
+
await nextTick();
|
|
166
|
+
|
|
167
|
+
const modalManager = wrapper.vm as unknown as ModalManagerMethods;
|
|
168
|
+
const spy = jest.spyOn(modalManager, 'close');
|
|
169
|
+
|
|
170
|
+
modalManager.close();
|
|
171
|
+
await nextTick();
|
|
172
|
+
|
|
173
|
+
expect(spy).toHaveBeenCalledWith();
|
|
174
|
+
expect(closeModalMutation).not.toHaveBeenCalled();
|
|
175
|
+
});
|
|
176
|
+
});
|