mirror of
https://github.com/docmost/docmost.git
synced 2026-08-30 02:25:01 +08:00
fix(base): store file-cell URLs in the editor's /api/files/{id}/{name} shape
The file-cell value was storing the raw S3 storage path returned by
attachmentService (e.g. "01944.../files/019dd.../AlgoExpert_Receipt.pdf"),
which the browser can't fetch as-is — and the cell never built it
into a clickable link anyway. Match the editor's attachment node-view
pattern: store url as "/api/files/{id}/{fileName}" on upload and
resolve it through getFileUrl when rendering. The dropdown's file
rows are now <a target="_blank"> links so the user can actually open
the attached file.
`buildFileUrl` falls back to constructing the path from id+fileName
for any pre-existing values that still carry the old shape, so
already-uploaded attachments don't break.
This commit is contained in:
@@ -9,15 +9,26 @@ import {
|
|||||||
import { IBaseProperty } from "@/features/base/types/base.types";
|
import { IBaseProperty } from "@/features/base/types/base.types";
|
||||||
import cellClasses from "@/features/base/styles/cells.module.css";
|
import cellClasses from "@/features/base/styles/cells.module.css";
|
||||||
import { uploadFile } from "@/features/page/services/page-service";
|
import { uploadFile } from "@/features/page/services/page-service";
|
||||||
|
import { getFileUrl } from "@/lib/config";
|
||||||
|
|
||||||
export type FileValue = {
|
export type FileValue = {
|
||||||
id: string;
|
id: string;
|
||||||
fileName: string;
|
fileName: string;
|
||||||
mimeType?: string;
|
mimeType?: string;
|
||||||
fileSize?: number;
|
fileSize?: number;
|
||||||
filePath?: string;
|
// `/api/files/{id}/{fileName}` — same shape the editor's attachment
|
||||||
|
// node view uses. `getFileUrl` strips the `/api/` prefix and
|
||||||
|
// prepends the backend host to produce a fetchable URL. Stored on
|
||||||
|
// upload so the original filename round-trips even if the cell
|
||||||
|
// value is moved to a row where the file's storage path no longer
|
||||||
|
// resolves from the cell's pageId.
|
||||||
|
url?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function buildFileUrl(file: Pick<FileValue, "id" | "fileName" | "url">): string {
|
||||||
|
return file.url ?? `/api/files/${file.id}/${encodeURIComponent(file.fileName)}`;
|
||||||
|
}
|
||||||
|
|
||||||
type CellFileProps = {
|
type CellFileProps = {
|
||||||
value: unknown;
|
value: unknown;
|
||||||
property: IBaseProperty;
|
property: IBaseProperty;
|
||||||
@@ -82,7 +93,7 @@ export function CellFile({
|
|||||||
fileName: attachment.fileName,
|
fileName: attachment.fileName,
|
||||||
mimeType: attachment.mimeType,
|
mimeType: attachment.mimeType,
|
||||||
fileSize: attachment.fileSize,
|
fileSize: attachment.fileSize,
|
||||||
filePath: attachment.filePath,
|
url: `/api/files/${attachment.id}/${encodeURIComponent(attachment.fileName)}`,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("File upload failed:", err);
|
console.error("File upload failed:", err);
|
||||||
@@ -147,7 +158,17 @@ export function CellFile({
|
|||||||
color: "var(--mantine-color-gray-6)",
|
color: "var(--mantine-color-gray-6)",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div style={{ flex: 1, minWidth: 0 }}>
|
<a
|
||||||
|
href={getFileUrl(buildFileUrl(file))}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
minWidth: 0,
|
||||||
|
textDecoration: "none",
|
||||||
|
color: "inherit",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Text size="xs" truncate="end" fw={500}>
|
<Text size="xs" truncate="end" fw={500}>
|
||||||
{file.fileName}
|
{file.fileName}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -156,7 +177,7 @@ export function CellFile({
|
|||||||
{formatFileSize(file.fileSize)}
|
{formatFileSize(file.fileSize)}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</div>
|
</a>
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
color="gray"
|
color="gray"
|
||||||
|
|||||||
Reference in New Issue
Block a user