Skip to content

Commit dd578a4

Browse files
committed
feat(feed-settings): polish multi-select header actions and bulk move UX
show selected feed count and batch actions inside table header when selection is active restore normal sortable headers when no feeds are selected reuse existing MoveFeed dialog for moving selected feeds (remove inline batch folder field) prevent modal/table width jumps when toggling selection mode stabilize table layout to reduce content reflow noise add indeterminate ("-") state for partially selected select-all checkbox keep checkbox cursor as pointer in all interactive states Signed-off-by: Benjamin Brahmer <info@b-brahmer.de>
1 parent d18dd82 commit dd578a4

2 files changed

Lines changed: 231 additions & 85 deletions

File tree

src/components/MoveFeed.vue

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<NcDialog
3-
:name="t('news', 'Move feed')"
3+
:name="dialogTitle"
44
size="small"
55
@close="$emit('close')">
66
<template #default>
@@ -18,7 +18,7 @@
1818
<NcButton
1919
:wide="true"
2020
variant="primary"
21-
:disabled="disableMoveFeed"
21+
:disabled="disableMoveFeed || moving"
2222
@click="moveFeed()">
2323
{{ t("news", "Move") }}
2424
</NcButton>
@@ -39,6 +39,7 @@ import { ACTIONS } from '../store/index.ts'
3939
4040
type MoveFeedState = {
4141
folder?: Folder
42+
moving: boolean
4243
}
4344
4445
export default defineComponent({
@@ -59,6 +60,12 @@ export default defineComponent({
5960
return { url: '' }
6061
},
6162
},
63+
64+
feeds: {
65+
type: Array,
66+
required: false,
67+
default: () => [],
68+
},
6269
},
6370
6471
emits: {
@@ -68,6 +75,7 @@ export default defineComponent({
6875
data: (): MoveFeedState => {
6976
return {
7077
folder: null,
78+
moving: false,
7179
}
7280
},
7381
@@ -76,7 +84,18 @@ export default defineComponent({
7684
return this.$store.state.folders.folders
7785
},
7886
87+
dialogTitle(): string {
88+
return this.isBatchMove ? t('news', 'Move feeds') : t('news', 'Move feed')
89+
},
90+
91+
isBatchMove(): boolean {
92+
return Array.isArray(this.feeds) && this.feeds.length > 0
93+
},
94+
7995
disableMoveFeed(): boolean {
96+
if (this.isBatchMove) {
97+
return false
98+
}
8099
return (this.folder && this.folder.id === this.feed.folderId)
81100
},
82101
},
@@ -86,11 +105,47 @@ export default defineComponent({
86105
* Move a Feed via the Vuex Store
87106
*/
88107
async moveFeed() {
108+
this.moving = true
109+
const folderId = this.folder ? this.folder.id : 0
110+
111+
if (this.isBatchMove) {
112+
let failedMoves = 0
113+
const feedsToMove = this.feeds.filter((feed) => (typeof feed.folderId === 'number' ? feed.folderId : 0) !== folderId)
114+
try {
115+
for (const feed of feedsToMove) {
116+
try {
117+
const response = await this.$store.dispatch(ACTIONS.MOVE_FEED, { feedId: feed.id, folderId })
118+
if (!response?.status || response.status < 200 || response.status >= 300) {
119+
failedMoves++
120+
}
121+
} catch {
122+
failedMoves++
123+
}
124+
}
125+
await this.$store.dispatch(ACTIONS.FETCH_FEEDS)
126+
} finally {
127+
this.moving = false
128+
}
129+
130+
if (failedMoves > 0) {
131+
showError(t('news', 'Some selected feeds could not be moved. Please try again later or check your connection.'))
132+
return
133+
}
134+
135+
this.$emit('close')
136+
return
137+
}
138+
89139
const data = {
90140
feedId: this.feed.id,
91-
folderId: this.folder ? this.folder.id : 0,
141+
folderId,
142+
}
143+
let response
144+
try {
145+
response = await this.$store.dispatch(ACTIONS.MOVE_FEED, data)
146+
} finally {
147+
this.moving = false
92148
}
93-
const response = await this.$store.dispatch(ACTIONS.MOVE_FEED, data)
94149
if (!response?.status || response.status < 200 || response.status >= 300) {
95150
showError(t('news', 'Unable to move feed. Please try again later or check your connection.'))
96151
return

0 commit comments

Comments
 (0)