feat(gmw): public features #7-14 — scam domains, top channels, hourly heatmap, category drill-down, coverage stats, channel culture glossary, term KB, edit history

ALSO fixes: dashboard.repository still JOINed dropped user_reputations table (listUsers/getUserDetail crash).
This commit is contained in:
asepharyana
2026-08-18 20:45:12 +07:00
parent 2a8f6d9062
commit 00e8d68ce5
38 changed files with 1542 additions and 25 deletions
+8 -1
View File
@@ -10,6 +10,7 @@ export {
useUsers,
} from "./use-dashboard";
export { useGuilds } from "./use-guilds";
export { useChannelCultures, useGlossary } from "./use-knowledge";
export {
useMediaLoop,
useMediaQueue,
@@ -21,22 +22,28 @@ export {
export {
useImages,
useLoadMore,
useMessageActivity,
useMessageDetail,
useMessageSearch,
useMessages,
useMessagesHasMore,
useMessagesStream,
useMessagesWsSync,
useRecentEdits,
useReview,
useSemanticSearch,
useTextChannels,
useMessageActivity,
} from "./use-messages";
export {
useHourlyModeration,
useLiveModeration,
useModerationActions,
useModerationByCategory,
useModerationCoverage,
useModerationStats,
useModerationTrends,
useTopFlaggedChannels,
useTopFlaggedDomains,
} from "./use-moderation";
export {
useDeleteRecording,
@@ -0,0 +1,22 @@
import useSWR from "swr";
import { knowledgeApi } from "@/lib/api";
import type { ChannelCultureRow, GlossaryRow } from "@/lib/types";
export function useChannelCultures(
limit = 100,
initialData?: ChannelCultureRow[],
) {
return useSWR<ChannelCultureRow[]>(
["channel-cultures", limit],
() => knowledgeApi.channelCultures(limit),
{ fallbackData: initialData },
);
}
export function useGlossary(limit = 100, initialData?: GlossaryRow[]) {
return useSWR<GlossaryRow[]>(
["glossary", limit],
() => knowledgeApi.glossary(limit),
{ fallbackData: initialData },
);
}
@@ -5,6 +5,7 @@ import { messagesApi, voiceApi } from "@/lib/api";
import type {
AttachmentRecord,
Channel,
EditHistoryRow,
MessageActivityBucket,
MessageRecord,
SemanticSearchResult,
@@ -381,3 +382,15 @@ export function useMessageActivity(days = 30) {
messagesApi.getActivity(days),
);
}
export function useRecentEdits(
limit = 50,
channelId?: string,
initialData?: EditHistoryRow[],
) {
return useSWR<EditHistoryRow[]>(
["recent-edits", limit, channelId ?? null],
() => messagesApi.getRecentEdits(limit, channelId),
{ fallbackData: initialData },
);
}
@@ -2,7 +2,12 @@ import { useCallback, useEffect, useRef, useState } from "react";
import useSWR from "swr";
import { moderationApi } from "@/lib/api";
import type {
CategoryAction,
FlaggedChannel,
FlaggedDomain,
HourlyModeration,
ModerationAction,
ModerationCoverage,
ModerationStats,
ModerationTrends,
} from "@/lib/types";
@@ -82,3 +87,35 @@ export function useModerationTrends(days = 30, initialData?: ModerationTrends) {
{ fallbackData: initialData },
);
}
export function useTopFlaggedDomains(days = 30) {
return useSWR<FlaggedDomain[]>(["moderation-domains", days], () =>
moderationApi.getTopDomains(days),
);
}
export function useTopFlaggedChannels(days = 30) {
return useSWR<FlaggedChannel[]>(["moderation-channels", days], () =>
moderationApi.getTopChannels(days),
);
}
export function useHourlyModeration(days = 30) {
return useSWR<HourlyModeration[]>(["moderation-byhour", days], () =>
moderationApi.getHourlyModeration(days),
);
}
export function useModerationByCategory(days = 30, category: string | null) {
return useSWR<CategoryAction[]>(
category ? ["moderation-bycategory", days, category] : null,
() => moderationApi.getByCategory(days, category as string),
{ keepPreviousData: true },
);
}
export function useModerationCoverage(days = 30) {
return useSWR<ModerationCoverage>(["moderation-coverage", days], () =>
moderationApi.getCoverage(days),
);
}