diff --git a/apps/files_sharing/src/files_actions/sharingStatusAction.ts b/apps/files_sharing/src/files_actions/sharingStatusAction.ts
index e81ef8fd8af..9d24a3082a8 100644
--- a/apps/files_sharing/src/files_actions/sharingStatusAction.ts
+++ b/apps/files_sharing/src/files_actions/sharingStatusAction.ts
@@ -3,28 +3,28 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-import type { Node } from '@nextcloud/files'
+import type { INode } from '@nextcloud/files'
import AccountGroupSvg from '@mdi/svg/svg/account-group-outline.svg?raw'
import AccountPlusSvg from '@mdi/svg/svg/account-plus-outline.svg?raw'
import LinkSvg from '@mdi/svg/svg/link.svg?raw'
import { getCurrentUser } from '@nextcloud/auth'
import { showError } from '@nextcloud/dialogs'
-import { FileAction, Permission, registerFileAction } from '@nextcloud/files'
+import { FileAction, getSidebar, Permission, registerFileAction } from '@nextcloud/files'
import { translate as t } from '@nextcloud/l10n'
import { ShareType } from '@nextcloud/sharing'
import { isPublicShare } from '@nextcloud/sharing/public'
import CircleSvg from '../../../../core/img/apps/circles.svg?raw'
-import { action as sidebarAction } from '../../../files/src/actions/sidebarAction.ts'
import { generateAvatarSvg } from '../utils/AccountIcon.ts'
import './sharingStatusAction.scss'
/**
+ * Check if the node is external (federated)
*
- * @param node
+ * @param node - The node to check
*/
-function isExternal(node: Node) {
+function isExternal(node: INode) {
return node.attributes?.['is-federated'] ?? false
}
@@ -136,12 +136,12 @@ export const action = new FileAction({
&& (node.permissions & Permission.READ) !== 0
},
- async exec({ nodes, view, folder, contents }) {
+ async exec({ nodes }) {
// You need read permissions to see the sidebar
const node = nodes[0]
if ((node.permissions & Permission.READ) !== 0) {
- window.OCA?.Files?.Sidebar?.setActiveTab?.('sharing')
- sidebarAction.exec({ nodes, view, folder, contents })
+ const sidebar = getSidebar()
+ sidebar.open(node, 'sharing')
return null
}
diff --git a/apps/files_sharing/src/files_sharing_tab.js b/apps/files_sharing/src/files_sharing_tab.js
index 9e0bc799f49..98191054e82 100644
--- a/apps/files_sharing/src/files_sharing_tab.js
+++ b/apps/files_sharing/src/files_sharing_tab.js
@@ -5,8 +5,11 @@
import ShareVariant from '@mdi/svg/svg/share-variant.svg?raw'
import { getCSPNonce } from '@nextcloud/auth'
+import { registerSidebarTab } from '@nextcloud/files'
import { n, t } from '@nextcloud/l10n'
+import wrap from '@vue/web-component-wrapper'
import Vue from 'vue'
+import FilesSidebarTab from './views/FilesSidebarTab.vue'
import ExternalShareActions from './services/ExternalShareActions.js'
import ShareSearch from './services/ShareSearch.js'
import TabSections from './services/TabSections.js'
@@ -14,9 +17,7 @@ import TabSections from './services/TabSections.js'
__webpack_nonce__ = getCSPNonce()
// Init Sharing Tab Service
-if (!window.OCA.Sharing) {
- window.OCA.Sharing = {}
-}
+window.OCA.Sharing ??= {}
Object.assign(window.OCA.Sharing, { ShareSearch: new ShareSearch() })
Object.assign(window.OCA.Sharing, { ExternalShareActions: new ExternalShareActions() })
Object.assign(window.OCA.Sharing, { ShareTabSections: new TabSections() })
@@ -24,42 +25,34 @@ Object.assign(window.OCA.Sharing, { ShareTabSections: new TabSections() })
Vue.prototype.t = t
Vue.prototype.n = n
-// Init Sharing tab component
-let TabInstance = null
+const tagName = 'files_sharing-sidebar-tab'
-window.addEventListener('DOMContentLoaded', function() {
- if (OCA.Files && OCA.Files.Sidebar) {
- OCA.Files.Sidebar.registerTab(new OCA.Files.Sidebar.Tab({
- id: 'sharing',
- name: t('files_sharing', 'Sharing'),
- iconSvg: ShareVariant,
-
- async mount(el, fileInfo, context) {
- const SharingTab = (await import('./views/SharingTab.vue')).default
- const View = Vue.extend(SharingTab)
-
- if (TabInstance) {
- TabInstance.$destroy()
- }
- TabInstance = new View({
- // Better integration with vue parent component
- parent: context,
- })
- // Only mount after we have all the info we need
- await TabInstance.update(fileInfo)
- TabInstance.$mount(el)
- },
-
- update(fileInfo) {
- TabInstance.update(fileInfo)
- },
-
- destroy() {
- if (TabInstance) {
- TabInstance.$destroy()
- TabInstance = null
- }
- },
- }))
- }
+registerSidebarTab({
+ id: 'sharing',
+ displayName: t('files_sharing', 'Sharing'),
+ iconSvgInline: ShareVariant,
+ order: 10,
+ tagName,
+ enabled() {
+ if (!window.customElements.get(tagName)) {
+ setupSidebarTab()
+ }
+ return true
+ },
})
+
+/**
+ * Setup the sidebar tab as a web component
+ */
+function setupSidebarTab() {
+ const webComponent = wrap(Vue, FilesSidebarTab)
+ // In Vue 2, wrap doesn't support diseabling shadow. Disable with a hack
+ Object.defineProperty(webComponent.prototype, 'attachShadow', {
+ value() { return this },
+ })
+ Object.defineProperty(webComponent.prototype, 'shadowRoot', {
+ get() { return this },
+ })
+
+ window.customElements.define(tagName, webComponent)
+}
diff --git a/apps/files/src/services/FileInfo.ts b/apps/files_sharing/src/services/FileInfo.ts
similarity index 88%
rename from apps/files/src/services/FileInfo.ts
rename to apps/files_sharing/src/services/FileInfo.ts
index f146b662fe8..f8ea6b37310 100644
--- a/apps/files/src/services/FileInfo.ts
+++ b/apps/files_sharing/src/services/FileInfo.ts
@@ -1,11 +1,9 @@
-/**
+/*!
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-/* eslint-disable jsdoc/require-jsdoc */
-
-import type { Attribute, Node } from '@nextcloud/files'
+import type { Attribute, INode } from '@nextcloud/files'
interface RawLegacyFileInfo {
id: number
@@ -30,11 +28,16 @@ export type LegacyFileInfo = RawLegacyFileInfo & {
get: (key: keyof RawLegacyFileInfo) => unknown
isDirectory: () => boolean
canEdit: () => boolean
- node: Node
+ node: INode
canDownload: () => boolean
}
-export default function(node: Node): LegacyFileInfo {
+/**
+ * Convert Node to legacy file info
+ *
+ * @param node - The Node to convert
+ */
+export default function(node: INode): LegacyFileInfo {
const rawFileInfo: RawLegacyFileInfo = {
id: node.fileid!,
path: node.dirname,
diff --git a/apps/files_sharing/src/views/FilesSidebarTab.vue b/apps/files_sharing/src/views/FilesSidebarTab.vue
new file mode 100644
index 00000000000..e46e78722c0
--- /dev/null
+++ b/apps/files_sharing/src/views/FilesSidebarTab.vue
@@ -0,0 +1,21 @@
+
+
+
+
+
diff --git a/apps/files_sharing/src/views/SharingTab.vue b/apps/files_sharing/src/views/SharingTab.vue
index 17398fbcf14..784958c5aed 100644
--- a/apps/files_sharing/src/views/SharingTab.vue
+++ b/apps/files_sharing/src/views/SharingTab.vue
@@ -230,6 +230,13 @@ export default {
mixins: [ShareDetails],
+ props: {
+ fileInfo: {
+ type: Object,
+ required: true,
+ },
+ },
+
data() {
return {
config: new Config(),
@@ -238,8 +245,6 @@ export default {
expirationInterval: null,
loading: true,
- fileInfo: null,
-
// reshare Share object
reshare: null,
sharedWithMe: {},
@@ -328,18 +333,19 @@ export default {
},
},
- methods: {
- /**
- * Update current fileInfo and fetch new data
- *
- * @param {object} fileInfo the current file FileInfo
- */
- async update(fileInfo) {
- this.fileInfo = fileInfo
- this.resetState()
- this.getShares()
+ watch: {
+ fileInfo: {
+ immediate: true,
+ handler(newValue, oldValue) {
+ if (oldValue?.id === undefined || oldValue?.id !== newValue?.id) {
+ this.resetState()
+ this.getShares()
+ }
+ },
},
+ },
+ methods: {
/**
* Get the existing shares infos
*/
diff --git a/cypress/e2e/files_sharing/FilesSharingUtils.ts b/cypress/e2e/files_sharing/FilesSharingUtils.ts
index fb3b3cb72b9..f83f0c9c782 100644
--- a/cypress/e2e/files_sharing/FilesSharingUtils.ts
+++ b/cypress/e2e/files_sharing/FilesSharingUtils.ts
@@ -35,8 +35,12 @@ export function createShare(fileName: string, username: string, shareSettings: P
export function openSharingDetails(index: number) {
cy.get('#app-sidebar-vue').within(() => {
- cy.get('[data-cy-files-sharing-share-actions]').eq(index).click({ force: true })
- cy.get('[data-cy-files-sharing-share-permissions-bundle="custom"]').click()
+ cy.findAllByRole('button', { name: /open sharing details/i })
+ .should('have.length.at.least', index + 1)
+ .eq(index)
+ .click({ force: true })
+ cy.get('[data-cy-files-sharing-share-permissions-bundle="custom"]')
+ .click()
})
}
diff --git a/cypress/e2e/files_sharing/expiry-date.cy.ts b/cypress/e2e/files_sharing/expiry-date.cy.ts
index 32b5239e3a1..0055b499d38 100644
--- a/cypress/e2e/files_sharing/expiry-date.cy.ts
+++ b/cypress/e2e/files_sharing/expiry-date.cy.ts
@@ -90,11 +90,13 @@ describe('files_sharing: Expiry date', () => {
prepareDirectory(dir)
updateShare(dir, 0, { expiryDate: fortnight })
validateExpiryDate(dir, fortnightString)
-
closeSidebar()
+
+ cy.log('Upadate share and validate expiry date is kept')
updateShare(dir, 0, { note: 'Only note changed' })
validateExpiryDate(dir, fortnightString)
+ cy.log('Reload page and validate expiry date is kept')
cy.visit('/apps/files')
validateExpiryDate(dir, fortnightString)
})