Skip to content

Commit affe40e

Browse files
committed
refactor: adjust for Nextcloud 33 new files sidebar API
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
1 parent ccf007b commit affe40e

10 files changed

Lines changed: 213 additions & 84 deletions

File tree

package-lock.json

Lines changed: 96 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"devDependencies": {
6262
"@nextcloud/browserslist-config": "^3.1.2",
6363
"@nextcloud/cypress": "^1.0.0-beta.15",
64+
"@nextcloud/files": "^4.0.0-beta.8",
6465
"@nextcloud/stylelint-config": "^3.1.1",
6566
"@nextcloud/vite-config": "^2.5.2",
6667
"@testing-library/cypress": "^10.1.0",

src/__mocks__/@nextcloud/axios.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import wsData from './activity_ws.json'
21
/**
32
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
43
* SPDX-License-Identifier: AGPL-3.0-or-later
54
*/
65

6+
import wsData from './activity_ws.json' with { type: 'json' }
7+
78
const axios = {
89
/**
910
* @param {string} url URL to get

src/__tests__/ActivityTab.test.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,33 @@
1-
/**
1+
/*!
22
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
33
* SPDX-License-Identifier: AGPL-3.0-or-later
44
*/
5+
6+
import type { VueWrapper } from '@vue/test-utils'
7+
58
import { mount } from '@vue/test-utils'
69
import { expect, test, vi } from 'vitest'
10+
import { nextTick } from 'vue'
711
import ActivityTab from '../views/ActivityTab.vue'
812

913
vi.mock('@nextcloud/axios')
1014

1115
test('Create ActivityTab', async () => {
12-
const wrapper = mount(ActivityTab, {})
16+
const wrapper = mount(ActivityTab, {
17+
props: {
18+
node: { id: 'test' } as any,
19+
},
20+
})
1321

14-
expect(wrapper.vm.$data.activities.length).toBe(0)
15-
16-
await wrapper.vm.update({ id: 'test' })
22+
await new Promise<void>((resolve) => waitFor('ul', wrapper, resolve))
1723

24+
await nextTick()
1825
expect(wrapper.vm.$data.activities.length).toBe(18)
1926
})
27+
28+
function waitFor(query: string, wrapper: VueWrapper, callback: () => void) {
29+
if (wrapper.find(query).exists()) {
30+
return callback()
31+
}
32+
nextTick(() => waitFor(query, wrapper, callback))
33+
}

src/components/ActivitySidebarPlugin.vue

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,18 @@
88
</template>
99

1010
<script setup lang="ts">
11+
import type { INode } from '@nextcloud/files'
1112
import type { IActivitySidebarAction } from '../models/ActivityAPI.ts'
1213
1314
import { getCurrentInstance, onBeforeUnmount, onMounted, ref } from 'vue'
1415
1516
const props = defineProps<{
1617
/** The sidebar plugin */
1718
plugin: IActivitySidebarAction
18-
fileInfo: object | null
19+
/**
20+
* The current node (file or folder)
21+
*/
22+
node: INode
1923
}>()
2024
2125
const emit = defineEmits<{
@@ -25,8 +29,8 @@ const emit = defineEmits<{
2529
const attachTarget = ref<HTMLDivElement>()
2630
2731
onMounted(() => props.plugin.mount(attachTarget.value as HTMLDivElement, {
28-
context: getCurrentInstance()?.proxy,
29-
fileInfo: props.fileInfo,
32+
node: props.node,
33+
context: getCurrentInstance()?.proxy ?? undefined,
3034
reload: () => emit('reload-activities'),
3135
}))
3236
onBeforeUnmount(() => props.plugin.unmount())

src/components/activities/GenericActivity.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
<template>
77
<li class="activity-entry">
88
<NcAvatar
9-
:class="[applyMonochromeIconColor, 'activity-entry__icon', 'activity-icon', 'avatardiv--unknown']"
9+
class="activity-entry__icon activity-icon avatardiv--unknown"
10+
:class="[applyMonochromeIconColor]"
1011
:disable-menu="true"
1112
:disable-tooltip="true"
1213
:url="activity.icon"

src/models/ActivityAPI.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,29 @@
22
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
33
* SPDX-License-Identifier: AGPL-3.0-or-later
44
*/
5+
6+
import type { INode } from '@nextcloud/files'
7+
import type { ComponentPublicInstance } from 'vue'
58
import type ActivityModel from './ActivityModel.js'
69

710
interface MountOptions {
811
/**
912
* Trigger reloading the activities
1013
*/
1114
reload: () => void
12-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
13-
fileInfo: any
14-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
15-
context: any
15+
/**
16+
* The current file or folder context
17+
*/
18+
node: INode
19+
/**
20+
* The current Vue component instance context
21+
*/
22+
context?: ComponentPublicInstance
1623
}
1724

1825
export interface ActivityFactoryQueryOptions {
19-
/** File to show entries for */
20-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
21-
fileInfo: any
26+
/** File or folder to show entries for */
27+
node: INode
2228
/** Limit the number of entries */
2329
limit?: number
2430
/** Offset for the entries queried */
@@ -52,7 +58,7 @@ export interface IActivitySidebarEntry {
5258
/**
5359
* The action is called with the HTML element where is should be mounted
5460
*/
55-
mount: (element: HTMLElement, options: Omit<MountOptions, 'fileInfo'>) => void
61+
mount: (element: HTMLElement, options: Omit<MountOptions, 'node'>) => void
5662

5763
/**
5864
* Called just before the sidebar is destroyed to allow plugins to cleanup

src/sidebar.ts

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

6-
import type { App, Component, ComponentPublicInstance } from 'vue'
7-
import type { ActivityTabType } from './views/ActivityTab.vue'
8-
96
import LightningBolt from '@mdi/svg/svg/lightning-bolt.svg?raw'
10-
import { translate as t } from '@nextcloud/l10n'
11-
import { createApp } from 'vue'
7+
import { registerSidebarTab } from '@nextcloud/files'
8+
import { t } from '@nextcloud/l10n'
9+
import { defineAsyncComponent, defineCustomElement } from 'vue'
1210

13-
// Init Activity tab component
14-
let LazyActivityTab: Component | null = null
15-
let activityTabApp: App<Element> | null = null
16-
let activityTabInstance: ComponentPublicInstance<ActivityTabType> | null = null
11+
window.customElements.define(
12+
'activity-files-sidebar-tab',
13+
defineCustomElement(defineAsyncComponent(() => import('./views/ActivityTab.vue'))),
14+
)
1715

18-
const activityTab = new OCA.Files.Sidebar.Tab({
16+
registerSidebarTab({
1917
id: 'activity',
20-
name: t('activity', 'Activity'),
21-
iconSvg: LightningBolt,
22-
23-
async mount(el, fileInfo) {
24-
// only load if needed
25-
if (LazyActivityTab === null) {
26-
const { default: ActivityTab } = await import('./views/ActivityTab.vue')
27-
LazyActivityTab = ActivityTab
28-
}
29-
// destroy previous instance if available
30-
if (activityTabApp) {
31-
activityTabApp.unmount()
32-
}
33-
activityTabApp = createApp(LazyActivityTab)
34-
// No need to await this, we will show a loading indicator instead
35-
activityTabInstance = activityTabApp.mount(el)
36-
activityTabInstance.update(fileInfo)
37-
},
38-
update(fileInfo) {
39-
activityTabInstance!.update(fileInfo)
18+
order: 50,
19+
displayName: t('activity', 'Activity'),
20+
iconSvgInline: LightningBolt,
21+
tagName: 'activity-files-sidebar-tab',
22+
enabled() {
23+
return true
4024
},
41-
destroy() {
42-
activityTabApp?.unmount()
43-
activityTabApp = null
44-
},
45-
})
46-
47-
window.addEventListener('DOMContentLoaded', async function() {
48-
if (OCA.Files && OCA.Files.Sidebar) {
49-
OCA.Files.Sidebar.registerTab(activityTab)
50-
const { default: ActivityTab } = await import('./views/ActivityTab.vue')
51-
LazyActivityTab = ActivityTab
52-
}
5325
})

0 commit comments

Comments
 (0)