fix: use MkPagination in notes for Quote, Boost, Reaction
This commit is contained in:
parent
dd3ad89b64
commit
35c7dccb49
9 changed files with 131 additions and 68 deletions
|
@ -1,4 +1,4 @@
|
|||
import { In } from "typeorm";
|
||||
import { In, IsNull, Not } from "typeorm";
|
||||
import * as mfm from "mfm-js";
|
||||
import { Note } from "@/models/entities/note.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
|
@ -10,6 +10,7 @@ import {
|
|||
Followings,
|
||||
Polls,
|
||||
Channels,
|
||||
Notes,
|
||||
} from "../index.js";
|
||||
import type { Packed } from "@/misc/schema.js";
|
||||
import { countReactions, decodeReaction, nyaify } from "backend-rs";
|
||||
|
@ -101,7 +102,7 @@ export const NoteRepository = db.getRepository(Note).extend({
|
|||
return true;
|
||||
} else {
|
||||
// 指定されているかどうか
|
||||
return note.visibleUserIds.some((id: any) => meId === id);
|
||||
return note.visibleUserIds.some((id) => meId === id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,8 +212,25 @@ export const NoteRepository = db.getRepository(Note).extend({
|
|||
localOnly: note.localOnly || undefined,
|
||||
visibleUserIds:
|
||||
note.visibility === "specified" ? note.visibleUserIds : undefined,
|
||||
// FIXME: Deleting a post does not decrease these two numbers, causing the number to be wrong
|
||||
renoteCount: note.renoteCount,
|
||||
repliesCount: note.repliesCount,
|
||||
// TODO: add it to database and use note.quoteCount
|
||||
quoteCount: Notes.count({
|
||||
where: {
|
||||
renoteId: note.id,
|
||||
text: Not(IsNull()),
|
||||
},
|
||||
}),
|
||||
meRenoteCount: me
|
||||
? Notes.count({
|
||||
where: {
|
||||
renoteId: note.id,
|
||||
text: IsNull(),
|
||||
userId: me.id,
|
||||
},
|
||||
})
|
||||
: undefined,
|
||||
reactions: countReactions(note.reactions),
|
||||
reactionEmojis: reactionEmoji,
|
||||
emojis: noteEmoji,
|
||||
|
|
|
@ -208,5 +208,15 @@ export const packedNoteSchema = {
|
|||
optional: true,
|
||||
nullable: true,
|
||||
},
|
||||
meRenoteCount: {
|
||||
type: "number",
|
||||
optional: true,
|
||||
nullable: false,
|
||||
},
|
||||
quoteCount: {
|
||||
type: "number",
|
||||
optional: false,
|
||||
nullable: false,
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
|
|
@ -42,8 +42,6 @@ export const paramDef = {
|
|||
type: { type: "string", nullable: true },
|
||||
limit: { type: "integer", minimum: 1, maximum: 100, default: 10 },
|
||||
offset: { type: "integer", default: 0 },
|
||||
sinceId: { type: "string", format: "misskey:id" },
|
||||
untilId: { type: "string", format: "misskey:id" },
|
||||
},
|
||||
required: ["noteId"],
|
||||
} as const;
|
||||
|
|
|
@ -42,6 +42,12 @@ export const paramDef = {
|
|||
limit: { type: "integer", minimum: 1, maximum: 100, default: 10 },
|
||||
sinceId: { type: "string", format: "misskey:id" },
|
||||
untilId: { type: "string", format: "misskey:id" },
|
||||
filter: {
|
||||
type: "string",
|
||||
enum: ["boost", "quote"],
|
||||
nullable: true,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
required: ["noteId"],
|
||||
} as const;
|
||||
|
@ -53,7 +59,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
throw err;
|
||||
});
|
||||
|
||||
let query = makePaginationQuery(
|
||||
const query = makePaginationQuery(
|
||||
Notes.createQueryBuilder("note"),
|
||||
ps.sinceId,
|
||||
ps.untilId,
|
||||
|
@ -61,6 +67,13 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
.andWhere("note.renoteId = :renoteId", { renoteId: note.id })
|
||||
.innerJoinAndSelect("note.user", "user");
|
||||
|
||||
if (ps.filter === "boost") {
|
||||
query.andWhere("note.text IS NULL");
|
||||
}
|
||||
if (ps.filter === "quote") {
|
||||
query.andWhere("note.text IS NOT NULL");
|
||||
}
|
||||
|
||||
if (ps.userId) {
|
||||
query.andWhere("user.id = :userId", { userId: ps.userId });
|
||||
}
|
||||
|
|
|
@ -64,11 +64,11 @@
|
|||
)
|
||||
}}
|
||||
</option>
|
||||
<option v-if="directQuotes && directQuotes.length > 0" value="quotes">
|
||||
<option v-if="note.quoteCount > 0" value="quotes">
|
||||
<!-- <i :class="icon('ph-quotes')"></i> -->
|
||||
{{
|
||||
wordWithCount(
|
||||
directQuotes.length,
|
||||
note.quoteCount,
|
||||
i18n.ts.quote,
|
||||
i18n.ts.quotes,
|
||||
)
|
||||
|
@ -92,32 +92,33 @@
|
|||
/>
|
||||
<MkLoading v-else-if="tab === 'replies' && note.repliesCount > 0" />
|
||||
|
||||
<MkPagination
|
||||
v-if="tab === 'quotes'"
|
||||
v-slot="{ items }"
|
||||
:pagination="quotePagination"
|
||||
>
|
||||
<MkNoteSub
|
||||
v-for="note in directQuotes"
|
||||
v-if="directQuotes && tab === 'quotes'"
|
||||
v-for="note in items"
|
||||
:key="note.id"
|
||||
:note="note"
|
||||
class="reply"
|
||||
:conversation="replies"
|
||||
:conversation="items"
|
||||
:detailed-view="true"
|
||||
:parent-id="note.id"
|
||||
/>
|
||||
<MkLoading v-else-if="tab === 'quotes' && directQuotes && directQuotes.length > 0" />
|
||||
</MkPagination>
|
||||
|
||||
<!-- <MkPagination
|
||||
<MkPagination
|
||||
v-if="tab === 'renotes'"
|
||||
v-slot="{ items }"
|
||||
ref="pagingComponent"
|
||||
:pagination="pagination"
|
||||
> -->
|
||||
:pagination="renotePagination"
|
||||
>
|
||||
<MkUserCardMini
|
||||
v-for="item in renotes"
|
||||
v-if="tab === 'renotes' && renotes"
|
||||
v-for="item in items"
|
||||
:key="item.user.id"
|
||||
:user="item.user"
|
||||
/>
|
||||
<!-- </MkPagination> -->
|
||||
<MkLoading v-else-if="tab === 'renotes' && note.renoteCount > 0" />
|
||||
</MkPagination>
|
||||
|
||||
<div v-if="tab === 'clips' && clips.length > 0" class="_content clips">
|
||||
<MkA
|
||||
|
@ -186,6 +187,7 @@ import { getNoteMenu } from "@/scripts/get-note-menu";
|
|||
import { useNoteCapture } from "@/scripts/use-note-capture";
|
||||
import { deepClone } from "@/scripts/clone";
|
||||
import { useStream } from "@/stream";
|
||||
import MkPagination, { Paging } from "@/components/MkPagination.vue";
|
||||
// import icon from "@/scripts/icon";
|
||||
|
||||
const props = defineProps<{
|
||||
|
@ -247,7 +249,6 @@ const replies = ref<entities.Note[]>([]);
|
|||
const directReplies = ref<null | entities.Note[]>([]);
|
||||
const directQuotes = ref<null | entities.Note[]>([]);
|
||||
const clips = ref();
|
||||
const renotes = ref();
|
||||
const isRenote = ref(note.value.renoteId != null);
|
||||
let isScrolling: boolean;
|
||||
|
||||
|
@ -401,24 +402,32 @@ os.api("notes/clips", {
|
|||
clips.value = res;
|
||||
});
|
||||
|
||||
// const pagination = {
|
||||
// endpoint: "notes/renotes",
|
||||
// noteId: note.id,
|
||||
// limit: 10,
|
||||
// };
|
||||
|
||||
// const pagingComponent = $ref<InstanceType<typeof MkPagination>>();
|
||||
|
||||
renotes.value = null;
|
||||
function loadTab() {
|
||||
if (tab.value === "renotes" && !renotes.value) {
|
||||
os.api("notes/renotes", {
|
||||
const renotePagination = {
|
||||
endpoint: "notes/renotes" as const,
|
||||
limit: 30,
|
||||
params: {
|
||||
noteId: note.value.id,
|
||||
limit: 100,
|
||||
}).then((res) => {
|
||||
renotes.value = res;
|
||||
});
|
||||
}
|
||||
filter: "boost" as const,
|
||||
},
|
||||
};
|
||||
const quotePagination = {
|
||||
endpoint: "notes/renotes" as const,
|
||||
limit: 30,
|
||||
params: {
|
||||
noteId: note.value.id,
|
||||
filter: "quote" as const,
|
||||
},
|
||||
};
|
||||
|
||||
function loadTab() {
|
||||
// if (tab.value === "renotes" && !renotes.value) {
|
||||
// os.api("notes/renotes", {
|
||||
// noteId: note.value.id,
|
||||
// limit: 100,
|
||||
// }).then((res) => {
|
||||
// renotes.value = res;
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
async function onNoteUpdated(
|
||||
|
|
|
@ -23,7 +23,13 @@
|
|||
}}</span>
|
||||
</button>
|
||||
</div>
|
||||
<MkUserCardMini v-for="user in users" :key="user.id" :user="user" />
|
||||
<MkPagination
|
||||
ref="pagingComponent"
|
||||
:pagination="pagination"
|
||||
v-slot="{ items }"
|
||||
>
|
||||
<MkUserCardMini v-for="{ user: user } in items" :key="user.id" :user="user" />
|
||||
</MkPagination>
|
||||
</div>
|
||||
<div v-else>
|
||||
<MkLoading />
|
||||
|
@ -36,6 +42,9 @@ import type { entities } from "firefish-js";
|
|||
import MkReactionIcon from "@/components/MkReactionIcon.vue";
|
||||
import MkUserCardMini from "@/components/MkUserCardMini.vue";
|
||||
import * as os from "@/os";
|
||||
import MkPagination, {
|
||||
type MkPaginationType,
|
||||
} from "@/components/MkPagination.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
noteId: entities.Note["id"];
|
||||
|
@ -44,16 +53,22 @@ const props = defineProps<{
|
|||
const note = ref<entities.Note>();
|
||||
const tab = ref<string | null>(null);
|
||||
const reactions = ref<string[]>();
|
||||
const users = ref();
|
||||
|
||||
async function updateUsers(): void {
|
||||
const res = await os.api("notes/reactions", {
|
||||
const pagingComponent = ref<MkPaginationType<"notes/reactions"> | null>(null);
|
||||
|
||||
const pagination = {
|
||||
endpoint: "notes/reactions" as const,
|
||||
params: {
|
||||
noteId: props.noteId,
|
||||
type: tab.value,
|
||||
},
|
||||
offsetMode: true,
|
||||
limit: 30,
|
||||
});
|
||||
};
|
||||
|
||||
users.value = res.map((x) => x.user);
|
||||
function updateUsers(): void {
|
||||
pagination.params.type = tab.value;
|
||||
pagingComponent.value?.reload();
|
||||
}
|
||||
|
||||
watch(tab, updateUsers);
|
||||
|
@ -64,7 +79,7 @@ onMounted(() => {
|
|||
}).then(async (res) => {
|
||||
reactions.value = Object.keys(res.reactions);
|
||||
note.value = res;
|
||||
await updateUsers();
|
||||
// updateUsers();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -27,7 +27,7 @@ import Ripple from "@/components/MkRipple.vue";
|
|||
import XDetails from "@/components/MkUsersTooltip.vue";
|
||||
import { pleaseLogin } from "@/scripts/please-login";
|
||||
import * as os from "@/os";
|
||||
import { isSignedIn, me } from "@/me";
|
||||
import { me } from "@/me";
|
||||
import { useTooltip } from "@/scripts/use-tooltip";
|
||||
import { i18n } from "@/i18n";
|
||||
import { defaultStore } from "@/store";
|
||||
|
@ -72,17 +72,9 @@ useTooltip(buttonRef, async (showing) => {
|
|||
);
|
||||
});
|
||||
|
||||
const hasRenotedBefore = ref(false);
|
||||
|
||||
if (isSignedIn) {
|
||||
os.api("notes/renotes", {
|
||||
noteId: props.note.id,
|
||||
userId: me!.id,
|
||||
limit: 1,
|
||||
}).then((res) => {
|
||||
hasRenotedBefore.value = res.length > 0;
|
||||
});
|
||||
}
|
||||
const hasRenotedBefore = ref(
|
||||
props.note.meRenoteCount && props.note.meRenoteCount > 0,
|
||||
);
|
||||
|
||||
const renote = (viaKeyboard = false, ev?: MouseEvent) => {
|
||||
pleaseLogin();
|
||||
|
|
|
@ -773,7 +773,12 @@ export type Endpoints = {
|
|||
res: null;
|
||||
};
|
||||
"notes/reactions": {
|
||||
req: { noteId: Note["id"]; type?: string | null; limit?: number };
|
||||
req: {
|
||||
noteId: Note["id"];
|
||||
type?: string | null;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
};
|
||||
res: NoteReaction[];
|
||||
};
|
||||
"notes/reactions/create": {
|
||||
|
@ -787,6 +792,7 @@ export type Endpoints = {
|
|||
sinceId?: Note["id"];
|
||||
untilId?: Note["id"];
|
||||
noteId: Note["id"];
|
||||
filter?: "boost" | "quote";
|
||||
};
|
||||
res: Note[];
|
||||
};
|
||||
|
|
|
@ -174,9 +174,11 @@ export type Note = {
|
|||
channelId?: Channel["id"];
|
||||
channel?: Channel;
|
||||
myReaction?: string;
|
||||
meRenoteCount?: number;
|
||||
reactions: Record<string, number>;
|
||||
renoteCount: number;
|
||||
repliesCount: number;
|
||||
quoteCount: number;
|
||||
poll?: {
|
||||
expiresAt: DateString | null;
|
||||
multiple: boolean;
|
||||
|
|
Loading…
Reference in a new issue