feat: track post creation method (WEB/API/MCP/AUTOPOST)
This commit is contained in:
parent
009bd36528
commit
e153ab0a9b
13 changed files with 154 additions and 44 deletions
|
|
@ -175,7 +175,7 @@ export class PostsController {
|
|||
) {
|
||||
console.log(JSON.stringify(rawBody, null, 2));
|
||||
const body = await this._postsService.mapTypeToPost(rawBody, org.id);
|
||||
return this._postsService.createPost(org.id, body);
|
||||
return this._postsService.createPost(org.id, body, 'WEB');
|
||||
}
|
||||
|
||||
@Post('/generator/draft')
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ export class PublicIntegrationsController {
|
|||
}
|
||||
|
||||
console.log(JSON.stringify(body, null, 2));
|
||||
return this._postsService.createPost(org.id, body);
|
||||
return this._postsService.createPost(org.id, body, 'API');
|
||||
}
|
||||
|
||||
@Delete('/posts/:id')
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { VideoOrImage } from '@gitroom/react/helpers/video.or.image';
|
|||
import { CopyClient } from '@gitroom/frontend/components/preview/copy.client';
|
||||
import { getT } from '@gitroom/react/translation/get.translation.service.backend';
|
||||
import { RenderPreviewDateClient } from '@gitroom/frontend/components/preview/render.preview.date.client';
|
||||
import { CreationMethodBadge } from '@gitroom/frontend/components/launches/creation.method.badge';
|
||||
|
||||
dayjs.extend(utc);
|
||||
export const metadata: Metadata = {
|
||||
|
|
@ -142,6 +143,12 @@ export default async function Auth(
|
|||
<span className="text-sm text-gray-500">
|
||||
@{post[0].integration.profile}
|
||||
</span>
|
||||
{index === 0 && (
|
||||
<CreationMethodBadge
|
||||
creationMethod={p.creationMethod}
|
||||
size="md"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col gap-[20px]">
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ import { MissingReleaseModal } from '@gitroom/frontend/components/launches/missi
|
|||
import { useT } from '@gitroom/react/translation/get.transation.service.client';
|
||||
import i18next from 'i18next';
|
||||
import { AddEditModal } from '@gitroom/frontend/components/new-launch/add.edit.modal';
|
||||
import { CreationMethodBadge } from '@gitroom/frontend/components/launches/creation.method.badge';
|
||||
import { deleteDialog } from '@gitroom/react/helpers/delete.dialog';
|
||||
import { useVariables } from '@gitroom/react/helpers/variable.context';
|
||||
import copy from 'copy-to-clipboard';
|
||||
|
|
@ -1005,6 +1006,8 @@ const CalendarItem: FC<{
|
|||
missingRelease,
|
||||
} = props;
|
||||
const { disableXAnalytics } = useVariables();
|
||||
const showCreationMethodBadge =
|
||||
post.creationMethod && post.creationMethod !== 'UNKNOWN';
|
||||
const preview = useCallback(() => {
|
||||
window.open(`/p/` + post.id + '?share=true', '_blank');
|
||||
}, [post]);
|
||||
|
|
@ -1044,6 +1047,14 @@ const CalendarItem: FC<{
|
|||
!
|
||||
</div>
|
||||
)}
|
||||
{showCreationMethodBadge && (
|
||||
<div className="absolute -bottom-[4px] -right-[4px] z-20">
|
||||
<CreationMethodBadge
|
||||
creationMethod={post.creationMethod}
|
||||
ringColor="var(--new-bgColor)"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={clsx(
|
||||
'text-white text-[11px] max-h-[24px] h-[24px] min-h-[24px] w-full rounded-tr-[10px] rounded-tl-[10px] flex items-center justify-center gap-[10px] px-[5px] bg-btnPrimary'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
import { FC } from 'react';
|
||||
import clsx from 'clsx';
|
||||
|
||||
type CreationMethod = 'UNKNOWN' | 'WEB' | 'API' | 'MCP' | 'AUTOPOST';
|
||||
|
||||
interface Props {
|
||||
creationMethod?: CreationMethod | string | null;
|
||||
size?: 'xs' | 'sm' | 'md';
|
||||
className?: string;
|
||||
ringColor?: string;
|
||||
}
|
||||
|
||||
const tooltipFor = (m: string) =>
|
||||
m === 'AUTOPOST' ? 'Auto-posted by system' : `Created via ${m}`;
|
||||
|
||||
export const CreationMethodBadge: FC<Props> = ({
|
||||
creationMethod,
|
||||
size = 'xs',
|
||||
className,
|
||||
ringColor,
|
||||
}) => {
|
||||
if (!creationMethod || creationMethod === 'UNKNOWN') return null;
|
||||
|
||||
const sizeClasses =
|
||||
size === 'xs'
|
||||
? 'h-[12px] px-[4px] text-[7px]'
|
||||
: size === 'md'
|
||||
? 'h-[22px] px-[10px] text-[12px]'
|
||||
: 'h-[18px] px-[8px] text-[10px]';
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
'inline-flex items-center justify-center rounded-full text-white font-bold uppercase tracking-wide leading-none cursor-default',
|
||||
sizeClasses,
|
||||
creationMethod === 'WEB' && 'bg-[#6b7280]',
|
||||
creationMethod === 'API' && 'bg-[#2563eb]',
|
||||
creationMethod === 'MCP' && 'bg-[#9333ea]',
|
||||
creationMethod === 'AUTOPOST' && 'bg-[#d97706]',
|
||||
className
|
||||
)}
|
||||
style={ringColor ? { boxShadow: `0 0 0 2px ${ringColor}` } : undefined}
|
||||
data-tooltip-id="tooltip"
|
||||
data-tooltip-content={tooltipFor(creationMethod)}
|
||||
>
|
||||
{creationMethod}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -33,6 +33,7 @@ import { SelectCustomer } from '@gitroom/frontend/components/launches/select.cus
|
|||
import { CopilotPopup } from '@copilotkit/react-ui';
|
||||
import { DummyCodeComponent } from '@gitroom/frontend/components/new-launch/dummy.code.component';
|
||||
import { stripHtmlValidation } from '@gitroom/helpers/utils/strip.html.validation';
|
||||
import { CreationMethodBadge } from '@gitroom/frontend/components/launches/creation.method.badge';
|
||||
import {
|
||||
SettingsIcon,
|
||||
ChevronDownIcon,
|
||||
|
|
@ -447,8 +448,12 @@ export const ManageModal: FC<AddEditModalProps> = (props) => {
|
|||
<div className="flex flex-1 bg-newBgColorInner rounded-[20px] flex-col">
|
||||
<div className="flex-1 flex">
|
||||
<div className="flex flex-col flex-1 border-e border-newBorder">
|
||||
<div className="bg-newBgColor h-[65px] rounded-s-[20px] !rounded-b-[0] flex items-center px-[20px] text-[20px] font-[600]">
|
||||
<div className="bg-newBgColor h-[65px] rounded-s-[20px] !rounded-b-[0] flex items-center gap-[12px] px-[20px] text-[20px] font-[600]">
|
||||
{t('create_post_title', 'Create Post')}
|
||||
<CreationMethodBadge
|
||||
creationMethod={existingData?.posts?.[0]?.creationMethod}
|
||||
size="sm"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 flex flex-col gap-[16px]">
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { Toaster } from '@gitroom/react/toaster/toaster';
|
|||
import { MantineWrapper } from '@gitroom/react/helpers/mantine.wrapper';
|
||||
import { useVariables } from '@gitroom/react/helpers/variable.context';
|
||||
import { CopilotKit } from '@copilotkit/react-core';
|
||||
import { ToolTip } from '@gitroom/frontend/components/layout/top.tip';
|
||||
export const PreviewWrapper = ({ children }: { children: ReactNode }) => {
|
||||
const fetch = useFetch();
|
||||
const { backendUrl } = useVariables();
|
||||
|
|
@ -30,6 +31,7 @@ export const PreviewWrapper = ({ children }: { children: ReactNode }) => {
|
|||
>
|
||||
<MantineWrapper>
|
||||
<Toaster />
|
||||
<ToolTip />
|
||||
{children}
|
||||
</MantineWrapper>
|
||||
</CopilotKit>
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ const POST_ITEM_KEYS: Record<string, string> = {
|
|||
integration: 'n',
|
||||
intervalInDays: 'iv',
|
||||
actualDate: 'ad',
|
||||
creationMethod: 'cm',
|
||||
};
|
||||
|
||||
const INTEGRATION_KEYS: Record<string, string> = {
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ If the tools return errors, you would need to rerun it with the right parameters
|
|||
})),
|
||||
},
|
||||
],
|
||||
});
|
||||
}, 'MCP');
|
||||
finalOutput.push(...output);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ export class AutopostService {
|
|||
},
|
||||
],
|
||||
})),
|
||||
});
|
||||
}, 'AUTOPOST');
|
||||
}
|
||||
|
||||
async updateUrl(state: WorkflowChannelsState) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
import { PrismaRepository } from '@gitroom/nestjs-libraries/database/prisma/prisma.service';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Post as PostBody } from '@gitroom/nestjs-libraries/dtos/posts/create.post.dto';
|
||||
import { APPROVED_SUBMIT_FOR_ORDER, Post, State } from '@prisma/client';
|
||||
import {
|
||||
APPROVED_SUBMIT_FOR_ORDER,
|
||||
CreationMethod,
|
||||
Post,
|
||||
State,
|
||||
} from '@prisma/client';
|
||||
import { GetPostsDto } from '@gitroom/nestjs-libraries/dtos/posts/get.posts.dto';
|
||||
import { GetPostsListDto } from '@gitroom/nestjs-libraries/dtos/posts/get.posts.list.dto';
|
||||
import dayjs from 'dayjs';
|
||||
|
|
@ -173,6 +178,7 @@ export class PostsRepository {
|
|||
state: true,
|
||||
intervalInDays: true,
|
||||
group: true,
|
||||
creationMethod: true,
|
||||
tags: {
|
||||
select: {
|
||||
tag: true,
|
||||
|
|
@ -260,6 +266,7 @@ export class PostsRepository {
|
|||
releaseId: true,
|
||||
state: true,
|
||||
group: true,
|
||||
creationMethod: true,
|
||||
tags: {
|
||||
select: {
|
||||
tag: true,
|
||||
|
|
@ -483,6 +490,7 @@ export class PostsRepository {
|
|||
date: string,
|
||||
body: PostBody,
|
||||
tags: { value: string; label: string }[],
|
||||
creationMethod: CreationMethod,
|
||||
inter?: number
|
||||
) {
|
||||
const posts: Post[] = [];
|
||||
|
|
@ -517,6 +525,7 @@ export class PostsRepository {
|
|||
group: uuid,
|
||||
intervalInDays: inter ? +inter : null,
|
||||
approvedSubmitForOrder: APPROVED_SUBMIT_FOR_ORDER.NO,
|
||||
...(type === 'create' ? { creationMethod } : {}),
|
||||
...(state === 'update'
|
||||
? {}
|
||||
: {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,14 @@ import { PostsRepository } from '@gitroom/nestjs-libraries/database/prisma/posts
|
|||
import { CreatePostDto } from '@gitroom/nestjs-libraries/dtos/posts/create.post.dto';
|
||||
import dayjs from 'dayjs';
|
||||
import { IntegrationManager } from '@gitroom/nestjs-libraries/integrations/integration.manager';
|
||||
import { Integration, Post, Media, From, State } from '@prisma/client';
|
||||
import {
|
||||
Integration,
|
||||
Post,
|
||||
Media,
|
||||
From,
|
||||
CreationMethod,
|
||||
State,
|
||||
} from '@prisma/client';
|
||||
import { GetPostsDto } from '@gitroom/nestjs-libraries/dtos/posts/get.posts.dto';
|
||||
import { GetPostsListDto } from '@gitroom/nestjs-libraries/dtos/posts/get.posts.list.dto';
|
||||
import { shuffle } from 'lodash';
|
||||
|
|
@ -731,7 +738,11 @@ export class PostsService {
|
|||
} catch (err) {}
|
||||
}
|
||||
|
||||
async createPost(orgId: string, body: CreatePostDto): Promise<any[]> {
|
||||
async createPost(
|
||||
orgId: string,
|
||||
body: CreatePostDto,
|
||||
creationMethod: CreationMethod
|
||||
): Promise<any[]> {
|
||||
const postList = [];
|
||||
for (const post of body.posts) {
|
||||
const messages = (post.value || []).map((p) => p.content);
|
||||
|
|
@ -750,6 +761,7 @@ export class PostsService {
|
|||
body.type === 'now' ? dayjs().format('YYYY-MM-DDTHH:mm:00') : body.date,
|
||||
post,
|
||||
body.tags,
|
||||
creationMethod,
|
||||
body.inter
|
||||
);
|
||||
|
||||
|
|
@ -881,43 +893,47 @@ export class PostsService {
|
|||
const group = makeId(10);
|
||||
const randomDate = findTime();
|
||||
|
||||
await this.createPost(orgId, {
|
||||
type: 'draft',
|
||||
date: randomDate,
|
||||
order: '',
|
||||
shortLink: false,
|
||||
tags: [],
|
||||
posts: [
|
||||
{
|
||||
group,
|
||||
integration: {
|
||||
id: integration.id,
|
||||
},
|
||||
settings: {
|
||||
__type: integration.providerIdentifier as any,
|
||||
title: '',
|
||||
tags: [],
|
||||
subreddit: [],
|
||||
},
|
||||
value: [
|
||||
...toPost.list.map((l) => ({
|
||||
id: '',
|
||||
content: l.post,
|
||||
delay: 0,
|
||||
image: [],
|
||||
})),
|
||||
{
|
||||
id: '',
|
||||
delay: 0,
|
||||
content: `Check out the full story here:\n${
|
||||
body.postId || body.url
|
||||
}`,
|
||||
image: [],
|
||||
await this.createPost(
|
||||
orgId,
|
||||
{
|
||||
type: 'draft',
|
||||
date: randomDate,
|
||||
order: '',
|
||||
shortLink: false,
|
||||
tags: [],
|
||||
posts: [
|
||||
{
|
||||
group,
|
||||
integration: {
|
||||
id: integration.id,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
settings: {
|
||||
__type: integration.providerIdentifier as any,
|
||||
title: '',
|
||||
tags: [],
|
||||
subreddit: [],
|
||||
},
|
||||
value: [
|
||||
...toPost.list.map((l) => ({
|
||||
id: '',
|
||||
content: l.post,
|
||||
delay: 0,
|
||||
image: [],
|
||||
})),
|
||||
{
|
||||
id: '',
|
||||
delay: 0,
|
||||
content: `Check out the full story here:\n${
|
||||
body.postId || body.url
|
||||
}`,
|
||||
image: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
'WEB'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -409,6 +409,7 @@ model Post {
|
|||
submittedForOrderId String?
|
||||
submittedForOrganizationId String?
|
||||
approvedSubmitForOrder APPROVED_SUBMIT_FOR_ORDER @default(NO)
|
||||
creationMethod CreationMethod @default(UNKNOWN)
|
||||
lastMessageId String?
|
||||
intervalInDays Int?
|
||||
error String?
|
||||
|
|
@ -436,6 +437,7 @@ model Post {
|
|||
@@index([submittedForOrderId])
|
||||
@@index([intervalInDays])
|
||||
@@index([approvedSubmitForOrder])
|
||||
@@index([creationMethod])
|
||||
@@index([lastMessageId])
|
||||
@@index([createdAt])
|
||||
@@index([updatedAt])
|
||||
|
|
@ -938,6 +940,14 @@ enum APPROVED_SUBMIT_FOR_ORDER {
|
|||
YES
|
||||
}
|
||||
|
||||
enum CreationMethod {
|
||||
UNKNOWN
|
||||
WEB
|
||||
MCP
|
||||
API
|
||||
AUTOPOST
|
||||
}
|
||||
|
||||
enum ShortLinkPreference {
|
||||
ASK
|
||||
YES
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue