Skip to content

Commit ec8b341

Browse files
groluholgerkoserpetersutter
authored
Move GShootListRowActions from GShootListRow to GShootList component (#2148)
* Move GShootListRowActions from GShootListRow to GShootList component * Use shared composable instead of event propagation to distribute state (#2155) * Uniform handling of action and menu events on ShootList * fixed lint errors * Added License * Improved `useShootAction` composable * License header format * Do not unset shootItem when menu closes * Update frontend/src/components/GShootListActions.vue Co-authored-by: Peter Sutter <[email protected]> --------- Co-authored-by: Peter Sutter <[email protected]> * Update frontend/src/views/GShootList.vue Co-authored-by: Peter Sutter <[email protected]> --------- Co-authored-by: Holger Koser <[email protected]> Co-authored-by: Peter Sutter <[email protected]>
1 parent 218d7ea commit ec8b341

File tree

4 files changed

+141
-87
lines changed

4 files changed

+141
-87
lines changed

frontend/src/components/GShootListRowActions.vue renamed to frontend/src/components/GShootListActions.vue

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,45 @@ SPDX-License-Identifier: Apache-2.0
55
-->
66

77
<template>
8+
<v-dialog
9+
v-if="!!shootUid"
10+
v-model="accessDialog"
11+
persistent
12+
max-width="850"
13+
>
14+
<v-card>
15+
<g-toolbar>
16+
Cluster Access
17+
<code class="text-toolbar-title">
18+
{{ shootName }}
19+
</code>
20+
<template #append>
21+
<v-btn
22+
variant="text"
23+
density="comfortable"
24+
icon="mdi-close"
25+
color="toolbar-title"
26+
@click="accessDialog = false"
27+
/>
28+
</template>
29+
</g-toolbar>
30+
<g-shoot-access-card
31+
ref="clusterAccess"
32+
:selected-shoot="shootActionItem"
33+
:hide-terminal-shortcuts="true"
34+
/>
35+
</v-card>
36+
</v-dialog>
837
<v-menu
9-
v-model="menu"
38+
v-model="actionMenu"
1039
location="left"
1140
:close-on-content-click="false"
1241
eager
42+
:target="shootActionTarget"
1343
>
14-
<template #activator="{ props }">
15-
<g-action-button
16-
v-bind="props"
17-
icon="mdi-dots-vertical"
18-
tooltip="Cluster Actions"
19-
/>
20-
</template>
2144
<v-list
2245
dense
23-
@click.capture="menu = false"
46+
@click.capture="actionMenu = false"
2447
>
2548
<v-list-item>
2649
<g-shoot-action-change-hibernation
@@ -39,7 +62,7 @@ SPDX-License-Identifier: Apache-2.0
3962
</v-list-item>
4063
<v-list-item>
4164
<g-shoot-action-rotate-credentials
42-
:type="rotationType"
65+
type="ALL_CREDENTIALS"
4366
text
4467
/>
4568
</v-list-item>
@@ -64,9 +87,9 @@ SPDX-License-Identifier: Apache-2.0
6487
</template>
6588

6689
<script setup>
67-
import { ref } from 'vue'
90+
import { watch } from 'vue'
6891
69-
import GActionButton from '@/components/GActionButton.vue'
92+
import GShootAccessCard from '@/components/ShootDetails/GShootAccessCard.vue'
7093
import GShootActionChangeHibernation from '@/components/ShootHibernation/GShootActionChangeHibernation.vue'
7194
import GShootActionMaintenanceStart from '@/components/ShootMaintenance/GShootActionMaintenanceStart.vue'
7295
import GShootActionReconcileStart from '@/components/GShootActionReconcileStart.vue'
@@ -75,13 +98,28 @@ import GShootActionDeleteCluster from '@/components/GShootActionDeleteCluster.vu
7598
import GShootActionForceDelete from '@/components/GShootActionForceDelete.vue'
7699
import GShootVersionConfiguration from '@/components/ShootVersion/GShootVersionConfiguration.vue'
77100
78-
import { useShootItem } from '@/composables/useShootItem'
101+
import { useProvideShootItem } from '@/composables/useShootItem'
102+
import { useShootAction } from '@/composables/useShootAction'
103+
104+
const {
105+
shootActionItem,
106+
shootActionTarget,
107+
createShootActionFlag,
108+
unsetShootAction,
109+
} = useShootAction()
79110
80111
const {
112+
shootName,
113+
shootUid,
81114
canForceDeleteShoot,
82-
} = useShootItem()
115+
} = useProvideShootItem(shootActionItem)
83116
84-
const menu = ref(false)
117+
const accessDialog = createShootActionFlag('access')
118+
const actionMenu = createShootActionFlag('menu')
85119
86-
const rotationType = ref('ALL_CREDENTIALS')
120+
watch(accessDialog, value => {
121+
if (!value) {
122+
unsetShootAction()
123+
}
124+
})
87125
</script>

frontend/src/components/GShootListRow.vue

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,13 @@ SPDX-License-Identifier: Apache-2.0
202202
icon="mdi-key"
203203
:disabled="isClusterAccessDialogDisabled"
204204
:tooltip="showClusterAccessActionTitle"
205-
@click="showDialog('access')"
205+
@click="setShootAction('access', shootItem)"
206206
/>
207-
<g-shoot-list-row-actions
207+
<g-action-button
208208
v-if="canPatchShoots"
209+
icon="mdi-dots-vertical"
210+
tooltip="Cluster Actions"
211+
@click="setShootAction('menu', shootItem, $event.target)"
209212
/>
210213
</v-row>
211214
</template>
@@ -255,14 +258,14 @@ import GShootVersionChip from '@/components/ShootVersion/GShootVersionChip.vue'
255258
import GTicketLabel from '@/components/ShootTickets/GTicketLabel.vue'
256259
import GShootSeedName from '@/components/GShootSeedName.vue'
257260
import GShootMessages from '@/components/ShootMessages/GShootMessages.vue'
258-
import GShootListRowActions from '@/components/GShootListRowActions.vue'
259261
import GAutoHide from '@/components/GAutoHide.vue'
260262
import GExternalLink from '@/components/GExternalLink.vue'
261263
import GControlPlaneHighAvailabilityTag from '@/components/ControlPlaneHighAvailability/GControlPlaneHighAvailabilityTag.vue'
262264
import GWorkerGroup from '@/components/ShootWorkers/GWorkerGroup'
263265
import GTextRouterLink from '@/components/GTextRouterLink.vue'
264266
import GCollapsibleItems from '@/components/GCollapsibleItems'
265267
268+
import { useShootAction } from '@/composables/useShootAction'
266269
import { useProvideShootItem } from '@/composables/useShootItem'
267270
import { useProvideShootHelper } from '@/composables/useShootHelper'
268271
import { formatValue } from '@/composables/useProjectShootCustomFields/helper'
@@ -289,9 +292,7 @@ const props = defineProps({
289292
})
290293
const shootItem = toRef(props, 'modelValue')
291294
292-
const emit = defineEmits([
293-
'showDialog',
294-
])
295+
const { setShootAction } = useShootAction()
295296
296297
const shootStore = useShootStore()
297298
const ticketStore = useTicketStore()
@@ -426,13 +427,6 @@ const cells = computed(() => {
426427
})
427428
})
428429
429-
function showDialog (action) {
430-
emit('showDialog', {
431-
action,
432-
shootItem: shootItem.value,
433-
})
434-
}
435-
436430
const hasShootWorkerGroupWarning = computed(() => {
437431
const machineImages = cloudProfileStore.machineImagesByCloudProfileName(shootCloudProfileName.value)
438432
return some(shootWorkerGroups.value, workerGroup => {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//
2+
// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
3+
//
4+
// SPDX-License-Identifier: Apache-2.0
5+
//
6+
7+
import {
8+
reactive,
9+
computed,
10+
toRef,
11+
inject,
12+
provide,
13+
} from 'vue'
14+
15+
import { useShootStore } from '@/store/shoot'
16+
17+
import { get } from '@/lodash'
18+
19+
export function createShootActionEventComposable (options = {}) {
20+
const {
21+
shootStore = useShootStore(),
22+
} = options
23+
24+
const state = reactive({
25+
name: '',
26+
target: null,
27+
})
28+
29+
const shootActionItem = toRef(shootStore, 'selectedShoot')
30+
const shootActionTarget = computed(() => state.target)
31+
32+
function setShootAction (name, shootItem, target = null) {
33+
const metadata = get(shootItem, ['metadata'], null)
34+
shootStore.setSelection(metadata)
35+
state.name = name
36+
state.target = target
37+
}
38+
39+
function unsetShootAction () {
40+
setShootAction('', null, null)
41+
}
42+
43+
function createShootActionFlag (name) {
44+
return computed({
45+
get () {
46+
return state.name === name
47+
},
48+
set (value) {
49+
if (!value) {
50+
state.name = ''
51+
}
52+
},
53+
})
54+
}
55+
56+
return {
57+
shootActionItem,
58+
shootActionTarget,
59+
setShootAction,
60+
unsetShootAction,
61+
createShootActionFlag,
62+
}
63+
}
64+
65+
export function useShootAction () {
66+
return inject('shoot-action-event', null)
67+
}
68+
69+
export function useProvideShootAction (options) {
70+
const composable = createShootActionEventComposable(options)
71+
provide('shoot-action-event', composable)
72+
return composable
73+
}

frontend/src/views/GShootList.vue

Lines changed: 7 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ SPDX-License-Identifier: Apache-2.0
180180
<g-shoot-list-row
181181
:model-value="item"
182182
:visible-headers="visibleHeaders"
183-
@show-dialog="showDialog"
184183
/>
185184
</template>
186185
<template #bottom="{ pageCount }">
@@ -193,36 +192,8 @@ SPDX-License-Identifier: Apache-2.0
193192
/>
194193
</template>
195194
</v-data-table>
196-
<v-dialog
197-
v-if="!isShootItemEmpty"
198-
v-model="clusterAccessDialog"
199-
persistent
200-
max-width="850"
201-
>
202-
<v-card>
203-
<g-toolbar>
204-
Cluster Access
205-
<code class="text-toolbar-title">
206-
{{ currentName }}
207-
</code>
208-
<template #append>
209-
<v-btn
210-
variant="text"
211-
density="comfortable"
212-
icon="mdi-close"
213-
color="toolbar-title"
214-
@click.stop="hideDialog"
215-
/>
216-
</template>
217-
</g-toolbar>
218-
<g-shoot-access-card
219-
ref="clusterAccess"
220-
:selected-shoot="shootItem"
221-
:hide-terminal-shortcuts="true"
222-
/>
223-
</v-card>
224-
</v-dialog>
225195
</v-card>
196+
<g-shoot-list-actions />
226197
</v-container>
227198
</template>
228199

@@ -256,10 +227,11 @@ import GTableColumnSelection from '@/components/GTableColumnSelection.vue'
256227
import GIconBase from '@/components/icons/GIconBase.vue'
257228
import GCertifiedKubernetes from '@/components/icons/GCertifiedKubernetes.vue'
258229
import GDataTableFooter from '@/components/GDataTableFooter.vue'
259-
import GShootAccessCard from '@/components/ShootDetails/GShootAccessCard.vue'
230+
import GShootListActions from '@/components/GShootListActions.vue'
260231
261232
import { useProjectShootCustomFields } from '@/composables/useProjectShootCustomFields'
262233
import { isCustomField } from '@/composables/useProjectShootCustomFields/helper'
234+
import { useProvideShootAction } from '@/composables/useShootAction'
263235
264236
import { mapTableHeader } from '@/utils'
265237
@@ -281,11 +253,11 @@ export default {
281253
GToolbar,
282254
GShootListRow,
283255
GShootListProgress,
284-
GShootAccessCard,
285256
GIconBase,
286257
GCertifiedKubernetes,
287258
GTableColumnSelection,
288259
GDataTableFooter,
260+
GShootListActions,
289261
},
290262
inject: ['logger'],
291263
beforeRouteEnter (to, from, next) {
@@ -314,6 +286,9 @@ export default {
314286
},
315287
setup () {
316288
const projectStore = useProjectStore()
289+
const shootStore = useShootStore()
290+
291+
useProvideShootAction({ shootStore })
317292
318293
const activePopoverKey = ref('')
319294
const expandedWorkerGroups = reactive({ default: false })
@@ -428,16 +403,6 @@ export default {
428403
defaultItemsPerPage () {
429404
return 10
430405
},
431-
clusterAccessDialog: {
432-
get () {
433-
return this.dialog === 'access'
434-
},
435-
set (value) {
436-
if (!value) {
437-
this.hideDialog()
438-
}
439-
},
440-
},
441406
focusModeInternal: {
442407
get () {
443408
return this.focusMode
@@ -819,29 +784,13 @@ export default {
819784
},
820785
methods: {
821786
...mapActions(useShootStore, [
822-
'setSelection',
823787
'toogleShootListFilter',
824788
'subscribeShoots',
825789
'sortItems',
826790
'searchItems',
827791
'setFocusMode',
828792
'setSortBy',
829793
]),
830-
async showDialog (args) {
831-
switch (args.action) {
832-
case 'access':
833-
try {
834-
await this.setSelection(args.shootItem.metadata)
835-
this.dialog = args.action
836-
} catch (err) {
837-
this.logger('Failed to select shoot: %s', err.message)
838-
}
839-
}
840-
},
841-
hideDialog () {
842-
this.dialog = null
843-
this.setSelection(null)
844-
},
845794
setSelectedHeader (header) {
846795
this.selectedColumns[header.key] = !header.selected
847796
this.saveSelectedColumns()

0 commit comments

Comments
 (0)