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
3 changes: 2 additions & 1 deletion packages/comment-widget/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
"dev": "vite build --watch",
"locale:build": "lit-localize build",
"locale:extract": "lit-localize extract",
"prepublishOnly": "pnpm run build"
"prepublishOnly": "pnpm run build",
"test": "node --test tests/*.test.ts"
},
"dependencies": {
"@emoji-mart/data": "^1.2.1",
Expand Down
6 changes: 5 additions & 1 deletion packages/comment-widget/src/comment-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import './loading-block';
import { when } from 'lit/directives/when.js';
import { ofetch } from 'ofetch';
import baseStyles from './styles/base';
import { getInitialReplySize } from './utils/reply-pagination';

export class CommentList extends LitElement {
@consume({ context: baseUrlContext })
Expand Down Expand Up @@ -106,6 +107,9 @@ export class CommentList extends LitElement {
this.comments.page = page;
}

const replySize = this.configMapData?.basic.replySize ?? 10;
const withReplySize = this.configMapData?.basic.withReplySize ?? 5;

const data = await ofetch<CommentVoList>(
`${this.baseUrl}/apis/api.halo.run/v1alpha1/comments`,
{
Expand All @@ -117,7 +121,7 @@ export class CommentList extends LitElement {
size: this.configMapData?.basic.size || 20,
version: this.version,
withReplies: this.configMapData?.basic.withReplies || false,
replySize: this.configMapData?.basic.replySize || 10,
replySize: getInitialReplySize(withReplySize, replySize),
},
}
);
Expand Down
66 changes: 41 additions & 25 deletions packages/comment-widget/src/comment-replies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { ofetch } from 'ofetch';
import type { ToastManager } from './lit-toast';
import baseStyles from './styles/base';
import type { ConfigMapData } from './types';
import { getNextReplyRequest } from './utils/reply-pagination';

export class CommentReplies extends LitElement {
@consume({ context: baseUrlContext })
Expand All @@ -35,6 +36,10 @@ export class CommentReplies extends LitElement {
@state()
page = 1;

private currentPageSize = 0;

private preloaded = false;

@state()
hasNext = false;

Expand Down Expand Up @@ -82,23 +87,25 @@ export class CommentReplies extends LitElement {
this.activeQuoteReply = event.detail.quoteReply;
}

async fetchReplies(options?: { append: boolean }) {
async fetchReplies(options?: {
page?: number;
size?: number;
append?: boolean;
}) {
try {
this.loading = true;

// Reload replies list
if (!options?.append) {
this.page = 1;
}
const page = options?.page ?? 1;
const size = options?.size ?? this.configMapData?.basic.replySize ?? 10;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clamp zero-sized legacy configurations before fetching

Existing installations can have replySize: 0 because the previous settings schema only required a value and imposed no minimum. Unlike the former || 10 fallback, ?? 10 preserves that zero, so this path sends size=0 to the reply endpoint; the same unnormalized value is also passed to getNextReplyRequest, breaking subsequent pagination. The new form constraint does not migrate saved settings, so normalize the configured page size to a positive fallback before using it.

Useful? React with 👍 / 👎.


const data = await ofetch<ReplyVoList>(
`${this.baseUrl}/apis/api.halo.run/v1alpha1/comments/${
this.comment?.metadata.name
}/reply`,
{
query: {
page: this.page || 1,
size: this.configMapData?.basic.replySize || 10,
page,
size,
},
}
);
Expand All @@ -111,6 +118,8 @@ export class CommentReplies extends LitElement {

this.hasNext = data.hasNext;
this.page = data.page;
this.currentPageSize = data.size;
this.preloaded = false;
} catch (error) {
console.error(error);
this.toastManager?.error(
Expand All @@ -122,31 +131,38 @@ export class CommentReplies extends LitElement {
}

async fetchNext() {
if (this.configMapData?.basic.withReplies) {
// if withReplies is true, we need to reload the replies list
await this.fetchReplies({ append: !(this.page === 1) });
this.page++;
} else {
this.page++;
await this.fetchReplies({ append: true });
if (this.loading || !this.hasNext) {
return;
}

const request = getNextReplyRequest({
page: this.page,
currentPageSize: this.currentPageSize,
replySize: this.configMapData?.basic.replySize ?? 10,
preloaded: this.preloaded,
});

await this.fetchReplies(request);
}

override connectedCallback(): void {
super.connectedCallback();

if (this.configMapData?.basic.withReplies) {
// TODO: Fix ts error
// Needs @halo-dev/api-client@2.14.0
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
this.replies = this.comment?.replies.items;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
this.page = this.comment?.replies.page;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
this.hasNext = this.comment?.replies.hasNext;
const preloadedReplies = (
this.comment as (CommentVo & { replies?: ReplyVoList }) | undefined
)?.replies;

if (!preloadedReplies) {
this.fetchReplies();
return;
}

this.replies = preloadedReplies.items;
this.page = preloadedReplies.page;
this.currentPageSize = preloadedReplies.size;
this.hasNext = preloadedReplies.hasNext;
this.preloaded = true;
} else {
this.fetchReplies();
}
Expand Down
40 changes: 40 additions & 0 deletions packages/comment-widget/src/utils/reply-pagination.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
export interface NextReplyRequestOptions {
page: number;
currentPageSize: number;
replySize: number;
preloaded: boolean;
}

export interface NextReplyRequest {
page: number;
size: number;
append: boolean;
}

export function getInitialReplySize(
withReplySize: number,
replySize: number
): number {
return Math.min(Math.max(1, withReplySize), Math.max(1, replySize));
}

export function getNextReplyRequest({
page,
currentPageSize,
replySize,
preloaded,
}: NextReplyRequestOptions): NextReplyRequest {
if (preloaded && currentPageSize < replySize) {
return {
page,
size: replySize,
append: false,
};
}

return {
page: page + 1,
size: replySize,
append: true,
};
}
50 changes: 50 additions & 0 deletions packages/comment-widget/tests/reply-pagination.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import {
getInitialReplySize,
getNextReplyRequest,
} from '../src/utils/reply-pagination.ts';

test('uses withReplySize for the initial replies request', () => {
assert.equal(getInitialReplySize(2, 4), 2);
});

test('fills the first page when fewer replies were preloaded', () => {
assert.deepEqual(
getNextReplyRequest({
page: 1,
currentPageSize: 2,
replySize: 4,
preloaded: true,
}),
{ page: 1, size: 4, append: false }
);
});

test('loads page two when a full first page was preloaded', () => {
assert.deepEqual(
getNextReplyRequest({
page: 1,
currentPageSize: 4,
replySize: 4,
preloaded: true,
}),
{ page: 2, size: 4, append: true }
);
});

test('continues with the next page after the preload is reconciled', () => {
assert.deepEqual(
getNextReplyRequest({
page: 2,
currentPageSize: 4,
replySize: 4,
preloaded: false,
}),
{ page: 3, size: 4, append: true }
);
});

test('clamps legacy preload sizes to the reply page size', () => {
assert.equal(getInitialReplySize(5, 3), 3);
});
12 changes: 10 additions & 2 deletions src/main/resources/extensions/settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ spec:
- $formkit: number
label: 回复分页条数
name: replySize
validation: required
id: replySize
key: replySize
min: 1
step: 1
validation: required|min:1
value: 10
- $formkit: checkbox
label: 同时加载评论的回复
Expand All @@ -29,7 +33,11 @@ spec:
name: withReplySize
id: withReplySize
key: withReplySize
validation: required
min: 1
max: "$get(replySize).value"
step: 1
validation: required|min:1
help: 不能大于回复分页条数
value: 5
- $formkit: checkbox
label: 显示评论者设备信息
Expand Down
Loading