diff --git a/locales/en-US.yml b/locales/en-US.yml index 948934d817..adc5012119 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -738,6 +738,7 @@ jumpToSpecifiedDate: "Jump to specific date" showingPastTimeline: "Currently displaying an old timeline" clear: "Return" markAllAsRead: "Mark all as read" +failedToMarkAsRead: "Failed to mark all as read" goBack: "Back" unlikeConfirm: "Really remove your like?" fullView: "Full view" diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 912998376f..c091010993 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -67,6 +67,7 @@ import * as ep___announcements from './endpoints/announcements.js'; import * as ep___antennas_create from './endpoints/antennas/create.js'; import * as ep___antennas_delete from './endpoints/antennas/delete.js'; import * as ep___antennas_list from './endpoints/antennas/list.js'; +import * as ep___antennas_markRead from './endpoints/antennas/markread.js'; import * as ep___antennas_notes from './endpoints/antennas/notes.js'; import * as ep___antennas_show from './endpoints/antennas/show.js'; import * as ep___antennas_update from './endpoints/antennas/update.js'; @@ -397,6 +398,7 @@ const eps = [ ['antennas/create', ep___antennas_create], ['antennas/delete', ep___antennas_delete], ['antennas/list', ep___antennas_list], + ['antennas/mark-read', ep___antennas_markRead], ['antennas/notes', ep___antennas_notes], ['antennas/show', ep___antennas_show], ['antennas/update', ep___antennas_update], diff --git a/packages/client/src/components/MkPagination.vue b/packages/client/src/components/MkPagination.vue index 8e1d2231bf..9f1fad38e3 100644 --- a/packages/client/src/components/MkPagination.vue +++ b/packages/client/src/components/MkPagination.vue @@ -124,6 +124,35 @@ const reload = (): void => { init(); }; +const refresh = async (): void => { + const params = props.pagination.params ? isRef(props.pagination.params) ? props.pagination.params.value : props.pagination.params : {}; + await os.api(props.pagination.endpoint, { + ...params, + limit: items.value.length + 1, + offset: 0, + }).then(res => { + let ids = items.value.reduce((a, b) => { + a[b.id] = true; + return a; + }, {} as { [id: string]: boolean; }); + + for (let i = 0; i < res.length; i++) { + const item = res[i]; + if (!updateItem(item.id, old => item)) { + append(item); + } + delete ids[item.id]; + } + + for (const id in ids) { + removeItem(i => i.id === id); + } + }, err => { + error.value = true; + fetching.value = false; + }); +}; + const fetchMore = async (): Promise => { if (!more.value || fetching.value || moreFetching.value || items.value.length === 0) return; moreFetching.value = true; @@ -257,14 +286,24 @@ const append = (item: Item): void => { items.value.push(item); }; -const removeItem = (finder: (item: Item) => boolean): void => { +const removeItem = (finder: (item: Item) => boolean): boolean => { const i = items.value.findIndex(finder); + if (i === -1) { + return false; + } + items.value.splice(i, 1); + return true; }; -const updateItem = (id: Item['id'], replacer: (old: Item) => Item): void => { +const updateItem = (id: Item['id'], replacer: (old: Item) => Item): boolean => { const i = items.value.findIndex(item => item.id === id); + if (i === -1) { + return false; + } + items.value[i] = replacer(items.value[i]); + return true; }; if (props.pagination.params && isRef(props.pagination.params)) { @@ -291,6 +330,7 @@ defineExpose({ queue, backed, reload, + refresh, prepend, append, removeItem, diff --git a/packages/client/src/pages/antenna-timeline.vue b/packages/client/src/pages/antenna-timeline.vue index 348512ea72..0b35a3f45d 100644 --- a/packages/client/src/pages/antenna-timeline.vue +++ b/packages/client/src/pages/antenna-timeline.vue @@ -61,6 +61,23 @@ function settings() { router.push(`/my/antennas/${props.antennaId}`); } +async function doMarkRead() { + const ret = await os.api('antennas/mark-read', { + antennaId: props.antennaId, + }); + + if (ret) { + return true + } + + throw new Error(i18n.ts.failedToMarkAsRead); +} + +async function markRead() { + await os.promiseDialog(doMarkRead()); + router.push(`/my/antennas`); +} + function focus() { tlEl.focus(); } @@ -79,6 +96,10 @@ const headerActions = $computed(() => antenna ? [{ icon: 'ph-gear-six-bold ph-lg', text: i18n.ts.settings, handler: settings, +}, { + icon: 'ph-checks-bold ph-lg', + text: i18n.ts.markAllAsRead, + handler: markRead, }] : []); const headerTabs = $computed(() => []); diff --git a/packages/client/src/pages/my-antennas/index.vue b/packages/client/src/pages/my-antennas/index.vue index 69534a1636..44897c9e21 100644 --- a/packages/client/src/pages/my-antennas/index.vue +++ b/packages/client/src/pages/my-antennas/index.vue @@ -7,9 +7,14 @@
- -
{{ antenna.name }}
-
+
+ + + + +
{{ antenna.name }}
+
+
@@ -18,7 +23,7 @@