Compare commits
3 Commits
master
...
feat/surve
Author | SHA1 | Date | |
---|---|---|---|
|
cbd6821def | ||
|
8a6a75f3f5 | ||
|
fd63f2a22e |
@ -1,12 +1,7 @@
|
|||||||
import { createFileRoute, useNavigate } from '@tanstack/react-router';
|
|
||||||
import { useTranslation } from '@i18next-toolkit/react';
|
import { useTranslation } from '@i18next-toolkit/react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { useEvent, useEventWithLoading } from '@/hooks/useEvent';
|
import { useEventWithLoading } from '@/hooks/useEvent';
|
||||||
import { useCurrentWorkspaceId } from '@/store/user';
|
|
||||||
import { defaultErrorHandler, trpc } from '@/api/trpc';
|
|
||||||
import { Card, CardContent, CardFooter } from '@/components/ui/card';
|
import { Card, CardContent, CardFooter } from '@/components/ui/card';
|
||||||
import { CommonWrapper } from '@/components/CommonWrapper';
|
|
||||||
import { routeAuthBeforeLoad } from '@/utils/route';
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
@ -18,7 +13,7 @@ import {
|
|||||||
FormMessage,
|
FormMessage,
|
||||||
} from '@/components/ui/form';
|
} from '@/components/ui/form';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { useForm, useFieldArray, useWatch } from 'react-hook-form';
|
import { useForm, useFieldArray } from 'react-hook-form';
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { generateRandomString } from '@/utils/common';
|
import { generateRandomString } from '@/utils/common';
|
||||||
import { LuArrowDown, LuArrowUp, LuMinus, LuPlus } from 'react-icons/lu';
|
import { LuArrowDown, LuArrowUp, LuMinus, LuPlus } from 'react-icons/lu';
|
||||||
@ -49,6 +44,7 @@ const addFormSchema = z.object({
|
|||||||
}),
|
}),
|
||||||
feedChannelIds: z.array(z.string()),
|
feedChannelIds: z.array(z.string()),
|
||||||
feedTemplate: z.string(),
|
feedTemplate: z.string(),
|
||||||
|
webhookUrl: z.string().url().or(z.literal('')),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type SurveyEditFormValues = z.infer<typeof addFormSchema>;
|
export type SurveyEditFormValues = z.infer<typeof addFormSchema>;
|
||||||
@ -80,6 +76,7 @@ export const SurveyEditForm: React.FC<SurveyEditFormProps> = React.memo(
|
|||||||
},
|
},
|
||||||
feedChannelIds: [],
|
feedChannelIds: [],
|
||||||
feedTemplate: '',
|
feedTemplate: '',
|
||||||
|
webhookUrl: '',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -87,7 +84,7 @@ export const SurveyEditForm: React.FC<SurveyEditFormProps> = React.memo(
|
|||||||
|
|
||||||
const [handleSubmit, isLoading] = useEventWithLoading(
|
const [handleSubmit, isLoading] = useEventWithLoading(
|
||||||
async (values: SurveyEditFormValues) => {
|
async (values: SurveyEditFormValues) => {
|
||||||
await props.onSubmit(values);
|
await props.onSubmit({ ...values });
|
||||||
form.reset();
|
form.reset();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -297,6 +294,23 @@ export const SurveyEditForm: React.FC<SurveyEditFormProps> = React.memo(
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="webhookUrl"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel optional={true}>{t('Webhook Url')}</FormLabel>
|
||||||
|
<FormControl className="w-full">
|
||||||
|
<Input {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>
|
||||||
|
{t('Optional, webhook url to send survey payload')}
|
||||||
|
</FormDescription>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|
||||||
<CardFooter>
|
<CardFooter>
|
||||||
|
@ -2,7 +2,7 @@ import { createFileRoute, useNavigate } from '@tanstack/react-router';
|
|||||||
import { useTranslation } from '@i18next-toolkit/react';
|
import { useTranslation } from '@i18next-toolkit/react';
|
||||||
import { useEvent } from '@/hooks/useEvent';
|
import { useEvent } from '@/hooks/useEvent';
|
||||||
import { useCurrentWorkspaceId } from '@/store/user';
|
import { useCurrentWorkspaceId } from '@/store/user';
|
||||||
import { trpc } from '@/api/trpc';
|
import { defaultErrorHandler, trpc } from '@/api/trpc';
|
||||||
import { Card, CardContent } from '@/components/ui/card';
|
import { Card, CardContent } from '@/components/ui/card';
|
||||||
import { CommonWrapper } from '@/components/CommonWrapper';
|
import { CommonWrapper } from '@/components/CommonWrapper';
|
||||||
import { routeAuthBeforeLoad } from '@/utils/route';
|
import { routeAuthBeforeLoad } from '@/utils/route';
|
||||||
@ -25,7 +25,9 @@ function PageComponent() {
|
|||||||
const { surveyId } = Route.useParams<{ surveyId: string }>();
|
const { surveyId } = Route.useParams<{ surveyId: string }>();
|
||||||
const workspaceId = useCurrentWorkspaceId();
|
const workspaceId = useCurrentWorkspaceId();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const mutation = trpc.survey.update.useMutation();
|
const mutation = trpc.survey.update.useMutation({
|
||||||
|
onError: defaultErrorHandler,
|
||||||
|
});
|
||||||
const { data: survey, isLoading } = trpc.survey.get.useQuery({
|
const { data: survey, isLoading } = trpc.survey.get.useQuery({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
surveyId,
|
surveyId,
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
import { version } from '@tianji/shared';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
axios.defaults.headers.common['User-Agent'] = `tianji/${version}`;
|
||||||
|
|
||||||
(BigInt.prototype as any).toJSON = function () {
|
(BigInt.prototype as any).toJSON = function () {
|
||||||
const int = Number.parseInt(this.toString());
|
const int = Number.parseInt(this.toString());
|
||||||
return int ?? this.toString();
|
return int ?? this.toString();
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Survey" ADD COLUMN "webhookUrl" TEXT NOT NULL DEFAULT '';
|
@ -495,6 +495,7 @@ model Survey {
|
|||||||
payload Json @db.Json
|
payload Json @db.Json
|
||||||
feedChannelIds String[] @default([]) // send survey result to feed channel
|
feedChannelIds String[] @default([]) // send survey result to feed channel
|
||||||
feedTemplate String @default("") // send survey result to feed channel
|
feedTemplate String @default("") // send survey result to feed channel
|
||||||
|
webhookUrl String @default("")
|
||||||
createdAt DateTime @default(now()) @db.Timestamptz(6)
|
createdAt DateTime @default(now()) @db.Timestamptz(6)
|
||||||
updatedAt DateTime @updatedAt @db.Timestamptz(6)
|
updatedAt DateTime @updatedAt @db.Timestamptz(6)
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ export const SurveyModelSchema = z.object({
|
|||||||
payload: imports.SurveyPayloadSchema,
|
payload: imports.SurveyPayloadSchema,
|
||||||
feedChannelIds: z.string().array(),
|
feedChannelIds: z.string().array(),
|
||||||
feedTemplate: z.string(),
|
feedTemplate: z.string(),
|
||||||
|
webhookUrl: z.string(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
})
|
})
|
||||||
|
@ -22,6 +22,7 @@ import { Prisma } from '@prisma/client';
|
|||||||
import { createFeedEvent } from '../../model/feed/event.js';
|
import { createFeedEvent } from '../../model/feed/event.js';
|
||||||
import { formatString } from '../../utils/template.js';
|
import { formatString } from '../../utils/template.js';
|
||||||
import { logger } from '../../utils/logger.js';
|
import { logger } from '../../utils/logger.js';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
export const surveyRouter = router({
|
export const surveyRouter = router({
|
||||||
all: workspaceProcedure
|
all: workspaceProcedure
|
||||||
@ -154,7 +155,7 @@ export const surveyRouter = router({
|
|||||||
|
|
||||||
const sessionId = hashUuid(workspaceId, surveyId, ip, userAgent!);
|
const sessionId = hashUuid(workspaceId, surveyId, ip, userAgent!);
|
||||||
|
|
||||||
await prisma.surveyResult.create({
|
const result = await prisma.surveyResult.create({
|
||||||
data: {
|
data: {
|
||||||
surveyId,
|
surveyId,
|
||||||
sessionId,
|
sessionId,
|
||||||
@ -191,11 +192,11 @@ export const surveyRouter = router({
|
|||||||
survey.feedTemplate ||
|
survey.feedTemplate ||
|
||||||
'survey {{_surveyName}} receive a new record.';
|
'survey {{_surveyName}} receive a new record.';
|
||||||
|
|
||||||
survey.feedChannelIds.forEach((channelId) => {
|
survey.feedChannelIds.forEach(async (channelId) => {
|
||||||
try {
|
try {
|
||||||
const surveyPayload = SurveyPayloadSchema.parse(survey.payload);
|
const surveyPayload = SurveyPayloadSchema.parse(survey.payload);
|
||||||
|
|
||||||
createFeedEvent(workspaceId, {
|
await createFeedEvent(workspaceId, {
|
||||||
channelId: channelId,
|
channelId: channelId,
|
||||||
eventName: 'receive',
|
eventName: 'receive',
|
||||||
eventContent: formatString(templateStr, {
|
eventContent: formatString(templateStr, {
|
||||||
@ -216,6 +217,19 @@ export const surveyRouter = router({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (survey && survey.webhookUrl) {
|
||||||
|
axios
|
||||||
|
.post(survey.webhookUrl, {
|
||||||
|
...result,
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
logger.info(
|
||||||
|
`[surveySubmitWebhook] send webhooks to ${survey.webhookUrl} success!`
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((err) => logger.error('[surveySubmitWebhook]', err));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return 'success';
|
return 'success';
|
||||||
@ -233,12 +247,19 @@ export const surveyRouter = router({
|
|||||||
payload: SurveyPayloadSchema,
|
payload: SurveyPayloadSchema,
|
||||||
feedChannelIds: z.array(z.string()),
|
feedChannelIds: z.array(z.string()),
|
||||||
feedTemplate: z.string(),
|
feedTemplate: z.string(),
|
||||||
|
webhookUrl: z.string(),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.output(SurveyModelSchema)
|
.output(SurveyModelSchema)
|
||||||
.mutation(async ({ input }) => {
|
.mutation(async ({ input }) => {
|
||||||
const { workspaceId, name, payload, feedChannelIds, feedTemplate } =
|
const {
|
||||||
input;
|
workspaceId,
|
||||||
|
name,
|
||||||
|
payload,
|
||||||
|
feedChannelIds,
|
||||||
|
feedTemplate,
|
||||||
|
webhookUrl,
|
||||||
|
} = input;
|
||||||
|
|
||||||
const res = await prisma.survey.create({
|
const res = await prisma.survey.create({
|
||||||
data: {
|
data: {
|
||||||
@ -247,6 +268,7 @@ export const surveyRouter = router({
|
|||||||
payload,
|
payload,
|
||||||
feedChannelIds,
|
feedChannelIds,
|
||||||
feedTemplate,
|
feedTemplate,
|
||||||
|
webhookUrl,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -266,6 +288,7 @@ export const surveyRouter = router({
|
|||||||
payload: SurveyPayloadSchema.optional(),
|
payload: SurveyPayloadSchema.optional(),
|
||||||
feedChannelIds: z.array(z.string()).optional(),
|
feedChannelIds: z.array(z.string()).optional(),
|
||||||
feedTemplate: z.string().optional(),
|
feedTemplate: z.string().optional(),
|
||||||
|
webhookUrl: z.string().optional(),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.output(SurveyModelSchema)
|
.output(SurveyModelSchema)
|
||||||
@ -277,6 +300,7 @@ export const surveyRouter = router({
|
|||||||
payload,
|
payload,
|
||||||
feedChannelIds,
|
feedChannelIds,
|
||||||
feedTemplate,
|
feedTemplate,
|
||||||
|
webhookUrl,
|
||||||
} = input;
|
} = input;
|
||||||
|
|
||||||
const res = await prisma.survey.update({
|
const res = await prisma.survey.update({
|
||||||
@ -289,6 +313,7 @@ export const surveyRouter = router({
|
|||||||
payload,
|
payload,
|
||||||
feedChannelIds,
|
feedChannelIds,
|
||||||
feedTemplate,
|
feedTemplate,
|
||||||
|
webhookUrl,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user