mirror of
https://github.com/umami-software/umami.git
synced 2026-02-04 04:37:11 +01:00
More conversions.
This commit is contained in:
parent
5999bf6256
commit
b4be6cb221
14 changed files with 240 additions and 262 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Button, Dropdown, Item, Flexbox } from '@umami/react-zen';
|
import { Button, Select, ListItem, Flexbox } from '@umami/react-zen';
|
||||||
import { useLocale, useMessages } from '@/components/hooks';
|
import { useLocale, useMessages } from '@/components/hooks';
|
||||||
import { DEFAULT_LOCALE } from '@/lib/constants';
|
import { DEFAULT_LOCALE } from '@/lib/constants';
|
||||||
import { languages } from '@/lib/lang';
|
import { languages } from '@/lib/lang';
|
||||||
|
|
@ -20,22 +20,19 @@ export function LanguageSetting() {
|
||||||
|
|
||||||
const handleReset = () => saveLocale(DEFAULT_LOCALE);
|
const handleReset = () => saveLocale(DEFAULT_LOCALE);
|
||||||
|
|
||||||
const renderValue = (value: string | number) => languages?.[value]?.label;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flexbox gap={10}>
|
<Flexbox gap={10}>
|
||||||
<Dropdown
|
<Select
|
||||||
items={options}
|
items={options}
|
||||||
value={locale}
|
value={locale}
|
||||||
renderValue={renderValue}
|
|
||||||
onChange={val => saveLocale(val as string)}
|
onChange={val => saveLocale(val as string)}
|
||||||
allowSearch={true}
|
allowSearch={true}
|
||||||
onSearch={setSearch}
|
onSearch={setSearch}
|
||||||
menuProps={{ className: styles.menu }}
|
menuProps={{ className: styles.menu }}
|
||||||
>
|
>
|
||||||
{item => <Item key={item}>{languages[item].label}</Item>}
|
{item => <ListItem key={item}>{languages[item].label}</ListItem>}
|
||||||
</Dropdown>
|
</Select>
|
||||||
<Button onClick={handleReset}>{formatMessage(labels.reset)}</Button>
|
<Button onPress={handleReset}>{formatMessage(labels.reset)}</Button>
|
||||||
</Flexbox>
|
</Flexbox>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Dropdown, Item, Button, Flexbox } from '@umami/react-zen';
|
import { Row, Select, ListItem, Button } from '@umami/react-zen';
|
||||||
import { useTimezone, useMessages } from '@/components/hooks';
|
import { useTimezone, useMessages } from '@/components/hooks';
|
||||||
import { getTimezone } from '@/lib/date';
|
import { getTimezone } from '@/lib/date';
|
||||||
import styles from './TimezoneSetting.module.css';
|
import styles from './TimezoneSetting.module.css';
|
||||||
|
|
@ -17,19 +17,22 @@ export function TimezoneSetting() {
|
||||||
const handleReset = () => saveTimezone(getTimezone());
|
const handleReset = () => saveTimezone(getTimezone());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flexbox gap={10}>
|
<Row gap="3">
|
||||||
<Dropdown
|
<Select
|
||||||
className={styles.dropdown}
|
className={styles.dropdown}
|
||||||
items={options}
|
items={options}
|
||||||
value={timezone}
|
value={timezone}
|
||||||
onChange={(value: any) => saveTimezone(value)}
|
onChange={(value: any) => saveTimezone(value)}
|
||||||
menuProps={{ className: styles.menu }}
|
|
||||||
allowSearch={true}
|
allowSearch={true}
|
||||||
onSearch={setSearch}
|
onSearch={setSearch}
|
||||||
>
|
>
|
||||||
{item => <Item key={item}>{item}</Item>}
|
{item => (
|
||||||
</Dropdown>
|
<ListItem key={item} id={item}>
|
||||||
<Button onClick={handleReset}>{formatMessage(labels.reset)}</Button>
|
{item}
|
||||||
</Flexbox>
|
</ListItem>
|
||||||
|
)}
|
||||||
|
</Select>
|
||||||
|
<Button onPress={handleReset}>{formatMessage(labels.reset)}</Button>
|
||||||
|
</Row>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { useFields, useMessages } from '@/components/hooks';
|
import { useFields, useMessages } from '@/components/hooks';
|
||||||
import { Icons } from '@/components/icons';
|
import { Icons } from '@/components/icons';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { Button, FormRow, Icon, Popup, PopupTrigger } from '@umami/react-zen';
|
import { Button, Row, Label, Icon, Popover, MenuTrigger } from '@umami/react-zen';
|
||||||
import { FieldSelectForm } from '../[reportId]/FieldSelectForm';
|
import { FieldSelectForm } from '../[reportId]/FieldSelectForm';
|
||||||
import { ParameterList } from '../[reportId]/ParameterList';
|
import { ParameterList } from '../[reportId]/ParameterList';
|
||||||
import { PopupForm } from '../[reportId]/PopupForm';
|
import { PopupForm } from '../[reportId]/PopupForm';
|
||||||
|
|
@ -26,27 +26,26 @@ export function FieldParameters() {
|
||||||
|
|
||||||
const AddButton = () => {
|
const AddButton = () => {
|
||||||
return (
|
return (
|
||||||
<PopupTrigger>
|
<MenuTrigger>
|
||||||
<Button size="sm">
|
<Button size="sm">
|
||||||
<Icon>
|
<Icon>
|
||||||
<Icons.Plus />
|
<Icons.Plus />
|
||||||
</Icon>
|
</Icon>
|
||||||
</Button>
|
</Button>
|
||||||
<Popup position="bottom" alignment="start">
|
<Popover placement="start">
|
||||||
<PopupForm>
|
<FieldSelectForm
|
||||||
<FieldSelectForm
|
fields={fieldOptions.filter(({ name }) => !fields.find(f => f.name === name))}
|
||||||
fields={fieldOptions.filter(({ name }) => !fields.find(f => f.name === name))}
|
onSelect={handleAdd}
|
||||||
onSelect={handleAdd}
|
showType={false}
|
||||||
showType={false}
|
/>
|
||||||
/>
|
</Popover>
|
||||||
</PopupForm>
|
</MenuTrigger>
|
||||||
</Popup>
|
|
||||||
</PopupTrigger>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormRow label={formatMessage(labels.fields)} action={<AddButton />}>
|
<Row>
|
||||||
|
<Label>{formatMessage(labels.fields)}</Label>
|
||||||
<ParameterList>
|
<ParameterList>
|
||||||
{fields.map(({ name }) => {
|
{fields.map(({ name }) => {
|
||||||
return (
|
return (
|
||||||
|
|
@ -56,6 +55,7 @@ export function FieldParameters() {
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</ParameterList>
|
</ParameterList>
|
||||||
</FormRow>
|
<AddButton />
|
||||||
|
</Row>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { useMessages, useFormat, useFilters, useFields } from '@/components/hooks';
|
import { useMessages, useFormat, useFilters, useFields } from '@/components/hooks';
|
||||||
import { Icons } from '@/components/icons';
|
import { Icons } from '@/components/icons';
|
||||||
import { Button, FormRow, Icon, Popup, PopupTrigger } from '@umami/react-zen';
|
import { Button, Text, Row, Label, Icon, Popover, MenuTrigger } from '@umami/react-zen';
|
||||||
import { FilterSelectForm } from '../[reportId]/FilterSelectForm';
|
import { FilterSelectForm } from '../[reportId]/FilterSelectForm';
|
||||||
import { ParameterList } from '../[reportId]/ParameterList';
|
import { ParameterList } from '../[reportId]/ParameterList';
|
||||||
import { PopupForm } from '../[reportId]/PopupForm';
|
import { PopupForm } from '../[reportId]/PopupForm';
|
||||||
|
|
@ -44,13 +44,13 @@ export function FilterParameters() {
|
||||||
|
|
||||||
const AddButton = () => {
|
const AddButton = () => {
|
||||||
return (
|
return (
|
||||||
<PopupTrigger>
|
<MenuTrigger>
|
||||||
<Button size="sm">
|
<Button size="sm">
|
||||||
<Icon>
|
<Icon>
|
||||||
<Icons.Plus />
|
<Icons.Plus />
|
||||||
</Icon>
|
</Icon>
|
||||||
</Button>
|
</Button>
|
||||||
<Popup position="bottom" alignment="start">
|
<Popover placement="bottom start">
|
||||||
<PopupForm>
|
<PopupForm>
|
||||||
<FilterSelectForm
|
<FilterSelectForm
|
||||||
websiteId={websiteId}
|
websiteId={websiteId}
|
||||||
|
|
@ -60,13 +60,17 @@ export function FilterParameters() {
|
||||||
onChange={handleAdd}
|
onChange={handleAdd}
|
||||||
/>
|
/>
|
||||||
</PopupForm>
|
</PopupForm>
|
||||||
</Popup>
|
</Popover>
|
||||||
</PopupTrigger>
|
</MenuTrigger>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormRow label={formatMessage(labels.filters)} action={<AddButton />}>
|
<>
|
||||||
|
<Row justifyContent="space-between">
|
||||||
|
<Label>{formatMessage(labels.filters)}</Label>
|
||||||
|
<AddButton />
|
||||||
|
</Row>
|
||||||
<ParameterList>
|
<ParameterList>
|
||||||
{filters.map(
|
{filters.map(
|
||||||
({ name, operator, value }: { name: string; operator: string; value: string }) => {
|
({ name, operator, value }: { name: string; operator: string; value: string }) => {
|
||||||
|
|
@ -90,7 +94,7 @@ export function FilterParameters() {
|
||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
</ParameterList>
|
</ParameterList>
|
||||||
</FormRow>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,29 +112,27 @@ const FilterParameter = ({
|
||||||
const { operatorLabels } = useFilters();
|
const { operatorLabels } = useFilters();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PopupTrigger>
|
<MenuTrigger>
|
||||||
<div className={styles.item}>
|
<div className={styles.item}>
|
||||||
<div className={styles.label}>{label}</div>
|
<div className={styles.label}>{label}</div>
|
||||||
<div className={styles.op}>{operatorLabels[operator]}</div>
|
<div className={styles.op}>{operatorLabels[operator]}</div>
|
||||||
<div className={styles.value}>{value}</div>
|
<div className={styles.value}>{value}</div>
|
||||||
</div>
|
</div>
|
||||||
<Popup className={styles.edit} alignment="start">
|
<Popover className={styles.edit} placement="right top">
|
||||||
{(close: any) => (
|
{(close: any) => (
|
||||||
<PopupForm>
|
<FieldFilterEditForm
|
||||||
<FieldFilterEditForm
|
websiteId={websiteId}
|
||||||
websiteId={websiteId}
|
name={name}
|
||||||
name={name}
|
label={label}
|
||||||
label={label}
|
type={type}
|
||||||
type={type}
|
startDate={startDate}
|
||||||
startDate={startDate}
|
endDate={endDate}
|
||||||
endDate={endDate}
|
operator={operator}
|
||||||
operator={operator}
|
defaultValue={value}
|
||||||
defaultValue={value}
|
onChange={onChange.bind(null, close)}
|
||||||
onChange={onChange.bind(null, close)}
|
/>
|
||||||
/>
|
|
||||||
</PopupForm>
|
|
||||||
)}
|
)}
|
||||||
</Popup>
|
</Popover>
|
||||||
</PopupTrigger>
|
</MenuTrigger>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { useContext, useState } from 'react';
|
import { useContext, useState } from 'react';
|
||||||
import { ReportContext } from './Report';
|
|
||||||
import styles from './ReportMenu.module.css';
|
|
||||||
import { Icon, Icons } from '@umami/react-zen';
|
import { Icon, Icons } from '@umami/react-zen';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import { ReportContext } from './Report';
|
||||||
|
import styles from './ReportMenu.module.css';
|
||||||
|
|
||||||
export function ReportMenu({ children }) {
|
export function ReportMenu({ children }) {
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
|
|
@ -16,7 +16,7 @@ export function ReportMenu({ children }) {
|
||||||
<div className={classNames(styles.menu, collapsed && styles.collapsed)}>
|
<div className={classNames(styles.menu, collapsed && styles.collapsed)}>
|
||||||
<div className={styles.button} onClick={() => setCollapsed(!collapsed)}>
|
<div className={styles.button} onClick={() => setCollapsed(!collapsed)}>
|
||||||
<Icon rotate={collapsed ? -90 : 90}>
|
<Icon rotate={collapsed ? -90 : 90}>
|
||||||
<Icons.ChevronDown />
|
<Icons.Chevron />
|
||||||
</Icon>
|
</Icon>
|
||||||
</div>
|
</div>
|
||||||
{!collapsed && children}
|
{!collapsed && children}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,15 @@
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useMessages } from '@/components/hooks';
|
import { useMessages } from '@/components/hooks';
|
||||||
import { Button, FormRow, TextField, Flexbox, Dropdown, Item } from '@umami/react-zen';
|
import {
|
||||||
|
Button,
|
||||||
|
Column,
|
||||||
|
Row,
|
||||||
|
TextField,
|
||||||
|
Label,
|
||||||
|
Select,
|
||||||
|
ListItem,
|
||||||
|
FormButtons,
|
||||||
|
} from '@umami/react-zen';
|
||||||
import styles from './FunnelStepAddForm.module.css';
|
import styles from './FunnelStepAddForm.module.css';
|
||||||
|
|
||||||
export interface FunnelStepAddFormProps {
|
export interface FunnelStepAddFormProps {
|
||||||
|
|
@ -39,40 +48,34 @@ export function FunnelStepAddForm({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderTypeValue = (value: any) => {
|
|
||||||
return items.find(item => item.value === value)?.label;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flexbox direction="column" gap={10}>
|
<Column gap="3">
|
||||||
<FormRow label={formatMessage(defaultValue ? labels.update : labels.add)}>
|
<Label>{formatMessage(defaultValue ? labels.update : labels.add)}</Label>
|
||||||
<Flexbox gap={10}>
|
<Row gap="3">
|
||||||
<Dropdown
|
<Select
|
||||||
className={styles.dropdown}
|
className={styles.dropdown}
|
||||||
items={items}
|
items={items}
|
||||||
value={type}
|
value={type}
|
||||||
renderValue={renderTypeValue}
|
onChange={(value: any) => setType(value)}
|
||||||
onChange={(value: any) => setType(value)}
|
>
|
||||||
>
|
{({ value, label }: any) => {
|
||||||
{({ value, label }) => {
|
return <ListItem key={value}>{label}</ListItem>;
|
||||||
return <Item key={value}>{label}</Item>;
|
}}
|
||||||
}}
|
</Select>
|
||||||
</Dropdown>
|
<TextField
|
||||||
<TextField
|
className={styles.input}
|
||||||
className={styles.input}
|
value={value}
|
||||||
value={value}
|
onChange={handleChange}
|
||||||
onChange={handleChange}
|
autoFocus={true}
|
||||||
autoFocus={true}
|
autoComplete="off"
|
||||||
autoComplete="off"
|
onKeyDown={handleKeyDown}
|
||||||
onKeyDown={handleKeyDown}
|
/>
|
||||||
/>
|
</Row>
|
||||||
</Flexbox>
|
<FormButtons>
|
||||||
</FormRow>
|
<Button variant="primary" onPress={handleSave} isDisabled={isDisabled}>
|
||||||
<FormRow>
|
|
||||||
<Button variant="primary" onClick={handleSave} disabled={isDisabled}>
|
|
||||||
{formatMessage(defaultValue ? labels.update : labels.add)}
|
{formatMessage(defaultValue ? labels.update : labels.add)}
|
||||||
</Button>
|
</Button>
|
||||||
</FormRow>
|
</FormButtons>
|
||||||
</Flexbox>
|
</Column>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,15 @@
|
||||||
import { useMessages } from '@/components/hooks';
|
import { useMessages } from '@/components/hooks';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Button, Dropdown, Flexbox, FormRow, Item, TextField } from '@umami/react-zen';
|
import {
|
||||||
|
Button,
|
||||||
|
Row,
|
||||||
|
Column,
|
||||||
|
Select,
|
||||||
|
Label,
|
||||||
|
ListItem,
|
||||||
|
TextField,
|
||||||
|
FormButtons,
|
||||||
|
} from '@umami/react-zen';
|
||||||
import styles from './GoalsAddForm.module.css';
|
import styles from './GoalsAddForm.module.css';
|
||||||
|
|
||||||
export function GoalsAddForm({
|
export function GoalsAddForm({
|
||||||
|
|
@ -71,44 +80,43 @@ export function GoalsAddForm({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flexbox direction="column" gap={10}>
|
<Column gap="3">
|
||||||
<FormRow label={formatMessage(defaultValue ? labels.update : labels.add)}>
|
<Label>{formatMessage(defaultValue ? labels.update : labels.add)}</Label>
|
||||||
<Flexbox gap={10}>
|
<Row gap="3">
|
||||||
<Dropdown
|
<Select
|
||||||
className={styles.dropdown}
|
className={styles.dropdown}
|
||||||
items={items}
|
items={items}
|
||||||
value={type}
|
value={type}
|
||||||
renderValue={renderTypeValue}
|
renderValue={renderTypeValue}
|
||||||
onChange={(value: any) => setType(value)}
|
onChange={(value: any) => setType(value)}
|
||||||
>
|
>
|
||||||
{({ value, label }) => {
|
{({ value, label }: any) => {
|
||||||
return <Item key={value}>{label}</Item>;
|
return <ListItem key={value}>{label}</ListItem>;
|
||||||
}}
|
}}
|
||||||
</Dropdown>
|
</Select>
|
||||||
<TextField
|
<TextField
|
||||||
className={styles.input}
|
className={styles.input}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={e => handleChange(e, setValue)}
|
onChange={e => handleChange(e, setValue)}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
/>
|
/>
|
||||||
</Flexbox>
|
</Row>
|
||||||
</FormRow>
|
|
||||||
{type === 'event-data' && (
|
{type === 'event-data' && (
|
||||||
<FormRow label={formatMessage(labels.property)}>
|
<Column>
|
||||||
<Flexbox gap={10}>
|
<Label>label={formatMessage(labels.property)}</Label>
|
||||||
<Dropdown
|
<Row gap="3">
|
||||||
|
<Select
|
||||||
className={styles.dropdown}
|
className={styles.dropdown}
|
||||||
items={operators}
|
items={operators}
|
||||||
value={operator}
|
value={operator}
|
||||||
renderValue={renderoperatorValue}
|
|
||||||
onChange={(value: any) => setOperator(value)}
|
onChange={(value: any) => setOperator(value)}
|
||||||
>
|
>
|
||||||
{({ value, label }) => {
|
{({ value, label }: any) => {
|
||||||
return <Item key={value}>{label}</Item>;
|
return <ListItem key={value}>{label}</ListItem>;
|
||||||
}}
|
}}
|
||||||
</Dropdown>
|
</Select>
|
||||||
<TextField
|
<TextField
|
||||||
className={styles.input}
|
className={styles.input}
|
||||||
value={property}
|
value={property}
|
||||||
|
|
@ -117,11 +125,12 @@ export function GoalsAddForm({
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
/>
|
/>
|
||||||
</Flexbox>
|
</Row>
|
||||||
</FormRow>
|
</Column>
|
||||||
)}
|
)}
|
||||||
<FormRow label={formatMessage(labels.goal)}>
|
<Column>
|
||||||
<Flexbox gap={10}>
|
<Label>{formatMessage(labels.goal)}</Label>
|
||||||
|
<Row gap="3">
|
||||||
<TextField
|
<TextField
|
||||||
className={styles.input}
|
className={styles.input}
|
||||||
value={goal?.toString()}
|
value={goal?.toString()}
|
||||||
|
|
@ -129,13 +138,13 @@ export function GoalsAddForm({
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
/>
|
/>
|
||||||
</Flexbox>
|
</Row>
|
||||||
</FormRow>
|
</Column>
|
||||||
<FormRow>
|
<FormButtons>
|
||||||
<Button variant="primary" onClick={handleSave} disabled={isDisabled}>
|
<Button variant="primary" onPress={handleSave} isDisabled={isDisabled}>
|
||||||
{formatMessage(defaultValue ? labels.update : labels.add)}
|
{formatMessage(defaultValue ? labels.update : labels.add)}
|
||||||
</Button>
|
</Button>
|
||||||
</FormRow>
|
</FormButtons>
|
||||||
</Flexbox>
|
</Column>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,18 +4,17 @@ import { formatNumber } from '@/lib/format';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Flexbox,
|
|
||||||
Form,
|
Form,
|
||||||
FormButtons,
|
FormButtons,
|
||||||
FormRow,
|
FormField,
|
||||||
Icon,
|
Icon,
|
||||||
Popup,
|
Popover,
|
||||||
PopupTrigger,
|
MenuTrigger,
|
||||||
SubmitButton,
|
FormSubmitButton,
|
||||||
|
Column,
|
||||||
} from '@umami/react-zen';
|
} from '@umami/react-zen';
|
||||||
import { BaseParameters } from '../[reportId]/BaseParameters';
|
import { BaseParameters } from '../[reportId]/BaseParameters';
|
||||||
import { ParameterList } from '../[reportId]/ParameterList';
|
import { ParameterList } from '../[reportId]/ParameterList';
|
||||||
import { PopupForm } from '../[reportId]/PopupForm';
|
|
||||||
import { ReportContext } from '../[reportId]/Report';
|
import { ReportContext } from '../[reportId]/Report';
|
||||||
import { GoalsAddForm } from './GoalsAddForm';
|
import { GoalsAddForm } from './GoalsAddForm';
|
||||||
import styles from './GoalsParameters.module.css';
|
import styles from './GoalsParameters.module.css';
|
||||||
|
|
@ -60,25 +59,24 @@ export function GoalsParameters() {
|
||||||
|
|
||||||
const AddGoalsButton = () => {
|
const AddGoalsButton = () => {
|
||||||
return (
|
return (
|
||||||
<PopupTrigger>
|
<MenuTrigger>
|
||||||
<Button>
|
<Button>
|
||||||
<Icon>
|
<Icon>
|
||||||
<Icons.Plus />
|
<Icons.Plus />
|
||||||
</Icon>
|
</Icon>
|
||||||
</Button>
|
</Button>
|
||||||
<Popup alignment="start">
|
<Popover placement="start">
|
||||||
<PopupForm>
|
<GoalsAddForm onChange={handleAddGoals} />
|
||||||
<GoalsAddForm onChange={handleAddGoals} />
|
</Popover>
|
||||||
</PopupForm>
|
</MenuTrigger>
|
||||||
</Popup>
|
|
||||||
</PopupTrigger>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form values={parameters} onSubmit={handleSubmit} preventSubmit={true}>
|
<Form values={parameters} onSubmit={handleSubmit} preventSubmit={true}>
|
||||||
<BaseParameters allowWebsiteSelect={!id} />
|
<BaseParameters allowWebsiteSelect={!id} />
|
||||||
<FormRow label={formatMessage(labels.goals)} action={<AddGoalsButton />}>
|
<AddGoalsButton />
|
||||||
|
<FormField label={formatMessage(labels.goals)}>
|
||||||
<ParameterList>
|
<ParameterList>
|
||||||
{goals.map(
|
{goals.map(
|
||||||
(
|
(
|
||||||
|
|
@ -92,12 +90,12 @@ export function GoalsParameters() {
|
||||||
index: number,
|
index: number,
|
||||||
) => {
|
) => {
|
||||||
return (
|
return (
|
||||||
<PopupTrigger key={index}>
|
<MenuTrigger key={index}>
|
||||||
<ParameterList.Item
|
<ParameterList.Item
|
||||||
icon={goal.type === 'url' ? <Icons.Eye /> : <Icons.Bolt />}
|
icon={goal.type === 'url' ? <Icons.Eye /> : <Icons.Bolt />}
|
||||||
onRemove={() => handleRemoveGoals(index)}
|
onRemove={() => handleRemoveGoals(index)}
|
||||||
>
|
>
|
||||||
<Flexbox direction="column" gap={5}>
|
<Column>
|
||||||
<div className={styles.value}>{goal.value}</div>
|
<div className={styles.value}>{goal.value}</div>
|
||||||
{goal.type === 'event-data' && (
|
{goal.type === 'event-data' && (
|
||||||
<div className={styles.eventData}>
|
<div className={styles.eventData}>
|
||||||
|
|
@ -107,32 +105,28 @@ export function GoalsParameters() {
|
||||||
<div className={styles.goal}>
|
<div className={styles.goal}>
|
||||||
{formatMessage(labels.goal)}: {formatNumber(goal.goal)}
|
{formatMessage(labels.goal)}: {formatNumber(goal.goal)}
|
||||||
</div>
|
</div>
|
||||||
</Flexbox>
|
</Column>
|
||||||
</ParameterList.Item>
|
</ParameterList.Item>
|
||||||
<Popup alignment="start">
|
<Popover placement="start">
|
||||||
{(close: () => void) => (
|
<GoalsAddForm
|
||||||
<PopupForm>
|
type={goal.type}
|
||||||
<GoalsAddForm
|
value={goal.value}
|
||||||
type={goal.type}
|
goal={goal.goal}
|
||||||
value={goal.value}
|
operator={goal.operator}
|
||||||
goal={goal.goal}
|
property={goal.property}
|
||||||
operator={goal.operator}
|
onChange={handleUpdateGoals.bind(null, () => {}, index)}
|
||||||
property={goal.property}
|
/>
|
||||||
onChange={handleUpdateGoals.bind(null, close, index)}
|
</Popover>
|
||||||
/>
|
</MenuTrigger>
|
||||||
</PopupForm>
|
|
||||||
)}
|
|
||||||
</Popup>
|
|
||||||
</PopupTrigger>
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
</ParameterList>
|
</ParameterList>
|
||||||
</FormRow>
|
</FormField>
|
||||||
<FormButtons>
|
<FormButtons>
|
||||||
<SubmitButton variant="primary" disabled={queryDisabled} isLoading={isRunning}>
|
<FormSubmitButton variant="primary" isDisabled={queryDisabled} isLoading={isRunning}>
|
||||||
{formatMessage(labels.runQuery)}
|
{formatMessage(labels.runQuery)}
|
||||||
</SubmitButton>
|
</FormSubmitButton>
|
||||||
</FormButtons>
|
</FormButtons>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { useMessages } from '@/components/hooks';
|
import { useMessages } from '@/components/hooks';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { Form, FormButtons, SubmitButton } from '@umami/react-zen';
|
import { Form, FormButtons, FormSubmitButton } from '@umami/react-zen';
|
||||||
import { BaseParameters } from '../[reportId]/BaseParameters';
|
import { BaseParameters } from '../[reportId]/BaseParameters';
|
||||||
import { ReportContext } from '../[reportId]/Report';
|
import { ReportContext } from '../[reportId]/Report';
|
||||||
import { FieldParameters } from '../[reportId]/FieldParameters';
|
import { FieldParameters } from '../[reportId]/FieldParameters';
|
||||||
|
|
@ -25,9 +25,9 @@ export function InsightsParameters() {
|
||||||
{parametersSelected && <FieldParameters />}
|
{parametersSelected && <FieldParameters />}
|
||||||
{parametersSelected && <FilterParameters />}
|
{parametersSelected && <FilterParameters />}
|
||||||
<FormButtons>
|
<FormButtons>
|
||||||
<SubmitButton variant="primary" disabled={!queryEnabled} isLoading={isRunning}>
|
<FormSubmitButton variant="primary" isDisabled={!queryEnabled} isLoading={isRunning}>
|
||||||
{formatMessage(labels.runQuery)}
|
{formatMessage(labels.runQuery)}
|
||||||
</SubmitButton>
|
</FormSubmitButton>
|
||||||
</FormButtons>
|
</FormButtons>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { useContext, useEffect, useState } from 'react';
|
import { useContext, useEffect, useState } from 'react';
|
||||||
import { GridTable, GridColumn } from '@umami/react-zen';
|
import { DataTable, DataColumn } from '@umami/react-zen';
|
||||||
import { useFormat, useMessages } from '@/components/hooks';
|
import { useFormat, useMessages } from '@/components/hooks';
|
||||||
import { ReportContext } from '../[reportId]/Report';
|
import { ReportContext } from '../[reportId]/Report';
|
||||||
import { EmptyPlaceholder } from '@/components/common/EmptyPlaceholder';
|
import { EmptyPlaceholder } from '@/components/common/EmptyPlaceholder';
|
||||||
|
|
@ -24,50 +24,35 @@ export function InsightsTable() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GridTable data={report?.data || []}>
|
<DataTable data={report?.data || []}>
|
||||||
{fields.map(({ name, label }) => {
|
{fields.map(({ name, label }) => {
|
||||||
return (
|
return (
|
||||||
<GridColumn key={name} name={name} label={label}>
|
<DataColumn key={name} id={name} label={label}>
|
||||||
{row => formatValue(row[name], name)}
|
{row => formatValue(row[name], name)}
|
||||||
</GridColumn>
|
</DataColumn>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
<GridColumn name="views" label={formatMessage(labels.views)} width="100px" alignment="end">
|
<DataColumn id="views" label={formatMessage(labels.views)} align="end">
|
||||||
{row => row?.views?.toLocaleString()}
|
{(row: any) => row?.views?.toLocaleString()}
|
||||||
</GridColumn>
|
</DataColumn>
|
||||||
<GridColumn name="visits" label={formatMessage(labels.visits)} width="100px" alignment="end">
|
<DataColumn id="visits" label={formatMessage(labels.visits)} align="end">
|
||||||
{row => row?.visits?.toLocaleString()}
|
{(row: any) => row?.visits?.toLocaleString()}
|
||||||
</GridColumn>
|
</DataColumn>
|
||||||
<GridColumn
|
<DataColumn id="visitors" label={formatMessage(labels.visitors)} align="end">
|
||||||
name="visitors"
|
{(row: any) => row?.visitors?.toLocaleString()}
|
||||||
label={formatMessage(labels.visitors)}
|
</DataColumn>
|
||||||
width="100px"
|
<DataColumn id="bounceRate" label={formatMessage(labels.bounceRate)} align="end">
|
||||||
alignment="end"
|
{(row: any) => {
|
||||||
>
|
|
||||||
{row => row?.visitors?.toLocaleString()}
|
|
||||||
</GridColumn>
|
|
||||||
<GridColumn
|
|
||||||
name="bounceRate"
|
|
||||||
label={formatMessage(labels.bounceRate)}
|
|
||||||
width="100px"
|
|
||||||
alignment="end"
|
|
||||||
>
|
|
||||||
{row => {
|
|
||||||
const n = (Math.min(row?.visits, row?.bounces) / row?.visits) * 100;
|
const n = (Math.min(row?.visits, row?.bounces) / row?.visits) * 100;
|
||||||
return Math.round(+n) + '%';
|
return Math.round(+n) + '%';
|
||||||
}}
|
}}
|
||||||
</GridColumn>
|
</DataColumn>
|
||||||
<GridColumn
|
<DataColumn id="visitDuration" label={formatMessage(labels.visitDuration)} align="end">
|
||||||
name="visitDuration"
|
{(row: any) => {
|
||||||
label={formatMessage(labels.visitDuration)}
|
|
||||||
width="100px"
|
|
||||||
alignment="end"
|
|
||||||
>
|
|
||||||
{row => {
|
|
||||||
const n = row?.totaltime / row?.visits;
|
const n = row?.totaltime / row?.visits;
|
||||||
return `${+n < 0 ? '-' : ''}${formatShortTime(Math.abs(~~n), ['m', 's'], ' ')}`;
|
return `${+n < 0 ? '-' : ''}${formatShortTime(Math.abs(~~n), ['m', 's'], ' ')}`;
|
||||||
}}
|
}}
|
||||||
</GridColumn>
|
</DataColumn>
|
||||||
</GridTable>
|
</DataTable>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { useMessages } from '@/components/hooks';
|
import { useMessages } from '@/components/hooks';
|
||||||
import {
|
import {
|
||||||
Dropdown,
|
Select,
|
||||||
Form,
|
Form,
|
||||||
FormButtons,
|
FormButtons,
|
||||||
FormInput,
|
FormField,
|
||||||
FormRow,
|
ListItem,
|
||||||
Item,
|
FormSubmitButton,
|
||||||
SubmitButton,
|
|
||||||
TextField,
|
TextField,
|
||||||
} from '@umami/react-zen';
|
} from '@umami/react-zen';
|
||||||
import { ReportContext } from '../[reportId]/Report';
|
import { ReportContext } from '../[reportId]/Report';
|
||||||
|
|
@ -33,28 +32,29 @@ export function JourneyParameters() {
|
||||||
return (
|
return (
|
||||||
<Form values={parameters} onSubmit={handleSubmit} preventSubmit={true}>
|
<Form values={parameters} onSubmit={handleSubmit} preventSubmit={true}>
|
||||||
<BaseParameters showDateSelect={true} allowWebsiteSelect={!id} />
|
<BaseParameters showDateSelect={true} allowWebsiteSelect={!id} />
|
||||||
<FormRow label={formatMessage(labels.steps)}>
|
<FormField
|
||||||
<FormInput
|
label={formatMessage(labels.steps)}
|
||||||
name="steps"
|
name="steps"
|
||||||
rules={{ required: formatMessage(labels.required), pattern: /[0-9]+/, min: 3, max: 7 }}
|
rules={{ required: formatMessage(labels.required), pattern: /[0-9]+/, min: 3, max: 7 }}
|
||||||
>
|
>
|
||||||
<Dropdown items={[3, 4, 5, 6, 7]}>{item => <Item key={item}>{item}</Item>}</Dropdown>
|
<Select items={[3, 4, 5, 6, 7]}>
|
||||||
</FormInput>
|
{(item: any) => (
|
||||||
</FormRow>
|
<ListItem key={item.toString()} id={item.toString()}>
|
||||||
<FormRow label={formatMessage(labels.startStep)}>
|
{item}
|
||||||
<FormInput name="startStep">
|
</ListItem>
|
||||||
<TextField autoComplete="off" />
|
)}
|
||||||
</FormInput>
|
</Select>
|
||||||
</FormRow>
|
</FormField>
|
||||||
<FormRow label={formatMessage(labels.endStep)}>
|
<FormField label={formatMessage(labels.startStep)} name="startStep">
|
||||||
<FormInput name="endStep">
|
<TextField autoComplete="off" />
|
||||||
<TextField autoComplete="off" />
|
</FormField>
|
||||||
</FormInput>
|
<FormField label={formatMessage(labels.endStep)} name="endStep">
|
||||||
</FormRow>
|
<TextField autoComplete="off" />
|
||||||
|
</FormField>
|
||||||
<FormButtons>
|
<FormButtons>
|
||||||
<SubmitButton variant="primary" disabled={queryDisabled} isLoading={isRunning}>
|
<FormSubmitButton variant="primary" isDisabled={queryDisabled} isLoading={isRunning}>
|
||||||
{formatMessage(labels.runQuery)}
|
{formatMessage(labels.runQuery)}
|
||||||
</SubmitButton>
|
</FormSubmitButton>
|
||||||
</FormButtons>
|
</FormButtons>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ export function RetentionParameters() {
|
||||||
|
|
||||||
const { id, parameters } = report || {};
|
const { id, parameters } = report || {};
|
||||||
const { websiteId, dateRange } = parameters || {};
|
const { websiteId, dateRange } = parameters || {};
|
||||||
const { startDate } = dateRange || {};
|
|
||||||
const queryDisabled = !websiteId || !dateRange;
|
const queryDisabled = !websiteId || !dateRange;
|
||||||
|
|
||||||
const handleSubmit = (data: any, e: any) => {
|
const handleSubmit = (data: any, e: any) => {
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,7 @@
|
||||||
import { useMessages } from '@/components/hooks';
|
import { useMessages } from '@/components/hooks';
|
||||||
import { useRevenueValues } from '@/components/hooks/queries/useRevenueValues';
|
import { useRevenueValues } from '@/components/hooks/queries/useRevenueValues';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import {
|
import { Select, Form, FormButtons, FormField, ListItem, FormSubmitButton } from '@umami/react-zen';
|
||||||
Dropdown,
|
|
||||||
Form,
|
|
||||||
FormButtons,
|
|
||||||
FormInput,
|
|
||||||
FormRow,
|
|
||||||
Item,
|
|
||||||
SubmitButton,
|
|
||||||
} from '@umami/react-zen';
|
|
||||||
import { BaseParameters } from '../[reportId]/BaseParameters';
|
import { BaseParameters } from '../[reportId]/BaseParameters';
|
||||||
import { ReportContext } from '../[reportId]/Report';
|
import { ReportContext } from '../[reportId]/Report';
|
||||||
|
|
||||||
|
|
@ -35,17 +27,20 @@ export function RevenueParameters() {
|
||||||
return (
|
return (
|
||||||
<Form values={parameters} onSubmit={handleSubmit} preventSubmit={true}>
|
<Form values={parameters} onSubmit={handleSubmit} preventSubmit={true}>
|
||||||
<BaseParameters showDateSelect={true} allowWebsiteSelect={!id} />
|
<BaseParameters showDateSelect={true} allowWebsiteSelect={!id} />
|
||||||
<FormRow label={formatMessage(labels.currency)}>
|
|
||||||
<FormInput name="currency" rules={{ required: formatMessage(labels.required) }}>
|
<FormField
|
||||||
<Dropdown items={values.map(item => item.currency)}>
|
label={formatMessage(labels.currency)}
|
||||||
{item => <Item key={item}>{item}</Item>}
|
name="currency"
|
||||||
</Dropdown>
|
rules={{ required: formatMessage(labels.required) }}
|
||||||
</FormInput>
|
>
|
||||||
</FormRow>
|
<Select items={values.map(item => item.currency)}>
|
||||||
|
{item => <ListItem key={item}>{item}</ListItem>}
|
||||||
|
</Select>
|
||||||
|
</FormField>
|
||||||
<FormButtons>
|
<FormButtons>
|
||||||
<SubmitButton variant="primary" disabled={!queryEnabled} isLoading={isRunning}>
|
<FormSubmitButton variant="primary" isDisabled={!queryEnabled} isLoading={isRunning}>
|
||||||
{formatMessage(labels.runQuery)}
|
{formatMessage(labels.runQuery)}
|
||||||
</SubmitButton>
|
</FormSubmitButton>
|
||||||
</FormButtons>
|
</FormButtons>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import { useState, Key } from 'react';
|
import { useState, Key } from 'react';
|
||||||
import { Dropdown, Item } from '@umami/react-zen';
|
import { Select, ListItem } from '@umami/react-zen';
|
||||||
import { useWebsite, useWebsites, useMessages } from '@/components/hooks';
|
import { useWebsite, useWebsites, useMessages } from '@/components/hooks';
|
||||||
import { Empty } from '@/components/common/Empty';
|
import { Empty } from '@/components/common/Empty';
|
||||||
import styles from './WebsiteSelect.module.css';
|
|
||||||
|
|
||||||
export function WebsiteSelect({
|
export function WebsiteSelect({
|
||||||
websiteId,
|
websiteId,
|
||||||
|
|
@ -21,10 +20,6 @@ export function WebsiteSelect({
|
||||||
|
|
||||||
const queryResult = useWebsites({ teamId }, { search, pageSize: 5 });
|
const queryResult = useWebsites({ teamId }, { search, pageSize: 5 });
|
||||||
|
|
||||||
const renderValue = () => {
|
|
||||||
return website?.name;
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderEmpty = () => {
|
const renderEmpty = () => {
|
||||||
return <Empty message={formatMessage(messages.noResultsFound)} />;
|
return <Empty message={formatMessage(messages.noResultsFound)} />;
|
||||||
};
|
};
|
||||||
|
|
@ -39,20 +34,16 @@ export function WebsiteSelect({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Select
|
||||||
menuProps={{ className: styles.dropdown }}
|
|
||||||
items={queryResult?.result?.data as any[]}
|
items={queryResult?.result?.data as any[]}
|
||||||
value={selectedId as string}
|
value={selectedId as string}
|
||||||
renderValue={renderValue}
|
|
||||||
renderEmpty={renderEmpty}
|
|
||||||
onChange={handleSelect}
|
onChange={handleSelect}
|
||||||
alignment="end"
|
|
||||||
placeholder={formatMessage(labels.selectWebsite)}
|
placeholder={formatMessage(labels.selectWebsite)}
|
||||||
allowSearch={true}
|
allowSearch={true}
|
||||||
onSearch={handleSearch}
|
onSearch={handleSearch}
|
||||||
isLoading={queryResult.query.isLoading}
|
isLoading={queryResult.query.isLoading}
|
||||||
>
|
>
|
||||||
{({ id, name }) => <Item key={id}>{name}</Item>}
|
{({ id, name }: any) => <ListItem key={id}>{name}</ListItem>}
|
||||||
</Dropdown>
|
</Select>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue