1919 {{ t('richdocuments', 'Cancel') }}
2020 </NcButton >
2121 <NcButton type =" primary"
22+ :disabled =" isChecking"
2223 @click =" close" >
23- {{ t('richdocuments', 'Save') }}
24+ {{ isChecking ? t('richdocuments', 'Checking…') : t('richdocuments', 'Save') }}
2425 </NcButton >
2526 </div >
2627 </div >
2930
3031<script >
3132import { translate as t } from ' @nextcloud/l10n'
33+ import { showError } from ' @nextcloud/dialogs'
34+ import { getCurrentUser } from ' @nextcloud/auth'
35+ import { getClient , getDefaultPropfind , resultToNode } from ' @nextcloud/files/dav'
36+ import { emit } from ' @nextcloud/event-bus'
37+ import { isPublicShare , getSharingToken } from ' @nextcloud/sharing/public'
3238
3339import NcButton from ' @nextcloud/vue/dist/Components/NcButton.js'
3440import NcModal from ' @nextcloud/vue/dist/Components/NcModal.js'
3541import NcTextField from ' @nextcloud/vue/dist/Components/NcTextField.js'
36-
42+ import Config from ' ../../services/config.tsx '
3743export default {
3844 name: ' SaveAs' ,
3945 components: {
@@ -67,9 +73,16 @@ export default {
6773 data () {
6874 return {
6975 selectedPath: ' ' ,
76+ isChecking: false ,
7077 }
7178 },
7279 computed: {
80+ rootPath () {
81+ if (isPublicShare ()) {
82+ return ` /files/${ getSharingToken ()} `
83+ }
84+ return ` /files/${ getCurrentUser ()? .uid ?? Config .get (' userId' )}`
85+ },
7386 newFileName: {
7487 get() {
7588 if (this.selectedPath !== '') {
@@ -86,7 +99,6 @@ export default {
8699 },
87100 },
88101 mounted() {
89- // prepare filename for having a separate picker for the path (.split('/').pop())
90102 const filename = this.path
91103 const extension = filename.split('.').pop()
92104 const filenameWithoutExtension = filename.substring(0, filename.length - extension.length - 1)
@@ -98,8 +110,49 @@ export default {
98110 },
99111 methods: {
100112 t,
101- close () {
102- this .$emit (' close' , this .newFileName )
113+ async close() {
114+ if (this.isChecking) {
115+ return
116+ }
117+
118+ this.isChecking = true
119+
120+ try {
121+ const client = getClient()
122+ const filename = this.newFileName
123+
124+ // In direct editing sessions there is no authenticated DAV session
125+ // so we skip the existence check and let the backend handle conflicts.
126+ // A future improvement could use a dedicated API endpoint that validates
127+ // the WOPI token and checks file existence on behalf of the user.
128+ if (!Config.get('direct')) {
129+ try {
130+ const result = await client.stat(` ${this .rootPath }/ ${filename}` , {
131+ details: true,
132+ data: getDefaultPropfind(),
133+ })
134+
135+ if (result) {
136+ showError(t('richdocuments', 'A file with that name already exists.'))
137+ const node = resultToNode(result.data)
138+ emit('files:node:updated', node)
139+ this.isChecking = false
140+ return
141+ }
142+ } catch (error) {
143+ if (error.response?.status !== 404) {
144+ console.error('Error checking file existence:', error)
145+ showError(t('richdocuments', 'Error checking if file exists.'))
146+ this.isChecking = false
147+ return
148+ }
149+ }
150+ }
151+
152+ this.$emit('close', this.newFileName)
153+ } finally {
154+ this.isChecking = false
155+ }
103156 },
104157 cancel() {
105158 this.$emit('close', null)
0 commit comments