mirror of
https://github.com/umami-software/umami.git
synced 2026-02-04 04:37:11 +01:00
Updated cohort processing.
Some checks are pending
Node.js CI / build (postgresql, 18.18) (push) Waiting to run
Some checks are pending
Node.js CI / build (postgresql, 18.18) (push) Waiting to run
This commit is contained in:
parent
c3b62e3a74
commit
f9442001e4
8 changed files with 46 additions and 56 deletions
|
|
@ -90,7 +90,9 @@ export function CohortEditForm({
|
|||
<Form
|
||||
error={error}
|
||||
onSubmit={handleSubmit}
|
||||
defaultValues={data || { parameters: { filters, dateRange: '30day' } }}
|
||||
defaultValues={
|
||||
data || { parameters: { filters, dateRange: '30day', action: { type: 'path' } } }
|
||||
}
|
||||
>
|
||||
<FormField
|
||||
name="name"
|
||||
|
|
@ -104,14 +106,19 @@ export function CohortEditForm({
|
|||
<Label>{formatMessage(labels.action)}</Label>
|
||||
<Grid columns="260px 1fr" gap>
|
||||
<Column>
|
||||
<Select value={action} onChange={setAction}>
|
||||
<ListItem id="path">{formatMessage(labels.viewedPage)}</ListItem>
|
||||
<ListItem id="event">{formatMessage(labels.triggeredEvent)}</ListItem>
|
||||
</Select>
|
||||
<FormField
|
||||
name="parameters.action.type"
|
||||
rules={{ required: formatMessage(labels.required) }}
|
||||
>
|
||||
<Select onSelectionChange={(value: any) => setAction(value)}>
|
||||
<ListItem id="path">{formatMessage(labels.viewedPage)}</ListItem>
|
||||
<ListItem id="event">{formatMessage(labels.triggeredEvent)}</ListItem>
|
||||
</Select>
|
||||
</FormField>
|
||||
</Column>
|
||||
<Column>
|
||||
<FormField
|
||||
name="parameters.action"
|
||||
name="parameters.action.value"
|
||||
rules={{ required: formatMessage(labels.required) }}
|
||||
>
|
||||
{({ field }) => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { canViewWebsite } from '@/validations';
|
||||
import { EVENT_COLUMNS, FILTER_COLUMNS, FILTER_GROUPS, SESSION_COLUMNS } from '@/lib/constants';
|
||||
import { EVENT_COLUMNS, FILTER_COLUMNS, SEGMENT_TYPES, SESSION_COLUMNS } from '@/lib/constants';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { badRequest, json, unauthorized } from '@/lib/response';
|
||||
import { getWebsiteSegments, getValues } from '@/queries';
|
||||
|
|
@ -30,14 +30,16 @@ export async function GET(
|
|||
|
||||
const { type } = query;
|
||||
|
||||
if (!SESSION_COLUMNS.includes(type) && !EVENT_COLUMNS.includes(type) && !FILTER_GROUPS[type]) {
|
||||
if (!SESSION_COLUMNS.includes(type) && !EVENT_COLUMNS.includes(type) && !SEGMENT_TYPES[type]) {
|
||||
return badRequest();
|
||||
}
|
||||
|
||||
let values;
|
||||
let values: any[];
|
||||
|
||||
if (FILTER_GROUPS[type]) {
|
||||
values = (await getWebsiteSegments(websiteId, type)).map(segment => ({ value: segment.name }));
|
||||
if (SEGMENT_TYPES[type]) {
|
||||
values = (await getWebsiteSegments(websiteId, type))?.data?.map(segment => ({
|
||||
value: segment.name,
|
||||
}));
|
||||
} else {
|
||||
const filters = await getQueryFilters(query, websiteId);
|
||||
values = await getValues(websiteId, FILTER_COLUMNS[type], filters);
|
||||
|
|
|
|||
|
|
@ -92,16 +92,9 @@ export function FilterBar({ websiteId }: { websiteId: string }) {
|
|||
</TooltipTrigger>
|
||||
)}
|
||||
<Modal>
|
||||
<Dialog title={formatMessage(labels.segment)} style={{ width: 400 }}>
|
||||
<Dialog title={formatMessage(labels.segment)} style={{ width: 800, minHeight: 300 }}>
|
||||
{({ close }) => {
|
||||
return (
|
||||
<SegmentEditForm
|
||||
websiteId={websiteId}
|
||||
onClose={close}
|
||||
filters={filters}
|
||||
showFilters={false}
|
||||
/>
|
||||
);
|
||||
return <SegmentEditForm websiteId={websiteId} onClose={close} filters={filters} />;
|
||||
}}
|
||||
</Dialog>
|
||||
</Modal>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useState } from 'react';
|
||||
import { Column, Tabs, TabList, Tab, TabPanel, Row, Button } from '@umami/react-zen';
|
||||
import { useDateRange, useMessages } from '@/components/hooks';
|
||||
import { useMessages } from '@/components/hooks';
|
||||
import { FieldFilters } from '@/components/input/FieldFilters';
|
||||
import { SegmentFilters } from '@/components/input/SegmentFilters';
|
||||
|
||||
|
|
@ -23,10 +23,6 @@ export function FilterEditForm({
|
|||
const [currentFilters, setCurrentFilters] = useState(filters);
|
||||
const [currentSegment, setCurrentSegment] = useState(segmentId);
|
||||
|
||||
const {
|
||||
dateRange: { startDate, endDate },
|
||||
} = useDateRange(websiteId);
|
||||
|
||||
const handleReset = () => {
|
||||
setCurrentFilters([]);
|
||||
setCurrentSegment(null);
|
||||
|
|
@ -49,13 +45,7 @@ export function FilterEditForm({
|
|||
<Tab id="segments">{formatMessage(labels.segments)}</Tab>
|
||||
</TabList>
|
||||
<TabPanel id="fields">
|
||||
<FieldFilters
|
||||
websiteId={websiteId}
|
||||
value={currentFilters}
|
||||
startDate={startDate}
|
||||
endDate={endDate}
|
||||
onSave={setCurrentFilters}
|
||||
/>
|
||||
<FieldFilters websiteId={websiteId} value={currentFilters} onChange={setCurrentFilters} />
|
||||
</TabPanel>
|
||||
<TabPanel id="segments" style={{ height: 400 }}>
|
||||
<SegmentFilters
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ export const SESSION_COLUMNS = [
|
|||
'region',
|
||||
];
|
||||
|
||||
export const FILTER_GROUPS = {
|
||||
export const SEGMENT_TYPES = {
|
||||
segment: 'segment',
|
||||
cohort: 'cohort',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export function isSearchOperator(operator: any) {
|
|||
return [OPERATORS.contains, OPERATORS.doesNotContain].includes(operator);
|
||||
}
|
||||
|
||||
export function filtersObjectToArray(filters: QueryFilters, options: QueryOptions = {}) {
|
||||
export function filtersObjectToArray(filters: QueryFilters, options: QueryOptions = {}): Filter[] {
|
||||
if (!filters) {
|
||||
return [];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { badRequest, unauthorized } from '@/lib/response';
|
|||
import { QueryFilters } from '@/lib/types';
|
||||
import { getWebsiteSegment } from '@/queries';
|
||||
import { z } from 'zod/v4';
|
||||
import { filtersArrayToObject } from '@/lib/params';
|
||||
|
||||
export async function parseRequest(
|
||||
request: Request,
|
||||
|
|
@ -103,36 +104,31 @@ export async function getQueryFilters(
|
|||
const segmentParams = (await getWebsiteSegment(websiteId, params.segment))
|
||||
?.parameters as Record<string, any>;
|
||||
|
||||
Object.assign(filters, segmentParams.filters);
|
||||
Object.assign(filters, filtersArrayToObject(segmentParams.filters));
|
||||
}
|
||||
|
||||
if (params.cohort) {
|
||||
const cohortParams = (await getWebsiteSegment(websiteId, params.cohort))
|
||||
?.parameters as Record<string, any>;
|
||||
|
||||
// convert dateRange to startDate and endDate
|
||||
if (cohortParams.dateRange) {
|
||||
const { startDate, endDate } = parseDateRange(cohortParams.dateRange);
|
||||
cohortParams.startDate = startDate;
|
||||
cohortParams.endDate = endDate;
|
||||
delete cohortParams.dateRange;
|
||||
}
|
||||
const { startDate, endDate } = parseDateRange(cohortParams.dateRange);
|
||||
|
||||
if (cohortParams.filters) {
|
||||
Object.assign(cohortParams, cohortParams.filters);
|
||||
delete cohortParams.filters;
|
||||
}
|
||||
const cohortFilters = cohortParams.filters.map(({ name, ...props }) => ({
|
||||
...props,
|
||||
name: `cohort_${name}`,
|
||||
}));
|
||||
|
||||
Object.assign(
|
||||
filters,
|
||||
Object.fromEntries(
|
||||
Object.entries(cohortParams || {}).map(([key, value]) =>
|
||||
key === 'startDate' || key === 'endDate'
|
||||
? [`cohort_${key}`, new Date(value)]
|
||||
: [`cohort_${key}`, value],
|
||||
),
|
||||
),
|
||||
);
|
||||
cohortFilters.push({
|
||||
name: cohortParams.action.type,
|
||||
operator: 'eq',
|
||||
value: cohortParams.action.value,
|
||||
});
|
||||
|
||||
Object.assign(filters, {
|
||||
...filtersArrayToObject(cohortFilters),
|
||||
cohort_startDate: startDate,
|
||||
cohort_endDate: endDate,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ export interface Filter {
|
|||
operator: string;
|
||||
value: string;
|
||||
type?: string;
|
||||
columns?: string;
|
||||
prefix?: string;
|
||||
}
|
||||
|
||||
export interface DateRange {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue