Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
refactor(comments): migrate to new Files Sidebar API
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
  • Loading branch information
susnux committed Jan 5, 2026
commit 34511e9036976218027d8d45cff0d2d9d02c1a1e
18 changes: 6 additions & 12 deletions apps/comments/src/actions/inlineUnreadCommentsAction.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,14 +180,12 @@ describe('Inline unread comments action enabled tests', () => {
describe('Inline unread comments action execute tests', () => {
test('Action opens sidebar', async () => {
const openMock = vi.fn()
const setActiveTabMock = vi.fn()
window.OCA = {
Files: {
// @ts-expect-error Mocking for testing
Sidebar: {
_sidebar: () => ({
open: openMock,
setActiveTab: setActiveTabMock,
},
}),
},
}

Expand All @@ -211,22 +209,19 @@ describe('Inline unread comments action execute tests', () => {
})

expect(result).toBe(null)
expect(setActiveTabMock).toBeCalledWith('comments')
expect(openMock).toBeCalledWith('/foobar.txt')
expect(openMock).toBeCalledWith(file, 'comments')
})

test('Action handles sidebar open failure', async () => {
const openMock = vi.fn(() => {
throw new Error('Mock error')
})
const setActiveTabMock = vi.fn()
window.OCA = {
Files: {
// @ts-expect-error Mocking for testing
Sidebar: {
_sidebar: () => ({
open: openMock,
setActiveTab: setActiveTabMock,
},
}),
},
}
vi.spyOn(logger, 'error').mockImplementation(() => vi.fn())
Expand All @@ -251,8 +246,7 @@ describe('Inline unread comments action execute tests', () => {
})

expect(result).toBe(false)
expect(setActiveTabMock).toBeCalledWith('comments')
expect(openMock).toBeCalledWith('/foobar.txt')
expect(openMock).toBeCalledWith(file, 'comments')
expect(logger.error).toBeCalledTimes(1)
})
})
9 changes: 5 additions & 4 deletions apps/comments/src/actions/inlineUnreadCommentsAction.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
/**
/*!
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import CommentProcessingSvg from '@mdi/svg/svg/comment-processing.svg?raw'
import { FileAction } from '@nextcloud/files'
import { FileAction, getSidebar } from '@nextcloud/files'
import { n, t } from '@nextcloud/l10n'
import logger from '../logger.js'

Expand Down Expand Up @@ -34,8 +35,8 @@ export const action = new FileAction({
}

try {
window.OCA.Files.Sidebar.setActiveTab('comments')
await window.OCA.Files.Sidebar.open(nodes[0].path)
const sidebar = getSidebar()
sidebar.open(nodes[0], 'comments')
return null
} catch (error) {
logger.error('Error while opening sidebar', { error })
Expand Down
59 changes: 0 additions & 59 deletions apps/comments/src/comments-tab.js

This file was deleted.

57 changes: 57 additions & 0 deletions apps/comments/src/files-sidebar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import MessageReplyText from '@mdi/svg/svg/message-reply-text.svg?raw'
import { getCSPNonce } from '@nextcloud/auth'
import { registerSidebarTab } from '@nextcloud/files'
import { loadState } from '@nextcloud/initial-state'
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()

const tagName = 'comments_files-sidebar-tab'

if (loadState('comments', 'activityEnabled', false) && OCA?.Activity?.registerSidebarAction !== undefined) {
// Do not mount own tab but mount into activity
window.addEventListener('DOMContentLoaded', function() {
registerCommentsPlugins()
})
} else {
registerSidebarTab({
id: 'comments',
displayName: t('comments', 'Comments'),
iconSvgInline: MessageReplyText,
order: 50,
tagName,
enabled() {
if (!window.customElements.get(tagName)) {
setupSidebarTab()
}
return true
},
})
}

/**
* 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 },
})
window.customElements.define(tagName, webComponent)
}
7 changes: 4 additions & 3 deletions apps/comments/src/mixins/CommentView.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { getCurrentUser } from '@nextcloud/auth'
/**
/*!
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import { getCurrentUser } from '@nextcloud/auth'
import axios from '@nextcloud/axios'
import { loadState } from '@nextcloud/initial-state'
import { generateOcsUrl } from '@nextcloud/router'
Expand Down Expand Up @@ -32,7 +33,7 @@ export default defineComponent({
},
methods: {
/**
* Autocomplete @mentions
* Autocomplete `@mentions`
*
* @param search the query
* @param callback the callback to process the results with
Expand Down
40 changes: 40 additions & 0 deletions apps/comments/src/views/FilesSidebarTab.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!--
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->

<script setup lang="ts">
import type { IFolder, INode, IView } from '@nextcloud/files'

import { computed } from 'vue'
import Comments from './Comments.vue'

const props = defineProps<{
node?: INode
// 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>
<Comments
v-if="resourceId !== undefined"
:key="resourceId"
:resource-id="resourceId"
resource-type="files" />
</template>
Loading