Updated funnel edit form.
Some checks are pending
Node.js CI / build (postgresql, 18.18) (push) Waiting to run

This commit is contained in:
Mike Cao 2025-09-01 20:18:38 -07:00
parent d534c0b221
commit f0ec24e8f5
4 changed files with 492 additions and 108 deletions

View file

@ -4,19 +4,19 @@ import {
FormFieldArray,
TextField,
Grid,
FormController,
FormButtons,
FormSubmitButton,
Button,
RadioGroup,
Radio,
Text,
Icon,
Row,
Loading,
Column,
} from '@umami/react-zen';
import { useMessages, useReportQuery, useUpdateQuery } from '@/components/hooks';
import { File, Lightning, Close, Plus } from '@/components/icons';
import { Close, Plus } from '@/components/icons';
import { ActionSelect } from '@/components/input/ActionSelect';
import { LookupField } from '@/components/input/LookupField';
const FUNNEL_STEPS_MAX = 8;
@ -41,6 +41,7 @@ export function FunnelEditForm({
{
onSuccess: async () => {
touch('reports:funnel');
touch(`report:${id}`);
onSave?.();
onClose?.();
},
@ -75,57 +76,38 @@ export function FunnelEditForm({
<TextField />
</FormField>
<FormFieldArray name="steps" label={formatMessage(labels.steps)}>
{({ fields, append, remove, control }) => {
{({ fields, append, remove, getValues }) => {
return (
<Grid gap>
{fields.map((field: { id: string; type: string; value: string }, index: number) => {
{fields.map(({ id }: { id: string }, index: number) => {
const type = getValues(`steps.${index}.type`);
return (
<Row key={field.id} alignItems="center" justifyContent="space-between" gap>
<FormController control={control} name={`steps.${index}.type`}>
{({ field }) => {
return (
<RadioGroup
orientation="horizontal"
variant="box"
value={field.value}
onChange={field.onChange}
>
<Grid columns="1fr 1fr" flexGrow={1} gap>
<Radio id="path" value="path">
<Icon>
<File />
</Icon>
<Text>{formatMessage(labels.page)}</Text>
</Radio>
<Radio id="event" value="event">
<Icon>
<Lightning />
</Icon>
<Text>{formatMessage(labels.event)}</Text>
</Radio>
</Grid>
</RadioGroup>
);
}}
</FormController>
<FormController control={control} name={`steps.${index}.value`}>
{({ field }) => {
return (
<TextField
value={field.value}
onChange={field.onChange}
defaultValue={field.value}
style={{ flexGrow: 1 }}
/>
);
}}
</FormController>
<Button variant="quiet" onPress={() => remove(index)}>
<Grid key={id} columns="260px 1fr auto" gap>
<Column>
<FormField
name={`steps.${index}.type`}
rules={{ required: formatMessage(labels.required) }}
>
<ActionSelect />
</FormField>
</Column>
<Column>
<FormField
name={`steps.${index}.value`}
rules={{ required: formatMessage(labels.required) }}
>
{({ field }) => {
return <LookupField websiteId={websiteId} type={type} {...field} />;
}}
</FormField>
</Column>
<Button onPress={() => remove(index)}>
<Icon size="sm">
<Close />
</Icon>
</Button>
</Row>
</Grid>
);
})}
<Row>

View file

@ -1,7 +1,6 @@
import debug from 'debug';
import { PrismaClient } from '@/generated/prisma/client';
import { PrismaPg } from '@prisma/adapter-pg';
import { readReplicas } from '@prisma/extension-read-replicas';
import { UmamiPrismaClient } from '@umami/prisma-client';
import { SESSION_COLUMNS, OPERATORS, DEFAULT_PAGE_SIZE, FILTER_COLUMNS } from './constants';
import { QueryOptions, QueryFilters, Operator } from './types';
import { filtersObjectToArray } from './params';
@ -9,14 +8,6 @@ import { filtersObjectToArray } from './params';
const log = debug('umami:prisma');
const PRISMA = 'prisma';
const PRISMA_LOG_OPTIONS = {
log: [
{
emit: 'event',
level: 'query',
},
],
};
const DATE_FORMATS = {
minute: 'YYYY-MM-DD HH24:MI:00',
@ -218,7 +209,7 @@ async function pagedQuery<T>(model: string, criteria: T, filters?: QueryFilters)
return { data, count, page: +page, pageSize: size, orderBy, search };
}
async function rawPagedQuery(
async function pagedRawQuery(
query: string,
filters: QueryFilters,
queryParams: Record<string, any>,
@ -274,52 +265,18 @@ function transaction(input: any, options?: any) {
return client.$transaction(input, options);
}
function getClient(params?: {
logQuery?: boolean;
queryLogger?: () => void;
replicaUrl?: string;
options?: any;
}): PrismaClient {
const {
logQuery = !!process.env.LOG_QUERY,
queryLogger,
replicaUrl = process.env.DATABASE_REPLICA_URL,
options,
} = params || {};
const url = new URL(process.env.DATABASE_URL);
const adapter = new PrismaPg(
{ connectionString: url.toString() },
{ schema: url.searchParams.get('schema') },
);
const prisma = new PrismaClient({
adapter,
errorFormat: 'pretty',
...(logQuery && PRISMA_LOG_OPTIONS),
...options,
function getClient() {
const prisma = new UmamiPrismaClient({
url: process.env.DATABASE_URL,
prismaClient: PrismaClient,
logQuery: !!process.env.LOG_QUERY,
});
if (replicaUrl) {
prisma.$extends(
readReplicas({
url: replicaUrl,
}),
);
}
if (logQuery) {
prisma.$on('query' as never, queryLogger || log);
}
if (process.env.NODE_ENV !== 'production') {
globalThis[PRISMA] = prisma;
globalThis[PRISMA] = prisma.client;
}
log('Prisma initialized');
return prisma;
return prisma.client;
}
const client = globalThis[PRISMA] || getClient();
@ -337,7 +294,7 @@ export default {
getTimestampDiffSQL,
getSearchSQL,
pagedQuery,
pagedRawQuery: rawPagedQuery,
pagedRawQuery,
parseFilters,
rawQuery,
};