diff --git a/apps/backend/src/api/routes/posts.controller.ts b/apps/backend/src/api/routes/posts.controller.ts index 790df94f..14756ce2 100644 --- a/apps/backend/src/api/routes/posts.controller.ts +++ b/apps/backend/src/api/routes/posts.controller.ts @@ -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') diff --git a/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts b/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts index 38ce060b..9eef59f1 100644 --- a/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts +++ b/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts @@ -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') diff --git a/apps/frontend/src/app/(app)/(preview)/p/[id]/page.tsx b/apps/frontend/src/app/(app)/(preview)/p/[id]/page.tsx index fb12181d..f5dc7b46 100644 --- a/apps/frontend/src/app/(app)/(preview)/p/[id]/page.tsx +++ b/apps/frontend/src/app/(app)/(preview)/p/[id]/page.tsx @@ -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( @{post[0].integration.profile} + {index === 0 && ( + + )}
{ window.open(`/p/` + post.id + '?share=true', '_blank'); }, [post]); @@ -1044,6 +1047,14 @@ const CalendarItem: FC<{ !
)} + {showCreationMethodBadge && ( +
+ +
+ )}
+ m === 'AUTOPOST' ? 'Auto-posted by system' : `Created via ${m}`; + +export const CreationMethodBadge: FC = ({ + 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 ( +
+ {creationMethod} +
+ ); +}; diff --git a/apps/frontend/src/components/new-launch/manage.modal.tsx b/apps/frontend/src/components/new-launch/manage.modal.tsx index 0af6af15..becc74b7 100644 --- a/apps/frontend/src/components/new-launch/manage.modal.tsx +++ b/apps/frontend/src/components/new-launch/manage.modal.tsx @@ -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 = (props) => {
-
+
{t('create_post_title', 'Create Post')} +
{ const fetch = useFetch(); const { backendUrl } = useVariables(); @@ -30,6 +31,7 @@ export const PreviewWrapper = ({ children }: { children: ReactNode }) => { > + {children} diff --git a/libraries/helpers/src/utils/posts.list.minify.ts b/libraries/helpers/src/utils/posts.list.minify.ts index cebe1497..f5847b9d 100644 --- a/libraries/helpers/src/utils/posts.list.minify.ts +++ b/libraries/helpers/src/utils/posts.list.minify.ts @@ -25,6 +25,7 @@ const POST_ITEM_KEYS: Record = { integration: 'n', intervalInDays: 'iv', actualDate: 'ad', + creationMethod: 'cm', }; const INTEGRATION_KEYS: Record = { diff --git a/libraries/nestjs-libraries/src/chat/tools/integration.schedule.post.ts b/libraries/nestjs-libraries/src/chat/tools/integration.schedule.post.ts index dc3c3f52..b2983de7 100644 --- a/libraries/nestjs-libraries/src/chat/tools/integration.schedule.post.ts +++ b/libraries/nestjs-libraries/src/chat/tools/integration.schedule.post.ts @@ -223,7 +223,7 @@ If the tools return errors, you would need to rerun it with the right parameters })), }, ], - }); + }, 'MCP'); finalOutput.push(...output); } diff --git a/libraries/nestjs-libraries/src/database/prisma/autopost/autopost.service.ts b/libraries/nestjs-libraries/src/database/prisma/autopost/autopost.service.ts index 5964983a..c8132847 100644 --- a/libraries/nestjs-libraries/src/database/prisma/autopost/autopost.service.ts +++ b/libraries/nestjs-libraries/src/database/prisma/autopost/autopost.service.ts @@ -303,7 +303,7 @@ export class AutopostService { }, ], })), - }); + }, 'AUTOPOST'); } async updateUrl(state: WorkflowChannelsState) { diff --git a/libraries/nestjs-libraries/src/database/prisma/posts/posts.repository.ts b/libraries/nestjs-libraries/src/database/prisma/posts/posts.repository.ts index be031e24..e131574e 100644 --- a/libraries/nestjs-libraries/src/database/prisma/posts/posts.repository.ts +++ b/libraries/nestjs-libraries/src/database/prisma/posts/posts.repository.ts @@ -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' ? {} : { diff --git a/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts b/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts index 2ca5c875..a4896849 100644 --- a/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts +++ b/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts @@ -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 { + async createPost( + orgId: string, + body: CreatePostDto, + creationMethod: CreationMethod + ): Promise { 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' + ); } } } diff --git a/libraries/nestjs-libraries/src/database/prisma/schema.prisma b/libraries/nestjs-libraries/src/database/prisma/schema.prisma index a005ed80..03335f30 100644 --- a/libraries/nestjs-libraries/src/database/prisma/schema.prisma +++ b/libraries/nestjs-libraries/src/database/prisma/schema.prisma @@ -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