fix: file preview URLs and milestone web link saving

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
EENE Dashboard
2026-06-05 22:44:52 +09:00
parent ccf892e479
commit fa8ed76e22
6 changed files with 36 additions and 6 deletions

View File

@@ -1,5 +1,6 @@
import { useEffect, useState } from 'react';
import * as XLSX from 'xlsx';
import { fileDownloadUrl, fileViewUrl } from '../../lib/apiClient';
interface ExcelPreviewProps {
fileId: string;
@@ -21,7 +22,7 @@ export function ExcelPreview({ fileId, fileName }: ExcelPreviewProps) {
(async () => {
try {
const res = await fetch(`/api/files/${fileId}/view`);
const res = await fetch(fileViewUrl(fileId));
if (!res.ok) throw new Error('파일을 불러올 수 없습니다.');
const buffer = await res.arrayBuffer();
const wb = XLSX.read(buffer, { type: 'array' });
@@ -48,7 +49,7 @@ export function ExcelPreview({ fileId, fileName }: ExcelPreviewProps) {
<div className="flex h-full w-full flex-col items-center justify-center gap-3 p-6 text-center">
<p className="text-lg text-white/60">{error}</p>
<a
href={`/api/files/${fileId}/download`}
href={fileDownloadUrl(fileId)}
className="rounded bg-white/10 px-4 py-2 text-sm font-bold text-white hover:bg-white/20"
>
{fileName}

View File

@@ -1,6 +1,7 @@
import { useState, useEffect, useCallback } from 'react';
import { createPortal } from 'react-dom';
import { ExcelPreview } from './ExcelPreview';
import { fileViewUrl } from '../../lib/apiClient';
import { openLinkOnRightMonitor } from '../../lib/dualMonitor';
import { fileDisplayName, isExcelFile, isVideoFile } from '../../lib/fileDisplay';
import type { FileRecord, MilestoneLink } from '../../types';
@@ -53,7 +54,7 @@ export function ResultPreview({ files, links, hasSelectedStage }: ResultPreviewP
if (isExcel) {
return <ExcelPreview fileId={activeFile.id} fileName={label} />;
}
const src = `/api/files/${activeFile.id}/view`;
const src = fileViewUrl(activeFile.id);
if (isImage) {
return (
<img

View File

@@ -291,6 +291,15 @@ export function StageModal({
if (editTarget?.type === 'file') applyFileEdit();
if (editTarget?.type === 'link') applyLinkEdit();
let saveForm = form;
const pendingUrl = linkUrl.trim();
if (editTarget?.type !== 'link' && pendingUrl) {
saveForm = {
...form,
links: [...form.links, { label: linkLabel.trim() || pendingUrl, url: pendingUrl }],
};
}
const sorted = [...fileRows].sort((a, b) => a.sortOrder - b.sortOrder);
const uploads: PendingFileUpload[] = [];
const existingEdits: ExistingFileEdit[] = [];
@@ -312,7 +321,7 @@ export function StageModal({
}
});
await onSave(form, {
await onSave(saveForm, {
uploads,
existingEdits,
deletedFileIds,

View File

@@ -16,6 +16,14 @@ export const apiClient = axios.create({
},
});
export function fileViewUrl(fileId: string): string {
return `${baseURL}/files/${fileId}/view`;
}
export function fileDownloadUrl(fileId: string): string {
return `${baseURL}/files/${fileId}/download`;
}
apiClient.interceptors.request.use((config) => {
if (config.data instanceof FormData) {
delete config.headers['Content-Type'];

View File

@@ -286,7 +286,7 @@ function DetailView({ task }: { task: TaskWithRelations }) {
startDate: data.startDate || undefined,
dueDate: data.dueDate || undefined,
progress: data.progress,
links: data.links.length > 0 ? JSON.stringify(data.links) : undefined,
links: data.links,
};
let milestoneId: string;