feat: add realtime feed event and desc feed list
This commit is contained in:
parent
adb1cc3919
commit
478d0c2af3
@ -1,9 +1,4 @@
|
||||
import {
|
||||
AppRouterOutput,
|
||||
defaultErrorHandler,
|
||||
defaultSuccessHandler,
|
||||
trpc,
|
||||
} from '@/api/trpc';
|
||||
import { defaultErrorHandler, defaultSuccessHandler, trpc } from '@/api/trpc';
|
||||
import { CommonHeader } from '@/components/CommonHeader';
|
||||
import { CommonWrapper } from '@/components/CommonWrapper';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
@ -19,6 +14,8 @@ import { FeedApiGuide } from '@/components/feed/FeedApiGuide';
|
||||
import { FeedEventItem } from '@/components/feed/FeedEventItem';
|
||||
import { FeedIntegration } from '@/components/feed/FeedIntegration';
|
||||
import { DialogWrapper } from '@/components/DialogWrapper';
|
||||
import { useSocketSubscribeList } from '@/api/socketio';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const Route = createFileRoute('/feed/$channelId/')({
|
||||
beforeLoad: routeAuthBeforeLoad,
|
||||
@ -33,7 +30,7 @@ function PageComponent() {
|
||||
workspaceId,
|
||||
channelId,
|
||||
});
|
||||
const { data: events } = trpc.feed.events.useQuery({
|
||||
const { data: events = [] } = trpc.feed.events.useQuery({
|
||||
workspaceId,
|
||||
channelId,
|
||||
});
|
||||
@ -53,6 +50,15 @@ function PageComponent() {
|
||||
});
|
||||
});
|
||||
|
||||
const realtimeEvents = useSocketSubscribeList('onReceiveFeedEvent', {
|
||||
filter: (event) => event.channelId === channelId,
|
||||
});
|
||||
|
||||
const fullEvents = useMemo(
|
||||
() => [...realtimeEvents, ...events],
|
||||
[realtimeEvents, events]
|
||||
);
|
||||
|
||||
return (
|
||||
<CommonWrapper
|
||||
header={
|
||||
@ -96,14 +102,14 @@ function PageComponent() {
|
||||
/>
|
||||
}
|
||||
>
|
||||
{events && events.length === 0 ? (
|
||||
{fullEvents && fullEvents.length === 0 ? (
|
||||
<div className="w-full overflow-hidden p-4">
|
||||
<FeedApiGuide channelId={channelId} />
|
||||
</div>
|
||||
) : (
|
||||
<ScrollArea className="h-full overflow-hidden p-4">
|
||||
<div className="space-y-2">
|
||||
{(events ?? []).map((event) => (
|
||||
{(fullEvents ?? []).map((event) => (
|
||||
<FeedEventItem key={event.id} event={event} />
|
||||
))}
|
||||
</div>
|
||||
|
@ -11,6 +11,7 @@ import { OpenApiMeta } from 'trpc-openapi';
|
||||
import { FeedChannelModelSchema, FeedEventModelSchema } from '../../prisma/zod';
|
||||
import { prisma } from '../../model/_client';
|
||||
import _ from 'lodash';
|
||||
import { subscribeEventBus } from '../../ws/shared';
|
||||
|
||||
export const feedIntegrationRouter = router({
|
||||
github: publicProcedure
|
||||
@ -32,6 +33,21 @@ export const feedIntegrationRouter = router({
|
||||
const eventType = ctx.req.headers['x-github-event'];
|
||||
const { channelId, ...data } = input;
|
||||
|
||||
const workspaceId = await prisma.feedChannel
|
||||
.findFirst({
|
||||
where: {
|
||||
id: channelId,
|
||||
},
|
||||
select: {
|
||||
workspaceId: true,
|
||||
},
|
||||
})
|
||||
.then((res) => res?.workspaceId);
|
||||
|
||||
if (!workspaceId) {
|
||||
return 'Not found';
|
||||
}
|
||||
|
||||
if (eventType === 'push') {
|
||||
const pusher = `${_.get(data, 'pusher.name')}<${_.get(data, 'pusher.email')}>`;
|
||||
const commits = _.map(_.get(data, 'commits') as any[], 'id').join(', ');
|
||||
@ -40,7 +56,7 @@ export const feedIntegrationRouter = router({
|
||||
const senderId = String(_.get(data, 'sender.id'));
|
||||
const senderName = String(_.get(data, 'sender.login'));
|
||||
const url = String(_.get(data, 'compare'));
|
||||
await prisma.feedEvent.create({
|
||||
const event = await prisma.feedEvent.create({
|
||||
data: {
|
||||
channelId: channelId,
|
||||
eventName: eventType,
|
||||
@ -53,6 +69,7 @@ export const feedIntegrationRouter = router({
|
||||
url,
|
||||
},
|
||||
});
|
||||
subscribeEventBus.emit('onReceiveFeedEvent', workspaceId, event);
|
||||
|
||||
return 'ok';
|
||||
} else if (eventType === 'star') {
|
||||
@ -61,7 +78,7 @@ export const feedIntegrationRouter = router({
|
||||
const senderId = String(_.get(data, 'sender.id'));
|
||||
const senderName = String(_.get(data, 'sender.login'));
|
||||
const url = String(_.get(data, 'compare'));
|
||||
await prisma.feedEvent.create({
|
||||
const event = await prisma.feedEvent.create({
|
||||
data: {
|
||||
channelId: channelId,
|
||||
eventName: eventType,
|
||||
@ -74,6 +91,7 @@ export const feedIntegrationRouter = router({
|
||||
url,
|
||||
},
|
||||
});
|
||||
subscribeEventBus.emit('onReceiveFeedEvent', workspaceId, event);
|
||||
|
||||
return 'ok';
|
||||
} else if (eventType === 'issues') {
|
||||
@ -96,7 +114,7 @@ export const feedIntegrationRouter = router({
|
||||
}
|
||||
|
||||
if (eventContent) {
|
||||
await prisma.feedEvent.create({
|
||||
const event = await prisma.feedEvent.create({
|
||||
data: {
|
||||
channelId: channelId,
|
||||
eventName: eventName,
|
||||
@ -109,6 +127,7 @@ export const feedIntegrationRouter = router({
|
||||
url,
|
||||
},
|
||||
});
|
||||
subscribeEventBus.emit('onReceiveFeedEvent', workspaceId, event);
|
||||
|
||||
return 'ok';
|
||||
}
|
||||
@ -235,6 +254,10 @@ export const feedRouter = router({
|
||||
where: {
|
||||
channelId: channelId,
|
||||
},
|
||||
take: 50,
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
});
|
||||
|
||||
return events;
|
||||
|
9
src/server/types/utils.ts
Normal file
9
src/server/types/utils.ts
Normal file
@ -0,0 +1,9 @@
|
||||
type NestedSwapDatesWithStrings<T> = {
|
||||
[k in keyof T]: T[k] extends Date | undefined
|
||||
? string
|
||||
: T[k] extends object
|
||||
? NestedSwapDatesWithStrings<T[k]>
|
||||
: T[k];
|
||||
};
|
||||
|
||||
export type Serialize<T> = NestedSwapDatesWithStrings<T>;
|
@ -1,13 +1,15 @@
|
||||
import { MonitorData } from '@prisma/client';
|
||||
import { EventEmitter } from 'eventemitter-strict';
|
||||
import { Socket } from 'socket.io';
|
||||
import { MaybePromise, ServerStatusInfo } from '../../types';
|
||||
import { FeedEvent, MonitorData } from '@prisma/client';
|
||||
import { Serialize } from '../types/utils';
|
||||
|
||||
type SubscribeEventFn<T> = (workspaceId: string, eventData: T) => void;
|
||||
|
||||
export interface SubscribeEventMap {
|
||||
onServerStatusUpdate: SubscribeEventFn<Record<string, ServerStatusInfo>>;
|
||||
onMonitorReceiveNewData: SubscribeEventFn<MonitorData>;
|
||||
onReceiveFeedEvent: SubscribeEventFn<Serialize<FeedEvent>>;
|
||||
}
|
||||
|
||||
type SocketEventFn<T, U = unknown> = (
|
||||
@ -29,14 +31,14 @@ export const socketEventBus = new EventEmitter<SocketEventMap>();
|
||||
export const subscribeEventBus = new EventEmitter<SubscribeEventMap>();
|
||||
|
||||
type SubscribeInitializerFn<
|
||||
T extends keyof SubscribeEventMap = keyof SubscribeEventMap
|
||||
T extends keyof SubscribeEventMap = keyof SubscribeEventMap,
|
||||
> = (
|
||||
workspaceId: string,
|
||||
socket: Socket
|
||||
) => MaybePromise<Parameters<SubscribeEventMap[T]>[1]> | MaybePromise<void>;
|
||||
const subscribeInitializerList: [
|
||||
keyof SubscribeEventMap,
|
||||
SubscribeInitializerFn
|
||||
SubscribeInitializerFn,
|
||||
][] = [];
|
||||
|
||||
let i = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user