Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 14 additions & 23 deletions apps/comments/src/files-sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { t } from '@nextcloud/l10n'
import wrap from '@vue/web-component-wrapper'
import { createPinia, PiniaVuePlugin } from 'pinia'
import Vue from 'vue'
import FilesSidebarTab from './views/FilesSidebarTab.vue'
import { registerCommentsPlugins } from './comments-activity-tab.ts'

__webpack_nonce__ = getCSPNonce()
Expand All @@ -30,28 +29,20 @@ if (loadState('comments', 'activityEnabled', false) && OCA?.Activity?.registerSi
iconSvgInline: MessageReplyText,
order: 50,
tagName,
enabled() {
if (!window.customElements.get(tagName)) {
setupSidebarTab()
}
return true
},
})
}
async onInit() {
const { default: FilesSidebarTab } = await import('./views/FilesSidebarTab.vue')

/**
* Setup the sidebar tab as a web component
*/
function setupSidebarTab() {
Vue.use(PiniaVuePlugin)
Vue.mixin({ pinia: createPinia() })
const webComponent = wrap(Vue, FilesSidebarTab)
// In Vue 2, wrap doesn't support disabling shadow. Disable with a hack
Object.defineProperty(webComponent.prototype, 'attachShadow', {
value() { return this },
})
Object.defineProperty(webComponent.prototype, 'shadowRoot', {
get() { return this },
Vue.use(PiniaVuePlugin)
Vue.mixin({ pinia: createPinia() })
const webComponent = wrap(Vue, FilesSidebarTab)
// In Vue 2, wrap doesn't support disabling 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)
},
})
window.customElements.define(tagName, webComponent)
}
14 changes: 3 additions & 11 deletions apps/comments/src/views/FilesSidebarTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,16 @@ import Comments from './Comments.vue'

const props = defineProps<{
node?: INode

// eslint-disable-next-line vue/no-unused-properties -- Required on the web component interface
active?: boolean
// eslint-disable-next-line vue/no-unused-properties -- Required on the web component interface
folder?: IFolder
// eslint-disable-next-line vue/no-unused-properties -- Required on the web component interface
view?: IView
}>()

defineExpose({ setActive })

const resourceId = computed(() => props.node?.fileid)

/**
* Set this tab as active
*
* @param active - The active state
*/
function setActive(active: boolean) {
return active
}
</script>

<template>
Expand Down
39 changes: 26 additions & 13 deletions apps/files/src/components/FilesSidebar/FilesSidebarTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
-->

<script setup lang="ts">
import type { ISidebarTab, SidebarComponent } from '@nextcloud/files'
import type { ISidebarTab } from '@nextcloud/files'

import { NcIconSvgWrapper, NcLoadingIcon } from '@nextcloud/vue'
import { ref, toRef, watch, watchEffect } from 'vue'
import { ref, toRef, watch } from 'vue'
import NcAppSidebarTab from '@nextcloud/vue/components/NcAppSidebarTab'
import NcEmptyContent from '@nextcloud/vue/components/NcEmptyContent'
import logger from '../../logger.ts'
import { useActiveStore } from '../../store/active.ts'
import { useSidebarStore } from '../../store/sidebar.ts'

Expand All @@ -29,19 +30,31 @@ const sidebar = useSidebarStore()
const activeStore = useActiveStore()

const loading = ref(true)
watch(toRef(props, 'tab'), async () => {
watch(toRef(props, 'active'), async (active) => {
if (!active) {
return
}

logger.debug('sidebar: activating files sidebar tab ' + props.tab.id, { tab: props.tab })
loading.value = true
await window.customElements.whenDefined(props.tab.tagName)
loading.value = false
try {
if (!initializedTabs.has(props.tab.tagName)) {
initializedTabs.add(props.tab.tagName)
logger.debug('sidebar: initializing ' + props.tab.id)
await props.tab.onInit?.()
}
logger.debug('sidebar: waiting for sidebar tab component becoming defined ' + props.tab.id)
await window.customElements.whenDefined(props.tab.tagName)
logger.debug('sidebar: tab component defined and loaded ' + props.tab.id)
loading.value = false
} catch (error) {
logger.error('Failed to get sidebar tab web component', { error })
}
}, { immediate: true })
</script>

const tabElement = ref<SidebarComponent>()
watchEffect(async () => {
if (tabElement.value) {
// Mark as active
await tabElement.value.setActive?.(props.active)
}
})
<script lang="ts">
const initializedTabs = new Set<string>()
</script>

<template>
Expand All @@ -61,7 +74,7 @@ watchEffect(async () => {
<component
:is="tab.tagName"
v-else
ref="tabElement"
:active.prop="active"
:node.prop="sidebar.currentNode"
:folder.prop="activeStore.activeFolder"
:view.prop="activeStore.activeView" />
Expand Down
4 changes: 2 additions & 2 deletions apps/files/src/store/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export const useSidebarStore = defineStore('sidebar', () => {
function getTabs(context?: ISidebarContext) {
let tabs = getSidebarTabs()
if (context) {
tabs = tabs.filter((tab) => tab.enabled(context))
tabs = tabs.filter((tab) => tab.enabled === undefined || tab.enabled(context))
}
return tabs.sort((a, b) => a.order - b.order)
}
Expand All @@ -98,7 +98,7 @@ export const useSidebarStore = defineStore('sidebar', () => {
function getActions(context?: ISidebarContext) {
let actions = getSidebarActions()
if (context) {
actions = actions.filter((tab) => tab.enabled(context))
actions = actions.filter((action) => action.enabled === undefined || action.enabled(context))
}
return actions.sort((a, b) => a.order - b.order)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@

import ShareVariant from '@mdi/svg/svg/share-variant.svg?raw'
import { getCSPNonce } from '@nextcloud/auth'
import { registerSidebarTab } from '@nextcloud/files'
import { getSidebar } 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'
Expand All @@ -27,32 +26,25 @@ Vue.prototype.n = n

const tagName = 'files_sharing-sidebar-tab'

registerSidebarTab({
getSidebar().registerTab({
id: 'sharing',
displayName: t('files_sharing', 'Sharing'),
iconSvgInline: ShareVariant,
order: 10,
tagName,
enabled() {
if (!window.customElements.get(tagName)) {
setupSidebarTab()
}
return true

async onInit() {
const { default: FilesSidebarTab } = await import('./views/FilesSidebarTab.vue')

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)
},
})

/**
* 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)
}
3 changes: 3 additions & 0 deletions apps/files_sharing/src/views/FilesSidebarTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import FileInfo from '../services/FileInfo.ts'

const props = defineProps<{
node?: INode

// eslint-disable-next-line vue/no-unused-properties -- Required on the web component interface
active?: boolean
// eslint-disable-next-line vue/no-unused-properties -- Required on the web component interface
folder?: IFolder
// eslint-disable-next-line vue/no-unused-properties -- Required on the web component interface
Expand Down
26 changes: 8 additions & 18 deletions apps/files_versions/src/sidebar_tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import { isPublicShare } from '@nextcloud/sharing/public'
import { defineAsyncComponent, defineCustomElement } from 'vue'

const tagName = 'files-versions_sidebar-tab'
const FilesVersionsSidebarTab = defineAsyncComponent(() => import('./views/FilesVersionsSidebarTab.vue'))

registerSidebarTab({
id: 'files_versions',
tagName,
order: 90,
displayName: t('files_versions', 'Versions'),
iconSvgInline: BackupRestore,
Expand All @@ -24,23 +24,13 @@ registerSidebarTab({
if (node.type !== FileType.File) {
return false
}
// setup tab
setupTab()
return true
},
tagName,
})

/**
* Setup the custom element for the Files Versions sidebar tab.
*/
function setupTab() {
if (window.customElements.get(tagName)) {
// already defined
return
}

window.customElements.define(tagName, defineCustomElement(FilesVersionsSidebarTab, {
shadowRoot: false,
}))
}
async onInit() {
const FilesVersionsSidebarTab = defineAsyncComponent(() => import('./views/FilesVersionsSidebarTab.vue'))
window.customElements.define(tagName, defineCustomElement(FilesVersionsSidebarTab, {
shadowRoot: false,
}))
},
})
24 changes: 8 additions & 16 deletions apps/files_versions/src/views/FilesVersionsSidebarTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
:key="row.items[0].version.mtime"
:can-view="canView"
:can-compare="canCompare"
:load-preview="isActive"
:load-preview="active"
:version="row.items[0].version"
:node="node"
:is-current="row.items[0].version.mtime === currentVersionMtime"
Expand Down Expand Up @@ -57,15 +57,16 @@ import logger from '../utils/logger.ts'
import { deleteVersion, fetchVersions, restoreVersion, setVersionLabel } from '../utils/versions.ts'

const props = defineProps<{
node?: INode
folder?: IFolder
view?: IView
}>()
active: boolean
node: INode

defineExpose({ setActive })
// eslint-disable-next-line vue/no-unused-properties -- required by SidebarTab but we do not need it
folder: IFolder
// eslint-disable-next-line vue/no-unused-properties -- required by SidebarTab but we do not need it
view: IView
}>()

const isMobile = useIsMobile()
const isActive = ref<boolean>(false)
const versions = ref<Version[]>([])
const loading = ref(false)
const showVersionLabelForm = ref(false)
Expand Down Expand Up @@ -138,15 +139,6 @@ const canCompare = computed(() => {
&& window.OCA.Viewer?.mimetypesCompare?.includes(props.node?.mime)
})

/**
* This method is called by the files app if the sidebar tab state changes.
*
* @param active - The new active state
*/
function setActive(active: boolean) {
isActive.value = active
}

/**
* Handle restored event from Version.vue
*
Expand Down
8 changes: 4 additions & 4 deletions build/frontend-legacy/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion build/frontend-legacy/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"@nextcloud/capabilities": "^1.2.1",
"@nextcloud/dialogs": "^7.1.0",
"@nextcloud/event-bus": "^3.3.3",
"@nextcloud/files": "^4.0.0-beta.9",
"@nextcloud/files": "^4.0.0-rc.0",
"@nextcloud/initial-state": "^3.0.0",
"@nextcloud/l10n": "^3.4.1",
"@nextcloud/logger": "^3.0.3",
Expand Down
2 changes: 1 addition & 1 deletion build/frontend-legacy/webpack.modules.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ module.exports = {
files_sharing: {
additionalScripts: path.join(__dirname, 'apps/files_sharing/src', 'additionalScripts.js'),
collaboration: path.join(__dirname, 'apps/files_sharing/src', 'collaborationresourceshandler.js'),
files_sharing_tab: path.join(__dirname, 'apps/files_sharing/src', 'files_sharing_tab.js'),
files_sharing_tab: path.join(__dirname, 'apps/files_sharing/src', 'files-sidebar.ts'),
init: path.join(__dirname, 'apps/files_sharing/src', 'init.ts'),
'init-public': path.join(__dirname, 'apps/files_sharing/src', 'init-public.ts'),
main: path.join(__dirname, 'apps/files_sharing/src', 'main.ts'),
Expand Down
12 changes: 11 additions & 1 deletion cypress/e2e/files/files-sidebar.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ describe('Files: Sidebar', { testIsolation: true }, () => {
.findByRole('heading', { name: 'file' })
.should('be.visible')

// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(600) // wait for a bit to avoid flakiness

triggerActionForFile('folder', 'details')
cy.get('[data-cy-sidebar]')
.should('be.visible')
Expand Down Expand Up @@ -89,7 +92,11 @@ describe('Files: Sidebar', { testIsolation: true }, () => {
// open the sidebar
triggerActionForFile('file', 'details')
// validate it is open
cy.get('[data-cy-sidebar]').should('be.visible')
cy.get('[data-cy-sidebar]')
.should('be.visible')
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(600) // wait for a bit to avoid flakiness

// delete the file
triggerActionForFile('file', 'delete')
cy.wait('@deleteFile', { timeout: 10000 })
Expand All @@ -116,6 +123,9 @@ describe('Files: Sidebar', { testIsolation: true }, () => {
cy.get('[data-cy-sidebar]').should('be.visible')
cy.url().should('contain', `apps/files/files/${otherFileId}`)

// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(600) // wait for a bit to avoid flakiness

triggerActionForFile('other', 'delete')
cy.wait('@deleteFile')

Expand Down
Loading
Loading