@rancher/shell 3.0.5-rc.3 → 3.0.5-rc.5
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/icons/document.svg +3 -0
- package/assets/images/vendor/cognito.svg +1 -0
- package/assets/styles/app.scss +1 -0
- package/assets/styles/base/_basic.scss +10 -0
- package/assets/styles/base/_spacing.scss +29 -0
- package/assets/styles/global/_layout.scss +1 -1
- package/assets/styles/themes/_dark.scss +25 -0
- package/assets/styles/themes/_light.scss +65 -0
- package/assets/translations/en-us.yaml +322 -24
- package/assets/translations/zh-hans.yaml +8 -5
- package/components/Certificates.vue +5 -0
- package/components/FilterPanel.vue +156 -0
- package/components/{fleet/ForceDirectedTreeChart/index.vue → ForceDirectedTreeChart.vue} +47 -41
- package/components/IconOrSvg.vue +14 -35
- package/components/PromptRemove.vue +5 -1
- package/components/Resource/Detail/Card/PodsCard/Bubble.vue +13 -0
- package/components/Resource/Detail/Card/PodsCard/composable.ts +30 -0
- package/components/Resource/Detail/Card/PodsCard/index.vue +118 -0
- package/components/Resource/Detail/Card/ResourceUsageCard/composable.ts +51 -0
- package/components/Resource/Detail/Card/ResourceUsageCard/index.vue +79 -0
- package/components/Resource/Detail/Card/Scaler.vue +89 -0
- package/components/Resource/Detail/Card/StateCard/composables.ts +112 -0
- package/components/Resource/Detail/Card/StateCard/index.vue +39 -0
- package/components/Resource/Detail/Card/VerticalGap.vue +11 -0
- package/components/Resource/Detail/Card/__tests__/Card.test.ts +36 -0
- package/components/Resource/Detail/Card/__tests__/PodsCard.test.ts +84 -0
- package/components/Resource/Detail/Card/__tests__/ResourceUsageCard.test.ts +72 -0
- package/components/Resource/Detail/Card/__tests__/Scaler.test.ts +87 -0
- package/components/Resource/Detail/Card/__tests__/StateCard.test.ts +53 -0
- package/components/Resource/Detail/Card/__tests__/VerticalGap.test.ts +14 -0
- package/components/Resource/Detail/Card/__tests__/index.test.ts +36 -0
- package/components/Resource/Detail/Card/index.vue +56 -0
- package/components/Resource/Detail/Metadata/Annotations/__tests__/index.test.ts +19 -0
- package/components/Resource/Detail/Metadata/Annotations/composable.ts +12 -0
- package/components/Resource/Detail/Metadata/Annotations/index.vue +26 -0
- package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/index.test.ts +103 -0
- package/components/Resource/Detail/Metadata/IdentifyingInformation/composable.ts +281 -0
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +111 -0
- package/components/Resource/Detail/Metadata/KeyValue.vue +130 -0
- package/components/Resource/Detail/Metadata/Labels/__tests__/index.test.ts +18 -0
- package/components/Resource/Detail/Metadata/Labels/composable.ts +12 -0
- package/components/Resource/Detail/Metadata/Labels/index.vue +27 -0
- package/components/Resource/Detail/Metadata/Rectangle.vue +32 -0
- package/components/Resource/Detail/Metadata/__tests__/KeyValue.test.ts +107 -0
- package/components/Resource/Detail/Metadata/__tests__/Rectangle.test.ts +24 -0
- package/components/Resource/Detail/Metadata/__tests__/index.test.ts +91 -0
- package/components/Resource/Detail/Metadata/composables.ts +29 -0
- package/components/Resource/Detail/Metadata/index.vue +66 -0
- package/components/Resource/Detail/Page.vue +22 -0
- package/components/Resource/Detail/PercentageBar.vue +40 -0
- package/components/Resource/Detail/ResourceRow.vue +119 -0
- package/components/Resource/Detail/SpacedRow.vue +14 -0
- package/components/Resource/Detail/StatusBar.vue +59 -0
- package/components/Resource/Detail/StatusRow.vue +61 -0
- package/components/Resource/Detail/TitleBar/Title.vue +13 -0
- package/components/Resource/Detail/TitleBar/Top.vue +14 -0
- package/components/Resource/Detail/TitleBar/__tests__/Title.test.ts +17 -0
- package/components/Resource/Detail/TitleBar/__tests__/Top.test.ts +17 -0
- package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +142 -0
- package/components/Resource/Detail/TitleBar/composable.ts +31 -0
- package/components/Resource/Detail/TitleBar/index.vue +124 -0
- package/components/Resource/Detail/Top/index.vue +34 -0
- package/components/Resource/Detail/__tests__/Page.test.ts +32 -0
- package/components/ResourceDetail/__tests__/index.test.ts +114 -0
- package/components/ResourceDetail/index.vue +64 -562
- package/components/ResourceDetail/legacy.vue +545 -0
- package/components/ResourceTable.vue +41 -7
- package/components/SlideInPanelManager.vue +76 -8
- package/components/SortableTable/index.vue +13 -2
- package/components/SortableTable/selection.js +21 -8
- package/components/StatusBadge.vue +6 -4
- package/components/SubtleLink.vue +25 -0
- package/components/Wizard.vue +12 -1
- package/components/YamlEditor.vue +1 -1
- package/components/__tests__/FilterPanel.test.ts +81 -0
- package/components/auth/AuthBanner.vue +2 -3
- package/components/auth/RoleDetailEdit.vue +45 -3
- package/components/auth/login/oidc.vue +6 -1
- package/components/fleet/FleetApplications.vue +181 -0
- package/components/fleet/FleetHelmOps.vue +115 -0
- package/components/fleet/FleetIntro.vue +58 -28
- package/components/fleet/FleetNoWorkspaces.vue +5 -1
- package/components/fleet/FleetOCIStorageSecret.vue +171 -0
- package/components/fleet/FleetRepos.vue +38 -76
- package/components/fleet/FleetResources.vue +50 -22
- package/components/fleet/FleetSummary.vue +26 -51
- package/components/fleet/__tests__/FleetOCIStorageSecret.test.ts +213 -0
- package/components/fleet/__tests__/FleetSummary.test.ts +39 -39
- package/components/fleet/dashboard/Empty.vue +73 -0
- package/components/fleet/dashboard/ResourceCard.vue +183 -0
- package/components/fleet/dashboard/ResourceCardSummary.vue +199 -0
- package/components/fleet/dashboard/ResourceDetails.vue +196 -0
- package/components/fleet/dashboard/ResourcePanel.vue +376 -0
- package/components/form/ArrayList.vue +6 -0
- package/components/form/SimpleSecretSelector.vue +8 -2
- package/components/form/ValueFromResource.vue +31 -19
- package/components/formatter/FleetApplicationClustersReady.vue +77 -0
- package/components/formatter/FleetApplicationSource.vue +71 -0
- package/components/formatter/FleetSummaryGraph.vue +7 -0
- package/components/nav/Header.vue +8 -7
- package/components/nav/TopLevelMenu.helper.ts +55 -34
- package/components/nav/TopLevelMenu.vue +11 -0
- package/components/nav/Type.vue +4 -1
- package/composables/useI18n.ts +12 -11
- package/config/labels-annotations.js +14 -11
- package/config/product/auth.js +1 -0
- package/config/product/fleet.js +70 -17
- package/config/query-params.js +3 -1
- package/config/roles.ts +1 -0
- package/config/router/routes.js +20 -2
- package/config/secret.ts +15 -0
- package/config/settings.ts +3 -2
- package/config/table-headers.js +52 -22
- package/config/types.js +2 -0
- package/core/plugin-helpers.ts +3 -2
- package/detail/fleet.cattle.io.cluster.vue +28 -15
- package/detail/fleet.cattle.io.gitrepo.vue +10 -1
- package/detail/fleet.cattle.io.helmop.vue +157 -0
- package/dialog/HelmOpForceUpdateDialog.vue +132 -0
- package/dialog/RedeployWorkloadDialog.vue +164 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +56 -67
- package/edit/auth/oidc.vue +159 -93
- package/edit/fleet.cattle.io.gitrepo.vue +26 -33
- package/edit/fleet.cattle.io.helmop.vue +997 -0
- package/edit/management.cattle.io.fleetworkspace.vue +43 -10
- package/list/fleet.cattle.io.gitrepo.vue +1 -1
- package/list/fleet.cattle.io.helmop.vue +108 -0
- package/list/namespace.vue +5 -2
- package/mixins/auth-config.js +8 -1
- package/mixins/preset.js +100 -0
- package/mixins/resource-fetch-api-pagination.js +2 -0
- package/mixins/resource-fetch.js +1 -1
- package/mixins/resource-table-watch.js +45 -0
- package/models/__tests__/chart.test.ts +273 -0
- package/models/__tests__/fleet.cattle.io.gitrepo.test.ts +1 -1
- package/models/chart.js +144 -2
- package/models/fleet-application.js +385 -0
- package/models/fleet.cattle.io.bundle.js +9 -8
- package/models/fleet.cattle.io.gitrepo.js +41 -365
- package/models/fleet.cattle.io.helmop.js +228 -0
- package/models/management.cattle.io.authconfig.js +1 -0
- package/models/management.cattle.io.fleetworkspace.js +12 -0
- package/models/workload.js +14 -18
- package/package.json +2 -1
- package/pages/auth/verify.vue +13 -1
- package/pages/c/_cluster/apps/charts/AddRepoLink.vue +37 -0
- package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +80 -0
- package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +54 -0
- package/pages/c/_cluster/apps/charts/StatusLabel.vue +33 -0
- package/pages/c/_cluster/apps/charts/index.vue +302 -484
- package/pages/c/_cluster/explorer/EventsTable.vue +1 -1
- package/pages/c/_cluster/fleet/__tests__/index.test.ts +426 -0
- package/pages/c/_cluster/fleet/application/_resource/_id.vue +14 -0
- package/pages/c/_cluster/fleet/application/_resource/create.vue +14 -0
- package/pages/c/_cluster/fleet/application/create.vue +340 -0
- package/pages/c/_cluster/fleet/application/index.vue +139 -0
- package/pages/c/_cluster/fleet/graph/config.js +277 -0
- package/pages/c/_cluster/fleet/index.vue +772 -330
- package/pages/explorer/resource/detail/configmap.vue +19 -0
- package/plugins/dashboard-store/actions.js +31 -9
- package/plugins/dashboard-store/getters.js +34 -21
- package/plugins/dashboard-store/mutations.js +51 -7
- package/plugins/dashboard-store/resource-class.js +14 -2
- package/plugins/steve/__tests__/subscribe.spec.ts +66 -1
- package/plugins/steve/actions.js +3 -0
- package/plugins/steve/steve-pagination-utils.ts +14 -13
- package/plugins/steve/subscribe.js +229 -42
- package/rancher-components/BadgeState/BadgeState.vue +3 -1
- package/rancher-components/Form/Checkbox/Checkbox.vue +2 -2
- package/rancher-components/RcItemCard/RcItemCard.test.ts +189 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +425 -0
- package/rancher-components/RcItemCard/RcItemCardAction.vue +24 -0
- package/rancher-components/RcItemCard/index.ts +2 -0
- package/store/auth.js +1 -0
- package/store/catalog.js +62 -24
- package/store/index.js +33 -14
- package/store/slideInPanel.ts +6 -0
- package/store/type-map.js +1 -0
- package/types/fleet.d.ts +35 -0
- package/types/resources/settings.d.ts +19 -1
- package/types/shell/index.d.ts +339 -272
- package/types/store/dashboard-store.types.ts +17 -3
- package/types/store/pagination.types.ts +6 -1
- package/types/store/subscribe.types.ts +50 -0
- package/utils/auth.js +32 -3
- package/utils/fleet-types.ts +0 -0
- package/utils/fleet.ts +200 -1
- package/utils/pagination-utils.ts +26 -1
- package/utils/pagination-wrapper.ts +132 -50
- package/utils/settings.ts +4 -1
- package/utils/style.ts +39 -0
- package/utils/validators/formRules/__tests__/index.test.ts +36 -3
- package/utils/validators/formRules/index.ts +10 -3
- package/utils/window.js +11 -7
- package/components/__tests__/ApplicationCard.test.ts +0 -27
- package/components/cards/ApplicationCard.vue +0 -145
- package/components/fleet/ForceDirectedTreeChart/chartIcons.js +0 -17
- package/config/secret.js +0 -14
- package/pages/c/_cluster/fleet/GitRepoGraphConfig.js +0 -249
- /package/{components/form/SSHKnownHosts → dialog}/__tests__/KnownHostsEditDialog.test.ts +0 -0
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import { computed } from 'vue';
|
|
2
|
+
import { computed, watch } from 'vue';
|
|
3
3
|
import { useStore } from 'vuex';
|
|
4
|
+
import {
|
|
5
|
+
DEFAULT_FOCUS_TRAP_OPTS,
|
|
6
|
+
useWatcherBasedSetupFocusTrapWithDestroyIncluded
|
|
7
|
+
} from '@shell/composables/focusTrap';
|
|
4
8
|
|
|
5
9
|
const HEADER_HEIGHT = 55;
|
|
6
10
|
|
|
7
11
|
const store = useStore();
|
|
8
12
|
const isOpen = computed(() => store.getters['slideInPanel/isOpen']);
|
|
13
|
+
const isClosing = computed(() => store.getters['slideInPanel/isClosing']);
|
|
9
14
|
const currentComponent = computed(() => store.getters['slideInPanel/component']);
|
|
10
15
|
const currentProps = computed(() => store.getters['slideInPanel/componentProps']);
|
|
11
16
|
|
|
@@ -23,8 +28,61 @@ const panelTop = computed(() => {
|
|
|
23
28
|
const panelHeight = computed(() => `calc(100vh - ${ panelTop?.value })`);
|
|
24
29
|
const panelWidth = computed(() => currentProps?.value?.width || '33%');
|
|
25
30
|
const panelRight = computed(() => (isOpen?.value ? '0' : `-${ panelWidth?.value }`));
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
const panelZIndex = computed(() => `${ (isOpen?.value ? 1 : 2) * (currentProps?.value?.zIndex ?? 1000) }`);
|
|
32
|
+
|
|
33
|
+
const showHeader = computed(() => currentProps?.value?.showHeader ?? true);
|
|
34
|
+
const panelTitle = showHeader.value ? computed(() => currentProps?.value?.title || 'Details') : null;
|
|
35
|
+
|
|
36
|
+
watch(
|
|
37
|
+
/**
|
|
38
|
+
* trigger focus trap
|
|
39
|
+
*/
|
|
40
|
+
() => currentProps?.value?.triggerFocusTrap,
|
|
41
|
+
(neu) => {
|
|
42
|
+
if (neu) {
|
|
43
|
+
const opts = {
|
|
44
|
+
...DEFAULT_FOCUS_TRAP_OPTS,
|
|
45
|
+
/**
|
|
46
|
+
* will return focus to the first iterable node of this container select
|
|
47
|
+
*/
|
|
48
|
+
setReturnFocus: () => {
|
|
49
|
+
const returnFocusSelector = currentProps?.value?.returnFocusSelector;
|
|
50
|
+
|
|
51
|
+
if (returnFocusSelector && !document.querySelector(returnFocusSelector)) {
|
|
52
|
+
console.warn('SlideInPanelManager: cannot find elem with "returnFocusSelector", returning focus to main view'); // eslint-disable-line no-console
|
|
53
|
+
|
|
54
|
+
return '.dashboard-root';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return returnFocusSelector || '.dashboard-root';
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
useWatcherBasedSetupFocusTrapWithDestroyIncluded(
|
|
62
|
+
() => {
|
|
63
|
+
if (currentProps?.value?.focusTrapWatcherBasedVariable) {
|
|
64
|
+
return currentProps.value.focusTrapWatcherBasedVariable;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return isOpen?.value && !isClosing?.value;
|
|
68
|
+
},
|
|
69
|
+
'#slide-in-panel-manager',
|
|
70
|
+
opts,
|
|
71
|
+
false
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
watch(
|
|
78
|
+
() => (store as any).$router?.currentRoute,
|
|
79
|
+
() => {
|
|
80
|
+
if (isOpen?.value && currentProps?.value.closeOnRouteChange !== false) {
|
|
81
|
+
closePanel();
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
{ deep: true }
|
|
85
|
+
);
|
|
28
86
|
|
|
29
87
|
function closePanel() {
|
|
30
88
|
store.commit('slideInPanel/close');
|
|
@@ -33,7 +91,10 @@ function closePanel() {
|
|
|
33
91
|
|
|
34
92
|
<template>
|
|
35
93
|
<Teleport to="#slides">
|
|
36
|
-
<div
|
|
94
|
+
<div
|
|
95
|
+
id="slide-in-panel-manager"
|
|
96
|
+
@keydown.escape="closePanel"
|
|
97
|
+
>
|
|
37
98
|
<div
|
|
38
99
|
v-show="isOpen"
|
|
39
100
|
data-testid="slide-in-glass"
|
|
@@ -44,9 +105,18 @@ function closePanel() {
|
|
|
44
105
|
<div
|
|
45
106
|
class="slide-in"
|
|
46
107
|
:class="{ 'slide-in-open': isOpen }"
|
|
47
|
-
:style="{
|
|
108
|
+
:style="{
|
|
109
|
+
width: panelWidth,
|
|
110
|
+
right: panelRight,
|
|
111
|
+
top: panelTop,
|
|
112
|
+
height: panelHeight,
|
|
113
|
+
['z-index']: panelZIndex
|
|
114
|
+
}"
|
|
48
115
|
>
|
|
49
|
-
<div
|
|
116
|
+
<div
|
|
117
|
+
v-if="showHeader"
|
|
118
|
+
class="header"
|
|
119
|
+
>
|
|
50
120
|
<div class="title">
|
|
51
121
|
{{ panelTitle }}
|
|
52
122
|
</div>
|
|
@@ -84,7 +154,6 @@ function closePanel() {
|
|
|
84
154
|
background-color: var(--body-bg);
|
|
85
155
|
display: block;
|
|
86
156
|
opacity: 0.5;
|
|
87
|
-
z-index: 1000;
|
|
88
157
|
}
|
|
89
158
|
|
|
90
159
|
.slide-in {
|
|
@@ -92,7 +161,6 @@ function closePanel() {
|
|
|
92
161
|
flex-direction: column;
|
|
93
162
|
position: fixed;
|
|
94
163
|
top: 0;
|
|
95
|
-
z-index: 2000;
|
|
96
164
|
transition: right 0.5s ease;
|
|
97
165
|
border-left: 1px solid var(--border);
|
|
98
166
|
background-color: var(--body-bg);
|
|
@@ -64,6 +64,7 @@ export default {
|
|
|
64
64
|
ActionMenu,
|
|
65
65
|
ActionDropdownShell,
|
|
66
66
|
},
|
|
67
|
+
|
|
67
68
|
mixins: [
|
|
68
69
|
filtering,
|
|
69
70
|
sorting,
|
|
@@ -378,8 +379,17 @@ export default {
|
|
|
378
379
|
manualRefreshButtonSize: {
|
|
379
380
|
type: String,
|
|
380
381
|
default: ''
|
|
381
|
-
}
|
|
382
|
+
},
|
|
382
383
|
|
|
384
|
+
/**
|
|
385
|
+
* Usually the manual refresh button is controlled via isTooManyItemsToAutoUpdate
|
|
386
|
+
*
|
|
387
|
+
* However this is singular on page. In some places there's more than one...
|
|
388
|
+
*/
|
|
389
|
+
hideManualRefreshButton: {
|
|
390
|
+
type: Boolean,
|
|
391
|
+
default: false
|
|
392
|
+
}
|
|
383
393
|
},
|
|
384
394
|
|
|
385
395
|
data() {
|
|
@@ -1196,9 +1206,10 @@ export default {
|
|
|
1196
1206
|
<div class="bg" />
|
|
1197
1207
|
</li>
|
|
1198
1208
|
</ul>
|
|
1209
|
+
<slot name="watch-controls" />
|
|
1199
1210
|
<slot name="header-right" />
|
|
1200
1211
|
<AsyncButton
|
|
1201
|
-
v-if="isTooManyItemsToAutoUpdate"
|
|
1212
|
+
v-if="!hideManualRefreshButton && isTooManyItemsToAutoUpdate"
|
|
1202
1213
|
mode="manual-refresh"
|
|
1203
1214
|
:size="manualRefreshButtonSize"
|
|
1204
1215
|
:current-phase="refreshButtonPhase"
|
|
@@ -127,25 +127,38 @@ export default {
|
|
|
127
127
|
},
|
|
128
128
|
|
|
129
129
|
watch: {
|
|
130
|
-
|
|
130
|
+
/**
|
|
131
|
+
* Handle changes to the page (SSP enabled)
|
|
132
|
+
*/
|
|
133
|
+
externalPaginationResult() {
|
|
134
|
+
// Handle changes to the page (SSP enabled)
|
|
135
|
+
this.pageChanged(this.pagedRows);
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Handle changes to the page (SSP disabled)
|
|
140
|
+
*/
|
|
131
141
|
pagedRows() {
|
|
132
|
-
|
|
133
|
-
|
|
142
|
+
this.pageChanged(this.pagedRows);
|
|
143
|
+
}
|
|
144
|
+
},
|
|
134
145
|
|
|
135
|
-
|
|
146
|
+
methods: {
|
|
147
|
+
/**
|
|
148
|
+
* Remove items that are in the selection but no longer in the table.
|
|
149
|
+
*/
|
|
150
|
+
pageChanged(page) {
|
|
136
151
|
const toRemove = [];
|
|
137
152
|
|
|
138
153
|
for (const node of this.selectedRows) {
|
|
139
|
-
if (!
|
|
154
|
+
if (!page.includes(node) ) {
|
|
140
155
|
toRemove.push(node);
|
|
141
156
|
}
|
|
142
157
|
}
|
|
143
158
|
|
|
144
159
|
this.update([], toRemove);
|
|
145
|
-
}
|
|
146
|
-
},
|
|
160
|
+
},
|
|
147
161
|
|
|
148
|
-
methods: {
|
|
149
162
|
onToggleAll(value) {
|
|
150
163
|
if ( value ) {
|
|
151
164
|
this.update(this.pagedRows, []);
|
|
@@ -19,11 +19,13 @@ const STATUS = {
|
|
|
19
19
|
}
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
+
export interface Props {
|
|
23
|
+
status?: 'success' | 'warning' | 'info' | 'error',
|
|
24
|
+
label?: string
|
|
25
|
+
}
|
|
26
|
+
|
|
22
27
|
withDefaults(
|
|
23
|
-
defineProps<
|
|
24
|
-
status?: 'success' | 'warning' | 'info' | 'error',
|
|
25
|
-
label?: string
|
|
26
|
-
}>(),
|
|
28
|
+
defineProps<Props>(),
|
|
27
29
|
{
|
|
28
30
|
status: 'success',
|
|
29
31
|
label: '',
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { RouterLink, RouteLocationRaw } from 'vue-router';
|
|
3
|
+
|
|
4
|
+
export interface Props {
|
|
5
|
+
to: RouteLocationRaw;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const { to } = defineProps<Props>();
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<RouterLink
|
|
13
|
+
class="subtle-link"
|
|
14
|
+
:to="to"
|
|
15
|
+
>
|
|
16
|
+
<slot name="default" />
|
|
17
|
+
</RouterLink>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<style lang="scss" scoped>
|
|
21
|
+
.subtle-link {
|
|
22
|
+
text-decoration: underline;
|
|
23
|
+
color: var(--body-text);
|
|
24
|
+
}
|
|
25
|
+
</style>
|
package/components/Wizard.vue
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
|
|
2
|
+
import { _CREATE, _VIEW } from '@shell/config/query-params';
|
|
3
3
|
import AsyncButton from '@shell/components/AsyncButton';
|
|
4
4
|
import { Banner } from '@components/Banner';
|
|
5
5
|
import Loading from '@shell/components/Loading';
|
|
@@ -56,6 +56,11 @@ export default {
|
|
|
56
56
|
required: true
|
|
57
57
|
},
|
|
58
58
|
|
|
59
|
+
mode: {
|
|
60
|
+
type: String,
|
|
61
|
+
default: _CREATE
|
|
62
|
+
},
|
|
63
|
+
|
|
59
64
|
// Initial step to show when Wizard loads.
|
|
60
65
|
initStepIndex: {
|
|
61
66
|
type: Number,
|
|
@@ -121,6 +126,11 @@ export default {
|
|
|
121
126
|
},
|
|
122
127
|
|
|
123
128
|
computed: {
|
|
129
|
+
|
|
130
|
+
isView() {
|
|
131
|
+
return this.mode === _VIEW;
|
|
132
|
+
},
|
|
133
|
+
|
|
124
134
|
errorStrings() {
|
|
125
135
|
return ( this.errors || [] ).map((x) => stringify(x));
|
|
126
136
|
},
|
|
@@ -461,6 +471,7 @@ export default {
|
|
|
461
471
|
:finish="finish"
|
|
462
472
|
>
|
|
463
473
|
<AsyncButton
|
|
474
|
+
v-if="!isView"
|
|
464
475
|
:disabled="!activeStep.ready"
|
|
465
476
|
:mode="finishMode"
|
|
466
477
|
@click="finish"
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import FilterPanel from '@shell/components/FilterPanel.vue';
|
|
3
|
+
import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
|
|
4
|
+
|
|
5
|
+
const filters = [
|
|
6
|
+
{
|
|
7
|
+
key: 'status',
|
|
8
|
+
title: 'Status',
|
|
9
|
+
options: [
|
|
10
|
+
{ label: 'Installed', value: 'installed' },
|
|
11
|
+
{ label: 'Deprecated', value: 'deprecated' }
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
key: 'repos',
|
|
16
|
+
title: 'Repository',
|
|
17
|
+
options: [
|
|
18
|
+
{ label: 'Repo A', value: 'repo-a' },
|
|
19
|
+
{ label: 'Repo B', value: 'repo-b' }
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
describe('component: FilterPanel', () => {
|
|
25
|
+
it('renders all filter groups and options with correct labels', () => {
|
|
26
|
+
const wrapper = mount(FilterPanel, {
|
|
27
|
+
props: {
|
|
28
|
+
modelValue: {},
|
|
29
|
+
filters
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
expect(wrapper.findAll('.filter-panel-filter-group-title')).toHaveLength(2);
|
|
34
|
+
expect(wrapper.text()).toContain('Status');
|
|
35
|
+
expect(wrapper.text()).toContain('Repository');
|
|
36
|
+
expect(wrapper.text()).toContain('Installed');
|
|
37
|
+
expect(wrapper.text()).toContain('Repo A');
|
|
38
|
+
expect(wrapper.text()).toContain('Repo B');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('emits update:modelValue when a new status is added via checkbox emit', async() => {
|
|
42
|
+
const wrapper = mount(FilterPanel, {
|
|
43
|
+
props: {
|
|
44
|
+
modelValue: { status: ['installed'] },
|
|
45
|
+
filters
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const checkboxes = wrapper.findAllComponents(Checkbox);
|
|
50
|
+
const deprecatedCheckbox = checkboxes.find((c) => c.props('label') === 'Deprecated');
|
|
51
|
+
|
|
52
|
+
expect(deprecatedCheckbox).toBeTruthy();
|
|
53
|
+
|
|
54
|
+
deprecatedCheckbox?.vm.$emit('update:value', ['installed', 'deprecated']);
|
|
55
|
+
await wrapper.vm.$nextTick();
|
|
56
|
+
|
|
57
|
+
const emitted = wrapper.emitted('update:modelValue');
|
|
58
|
+
|
|
59
|
+
expect(emitted).toBeTruthy();
|
|
60
|
+
expect(emitted?.[0][0].status).toStrictEqual(['installed', 'deprecated']);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('renders a custom component if provided in option', () => {
|
|
64
|
+
const CustomComponent = { template: '<div>Custom content</div>' };
|
|
65
|
+
|
|
66
|
+
const wrapper = mount(FilterPanel, {
|
|
67
|
+
props: {
|
|
68
|
+
modelValue: {},
|
|
69
|
+
filters: [
|
|
70
|
+
{
|
|
71
|
+
key: 'custom',
|
|
72
|
+
title: 'Custom Filters',
|
|
73
|
+
options: [{ component: CustomComponent }]
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
expect(wrapper.text()).toContain('Custom content');
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -98,9 +98,8 @@ export default {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
.values {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
101
|
+
border-spacing: 8px 8px; // Add spacing between columns and rows
|
|
102
|
+
margin-left: -8px; // Move the table back to the left, to compensate for the spacing from above on the left-hand column
|
|
104
103
|
}
|
|
105
104
|
|
|
106
105
|
</style>
|
|
@@ -18,6 +18,7 @@ import LabeledInput from '@components/Form/LabeledInput/LabeledInput.vue';
|
|
|
18
18
|
|
|
19
19
|
import { SUBTYPE_MAPPING, VERBS } from '@shell/models/management.cattle.io.roletemplate';
|
|
20
20
|
import Loading from '@shell/components/Loading';
|
|
21
|
+
import Banner from '@components/Banner/Banner.vue';
|
|
21
22
|
|
|
22
23
|
const GLOBAL = SUBTYPE_MAPPING.GLOBAL.key;
|
|
23
24
|
const CLUSTER = SUBTYPE_MAPPING.CLUSTER.key;
|
|
@@ -64,7 +65,8 @@ export default {
|
|
|
64
65
|
SortableTable,
|
|
65
66
|
Loading,
|
|
66
67
|
Error,
|
|
67
|
-
LabeledInput
|
|
68
|
+
LabeledInput,
|
|
69
|
+
Banner,
|
|
68
70
|
},
|
|
69
71
|
|
|
70
72
|
mixins: [CreateEditView, FormValidation],
|
|
@@ -497,7 +499,8 @@ export default {
|
|
|
497
499
|
index: i,
|
|
498
500
|
apiGroups: rule.apiGroups || [''],
|
|
499
501
|
resources: rule.resources || [],
|
|
500
|
-
nonResourceURLs: rule.nonResourceURLs || []
|
|
502
|
+
nonResourceURLs: rule.nonResourceURLs || [],
|
|
503
|
+
verbs: rule.verbs,
|
|
501
504
|
};
|
|
502
505
|
|
|
503
506
|
VERBS.forEach((verb) => {
|
|
@@ -531,6 +534,13 @@ export default {
|
|
|
531
534
|
|
|
532
535
|
return res;
|
|
533
536
|
},
|
|
537
|
+
|
|
538
|
+
showPsaWarning(grant) {
|
|
539
|
+
return this.value.subtype === NAMESPACE &&
|
|
540
|
+
grant.verbs?.includes('updatepsa') &&
|
|
541
|
+
grant.resources?.includes('projects') &&
|
|
542
|
+
grant.apiGroups?.includes('management.cattle.io');
|
|
543
|
+
}
|
|
534
544
|
}
|
|
535
545
|
};
|
|
536
546
|
</script>
|
|
@@ -558,7 +568,28 @@ export default {
|
|
|
558
568
|
:table-actions="false"
|
|
559
569
|
:row-actions="false"
|
|
560
570
|
:search="false"
|
|
561
|
-
|
|
571
|
+
:sub-rows="true"
|
|
572
|
+
>
|
|
573
|
+
<template #sub-row="{row, fullColspan, onRowMouseEnter, onRowMouseLeave}">
|
|
574
|
+
<tr
|
|
575
|
+
|
|
576
|
+
class="sub-row"
|
|
577
|
+
@mouseenter="onRowMouseEnter"
|
|
578
|
+
@mouseleave="onRowMouseLeave"
|
|
579
|
+
>
|
|
580
|
+
<td
|
|
581
|
+
v-if="showPsaWarning(row)"
|
|
582
|
+
:colspan="fullColspan"
|
|
583
|
+
>
|
|
584
|
+
<Banner
|
|
585
|
+
style="margin: 0px"
|
|
586
|
+
label-key="rbac.roletemplate.tabs.grantResources.psaWarning"
|
|
587
|
+
color="warning"
|
|
588
|
+
/>
|
|
589
|
+
</td>
|
|
590
|
+
</tr>
|
|
591
|
+
</template>
|
|
592
|
+
</SortableTable>
|
|
562
593
|
<div
|
|
563
594
|
v-for="(inherited, index) of inheritedRules"
|
|
564
595
|
:key="index"
|
|
@@ -732,6 +763,17 @@ export default {
|
|
|
732
763
|
</div>
|
|
733
764
|
</div>
|
|
734
765
|
</template>
|
|
766
|
+
<template #value-sub-row="{row}">
|
|
767
|
+
<div
|
|
768
|
+
v-if="showPsaWarning(row.value)"
|
|
769
|
+
class="mr-20"
|
|
770
|
+
>
|
|
771
|
+
<Banner
|
|
772
|
+
label-key="rbac.roletemplate.tabs.grantResources.psaWarning"
|
|
773
|
+
color="warning"
|
|
774
|
+
/>
|
|
775
|
+
</div>
|
|
776
|
+
</template>
|
|
735
777
|
</ArrayList>
|
|
736
778
|
</Tab>
|
|
737
779
|
<Tab
|
|
@@ -6,7 +6,12 @@ export default {
|
|
|
6
6
|
|
|
7
7
|
computed: {
|
|
8
8
|
uniqueDisplayName() {
|
|
9
|
-
|
|
9
|
+
switch (this.name) {
|
|
10
|
+
case 'cognito':
|
|
11
|
+
return this.t('model.authConfig.description.cognito');
|
|
12
|
+
default:
|
|
13
|
+
return this.t('model.authConfig.description.oidc');
|
|
14
|
+
}
|
|
10
15
|
},
|
|
11
16
|
},
|
|
12
17
|
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { PropType } from 'vue';
|
|
3
|
+
import { checkPermissions } from '@shell/utils/auth';
|
|
4
|
+
import { FLEET } from '@shell/config/types';
|
|
5
|
+
import { Application } from '@shell/types/fleet';
|
|
6
|
+
import ResourceTable from '@shell/components/ResourceTable.vue';
|
|
7
|
+
import FleetIntro from '@shell/components/fleet/FleetIntro.vue';
|
|
8
|
+
import {
|
|
9
|
+
AGE,
|
|
10
|
+
NAME,
|
|
11
|
+
STATE,
|
|
12
|
+
FLEET_APPLICATION_TYPE,
|
|
13
|
+
FLEET_APPLICATION_SOURCE,
|
|
14
|
+
FLEET_APPLICATION_TARGET,
|
|
15
|
+
FLEET_APPLICATION_CLUSTERS_READY,
|
|
16
|
+
FLEET_APPLICATION_RESOURCES_SUMMARY,
|
|
17
|
+
} from '@shell/config/table-headers';
|
|
18
|
+
|
|
19
|
+
interface Permissions {
|
|
20
|
+
gitRepos: boolean,
|
|
21
|
+
helmOps: boolean,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface DataType {
|
|
25
|
+
permissions: Permissions
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default {
|
|
29
|
+
name: 'FleetApplications',
|
|
30
|
+
|
|
31
|
+
components: {
|
|
32
|
+
FleetIntro,
|
|
33
|
+
ResourceTable,
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
props: {
|
|
37
|
+
schema: {
|
|
38
|
+
type: Object,
|
|
39
|
+
required: true,
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
workspace: {
|
|
43
|
+
type: String,
|
|
44
|
+
default: ''
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
clusterId: {
|
|
48
|
+
type: String,
|
|
49
|
+
required: false,
|
|
50
|
+
default: null,
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
rows: {
|
|
54
|
+
type: Array as PropType<Application[]>,
|
|
55
|
+
required: true,
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
loading: {
|
|
59
|
+
type: Boolean,
|
|
60
|
+
required: false,
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
useQueryParamsForSimpleFiltering: {
|
|
64
|
+
type: Boolean,
|
|
65
|
+
default: false
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
showIntro: {
|
|
69
|
+
type: Boolean,
|
|
70
|
+
default: true,
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
async fetch() {
|
|
75
|
+
try {
|
|
76
|
+
const permissionsSchemas = {
|
|
77
|
+
gitRepos: {
|
|
78
|
+
type: FLEET.GIT_REPO,
|
|
79
|
+
schemaValidator: (schema: any) => schema.resourceMethods.includes('PUT')
|
|
80
|
+
},
|
|
81
|
+
helmOps: {
|
|
82
|
+
type: FLEET.HELM_OP,
|
|
83
|
+
schemaValidator: (schema: any) => schema.resourceMethods.includes('PUT')
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const permissions = await checkPermissions(permissionsSchemas, this.$store.getters) as Permissions;
|
|
88
|
+
|
|
89
|
+
this.permissions = permissions;
|
|
90
|
+
} catch (e) {
|
|
91
|
+
console.error(e); // eslint-disable-line no-console
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
data(): DataType {
|
|
96
|
+
return {
|
|
97
|
+
permissions: {
|
|
98
|
+
gitRepos: true,
|
|
99
|
+
helmOps: true
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
computed: {
|
|
105
|
+
createLocation() {
|
|
106
|
+
return { name: 'c-cluster-fleet-application-create' };
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
filteredRows() {
|
|
110
|
+
if (!this.rows) {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const selectedNamespaces = this.$store.getters['namespaces']();
|
|
115
|
+
|
|
116
|
+
return this.rows.filter((row) => {
|
|
117
|
+
if (this.workspace) {
|
|
118
|
+
return this.workspace === row.metadata.namespace;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return !!selectedNamespaces[row.metadata.namespace];
|
|
122
|
+
});
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
isClusterView() {
|
|
126
|
+
return !!this.clusterId;
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
shouldShowIntro() {
|
|
130
|
+
return this.showIntro && !this.filteredRows.length;
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
headers() {
|
|
134
|
+
return [
|
|
135
|
+
STATE,
|
|
136
|
+
NAME,
|
|
137
|
+
FLEET_APPLICATION_TYPE,
|
|
138
|
+
FLEET_APPLICATION_SOURCE,
|
|
139
|
+
FLEET_APPLICATION_TARGET,
|
|
140
|
+
FLEET_APPLICATION_CLUSTERS_READY,
|
|
141
|
+
FLEET_APPLICATION_RESOURCES_SUMMARY,
|
|
142
|
+
AGE
|
|
143
|
+
];
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
methods: {
|
|
148
|
+
getDetailLocation(row: Application) {
|
|
149
|
+
return row._detailLocation;
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
</script>
|
|
154
|
+
|
|
155
|
+
<template>
|
|
156
|
+
<div>
|
|
157
|
+
<FleetIntro
|
|
158
|
+
v-if="shouldShowIntro && !loading"
|
|
159
|
+
:schema="schema"
|
|
160
|
+
:is-creatable="permissions.gitRepos || permissions.helmOps"
|
|
161
|
+
:labelKey="'application'"
|
|
162
|
+
:route="createLocation"
|
|
163
|
+
:icon="'icon-repository'"
|
|
164
|
+
/>
|
|
165
|
+
<ResourceTable
|
|
166
|
+
v-if="!shouldShowIntro"
|
|
167
|
+
v-bind="$attrs"
|
|
168
|
+
key-field="_key"
|
|
169
|
+
:schema="schema"
|
|
170
|
+
:headers="headers"
|
|
171
|
+
:rows="filteredRows"
|
|
172
|
+
:get-custom-detail-link="getDetailLocation"
|
|
173
|
+
:loading="loading"
|
|
174
|
+
:use-query-params-for-simple-filtering="useQueryParamsForSimpleFiltering"
|
|
175
|
+
:namespaced="!workspace"
|
|
176
|
+
/>
|
|
177
|
+
</div>
|
|
178
|
+
</template>
|
|
179
|
+
|
|
180
|
+
<style lang="scss" scoped>
|
|
181
|
+
</style>
|