diff --git a/apps/files_external/src/actions/enterCredentialsAction.ts b/apps/files_external/src/actions/enterCredentialsAction.ts index 20d54e64cf01d..68f3226248caf 100644 --- a/apps/files_external/src/actions/enterCredentialsAction.ts +++ b/apps/files_external/src/actions/enterCredentialsAction.ts @@ -35,7 +35,7 @@ addPasswordConfirmationInterceptors(axios) async function setCredentials(node: INode, login: string, password: string): Promise { const configResponse = await axios.request({ method: 'PUT', - url: generateUrl('apps/files_external/userglobalstorages/{id}', { id: node.attributes.id }), + url: generateUrl('apps/files_external/userglobalstorages/{id}', { id: node.id }), confirmPassword: PwdConfirmationMode.Strict, data: { backendOptions: { user: login, password }, diff --git a/apps/files_external/src/actions/inlineStorageCheckAction.ts b/apps/files_external/src/actions/inlineStorageCheckAction.ts index 2a34af8b938d4..563482f1f3cb4 100644 --- a/apps/files_external/src/actions/inlineStorageCheckAction.ts +++ b/apps/files_external/src/actions/inlineStorageCheckAction.ts @@ -47,7 +47,7 @@ export const action: IFileAction = { let config: IStorage | undefined try { - const { data } = await getStatus(node.attributes.id, node.attributes.scope === 'system') + const { data } = await getStatus(node.id, node.attributes.scope === 'system') config = data node.attributes.config = config emit('files:node:updated', node) diff --git a/dist/files_external-init.mjs b/dist/files_external-init.mjs index 405374b1b0dac..bbf6550a825cb 100644 --- a/dist/files_external-init.mjs +++ b/dist/files_external-init.mjs @@ -1,3 +1,3 @@ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=[window.OC.filePath('', '', 'dist/CredentialsDialog-BwuMsqpU.chunk.mjs'),window.OC.filePath('', '', 'dist/translation-DoG5ZELJ-Bni_xMHF.chunk.mjs'),window.OC.filePath('', '', 'dist/index-Bndk0DrU.chunk.mjs'),window.OC.filePath('', '', 'dist/index-BrC2bLMO.chunk.mjs'),window.OC.filePath('', '', 'dist/runtime-dom.esm-bundler-CU8rrbZA.chunk.mjs'),window.OC.filePath('', '', 'dist/createElementId-DhjFt1I9-C_WKCRq3.chunk.mjs'),window.OC.filePath('', '', 'dist/createElementId-DhjFt1I9-C_oBIsvc.chunk.css'),window.OC.filePath('', '', 'dist/logger-D3RVzcfQ-CklyzrxW.chunk.mjs'),window.OC.filePath('', '', 'dist/logger-D3RVzcfQ-R3us1MM8.chunk.css'),window.OC.filePath('', '', 'dist/mdi-Bm11w6Fn.chunk.mjs'),window.OC.filePath('', '', 'dist/mdi-BYHcrfvW.chunk.css'),window.OC.filePath('', '', 'dist/index-CySLkPBX.chunk.css'),window.OC.filePath('', '', 'dist/NcNoteCard-Cok_4Fld-C71YD40i.chunk.mjs'),window.OC.filePath('', '', 'dist/NcNoteCard-Cok_4Fld-Jq77EThs.chunk.css'),window.OC.filePath('', '', 'dist/NcPasswordField-uaMO2pdt-Bi58_jEx.chunk.mjs'),window.OC.filePath('', '', 'dist/index-BT4ljBnH.chunk.mjs'),window.OC.filePath('', '', 'dist/string_decoder-BO00msnV.chunk.mjs'),window.OC.filePath('', '', 'dist/index-DCpg1aui.chunk.mjs'),window.OC.filePath('', '', 'dist/NcInputField-o5OFv3z6-DJtp_yB7.chunk.mjs'),window.OC.filePath('', '', 'dist/NcInputField-o5OFv3z6-BYlw6Xsd.chunk.css'),window.OC.filePath('', '', 'dist/NcPasswordField-uaMO2pdt-DxPSRxK-.chunk.css'),window.OC.filePath('', '', 'dist/TrashCanOutline-B5FsJrKA.chunk.mjs')])))=>i.map(i=>d[i]); -import{D as x,g as C,V as E,C as p,b as c}from"./index-CuwFxdv0.chunk.mjs";import{_ as V,l as M}from"./index-DCpg1aui.chunk.mjs";import{t as s}from"./translation-DoG5ZELJ-Bni_xMHF.chunk.mjs";import{c as l}from"./index-BT4ljBnH.chunk.mjs";import{d as w,a as h,s as L,e as S}from"./index-JpgrUA2Z-BYgeawUc.chunk.mjs";import{e as _,a as u}from"./index-Bndk0DrU.chunk.mjs";import{a as T,P as A}from"./index-CLPHpMLr.chunk.mjs";import{g as m,b as N,i as b}from"./createElementId-DhjFt1I9-C_WKCRq3.chunk.mjs";import{s as P}from"./index-BrC2bLMO.chunk.mjs";import{S as a}from"./types-DSMBPDbS.chunk.mjs";import{F as k,b as y,P as d}from"./public-Sa--me8z.chunk.mjs";import{a as D}from"./runtime-dom.esm-bundler-CU8rrbZA.chunk.mjs";import"./string_decoder-BO00msnV.chunk.mjs";import"./NcNoteCard-Cok_4Fld-C71YD40i.chunk.mjs";import"./logger-D3RVzcfQ-CklyzrxW.chunk.mjs";import"./NcPasswordField-uaMO2pdt-Bi58_jEx.chunk.mjs";import"./NcInputField-o5OFv3z6-DJtp_yB7.chunk.mjs";import"./mdi-Bm11w6Fn.chunk.mjs";const I='',O='';function v(e){return e.status===void 0||e.status===a.Success?!1:e.userProvided||e.authMechanism==="password::global::user"}function H(e){if(e.type===k.File)return!1;const t=e.attributes;return!t.scope||!t.backend?!1:t.scope==="personal"||t.scope==="system"}T(l);async function R(e,t,n){const r=(await l.request({method:"PUT",url:m("apps/files_external/userglobalstorages/{id}",{id:e.attributes.id}),confirmPassword:A.Strict,data:{backendOptions:{user:t,password:n}}})).data;return r.status!==a.Success?(h(s("files_external","Unable to update this external storage config. {statusMessage}",{statusMessage:r?.statusMessage||""})),null):(w(s("files_external","New configuration successfully saved")),e.attributes.config=r,_("files:node:updated",e),!0)}const F="credentials-external-storage",U={id:F,displayName:()=>s("files","Enter missing credentials"),iconSvgInline:()=>O,enabled:({nodes:e})=>{if(e.length!==1||!e[0])return!1;const t=e[0];if(!H(t))return!1;const n=t.attributes?.config||{};return!!v(n)},async exec({nodes:e}){const{login:t,password:n}=await P(D(()=>V(()=>import("./CredentialsDialog-BwuMsqpU.chunk.mjs"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21]),import.meta.url)))??{};if(t&&n)try{await R(e[0],t,n),w(s("files_external","Credentials successfully set"))}catch(r){h(s("files_external","Error while setting credentials: {error}",{error:r.message}))}return null},order:-1e3,default:x.DEFAULT,inline:()=>!0},$='',o=`/files/${u()?.uid}`;function B(e){const t=(e.path+"/"+e.name).replace(/^\//gm,"");return new y({id:e.id,source:b("dav"+o+"/"+t),root:o,owner:u()?.uid||null,permissions:e.config.status!==a.Success?d.NONE:e?.permissions||d.READ,attributes:{displayName:t,...e}})}async function Z(){const e=(await l.get(N("apps/files_external/api/v1/mounts"))).data.ocs.data.map(B);return{folder:new y({id:0,source:b("dav"+o),root:o,owner:u()?.uid||null,permissions:d.READ}),contents:e}}function j(e,t=!0){const n=t?"userglobalstorages":"userstorages";return l.get(m(`apps/files_external/${n}/${e}?testOnly=false`))}const q={id:"check-external-storage",displayName:()=>"",iconSvgInline:()=>"",enabled:({nodes:e})=>e.every(t=>H(t)===!0),exec:async()=>null,async renderInline({nodes:e}){if(e.length!==1||!e[0])return null;const t=e[0],n=document.createElement("span");n.className="files-list__row-status",n.innerHTML=s("files_external","Checking storage …");let r;try{const{data:i}=await j(t.attributes.id,t.attributes.scope==="system");if(r=i,t.attributes.config=r,_("files:node:updated",t),r.status!==a.Success)throw new Error(r?.statusMessage||s("files_external","There was an error with this external storage."));n.remove()}catch(i){i.response&&!r&&L(s("files_external","We were unable to check the external storage {basename}",{basename:t.basename})),n.innerHTML="";const f=r?v(r):!1,g=document.createElement("span");g.classList.add(`files-list__row-status--${f?"warning":"error"}`),f||(n.innerHTML=$,n.title=i.message),n.prepend(g)}return n},order:10},W={id:"open-in-files-external-storage",displayName:({nodes:e})=>(e?.[0]?.attributes?.config||{status:a.Indeterminate}).status!==a.Success?s("files_external","Examine this faulty external storage configuration"):s("files","Open in Files"),iconSvgInline:()=>"",enabled:({view:e})=>e.id==="extstoragemounts",async exec({nodes:e}){if(e[0]?.attributes?.config?.status!==a.Success){if(await S({name:s("files_external","External mount error"),text:s("files_external","There was an error with this external storage. Do you want to review this mount point config in the settings page?"),labelConfirm:s("files_external","Open settings"),labelReject:s("files_external","Ignore")})===!0){const t=u()?.isAdmin?"admin":"user";window.location.href=m(`/settings/${t}/externalstorages`)}return null}return window.OCP.Files.Router.goToRoute(null,{view:"files"},{dir:e[0].path}),null},order:-1e3,default:x.HIDDEN},Y=M("files_external","allowUserMounting",!1),z=C();z.register(new E({id:"extstoragemounts",name:s("files_external","External storage"),caption:s("files_external","List of external storage."),emptyCaption:Y?s("files_external","There is no external storage configured. You can configure them in your Personal settings."):s("files_external","There is no external storage configured and you don't have the permission to configure them."),emptyTitle:s("files_external","No external storage"),icon:I,order:30,columns:[new p({id:"storage-type",title:s("files_external","Storage type"),render(e){const t=e.attributes?.backend||s("files_external","Unknown"),n=document.createElement("span");return n.textContent=t,n}}),new p({id:"scope",title:s("files_external","Scope"),render(e){const t=document.createElement("span");let n=s("files_external","Personal");return e.attributes?.scope==="system"&&(n=s("files_external","System")),t.textContent=n,t}})],getContents:Z})),c(U),c(q),c(W); +import{D as x,g as C,V as E,C as p,b as u}from"./index-CuwFxdv0.chunk.mjs";import{_ as V,l as M}from"./index-DCpg1aui.chunk.mjs";import{t as s}from"./translation-DoG5ZELJ-Bni_xMHF.chunk.mjs";import{c as l}from"./index-BT4ljBnH.chunk.mjs";import{d as w,a as h,s as L,e as S}from"./index-JpgrUA2Z-BYgeawUc.chunk.mjs";import{e as _,a as c}from"./index-Bndk0DrU.chunk.mjs";import{a as T,P as A}from"./index-CLPHpMLr.chunk.mjs";import{g as m,b as N,i as y}from"./createElementId-DhjFt1I9-C_WKCRq3.chunk.mjs";import{s as P}from"./index-BrC2bLMO.chunk.mjs";import{S as a}from"./types-DSMBPDbS.chunk.mjs";import{F as k,b,P as d}from"./public-Sa--me8z.chunk.mjs";import{a as D}from"./runtime-dom.esm-bundler-CU8rrbZA.chunk.mjs";import"./string_decoder-BO00msnV.chunk.mjs";import"./NcNoteCard-Cok_4Fld-C71YD40i.chunk.mjs";import"./logger-D3RVzcfQ-CklyzrxW.chunk.mjs";import"./NcPasswordField-uaMO2pdt-Bi58_jEx.chunk.mjs";import"./NcInputField-o5OFv3z6-DJtp_yB7.chunk.mjs";import"./mdi-Bm11w6Fn.chunk.mjs";const I='',O='';function v(e){return e.status===void 0||e.status===a.Success?!1:e.userProvided||e.authMechanism==="password::global::user"}function H(e){if(e.type===k.File)return!1;const t=e.attributes;return!t.scope||!t.backend?!1:t.scope==="personal"||t.scope==="system"}T(l);async function R(e,t,n){const r=(await l.request({method:"PUT",url:m("apps/files_external/userglobalstorages/{id}",{id:e.id}),confirmPassword:A.Strict,data:{backendOptions:{user:t,password:n}}})).data;return r.status!==a.Success?(h(s("files_external","Unable to update this external storage config. {statusMessage}",{statusMessage:r?.statusMessage||""})),null):(w(s("files_external","New configuration successfully saved")),e.attributes.config=r,_("files:node:updated",e),!0)}const F="credentials-external-storage",U={id:F,displayName:()=>s("files","Enter missing credentials"),iconSvgInline:()=>O,enabled:({nodes:e})=>{if(e.length!==1||!e[0])return!1;const t=e[0];if(!H(t))return!1;const n=t.attributes?.config||{};return!!v(n)},async exec({nodes:e}){const{login:t,password:n}=await P(D(()=>V(()=>import("./CredentialsDialog-BwuMsqpU.chunk.mjs"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21]),import.meta.url)))??{};if(t&&n)try{await R(e[0],t,n),w(s("files_external","Credentials successfully set"))}catch(r){h(s("files_external","Error while setting credentials: {error}",{error:r.message}))}return null},order:-1e3,default:x.DEFAULT,inline:()=>!0},$='',o=`/files/${c()?.uid}`;function B(e){const t=(e.path+"/"+e.name).replace(/^\//gm,"");return new b({id:e.id,source:y("dav"+o+"/"+t),root:o,owner:c()?.uid||null,permissions:e.config.status!==a.Success?d.NONE:e?.permissions||d.READ,attributes:{displayName:t,...e}})}async function Z(){const e=(await l.get(N("apps/files_external/api/v1/mounts"))).data.ocs.data.map(B);return{folder:new b({id:0,source:y("dav"+o),root:o,owner:c()?.uid||null,permissions:d.READ}),contents:e}}function j(e,t=!0){const n=t?"userglobalstorages":"userstorages";return l.get(m(`apps/files_external/${n}/${e}?testOnly=false`))}const q={id:"check-external-storage",displayName:()=>"",iconSvgInline:()=>"",enabled:({nodes:e})=>e.every(t=>H(t)===!0),exec:async()=>null,async renderInline({nodes:e}){if(e.length!==1||!e[0])return null;const t=e[0],n=document.createElement("span");n.className="files-list__row-status",n.innerHTML=s("files_external","Checking storage …");let r;try{const{data:i}=await j(t.id,t.attributes.scope==="system");if(r=i,t.attributes.config=r,_("files:node:updated",t),r.status!==a.Success)throw new Error(r?.statusMessage||s("files_external","There was an error with this external storage."));n.remove()}catch(i){i.response&&!r&&L(s("files_external","We were unable to check the external storage {basename}",{basename:t.basename})),n.innerHTML="";const f=r?v(r):!1,g=document.createElement("span");g.classList.add(`files-list__row-status--${f?"warning":"error"}`),f||(n.innerHTML=$,n.title=i.message),n.prepend(g)}return n},order:10},W={id:"open-in-files-external-storage",displayName:({nodes:e})=>(e?.[0]?.attributes?.config||{status:a.Indeterminate}).status!==a.Success?s("files_external","Examine this faulty external storage configuration"):s("files","Open in Files"),iconSvgInline:()=>"",enabled:({view:e})=>e.id==="extstoragemounts",async exec({nodes:e}){if(e[0]?.attributes?.config?.status!==a.Success){if(await S({name:s("files_external","External mount error"),text:s("files_external","There was an error with this external storage. Do you want to review this mount point config in the settings page?"),labelConfirm:s("files_external","Open settings"),labelReject:s("files_external","Ignore")})===!0){const t=c()?.isAdmin?"admin":"user";window.location.href=m(`/settings/${t}/externalstorages`)}return null}return window.OCP.Files.Router.goToRoute(null,{view:"files"},{dir:e[0].path}),null},order:-1e3,default:x.HIDDEN},Y=M("files_external","allowUserMounting",!1),z=C();z.register(new E({id:"extstoragemounts",name:s("files_external","External storage"),caption:s("files_external","List of external storage."),emptyCaption:Y?s("files_external","There is no external storage configured. You can configure them in your Personal settings."):s("files_external","There is no external storage configured and you don't have the permission to configure them."),emptyTitle:s("files_external","No external storage"),icon:I,order:30,columns:[new p({id:"storage-type",title:s("files_external","Storage type"),render(e){const t=e.attributes?.backend||s("files_external","Unknown"),n=document.createElement("span");return n.textContent=t,n}}),new p({id:"scope",title:s("files_external","Scope"),render(e){const t=document.createElement("span");let n=s("files_external","Personal");return e.attributes?.scope==="system"&&(n=s("files_external","System")),t.textContent=n,t}})],getContents:Z})),u(U),u(q),u(W); //# sourceMappingURL=files_external-init.mjs.map diff --git a/dist/files_external-init.mjs.map b/dist/files_external-init.mjs.map index 59e572da8c3df..99629c05e358a 100644 --- a/dist/files_external-init.mjs.map +++ b/dist/files_external-init.mjs.map @@ -1 +1 @@ -{"version":3,"mappings":"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","names":["FolderNetworkSvg","LoginSvg","isMissingAuthConfig","config","StorageStatus","isNodeExternalStorage","node","FileType","attributes","addPasswordConfirmationInterceptors","axios","setCredentials","login","password","generateUrl","PwdConfirmationMode","showError","t","showSuccess","emit","ACTION_CREDENTIALS_EXTERNAL_STORAGE","action","nodes","spawnDialog","defineAsyncComponent","error","DefaultType","AlertSvg","rootPath","getCurrentUser","entryToFolder","ocsEntry","path","Folder","generateRemoteUrl","Permission","getContents","contents","generateOcsUrl","getStatus","id","global","type","span","data","showWarning","isWarning","overlay","view","showConfirmation","scope","allowUserMounting","loadState","Navigation","getNavigation","View","Column","backend","registerFileAction","enterCredentialsAction","inlineStorageCheckAction","openInFilesAction"],"ignoreList":[0,1,5],"sources":["../node_modules/@mdi/svg/svg/folder-network-outline.svg?raw","../node_modules/@mdi/svg/svg/login.svg?raw","../build/frontend/apps/files_external/src/utils/credentialsUtils.ts","../build/frontend/apps/files_external/src/utils/externalStorageUtils.ts","../build/frontend/apps/files_external/src/actions/enterCredentialsAction.ts","../node_modules/@mdi/svg/svg/alert-circle.svg?raw","../build/frontend/apps/files_external/src/services/externalStorage.ts","../build/frontend/apps/files_external/src/actions/inlineStorageCheckAction.ts","../build/frontend/apps/files_external/src/actions/openInFilesAction.ts","../build/frontend/apps/files_external/src/init-files.ts"],"sourcesContent":["export default \"\"","export default \"\"","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IStorage } from '../types.ts'\n\nimport { StorageStatus } from '../types.ts'\n\n/**\n * Check if the given storage configuration is missing authentication configuration\n *\n * @param config - The storage configuration to check\n */\nexport function isMissingAuthConfig(config: IStorage) {\n\t// If we don't know the status, assume it is ok\n\tif (config.status === undefined || config.status === StorageStatus.Success) {\n\t\treturn false\n\t}\n\n\treturn config.userProvided || config.authMechanism === 'password::global::user'\n}\n","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { INode } from '@nextcloud/files'\nimport type { MountEntry } from '../services/externalStorage.ts'\n\nimport { FileType } from '@nextcloud/files'\n\n/**\n * Check if the given node represents an external storage mount\n *\n * @param node - The node to check\n */\nexport function isNodeExternalStorage(node: INode) {\n\t// Not a folder, not a storage\n\tif (node.type === FileType.File) {\n\t\treturn false\n\t}\n\n\t// No backend or scope, not a storage\n\tconst attributes = node.attributes as MountEntry\n\tif (!attributes.scope || !attributes.backend) {\n\t\treturn false\n\t}\n\n\t// Specific markers that we're sure are ext storage only\n\treturn attributes.scope === 'personal' || attributes.scope === 'system'\n}\n","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { AxiosResponse } from '@nextcloud/axios'\nimport type { IFileAction, INode } from '@nextcloud/files'\nimport type { IStorage } from '../types.ts'\n\nimport LoginSvg from '@mdi/svg/svg/login.svg?raw'\nimport axios from '@nextcloud/axios'\nimport { showError, showSuccess } from '@nextcloud/dialogs'\nimport { emit } from '@nextcloud/event-bus'\nimport { DefaultType } from '@nextcloud/files'\nimport { t } from '@nextcloud/l10n'\nimport { addPasswordConfirmationInterceptors, PwdConfirmationMode } from '@nextcloud/password-confirmation'\nimport { generateUrl } from '@nextcloud/router'\nimport { spawnDialog } from '@nextcloud/vue/functions/dialog'\nimport { defineAsyncComponent } from 'vue'\nimport { StorageStatus } from '../types.ts'\nimport { isMissingAuthConfig } from '../utils/credentialsUtils.ts'\nimport { isNodeExternalStorage } from '../utils/externalStorageUtils.ts'\n\n// Add password confirmation interceptors as\n// the backend requires the user to confirm their password\naddPasswordConfirmationInterceptors(axios)\n\n/**\n * Set credentials for external storage\n *\n * @param node The node for which to set the credentials\n * @param login The username\n * @param password The password\n */\nasync function setCredentials(node: INode, login: string, password: string): Promise {\n\tconst configResponse = await axios.request({\n\t\tmethod: 'PUT',\n\t\turl: generateUrl('apps/files_external/userglobalstorages/{id}', { id: node.attributes.id }),\n\t\tconfirmPassword: PwdConfirmationMode.Strict,\n\t\tdata: {\n\t\t\tbackendOptions: { user: login, password },\n\t\t},\n\t}) as AxiosResponse\n\n\tconst config = configResponse.data\n\tif (config.status !== StorageStatus.Success) {\n\t\tshowError(t('files_external', 'Unable to update this external storage config. {statusMessage}', {\n\t\t\tstatusMessage: config?.statusMessage || '',\n\t\t}))\n\t\treturn null\n\t}\n\n\t// Success update config attribute\n\tshowSuccess(t('files_external', 'New configuration successfully saved'))\n\tnode.attributes.config = config\n\temit('files:node:updated', node)\n\n\treturn true\n}\n\nexport const ACTION_CREDENTIALS_EXTERNAL_STORAGE = 'credentials-external-storage'\n\nexport const action: IFileAction = {\n\tid: ACTION_CREDENTIALS_EXTERNAL_STORAGE,\n\tdisplayName: () => t('files', 'Enter missing credentials'),\n\ticonSvgInline: () => LoginSvg,\n\n\tenabled: ({ nodes }) => {\n\t\t// Only works on single node\n\t\tif (nodes.length !== 1 || !nodes[0]) {\n\t\t\treturn false\n\t\t}\n\n\t\tconst node = nodes[0]\n\t\tif (!isNodeExternalStorage(node)) {\n\t\t\treturn false\n\t\t}\n\n\t\tconst config = (node.attributes?.config || {}) as IStorage\n\t\tif (isMissingAuthConfig(config)) {\n\t\t\treturn true\n\t\t}\n\n\t\treturn false\n\t},\n\n\tasync exec({ nodes }) {\n\t\tconst { login, password } = await spawnDialog(defineAsyncComponent(() => import('../views/CredentialsDialog.vue'))) ?? {}\n\t\tif (login && password) {\n\t\t\ttry {\n\t\t\t\tawait setCredentials(nodes[0]!, login, password)\n\t\t\t\tshowSuccess(t('files_external', 'Credentials successfully set'))\n\t\t\t} catch (error) {\n\t\t\t\tshowError(t('files_external', 'Error while setting credentials: {error}', {\n\t\t\t\t\terror: (error as Error).message,\n\t\t\t\t}))\n\t\t\t}\n\t\t}\n\n\t\treturn null\n\t},\n\n\t// Before openFolderAction\n\torder: -1000,\n\tdefault: DefaultType.DEFAULT,\n\tinline: () => true,\n}\n","export default \"\"","/**\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { AxiosResponse } from '@nextcloud/axios'\nimport type { ContentsWithRoot } from '@nextcloud/files'\nimport type { OCSResponse } from '@nextcloud/typings/ocs'\nimport type { IStorage } from '../types.ts'\n\nimport { getCurrentUser } from '@nextcloud/auth'\nimport axios from '@nextcloud/axios'\nimport { Folder, Permission } from '@nextcloud/files'\nimport { generateOcsUrl, generateRemoteUrl, generateUrl } from '@nextcloud/router'\nimport { StorageStatus } from '../types.ts'\n\nexport const rootPath = `/files/${getCurrentUser()?.uid}`\n\n/**\n * https://github.com/nextcloud/server/blob/ac2bc2384efe3c15ff987b87a7432bc60d545c67/apps/files_external/lib/Controller/ApiController.php#L71-L97\n */\nexport type MountEntry = {\n\tname: string\n\tpath: string\n\ttype: 'dir'\n\tbackend: 'SFTP'\n\tscope: 'system' | 'personal'\n\tpermissions: number\n\tid: number\n\tclass: string\n\tconfig: IStorage\n}\n\n/**\n * Convert an OCS api result (mount entry) to a Folder instance\n *\n * @param ocsEntry - The OCS mount entry\n */\nfunction entryToFolder(ocsEntry: MountEntry): Folder {\n\tconst path = (ocsEntry.path + '/' + ocsEntry.name).replace(/^\\//gm, '')\n\treturn new Folder({\n\t\tid: ocsEntry.id,\n\t\tsource: generateRemoteUrl('dav' + rootPath + '/' + path),\n\t\troot: rootPath,\n\t\towner: getCurrentUser()?.uid || null,\n\t\tpermissions: ocsEntry.config.status !== StorageStatus.Success\n\t\t\t? Permission.NONE\n\t\t\t: ocsEntry?.permissions || Permission.READ,\n\t\tattributes: {\n\t\t\tdisplayName: path,\n\t\t\t...ocsEntry,\n\t\t},\n\t})\n}\n\n/**\n * Fetch the contents of external storage mounts\n */\nexport async function getContents(): Promise {\n\tconst response = await axios.get(generateOcsUrl('apps/files_external/api/v1/mounts')) as AxiosResponse>\n\tconst contents = response.data.ocs.data.map(entryToFolder)\n\n\treturn {\n\t\tfolder: new Folder({\n\t\t\tid: 0,\n\t\t\tsource: generateRemoteUrl('dav' + rootPath),\n\t\t\troot: rootPath,\n\t\t\towner: getCurrentUser()?.uid || null,\n\t\t\tpermissions: Permission.READ,\n\t\t}),\n\t\tcontents,\n\t}\n}\n\n/**\n * Get the status of an external storage mount\n *\n * @param id - The storage ID\n * @param global - Whether the storage is global or user specific\n */\nexport function getStatus(id: number, global = true) {\n\tconst type = global ? 'userglobalstorages' : 'userstorages'\n\treturn axios.get(generateUrl(`apps/files_external/${type}/${id}?testOnly=false`)) as Promise>\n}\n","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { AxiosError } from '@nextcloud/axios'\nimport type { IFileAction } from '@nextcloud/files'\nimport type { IStorage } from '../types.ts'\n\nimport AlertSvg from '@mdi/svg/svg/alert-circle.svg?raw'\nimport { showWarning } from '@nextcloud/dialogs'\nimport { emit } from '@nextcloud/event-bus'\nimport { t } from '@nextcloud/l10n'\nimport { getStatus } from '../services/externalStorage.ts'\nimport { StorageStatus } from '../types.ts'\nimport { isMissingAuthConfig } from '../utils/credentialsUtils.ts'\nimport { isNodeExternalStorage } from '../utils/externalStorageUtils.ts'\n\nimport '../css/fileEntryStatus.scss'\n\nexport const action: IFileAction = {\n\tid: 'check-external-storage',\n\tdisplayName: () => '',\n\ticonSvgInline: () => '',\n\n\tenabled: ({ nodes }) => {\n\t\treturn nodes.every((node) => isNodeExternalStorage(node) === true)\n\t},\n\texec: async () => null,\n\n\t/**\n\t * Use this function to check the storage availability\n\t * We then update the node attributes directly.\n\t *\n\t * @param context - The action context\n\t * @param context.nodes - The node to render inline\n\t */\n\tasync renderInline({ nodes }) {\n\t\tif (nodes.length !== 1 || !nodes[0]) {\n\t\t\treturn null\n\t\t}\n\n\t\tconst node = nodes[0]\n\t\tconst span = document.createElement('span')\n\t\tspan.className = 'files-list__row-status'\n\t\tspan.innerHTML = t('files_external', 'Checking storage …')\n\n\t\tlet config: IStorage | undefined\n\t\ttry {\n\t\t\tconst { data } = await getStatus(node.attributes.id, node.attributes.scope === 'system')\n\t\t\tconfig = data\n\t\t\tnode.attributes.config = config\n\t\t\temit('files:node:updated', node)\n\n\t\t\tif (config.status !== StorageStatus.Success) {\n\t\t\t\tthrow new Error(config?.statusMessage || t('files_external', 'There was an error with this external storage.'))\n\t\t\t}\n\n\t\t\tspan.remove()\n\t\t} catch (error) {\n\t\t\t// If axios failed or if something else prevented\n\t\t\t// us from getting the config\n\t\t\tif ((error as AxiosError).response && !config) {\n\t\t\t\tshowWarning(t('files_external', 'We were unable to check the external storage {basename}', {\n\t\t\t\t\tbasename: node.basename,\n\t\t\t\t}))\n\t\t\t}\n\n\t\t\t// Reset inline status\n\t\t\tspan.innerHTML = ''\n\n\t\t\t// Checking if we really have an error\n\t\t\tconst isWarning = !config ? false : isMissingAuthConfig(config)\n\t\t\tconst overlay = document.createElement('span')\n\t\t\toverlay.classList.add(`files-list__row-status--${isWarning ? 'warning' : 'error'}`)\n\n\t\t\t// Only show an icon for errors, warning like missing credentials\n\t\t\t// have a dedicated inline action button\n\t\t\tif (!isWarning) {\n\t\t\t\tspan.innerHTML = AlertSvg\n\t\t\t\tspan.title = (error as Error).message\n\t\t\t}\n\n\t\t\tspan.prepend(overlay)\n\t\t}\n\n\t\treturn span\n\t},\n\n\torder: 10,\n}\n","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IFileAction } from '@nextcloud/files'\nimport type { IStorage } from '../types.ts'\n\nimport { getCurrentUser } from '@nextcloud/auth'\nimport { showConfirmation } from '@nextcloud/dialogs'\nimport { DefaultType } from '@nextcloud/files'\nimport { t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { StorageStatus } from '../types.ts'\n\nexport const action: IFileAction = {\n\tid: 'open-in-files-external-storage',\n\tdisplayName: ({ nodes }) => {\n\t\tconst config = nodes?.[0]?.attributes?.config as IStorage || { status: StorageStatus.Indeterminate }\n\t\tif (config.status !== StorageStatus.Success) {\n\t\t\treturn t('files_external', 'Examine this faulty external storage configuration')\n\t\t}\n\t\treturn t('files', 'Open in Files')\n\t},\n\ticonSvgInline: () => '',\n\n\tenabled: ({ view }) => view.id === 'extstoragemounts',\n\n\tasync exec({ nodes }) {\n\t\tconst config = nodes[0]?.attributes?.config as IStorage\n\t\tif (config?.status !== StorageStatus.Success) {\n\t\t\tconst redirect = await showConfirmation({\n\t\t\t\tname: t('files_external', 'External mount error'),\n\t\t\t\ttext: t('files_external', 'There was an error with this external storage. Do you want to review this mount point config in the settings page?'),\n\t\t\t\tlabelConfirm: t('files_external', 'Open settings'),\n\t\t\t\tlabelReject: t('files_external', 'Ignore'),\n\t\t\t})\n\t\t\tif (redirect === true) {\n\t\t\t\tconst scope = getCurrentUser()?.isAdmin ? 'admin' : 'user'\n\t\t\t\twindow.location.href = generateUrl(`/settings/${scope}/externalstorages`)\n\t\t\t}\n\t\t\treturn null\n\t\t}\n\n\t\t// Do not use fileid as we don't have that information\n\t\t// from the external storage api\n\t\twindow.OCP.Files.Router.goToRoute(\n\t\t\tnull, // use default route\n\t\t\t{ view: 'files' },\n\t\t\t{ dir: nodes[0].path },\n\t\t)\n\t\treturn null\n\t},\n\n\t// Before openFolderAction\n\torder: -1000,\n\tdefault: DefaultType.HIDDEN,\n}\n","/*\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport FolderNetworkSvg from '@mdi/svg/svg/folder-network-outline.svg?raw'\nimport { Column, getNavigation, registerFileAction, View } from '@nextcloud/files'\nimport { loadState } from '@nextcloud/initial-state'\nimport { translate as t } from '@nextcloud/l10n'\nimport { action as enterCredentialsAction } from './actions/enterCredentialsAction.ts'\nimport { action as inlineStorageCheckAction } from './actions/inlineStorageCheckAction.ts'\nimport { action as openInFilesAction } from './actions/openInFilesAction.ts'\nimport { getContents } from './services/externalStorage.ts'\n\nconst allowUserMounting = loadState('files_external', 'allowUserMounting', false)\n\n// Register view\nconst Navigation = getNavigation()\nNavigation.register(new View({\n\tid: 'extstoragemounts',\n\tname: t('files_external', 'External storage'),\n\tcaption: t('files_external', 'List of external storage.'),\n\n\temptyCaption: allowUserMounting\n\t\t? t('files_external', 'There is no external storage configured. You can configure them in your Personal settings.')\n\t\t: t('files_external', 'There is no external storage configured and you don\\'t have the permission to configure them.'),\n\temptyTitle: t('files_external', 'No external storage'),\n\n\ticon: FolderNetworkSvg,\n\torder: 30,\n\n\tcolumns: [\n\t\tnew Column({\n\t\t\tid: 'storage-type',\n\t\t\ttitle: t('files_external', 'Storage type'),\n\t\t\trender(node) {\n\t\t\t\tconst backend = node.attributes?.backend || t('files_external', 'Unknown')\n\t\t\t\tconst span = document.createElement('span')\n\t\t\t\tspan.textContent = backend\n\t\t\t\treturn span\n\t\t\t},\n\t\t}),\n\t\tnew Column({\n\t\t\tid: 'scope',\n\t\t\ttitle: t('files_external', 'Scope'),\n\t\t\trender(node) {\n\t\t\t\tconst span = document.createElement('span')\n\t\t\t\tlet scope = t('files_external', 'Personal')\n\t\t\t\tif (node.attributes?.scope === 'system') {\n\t\t\t\t\tscope = t('files_external', 'System')\n\t\t\t\t}\n\t\t\t\tspan.textContent = scope\n\t\t\t\treturn span\n\t\t\t},\n\t\t}),\n\t],\n\n\tgetContents,\n}))\n\n// Register actions\nregisterFileAction(enterCredentialsAction)\nregisterFileAction(inlineStorageCheckAction)\nregisterFileAction(openInFilesAction)\n"],"file":"files_external-init.mjs"} \ No newline at end of file +{"version":3,"mappings":"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","names":["FolderNetworkSvg","LoginSvg","isMissingAuthConfig","config","StorageStatus","isNodeExternalStorage","node","FileType","attributes","addPasswordConfirmationInterceptors","axios","setCredentials","login","password","generateUrl","PwdConfirmationMode","showError","t","showSuccess","emit","ACTION_CREDENTIALS_EXTERNAL_STORAGE","action","nodes","spawnDialog","defineAsyncComponent","error","DefaultType","AlertSvg","rootPath","getCurrentUser","entryToFolder","ocsEntry","path","Folder","generateRemoteUrl","Permission","getContents","contents","generateOcsUrl","getStatus","id","global","type","span","data","showWarning","isWarning","overlay","view","showConfirmation","scope","allowUserMounting","loadState","Navigation","getNavigation","View","Column","backend","registerFileAction","enterCredentialsAction","inlineStorageCheckAction","openInFilesAction"],"ignoreList":[0,1,5],"sources":["../node_modules/@mdi/svg/svg/folder-network-outline.svg?raw","../node_modules/@mdi/svg/svg/login.svg?raw","../build/frontend/apps/files_external/src/utils/credentialsUtils.ts","../build/frontend/apps/files_external/src/utils/externalStorageUtils.ts","../build/frontend/apps/files_external/src/actions/enterCredentialsAction.ts","../node_modules/@mdi/svg/svg/alert-circle.svg?raw","../build/frontend/apps/files_external/src/services/externalStorage.ts","../build/frontend/apps/files_external/src/actions/inlineStorageCheckAction.ts","../build/frontend/apps/files_external/src/actions/openInFilesAction.ts","../build/frontend/apps/files_external/src/init-files.ts"],"sourcesContent":["export default \"\"","export default \"\"","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IStorage } from '../types.ts'\n\nimport { StorageStatus } from '../types.ts'\n\n/**\n * Check if the given storage configuration is missing authentication configuration\n *\n * @param config - The storage configuration to check\n */\nexport function isMissingAuthConfig(config: IStorage) {\n\t// If we don't know the status, assume it is ok\n\tif (config.status === undefined || config.status === StorageStatus.Success) {\n\t\treturn false\n\t}\n\n\treturn config.userProvided || config.authMechanism === 'password::global::user'\n}\n","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { INode } from '@nextcloud/files'\nimport type { MountEntry } from '../services/externalStorage.ts'\n\nimport { FileType } from '@nextcloud/files'\n\n/**\n * Check if the given node represents an external storage mount\n *\n * @param node - The node to check\n */\nexport function isNodeExternalStorage(node: INode) {\n\t// Not a folder, not a storage\n\tif (node.type === FileType.File) {\n\t\treturn false\n\t}\n\n\t// No backend or scope, not a storage\n\tconst attributes = node.attributes as MountEntry\n\tif (!attributes.scope || !attributes.backend) {\n\t\treturn false\n\t}\n\n\t// Specific markers that we're sure are ext storage only\n\treturn attributes.scope === 'personal' || attributes.scope === 'system'\n}\n","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { AxiosResponse } from '@nextcloud/axios'\nimport type { IFileAction, INode } from '@nextcloud/files'\nimport type { IStorage } from '../types.ts'\n\nimport LoginSvg from '@mdi/svg/svg/login.svg?raw'\nimport axios from '@nextcloud/axios'\nimport { showError, showSuccess } from '@nextcloud/dialogs'\nimport { emit } from '@nextcloud/event-bus'\nimport { DefaultType } from '@nextcloud/files'\nimport { t } from '@nextcloud/l10n'\nimport { addPasswordConfirmationInterceptors, PwdConfirmationMode } from '@nextcloud/password-confirmation'\nimport { generateUrl } from '@nextcloud/router'\nimport { spawnDialog } from '@nextcloud/vue/functions/dialog'\nimport { defineAsyncComponent } from 'vue'\nimport { StorageStatus } from '../types.ts'\nimport { isMissingAuthConfig } from '../utils/credentialsUtils.ts'\nimport { isNodeExternalStorage } from '../utils/externalStorageUtils.ts'\n\n// Add password confirmation interceptors as\n// the backend requires the user to confirm their password\naddPasswordConfirmationInterceptors(axios)\n\n/**\n * Set credentials for external storage\n *\n * @param node The node for which to set the credentials\n * @param login The username\n * @param password The password\n */\nasync function setCredentials(node: INode, login: string, password: string): Promise {\n\tconst configResponse = await axios.request({\n\t\tmethod: 'PUT',\n\t\turl: generateUrl('apps/files_external/userglobalstorages/{id}', { id: node.id }),\n\t\tconfirmPassword: PwdConfirmationMode.Strict,\n\t\tdata: {\n\t\t\tbackendOptions: { user: login, password },\n\t\t},\n\t}) as AxiosResponse\n\n\tconst config = configResponse.data\n\tif (config.status !== StorageStatus.Success) {\n\t\tshowError(t('files_external', 'Unable to update this external storage config. {statusMessage}', {\n\t\t\tstatusMessage: config?.statusMessage || '',\n\t\t}))\n\t\treturn null\n\t}\n\n\t// Success update config attribute\n\tshowSuccess(t('files_external', 'New configuration successfully saved'))\n\tnode.attributes.config = config\n\temit('files:node:updated', node)\n\n\treturn true\n}\n\nexport const ACTION_CREDENTIALS_EXTERNAL_STORAGE = 'credentials-external-storage'\n\nexport const action: IFileAction = {\n\tid: ACTION_CREDENTIALS_EXTERNAL_STORAGE,\n\tdisplayName: () => t('files', 'Enter missing credentials'),\n\ticonSvgInline: () => LoginSvg,\n\n\tenabled: ({ nodes }) => {\n\t\t// Only works on single node\n\t\tif (nodes.length !== 1 || !nodes[0]) {\n\t\t\treturn false\n\t\t}\n\n\t\tconst node = nodes[0]\n\t\tif (!isNodeExternalStorage(node)) {\n\t\t\treturn false\n\t\t}\n\n\t\tconst config = (node.attributes?.config || {}) as IStorage\n\t\tif (isMissingAuthConfig(config)) {\n\t\t\treturn true\n\t\t}\n\n\t\treturn false\n\t},\n\n\tasync exec({ nodes }) {\n\t\tconst { login, password } = await spawnDialog(defineAsyncComponent(() => import('../views/CredentialsDialog.vue'))) ?? {}\n\t\tif (login && password) {\n\t\t\ttry {\n\t\t\t\tawait setCredentials(nodes[0]!, login, password)\n\t\t\t\tshowSuccess(t('files_external', 'Credentials successfully set'))\n\t\t\t} catch (error) {\n\t\t\t\tshowError(t('files_external', 'Error while setting credentials: {error}', {\n\t\t\t\t\terror: (error as Error).message,\n\t\t\t\t}))\n\t\t\t}\n\t\t}\n\n\t\treturn null\n\t},\n\n\t// Before openFolderAction\n\torder: -1000,\n\tdefault: DefaultType.DEFAULT,\n\tinline: () => true,\n}\n","export default \"\"","/**\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { AxiosResponse } from '@nextcloud/axios'\nimport type { ContentsWithRoot } from '@nextcloud/files'\nimport type { OCSResponse } from '@nextcloud/typings/ocs'\nimport type { IStorage } from '../types.ts'\n\nimport { getCurrentUser } from '@nextcloud/auth'\nimport axios from '@nextcloud/axios'\nimport { Folder, Permission } from '@nextcloud/files'\nimport { generateOcsUrl, generateRemoteUrl, generateUrl } from '@nextcloud/router'\nimport { StorageStatus } from '../types.ts'\n\nexport const rootPath = `/files/${getCurrentUser()?.uid}`\n\n/**\n * https://github.com/nextcloud/server/blob/ac2bc2384efe3c15ff987b87a7432bc60d545c67/apps/files_external/lib/Controller/ApiController.php#L71-L97\n */\nexport type MountEntry = {\n\tname: string\n\tpath: string\n\ttype: 'dir'\n\tbackend: 'SFTP'\n\tscope: 'system' | 'personal'\n\tpermissions: number\n\tid: number\n\tclass: string\n\tconfig: IStorage\n}\n\n/**\n * Convert an OCS api result (mount entry) to a Folder instance\n *\n * @param ocsEntry - The OCS mount entry\n */\nfunction entryToFolder(ocsEntry: MountEntry): Folder {\n\tconst path = (ocsEntry.path + '/' + ocsEntry.name).replace(/^\\//gm, '')\n\treturn new Folder({\n\t\tid: ocsEntry.id,\n\t\tsource: generateRemoteUrl('dav' + rootPath + '/' + path),\n\t\troot: rootPath,\n\t\towner: getCurrentUser()?.uid || null,\n\t\tpermissions: ocsEntry.config.status !== StorageStatus.Success\n\t\t\t? Permission.NONE\n\t\t\t: ocsEntry?.permissions || Permission.READ,\n\t\tattributes: {\n\t\t\tdisplayName: path,\n\t\t\t...ocsEntry,\n\t\t},\n\t})\n}\n\n/**\n * Fetch the contents of external storage mounts\n */\nexport async function getContents(): Promise {\n\tconst response = await axios.get(generateOcsUrl('apps/files_external/api/v1/mounts')) as AxiosResponse>\n\tconst contents = response.data.ocs.data.map(entryToFolder)\n\n\treturn {\n\t\tfolder: new Folder({\n\t\t\tid: 0,\n\t\t\tsource: generateRemoteUrl('dav' + rootPath),\n\t\t\troot: rootPath,\n\t\t\towner: getCurrentUser()?.uid || null,\n\t\t\tpermissions: Permission.READ,\n\t\t}),\n\t\tcontents,\n\t}\n}\n\n/**\n * Get the status of an external storage mount\n *\n * @param id - The storage ID\n * @param global - Whether the storage is global or user specific\n */\nexport function getStatus(id: number, global = true) {\n\tconst type = global ? 'userglobalstorages' : 'userstorages'\n\treturn axios.get(generateUrl(`apps/files_external/${type}/${id}?testOnly=false`)) as Promise>\n}\n","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { AxiosError } from '@nextcloud/axios'\nimport type { IFileAction } from '@nextcloud/files'\nimport type { IStorage } from '../types.ts'\n\nimport AlertSvg from '@mdi/svg/svg/alert-circle.svg?raw'\nimport { showWarning } from '@nextcloud/dialogs'\nimport { emit } from '@nextcloud/event-bus'\nimport { t } from '@nextcloud/l10n'\nimport { getStatus } from '../services/externalStorage.ts'\nimport { StorageStatus } from '../types.ts'\nimport { isMissingAuthConfig } from '../utils/credentialsUtils.ts'\nimport { isNodeExternalStorage } from '../utils/externalStorageUtils.ts'\n\nimport '../css/fileEntryStatus.scss'\n\nexport const action: IFileAction = {\n\tid: 'check-external-storage',\n\tdisplayName: () => '',\n\ticonSvgInline: () => '',\n\n\tenabled: ({ nodes }) => {\n\t\treturn nodes.every((node) => isNodeExternalStorage(node) === true)\n\t},\n\texec: async () => null,\n\n\t/**\n\t * Use this function to check the storage availability\n\t * We then update the node attributes directly.\n\t *\n\t * @param context - The action context\n\t * @param context.nodes - The node to render inline\n\t */\n\tasync renderInline({ nodes }) {\n\t\tif (nodes.length !== 1 || !nodes[0]) {\n\t\t\treturn null\n\t\t}\n\n\t\tconst node = nodes[0]\n\t\tconst span = document.createElement('span')\n\t\tspan.className = 'files-list__row-status'\n\t\tspan.innerHTML = t('files_external', 'Checking storage …')\n\n\t\tlet config: IStorage | undefined\n\t\ttry {\n\t\t\tconst { data } = await getStatus(node.id, node.attributes.scope === 'system')\n\t\t\tconfig = data\n\t\t\tnode.attributes.config = config\n\t\t\temit('files:node:updated', node)\n\n\t\t\tif (config.status !== StorageStatus.Success) {\n\t\t\t\tthrow new Error(config?.statusMessage || t('files_external', 'There was an error with this external storage.'))\n\t\t\t}\n\n\t\t\tspan.remove()\n\t\t} catch (error) {\n\t\t\t// If axios failed or if something else prevented\n\t\t\t// us from getting the config\n\t\t\tif ((error as AxiosError).response && !config) {\n\t\t\t\tshowWarning(t('files_external', 'We were unable to check the external storage {basename}', {\n\t\t\t\t\tbasename: node.basename,\n\t\t\t\t}))\n\t\t\t}\n\n\t\t\t// Reset inline status\n\t\t\tspan.innerHTML = ''\n\n\t\t\t// Checking if we really have an error\n\t\t\tconst isWarning = !config ? false : isMissingAuthConfig(config)\n\t\t\tconst overlay = document.createElement('span')\n\t\t\toverlay.classList.add(`files-list__row-status--${isWarning ? 'warning' : 'error'}`)\n\n\t\t\t// Only show an icon for errors, warning like missing credentials\n\t\t\t// have a dedicated inline action button\n\t\t\tif (!isWarning) {\n\t\t\t\tspan.innerHTML = AlertSvg\n\t\t\t\tspan.title = (error as Error).message\n\t\t\t}\n\n\t\t\tspan.prepend(overlay)\n\t\t}\n\n\t\treturn span\n\t},\n\n\torder: 10,\n}\n","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IFileAction } from '@nextcloud/files'\nimport type { IStorage } from '../types.ts'\n\nimport { getCurrentUser } from '@nextcloud/auth'\nimport { showConfirmation } from '@nextcloud/dialogs'\nimport { DefaultType } from '@nextcloud/files'\nimport { t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { StorageStatus } from '../types.ts'\n\nexport const action: IFileAction = {\n\tid: 'open-in-files-external-storage',\n\tdisplayName: ({ nodes }) => {\n\t\tconst config = nodes?.[0]?.attributes?.config as IStorage || { status: StorageStatus.Indeterminate }\n\t\tif (config.status !== StorageStatus.Success) {\n\t\t\treturn t('files_external', 'Examine this faulty external storage configuration')\n\t\t}\n\t\treturn t('files', 'Open in Files')\n\t},\n\ticonSvgInline: () => '',\n\n\tenabled: ({ view }) => view.id === 'extstoragemounts',\n\n\tasync exec({ nodes }) {\n\t\tconst config = nodes[0]?.attributes?.config as IStorage\n\t\tif (config?.status !== StorageStatus.Success) {\n\t\t\tconst redirect = await showConfirmation({\n\t\t\t\tname: t('files_external', 'External mount error'),\n\t\t\t\ttext: t('files_external', 'There was an error with this external storage. Do you want to review this mount point config in the settings page?'),\n\t\t\t\tlabelConfirm: t('files_external', 'Open settings'),\n\t\t\t\tlabelReject: t('files_external', 'Ignore'),\n\t\t\t})\n\t\t\tif (redirect === true) {\n\t\t\t\tconst scope = getCurrentUser()?.isAdmin ? 'admin' : 'user'\n\t\t\t\twindow.location.href = generateUrl(`/settings/${scope}/externalstorages`)\n\t\t\t}\n\t\t\treturn null\n\t\t}\n\n\t\t// Do not use fileid as we don't have that information\n\t\t// from the external storage api\n\t\twindow.OCP.Files.Router.goToRoute(\n\t\t\tnull, // use default route\n\t\t\t{ view: 'files' },\n\t\t\t{ dir: nodes[0].path },\n\t\t)\n\t\treturn null\n\t},\n\n\t// Before openFolderAction\n\torder: -1000,\n\tdefault: DefaultType.HIDDEN,\n}\n","/*\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport FolderNetworkSvg from '@mdi/svg/svg/folder-network-outline.svg?raw'\nimport { Column, getNavigation, registerFileAction, View } from '@nextcloud/files'\nimport { loadState } from '@nextcloud/initial-state'\nimport { translate as t } from '@nextcloud/l10n'\nimport { action as enterCredentialsAction } from './actions/enterCredentialsAction.ts'\nimport { action as inlineStorageCheckAction } from './actions/inlineStorageCheckAction.ts'\nimport { action as openInFilesAction } from './actions/openInFilesAction.ts'\nimport { getContents } from './services/externalStorage.ts'\n\nconst allowUserMounting = loadState('files_external', 'allowUserMounting', false)\n\n// Register view\nconst Navigation = getNavigation()\nNavigation.register(new View({\n\tid: 'extstoragemounts',\n\tname: t('files_external', 'External storage'),\n\tcaption: t('files_external', 'List of external storage.'),\n\n\temptyCaption: allowUserMounting\n\t\t? t('files_external', 'There is no external storage configured. You can configure them in your Personal settings.')\n\t\t: t('files_external', 'There is no external storage configured and you don\\'t have the permission to configure them.'),\n\temptyTitle: t('files_external', 'No external storage'),\n\n\ticon: FolderNetworkSvg,\n\torder: 30,\n\n\tcolumns: [\n\t\tnew Column({\n\t\t\tid: 'storage-type',\n\t\t\ttitle: t('files_external', 'Storage type'),\n\t\t\trender(node) {\n\t\t\t\tconst backend = node.attributes?.backend || t('files_external', 'Unknown')\n\t\t\t\tconst span = document.createElement('span')\n\t\t\t\tspan.textContent = backend\n\t\t\t\treturn span\n\t\t\t},\n\t\t}),\n\t\tnew Column({\n\t\t\tid: 'scope',\n\t\t\ttitle: t('files_external', 'Scope'),\n\t\t\trender(node) {\n\t\t\t\tconst span = document.createElement('span')\n\t\t\t\tlet scope = t('files_external', 'Personal')\n\t\t\t\tif (node.attributes?.scope === 'system') {\n\t\t\t\t\tscope = t('files_external', 'System')\n\t\t\t\t}\n\t\t\t\tspan.textContent = scope\n\t\t\t\treturn span\n\t\t\t},\n\t\t}),\n\t],\n\n\tgetContents,\n}))\n\n// Register actions\nregisterFileAction(enterCredentialsAction)\nregisterFileAction(inlineStorageCheckAction)\nregisterFileAction(openInFilesAction)\n"],"file":"files_external-init.mjs"} \ No newline at end of file