fix: file preview URLs and milestone web link saving
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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} 다운로드
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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'];
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user