sync: update from private repo (d31b280)
CI / build-and-test (push) Has been cancelled

This commit is contained in:
oss-sync
2026-06-11 11:28:40 +00:00
parent d061ad08d8
commit 3b1645cc91
96 changed files with 4627 additions and 287 deletions
+19 -7
View File
@@ -2,6 +2,8 @@ import { useEffect, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { LocalFileEntry, getLocalFileRawUrl } from '../../api';
import { isPreviewable, formatFileDate } from '../../lib/utils';
import { splitFileName } from '../../lib/fileType';
import { FileTypeIcon } from './FileTypeIcon';
interface FileBrowserProps {
section: 'workspace' | 'input' | 'output' | 'logs';
@@ -211,20 +213,30 @@ export function FileBrowser({
key={`${entry.kind}:${entry.path}`}
className="flex items-center gap-2 px-2.5 py-1.5 rounded-md bg-canvas border border-hairline hover:bg-surface transition-colors"
>
<span className="text-slate-400 flex-shrink-0" aria-hidden="true">
<span className="flex-shrink-0" aria-hidden="true">
{entry.kind === 'directory' ? (
<svg className="w-4 h-4" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<svg className="w-4 h-4 text-slate-400" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M2 4.5A1.5 1.5 0 013.5 3h3l1.5 2h4.5A1.5 1.5 0 0114 6.5v5A1.5 1.5 0 0112.5 13h-9A1.5 1.5 0 012 11.5v-7z" />
</svg>
) : (
<svg className="w-4 h-4" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M9 2H4a1.5 1.5 0 00-1.5 1.5v9A1.5 1.5 0 004 14h8a1.5 1.5 0 001.5-1.5V6.5L9 2z" />
<path d="M9 2v4.5h4.5" />
</svg>
<FileTypeIcon name={entry.name} />
)}
</span>
<div className="min-w-0 flex-1">
<div className="text-[13px] text-slate-800 truncate" title={entry.name}>{entry.name}</div>
{entry.kind === 'file'
? (() => {
// Truncate the stem but never the extension, so the file
// type stays readable on long names: `long-na…me.xlsx`.
const { stem, ext } = splitFileName(entry.name);
return (
<div className="flex items-baseline text-[13px] text-slate-800 min-w-0" title={entry.name}>
<span className="truncate min-w-0">{stem}</span>
{ext && <span className="flex-shrink-0">{ext}</span>}
</div>
);
})()
: <div className="text-[13px] text-slate-800 truncate" title={entry.name}>{entry.name}</div>
}
{entry.kind === 'file' && entry.modifiedAt && (
<div className="text-[10px] text-slate-400 font-mono leading-tight">{formatFileDate(entry.modifiedAt)}</div>
)}
+18 -1
View File
@@ -65,6 +65,7 @@ interface FilePreviewProps {
section?: string;
filePath?: string;
editable?: boolean;
trustedHtmlUrl?: string;
}
// --- CSV ---
@@ -622,7 +623,7 @@ function renderJsonl(content: string): JSX.Element {
}
// --- FilePreview ---
export function FilePreview({ name, content, imageSrc, markdownImageBaseUrl, onClose, taskId, section, filePath, editable }: FilePreviewProps) {
export function FilePreview({ name, content, imageSrc, markdownImageBaseUrl, onClose, taskId, section, filePath, editable, trustedHtmlUrl }: FilePreviewProps) {
const { t } = useTranslation('files');
const [mode, setMode] = useState<'view' | 'edit'>('view');
const [editContent, setEditContent] = useState(content);
@@ -634,6 +635,7 @@ export function FilePreview({ name, content, imageSrc, markdownImageBaseUrl, onC
const canEdit = editable && taskId != null && section && filePath;
const isMarkdownFile = /\.(md|markdown)$/i.test(name);
const canOpenTrustedHtml = mode === 'view' && !!trustedHtmlUrl && /\.html?$/i.test(name);
const handlePrint = async () => {
if (printing) return;
@@ -756,6 +758,21 @@ export function FilePreview({ name, content, imageSrc, markdownImageBaseUrl, onC
<div className="flex justify-between items-center px-4 py-2.5 border-b border-hairline flex-shrink-0 sticky top-0 bg-surface z-10 gap-2">
<div className="font-mono text-xs text-slate-700 truncate" title={name}>{name}</div>
<div className="flex items-center gap-1 flex-shrink-0">
{canOpenTrustedHtml && (
<a
href={trustedHtmlUrl}
target="_blank"
rel="noopener noreferrer"
title={t('trustedHtml.tooltip')}
className="inline-flex items-center gap-1 px-2.5 h-7 text-2xs font-medium rounded-md border border-amber-300 bg-amber-50 text-amber-800 hover:bg-amber-100 transition-colors"
>
<svg className="w-3 h-3" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M6 3H3.5A1.5 1.5 0 0 0 2 4.5v8A1.5 1.5 0 0 0 3.5 14h8a1.5 1.5 0 0 0 1.5-1.5V10" />
<path d="M9 2h5v5M8 8l6-6" />
</svg>
{t('trustedHtml.button')}
</a>
)}
{isMarkdownFile && mode === 'view' && (
<button
onClick={handlePrint}
+89
View File
@@ -0,0 +1,89 @@
import { fileCategory, categoryColorClass, type FileCategory } from '../../lib/fileType';
/** カテゴリごとの 16x16 ストロークグリフ (既存ファイル行のアイコンと同じスタイル)。 */
function glyph(cat: FileCategory) {
switch (cat) {
case 'image':
return (
<>
<rect x="2" y="3" width="12" height="10" rx="1.5" />
<circle cx="5.5" cy="6.5" r="1" />
<path d="M3 12l3-3 2.5 2.5L11 7l2 2" />
</>
);
case 'spreadsheet':
return (
<>
<rect x="2.5" y="3" width="11" height="10" rx="1" />
<path d="M2.5 6.5h11M2.5 10h11M6 3v10M10 3v10" />
</>
);
case 'document':
return (
<>
<path d="M9 2H4a1.5 1.5 0 00-1.5 1.5v9A1.5 1.5 0 004 14h8a1.5 1.5 0 001.5-1.5V6.5L9 2z" />
<path d="M9 2v4.5h4.5" />
<path d="M5.5 9h5M5.5 11h3" />
</>
);
case 'presentation':
return (
<>
<rect x="2" y="3" width="12" height="8" rx="1" />
<path d="M8 11v2M6 14h4" />
</>
);
case 'code':
return <path d="M6 5L3 8l3 3M10 5l3 3-3 3" />;
case 'archive':
return (
<>
<rect x="3" y="3" width="10" height="11" rx="1" />
<path d="M8 3v11" strokeDasharray="1.5 1.5" />
</>
);
case 'audio':
return (
<>
<circle cx="5.3" cy="11.5" r="1.7" />
<circle cx="10.7" cy="9.7" r="1.7" />
<path d="M7 11.5V4l5.4-1.5v7.2" />
</>
);
case 'video':
return (
<>
<rect x="2" y="3.5" width="12" height="9" rx="1.5" />
<path d="M7 6.3l3 1.7-3 1.7z" />
</>
);
case 'pdf':
case 'other':
default:
// 折れ角のあるページ。pdf は色 (赤) で識別、other は灰色。
return (
<>
<path d="M9 2H4a1.5 1.5 0 00-1.5 1.5v9A1.5 1.5 0 004 14h8a1.5 1.5 0 001.5-1.5V6.5L9 2z" />
<path d="M9 2v4.5h4.5" />
</>
);
}
}
export function FileTypeIcon({ name, className }: { name: string; className?: string }) {
const cat = fileCategory(name);
return (
<svg
className={`${className ?? 'w-4 h-4'} ${categoryColorClass(cat)}`}
viewBox="0 0 16 16"
fill="none"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
{glyph(cat)}
</svg>
);
}