Skip to content

Commit 25a0d78

Browse files
committed
refactor(files_external): migrate to script-setup and Vue 3
Signed-off-by: Ferdinand Thiessen <[email protected]>
1 parent 75e5776 commit 25a0d78

File tree

11 files changed

+90
-113
lines changed

11 files changed

+90
-113
lines changed

apps/files_external/src/actions/enterCredentialsAction.ts

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,20 @@ import type { StorageConfig } from '../services/externalStorage.ts'
1010
import LoginSvg from '@mdi/svg/svg/login.svg?raw'
1111
import axios from '@nextcloud/axios'
1212
import { showError, showSuccess } from '@nextcloud/dialogs'
13+
import { emit } from '@nextcloud/event-bus'
1314
import { DefaultType, FileAction } from '@nextcloud/files'
1415
import { t } from '@nextcloud/l10n'
1516
import { addPasswordConfirmationInterceptors, PwdConfirmationMode } from '@nextcloud/password-confirmation'
1617
import { generateUrl } from '@nextcloud/router'
1718
import { spawnDialog } from '@nextcloud/vue/functions/dialog'
18-
import Vue, { defineAsyncComponent } from 'vue'
19+
import { defineAsyncComponent } from 'vue'
1920
import { isMissingAuthConfig, STORAGE_STATUS } from '../utils/credentialsUtils.ts'
2021
import { isNodeExternalStorage } from '../utils/externalStorageUtils.ts'
2122

2223
// Add password confirmation interceptors as
2324
// the backend requires the user to confirm their password
2425
addPasswordConfirmationInterceptors(axios)
2526

26-
type CredentialResponse = {
27-
login?: string
28-
password?: string
29-
}
30-
3127
/**
3228
* Set credentials for external storage
3329
*
@@ -55,7 +51,9 @@ async function setCredentials(node: Node, login: string, password: string): Prom
5551

5652
// Success update config attribute
5753
showSuccess(t('files_external', 'New configuration successfully saved'))
58-
Vue.set(node.attributes, 'config', config)
54+
node.attributes.config = config
55+
emit('files:node:updated', node)
56+
5957
return true
6058
}
6159

@@ -86,14 +84,7 @@ export const action = new FileAction({
8684
},
8785

8886
async exec({ nodes }) {
89-
const { login, password } = await new Promise<CredentialResponse>((resolve) => spawnDialog(
90-
defineAsyncComponent(() => import('../views/CredentialsDialog.vue')),
91-
{},
92-
(args) => {
93-
resolve(args as CredentialResponse)
94-
},
95-
))
96-
87+
const { login, password } = await spawnDialog(defineAsyncComponent(() => import('../views/CredentialsDialog.vue'))) ?? {}
9788
if (login && password) {
9889
try {
9990
await setCredentials(nodes[0], login, password)

apps/files_external/src/actions/inlineStorageCheckAction.ts

Lines changed: 42 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/**
1+
/*!
22
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
33
* SPDX-License-Identifier: AGPL-3.0-or-later
44
*/
@@ -8,9 +8,9 @@ import type { StorageConfig } from '../services/externalStorage.ts'
88

99
import AlertSvg from '@mdi/svg/svg/alert-circle.svg?raw'
1010
import { showWarning } from '@nextcloud/dialogs'
11+
import { emit } from '@nextcloud/event-bus'
1112
import { FileAction } from '@nextcloud/files'
12-
import { translate as t } from '@nextcloud/l10n'
13-
import Vue from 'vue'
13+
import { t } from '@nextcloud/l10n'
1414
import { getStatus } from '../services/externalStorage.ts'
1515
import { isMissingAuthConfig, STORAGE_STATUS } from '../utils/credentialsUtils.ts'
1616
import { isNodeExternalStorage } from '../utils/externalStorageUtils.ts'
@@ -31,7 +31,8 @@ export const action = new FileAction({
3131
* Use this function to check the storage availability
3232
* We then update the node attributes directly.
3333
*
34-
* @param node The node to render inline
34+
* @param context - The action context
35+
* @param context.nodes - The node to render inline
3536
*/
3637
async renderInline({ nodes }) {
3738
if (nodes.length !== 1 || !nodes[0]) {
@@ -44,43 +45,43 @@ export const action = new FileAction({
4445
span.innerHTML = t('files_external', 'Checking storage …')
4546

4647
let config = null as unknown as StorageConfig
47-
getStatus(node.attributes.id, node.attributes.scope === 'system')
48-
.then((response) => {
49-
config = response.data
50-
Vue.set(node.attributes, 'config', config)
51-
52-
if (config.status !== STORAGE_STATUS.SUCCESS) {
53-
throw new Error(config?.statusMessage || t('files_external', 'There was an error with this external storage.'))
54-
}
55-
56-
span.remove()
57-
})
58-
.catch((error) => {
59-
// If axios failed or if something else prevented
60-
// us from getting the config
61-
if ((error as AxiosError).response && !config) {
62-
showWarning(t('files_external', 'We were unable to check the external storage {basename}', {
63-
basename: node.basename,
64-
}))
65-
}
66-
67-
// Reset inline status
68-
span.innerHTML = ''
69-
70-
// Checking if we really have an error
71-
const isWarning = !config ? false : isMissingAuthConfig(config)
72-
const overlay = document.createElement('span')
73-
overlay.classList.add(`files-list__row-status--${isWarning ? 'warning' : 'error'}`)
74-
75-
// Only show an icon for errors, warning like missing credentials
76-
// have a dedicated inline action button
77-
if (!isWarning) {
78-
span.innerHTML = AlertSvg
79-
span.title = (error as Error).message
80-
}
81-
82-
span.prepend(overlay)
83-
})
48+
try {
49+
const { data } = await getStatus(node.attributes.id, node.attributes.scope === 'system')
50+
config = data
51+
node.attributes.config = config
52+
emit('files:node:updated', node)
53+
54+
if (config.status !== STORAGE_STATUS.SUCCESS) {
55+
throw new Error(config?.statusMessage || t('files_external', 'There was an error with this external storage.'))
56+
}
57+
58+
span.remove()
59+
} catch (error) {
60+
// If axios failed or if something else prevented
61+
// us from getting the config
62+
if ((error as AxiosError).response && !config) {
63+
showWarning(t('files_external', 'We were unable to check the external storage {basename}', {
64+
basename: node.basename,
65+
}))
66+
}
67+
68+
// Reset inline status
69+
span.innerHTML = ''
70+
71+
// Checking if we really have an error
72+
const isWarning = !config ? false : isMissingAuthConfig(config)
73+
const overlay = document.createElement('span')
74+
overlay.classList.add(`files-list__row-status--${isWarning ? 'warning' : 'error'}`)
75+
76+
// Only show an icon for errors, warning like missing credentials
77+
// have a dedicated inline action button
78+
if (!isWarning) {
79+
span.innerHTML = AlertSvg
80+
span.title = (error as Error).message
81+
}
82+
83+
span.prepend(overlay)
84+
}
8485

8586
return span
8687
},

apps/files_external/src/actions/openInFilesAction.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { StorageConfig } from '../services/externalStorage.ts'
66

77
import { getCurrentUser } from '@nextcloud/auth'
88
import { DefaultType, FileAction } from '@nextcloud/files'
9-
import { translate as t } from '@nextcloud/l10n'
9+
import { t } from '@nextcloud/l10n'
1010
import { generateUrl } from '@nextcloud/router'
1111
import { STORAGE_STATUS } from '../utils/credentialsUtils.ts'
1212

apps/files_external/src/init.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import FolderNetworkSvg from '@mdi/svg/svg/folder-network-outline.svg?raw'
2-
import { Column, getNavigation, registerFileAction, View } from '@nextcloud/files'
3-
/**
1+
/*
42
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
53
* SPDX-License-Identifier: AGPL-3.0-or-later
64
*/
5+
6+
import FolderNetworkSvg from '@mdi/svg/svg/folder-network-outline.svg?raw'
7+
import { Column, getNavigation, registerFileAction, View } from '@nextcloud/files'
78
import { loadState } from '@nextcloud/initial-state'
89
import { translate as t } from '@nextcloud/l10n'
910
import { action as enterCredentialsAction } from './actions/enterCredentialsAction.ts'

apps/files_external/src/services/externalStorage.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ export type MountEntry = {
4848
}
4949

5050
/**
51+
* Convert an OCS api result (mount entry) to a Folder instance
5152
*
52-
* @param ocsEntry
53+
* @param ocsEntry - The OCS mount entry
5354
*/
5455
function entryToFolder(ocsEntry: MountEntry): Folder {
5556
const path = (ocsEntry.path + '/' + ocsEntry.name).replace(/^\//gm, '')
@@ -69,7 +70,7 @@ function entryToFolder(ocsEntry: MountEntry): Folder {
6970
}
7071

7172
/**
72-
*
73+
* Fetch the contents of external storage mounts
7374
*/
7475
export async function getContents(): Promise<ContentsWithRoot> {
7576
const response = await axios.get(generateOcsUrl('apps/files_external/api/v1/mounts')) as AxiosResponse<OCSResponse<MountEntry[]>>

apps/files_external/src/utils/credentialsUtils.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ export enum STORAGE_STATUS {
1717
}
1818

1919
/**
20-
* @param config
20+
* Check if the given storage configuration is missing authentication configuration
21+
*
22+
* @param config - The storage configuration to check
2123
*/
2224
export function isMissingAuthConfig(config: StorageConfig) {
2325
// If we don't know the status, assume it is ok

apps/files_external/src/utils/externalStorageUtils.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,17 @@
33
* SPDX-License-Identifier: AGPL-3.0-or-later
44
*/
55

6-
import type { Node } from '@nextcloud/files'
6+
import type { INode } from '@nextcloud/files'
77
import type { MountEntry } from '../services/externalStorage.ts'
88

99
import { FileType } from '@nextcloud/files'
1010

1111
/**
12-
* @param node
12+
* Check if the given node represents an external storage mount
13+
*
14+
* @param node - The node to check
1315
*/
14-
export function isNodeExternalStorage(node: Node) {
16+
export function isNodeExternalStorage(node: INode) {
1517
// Not a folder, not a storage
1618
if (node.type === FileType.File) {
1719
return false

apps/files_external/src/views/CredentialsDialog.vue

Lines changed: 22 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,28 @@
33
- SPDX-License-Identifier: AGPL-3.0-or-later
44
-->
55

6+
<script setup lang="ts">
7+
import { t } from '@nextcloud/l10n'
8+
import { ref } from 'vue'
9+
import NcDialog from '@nextcloud/vue/components/NcDialog'
10+
import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'
11+
import NcPasswordField from '@nextcloud/vue/components/NcPasswordField'
12+
import NcTextField from '@nextcloud/vue/components/NcTextField'
13+
14+
defineEmits<{
15+
close: [payload?: { login: string, password: string }]
16+
}>()
17+
18+
const login = ref('')
19+
const password = ref('')
20+
21+
const dialogButtons: InstanceType<typeof NcDialog>['buttons'] = [{
22+
label: t('files_external', 'Confirm'),
23+
type: 'submit',
24+
variant: 'primary',
25+
}]
26+
</script>
27+
628
<template>
729
<NcDialog
830
:buttons="dialogButtons"
@@ -44,46 +66,3 @@
4466
required />
4567
</NcDialog>
4668
</template>
47-
48-
<script lang="ts">
49-
import { t } from '@nextcloud/l10n'
50-
import { defineComponent } from 'vue'
51-
import NcDialog from '@nextcloud/vue/components/NcDialog'
52-
import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'
53-
import NcPasswordField from '@nextcloud/vue/components/NcPasswordField'
54-
import NcTextField from '@nextcloud/vue/components/NcTextField'
55-
56-
export default defineComponent({
57-
name: 'CredentialsDialog',
58-
59-
components: {
60-
NcDialog,
61-
NcNoteCard,
62-
NcTextField,
63-
NcPasswordField,
64-
},
65-
66-
setup() {
67-
return {
68-
t,
69-
}
70-
},
71-
72-
data() {
73-
return {
74-
login: '',
75-
password: '',
76-
}
77-
},
78-
79-
computed: {
80-
dialogButtons() {
81-
return [{
82-
label: t('files_external', 'Confirm'),
83-
type: 'submit',
84-
variant: 'primary',
85-
}]
86-
},
87-
},
88-
})
89-
</script>

build/frontend-legacy/webpack.modules.cjs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,6 @@ module.exports = {
4040
'settings-personal': path.join(__dirname, 'apps/files/src', 'main-settings-personal.ts'),
4141
'reference-files': path.join(__dirname, 'apps/files/src', 'reference-files.ts'),
4242
},
43-
files_external: {
44-
init: path.join(__dirname, 'apps/files_external/src', 'init.ts'),
45-
settings: path.join(__dirname, 'apps/files_external/src', 'settings.js'),
46-
},
4743
files_sharing: {
4844
additionalScripts: path.join(__dirname, 'apps/files_sharing/src', 'additionalScripts.js'),
4945
collaboration: path.join(__dirname, 'apps/files_sharing/src', 'collaborationresourceshandler.js'),

0 commit comments

Comments
 (0)