diff --git a/apps/frontend/src/lib/components/blocks/record-detail/record-detail-sheet.svelte b/apps/frontend/src/lib/components/blocks/record-detail/record-detail-sheet.svelte index f8a367f3e..9c6dd94c0 100644 --- a/apps/frontend/src/lib/components/blocks/record-detail/record-detail-sheet.svelte +++ b/apps/frontend/src/lib/components/blocks/record-detail/record-detail-sheet.svelte @@ -3,48 +3,29 @@ import Button from "$lib/components/ui/button/button.svelte" import RecordDetail from "./record-detail.svelte" import { queryParam, ssp } from "sveltekit-search-params" - import { getTable, viewId } from "$lib/store/table.store" - import { trpc } from "$lib/trpc/client" - import { createQuery, useIsMutating, useQueryClient } from "@tanstack/svelte-query" + import { getTable } from "$lib/store/table.store" + import { useIsMutating, useQueryClient } from "@tanstack/svelte-query" import { RecordDO } from "@undb/table" - import { derived } from "svelte/store" import Skeleton from "$lib/components/ui/skeleton/skeleton.svelte" import { cn } from "$lib/utils" import AuditList from "../audit/audit-list.svelte" - import { HistoryIcon, LoaderCircleIcon } from "lucide-svelte" + import { LoaderCircleIcon } from "lucide-svelte" import { preferences } from "$lib/store/persisted.store" import { ScrollArea } from "$lib/components/ui/scroll-area" export let readonly = false + export let recordDo: RecordDO | undefined + export let isLoading: boolean const r = queryParam("r", ssp.string(), { pushHistory: false }) const table = getTable() - - const record = createQuery( - derived([table, r, preferences], ([$table, $recordId, $preferences]) => ({ - queryKey: [$recordId, "get", $preferences.showHiddenFields], - queryFn: () => { - return trpc.record.get.query({ - tableId: $table?.id.value, - id: $recordId!, - select: $preferences.showHiddenFields - ? undefined - : $table?.getOrderedVisibleFields($viewId).map((f) => f.id.value), - }) - }, - enabled: !!$recordId, - })), - ) - const isUpdatingRecord = useIsMutating({ mutationKey: ["updateRecord"], }) const client = useQueryClient() - $: recordDo = $record.data?.record ? RecordDO.fromJSON($table, $record.data?.record) : undefined - let disabled = false @@ -73,7 +54,7 @@
- {#if $record.isLoading} + {#if isLoading}
diff --git a/apps/frontend/src/lib/components/blocks/record-detail/share-record-detail-sheet.svelte b/apps/frontend/src/lib/components/blocks/record-detail/share-record-detail-sheet.svelte new file mode 100644 index 000000000..4442ac7b0 --- /dev/null +++ b/apps/frontend/src/lib/components/blocks/record-detail/share-record-detail-sheet.svelte @@ -0,0 +1,34 @@ + + + diff --git a/apps/frontend/src/lib/components/blocks/record-detail/table-record-detail-sheet.svelte b/apps/frontend/src/lib/components/blocks/record-detail/table-record-detail-sheet.svelte new file mode 100644 index 000000000..8ae0633a3 --- /dev/null +++ b/apps/frontend/src/lib/components/blocks/record-detail/table-record-detail-sheet.svelte @@ -0,0 +1,36 @@ + + + diff --git a/apps/frontend/src/routes/(authed)/t/[tableId]/[[viewId]]/+page.svelte b/apps/frontend/src/routes/(authed)/t/[tableId]/[[viewId]]/+page.svelte index ee5298b2d..76befc344 100644 --- a/apps/frontend/src/routes/(authed)/t/[tableId]/[[viewId]]/+page.svelte +++ b/apps/frontend/src/routes/(authed)/t/[tableId]/[[viewId]]/+page.svelte @@ -19,6 +19,7 @@ import { derived } from "svelte/store" import UpdateTableDialog from "$lib/components/blocks/update-table/update-table-dialog.svelte" import DeleteTableDialog from "$lib/components/blocks/delete-table/delete-table-dialog.svelte" + import TableRecordDetailSheet from "$lib/components/blocks/record-detail/table-record-detail-sheet.svelte" function handleR() { toggleModal(CREATE_RECORD_MODAL) @@ -47,7 +48,7 @@ - + diff --git a/apps/frontend/src/routes/s/v/[shareId]/+page.svelte b/apps/frontend/src/routes/s/v/[shareId]/+page.svelte index 6d4f445d0..095d4eb43 100644 --- a/apps/frontend/src/routes/s/v/[shareId]/+page.svelte +++ b/apps/frontend/src/routes/s/v/[shareId]/+page.svelte @@ -13,7 +13,7 @@ let RecordDetailSheet: ComponentType onMount(async () => { - RecordDetailSheet = (await import("$lib/components/blocks/record-detail/record-detail-sheet.svelte")).default + RecordDetailSheet = (await import("$lib/components/blocks/record-detail/share-record-detail-sheet.svelte")).default }) const viewId = derived([shareStore, page], ([$shareStore, $page]) => { diff --git a/packages/queries/src/get-record-by-id.query.ts b/packages/queries/src/get-record-by-id.query.ts index 0b82254b6..e77ab9150 100644 --- a/packages/queries/src/get-record-by-id.query.ts +++ b/packages/queries/src/get-record-by-id.query.ts @@ -13,13 +13,17 @@ export const getRecordByIdOutput = z.object({ export type IGetRecordByIdOutput = z.infer export class GetRecordByIdQuery extends Query implements IGetRecordByIdQuery { - public readonly tableId: string + public readonly tableId?: string + public readonly baseName?: string + public readonly tableName?: string public readonly id: string public readonly select?: string[] constructor(props: QueryProps) { super() this.tableId = props.tableId + this.baseName = props.baseName + this.tableName = props.tableName this.id = props.id this.select = props.select } diff --git a/packages/queries/src/get-share-record-by-id.query.ts b/packages/queries/src/get-share-record-by-id.query.ts new file mode 100644 index 000000000..d862718e3 --- /dev/null +++ b/packages/queries/src/get-share-record-by-id.query.ts @@ -0,0 +1,28 @@ +import { Query, type QueryProps } from "@undb/domain" +import { shareIdSchema } from "@undb/share" +import { recordDTO, recordId } from "@undb/table" +import { z } from "@undb/zod" + +export const getShareRecordByIdQuery = z.object({ + shareId: shareIdSchema, + recordId: recordId, +}) + +export type IGetShareRecordByIdQuery = z.infer + +export const getShareRecordByIdOutput = z.object({ + record: recordDTO.nullable(), +}) + +export type IGetShareRecordByIdOutput = z.infer + +export class GetShareRecordByIdQuery extends Query implements IGetShareRecordByIdQuery { + public readonly shareId: string + public readonly recordId: string + + constructor(props: QueryProps) { + super() + this.shareId = props.shareId + this.recordId = props.recordId + } +} diff --git a/packages/queries/src/index.ts b/packages/queries/src/index.ts index 59559443c..e00a93b93 100644 --- a/packages/queries/src/index.ts +++ b/packages/queries/src/index.ts @@ -14,6 +14,7 @@ export * from "./get-record-audits.query" export * from "./get-record-by-id.query" export * from "./get-records.query" export * from "./get-rollup-foreign-tables.query" +export * from "./get-share-record-by-id.query" export * from "./get-share-records.query" export * from "./get-share.query" export * from "./get-space-by-id.query" diff --git a/packages/query-handlers/src/handlers/get-share-record-by-id.query-handler.ts b/packages/query-handlers/src/handlers/get-share-record-by-id.query-handler.ts new file mode 100644 index 000000000..0a362e5b8 --- /dev/null +++ b/packages/query-handlers/src/handlers/get-share-record-by-id.query-handler.ts @@ -0,0 +1,30 @@ +import { setContextValue } from "@undb/context/server" +import { queryHandler } from "@undb/cqrs" +import { singleton } from "@undb/di" +import type { IQueryHandler } from "@undb/domain" +import { GetShareRecordByIdQuery, type IGetShareRecordByIdOutput, type IGetShareRecordByIdQuery } from "@undb/queries" +import { injectShareService, type IShareService } from "@undb/share" +import { injectSpaceService, type ISpaceService } from "@undb/space" + +@queryHandler(GetShareRecordByIdQuery) +@singleton() +export class GetShareRecordByIdQueryHandler + implements IQueryHandler +{ + constructor( + @injectShareService() + private readonly svc: IShareService, + @injectSpaceService() + private readonly spaceService: ISpaceService, + ) {} + + async execute(query: IGetShareRecordByIdQuery): Promise { + const { shareId, recordId } = query + await this.spaceService.setSpaceContext(setContextValue, { shareId }) + const record = await this.svc.getShareRecordById(shareId, recordId) + + return { + record: record.into(null), + } + } +} diff --git a/packages/query-handlers/src/handlers/index.ts b/packages/query-handlers/src/handlers/index.ts index 76d56733d..69dd6588d 100644 --- a/packages/query-handlers/src/handlers/index.ts +++ b/packages/query-handlers/src/handlers/index.ts @@ -14,6 +14,7 @@ import { GetRecordAuditsQueryHandler } from "./get-record-audits.query-handler" import { GetRecordByIdQueryHandler } from "./get-record-by-id.query-handler" import { GetRecordsQueryHandler } from "./get-records.query-handler" import { GetRollupForeignTablesTablesQueryHandler } from "./get-rollup-foreign-tables.query-handler" +import { GetShareRecordByIdQueryHandler } from "./get-share-record-by-id.query-handler" import { GetShareRecordsQueryHandler } from "./get-share-records.query-handler" import { GetShareQueryHandler } from "./get-share.query-handler" import { GetSpaceByIdQueryHandler } from "./get-space-by-id.query-handler" @@ -30,6 +31,7 @@ export const queryHandlers = [ GetTableQueryHandler, GetRecordsQueryHandler, GetShareRecordsQueryHandler, + GetShareRecordByIdQueryHandler, GetRecordByIdQueryHandler, GetReadableRecordsHandler, GetAggregatesQueryHandler, diff --git a/packages/share/src/services/share.service.ts b/packages/share/src/services/share.service.ts index bc66fa2ad..f30835c71 100644 --- a/packages/share/src/services/share.service.ts +++ b/packages/share/src/services/share.service.ts @@ -1,6 +1,7 @@ import { inject, singleton } from "@undb/di" -import { Option, Some, type PaginatedDTO } from "@undb/domain" +import { None, Option, Some, type PaginatedDTO } from "@undb/domain" import { + RecordIdVO, TableComositeSpecification, ViewIdVo, WithFormIdSpecification, @@ -36,6 +37,7 @@ export interface IShareService { getShareByTarget(target: IShareTarget): Promise> getTableByShare(id: string): Promise getShareRecords(id: string): Promise> + getShareRecordById(id: string, recordId: string): Promise> } export const SHARE_SERVICE = Symbol.for("SHARE_SERVICE") @@ -135,4 +137,27 @@ export class ShareService implements IShareService { values: await this.recordsService.populateAttachments({ viewId }, table, records.values), } } + + async getShareRecordById(id: string, recordId: string): Promise> { + const share = (await this.repo.findOneById(id)).expect("share not found") + const spec = match(share.target.type) + .returnType() + .with("form", () => new WithFormIdSpecification(share.target.id)) + .with("view", () => new WithViewIdSpecification(share.target.id)) + .exhaustive() + + const table = (await this.tableRepo.findOne(Some(spec))).expect("table not found") + + const record = await this.recordRepo.findOneById(table, new RecordIdVO(recordId), None) + if (record.isNone()) { + return None + } + + const r = record.unwrap() + const values = await this.recordsService.populateAttachment({}, table, r.values) + return Some({ + ...r, + values, + }) + } } diff --git a/packages/table/src/modules/records/services/records.query-service.ts b/packages/table/src/modules/records/services/records.query-service.ts index ed6f11385..60ab9f85b 100644 --- a/packages/table/src/modules/records/services/records.query-service.ts +++ b/packages/table/src/modules/records/services/records.query-service.ts @@ -28,6 +28,7 @@ export interface IRecordsQueryService { getReadableRecordById(query: IGetRecordByIdDTO): Promise> getAggregates(query: IGetAggregatesDTO): Promise> populateAttachments(dto: IGetRecordsDTO, table: TableDo, records: IRecordDTO[]): Promise + populateAttachment(dto: IGetRecordsDTO, table: TableDo, value: IRecordDTO["values"]): Promise } @singleton() diff --git a/packages/trpc/src/router.ts b/packages/trpc/src/router.ts index 7221ba3e3..c617f9b24 100644 --- a/packages/trpc/src/router.ts +++ b/packages/trpc/src/router.ts @@ -94,6 +94,7 @@ import { GetMemberSpacesQuery, GetRecordByIdQuery, GetRecordsQuery, + GetShareRecordByIdQuery, GetShareRecordsQuery, GetTableQuery, GetTablesQuery, @@ -105,6 +106,7 @@ import { getMemberSpacesQuery, getRecordByIdQuery, getRecordsQuery, + getShareRecordByIdQuery, getShareRecordsQuery, getTableQuery, getWebhooksQuery, @@ -318,6 +320,9 @@ const shareDataRouter = t.router({ records: publicProcedure .input(getShareRecordsQuery) .query(({ input }) => queryBus.execute(new GetShareRecordsQuery(input))), + record: publicProcedure + .input(getShareRecordByIdQuery) + .query(({ input }) => queryBus.execute(new GetShareRecordByIdQuery(input))), }) const authzRouter = t.router({