diff --git a/src/mixins/saveAs.js b/src/mixins/saveAs.js index 8740a4f55d..03a0994f6c 100644 --- a/src/mixins/saveAs.js +++ b/src/mixins/saveAs.js @@ -4,6 +4,7 @@ */ import { spawnDialog } from '@nextcloud/dialogs' +import { basename } from 'path' import SaveAs from '../components/Modal/SaveAs.vue' export default { @@ -16,7 +17,13 @@ export default { format, description: t('richdocuments', 'Save a copy of the file under a new name and continue editing the new file'), }, - (value) => value && this.sendPostMessage('Action_SaveAs', { Filename: value, Notify: true }), + (value) => { + if (value) { + // Track the requested filename for export operations + this.lastSaveAsFilename = basename(value) + this.sendPostMessage('Action_SaveAs', { Filename: value, Notify: true }) + } + }, ) }, }, diff --git a/src/view/FilesAppIntegration.js b/src/view/FilesAppIntegration.js index 41684c8ffe..a146189e4d 100644 --- a/src/view/FilesAppIntegration.js +++ b/src/view/FilesAppIntegration.js @@ -537,6 +537,38 @@ export default { return this.fileNode }, + /** + * Fetch metadata for a newly created file and emit files:node:created event + * This is used when exporting a document (e.g., DOCX -> PDF) to make the + * new file appear in the files list without manual reload + * + * @param {string} basename - The name of the new file (e.g., "test.pdf") + */ + async createNodeForNewFile(basename) { + if (isPublicShare()) { + return + } + + try { + const path = `${this.filePath}/${basename}` + const client = davGetClient() + const results = await client.getDirectoryContents(`${davRootPath}${path}`, { + details: true, + data: davGetDefaultPropfind(), + }) + const nodes = results.data.map((result) => davResultToNode(result)) + + if (nodes[0]) { + console.debug('[FilesAppIntegration] Emitting files:node:created for', basename) + emit('files:node:created', nodes[0]) + } else { + console.warn('[FilesAppIntegration] New file not found:', basename) + } + } catch (e) { + console.error('Failed to fetch new file metadata from webdav', e) + } + }, + changeFilesRoute(fileId) { OCP?.Files?.Router?.goToRoute( OCP.Files.Router.name, diff --git a/src/view/Office.vue b/src/view/Office.vue index fc19dd64a4..7b42f7a88f 100644 --- a/src/view/Office.vue +++ b/src/view/Office.vue @@ -192,6 +192,9 @@ export default { modified: false, hasWidgetEditingEnabled: false, + // Track the last requested save-as filename for export operations + lastSaveAsFilename: null, + formData: { action: null, accessToken: null, @@ -425,8 +428,24 @@ export default { this.saveAs(args.format) break case 'Action_Save_Resp': - if (args.fileName !== this.filename) { - FilesAppIntegration.saveAs(args.fileName) + console.debug('[viewer] Received post message Action_Save_Resp', args, this.lastSaveAsFilename) + if (args.success) { + let newFileName = args.fileName + + // If no filename is provided for exportas, use the last tracked filename + if (!newFileName && args.result === 'exportas' && this.lastSaveAsFilename) { + newFileName = this.lastSaveAsFilename + } + + if (newFileName && newFileName !== this.filename) { + // When exporting (e.g., DOCX -> PDF), a new file is created + // Fetch its metadata and emit files:node:created to show it in the files list + FilesAppIntegration.createNodeForNewFile(newFileName) + } else { + // When saving the current file, update its modification time + FilesAppIntegration.updateFileInfo(undefined, Date.now()) + } + this.lastSaveAsFilename = null } break case 'UI_InsertGraphic':