mirror of
https://github.com/umami-software/umami.git
synced 2026-02-13 00:55:37 +01:00
Typescript refactor.
This commit is contained in:
parent
b578162cb6
commit
7c42f0da82
173 changed files with 968 additions and 549 deletions
|
|
@ -3,13 +3,21 @@ import ConfirmDeleteForm from 'components/common/ConfirmDeleteForm';
|
|||
import { useApi, useMessages } from 'components/hooks';
|
||||
import { setValue } from 'store/cache';
|
||||
|
||||
export function ReportDeleteButton({ reportId, reportName, onDelete }) {
|
||||
export function ReportDeleteButton({
|
||||
reportId,
|
||||
reportName,
|
||||
onDelete,
|
||||
}: {
|
||||
reportId: string;
|
||||
reportName: string;
|
||||
onDelete?: () => void;
|
||||
}) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { del, useMutation } = useApi();
|
||||
const { mutate } = useMutation(reportId => del(`/reports/${reportId}`));
|
||||
|
||||
const handleConfirm = close => {
|
||||
mutate(reportId, {
|
||||
const handleConfirm = (close: () => void) => {
|
||||
mutate(reportId as any, {
|
||||
onSuccess: () => {
|
||||
setValue('reports', Date.now());
|
||||
onDelete?.();
|
||||
|
|
@ -1,18 +1,10 @@
|
|||
'use client';
|
||||
import { useApi } from 'components/hooks';
|
||||
import { useReports } from 'components/hooks';
|
||||
import ReportsTable from './ReportsTable';
|
||||
import useFilterQuery from 'components/hooks/useFilterQuery';
|
||||
import DataTable from 'components/common/DataTable';
|
||||
import useCache from 'store/cache';
|
||||
|
||||
export default function ReportsDataTable({ websiteId }: { websiteId?: string }) {
|
||||
const { get } = useApi();
|
||||
const modified = useCache(state => (state as any)?.reports);
|
||||
const queryResult = useFilterQuery({
|
||||
queryKey: ['reports', { websiteId, modified }],
|
||||
queryFn: (params: any) =>
|
||||
get(websiteId ? `/websites/${websiteId}/reports` : `/reports`, params),
|
||||
});
|
||||
const queryResult = useReports(websiteId);
|
||||
|
||||
return (
|
||||
<DataTable queryResult={queryResult}>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import useUser from 'components/hooks/useUser';
|
|||
import { REPORT_TYPES } from 'lib/constants';
|
||||
import ReportDeleteButton from './ReportDeleteButton';
|
||||
|
||||
export function ReportsTable({ data = [], showDomain }) {
|
||||
export function ReportsTable({ data = [], showDomain }: { data: any[]; showDomain?: boolean }) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { user } = useUser();
|
||||
const breakpoint = useBreakpoint();
|
||||
|
|
@ -6,12 +6,19 @@ import WebsiteSelect from 'components/input/WebsiteSelect';
|
|||
import { useMessages } from 'components/hooks';
|
||||
import { ReportContext } from './Report';
|
||||
|
||||
export interface BaseParametersProps {
|
||||
showWebsiteSelect?: boolean;
|
||||
allowWebsiteSelect?: boolean;
|
||||
showDateSelect?: boolean;
|
||||
allowDateSelect?: boolean;
|
||||
}
|
||||
|
||||
export function BaseParameters({
|
||||
showWebsiteSelect = true,
|
||||
allowWebsiteSelect = true,
|
||||
showDateSelect = true,
|
||||
allowDateSelect = true,
|
||||
}) {
|
||||
}: BaseParametersProps) {
|
||||
const { report, updateReport } = useContext(ReportContext);
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
||||
|
|
@ -19,11 +26,11 @@ export function BaseParameters({
|
|||
const { websiteId, dateRange } = parameters || {};
|
||||
const { value, startDate, endDate } = dateRange || {};
|
||||
|
||||
const handleWebsiteSelect = websiteId => {
|
||||
const handleWebsiteSelect = (websiteId: string) => {
|
||||
updateReport({ websiteId, parameters: { websiteId } });
|
||||
};
|
||||
|
||||
const handleDateChange = value => {
|
||||
const handleDateChange = (value: string) => {
|
||||
updateReport({ parameters: { dateRange: { ...parseDateRange(value) } } });
|
||||
};
|
||||
|
||||
|
|
@ -7,10 +7,20 @@ import FieldAggregateForm from './FieldAggregateForm';
|
|||
import FieldFilterForm from './FieldFilterForm';
|
||||
import styles from './FieldAddForm.module.css';
|
||||
|
||||
export function FieldAddForm({ fields = [], group, onAdd, onClose }) {
|
||||
const [selected, setSelected] = useState();
|
||||
export function FieldAddForm({
|
||||
fields = [],
|
||||
group,
|
||||
onAdd,
|
||||
onClose,
|
||||
}: {
|
||||
fields?: any[];
|
||||
group: string;
|
||||
onAdd: (group: string, value: string) => void;
|
||||
onClose: () => void;
|
||||
}) {
|
||||
const [selected, setSelected] = useState<{ name: string; type: string; value: string }>();
|
||||
|
||||
const handleSelect = value => {
|
||||
const handleSelect = (value: any) => {
|
||||
const { type } = value;
|
||||
|
||||
if (group === REPORT_PARAMETERS.groups || type === 'array' || type === 'boolean') {
|
||||
|
|
@ -22,7 +32,7 @@ export function FieldAddForm({ fields = [], group, onAdd, onClose }) {
|
|||
setSelected(value);
|
||||
};
|
||||
|
||||
const handleSave = value => {
|
||||
const handleSave = (value: any) => {
|
||||
onAdd(group, value);
|
||||
onClose();
|
||||
};
|
||||
|
|
@ -1,7 +1,15 @@
|
|||
import { Form, FormRow, Menu, Item } from 'react-basics';
|
||||
import { useMessages } from 'components/hooks';
|
||||
|
||||
export default function FieldAggregateForm({ name, type, onSelect }) {
|
||||
export default function FieldAggregateForm({
|
||||
name,
|
||||
type,
|
||||
onSelect,
|
||||
}: {
|
||||
name: string;
|
||||
type: string;
|
||||
onSelect: (key: any) => void;
|
||||
}) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
||||
const options = {
|
||||
|
|
@ -27,7 +35,7 @@ export default function FieldAggregateForm({ name, type, onSelect }) {
|
|||
|
||||
const items = options[type];
|
||||
|
||||
const handleSelect = value => {
|
||||
const handleSelect = (value: any) => {
|
||||
onSelect({ name, type, value });
|
||||
};
|
||||
|
||||
|
|
@ -3,6 +3,15 @@ import { Form, FormRow, Item, Flexbox, Dropdown, Button } from 'react-basics';
|
|||
import { useMessages, useFilters, useFormat, useLocale } from 'components/hooks';
|
||||
import styles from './FieldFilterForm.module.css';
|
||||
|
||||
export interface FieldFilterFormProps {
|
||||
name: string;
|
||||
label?: string;
|
||||
type: string;
|
||||
values?: any[];
|
||||
onSelect?: (key: any) => void;
|
||||
allowFilterSelect?: boolean;
|
||||
}
|
||||
|
||||
export default function FieldFilterForm({
|
||||
name,
|
||||
label,
|
||||
|
|
@ -10,7 +19,7 @@ export default function FieldFilterForm({
|
|||
values,
|
||||
onSelect,
|
||||
allowFilterSelect = true,
|
||||
}) {
|
||||
}: FieldFilterFormProps) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const [filter, setFilter] = useState('eq');
|
||||
const [value, setValue] = useState();
|
||||
|
|
@ -21,7 +30,7 @@ export default function FieldFilterForm({
|
|||
|
||||
const formattedValues = useMemo(() => {
|
||||
const formatted = {};
|
||||
const format = val => {
|
||||
const format = (val: string) => {
|
||||
formatted[val] = formatValue(val, name);
|
||||
return formatted[val];
|
||||
};
|
||||
|
|
@ -56,7 +65,7 @@ export default function FieldFilterForm({
|
|||
items={filters}
|
||||
value={filter}
|
||||
renderValue={renderFilterValue}
|
||||
onChange={setFilter}
|
||||
onChange={(key: any) => setFilter(key)}
|
||||
>
|
||||
{({ value, label }) => {
|
||||
return <Item key={value}>{label}</Item>;
|
||||
|
|
@ -69,12 +78,12 @@ export default function FieldFilterForm({
|
|||
items={values}
|
||||
value={value}
|
||||
renderValue={renderValue}
|
||||
onChange={setValue}
|
||||
onChange={(key: any) => setValue(key)}
|
||||
style={{
|
||||
minWidth: '250px',
|
||||
}}
|
||||
>
|
||||
{value => {
|
||||
{(value: string) => {
|
||||
return <Item key={value}>{formattedValues[value]}</Item>;
|
||||
}}
|
||||
</Dropdown>
|
||||
|
|
@ -1,15 +1,26 @@
|
|||
import { Menu, Item, Form, FormRow } from 'react-basics';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import styles from './FieldSelectForm.module.css';
|
||||
import { Key } from 'react';
|
||||
|
||||
export default function FieldSelectForm({ items, onSelect, showType = true }) {
|
||||
export interface FieldSelectFormProps {
|
||||
fields?: any[];
|
||||
onSelect?: (key: any) => void;
|
||||
showType?: boolean;
|
||||
}
|
||||
|
||||
export default function FieldSelectForm({
|
||||
fields = [],
|
||||
onSelect,
|
||||
showType = true,
|
||||
}: FieldSelectFormProps) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
||||
return (
|
||||
<Form>
|
||||
<FormRow label={formatMessage(labels.fields)}>
|
||||
<Menu className={styles.menu} onSelect={key => onSelect(items[key])}>
|
||||
{items.map(({ name, label, type }, index) => {
|
||||
<Menu className={styles.menu} onSelect={key => onSelect(fields[key as any])}>
|
||||
{fields.map(({ name, label, type }: any, index: Key) => {
|
||||
return (
|
||||
<Item key={index} className={styles.item}>
|
||||
<div>{label || name}</div>
|
||||
|
|
@ -5,7 +5,7 @@ import FieldSelectForm from './FieldSelectForm';
|
|||
import FieldFilterForm from './FieldFilterForm';
|
||||
import { useApi } from 'components/hooks';
|
||||
|
||||
function useValues(websiteId, type) {
|
||||
function useValues(websiteId: string, type: string) {
|
||||
const now = Date.now();
|
||||
const { get, useQuery } = useApi();
|
||||
const { data, error, isLoading } = useQuery({
|
||||
|
|
@ -22,12 +22,24 @@ function useValues(websiteId, type) {
|
|||
return { data, error, isLoading };
|
||||
}
|
||||
|
||||
export default function FilterSelectForm({ websiteId, items, onSelect, allowFilterSelect }) {
|
||||
const [field, setField] = useState();
|
||||
export interface FilterSelectFormProps {
|
||||
websiteId: string;
|
||||
items: any[];
|
||||
onSelect?: (key: any) => void;
|
||||
allowFilterSelect?: boolean;
|
||||
}
|
||||
|
||||
export default function FilterSelectForm({
|
||||
websiteId,
|
||||
items,
|
||||
onSelect,
|
||||
allowFilterSelect,
|
||||
}: FilterSelectFormProps) {
|
||||
const [field, setField] = useState<{ name: string; label: string; type: string }>();
|
||||
const { data, isLoading } = useValues(websiteId, field?.name);
|
||||
|
||||
if (!field) {
|
||||
return <FieldSelectForm items={items} onSelect={setField} showType={false} />;
|
||||
return <FieldSelectForm fields={items} onSelect={setField} showType={false} />;
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
|
|
@ -1,10 +1,17 @@
|
|||
import { ReactNode } from 'react';
|
||||
import { Icon, TooltipPopup } from 'react-basics';
|
||||
import Icons from 'components/icons';
|
||||
import Empty from 'components/common/Empty';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import styles from './ParameterList.module.css';
|
||||
|
||||
export function ParameterList({ items = [], children, onRemove }) {
|
||||
export interface ParameterListProps {
|
||||
items: any[];
|
||||
children?: ReactNode | ((item: any) => ReactNode);
|
||||
onRemove: (index: number, e: any) => void;
|
||||
}
|
||||
|
||||
export function ParameterList({ items = [], children, onRemove }: ParameterListProps) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
||||
return (
|
||||
|
|
@ -1,7 +1,16 @@
|
|||
import { CSSProperties, ReactNode } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import styles from './PopupForm.module.css';
|
||||
|
||||
export function PopupForm({ className, style, children }) {
|
||||
export function PopupForm({
|
||||
className,
|
||||
style,
|
||||
children,
|
||||
}: {
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={classNames(styles.form, className)}
|
||||
|
|
@ -1,11 +1,19 @@
|
|||
'use client';
|
||||
import { createContext } from 'react';
|
||||
import { createContext, ReactNode } from 'react';
|
||||
import { useReport } from 'components/hooks';
|
||||
import styles from './Report.module.css';
|
||||
import classNames from 'classnames';
|
||||
|
||||
export const ReportContext = createContext(null);
|
||||
|
||||
export function Report({ reportId, defaultParameters, children, ...props }) {
|
||||
export interface ReportProps {
|
||||
reportId: string;
|
||||
defaultParameters: { [key: string]: any };
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function Report({ reportId, defaultParameters, children, className }: ReportProps) {
|
||||
const report = useReport(reportId, defaultParameters);
|
||||
|
||||
if (!report) {
|
||||
|
|
@ -14,9 +22,7 @@ export function Report({ reportId, defaultParameters, children, ...props }) {
|
|||
|
||||
return (
|
||||
<ReportContext.Provider value={{ ...report }}>
|
||||
<div {...props} className={styles.container}>
|
||||
{children}
|
||||
</div>
|
||||
<div className={classNames(styles.container, className)}>{children}</div>
|
||||
</ReportContext.Provider>
|
||||
);
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ const reports = {
|
|||
retention: RetentionReport,
|
||||
};
|
||||
|
||||
export default function ReportDetails({ reportId }) {
|
||||
export default function ReportDetails({ reportId }: { reportId: string }) {
|
||||
const { get, useQuery } = useApi();
|
||||
const { data: report } = useQuery({
|
||||
queryKey: ['reports', reportId],
|
||||
|
|
@ -12,8 +12,10 @@ export function ReportHeader({ icon }) {
|
|||
const { showToast } = useToasts();
|
||||
const { post, useMutation } = useApi();
|
||||
const router = useRouter();
|
||||
const { mutate: create, isLoading: isCreating } = useMutation(data => post(`/reports`, data));
|
||||
const { mutate: update, isLoading: isUpdating } = useMutation(data =>
|
||||
const { mutate: create, isLoading: isCreating } = useMutation((data: any) =>
|
||||
post(`/reports`, data),
|
||||
);
|
||||
const { mutate: update, isLoading: isUpdating } = useMutation((data: any) =>
|
||||
post(`/reports/${data.id}`, data),
|
||||
);
|
||||
|
||||
|
|
@ -26,7 +28,7 @@ export function ReportHeader({ icon }) {
|
|||
create(report, {
|
||||
onSuccess: async ({ id }) => {
|
||||
showToast({ message: formatMessage(messages.saved), variant: 'success' });
|
||||
router.push(`/reports/${id}`, null, { shallow: true });
|
||||
router.push(`/reports/${id}`);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
|
|
@ -38,11 +40,11 @@ export function ReportHeader({ icon }) {
|
|||
}
|
||||
};
|
||||
|
||||
const handleNameChange = name => {
|
||||
const handleNameChange = (name: string) => {
|
||||
updateReport({ name: name || defaultName });
|
||||
};
|
||||
|
||||
const handleDescriptionChange = description => {
|
||||
const handleDescriptionChange = (description: string) => {
|
||||
updateReport({ description });
|
||||
};
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { useContext, useRef } from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { Form, FormRow, FormButtons, SubmitButton, PopupTrigger, Icon, Popup } from 'react-basics';
|
||||
import Empty from 'components/common/Empty';
|
||||
import Icons from 'components/icons';
|
||||
|
|
@ -29,7 +29,6 @@ function useFields(websiteId, startDate, endDate) {
|
|||
export function EventDataParameters() {
|
||||
const { report, runReport, updateReport, isRunning } = useContext(ReportContext);
|
||||
const { formatMessage, labels, messages } = useMessages();
|
||||
const ref = useRef(null);
|
||||
const { parameters } = report || {};
|
||||
const { websiteId, dateRange, fields, filters, groups } = parameters || {};
|
||||
const { startDate, endDate } = dateRange || {};
|
||||
|
|
@ -53,28 +52,28 @@ export function EventDataParameters() {
|
|||
runReport(values);
|
||||
};
|
||||
|
||||
const handleAdd = (group, value) => {
|
||||
const handleAdd = (group: string, value: any) => {
|
||||
const data = parameterData[group];
|
||||
|
||||
if (!data.find(({ name }) => name === value.name)) {
|
||||
if (!data.find(({ name }) => name === value?.name)) {
|
||||
updateReport({ parameters: { [group]: data.concat(value) } });
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemove = (group, index) => {
|
||||
const handleRemove = (group: string, index: number) => {
|
||||
const data = [...parameterData[group]];
|
||||
data.splice(index, 1);
|
||||
updateReport({ parameters: { [group]: data } });
|
||||
};
|
||||
|
||||
const AddButton = ({ group }) => {
|
||||
const AddButton = ({ group, onAdd }) => {
|
||||
return (
|
||||
<PopupTrigger>
|
||||
<Icon>
|
||||
<Icons.Plus />
|
||||
</Icon>
|
||||
<Popup position="bottom" alignment="start">
|
||||
{close => {
|
||||
{(close: () => void) => {
|
||||
return (
|
||||
<FieldAddForm
|
||||
fields={data.map(({ eventKey, eventDataType }) => ({
|
||||
|
|
@ -82,7 +81,7 @@ export function EventDataParameters() {
|
|||
type: DATA_TYPES[eventDataType],
|
||||
}))}
|
||||
group={group}
|
||||
onAdd={handleAdd}
|
||||
onAdd={onAdd}
|
||||
onClose={close}
|
||||
/>
|
||||
);
|
||||
|
|
@ -93,7 +92,7 @@ export function EventDataParameters() {
|
|||
};
|
||||
|
||||
return (
|
||||
<Form ref={ref} values={parameters} error={error} onSubmit={handleSubmit}>
|
||||
<Form values={parameters} error={error} onSubmit={handleSubmit}>
|
||||
<BaseParameters />
|
||||
{!hasData && <Empty message={formatMessage(messages.noEventData)} />}
|
||||
{parametersSelected &&
|
||||
|
|
@ -11,7 +11,7 @@ const defaultParameters = {
|
|||
parameters: { fields: [], filters: [] },
|
||||
};
|
||||
|
||||
export default function EventDataReport({ reportId }) {
|
||||
export default function EventDataReport({ reportId }: { reportId: string }) {
|
||||
return (
|
||||
<Report reportId={reportId} defaultParameters={defaultParameters}>
|
||||
<ReportHeader icon={<Nodes />} />
|
||||
|
|
@ -1,13 +1,18 @@
|
|||
import { useCallback, useContext, useMemo } from 'react';
|
||||
import { JSX, useCallback, useContext, useMemo } from 'react';
|
||||
import { Loading, StatusLight } from 'react-basics';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import useTheme from 'components/hooks/useTheme';
|
||||
import BarChart from 'components/metrics/BarChart';
|
||||
import { formatLongNumber } from 'lib/format';
|
||||
import styles from './FunnelChart.module.css';
|
||||
import { ReportContext } from '../[id]/Report';
|
||||
import styles from './FunnelChart.module.css';
|
||||
|
||||
export function FunnelChart({ className, loading }) {
|
||||
export interface FunnelChartProps {
|
||||
className?: string;
|
||||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
export function FunnelChart({ className, isLoading }: FunnelChartProps) {
|
||||
const { report } = useContext(ReportContext);
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { colors } = useTheme();
|
||||
|
|
@ -15,33 +20,39 @@ export function FunnelChart({ className, loading }) {
|
|||
const { parameters, data } = report || {};
|
||||
|
||||
const renderXLabel = useCallback(
|
||||
(label, index) => {
|
||||
(label: string, index: number) => {
|
||||
return parameters.urls[index];
|
||||
},
|
||||
[parameters],
|
||||
);
|
||||
|
||||
const renderTooltipPopup = useCallback((setTooltipPopup, model) => {
|
||||
const { opacity, labelColors, dataPoints } = model.tooltip;
|
||||
const renderTooltipPopup = useCallback(
|
||||
(
|
||||
setTooltipPopup: (arg0: JSX.Element) => void,
|
||||
model: { tooltip: { opacity: any; labelColors: any; dataPoints: any } },
|
||||
) => {
|
||||
const { opacity, labelColors, dataPoints } = model.tooltip;
|
||||
|
||||
if (!dataPoints?.length || !opacity) {
|
||||
setTooltipPopup(null);
|
||||
return;
|
||||
}
|
||||
if (!dataPoints?.length || !opacity) {
|
||||
setTooltipPopup(null);
|
||||
return;
|
||||
}
|
||||
|
||||
setTooltipPopup(
|
||||
<>
|
||||
<div>
|
||||
{formatLongNumber(dataPoints[0].raw.y)} {formatMessage(labels.visitors)}
|
||||
</div>
|
||||
<div>
|
||||
<StatusLight color={labelColors?.[0]?.backgroundColor}>
|
||||
{formatLongNumber(dataPoints[0].raw.z)}% {formatMessage(labels.dropoff)}
|
||||
</StatusLight>
|
||||
</div>
|
||||
</>,
|
||||
);
|
||||
}, []);
|
||||
setTooltipPopup(
|
||||
<>
|
||||
<div>
|
||||
{formatLongNumber(dataPoints[0].raw.y)} {formatMessage(labels.visitors)}
|
||||
</div>
|
||||
<div>
|
||||
<StatusLight color={labelColors?.[0]?.backgroundColor}>
|
||||
{formatLongNumber(dataPoints[0].raw.z)}% {formatMessage(labels.dropoff)}
|
||||
</StatusLight>
|
||||
</div>
|
||||
</>,
|
||||
);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const datasets = useMemo(() => {
|
||||
return [
|
||||
|
|
@ -54,7 +65,7 @@ export function FunnelChart({ className, loading }) {
|
|||
];
|
||||
}, [data, colors, formatMessage, labels]);
|
||||
|
||||
if (loading) {
|
||||
if (isLoading) {
|
||||
return <Loading icon="dots" className={styles.loading} />;
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +74,7 @@ export function FunnelChart({ className, loading }) {
|
|||
className={className}
|
||||
datasets={datasets}
|
||||
unit="day"
|
||||
loading={loading}
|
||||
isLoading={isLoading}
|
||||
renderXLabel={renderXLabel}
|
||||
renderTooltipPopup={renderTooltipPopup}
|
||||
XAxisType="category"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { useContext, useRef } from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import {
|
||||
Icon,
|
||||
|
|
@ -21,13 +21,12 @@ import PopupForm from '../[id]/PopupForm';
|
|||
export function FunnelParameters() {
|
||||
const { report, runReport, updateReport, isRunning } = useContext(ReportContext);
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const ref = useRef(null);
|
||||
|
||||
const { parameters } = report || {};
|
||||
const { websiteId, dateRange, urls } = parameters || {};
|
||||
const queryDisabled = !websiteId || !dateRange || urls?.length < 2;
|
||||
|
||||
const handleSubmit = (data, e) => {
|
||||
const handleSubmit = (data: any, e: any) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
if (!queryDisabled) {
|
||||
|
|
@ -35,11 +34,11 @@ export function FunnelParameters() {
|
|||
}
|
||||
};
|
||||
|
||||
const handleAddUrl = url => {
|
||||
const handleAddUrl = (url: string) => {
|
||||
updateReport({ parameters: { urls: parameters.urls.concat(url) } });
|
||||
};
|
||||
|
||||
const handleRemoveUrl = (index, e) => {
|
||||
const handleRemoveUrl = (index: number, e: any) => {
|
||||
e.stopPropagation();
|
||||
const urls = [...parameters.urls];
|
||||
urls.splice(index, 1);
|
||||
|
|
@ -62,7 +61,7 @@ export function FunnelParameters() {
|
|||
};
|
||||
|
||||
return (
|
||||
<Form ref={ref} values={parameters} onSubmit={handleSubmit} preventSubmit={true}>
|
||||
<Form values={parameters} onSubmit={handleSubmit} preventSubmit={true}>
|
||||
<BaseParameters />
|
||||
<FormRow label={formatMessage(labels.window)}>
|
||||
<FormInput
|
||||
|
|
@ -73,7 +72,10 @@ export function FunnelParameters() {
|
|||
</FormInput>
|
||||
</FormRow>
|
||||
<FormRow label={formatMessage(labels.urls)} action={<AddUrlButton />}>
|
||||
<ParameterList items={urls} onRemove={handleRemoveUrl} />
|
||||
<ParameterList
|
||||
items={urls}
|
||||
onRemove={(index: number, e: any) => handleRemoveUrl(index, e)}
|
||||
/>
|
||||
</FormRow>
|
||||
<FormButtons>
|
||||
<SubmitButton variant="primary" disabled={queryDisabled} isLoading={isRunning}>
|
||||
|
|
@ -3,7 +3,12 @@ import { useMessages } from 'components/hooks';
|
|||
import { Button, Form, FormRow, TextField, Flexbox } from 'react-basics';
|
||||
import styles from './UrlAddForm.module.css';
|
||||
|
||||
export function UrlAddForm({ defaultValue = '', onAdd }) {
|
||||
export interface UrlAddFormProps {
|
||||
defaultValue?: string;
|
||||
onAdd?: (url: string) => void;
|
||||
}
|
||||
|
||||
export function UrlAddForm({ defaultValue = '', onAdd }: UrlAddFormProps) {
|
||||
const [url, setUrl] = useState(defaultValue);
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { useContext, useRef } from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { useFormat, useMessages, useFilters } from 'components/hooks';
|
||||
import {
|
||||
Form,
|
||||
|
|
@ -24,7 +24,6 @@ export function InsightsParameters() {
|
|||
const { formatMessage, labels } = useMessages();
|
||||
const { formatValue } = useFormat();
|
||||
const { filterLabels } = useFilters();
|
||||
const ref = useRef(null);
|
||||
const { parameters } = report || {};
|
||||
const { websiteId, dateRange, fields, filters } = parameters || {};
|
||||
const { startDate, endDate } = dateRange || {};
|
||||
|
|
@ -72,7 +71,7 @@ export function InsightsParameters() {
|
|||
updateReport({ parameters: { [id]: data } });
|
||||
};
|
||||
|
||||
const AddButton = ({ id }) => {
|
||||
const AddButton = ({ id, onAdd }) => {
|
||||
return (
|
||||
<PopupTrigger>
|
||||
<TooltipPopup label={formatMessage(labels.add)} position="top">
|
||||
|
|
@ -84,8 +83,8 @@ export function InsightsParameters() {
|
|||
<PopupForm>
|
||||
{id === 'fields' && (
|
||||
<FieldSelectForm
|
||||
items={fieldOptions}
|
||||
onSelect={handleAdd.bind(null, id)}
|
||||
fields={fieldOptions}
|
||||
onSelect={onAdd.bind(null, id)}
|
||||
showType={false}
|
||||
/>
|
||||
)}
|
||||
|
|
@ -93,7 +92,7 @@ export function InsightsParameters() {
|
|||
<FilterSelectForm
|
||||
websiteId={websiteId}
|
||||
items={fieldOptions}
|
||||
onSelect={handleAdd.bind(null, id)}
|
||||
onSelect={onAdd.bind(null, id)}
|
||||
/>
|
||||
)}
|
||||
</PopupForm>
|
||||
|
|
@ -103,7 +102,7 @@ export function InsightsParameters() {
|
|||
};
|
||||
|
||||
return (
|
||||
<Form ref={ref} values={parameters} onSubmit={handleSubmit}>
|
||||
<Form values={parameters} onSubmit={handleSubmit}>
|
||||
<BaseParameters />
|
||||
{parametersSelected &&
|
||||
parameterGroups.map(({ id, label }) => {
|
||||
|
|
@ -13,7 +13,7 @@ const defaultParameters = {
|
|||
parameters: { fields: [], filters: [] },
|
||||
};
|
||||
|
||||
export default function InsightsReport({ reportId }) {
|
||||
export default function InsightsReport({ reportId }: { reportId: string }) {
|
||||
return (
|
||||
<Report reportId={reportId} defaultParameters={defaultParameters}>
|
||||
<ReportHeader icon={<Lightbulb />} />
|
||||
|
|
@ -5,7 +5,7 @@ import { ReportContext } from '../[id]/Report';
|
|||
import EmptyPlaceholder from 'components/common/EmptyPlaceholder';
|
||||
|
||||
export function InsightsTable() {
|
||||
const [fields, setFields] = useState();
|
||||
const [fields, setFields] = useState([]);
|
||||
const { report } = useContext(ReportContext);
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { formatValue } = useFormat();
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { useContext, useRef } from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import { Form, FormButtons, FormRow, SubmitButton } from 'react-basics';
|
||||
import { ReportContext } from '../[id]/Report';
|
||||
|
|
@ -9,14 +9,13 @@ import { parseDateRange } from 'lib/date';
|
|||
export function RetentionParameters() {
|
||||
const { report, runReport, isRunning, updateReport } = useContext(ReportContext);
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const ref = useRef(null);
|
||||
|
||||
const { parameters } = report || {};
|
||||
const { websiteId, dateRange } = parameters || {};
|
||||
const { startDate } = dateRange || {};
|
||||
const queryDisabled = !websiteId || !dateRange;
|
||||
|
||||
const handleSubmit = (data, e) => {
|
||||
const handleSubmit = (data: any, e: any) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
|
|
@ -30,7 +29,7 @@ export function RetentionParameters() {
|
|||
};
|
||||
|
||||
return (
|
||||
<Form ref={ref} values={parameters} onSubmit={handleSubmit} preventSubmit={true}>
|
||||
<Form values={parameters} onSubmit={handleSubmit} preventSubmit={true}>
|
||||
<BaseParameters showDateSelect={false} />
|
||||
<FormRow label={formatMessage(labels.date)}>
|
||||
<MonthSelect date={startDate} onChange={handleDateChange} />
|
||||
|
|
@ -19,7 +19,7 @@ const defaultParameters = {
|
|||
},
|
||||
};
|
||||
|
||||
export default function RetentionReport({ reportId }) {
|
||||
export default function RetentionReport({ reportId }: { reportId: string }) {
|
||||
return (
|
||||
<Report reportId={reportId} defaultParameters={defaultParameters}>
|
||||
<ReportHeader icon={<Magnet />} />
|
||||
|
|
@ -18,7 +18,7 @@ export function RetentionTable({ days = DAYS }) {
|
|||
return <EmptyPlaceholder />;
|
||||
}
|
||||
|
||||
const rows = data.reduce((arr, row) => {
|
||||
const rows = data.reduce((arr: any[], row: { date: any; visitors: any; day: any }) => {
|
||||
const { date, visitors, day } = row;
|
||||
if (day === 0) {
|
||||
return arr.concat({
|
||||
Loading…
Add table
Add a link
Reference in a new issue