Skip to content

Commit 5ffc49b

Browse files
committed
refactor(comments): migrate to Vue 3
Signed-off-by: Edward Ly <contact@edward.ly>
1 parent b5d5602 commit 5ffc49b

File tree

6 files changed

+60
-78
lines changed

6 files changed

+60
-78
lines changed

apps/comments/lib/Listener/LoadSidebarScripts.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ public function handle(Event $event): void {
3434
$this->commentsManager->load();
3535

3636
$this->initialState->provideInitialState('activityEnabled', $this->appManager->isEnabledForUser('activity'));
37-
// Add comments sidebar tab script
37+
// Add comments sidebar tab script/style
38+
Util::addStyle(Application::APP_ID, 'comments-tab');
3839
Util::addScript(Application::APP_ID, 'comments-tab', 'files');
3940
}
4041
}

apps/comments/src/comments-activity-tab.ts

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,44 +6,38 @@
66
import type { INode } from '@nextcloud/files'
77

88
import moment from '@nextcloud/moment'
9-
import { createPinia, PiniaVuePlugin } from 'pinia'
10-
import Vue, { type ComponentPublicInstance } from 'vue'
9+
import { createPinia } from 'pinia'
10+
import { type ComponentPublicInstance, createApp } from 'vue'
1111
import logger from './logger.ts'
1212
import { getComments } from './services/GetComments.ts'
1313

14-
Vue.use(PiniaVuePlugin)
15-
16-
let ActivityTabPluginView
17-
let ActivityTabPluginInstance
18-
1914
/**
2015
* Register the comments plugins for the Activity sidebar
2116
*/
2217
export function registerCommentsPlugins() {
18+
let app
19+
2320
window.OCA.Activity.registerSidebarAction({
2421
mount: async (el: HTMLElement, { node, reload }: { node: INode, reload: () => void }) => {
2522
const pinia = createPinia()
2623

27-
if (!ActivityTabPluginView) {
24+
if (!app) {
2825
const { default: ActivityCommentAction } = await import('./views/ActivityCommentAction.vue')
29-
// @ts-expect-error Types are broken for Vue2
30-
ActivityTabPluginView = Vue.extend(ActivityCommentAction)
26+
app = createApp(
27+
ActivityCommentAction,
28+
{
29+
reloadCallback: reload,
30+
resourceId: node.fileid,
31+
},
32+
)
3133
}
32-
ActivityTabPluginInstance = new ActivityTabPluginView({
33-
el,
34-
pinia,
35-
propsData: {
36-
reloadCallback: reload,
37-
resourceId: node.fileid,
38-
},
39-
})
34+
app.use(pinia)
35+
app.mount(el)
4036
logger.info('Comments plugin mounted in Activity sidebar action', { node })
4137
},
4238
unmount: () => {
4339
// destroy previous instance if available
44-
if (ActivityTabPluginInstance) {
45-
ActivityTabPluginInstance.$destroy()
46-
}
40+
app?.unmount()
4741
},
4842
})
4943

@@ -57,26 +51,25 @@ export function registerCommentsPlugins() {
5751
)
5852
logger.debug('Loaded comments', { node, comments })
5953
const { default: CommentView } = await import('./views/ActivityCommentEntry.vue')
60-
// @ts-expect-error Types are broken for Vue2
61-
const CommentsViewObject = Vue.extend(CommentView)
6254

6355
return comments.map((comment) => ({
6456
_CommentsViewInstance: undefined as ComponentPublicInstance | undefined,
6557

6658
timestamp: moment(comment.props?.creationDateTime).toDate().getTime(),
6759

6860
mount(element: HTMLElement, { reload }) {
69-
this._CommentsViewInstance = new CommentsViewObject({
70-
el: element,
71-
propsData: {
61+
this._CommentsViewInstance = createApp(
62+
CommentView,
63+
{
7264
comment,
7365
resourceId: node.fileid,
7466
reloadCallback: reload,
7567
},
76-
})
68+
)
69+
this._CommentsViewInstance.mount(el)
7770
},
7871
unmount() {
79-
this._CommentsViewInstance?.$destroy()
72+
this._CommentsViewInstance?.unmount()
8073
},
8174
}))
8275
})

apps/comments/src/components/Comment.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
:model-value="localMessage"
7676
:user-data="userData"
7777
aria-describedby="tab-comments__editor-description"
78-
@update:value="updateLocalMessage"
78+
@update:model-value="updateLocalMessage"
7979
@submit="onSubmit" />
8080
<div class="comment__submit">
8181
<NcButton
@@ -104,7 +104,7 @@
104104
:text="richContent.message"
105105
:arguments="richContent.mentions"
106106
use-markdown
107-
@click.native="onExpand" />
107+
@click="onExpand" />
108108
</div>
109109
</component>
110110
</template>

apps/comments/src/files-sidebar.ts

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,13 @@
44
*/
55

66
import MessageReplyText from '@mdi/svg/svg/message-reply-text.svg?raw'
7-
import { getCSPNonce } from '@nextcloud/auth'
87
import { registerSidebarTab } from '@nextcloud/files'
98
import { t } from '@nextcloud/l10n'
10-
import wrap from '@vue/web-component-wrapper'
11-
import { createPinia, PiniaVuePlugin } from 'pinia'
12-
import Vue from 'vue'
9+
import { createPinia } from 'pinia'
10+
import { defineCustomElement } from 'vue'
1311
import { registerCommentsPlugins } from './comments-activity-tab.ts'
1412
import { isUsingActivityIntegration } from './utils/activity.ts'
1513

16-
__webpack_nonce__ = getCSPNonce()
17-
1814
const tagName = 'comments_files-sidebar-tab'
1915

2016
if (isUsingActivityIntegration()) {
@@ -32,17 +28,15 @@ if (isUsingActivityIntegration()) {
3228
async onInit() {
3329
const { default: FilesSidebarTab } = await import('./views/FilesSidebarTab.vue')
3430

35-
Vue.use(PiniaVuePlugin)
36-
Vue.mixin({ pinia: createPinia() })
37-
const webComponent = wrap(Vue, FilesSidebarTab)
38-
// In Vue 2, wrap doesn't support disabling shadow. Disable with a hack
39-
Object.defineProperty(webComponent.prototype, 'attachShadow', {
40-
value() { return this },
41-
})
42-
Object.defineProperty(webComponent.prototype, 'shadowRoot', {
43-
get() { return this },
31+
const FilesSidebarTabElement = defineCustomElement(FilesSidebarTab, {
32+
configureApp(app) {
33+
const pinia = createPinia()
34+
app.use(pinia)
35+
},
36+
shadowRoot: false,
4437
})
45-
window.customElements.define(tagName, webComponent)
38+
39+
window.customElements.define(tagName, FilesSidebarTabElement)
4640
},
4741
})
4842
}

apps/comments/src/services/CommentsInstance.ts

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

6-
import { getCSPNonce } from '@nextcloud/auth'
76
import { n, t } from '@nextcloud/l10n'
8-
import { createPinia, PiniaVuePlugin } from 'pinia'
9-
import Vue from 'vue'
7+
import { createPinia } from 'pinia'
8+
import { createApp } from 'vue'
109
import CommentsApp from '../views/Comments.vue'
1110
import logger from '../logger.ts'
1211

13-
Vue.use(PiniaVuePlugin)
14-
15-
__webpack_nonce__ = getCSPNonce()
16-
17-
// Add translates functions
18-
Vue.mixin({
19-
data() {
20-
return {
21-
logger,
22-
}
23-
},
24-
methods: {
25-
t,
26-
n,
27-
},
28-
})
29-
3012
export default class CommentInstance {
3113
/**
3214
* Initialize a new Comments instance for the desired type
3315
*
3416
* @param {string} resourceType the comments endpoint type
35-
* @param {object} options the vue options (propsData, parent, el...)
17+
* @param {object} options the vue options (propsData, parent, el...)
3618
*/
3719
constructor(resourceType = 'files', options = {}) {
3820
const pinia = createPinia()
3921

40-
// Merge options and set `resourceType` property
41-
options = {
42-
...options,
43-
propsData: {
22+
const app = createApp(
23+
CommentsApp,
24+
{
4425
...(options.propsData ?? {}),
4526
resourceType,
4627
},
47-
pinia,
48-
}
49-
// Init Comments component
50-
const View = Vue.extend(CommentsApp)
51-
return new View(options)
28+
)
29+
30+
// Add translates functions
31+
app.mixin({
32+
data() {
33+
return {
34+
logger,
35+
}
36+
},
37+
methods: {
38+
t,
39+
n,
40+
},
41+
})
42+
43+
app.use(pinia)
44+
// app.mount(options.el)
45+
return app
5246
}
5347
}

apps/comments/src/views/Comments.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@
3333
<Comment
3434
v-for="comment in comments"
3535
:key="comment.props.id"
36+
v-model="comment.props.message"
3637
tag="li"
3738
v-bind="comment.props"
3839
:auto-complete="autoComplete"
3940
:resource-type="resourceType"
40-
:message.sync="comment.props.message"
4141
:resource-id="currentResourceId"
4242
:user-data="genMentionsData(comment.props.mentions)"
4343
class="comments__list"

0 commit comments

Comments
 (0)