🐛 Fixing pagination for "Shared with me"/ES (#778)
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types */
|
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
import { SearchDocumentsOptions } from "src/services/documents/types";
|
||||||
import { TdriveServiceProvider } from "../../framework";
|
import { TdriveServiceProvider } from "../../framework";
|
||||||
import { ListResult } from "../../framework/api/crud-service";
|
import { ListResult } from "../../framework/api/crud-service";
|
||||||
import {
|
import {
|
||||||
@@ -62,6 +63,7 @@ export interface SearchServiceAPI extends TdriveServiceProvider {
|
|||||||
getRepository<Entity>(table: string, entityType: EntityTarget<Entity>): SearchRepository<Entity>;
|
getRepository<Entity>(table: string, entityType: EntityTarget<Entity>): SearchRepository<Entity>;
|
||||||
upsert(entities: any[]): Promise<void>;
|
upsert(entities: any[]): Promise<void>;
|
||||||
remove(entities: any[]): Promise<void>;
|
remove(entities: any[]): Promise<void>;
|
||||||
|
handlePagination(options: SearchDocumentsOptions): void;
|
||||||
type: SearchConfiguration["type"];
|
type: SearchConfiguration["type"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { DatabaseServiceAPI } from "../database/api";
|
|||||||
import SearchRepository from "./repository";
|
import SearchRepository from "./repository";
|
||||||
import { Client as OpenClient } from "@opensearch-project/opensearch";
|
import { Client as OpenClient } from "@opensearch-project/opensearch";
|
||||||
import { Client as ESClient } from "@elastic/elasticsearch";
|
import { Client as ESClient } from "@elastic/elasticsearch";
|
||||||
|
import { SearchDocumentsOptions } from "src/services/documents/types";
|
||||||
|
|
||||||
@ServiceName("search")
|
@ServiceName("search")
|
||||||
@Consumes(["database"])
|
@Consumes(["database"])
|
||||||
@@ -96,4 +97,30 @@ export default class Search extends TdriveService<SearchServiceAPI> {
|
|||||||
api(): SearchServiceAPI {
|
api(): SearchServiceAPI {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handlePagination(options: SearchDocumentsOptions): void {
|
||||||
|
if (this.type === "mongodb") {
|
||||||
|
// No custom pagination logic for MongoDB
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.type === "elasticsearch" || this.type === "opensearch") {
|
||||||
|
if (options.nextPage?.page_token) {
|
||||||
|
// Set the scroll ID as the page token
|
||||||
|
options.pagination = {
|
||||||
|
...options.pagination,
|
||||||
|
page_token: options.nextPage.page_token,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// Clear pagination if no nextPage token is provided
|
||||||
|
options.pagination = {
|
||||||
|
limitStr: options.pagination?.limitStr,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle unsupported platform types
|
||||||
|
throw new Error(`Pagination handling is not implemented for platform type: ${this.type}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,6 +133,9 @@ export class DocumentsService {
|
|||||||
options.sort = this.getSortFieldMapping(options.sort);
|
options.sort = this.getSortFieldMapping(options.sort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle pagination differently for non-MongoDB platforms
|
||||||
|
globalResolver.platformServices.search.handlePagination(options);
|
||||||
|
|
||||||
const fileList: ListResult<DriveFile> = await this.search(options, context);
|
const fileList: ListResult<DriveFile> = await this.search(options, context);
|
||||||
const result = fileList.getEntities();
|
const result = fileList.getEntities();
|
||||||
|
|
||||||
|
|||||||
@@ -57,12 +57,18 @@ export type SearchDocumentsOptions = {
|
|||||||
onlyDirectlyShared?: boolean;
|
onlyDirectlyShared?: boolean;
|
||||||
onlyUploadedNotByMe?: boolean;
|
onlyUploadedNotByMe?: boolean;
|
||||||
pagination?: Paginable;
|
pagination?: Paginable;
|
||||||
|
nextPage?: {
|
||||||
|
page_token: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type BrowseDocumentsOptions = {
|
export type BrowseDocumentsOptions = {
|
||||||
filter?: SearchDocumentsBody;
|
filter?: SearchDocumentsBody;
|
||||||
sort?: SortType;
|
sort?: SortType;
|
||||||
paginate?: Paginable;
|
paginate?: Paginable;
|
||||||
|
nextPage?: {
|
||||||
|
page_token: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SearchDocumentsBody = {
|
export type SearchDocumentsBody = {
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ export class DocumentsController {
|
|||||||
onlyUploadedNotByMe: true,
|
onlyUploadedNotByMe: true,
|
||||||
sort: request.body.sort,
|
sort: request.body.sort,
|
||||||
pagination: request.body.paginate,
|
pagination: request.body.paginate,
|
||||||
|
nextPage: request.body.nextPage,
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -70,7 +70,13 @@ export class DriveApiClient {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async browse(companyId: string, id: string | 'trash' | '', filter: BrowseFilter, sort: BrowseSort, paginate: BrowsePaginate) {
|
static async browse(
|
||||||
|
companyId: string,
|
||||||
|
id: string | 'trash' | '',
|
||||||
|
filter: BrowseFilter,
|
||||||
|
sort: BrowseSort,
|
||||||
|
paginate: BrowsePaginate,
|
||||||
|
) {
|
||||||
return await Api.post<BrowseQuery, DriveItemDetails>(
|
return await Api.post<BrowseQuery, DriveItemDetails>(
|
||||||
`/internal/services/documents/v1/companies/${companyId}/browse/${id}${appendTdriveToken()}`,
|
`/internal/services/documents/v1/companies/${companyId}/browse/${id}${appendTdriveToken()}`,
|
||||||
{
|
{
|
||||||
@@ -79,7 +85,10 @@ export class DriveApiClient {
|
|||||||
paginate: {
|
paginate: {
|
||||||
page_token: paginate.page.toString(),
|
page_token: paginate.page.toString(),
|
||||||
limitStr: paginate.limit.toString(),
|
limitStr: paginate.limit.toString(),
|
||||||
}
|
},
|
||||||
|
nextPage: {
|
||||||
|
page_token: paginate.nextPage?.page_token || '',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -93,7 +102,7 @@ export class DriveApiClient {
|
|||||||
static async restore(companyId: string, id: string | 'trash' | '') {
|
static async restore(companyId: string, id: string | 'trash' | '') {
|
||||||
return await Api.post<any, any>(
|
return await Api.post<any, any>(
|
||||||
`/internal/services/documents/v1/companies/${companyId}/item/${id}/restore${appendTdriveToken()}`,
|
`/internal/services/documents/v1/companies/${companyId}/item/${id}/restore${appendTdriveToken()}`,
|
||||||
{}
|
{},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,13 +120,10 @@ export class DriveApiClient {
|
|||||||
if (!data.version) data.version = {} as Partial<DriveItemVersion>;
|
if (!data.version) data.version = {} as Partial<DriveItemVersion>;
|
||||||
|
|
||||||
return new Promise<DriveItem>((resolve, reject) => {
|
return new Promise<DriveItem>((resolve, reject) => {
|
||||||
Api.post<
|
Api.post<{ item: Partial<DriveItem>; version: Partial<DriveItemVersion> }, DriveItem>(
|
||||||
{ item: Partial<DriveItem>; version: Partial<DriveItemVersion> },
|
|
||||||
DriveItem
|
|
||||||
>(
|
|
||||||
`/internal/services/documents/v1/companies/${companyId}/item${appendTdriveToken()}`,
|
`/internal/services/documents/v1/companies/${companyId}/item${appendTdriveToken()}`,
|
||||||
data as { item: Partial<DriveItem>; version: Partial<DriveItemVersion> },
|
data as { item: Partial<DriveItem>; version: Partial<DriveItemVersion> },
|
||||||
(res) => {
|
res => {
|
||||||
if ((res as any)?.statusCode || (res as any)?.error) {
|
if ((res as any)?.statusCode || (res as any)?.error) {
|
||||||
reject(res);
|
reject(res);
|
||||||
}
|
}
|
||||||
@@ -151,7 +157,9 @@ export class DriveApiClient {
|
|||||||
|
|
||||||
static getDownloadUrl(companyId: string, id: string, versionId?: string) {
|
static getDownloadUrl(companyId: string, id: string, versionId?: string) {
|
||||||
if (versionId)
|
if (versionId)
|
||||||
return Api.route(`/internal/services/documents/v1/companies/${companyId}/item/${id}/download?version_id=${versionId}`);
|
return Api.route(
|
||||||
|
`/internal/services/documents/v1/companies/${companyId}/item/${id}/download?version_id=${versionId}`,
|
||||||
|
);
|
||||||
return Api.route(`/internal/services/documents/v1/companies/${companyId}/item/${id}/download`);
|
return Api.route(`/internal/services/documents/v1/companies/${companyId}/item/${id}/download`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
DriveItemPagination,
|
DriveItemPagination,
|
||||||
DriveItemSort,
|
DriveItemSort,
|
||||||
} from '../state/store';
|
} from '../state/store';
|
||||||
import { BrowseFilter, DriveItem, DriveItemVersion } from '../types';
|
import { BrowseFilter, DriveItem, DriveItemDetails, DriveItemVersion } from '../types';
|
||||||
import { SharedWithMeFilterState } from '../state/shared-with-me-filter';
|
import { SharedWithMeFilterState } from '../state/shared-with-me-filter';
|
||||||
import Languages from 'features/global/services/languages-service';
|
import Languages from 'features/global/services/languages-service';
|
||||||
import { useUserQuota } from 'features/users/hooks/use-user-quota';
|
import { useUserQuota } from 'features/users/hooks/use-user-quota';
|
||||||
@@ -70,11 +70,12 @@ export const useDriveActions = (inPublicSharing?: boolean) => {
|
|||||||
let pagination = await snapshot.getPromise(DriveItemPagination);
|
let pagination = await snapshot.getPromise(DriveItemPagination);
|
||||||
|
|
||||||
if (resetPagination) {
|
if (resetPagination) {
|
||||||
pagination = { page: 0, limit: pagination.limit };
|
pagination = { page: 0, limit: pagination.limit, nextPage: pagination.nextPage };
|
||||||
set(DriveItemPagination, pagination);
|
set(DriveItemPagination, pagination);
|
||||||
}
|
}
|
||||||
|
let details: DriveItemDetails | undefined;
|
||||||
try {
|
try {
|
||||||
const details = await DriveApiClient.browse(
|
details = await DriveApiClient.browse(
|
||||||
companyId,
|
companyId,
|
||||||
parentId,
|
parentId,
|
||||||
filter,
|
filter,
|
||||||
@@ -94,7 +95,13 @@ export const useDriveActions = (inPublicSharing?: boolean) => {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
ToasterService.error(Languages.t('hooks.use-drive-actions.unable_load_file'));
|
ToasterService.error(Languages.t('hooks.use-drive-actions.unable_load_file'));
|
||||||
} finally {
|
} finally {
|
||||||
set(DriveItemPagination, { page: pagination.limit, limit: pagination.limit });
|
set(DriveItemPagination, {
|
||||||
|
page: pagination.limit,
|
||||||
|
limit: pagination.limit,
|
||||||
|
nextPage: {
|
||||||
|
page_token: details?.nextPage?.page_token || '',
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ export const DriveItemAtom = atomFamily<Partial<DriveItemDetails> | null, string
|
|||||||
default: () => null,
|
default: () => null,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const DriveItemSelectedList = atom<{[key: string]: boolean }>({
|
export const DriveItemSelectedList = atom<{ [key: string]: boolean }>({
|
||||||
key: 'DriveItemSelectedList',
|
key: 'DriveItemSelectedList',
|
||||||
default: {}
|
default: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const DriveItemSort = atom<BrowseSort>({
|
export const DriveItemSort = atom<BrowseSort>({
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ export type BrowseQuery = {
|
|||||||
page_token: string;
|
page_token: string;
|
||||||
limitStr: string;
|
limitStr: string;
|
||||||
};
|
};
|
||||||
|
nextPage?: {
|
||||||
|
page_token: string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BrowseFilter = {
|
export type BrowseFilter = {
|
||||||
@@ -21,6 +24,9 @@ export type BrowsePaginate = {
|
|||||||
page: number;
|
page: number;
|
||||||
limit: number;
|
limit: number;
|
||||||
lastPage?: boolean;
|
lastPage?: boolean;
|
||||||
|
nextPage?: {
|
||||||
|
page_token: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DriveItemDetails = {
|
export type DriveItemDetails = {
|
||||||
@@ -33,6 +39,9 @@ export type DriveItemDetails = {
|
|||||||
room: string;
|
room: string;
|
||||||
token?: string;
|
token?: string;
|
||||||
}[];
|
}[];
|
||||||
|
nextPage?: {
|
||||||
|
page_token: string;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DriveItem = {
|
export type DriveItem = {
|
||||||
|
|||||||
@@ -137,7 +137,6 @@ export default memo(
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setChecked({});
|
setChecked({});
|
||||||
refresh(parentId);
|
refresh(parentId);
|
||||||
if (!inPublicSharing) refresh('trash');
|
|
||||||
}, [parentId, refresh, filter]);
|
}, [parentId, refresh, filter]);
|
||||||
|
|
||||||
const uploadItemModal = useCallback(() => {
|
const uploadItemModal = useCallback(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user