Skip to content

Commit fc9ed33

Browse files
committed
Perf: Optimize trashed pages
Signed-off-by: Kostiantyn Miakshyn <molodchick@gmail.com>
1 parent caca2ee commit fc9ed33

File tree

4 files changed

+70
-11
lines changed

4 files changed

+70
-11
lines changed

lib/Db/PageMapper.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,36 @@ public function findByFileId(int $fileId, bool $trashed = false): ?Page {
8080
}
8181
}
8282

83+
/**
84+
* @param int[] $fileIds
85+
* @return array<int, Page> Indexed by file_id
86+
*/
87+
public function findByFileIds(array $fileIds, bool $trashed = false): array {
88+
if (empty($fileIds)) {
89+
return [];
90+
}
91+
92+
$qb = $this->db->getQueryBuilder();
93+
$qb->select('*')
94+
->from($this->tableName)
95+
->where($qb->expr()->in('file_id',
96+
$qb->createNamedParameter($fileIds, IQueryBuilder::PARAM_INT_ARRAY)));
97+
98+
if ($trashed) {
99+
$qb->andWhere($qb->expr()->isNotNull('trash_timestamp'));
100+
} else {
101+
$qb->andWhere($qb->expr()->isNull('trash_timestamp'));
102+
}
103+
104+
$pages = $this->findEntities($qb);
105+
$pagesByFileId = [];
106+
foreach ($pages as $page) {
107+
$pagesByFileId[$page->getFileId()] = $page;
108+
}
109+
110+
return $pagesByFileId;
111+
}
112+
83113
/**
84114
* @return Page[]
85115
*/

lib/Service/PageService.php

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -245,12 +245,7 @@ private function getPageByFile(File $file, ?Node $parent = null): PageInfo {
245245
/**
246246
* @throws NotFoundException
247247
*/
248-
private function getTrashPageByFile(File $file, string $filename, string $timestamp): PageInfo {
249-
try {
250-
$page = $this->pageMapper->findByFileId($file->getId(), true);
251-
} catch (InvalidPathException|FilesNotFoundException $e) {
252-
throw new NotFoundException($e->getMessage(), 0, $e);
253-
}
248+
private function createTrashPageInfo(File $file, string $filename, string $timestamp, ?Page $page): PageInfo {
254249
$lastUserId = ($page !== null) ? $page->getLastUserId() : null;
255250
$emoji = ($page !== null) ? $page->getEmoji() : null;
256251
$subpageOrder = ($page !== null) ? $page->getSubpageOrder() : null;
@@ -550,7 +545,9 @@ public function findAllTrash(int $collectiveId, string $userId): array {
550545
}
551546

552547
$trashNodes = $this->trashBackend->listTrashForCollective($this->userManager->get($userId), $collectiveId);
553-
$trashPageInfos = [];
548+
549+
// Collect file data and file IDs
550+
$fileData = [];
554551
foreach ($trashNodes as $node) {
555552
$pathParts = pathInfo($node->getName());
556553
$filename = $pathParts['filename'];
@@ -570,7 +567,29 @@ public function findAllTrash(int $collectiveId, string $userId): array {
570567
continue;
571568
}
572569

573-
$trashPageInfos[] = $this->getTrashPageByFile($node, $filename, $timestamp);
570+
$fileData[$node->getId()] = [
571+
'node' => $node,
572+
'filename' => $filename,
573+
'timestamp' => $timestamp
574+
];
575+
}
576+
577+
// Single query to get all pages by file IDs
578+
$pagesByFileId = $this->pageMapper->findByFileIds(array_keys($fileData), true);
579+
580+
// Create trash page infos using the pre-loaded pages
581+
$trashPageInfos = [];
582+
foreach ($fileData as $fileId => $data) {
583+
if (!isset($pagesByFileId[$fileId])) {
584+
continue;
585+
}
586+
587+
$trashPageInfos[] = $this->createTrashPageInfo(
588+
$data['node'],
589+
$data['filename'],
590+
$data['timestamp'],
591+
$pagesByFileId[$fileId],
592+
);
574593
}
575594

576595
return $trashPageInfos;

src/components/PageList/PageTrash.vue

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,13 @@
2222
class="dialog__page-trash"
2323
size="large">
2424
<div class="modal__content">
25+
<NcEmptyContent v-if="loading('pageTrash')" :name="t('collectives', 'Loading…')">
26+
<template #icon>
27+
<NcLoadingIcon />
28+
</template>
29+
</NcEmptyContent>
2530
<NcEmptyContent
26-
v-if="!sortedTrashPages.length"
31+
v-else-if="!sortedTrashPages.length"
2732
class="modal__content_empty"
2833
:description="t('collectives', 'No deleted pages.')">
2934
<template #icon>
@@ -104,10 +109,12 @@ import NcActions from '@nextcloud/vue/components/NcActions'
104109
import NcButton from '@nextcloud/vue/components/NcButton'
105110
import NcDialog from '@nextcloud/vue/components/NcDialog'
106111
import NcEmptyContent from '@nextcloud/vue/components/NcEmptyContent'
112+
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'
107113
import RestoreIcon from 'vue-material-design-icons/Restore.vue'
108114
import DeleteIcon from 'vue-material-design-icons/TrashCanOutline.vue'
109115
import PageIcon from '../Icon/PageIcon.vue'
110116
import { usePagesStore } from '../../stores/pages.js'
117+
import { useRootStore } from '../../stores/root.js'
111118
import { scrollToPage } from '../../util/scrollToElement.js'
112119
113120
export default {
@@ -119,6 +126,7 @@ export default {
119126
NcButton,
120127
NcDialog,
121128
NcEmptyContent,
129+
NcLoadingIcon,
122130
DeleteIcon,
123131
RestoreIcon,
124132
PageIcon,
@@ -144,6 +152,7 @@ export default {
144152
145153
computed: {
146154
...mapState(usePagesStore, ['sortedTrashPages']),
155+
...mapState(useRootStore, ['loading']),
147156
148157
titleDate() {
149158
return (timestamp) => {
@@ -175,11 +184,13 @@ export default {
175184
'deletePage',
176185
'expandParents',
177186
'restorePage',
187+
'getTrashPages',
178188
'setHighlightAnimationPageId',
179189
]),
180190
181191
openTrash() {
182192
this.showModal = true
193+
this.getTrashPages()
183194
},
184195
185196
onClickRestore(trashPage) {

src/views/CollectiveView.vue

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ export default {
126126
...mapActions(useSessionsStore, ['createSession', 'updateSession', 'closeSession']),
127127
...mapActions(useTagsStore, ['getTags']),
128128
...mapActions(useTemplatesStore, ['getTemplates']),
129-
...mapActions(usePagesStore, ['getPages', 'getTrashPages']),
129+
...mapActions(usePagesStore, ['getPages']),
130130
131131
initSession() {
132132
if (this.listenPush) {
@@ -217,7 +217,6 @@ export default {
217217
if (this.currentCollectiveCanEdit) {
218218
if (!this.currentCollectiveIsPageShare) {
219219
promises.push(this.getTemplates(setLoading))
220-
promises.push(this.getTrashPages())
221220
}
222221
}
223222

0 commit comments

Comments
 (0)