mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-30 16:16:19 +00:00
feat: create documents in the formats the document editor can edit from New file #1393
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
- **Privacy**: One switch, `NO_THIRD_PARTY_TRAFFIC` or Organisation > Security, stops every connection to services outside your own servers: telemetry, the version check, the built-in push relay, the official extension directory, sender icons, MyMemory translation, map links, OpenPGP key lookups and remote pictures in mail. Plugins that need network access don't run, and the page's CSP allows only the hosts you configured. Push registrations move to your own relay. The admin page lists what stays reachable (#903)
|
||||
- **Team inbox**: The new official Team inbox plugin lets members of a team mailbox assign messages to each other, mark them done, and filter by "Assigned to me" and "Open"
|
||||
- **Plugins**: Plugins can add keyword filters to the message list, shown as chips above it, put icons on row badges, show actions only in team mailboxes or for some keywords, change several keywords in one step, see the user's own account and which mailboxes are team mailboxes, and keep a small shared value in a team mailbox on Stalwart 1.0. Looking people up in the directory needs the new `directory:read` permission. Plugins can no longer set `$draft`, `$junk`, `$notjunk` or `$phishing`
|
||||
- **Files**: With a document editor configured, "New file" also creates Word, Excel, PowerPoint, OpenDocument and (where the editor edits PDFs) PDF files and opens them in the editor. It offers the formats the editor can edit; admins can narrow the list with `WOPI_NEW_FILE_FORMATS` and add their own blank templates, or other formats, with `WOPI_TEMPLATE_DIR` (#1393)
|
||||
|
||||
## 1.18.0 (2026-10-26)
|
||||
|
||||
|
||||
@@ -165,9 +165,14 @@ export function SettingsPage() {
|
||||
<SettingsSection id="wopi" title="Document editing">
|
||||
<ConfigTextItem label="WOPI client URL" configKey="wopiClientUrl" value={currentValue('wopiClientUrl') as string} source={config.wopiClientUrl?.source} onChange={handleChange} onRevert={handleRevert} placeholder="https://office.example.com" wide />
|
||||
<ConfigTextItem label="WOPI host URL override" configKey="wopiHostUrl" value={currentValue('wopiHostUrl') as string} source={config.wopiHostUrl?.source} onChange={handleChange} onRevert={handleRevert} placeholder="http://webmail:3000" wide />
|
||||
<ConfigTextItem label="New file formats" configKey="wopiNewFileFormats" value={currentValue('wopiNewFileFormats') as string} source={config.wopiNewFileFormats?.source} onChange={handleChange} onRevert={handleRevert} placeholder="Every format the editor can edit" wide />
|
||||
<ConfigTextItem label="Template directory" configKey="wopiTemplateDir" value={currentValue('wopiTemplateDir') as string} source={config.wopiTemplateDir?.source} onChange={handleChange} onRevert={handleRevert} placeholder="/data/templates" wide />
|
||||
<ConfigNote>
|
||||
Point the client URL at a WOPI-compatible office suite (Collabora Online, OnlyOffice, EuroOffice, …) to let users edit documents in Files. The client URL may be an internal address: the browser loads the editor from the address its discovery advertises. The host override is only needed when the editor reaches this webmail under a different address than the browser does (e.g. Docker networks); give the address alone, the webmail's base path is added to it. The editor must also allow this webmail as a WOPI host.
|
||||
</ConfigNote>
|
||||
<ConfigNote>
|
||||
"New file" in Files offers .txt plus every format the editor can edit that a blank template exists for: .docx, .xlsx, .pptx, .odt, .ods, .odp and .pdf are built in. List extensions separated by commas (e.g. <code className="text-[11px] bg-muted px-1 py-0.5 rounded">docx,xlsx,pptx</code>) to offer only those. A file named <code className="text-[11px] bg-muted px-1 py-0.5 rounded">new.<ext></code> in the template directory on this server replaces the built-in blank file for that format or adds a format, so ONLYOFFICE's <code className="text-[11px] bg-muted px-1 py-0.5 rounded">document-templates/new/<locale></code> folder works as one.
|
||||
</ConfigNote>
|
||||
</SettingsSection>
|
||||
|
||||
<SettingsSection id="logging" title="Logging">
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { getStalwartCredentials } from '@/lib/stalwart/credentials';
|
||||
import { getWopiActions, getWopiClientUrl } from '@/lib/wopi/discovery';
|
||||
import { getNewFileFormats } from '@/lib/wopi/new-file';
|
||||
|
||||
/**
|
||||
* GET /api/wopi/status
|
||||
*
|
||||
* Tells the Files UI whether a WOPI document editor is configured and which
|
||||
* file extensions it can edit/view (#425). Session-authenticated; the WOPI
|
||||
* client URL itself stays server-side.
|
||||
* Tells the Files UI whether a WOPI document editor is configured, which
|
||||
* file extensions it can edit/view (#425) and which ones "New file" can
|
||||
* create (#1393). Session-authenticated; the WOPI client URL itself stays
|
||||
* server-side.
|
||||
*/
|
||||
export async function GET(request: NextRequest) {
|
||||
const creds = await getStalwartCredentials(request);
|
||||
@@ -15,19 +17,21 @@ export async function GET(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });
|
||||
}
|
||||
|
||||
const disabled = { enabled: false, editExtensions: [], viewExtensions: [], newExtensions: [] };
|
||||
const clientUrl = await getWopiClientUrl();
|
||||
if (!clientUrl) {
|
||||
return NextResponse.json({ enabled: false, editExtensions: [], viewExtensions: [] });
|
||||
return NextResponse.json(disabled);
|
||||
}
|
||||
|
||||
const actions = await getWopiActions();
|
||||
if (!actions) {
|
||||
return NextResponse.json({ enabled: false, editExtensions: [], viewExtensions: [] });
|
||||
return NextResponse.json(disabled);
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
enabled: true,
|
||||
editExtensions: Object.keys(actions.edit),
|
||||
viewExtensions: Object.keys(actions.view),
|
||||
newExtensions: await getNewFileFormats(actions),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { getStalwartCredentials } from '@/lib/stalwart/credentials';
|
||||
import { getWopiActions } from '@/lib/wopi/discovery';
|
||||
import { getBlankTemplate, getNewFileFormats } from '@/lib/wopi/new-file';
|
||||
|
||||
/**
|
||||
* GET /api/wopi/template?ext=docx
|
||||
*
|
||||
* The blank file "New file" uploads for a document format the editor can
|
||||
* create (#1393). Only formats /api/wopi/status lists under newExtensions.
|
||||
* Session-authenticated.
|
||||
*/
|
||||
export async function GET(request: NextRequest) {
|
||||
const creds = await getStalwartCredentials(request);
|
||||
if (!creds) {
|
||||
return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });
|
||||
}
|
||||
|
||||
const ext = (request.nextUrl.searchParams.get('ext') ?? '').toLowerCase();
|
||||
const actions = await getWopiActions();
|
||||
if (!actions || !(await getNewFileFormats(actions)).includes(ext)) {
|
||||
return NextResponse.json({ error: 'Unknown format' }, { status: 404 });
|
||||
}
|
||||
|
||||
const template = await getBlankTemplate(ext);
|
||||
if (!template) {
|
||||
return NextResponse.json({ error: 'Unknown format' }, { status: 404 });
|
||||
}
|
||||
return new NextResponse(new Blob([template.data as BlobPart], { type: template.type }), {
|
||||
headers: {
|
||||
'Content-Type': template.type,
|
||||
'Cache-Control': 'private, no-cache',
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -105,7 +105,7 @@ function renderBrowser(opts: { resources?: FileResource[]; allFolders?: FileReso
|
||||
onPaste={noop}
|
||||
onMoveTo={noop}
|
||||
onPreviewImage={vi.fn()}
|
||||
onCreateTextFile={noop}
|
||||
onCreateFile={noop}
|
||||
onDuplicate={noop}
|
||||
getImageUrl={async () => ''}
|
||||
favorites={[]}
|
||||
|
||||
@@ -77,7 +77,7 @@ function renderBrowser(selected: string[] = []) {
|
||||
onPaste={noop}
|
||||
onMoveTo={noop}
|
||||
onPreviewImage={vi.fn()}
|
||||
onCreateTextFile={noop}
|
||||
onCreateFile={noop}
|
||||
onDuplicate={noop}
|
||||
getImageUrl={async () => ''}
|
||||
favorites={[]}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { render, screen, fireEvent, cleanup } from '@testing-library/react';
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
import { NewFileDialog, withExtension } from '@/components/files/new-file-dialog';
|
||||
|
||||
// #1393: with a document editor, "New file" offers its formats next to .txt.
|
||||
|
||||
vi.mock('next-intl', () => ({ useTranslations: () => (key: string) => key }));
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
const nameField = () => screen.getByLabelText('file_name') as HTMLInputElement;
|
||||
const checked = () => screen.getAllByRole('radio').filter((r) => r.getAttribute('aria-checked') === 'true').map((r) => r.textContent);
|
||||
|
||||
describe('NewFileDialog', () => {
|
||||
it('is the plain text-file prompt without an editor', () => {
|
||||
render(<NewFileDialog isOpen onClose={() => {}} onSubmit={() => {}} formats={[]} />);
|
||||
expect(screen.getByText('new_text_file')).toBeTruthy();
|
||||
expect(screen.queryByRole('radiogroup')).toBeNull();
|
||||
expect(nameField().value).toBe('new-file.txt');
|
||||
});
|
||||
|
||||
it('switches the extension with the format and the format with the extension', () => {
|
||||
const onSubmit = vi.fn();
|
||||
render(<NewFileDialog isOpen onClose={() => {}} onSubmit={onSubmit} formats={['docx', 'xlsx', 'pdf']} />);
|
||||
expect(screen.getByText('new_file')).toBeTruthy();
|
||||
expect(screen.getAllByRole('radio').map((r) => r.textContent)).toEqual([
|
||||
'format_text.txt', 'format_document.docx', 'format_spreadsheet.xlsx', 'format_pdf.pdf',
|
||||
]);
|
||||
expect(checked()).toEqual(['format_text.txt']);
|
||||
|
||||
fireEvent.change(nameField(), { target: { value: 'Budget 2027.txt' } });
|
||||
fireEvent.click(screen.getByText('format_spreadsheet'));
|
||||
expect(nameField().value).toBe('Budget 2027.xlsx');
|
||||
expect(checked()).toEqual(['format_spreadsheet.xlsx']);
|
||||
|
||||
fireEvent.change(nameField(), { target: { value: 'Budget 2027.DOCX' } });
|
||||
expect(checked()).toEqual(['format_document.docx']);
|
||||
fireEvent.change(nameField(), { target: { value: 'Budget 2027.md' } });
|
||||
expect(checked()).toEqual([]);
|
||||
|
||||
fireEvent.click(screen.getByText('create'));
|
||||
expect(onSubmit).toHaveBeenCalledWith('Budget 2027.md');
|
||||
});
|
||||
|
||||
it('keeps the base name when changing the extension', () => {
|
||||
expect(withExtension('report.txt', 'docx')).toBe('report.docx');
|
||||
expect(withExtension('archive.tar.gz', 'odt')).toBe('archive.tar.odt');
|
||||
expect(withExtension('notes', 'pptx')).toBe('notes.pptx');
|
||||
expect(withExtension('.hidden', 'ods')).toBe('.hidden.ods');
|
||||
expect(withExtension('', 'pdf')).toBe('new-file.pdf');
|
||||
});
|
||||
});
|
||||
@@ -16,6 +16,7 @@ import { ContextMenu, ContextMenuItem, ContextMenuSeparator } from "@/components
|
||||
import { Avatar } from "@/components/ui/avatar";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { PromptDialog } from "@/components/ui/prompt-dialog";
|
||||
import { NewFileDialog } from "@/components/files/new-file-dialog";
|
||||
import { FolderPickerDialog } from "@/components/files/folder-picker-dialog";
|
||||
import { fileNameProblem } from "@/lib/file-name-rules";
|
||||
import { EmptyFolder, NoSearchResults } from "@/components/files/file-empty-state";
|
||||
@@ -38,6 +39,8 @@ import type { IJMAPClient } from "@/lib/jmap/client-interface";
|
||||
import type { FileNodeRights } from "@/lib/jmap/types";
|
||||
import type { FileResourceView } from "@/lib/plugin-types";
|
||||
|
||||
const NO_FORMATS: string[] = [];
|
||||
|
||||
interface ClipboardState {
|
||||
mode: "cut" | "copy";
|
||||
ids: string[];
|
||||
@@ -93,7 +96,10 @@ interface FileBrowserProps {
|
||||
/** WOPI document editing (#425): whether a file can open in the document editor. */
|
||||
isOfficeEditable?: (name: string) => boolean;
|
||||
onEditFile?: (name: string) => void;
|
||||
onCreateTextFile: (name: string) => Promise<void>;
|
||||
/** "New file": empty text, or a blank document of a format in `newFileFormats`. */
|
||||
onCreateFile: (name: string) => Promise<void>;
|
||||
/** Document formats a WOPI editor can create besides .txt (#1393). */
|
||||
newFileFormats?: string[];
|
||||
onDuplicate: (name: string) => Promise<void>;
|
||||
getImageUrl: (name: string) => Promise<string>;
|
||||
favorites: string[];
|
||||
@@ -182,7 +188,8 @@ export function FileBrowser({
|
||||
onPreviewFile,
|
||||
isOfficeEditable,
|
||||
onEditFile,
|
||||
onCreateTextFile,
|
||||
onCreateFile,
|
||||
newFileFormats = NO_FORMATS,
|
||||
onDuplicate,
|
||||
getImageUrl,
|
||||
favorites,
|
||||
@@ -204,6 +211,7 @@ export function FileBrowser({
|
||||
onShare,
|
||||
}: FileBrowserProps) {
|
||||
const t = useTranslations("files");
|
||||
const newFileLabel = newFileFormats.length > 0 ? t("new_file") : t("new_text_file");
|
||||
const fileNameRules = useMemo(() => client?.getFileNameRules?.() ?? null, [client]);
|
||||
const validateFileName = useCallback((name: string) => {
|
||||
const problem = fileNameProblem(name, fileNameRules);
|
||||
@@ -940,7 +948,7 @@ export function FileBrowser({
|
||||
<ContextMenuItem icon={FolderUp} label={t("upload_folder")} onClick={() => { closeMenu(); folderInputRef.current?.click(); }} />
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuItem icon={FolderPlus} label={t("new_folder")} onClick={() => { closeMenu(); setShowNewFolder(true); }} />
|
||||
<ContextMenuItem icon={FilePlus} label={t("new_text_file")} onClick={() => { closeMenu(); setShowNewTextFile(true); }} />
|
||||
<ContextMenuItem icon={FilePlus} label={newFileLabel} onClick={() => { closeMenu(); setShowNewTextFile(true); }} />
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -978,7 +986,7 @@ export function FileBrowser({
|
||||
{ id: "upload-files", label: t("upload_files"), icon: Upload, run: () => fileInputRef.current?.click(), when: () => canCreate },
|
||||
{ id: "upload-folder", label: t("upload_folder"), icon: FolderUp, run: () => folderInputRef.current?.click(), when: () => canCreate },
|
||||
{ id: "new-folder", label: t("new_folder"), icon: FolderPlus, run: () => setShowNewFolder(true), when: () => canCreate },
|
||||
{ id: "new-text-file", label: t("new_text_file"), icon: FilePlus, run: () => setShowNewTextFile(true), when: () => canCreate },
|
||||
{ id: "new-text-file", label: newFileLabel, icon: FilePlus, run: () => setShowNewTextFile(true), when: () => canCreate },
|
||||
{ id: "trash", label: t("trash"), icon: Trash2, run: () => onNavigate(TRASH_PATH, TRASH_LOCATION), when: () => !inTrash && !accountPickerMode },
|
||||
{ id: "empty-trash", label: t("empty_trash"), icon: Trash2, run: () => onEmptyTrash?.(), when: () => inTrash && trashCount > 0 && !!onEmptyTrash },
|
||||
{ id: "refresh", label: t("refresh"), icon: RefreshCw, run: () => void onRefresh() },
|
||||
@@ -1000,6 +1008,7 @@ export function FileBrowser({
|
||||
onUploadFolder={fromDrawer(() => folderInputRef.current?.click())}
|
||||
onNewFolder={fromDrawer(() => setShowNewFolder(true))}
|
||||
onNewTextFile={fromDrawer(() => setShowNewTextFile(true))}
|
||||
newFileLabel={newFileLabel}
|
||||
onToggleFavorite={onToggleFavorite}
|
||||
onDropItems={moveNames}
|
||||
canShare={canShare}
|
||||
@@ -1358,17 +1367,12 @@ export function FileBrowser({
|
||||
onSubmit={(name) => void onCreateFolder(name)}
|
||||
/>
|
||||
|
||||
<PromptDialog
|
||||
<NewFileDialog
|
||||
isOpen={showNewTextFile}
|
||||
onClose={() => setShowNewTextFile(false)}
|
||||
title={t("new_text_file")}
|
||||
placeholder={t("file_name")}
|
||||
defaultValue="new-file.txt"
|
||||
selectBaseName
|
||||
confirmText={t("create")}
|
||||
cancelText={t("cancel")}
|
||||
formats={newFileFormats}
|
||||
validate={validateFileName}
|
||||
onSubmit={(name) => void onCreateTextFile(name)}
|
||||
onSubmit={(name) => void onCreateFile(name)}
|
||||
/>
|
||||
|
||||
<PromptDialog
|
||||
|
||||
@@ -26,7 +26,8 @@ import type { FileNodeRights } from "@/lib/jmap/types";
|
||||
import { ImagePreviewModal } from "@/components/files/image-preview-modal";
|
||||
import { FilePreviewModal } from "@/components/files/file-preview-modal";
|
||||
import { WopiEditor } from "@/components/files/wopi-editor";
|
||||
import { useWopiStatus, canWopiOpen } from "@/hooks/use-wopi-status";
|
||||
import { useWopiStatus, canWopiOpen, fileExtension } from "@/hooks/use-wopi-status";
|
||||
import { apiFetch } from "@/lib/browser-navigation";
|
||||
import { AppTopBannerSlot } from "@/components/plugins/app-top-banner-slot";
|
||||
import { AlertTriangle, Loader2 } from "@/components/icons";
|
||||
import { isFilePreviewable } from "@/lib/file-preview";
|
||||
@@ -86,7 +87,7 @@ export function FilesApp({ linkSegments: routeSegments }: FilesAppProps = {}) {
|
||||
downloadResource,
|
||||
getImageUrl,
|
||||
getFileContent,
|
||||
createTextFile,
|
||||
createFile,
|
||||
duplicateResource,
|
||||
downloadResources,
|
||||
downloadZip,
|
||||
@@ -563,15 +564,25 @@ export function FilesApp({ linkSegments: routeSegments }: FilesAppProps = {}) {
|
||||
}
|
||||
}, [downloadZip, t, failureReason]);
|
||||
|
||||
const handleCreateTextFile = useCallback(async (name: string) => {
|
||||
// A document format the editor can create starts from a blank template
|
||||
// and opens in the editor (#1393); any other name is an empty text file.
|
||||
const handleCreateFile = useCallback(async (name: string) => {
|
||||
try {
|
||||
await createTextFile(name);
|
||||
const ext = fileExtension(name);
|
||||
let template: Blob | undefined;
|
||||
if (wopiStatus?.newExtensions.includes(ext)) {
|
||||
const res = await apiFetch(`/api/wopi/template?ext=${encodeURIComponent(ext)}`);
|
||||
if (!res.ok) throw new Error(`Template for .${ext} unavailable (${res.status})`);
|
||||
template = await res.blob();
|
||||
}
|
||||
const created = await createFile(name, template);
|
||||
toast.success(t("create_file_success"));
|
||||
if (template && created && isOfficeEditable(created)) setEditFile(created);
|
||||
} catch (err) {
|
||||
console.error("Failed to create file:", err);
|
||||
toast.error(t("create_file_error"), failureReason(err));
|
||||
}
|
||||
}, [createTextFile, t, failureReason]);
|
||||
}, [createFile, wopiStatus, isOfficeEditable, t, failureReason]);
|
||||
|
||||
const handleDuplicate = useCallback(async (name: string) => {
|
||||
try {
|
||||
@@ -867,7 +878,8 @@ export function FilesApp({ linkSegments: routeSegments }: FilesAppProps = {}) {
|
||||
onPreviewFile={handlePreviewFile}
|
||||
isOfficeEditable={isOfficeEditable}
|
||||
onEditFile={setEditFile}
|
||||
onCreateTextFile={handleCreateTextFile}
|
||||
onCreateFile={handleCreateFile}
|
||||
newFileFormats={wopiStatus?.newExtensions}
|
||||
onDuplicate={handleDuplicate}
|
||||
getImageUrl={getImageUrl}
|
||||
favorites={favorites}
|
||||
|
||||
@@ -66,6 +66,8 @@ export interface FilesSidebarProps {
|
||||
onUploadFolder: () => void;
|
||||
onNewFolder: () => void;
|
||||
onNewTextFile: () => void;
|
||||
/** The label of the new-file entries: "New file" when documents can be made too (#1393). */
|
||||
newFileLabel?: string;
|
||||
onToggleFavorite: (path: string) => void;
|
||||
/** Move dragged items from the open folder into a folder (null = the root). */
|
||||
onDropItems: (names: string[], targetId: string | null) => void;
|
||||
@@ -104,6 +106,7 @@ export function FilesSidebar({
|
||||
onUploadFolder,
|
||||
onNewFolder,
|
||||
onNewTextFile,
|
||||
newFileLabel,
|
||||
onToggleFavorite,
|
||||
onDropItems,
|
||||
canShare,
|
||||
@@ -269,7 +272,7 @@ export function FilesSidebar({
|
||||
<>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuItem icon={FolderPlus} label={t("new_folder")} onClick={() => run(() => onCreateIn(path, id, "folder"))} />
|
||||
<ContextMenuItem icon={FilePlus} label={t("new_text_file")} onClick={() => run(() => onCreateIn(path, id, "text"))} />
|
||||
<ContextMenuItem icon={FilePlus} label={newFileLabel ?? t("new_text_file")} onClick={() => run(() => onCreateIn(path, id, "text"))} />
|
||||
<ContextMenuItem icon={Upload} label={t("upload_files")} onClick={() => run(() => onCreateIn(path, id, "files"))} />
|
||||
<ContextMenuItem icon={FolderUp} label={t("upload_folder")} onClick={() => run(() => onCreateIn(path, id, "dir"))} />
|
||||
</>
|
||||
@@ -443,7 +446,7 @@ export function FilesSidebar({
|
||||
<ContextMenuItem icon={FolderUp} label={t("upload_folder")} onClick={() => { newMenu.closeContextMenu(); onUploadFolder(); }} />
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuItem icon={FolderPlus} label={t("new_folder")} onClick={() => { newMenu.closeContextMenu(); onNewFolder(); }} />
|
||||
<ContextMenuItem icon={FilePlus} label={t("new_text_file")} onClick={() => { newMenu.closeContextMenu(); onNewTextFile(); }} />
|
||||
<ContextMenuItem icon={FilePlus} label={newFileLabel ?? t("new_text_file")} onClick={() => { newMenu.closeContextMenu(); onNewTextFile(); }} />
|
||||
</ContextMenu>
|
||||
|
||||
<ContextMenu ref={itemMenu.menuRef} isOpen={itemMenu.contextMenu.isOpen} position={itemMenu.contextMenu.position} onClose={itemMenu.closeContextMenu}>
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useId, useRef, useState } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Dialog } from "@/components/ui/dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { nameSelectionRange } from "@/components/ui/prompt-dialog";
|
||||
import { getFileIconByName } from "@/components/files/file-icons";
|
||||
import { fileExtension } from "@/hooks/use-wopi-status";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const DEFAULT_BASE_NAME = "new-file";
|
||||
|
||||
/** The kind of document a format makes, for its label; null for an unknown one. */
|
||||
export function formatKind(ext: string): "text" | "document" | "spreadsheet" | "presentation" | "pdf" | null {
|
||||
if (ext === "txt") return "text";
|
||||
if (["docx", "odt", "doc", "rtf"].includes(ext)) return "document";
|
||||
if (["xlsx", "ods", "xls"].includes(ext)) return "spreadsheet";
|
||||
if (["pptx", "odp", "ppt"].includes(ext)) return "presentation";
|
||||
if (ext === "pdf") return "pdf";
|
||||
return null;
|
||||
}
|
||||
|
||||
/** `name` with its extension replaced by `ext` (or added, when it has none). */
|
||||
export function withExtension(name: string, ext: string): string {
|
||||
const dot = name.lastIndexOf(".");
|
||||
const base = dot > 0 ? name.slice(0, dot) : name;
|
||||
return `${base || DEFAULT_BASE_NAME}.${ext}`;
|
||||
}
|
||||
|
||||
interface NewFileDialogProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onSubmit: (name: string) => void;
|
||||
/**
|
||||
* Document formats a WOPI editor can create besides .txt (#1393). Without
|
||||
* any, this is the plain "New text file" prompt.
|
||||
*/
|
||||
formats: string[];
|
||||
validate?: (value: string) => string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* "New file": a name and, with a document editor, the format to start from.
|
||||
* The name decides: picking a format rewrites its extension, and typing an
|
||||
* extension selects the format it names.
|
||||
*/
|
||||
export function NewFileDialog({ isOpen, onClose, onSubmit, formats, validate }: NewFileDialogProps) {
|
||||
const t = useTranslations("files");
|
||||
const id = useId();
|
||||
const choices = formats.length > 0 ? ["txt", ...formats.filter((ext) => ext !== "txt")] : [];
|
||||
const [value, setValue] = useState(`${DEFAULT_BASE_NAME}.txt`);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const focusBaseName = () => {
|
||||
const input = inputRef.current;
|
||||
if (!input) return;
|
||||
input.focus();
|
||||
const [start, end] = nameSelectionRange(input.value, true);
|
||||
input.setSelectionRange(start, end);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) return;
|
||||
setValue(`${DEFAULT_BASE_NAME}.txt`);
|
||||
const timer = setTimeout(focusBaseName, 50);
|
||||
return () => clearTimeout(timer);
|
||||
}, [isOpen]);
|
||||
|
||||
const trimmed = value.trim();
|
||||
const error = trimmed.length > 0 && validate ? validate(trimmed) : null;
|
||||
const canSubmit = trimmed.length > 0 && !error;
|
||||
const errorId = `${id}-error`;
|
||||
const selected = fileExtension(trimmed);
|
||||
|
||||
const pick = (ext: string) => {
|
||||
setValue(withExtension(trimmed, ext));
|
||||
setTimeout(focusBaseName, 0);
|
||||
};
|
||||
|
||||
const label = (ext: string) => {
|
||||
const kind = formatKind(ext);
|
||||
return kind ? t(`format_${kind}`) : ext.toUpperCase();
|
||||
};
|
||||
|
||||
const handleSubmit = (e?: React.FormEvent) => {
|
||||
e?.preventDefault();
|
||||
if (!canSubmit) return;
|
||||
try {
|
||||
onSubmit(trimmed);
|
||||
} finally {
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
isOpen={isOpen}
|
||||
onClose={onClose}
|
||||
title={choices.length > 0 ? t("new_file") : t("new_text_file")}
|
||||
showClose={false}
|
||||
initialFocus={inputRef}
|
||||
onSubmit={handleSubmit}
|
||||
footer={
|
||||
<>
|
||||
<Button type="button" variant="outline" onClick={onClose}>
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
<Button type="submit" variant="default" disabled={!canSubmit}>
|
||||
{t("create")}
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
placeholder={t("file_name")}
|
||||
aria-label={t("file_name")}
|
||||
aria-invalid={error ? true : undefined}
|
||||
aria-describedby={error ? errorId : undefined}
|
||||
className={error ? "mt-4 border-destructive focus-visible:border-destructive" : "mt-4"}
|
||||
/>
|
||||
{error && (
|
||||
<p id={errorId} role="alert" className="mt-1.5 text-xs text-destructive">
|
||||
{error}
|
||||
</p>
|
||||
)}
|
||||
{choices.length > 0 && (
|
||||
<div role="radiogroup" aria-label={t("file_format")} className="mt-4 grid grid-cols-2 gap-2 sm:grid-cols-4">
|
||||
{choices.map((ext) => (
|
||||
<button
|
||||
key={ext}
|
||||
type="button"
|
||||
role="radio"
|
||||
aria-checked={selected === ext}
|
||||
onClick={() => pick(ext)}
|
||||
className={cn(
|
||||
"flex flex-col items-center gap-1 rounded-md border px-2 py-3 text-center transition-colors",
|
||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
||||
selected === ext ? "border-primary bg-primary/10" : "border-border hover:bg-muted",
|
||||
)}
|
||||
>
|
||||
{getFileIconByName(`file.${ext}`, "md")}
|
||||
<span className="text-xs font-medium leading-tight">{label(ext)}</span>
|
||||
<span className="text-[11px] text-muted-foreground">.{ext}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@@ -13,9 +13,11 @@ export interface WopiStatus {
|
||||
enabled: boolean;
|
||||
editExtensions: string[];
|
||||
viewExtensions: string[];
|
||||
/** Formats "New file" can create from a blank template besides .txt (#1393). */
|
||||
newExtensions: string[];
|
||||
}
|
||||
|
||||
const DISABLED: WopiStatus = { enabled: false, editExtensions: [], viewExtensions: [] };
|
||||
const DISABLED: WopiStatus = { enabled: false, editExtensions: [], viewExtensions: [], newExtensions: [] };
|
||||
|
||||
let statusPromise: Promise<WopiStatus> | null = null;
|
||||
|
||||
@@ -29,6 +31,7 @@ function fetchWopiStatus(): Promise<WopiStatus> {
|
||||
enabled: !!data?.enabled,
|
||||
editExtensions: Array.isArray(data?.editExtensions) ? data.editExtensions : [],
|
||||
viewExtensions: Array.isArray(data?.viewExtensions) ? data.viewExtensions : [],
|
||||
newExtensions: Array.isArray(data?.newExtensions) ? data.newExtensions : [],
|
||||
}))
|
||||
.catch(() => {
|
||||
statusPromise = null; // allow a retry on the next mount
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
// @vitest-environment node
|
||||
import { mkdtempSync, writeFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { describe, it, expect, vi, beforeEach, afterEach, type Mock } from 'vitest';
|
||||
import { NextRequest } from 'next/server';
|
||||
import JSZip from 'jszip';
|
||||
|
||||
// #1393: "New file" offers the formats the WOPI editor can edit and has a
|
||||
// blank template for, and serves that template.
|
||||
|
||||
const config = vi.hoisted(() => ({ values: {} as Record<string, unknown> }));
|
||||
|
||||
vi.mock('@/lib/logger', () => ({
|
||||
logger: { warn: () => {}, error: () => {}, info: () => {}, debug: () => {} },
|
||||
}));
|
||||
vi.mock('@/lib/admin/config-manager', () => ({
|
||||
configManager: {
|
||||
ensureLoaded: async () => {},
|
||||
get: (key: string, fallback: unknown) => config.values[key] ?? fallback,
|
||||
},
|
||||
}));
|
||||
vi.mock('@/lib/stalwart/credentials', () => ({ getStalwartCredentials: vi.fn() }));
|
||||
|
||||
import { GET as status } from '@/app/api/wopi/status/route';
|
||||
import { GET as template } from '@/app/api/wopi/template/route';
|
||||
import { getBlankTemplate, getNewFileFormats, parseFormatList } from '@/lib/wopi/new-file';
|
||||
import { getStalwartCredentials } from '@/lib/stalwart/credentials';
|
||||
import type { WopiActions } from '@/lib/wopi/discovery';
|
||||
|
||||
const action = (name: string, ext: string) =>
|
||||
`<action name="${name}" ext="${ext}" urlsrc="https://office.example/edit?"/>`;
|
||||
|
||||
// What Collabora advertises: PDF can be viewed and commented, not edited.
|
||||
const COLLABORA = `<wopi-discovery><net-zone><app name="x">${[
|
||||
action('edit', 'docx'), action('editnew', 'docx'), action('edit', 'xlsx'), action('edit', 'pptx'),
|
||||
action('edit', 'odt'), action('edit', 'ods'), action('edit', 'odp'), action('edit', 'txt'),
|
||||
action('edit', 'rtf'), action('view', 'pdf'), action('view_comment', 'pdf'),
|
||||
].join('')}</app></net-zone></wopi-discovery>`;
|
||||
|
||||
const actions = (edit: string[], view: string[] = []): WopiActions => ({
|
||||
edit: Object.fromEntries(edit.map((ext) => [ext, 'https://office.example/edit?'])),
|
||||
view: Object.fromEntries(view.map((ext) => [ext, 'https://office.example/view?'])),
|
||||
});
|
||||
|
||||
let editorSeq = 0;
|
||||
function useEditor(xml: string) {
|
||||
// A fresh editor URL each time: discovery is cached per URL.
|
||||
config.values.wopiClientUrl = `https://office${++editorSeq}.example`;
|
||||
(globalThis.fetch as Mock).mockResolvedValue(new Response(xml, { status: 200 }));
|
||||
}
|
||||
|
||||
const request = (url: string) => new NextRequest(`https://mail.example${url}`);
|
||||
|
||||
beforeEach(() => {
|
||||
config.values = {};
|
||||
vi.stubGlobal('fetch', vi.fn());
|
||||
(getStalwartCredentials as Mock).mockResolvedValue({ serverUrl: 'https://jmap.example', username: 'u', authHeader: 'Basic x' });
|
||||
});
|
||||
afterEach(() => vi.unstubAllGlobals());
|
||||
|
||||
describe('new file formats (#1393)', () => {
|
||||
it('offers the formats the editor can edit and has a template for', async () => {
|
||||
// rtf has no template and txt needs none, pdf is view-only.
|
||||
expect(await getNewFileFormats(actions(['txt', 'rtf', 'odt', 'docx', 'pptx', 'xlsx'], ['pdf'])))
|
||||
.toEqual(['docx', 'xlsx', 'pptx', 'odt']);
|
||||
expect(await getNewFileFormats(actions(['pdf', 'docx']))).toEqual(['docx', 'pdf']);
|
||||
});
|
||||
|
||||
it('takes the admin list instead of discovery, still only with a template', async () => {
|
||||
config.values.wopiNewFileFormats = ' .DOCX, ods ; vsdx';
|
||||
expect(await getNewFileFormats(actions(['docx', 'xlsx', 'pptx']))).toEqual(['docx', 'ods']);
|
||||
expect(parseFormatList('docx,,docx, ../x, .odt')).toEqual(['docx', 'odt']);
|
||||
});
|
||||
|
||||
it('adds and replaces templates from the template directory', async () => {
|
||||
const dir = mkdtempSync(path.join(tmpdir(), 'bw-wopi-tpl-'));
|
||||
writeFileSync(path.join(dir, 'new.vsdx'), 'visio');
|
||||
writeFileSync(path.join(dir, 'new.docx'), 'letterhead');
|
||||
writeFileSync(path.join(dir, 'other.odg'), 'not a template name');
|
||||
config.values.wopiTemplateDir = dir;
|
||||
|
||||
expect(await getNewFileFormats(actions(['docx', 'vsdx', 'odg']))).toEqual(['docx', 'vsdx']);
|
||||
const docx = await getBlankTemplate('docx');
|
||||
expect(Buffer.from(docx!.data).toString()).toBe('letterhead');
|
||||
expect(docx!.type).toBe('application/vnd.openxmlformats-officedocument.wordprocessingml.document');
|
||||
expect(Buffer.from((await getBlankTemplate('vsdx'))!.data).toString()).toBe('visio');
|
||||
// Formats the directory doesn't have still come from the shipped set.
|
||||
expect((await getBlankTemplate('xlsx'))!.data.length).toBeGreaterThan(1000);
|
||||
expect(await getBlankTemplate('../new')).toBeNull();
|
||||
});
|
||||
|
||||
it('ships blank templates the editors can open', async () => {
|
||||
const parts: Record<string, string> = {
|
||||
docx: 'word/document.xml', xlsx: 'xl/workbook.xml', pptx: 'ppt/presentation.xml',
|
||||
odt: 'content.xml', ods: 'content.xml', odp: 'content.xml',
|
||||
};
|
||||
for (const [ext, part] of Object.entries(parts)) {
|
||||
const zip = await JSZip.loadAsync((await getBlankTemplate(ext))!.data);
|
||||
expect(zip.file(part), `${ext} has ${part}`).not.toBeNull();
|
||||
if (ext.startsWith('od')) {
|
||||
// ODF: an uncompressed mimetype entry first.
|
||||
expect(Object.keys(zip.files)[0]).toBe('mimetype');
|
||||
expect(await zip.file('mimetype')!.async('string')).toBe(`application/vnd.oasis.opendocument.${{ odt: 'text', ods: 'spreadsheet', odp: 'presentation' }[ext]}`);
|
||||
}
|
||||
// No language of their own: a new document takes the editor's.
|
||||
for (const file of Object.values(zip.files).filter((f) => f.name.endsWith('.xml'))) {
|
||||
expect(await file.async('string'), `${ext} ${file.name}`).not.toMatch(/en-GB|en-US|fo:language=|<w:lang\b/);
|
||||
}
|
||||
}
|
||||
expect(Buffer.from((await getBlankTemplate('pdf'))!.data).subarray(0, 5).toString()).toBe('%PDF-');
|
||||
});
|
||||
|
||||
it('lists the creatable formats in /api/wopi/status', async () => {
|
||||
useEditor(COLLABORA);
|
||||
const body = await (await status(request('/api/wopi/status'))).json();
|
||||
expect(body.newExtensions).toEqual(['docx', 'xlsx', 'pptx', 'odt', 'ods', 'odp']);
|
||||
});
|
||||
|
||||
it('serves a template only for a format it offers', async () => {
|
||||
useEditor(COLLABORA);
|
||||
const res = await template(request('/api/wopi/template?ext=DOCX'));
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.headers.get('content-type')).toBe('application/vnd.openxmlformats-officedocument.wordprocessingml.document');
|
||||
expect((await JSZip.loadAsync(await res.arrayBuffer())).file('word/document.xml')).not.toBeNull();
|
||||
|
||||
expect((await template(request('/api/wopi/template?ext=pdf'))).status).toBe(404);
|
||||
expect((await template(request('/api/wopi/template?ext=rtf'))).status).toBe(404);
|
||||
});
|
||||
|
||||
it('serves nothing without a session or an editor', async () => {
|
||||
useEditor(COLLABORA);
|
||||
(getStalwartCredentials as Mock).mockResolvedValueOnce(null);
|
||||
expect((await template(request('/api/wopi/template?ext=docx'))).status).toBe(401);
|
||||
|
||||
config.values.wopiClientUrl = '';
|
||||
expect((await template(request('/api/wopi/template?ext=docx'))).status).toBe(404);
|
||||
expect((await (await status(request('/api/wopi/status'))).json()).newExtensions).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -373,6 +373,12 @@ export const CONFIG_ENV_MAP: Record<string, { envVar: string; fileEnvVar?: strin
|
||||
// than the browser (docker networks, split DNS). The base path of a
|
||||
// sub-path install is added to a bare origin (#1130).
|
||||
wopiHostUrl: { envVar: 'WOPI_HOST_URL', type: 'url', defaultValue: '' },
|
||||
// "New file" formats (#1393). Empty = every format the editor can edit and
|
||||
// a blank template exists for; otherwise a comma-separated list of
|
||||
// extensions. `wopiTemplateDir` is a server directory whose `new.<ext>`
|
||||
// files replace the shipped blank templates or add formats.
|
||||
wopiNewFileFormats: { envVar: 'WOPI_NEW_FILE_FORMATS', type: 'string', defaultValue: '' },
|
||||
wopiTemplateDir: { envVar: 'WOPI_TEMPLATE_DIR', type: 'string', defaultValue: '' },
|
||||
};
|
||||
|
||||
/** Keys that should never be exposed to the client config endpoint */
|
||||
|
||||
@@ -0,0 +1,731 @@
|
||||
/**
|
||||
* Blank documents for "New file" with a WOPI editor (#1393): a new .docx
|
||||
* or .ods is not a zero-byte file, so the file is created from one of these.
|
||||
*
|
||||
* Made with LibreOffice (Collabora Online convert-to, lang en-GB for A4
|
||||
* pages) from empty files, then stripped of their language tags and
|
||||
* creation date so a new document takes the editor's language. Generated;
|
||||
* an admin can replace any of them with `wopiTemplateDir`.
|
||||
*/
|
||||
|
||||
export const BLANK_TEMPLATES: Record<string, { type: string; base64: string }> = {
|
||||
docx: {
|
||||
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
base64:
|
||||
'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',
|
||||
},
|
||||
xlsx: {
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
base64:
|
||||
'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',
|
||||
},
|
||||
pptx: {
|
||||
type: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
base64:
|
||||
'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',
|
||||
},
|
||||
odt: {
|
||||
type: 'application/vnd.oasis.opendocument.text',
|
||||
base64:
|
||||
'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',
|
||||
},
|
||||
ods: {
|
||||
type: 'application/vnd.oasis.opendocument.spreadsheet',
|
||||
base64:
|
||||
'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' +
|
||||
'AAAKAAoATwIAAAkYAAAAAA==',
|
||||
},
|
||||
odp: {
|
||||
type: 'application/vnd.oasis.opendocument.presentation',
|
||||
base64:
|
||||
'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',
|
||||
},
|
||||
pdf: {
|
||||
type: 'application/pdf',
|
||||
base64:
|
||||
'JVBERi0xLjcKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0ZpbHRlci9GbGF0ZURlY29kZT4+CnN0cmVhbQp4nDPQ' +
|
||||
'M1Qo5ypUMFAw0DMwslAwtTTVMzI3U7AwMdSzMDNUKErlCtdSyOMKVAAAtyYIrwplbmRzdHJlYW0KZW5kb2JqCgozIDAgb2JqCjUw' +
|
||||
'CmVuZG9iagoKNSAwIG9iago8PAo+PgplbmRvYmoKCjYgMCBvYmoKPDwvRm9udCA1IDAgUi9Qcm9jU2V0Wy9QREYvVGV4dF0KPj4K' +
|
||||
'ZW5kb2JqCgoxIDAgb2JqCjw8L1R5cGUvUGFnZS9QYXJlbnQgNCAwIFIvUmVzb3VyY2VzIDYgMCBSL01lZGlhQm94WzAgMCA1OTUu' +
|
||||
'MzAzOTM3MDA3ODc0IDg0MS44ODk3NjM3Nzk1MjhdL1RhYnMvUwovQ29udGVudHMgMiAwIFI+PgplbmRvYmoKCjcgMCBvYmoKPDwv' +
|
||||
'VHlwZS9NZXRhZGF0YS9TdWJ0eXBlL1hNTC9MZW5ndGggNDk0Mj4+CnN0cmVhbQo8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1' +
|
||||
'TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/Pgo8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIj4KIDxyZGY6UkRGIHht' +
|
||||
'bG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgPHJkZjpEZXNjcmlwdGlvbiBy' +
|
||||
'ZGY6YWJvdXQ9IiIgeG1sbnM6cGRmPSJodHRwOi8vbnMuYWRvYmUuY29tL3BkZi8xLjMvIj4KICAgPHBkZjpQcm9kdWNlcj5Db2xs' +
|
||||
'YWJvcmEgT2ZmaWNlIDI2LjA0LjMuMiAoWDg2XzY0KTwvcGRmOlByb2R1Y2VyPgogICA8cGRmOlBERlZlcnNpb24+MS43PC9wZGY6' +
|
||||
'UERGVmVyc2lvbj4KICA8L3JkZjpEZXNjcmlwdGlvbj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9' +
|
||||
'Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iPgogICA8eG1wOkNyZWF0b3JUb29sPldyaXRlcjwveG1wOkNyZWF0b3JUb29s' +
|
||||
'PgogICA8eG1wOkNyZWF0ZURhdGU+MjAyNi0xMC0yOFQyMjoyODo1MFo8L3htcDpDcmVhdGVEYXRlPgogICA8eG1wOk1vZGlmeURh' +
|
||||
'dGU+MjAyNi0xMC0yOFQyMjoyODo1MFo8L3htcDpNb2RpZnlEYXRlPgogICA8eG1wOk1ldGFkYXRhRGF0ZT4yMDI2LTEwLTI4VDIy' +
|
||||
'OjI4OjUwWjwveG1wOk1ldGFkYXRhRGF0ZT4KICA8L3JkZjpEZXNjcmlwdGlvbj4KIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
|
||||
'ICAgICAgICAgICAgICAgICAgCjw/eHBhY2tldCBlbmQ9InciPz4KCmVuZHN0cmVhbQplbmRvYmoKCjQgMCBvYmoKPDwvVHlwZS9Q' +
|
||||
'YWdlcwovUmVzb3VyY2VzIDYgMCBSCi9LaWRzWyAxIDAgUiBdCi9Db3VudCAxPj4KZW5kb2JqCgo4IDAgb2JqCjw8L1R5cGUvQ2F0' +
|
||||
'YWxvZy9QYWdlcyA0IDAgUgovTGFuZyhlbi1HQikKL01ldGFkYXRhIDcgMCBSPj4KZW5kb2JqCgo5IDAgb2JqCjw8L0NyZWF0b3I8' +
|
||||
'RkVGRjAwNTcwMDcyMDA2OTAwNzQwMDY1MDA3Mj4vUHJvZHVjZXI8RkVGRjAwNDMwMDZGMDA2QzAwNkMwMDYxMDA2MjAwNkYwMDcy' +
|
||||
'MDA2MTAwMjAwMDRGMDA2NjAwNjYwMDY5MDA2MzAwNjUwMDIwMDAzMjAwMzYwMDJFMDAzMDAwMzQwMDJFMDAzMzAwMkUwMDMyMDAy' +
|
||||
'MDAwMjgwMDU4MDAzODAwMzYwMDVGMDAzNjAwMzQwMDI5Pi9DcmVhdGlvbkRhdGUoRDoyMDI2MTAyODIyMjg1MFonKT4+CmVuZG9i' +
|
||||
'agoKeHJlZgowIDEwCjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDIzMyAwMDAwMCBuIAowMDAwMDAwMDE5IDAwMDAwIG4gCjAw' +
|
||||
'MDAwMDAxNDAgMDAwMDAgbiAKMDAwMDAwNTM4MyAwMDAwMCBuIAowMDAwMDAwMTU5IDAwMDAwIG4gCjAwMDAwMDAxODEgMDAwMDAg' +
|
||||
'biAKMDAwMDAwMDM2NCAwMDAwMCBuIAowMDAwMDA1NDU2IDAwMDAwIG4gCjAwMDAwMDU1MzEgMDAwMDAgbiAKdHJhaWxlcgo8PC9T' +
|
||||
'aXplIDEwL1Jvb3QgOCAwIFIKL0luZm8gOSAwIFIKL0lEIFsgPDZCRTZEOTlGQzUxNzNDRTREQTQ1N0UwNjg5OTA4NEJBPgo8NkJF' +
|
||||
'NkQ5OUZDNTE3M0NFNERBNDU3RTA2ODk5MDg0QkE+IF0KL0RvY0NoZWNrc3VtIC8zQzM4MzIyRDAxMzdGMzZEMUIzMDNGQzUxOEEx' +
|
||||
'QjhEQQo+PgpzdGFydHhyZWYKNTc3OAolJUVPRgo=',
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,86 @@
|
||||
import { readFile, readdir } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { configManager } from '@/lib/admin/config-manager';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { BLANK_TEMPLATES } from '@/lib/wopi/blank-templates';
|
||||
import type { WopiActions } from '@/lib/wopi/discovery';
|
||||
|
||||
/**
|
||||
* The formats "New file" offers next to .txt when a WOPI editor is
|
||||
* configured (#1393), and the blank file each one starts from.
|
||||
*
|
||||
* A format is offered when the editor has an "edit" action for it (a
|
||||
* view-only one could be created but not filled in) and there is a blank
|
||||
* template for it: one shipped in blank-templates.ts, or `new.<ext>` in the
|
||||
* admin's `wopiTemplateDir` (ONLYOFFICE's document-templates/new/<locale>
|
||||
* folders use that name). `wopiNewFileFormats` replaces the discovery part
|
||||
* with the admin's own list.
|
||||
*/
|
||||
|
||||
const EXTENSION = /^[a-z0-9]{1,10}$/;
|
||||
|
||||
export interface BlankTemplate {
|
||||
type: string;
|
||||
data: Uint8Array;
|
||||
}
|
||||
|
||||
async function getTemplateDir(): Promise<string> {
|
||||
await configManager.ensureLoaded();
|
||||
return configManager.get<string>('wopiTemplateDir', '').trim();
|
||||
}
|
||||
|
||||
/** The admin's format list, lowercased and without dots; empty when unset. */
|
||||
export function parseFormatList(value: string): string[] {
|
||||
const formats = value
|
||||
.split(/[\s,;]+/)
|
||||
.map((ext) => ext.trim().replace(/^\./, '').toLowerCase())
|
||||
.filter((ext) => EXTENSION.test(ext));
|
||||
return Array.from(new Set(formats));
|
||||
}
|
||||
|
||||
/** Extensions with a `new.<ext>` file in the template directory. */
|
||||
async function templateDirFormats(dir: string): Promise<string[]> {
|
||||
if (!dir) return [];
|
||||
try {
|
||||
return (await readdir(dir))
|
||||
.map((name) => /^new\.([^.]+)$/.exec(name)?.[1] ?? '')
|
||||
.filter((ext) => EXTENSION.test(ext));
|
||||
} catch (error) {
|
||||
logger.warn('WOPI template directory unreadable', {
|
||||
dir,
|
||||
error: error instanceof Error ? error.message : 'Unknown',
|
||||
});
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/** The extensions "New file" offers besides .txt, in a stable order. */
|
||||
export async function getNewFileFormats(actions: WopiActions): Promise<string[]> {
|
||||
await configManager.ensureLoaded();
|
||||
const override = parseFormatList(configManager.get<string>('wopiNewFileFormats', ''));
|
||||
const available = new Set([...Object.keys(BLANK_TEMPLATES), ...await templateDirFormats(await getTemplateDir())]);
|
||||
const wanted = override.length > 0 ? override : Object.keys(actions.edit);
|
||||
const formats = wanted.filter((ext) => ext !== 'txt' && available.has(ext));
|
||||
// Shipped formats first, in their own order (documents, spreadsheets,
|
||||
// presentations, then ODF), then the admin's extras.
|
||||
const order = Object.keys(BLANK_TEMPLATES);
|
||||
const rank = (ext: string) => (order.includes(ext) ? order.indexOf(ext) : order.length);
|
||||
return formats.sort((a, b) => rank(a) - rank(b));
|
||||
}
|
||||
|
||||
/** The blank file a new document of this format starts from, or null. */
|
||||
export async function getBlankTemplate(ext: string): Promise<BlankTemplate | null> {
|
||||
if (!EXTENSION.test(ext)) return null;
|
||||
const shipped = BLANK_TEMPLATES[ext];
|
||||
const dir = await getTemplateDir();
|
||||
if (dir) {
|
||||
try {
|
||||
const data = await readFile(path.join(dir, `new.${ext}`));
|
||||
return { type: shipped?.type ?? 'application/octet-stream', data: new Uint8Array(data) };
|
||||
} catch {
|
||||
// No admin template for this format: fall back to the shipped one.
|
||||
}
|
||||
}
|
||||
if (!shipped) return null;
|
||||
return { type: shipped.type, data: new Uint8Array(Buffer.from(shipped.base64, 'base64')) };
|
||||
}
|
||||
@@ -4619,6 +4619,13 @@
|
||||
"paste_success": "تم اللصق بنجاح",
|
||||
"paste_error": "فشل اللصق",
|
||||
"new_text_file": "ملف نصي جديد",
|
||||
"new_file": "ملف جديد",
|
||||
"file_format": "التنسيق",
|
||||
"format_text": "ملف نصي",
|
||||
"format_document": "مستند",
|
||||
"format_spreadsheet": "جدول بيانات",
|
||||
"format_presentation": "عرض تقديمي",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "اسم الملف",
|
||||
"retry": "إعادة المحاولة",
|
||||
"refresh": "تحديث",
|
||||
|
||||
@@ -4619,6 +4619,13 @@
|
||||
"paste_success": "Enganxat correctament",
|
||||
"paste_error": "No s'ha pogut enganxar",
|
||||
"new_text_file": "Fitxer de text nou",
|
||||
"new_file": "Fitxer nou",
|
||||
"file_format": "Format",
|
||||
"format_text": "Fitxer de text",
|
||||
"format_document": "Document",
|
||||
"format_spreadsheet": "Full de càlcul",
|
||||
"format_presentation": "Presentació",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Nom del fitxer",
|
||||
"retry": "Reintenta",
|
||||
"refresh": "Actualitza",
|
||||
|
||||
@@ -4489,6 +4489,13 @@
|
||||
"paste_success": "Úspěšně vloženo",
|
||||
"paste_error": "Vložení selhalo",
|
||||
"new_text_file": "Nový textový soubor",
|
||||
"new_file": "Nový soubor",
|
||||
"file_format": "Formát",
|
||||
"format_text": "Textový soubor",
|
||||
"format_document": "Dokument",
|
||||
"format_spreadsheet": "Tabulka",
|
||||
"format_presentation": "Prezentace",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Název souboru",
|
||||
"retry": "Opakovat",
|
||||
"refresh": "Obnovit",
|
||||
|
||||
@@ -4618,6 +4618,13 @@
|
||||
"paste_success": "Indsat",
|
||||
"paste_error": "Kunne ikke indsætte",
|
||||
"new_text_file": "Ny tekstfil",
|
||||
"new_file": "Ny fil",
|
||||
"file_format": "Format",
|
||||
"format_text": "Tekstfil",
|
||||
"format_document": "Dokument",
|
||||
"format_spreadsheet": "Regneark",
|
||||
"format_presentation": "Præsentation",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Filnavn",
|
||||
"retry": "Prøv igen",
|
||||
"refresh": "Opdatér",
|
||||
|
||||
@@ -4489,6 +4489,13 @@
|
||||
"paste_success": "Erfolgreich eingefügt",
|
||||
"paste_error": "Einfügen fehlgeschlagen",
|
||||
"new_text_file": "Neue Textdatei",
|
||||
"new_file": "Neue Datei",
|
||||
"file_format": "Format",
|
||||
"format_text": "Textdatei",
|
||||
"format_document": "Dokument",
|
||||
"format_spreadsheet": "Tabelle",
|
||||
"format_presentation": "Präsentation",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Dateiname",
|
||||
"retry": "Wiederholen",
|
||||
"refresh": "Aktualisieren",
|
||||
|
||||
@@ -4619,6 +4619,13 @@
|
||||
"paste_success": "Pasted",
|
||||
"paste_error": "Couldn't paste",
|
||||
"new_text_file": "New text file",
|
||||
"new_file": "New file",
|
||||
"file_format": "Format",
|
||||
"format_text": "Text file",
|
||||
"format_document": "Document",
|
||||
"format_spreadsheet": "Spreadsheet",
|
||||
"format_presentation": "Presentation",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "File name",
|
||||
"retry": "Retry",
|
||||
"refresh": "Refresh",
|
||||
|
||||
@@ -4489,6 +4489,13 @@
|
||||
"paste_success": "Pegado correctamente",
|
||||
"paste_error": "Error al pegar",
|
||||
"new_text_file": "Nuevo archivo de texto",
|
||||
"new_file": "Nuevo archivo",
|
||||
"file_format": "Formato",
|
||||
"format_text": "Archivo de texto",
|
||||
"format_document": "Documento",
|
||||
"format_spreadsheet": "Hoja de cálculo",
|
||||
"format_presentation": "Presentación",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Nombre del archivo",
|
||||
"retry": "Reintentar",
|
||||
"refresh": "Actualizar",
|
||||
|
||||
@@ -4619,6 +4619,13 @@
|
||||
"paste_success": "Edukalt kleebitud",
|
||||
"paste_error": "Kleepimine ebaõnnestus",
|
||||
"new_text_file": "Uus tekstifail",
|
||||
"new_file": "Uus fail",
|
||||
"file_format": "Vorming",
|
||||
"format_text": "Tekstifail",
|
||||
"format_document": "Dokument",
|
||||
"format_spreadsheet": "Arvutustabel",
|
||||
"format_presentation": "Esitlus",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Faili nimi",
|
||||
"retry": "Proovi uuesti",
|
||||
"refresh": "Värskenda",
|
||||
|
||||
@@ -4619,6 +4619,13 @@
|
||||
"paste_success": "با موفقیت چسبانده شد",
|
||||
"paste_error": "چسباندن ناموفق بود",
|
||||
"new_text_file": "فایل متنی جدید",
|
||||
"new_file": "فایل جدید",
|
||||
"file_format": "قالب",
|
||||
"format_text": "فایل متنی",
|
||||
"format_document": "سند",
|
||||
"format_spreadsheet": "صفحهگسترده",
|
||||
"format_presentation": "ارائه",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "نام فایل",
|
||||
"retry": "تلاش مجدد",
|
||||
"refresh": "بازنشانی",
|
||||
|
||||
@@ -4489,6 +4489,13 @@
|
||||
"paste_success": "Collé avec succès",
|
||||
"paste_error": "Échec du collage",
|
||||
"new_text_file": "Nouveau fichier texte",
|
||||
"new_file": "Nouveau fichier",
|
||||
"file_format": "Format",
|
||||
"format_text": "Fichier texte",
|
||||
"format_document": "Document",
|
||||
"format_spreadsheet": "Feuille de calcul",
|
||||
"format_presentation": "Présentation",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Nom du fichier",
|
||||
"retry": "Réessayer",
|
||||
"refresh": "Actualiser",
|
||||
|
||||
@@ -4406,6 +4406,13 @@
|
||||
"paste_success": "הודבק בהצלחה",
|
||||
"paste_error": "ההדבקה נכשלה",
|
||||
"new_text_file": "קובץ טקסט חדש",
|
||||
"new_file": "קובץ חדש",
|
||||
"file_format": "פורמט",
|
||||
"format_text": "קובץ טקסט",
|
||||
"format_document": "מסמך",
|
||||
"format_spreadsheet": "גיליון אלקטרוני",
|
||||
"format_presentation": "מצגת",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "שם הקובץ",
|
||||
"retry": "נסה שוב",
|
||||
"refresh": "רענן",
|
||||
|
||||
@@ -4619,6 +4619,13 @@
|
||||
"paste_success": "Sikeresen beillesztve",
|
||||
"paste_error": "Nem sikerült beilleszteni",
|
||||
"new_text_file": "Új szöveges fájl",
|
||||
"new_file": "Új fájl",
|
||||
"file_format": "Formátum",
|
||||
"format_text": "Szöveges fájl",
|
||||
"format_document": "Dokumentum",
|
||||
"format_spreadsheet": "Táblázat",
|
||||
"format_presentation": "Bemutató",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Fájl neve",
|
||||
"retry": "Újra",
|
||||
"refresh": "Frissítés",
|
||||
|
||||
@@ -4489,6 +4489,13 @@
|
||||
"paste_success": "Incollato con successo",
|
||||
"paste_error": "Incollaggio non riuscito",
|
||||
"new_text_file": "Nuovo file di testo",
|
||||
"new_file": "Nuovo file",
|
||||
"file_format": "Formato",
|
||||
"format_text": "File di testo",
|
||||
"format_document": "Documento",
|
||||
"format_spreadsheet": "Foglio di calcolo",
|
||||
"format_presentation": "Presentazione",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Nome del file",
|
||||
"retry": "Riprova",
|
||||
"refresh": "Aggiorna",
|
||||
|
||||
@@ -4489,6 +4489,13 @@
|
||||
"paste_success": "正常に貼り付けました",
|
||||
"paste_error": "貼り付けに失敗しました",
|
||||
"new_text_file": "新規テキストファイル",
|
||||
"new_file": "新規ファイル",
|
||||
"file_format": "形式",
|
||||
"format_text": "テキストファイル",
|
||||
"format_document": "ドキュメント",
|
||||
"format_spreadsheet": "スプレッドシート",
|
||||
"format_presentation": "プレゼンテーション",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "ファイル名",
|
||||
"retry": "再試行",
|
||||
"refresh": "更新",
|
||||
|
||||
@@ -4489,6 +4489,13 @@
|
||||
"paste_success": "붙여넣기 성공",
|
||||
"paste_error": "붙여넣기에 실패했어요",
|
||||
"new_text_file": "새 텍스트 파일",
|
||||
"new_file": "새 파일",
|
||||
"file_format": "형식",
|
||||
"format_text": "텍스트 파일",
|
||||
"format_document": "문서",
|
||||
"format_spreadsheet": "스프레드시트",
|
||||
"format_presentation": "프레젠테이션",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "파일 이름",
|
||||
"retry": "재시도",
|
||||
"refresh": "새로고침",
|
||||
|
||||
@@ -4489,6 +4489,13 @@
|
||||
"paste_success": "Ielīmēts sekmīgi",
|
||||
"paste_error": "Neizdevās ielīmēt",
|
||||
"new_text_file": "Jauns teksta fails",
|
||||
"new_file": "Jauns fails",
|
||||
"file_format": "Formāts",
|
||||
"format_text": "Teksta fails",
|
||||
"format_document": "Dokuments",
|
||||
"format_spreadsheet": "Izklājlapa",
|
||||
"format_presentation": "Prezentācija",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Faila nosaukums",
|
||||
"retry": "Mēģināt vēlreiz",
|
||||
"refresh": "Atsvaidzināt",
|
||||
|
||||
@@ -4619,6 +4619,13 @@
|
||||
"paste_success": "Амжилттай буулгалаа",
|
||||
"paste_error": "Буулгаж чадсангүй",
|
||||
"new_text_file": "Шинэ текст файл",
|
||||
"new_file": "Шинэ файл",
|
||||
"file_format": "Формат",
|
||||
"format_text": "Текст файл",
|
||||
"format_document": "Баримт бичиг",
|
||||
"format_spreadsheet": "Хүснэгт",
|
||||
"format_presentation": "Танилцуулга",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Файлын нэр",
|
||||
"retry": "Дахин оролдох",
|
||||
"refresh": "Сэргээх",
|
||||
|
||||
@@ -4619,6 +4619,13 @@
|
||||
"paste_success": "Limt inn",
|
||||
"paste_error": "Kunne ikke lime inn",
|
||||
"new_text_file": "Ny tekstfil",
|
||||
"new_file": "Ny fil",
|
||||
"file_format": "Format",
|
||||
"format_text": "Tekstfil",
|
||||
"format_document": "Dokument",
|
||||
"format_spreadsheet": "Regneark",
|
||||
"format_presentation": "Presentasjon",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Filnavn",
|
||||
"retry": "Prøv på nytt",
|
||||
"refresh": "Oppdater",
|
||||
|
||||
@@ -4489,6 +4489,13 @@
|
||||
"paste_success": "Succesvol geplakt",
|
||||
"paste_error": "Plakken mislukt",
|
||||
"new_text_file": "Nieuw tekstbestand",
|
||||
"new_file": "Nieuw bestand",
|
||||
"file_format": "Formaat",
|
||||
"format_text": "Tekstbestand",
|
||||
"format_document": "Document",
|
||||
"format_spreadsheet": "Spreadsheet",
|
||||
"format_presentation": "Presentatie",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Bestandsnaam",
|
||||
"retry": "Opnieuw proberen",
|
||||
"refresh": "Vernieuwen",
|
||||
|
||||
@@ -4489,6 +4489,13 @@
|
||||
"paste_success": "Wklejono pomyślnie",
|
||||
"paste_error": "Nie udało się wkleić",
|
||||
"new_text_file": "Nowy plik tekstowy",
|
||||
"new_file": "Nowy plik",
|
||||
"file_format": "Format",
|
||||
"format_text": "Plik tekstowy",
|
||||
"format_document": "Dokument",
|
||||
"format_spreadsheet": "Arkusz kalkulacyjny",
|
||||
"format_presentation": "Prezentacja",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Nazwa pliku",
|
||||
"retry": "Ponów",
|
||||
"refresh": "Odśwież",
|
||||
|
||||
@@ -4489,6 +4489,13 @@
|
||||
"paste_success": "Colado com sucesso",
|
||||
"paste_error": "Falha ao colar",
|
||||
"new_text_file": "Novo arquivo de texto",
|
||||
"new_file": "Novo arquivo",
|
||||
"file_format": "Formato",
|
||||
"format_text": "Arquivo de texto",
|
||||
"format_document": "Documento",
|
||||
"format_spreadsheet": "Planilha",
|
||||
"format_presentation": "Apresentação",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Nome do arquivo",
|
||||
"retry": "Tentar novamente",
|
||||
"refresh": "Atualizar",
|
||||
|
||||
@@ -4619,6 +4619,13 @@
|
||||
"paste_success": "S-a lipit cu succes",
|
||||
"paste_error": "Nu s-a putut insera",
|
||||
"new_text_file": "Fișier text nou",
|
||||
"new_file": "Fișier nou",
|
||||
"file_format": "Format",
|
||||
"format_text": "Fișier text",
|
||||
"format_document": "Document",
|
||||
"format_spreadsheet": "Foaie de calcul",
|
||||
"format_presentation": "Prezentare",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Numele fișierului",
|
||||
"retry": "Reîncearcă",
|
||||
"refresh": "Reîmprospătează",
|
||||
|
||||
@@ -4489,6 +4489,13 @@
|
||||
"paste_success": "Вставлено успешно",
|
||||
"paste_error": "Не удалось вставить",
|
||||
"new_text_file": "Новый текстовый файл",
|
||||
"new_file": "Новый файл",
|
||||
"file_format": "Формат",
|
||||
"format_text": "Текстовый файл",
|
||||
"format_document": "Документ",
|
||||
"format_spreadsheet": "Таблица",
|
||||
"format_presentation": "Презентация",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Имя файла",
|
||||
"retry": "Повторить",
|
||||
"refresh": "Обновить",
|
||||
|
||||
@@ -4619,6 +4619,13 @@
|
||||
"paste_success": "Úspešne vložené",
|
||||
"paste_error": "Vloženie zlyhalo",
|
||||
"new_text_file": "Nový textový súbor",
|
||||
"new_file": "Nový súbor",
|
||||
"file_format": "Formát",
|
||||
"format_text": "Textový súbor",
|
||||
"format_document": "Dokument",
|
||||
"format_spreadsheet": "Tabuľka",
|
||||
"format_presentation": "Prezentácia",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Názov súboru",
|
||||
"retry": "Opakovať",
|
||||
"refresh": "Obnoviť",
|
||||
|
||||
@@ -1820,6 +1820,13 @@
|
||||
"new_folder_name": "ชื่อโฟลเดอร์",
|
||||
"new_name": "ชื่อใหม่",
|
||||
"new_text_file": "ไฟล์ข้อความใหม่",
|
||||
"new_file": "ไฟล์ใหม่",
|
||||
"file_format": "รูปแบบ",
|
||||
"format_text": "ไฟล์ข้อความ",
|
||||
"format_document": "เอกสาร",
|
||||
"format_spreadsheet": "สเปรดชีต",
|
||||
"format_presentation": "งานนำเสนอ",
|
||||
"format_pdf": "PDF",
|
||||
"no_accounts": "ไม่มีบัญชีที่เชื่อมต่ออยู่",
|
||||
"no_results": "ไม่พบไฟล์ที่ตรงกับการค้นหา",
|
||||
"no_results_for": "ไม่มีไฟล์ในโฟลเดอร์นี้ที่ตรงกับ “{query}”",
|
||||
|
||||
@@ -4618,6 +4618,13 @@
|
||||
"paste_success": "Başarıyla yapıştırıldı",
|
||||
"paste_error": "Yapıştırılamadı",
|
||||
"new_text_file": "Yeni Metin Dosyası",
|
||||
"new_file": "Yeni Dosya",
|
||||
"file_format": "Biçim",
|
||||
"format_text": "Metin dosyası",
|
||||
"format_document": "Belge",
|
||||
"format_spreadsheet": "Elektronik tablo",
|
||||
"format_presentation": "Sunu",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Dosya adı",
|
||||
"retry": "Yeniden dene",
|
||||
"refresh": "Yenile",
|
||||
|
||||
@@ -4489,6 +4489,13 @@
|
||||
"paste_success": "Вставлено успішно",
|
||||
"paste_error": "Не вдалося вставити",
|
||||
"new_text_file": "Новий текстовий файл",
|
||||
"new_file": "Новий файл",
|
||||
"file_format": "Формат",
|
||||
"format_text": "Текстовий файл",
|
||||
"format_document": "Документ",
|
||||
"format_spreadsheet": "Таблиця",
|
||||
"format_presentation": "Презентація",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "Ім'я файлу",
|
||||
"retry": "Повторіть спробу",
|
||||
"refresh": "Оновити",
|
||||
|
||||
@@ -4619,6 +4619,13 @@
|
||||
"paste_success": "貼上成功",
|
||||
"paste_error": "貼上失敗",
|
||||
"new_text_file": "新增文字檔案",
|
||||
"new_file": "新增檔案",
|
||||
"file_format": "格式",
|
||||
"format_text": "文字檔案",
|
||||
"format_document": "文件",
|
||||
"format_spreadsheet": "試算表",
|
||||
"format_presentation": "簡報",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "檔名",
|
||||
"retry": "重試",
|
||||
"refresh": "重新整理",
|
||||
|
||||
@@ -4489,6 +4489,13 @@
|
||||
"paste_success": "粘贴成功",
|
||||
"paste_error": "粘贴失败",
|
||||
"new_text_file": "新建文本文件",
|
||||
"new_file": "新建文件",
|
||||
"file_format": "格式",
|
||||
"format_text": "文本文件",
|
||||
"format_document": "文档",
|
||||
"format_spreadsheet": "电子表格",
|
||||
"format_presentation": "演示文稿",
|
||||
"format_pdf": "PDF",
|
||||
"file_name": "文件名",
|
||||
"retry": "重试",
|
||||
"refresh": "刷新",
|
||||
|
||||
@@ -582,7 +582,7 @@ describe('file-store "Shared with me"', () => {
|
||||
const refusal = (promise: Promise<unknown>) => promise.then(() => null, (error: unknown) => fileErrorKind(error));
|
||||
|
||||
expect(await refusal(store.createDirectory('New'))).toBe('forbidden');
|
||||
expect(await refusal(store.createTextFile('a.txt'))).toBe('forbidden');
|
||||
expect(await refusal(store.createFile('a.txt'))).toBe('forbidden');
|
||||
expect(await refusal(store.uploadFiles([new File(['x'], 'a.txt')]))).toBe('forbidden');
|
||||
expect(await refusal(store.uploadFolder([new File(['x'], 'a.txt')]))).toBe('forbidden');
|
||||
expect(await refusal(store.duplicateResource('notes.txt'))).toBe('forbidden');
|
||||
@@ -1077,3 +1077,37 @@ describe('file-store preview content', () => {
|
||||
expect(contentType).toBe('text/plain');
|
||||
});
|
||||
});
|
||||
|
||||
describe('file-store new file (#1393)', () => {
|
||||
const DOCX = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
|
||||
|
||||
it('creates a document from its blank template and returns the name the server gave it', async () => {
|
||||
const client = makeMockClient([file('a', 'Report.docx', null)]);
|
||||
const uploads: File[] = [];
|
||||
const upload = client.uploadBlob.bind(client);
|
||||
const create = client.createFileNode.bind(client);
|
||||
Object.assign(client, {
|
||||
uploadBlob: async (f: File) => { uploads.push(f); return upload(f); },
|
||||
// Stalwart's onExists: "rename".
|
||||
createFileNode: (name: string, ...rest: [string, string, number, string | null]) =>
|
||||
create(name === 'Report.docx' ? 'Report (2).docx' : name, ...rest),
|
||||
});
|
||||
useFileStore.getState().initClient(client);
|
||||
await useFileStore.getState().navigate(null);
|
||||
|
||||
const blank = new Blob(['PK blank docx'], { type: DOCX });
|
||||
expect(await useFileStore.getState().createFile('Report.docx', blank)).toBe('Report (2).docx');
|
||||
expect(await uploads[0].text()).toBe('PK blank docx');
|
||||
expect(client._nodes().find(n => n.name === 'Report (2).docx')).toMatchObject({ type: DOCX, size: 13 });
|
||||
expect(useFileStore.getState().resources.map(r => r.name)).toContain('Report (2).docx');
|
||||
});
|
||||
|
||||
it('creates an empty text file without a template', async () => {
|
||||
const client = makeMockClient();
|
||||
useFileStore.getState().initClient(client);
|
||||
await useFileStore.getState().navigate(null);
|
||||
|
||||
expect(await useFileStore.getState().createFile('notes.txt')).toBe('notes.txt');
|
||||
expect(client._nodes()[0]).toMatchObject({ name: 'notes.txt', type: 'text/plain', size: 0 });
|
||||
});
|
||||
});
|
||||
|
||||
+13
-6
@@ -152,7 +152,12 @@ interface FileState {
|
||||
downloadZip: (ids: string[], zipName: string, options?: { signal?: AbortSignal; onProgress?: (p: ZipProgress) => void }) => Promise<void>;
|
||||
getImageUrl: (name: string) => Promise<string>;
|
||||
getFileContent: (name: string) => Promise<{ blob: Blob; contentType: string }>;
|
||||
createTextFile: (name: string) => Promise<void>;
|
||||
/**
|
||||
* A new file in the open folder: empty text, or a copy of `template` (a
|
||||
* blank document, #1393). Resolves to the name it got, which differs from
|
||||
* `name` when the server renamed it to avoid a clash.
|
||||
*/
|
||||
createFile: (name: string, template?: Blob) => Promise<string | null>;
|
||||
duplicateResource: (name: string) => Promise<void>;
|
||||
moveToFolder: (names: string[], targetFolder: string) => Promise<boolean>;
|
||||
moveToParent: (names: string[]) => Promise<boolean>;
|
||||
@@ -1380,15 +1385,17 @@ export const useFileStore = create<FileState>((set, get) => ({
|
||||
return { blob, contentType: resource.contentType || 'application/octet-stream' };
|
||||
},
|
||||
|
||||
createTextFile: async (name: string) => {
|
||||
createFile: async (name: string, template?: Blob) => {
|
||||
const { client, currentParentId, refresh } = get();
|
||||
if (!client) return;
|
||||
if (!client) return null;
|
||||
assertCanAddTo(currentParentId);
|
||||
|
||||
const emptyBlob = new File([''], name, { type: 'text/plain' });
|
||||
const { blobId } = await client.uploadBlob(emptyBlob);
|
||||
await client.createFileNode(name, blobId, 'text/plain', 0, currentParentId);
|
||||
const type = template?.type || 'text/plain';
|
||||
const content = new File(template ? [template] : [''], name, { type });
|
||||
const { blobId } = await client.uploadBlob(content);
|
||||
const node = await client.createFileNode(name, blobId, type, content.size, currentParentId);
|
||||
await refresh();
|
||||
return node.name || name;
|
||||
},
|
||||
|
||||
duplicateResource: async (name: string) => {
|
||||
|
||||
Reference in New Issue
Block a user