feat: add feed template string of survey

This commit is contained in:
moonrailgun 2024-08-15 01:33:23 +08:00
parent d9862105ed
commit 22fc5f98f8
9 changed files with 110 additions and 19 deletions

View File

@ -504,6 +504,9 @@ importers:
lodash:
specifier: ^4.17.21
version: 4.17.21
lodash-es:
specifier: ^4.17.21
version: 4.17.21
maxmind:
specifier: ^4.3.18
version: 4.3.18
@ -592,6 +595,9 @@ importers:
'@types/lodash':
specifier: ^4.14.198
version: 4.14.198
'@types/lodash-es':
specifier: ^4.17.12
version: 4.17.12
'@types/md5':
specifier: ^2.3.5
version: 2.3.5

View File

@ -18,7 +18,7 @@ import {
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { useForm, useFieldArray } from 'react-hook-form';
import { useForm, useFieldArray, useWatch } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { generateRandomString } from '@/utils/common';
import { LuArrowDown, LuArrowUp, LuMinus, LuPlus } from 'react-icons/lu';
@ -48,6 +48,7 @@ const addFormSchema = z.object({
),
}),
feedChannelIds: z.array(z.string()),
feedTemplate: z.string(),
});
export type SurveyEditFormValues = z.infer<typeof addFormSchema>;
@ -78,9 +79,12 @@ export const SurveyEditForm: React.FC<SurveyEditFormProps> = React.memo(
items: [generateDefaultItem()],
},
feedChannelIds: [],
feedTemplate: '',
},
});
const feedChannelIds = form.watch('feedChannelIds');
const [handleSubmit, isLoading] = useEventWithLoading(
async (values: SurveyEditFormValues) => {
await props.onSubmit(values);
@ -263,6 +267,36 @@ export const SurveyEditForm: React.FC<SurveyEditFormProps> = React.memo(
</FormItem>
)}
/>
{feedChannelIds.length > 0 && (
<FormField
control={form.control}
name="feedTemplate"
render={({ field }) => (
<FormItem>
<FormLabel>{t('Feed Template')}</FormLabel>
<FormControl>
<Input
placeholder="survey {{_surveyName}} receive a new record."
{...field}
/>
</FormControl>
<FormDescription>
<p>
{t(
'Survey Template String, here are available variables:'
)}
</p>
<p>
{'{{_surveyName}} '}
{fields.map((f) => `{{${f.name}}}`).join(' ')}
</p>
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
)}
</CardContent>
<CardFooter>

View File

@ -51,6 +51,7 @@
"isolated-vm": "^4.7.2",
"jsonwebtoken": "^9.0.2",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"maxmind": "^4.3.18",
"md5": "^2.3.0",
"morgan": "^1.10.0",
@ -82,6 +83,7 @@
"@types/fs-extra": "^11.0.3",
"@types/jsonwebtoken": "^9.0.5",
"@types/lodash": "^4.14.198",
"@types/lodash-es": "^4.17.12",
"@types/md5": "^2.3.5",
"@types/morgan": "^1.9.5",
"@types/node": "^18.17.12",

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Survey" ADD COLUMN "feedTemplate" TEXT NOT NULL DEFAULT '';

View File

@ -459,6 +459,7 @@ model Survey {
/// @zod.custom(imports.SurveyPayloadSchema)
payload Json @db.Json
feedChannelIds String[] @default([]) // send survey result to feed channel
feedTemplate String @default("") // send survey result to feed channel
createdAt DateTime @default(now()) @db.Timestamptz(6)
updatedAt DateTime @updatedAt @db.Timestamptz(6)

View File

@ -17,6 +17,7 @@ export const SurveyModelSchema = z.object({
*/
payload: imports.SurveyPayloadSchema,
feedChannelIds: z.string().array(),
feedTemplate: z.string(),
createdAt: z.date(),
updatedAt: z.date(),
})

View File

@ -20,6 +20,8 @@ import { buildCursorResponseSchema } from '../../utils/schema.js';
import { fetchDataByCursor } from '../../utils/prisma.js';
import { Prisma } from '@prisma/client';
import { createFeedEvent } from '../../model/feed/event.js';
import { formatString } from '../../utils/template.js';
import { logger } from '../../utils/logger.js';
export const surveyRouter = router({
all: workspaceProcedure
@ -185,15 +187,33 @@ export const surveyRouter = router({
Array.isArray(survey.feedChannelIds) &&
survey.feedChannelIds.length > 0
) {
const templateStr =
survey.feedTemplate ||
'survey {{_surveyName}} receive a new record.';
survey.feedChannelIds.forEach((channelId) => {
try {
const surveyPayload = SurveyPayloadSchema.parse(survey.payload);
createFeedEvent(workspaceId, {
channelId: channelId,
eventName: 'receive',
eventContent: `survey [${survey.name}] receive a new record.`,
eventContent: formatString(templateStr, {
_surveyName: survey.name,
...Object.fromEntries(
surveyPayload.items.map((item) => [
item.name,
payload[item.name] ?? '',
])
),
}),
tags: [],
source: 'survey',
important: false,
});
} catch (err) {
logger.error('[surveySubmitSendFeed]', err);
}
});
}
});
@ -212,11 +232,13 @@ export const surveyRouter = router({
name: z.string(),
payload: SurveyPayloadSchema,
feedChannelIds: z.array(z.string()),
feedTemplate: z.string(),
})
)
.output(SurveyModelSchema)
.mutation(async ({ input }) => {
const { workspaceId, name, payload, feedChannelIds } = input;
const { workspaceId, name, payload, feedChannelIds, feedTemplate } =
input;
const res = await prisma.survey.create({
data: {
@ -224,6 +246,7 @@ export const surveyRouter = router({
name,
payload,
feedChannelIds,
feedTemplate,
},
});
@ -242,11 +265,19 @@ export const surveyRouter = router({
name: z.string().optional(),
payload: SurveyPayloadSchema.optional(),
feedChannelIds: z.array(z.string()).optional(),
feedTemplate: z.string().optional(),
})
)
.output(SurveyModelSchema)
.mutation(async ({ input }) => {
const { workspaceId, surveyId, name, payload, feedChannelIds } = input;
const {
workspaceId,
surveyId,
name,
payload,
feedChannelIds,
feedTemplate,
} = input;
const res = await prisma.survey.update({
where: {
@ -257,6 +288,7 @@ export const surveyRouter = router({
name,
payload,
feedChannelIds,
feedTemplate,
},
});

View File

@ -1,8 +1,8 @@
import type { JWTPayload } from '../middleware/auth';
import type { JWTPayload } from '../middleware/auth.ts';
import type {
MonitorStatusPageListSchema,
SurveyPayloadSchema,
} from '../prisma/zod/schemas';
} from '../prisma/zod/schemas/index.ts';
declare global {
namespace Express {

View File

@ -0,0 +1,13 @@
import { template, templateSettings } from 'lodash-es';
templateSettings.interpolate = /{{([\s\S]+?)}}/g;
/**
* @example
*
* buildTemplate('hello {{ user }}!', { user: 'mustache' })
* => 'hello mustache!'
*/
export function formatString(raw: string, variable: Record<string, string>) {
return template(raw)(variable);
}