From 3997d92af574dd73adf870a4f3162947472a939d Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Tue, 12 Aug 2025 15:20:59 +0800 Subject: [PATCH 1/3] Add allow notification option to comment forms --- packages/comment-widget/src/base-form.ts | 8 ++++++++ packages/comment-widget/src/comment-form.ts | 6 +++--- packages/comment-widget/src/reply-form.ts | 6 +++--- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/comment-widget/src/base-form.ts b/packages/comment-widget/src/base-form.ts index 09dfc416..63af60cd 100644 --- a/packages/comment-widget/src/base-form.ts +++ b/packages/comment-widget/src/base-form.ts @@ -237,7 +237,14 @@ export class BaseForm extends LitElement { ` : '' } +
+ +
+ + +
+ ${ this.showCaptcha && this.captcha ? html` @@ -292,6 +299,7 @@ export class BaseForm extends LitElement { detail: { ...data, content, + allowNotification: data.allowNotification === 'on', }, }); this.dispatchEvent(event); diff --git a/packages/comment-widget/src/comment-form.ts b/packages/comment-widget/src/comment-form.ts index 8dc3e9ec..a359f4ae 100644 --- a/packages/comment-widget/src/comment-form.ts +++ b/packages/comment-widget/src/comment-form.ts @@ -81,13 +81,13 @@ export class CommentForm extends LitElement { const data = e.detail; - const { displayName, email, website, content } = data || {}; + const { displayName, email, website, content, allowNotification } = + data || {}; const commentRequest: CommentRequest = { raw: content, content: content, - // TODO: support user input - allowNotification: true, + allowNotification: allowNotification, subjectRef: { group: this.group, kind: this.kind, diff --git a/packages/comment-widget/src/reply-form.ts b/packages/comment-widget/src/reply-form.ts index 55791f2a..63418d04 100644 --- a/packages/comment-widget/src/reply-form.ts +++ b/packages/comment-widget/src/reply-form.ts @@ -86,13 +86,13 @@ export class ReplyForm extends LitElement { const data = e.detail; - const { displayName, email, website, content } = data || {}; + const { displayName, email, website, content, allowNotification } = + data || {}; const replyRequest: ReplyRequest = { raw: content, content: content, - // TODO: support user input - allowNotification: true, + allowNotification: allowNotification, }; if (this.quoteReply) { From 4e1c3697bbed063e3438f77ff32c1c59a0c18c9d Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Fri, 23 Oct 2026 16:53:17 +0800 Subject: [PATCH 2/3] Cover allow notification option in browser tests --- .../tests/allow-notification.browser.test.js | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 packages/comment-widget/tests/allow-notification.browser.test.js diff --git a/packages/comment-widget/tests/allow-notification.browser.test.js b/packages/comment-widget/tests/allow-notification.browser.test.js new file mode 100644 index 00000000..94ecc3ff --- /dev/null +++ b/packages/comment-widget/tests/allow-notification.browser.test.js @@ -0,0 +1,49 @@ +import { assert, test } from 'vitest'; +import { mockApi, until } from './browser-helpers.js'; + +test.each(['comment-form', 'reply-form'])( + '%s submits the selected allow notification state', + async (tag) => { + const requests = []; + mockApi(async (_input, options = {}) => { + requests.push(JSON.parse(options.body)); + return new Response(JSON.stringify({ spec: { approved: true } }), { + headers: { 'Content-Type': 'application/json' }, + }); + }); + await import('../src/index.ts'); + + const form = document.createElement(tag); + form.comment = { metadata: { name: 'comment-1' } }; + form.currentUser = { metadata: { name: 'commenter' }, spec: {} }; + document.body.append(form); + await form.updateComplete; + const base = form.baseFormRef.value; + base.currentUser = form.currentUser; + await base.updateComplete; + await until(() => base.editorRef.value?.editor); + + const checkbox = base.shadowRoot.querySelector('#allowNotification'); + assert(checkbox, 'Allow notification must be selectable'); + assert(checkbox.checked, 'Allow notification must be enabled by default'); + + base.editorRef.value.editor.commands.setContent('

Notify me

'); + base.shadowRoot.querySelector('form').requestSubmit(); + await until(() => requests.length === 1 && !form.submitting); + assert( + requests[0].allowNotification === true, + 'Checked must send allowNotification=true' + ); + + checkbox.click(); + assert(!checkbox.checked, 'Allow notification must be toggleable'); + base.editorRef.value.editor.commands.setContent('

Do not notify me

'); + base.shadowRoot.querySelector('form').requestSubmit(); + await until(() => requests.length === 2 && !form.submitting); + assert( + requests[1].allowNotification === false, + 'Unchecked must send allowNotification=false' + ); + form.remove(); + } +); From 136327541e3d433b03c2d4cec893691fb010a72e Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Fri, 23 Oct 2026 17:46:27 +0800 Subject: [PATCH 3/3] Add plugin setting to control allow notification option --- packages/comment-widget/src/base-form.ts | 19 ++++++--- packages/comment-widget/src/types/index.ts | 1 + .../tests/allow-notification.browser.test.js | 39 +++++++++++++++++++ .../comment/widget/SettingConfigGetter.java | 1 + src/main/resources/extensions/settings.yaml | 7 ++++ 5 files changed, 62 insertions(+), 5 deletions(-) diff --git a/packages/comment-widget/src/base-form.ts b/packages/comment-widget/src/base-form.ts index bc3e6ea2..dcdaaad5 100644 --- a/packages/comment-widget/src/base-form.ts +++ b/packages/comment-widget/src/base-form.ts @@ -496,10 +496,13 @@ export class BaseForm extends LitElement {
` )} -
- - -
+ ${when( + this.allowNotificationConfigurable, + () => html`
+ + +
` + )} ${when( this.showCaptcha && @@ -572,6 +575,10 @@ export class BaseForm extends LitElement { `; } + private get allowNotificationConfigurable() { + return this.configMapData?.basic.allowNotificationConfigurable === true; + } + private get canUploadImages() { if (!this.configMapData?.editor?.enableUpload) { return false; @@ -594,7 +601,9 @@ export class BaseForm extends LitElement { waitUntil: (submission: Promise) => submissions.push(submission), content, - allowNotification: data.allowNotification === 'on', + allowNotification: this.allowNotificationConfigurable + ? data.allowNotification === 'on' + : true, uploadIds: uploadedIds(editor), uploadSession: uploadSession(editor), hidden: data.hidden === 'on', diff --git a/packages/comment-widget/src/types/index.ts b/packages/comment-widget/src/types/index.ts index 43e2433d..bd67f61d 100644 --- a/packages/comment-widget/src/types/index.ts +++ b/packages/comment-widget/src/types/index.ts @@ -11,6 +11,7 @@ interface BasicConfig { size: number; withReplySize: number; replySize: number; + allowNotificationConfigurable?: boolean; showCommenterDevice?: boolean; enablePrivateComment?: boolean; showPrivateCommentBadge?: boolean; diff --git a/packages/comment-widget/tests/allow-notification.browser.test.js b/packages/comment-widget/tests/allow-notification.browser.test.js index 94ecc3ff..f6e274d8 100644 --- a/packages/comment-widget/tests/allow-notification.browser.test.js +++ b/packages/comment-widget/tests/allow-notification.browser.test.js @@ -20,6 +20,7 @@ test.each(['comment-form', 'reply-form'])( await form.updateComplete; const base = form.baseFormRef.value; base.currentUser = form.currentUser; + base.configMapData = { basic: { allowNotificationConfigurable: true } }; await base.updateComplete; await until(() => base.editorRef.value?.editor); @@ -47,3 +48,41 @@ test.each(['comment-form', 'reply-form'])( form.remove(); } ); + +test.each(['comment-form', 'reply-form'])( + '%s always allows notifications when the option is disabled', + async (tag) => { + const requests = []; + mockApi(async (_input, options = {}) => { + requests.push(JSON.parse(options.body)); + return new Response(JSON.stringify({ spec: { approved: true } }), { + headers: { 'Content-Type': 'application/json' }, + }); + }); + await import('../src/index.ts'); + + const form = document.createElement(tag); + form.comment = { metadata: { name: 'comment-1' } }; + form.currentUser = { metadata: { name: 'commenter' }, spec: {} }; + document.body.append(form); + await form.updateComplete; + const base = form.baseFormRef.value; + base.currentUser = form.currentUser; + await base.updateComplete; + await until(() => base.editorRef.value?.editor); + + assert( + !base.shadowRoot.querySelector('#allowNotification'), + 'Allow notification must be hidden when the option is disabled' + ); + + base.editorRef.value.editor.commands.setContent('

Notify me

'); + base.shadowRoot.querySelector('form').requestSubmit(); + await until(() => requests.length === 1 && !form.submitting); + assert( + requests[0].allowNotification === true, + 'Disabled option must send allowNotification=true' + ); + form.remove(); + } +); diff --git a/src/main/java/run/halo/comment/widget/SettingConfigGetter.java b/src/main/java/run/halo/comment/widget/SettingConfigGetter.java index 57ae0ee7..81d1bb60 100644 --- a/src/main/java/run/halo/comment/widget/SettingConfigGetter.java +++ b/src/main/java/run/halo/comment/widget/SettingConfigGetter.java @@ -130,6 +130,7 @@ class BasicConfig { private int replySize; private boolean withReplies; private int withReplySize; + private boolean allowNotificationConfigurable; } @Data diff --git a/src/main/resources/extensions/settings.yaml b/src/main/resources/extensions/settings.yaml index 4e65ea6c..7111dc4a 100644 --- a/src/main/resources/extensions/settings.yaml +++ b/src/main/resources/extensions/settings.yaml @@ -43,6 +43,13 @@ spec: label: 显示评论者设备信息 name: showCommenterDevice value: false + - $formkit: checkbox + label: 允许用户选择是否接收通知 + name: allowNotificationConfigurable + id: allowNotificationConfigurable + key: allowNotificationConfigurable + value: false + help: 开启后,评论和回复表单中会显示「允许通知」选项;关闭时始终接收后续回复通知。 - $formkit: checkbox label: 支持私密评论和回复 id: enablePrivateComment