diff --git a/src/app/(main)/reports/[reportId]/FieldAddForm.module.css b/src/app/(main)/reports/[reportId]/FieldAddForm.module.css deleted file mode 100644 index 5c5aaa4f0..000000000 --- a/src/app/(main)/reports/[reportId]/FieldAddForm.module.css +++ /dev/null @@ -1,38 +0,0 @@ -.menu { - width: 360px; - max-height: 300px; - overflow: auto; -} - -.item { - display: flex; - flex-direction: row; - justify-content: space-between; - border-radius: var(--border-radius); -} - -.item:hover { - background: var(--base75); -} - -.type { - color: var(--font-color300); -} - -.selected { - font-weight: bold; -} - -.popup { - display: flex; -} - -.filter { - display: flex; - flex-direction: column; - gap: 20px; -} - -.dropdown { - min-width: 60px; -} diff --git a/src/app/(main)/reports/[reportId]/FieldAddForm.tsx b/src/app/(main)/reports/[reportId]/FieldAddForm.tsx index 9db472d8d..32a0b0afc 100644 --- a/src/app/(main)/reports/[reportId]/FieldAddForm.tsx +++ b/src/app/(main)/reports/[reportId]/FieldAddForm.tsx @@ -4,8 +4,7 @@ import { REPORT_PARAMETERS } from 'lib/constants'; import PopupForm from './PopupForm'; import FieldSelectForm from './FieldSelectForm'; import FieldAggregateForm from './FieldAggregateForm'; -import FieldFilterForm from './FieldFilterForm'; -import styles from './FieldAddForm.module.css'; +import FieldFilterEditForm from './FieldFilterEditForm'; export function FieldAddForm({ fields = [], @@ -38,13 +37,13 @@ export function FieldAddForm({ }; return createPortal( - + {!selected && } {selected && group === REPORT_PARAMETERS.fields && ( )} {selected && group === REPORT_PARAMETERS.filters && ( - + )} , document.body, diff --git a/src/app/(main)/reports/[reportId]/FieldFilterForm.module.css b/src/app/(main)/reports/[reportId]/FieldFilterEditForm.module.css similarity index 91% rename from src/app/(main)/reports/[reportId]/FieldFilterForm.module.css rename to src/app/(main)/reports/[reportId]/FieldFilterEditForm.module.css index be7bb9546..ed78512dc 100644 --- a/src/app/(main)/reports/[reportId]/FieldFilterForm.module.css +++ b/src/app/(main)/reports/[reportId]/FieldFilterEditForm.module.css @@ -2,7 +2,7 @@ display: flex; max-width: 300px; max-height: 210px; - overflow-x: hidden; + overflow: hidden; } .popup > div { diff --git a/src/app/(main)/reports/[reportId]/FieldFilterForm.tsx b/src/app/(main)/reports/[reportId]/FieldFilterEditForm.tsx similarity index 59% rename from src/app/(main)/reports/[reportId]/FieldFilterForm.tsx rename to src/app/(main)/reports/[reportId]/FieldFilterEditForm.tsx index e38f3d656..f3b5b247f 100644 --- a/src/app/(main)/reports/[reportId]/FieldFilterForm.tsx +++ b/src/app/(main)/reports/[reportId]/FieldFilterEditForm.tsx @@ -10,54 +10,67 @@ import { Menu, Popup, PopupTrigger, + Loading, } from 'react-basics'; -import { useMessages, useFilters, useFormat, useLocale } from 'components/hooks'; +import { useMessages, useFilters, useFormat, useLocale, useWebsiteValues } from 'components/hooks'; import { safeDecodeURIComponent } from 'next-basics'; import { OPERATORS } from 'lib/constants'; -import styles from './FieldFilterForm.module.css'; +import styles from './FieldFilterEditForm.module.css'; export interface FieldFilterFormProps { + websiteId?: string; name: string; label?: string; type: string; - values?: any[]; - onSelect?: (key: any) => void; + defaultValue?: string; + onChange?: (filter: { name: string; type: string; filter: string; value: string }) => void; allowFilterSelect?: boolean; + isNew?: boolean; } -export default function FieldFilterForm({ +export default function FieldFilterEditForm({ + websiteId, name, label, type, - values, - onSelect, + defaultValue, + onChange, allowFilterSelect = true, + isNew, }: FieldFilterFormProps) { const { formatMessage, labels } = useMessages(); const [filter, setFilter] = useState('eq'); - const [value, setValue] = useState(''); + const [value, setValue] = useState(defaultValue ?? ''); const { getFilters } = useFilters(); const { formatValue } = useFormat(); const { locale } = useLocale(); const filters = getFilters(type); + const { data: values = [], isLoading } = useWebsiteValues(websiteId, name); const formattedValues = useMemo(() => { + if (!values) { + return {}; + } const formatted = {}; const format = (val: string) => { formatted[val] = formatValue(val, name); return formatted[val]; }; - if (values.length !== 1) { + + if (values?.length !== 1) { const { compare } = new Intl.Collator(locale, { numeric: true }); values.sort((a, b) => compare(formatted[a] ?? format(a), formatted[b] ?? format(b))); } else { format(values[0]); } + return formatted; }, [formatValue, locale, name, values]); const filteredValues = useMemo(() => { - return value ? values.filter(n => n.includes(value)) : values; + return value + ? values.filter(n => formattedValues[n].toLowerCase().includes(value.toLowerCase())) + : values; }, [value, formattedValues]); const renderFilterValue = value => { @@ -65,7 +78,7 @@ export default function FieldFilterForm({ }; const handleAdd = () => { - onSelect({ name, type, filter, value }); + onChange({ name, type, filter, value }); }; const handleMenuSelect = value => { @@ -74,7 +87,7 @@ export default function FieldFilterForm({ const showMenu = [OPERATORS.equals, OPERATORS.notEquals].includes(filter as any) && - !(filteredValues.length === 1 && filteredValues[0] === value); + !(filteredValues?.length === 1 && filteredValues[0] === formattedValues[value]); return (
@@ -97,25 +110,44 @@ export default function FieldFilterForm({ setValue(e.target.value)} /> {showMenu && ( - - {filteredValues.length > 0 && ( - - {filteredValues.map(value => { - return {safeDecodeURIComponent(value)}; - })} - - )} + + )} ); } + +const ResultsMenu = ({ values, type, isLoading, onSelect }) => { + const { formatValue } = useFormat(); + if (isLoading) { + return ; + } + + if (!values?.length) { + return null; + } + + return ( + + {values?.map(value => { + return {safeDecodeURIComponent(formatValue(value, type))}; + })} + + ); +}; diff --git a/src/app/(main)/reports/insights/InsightsFieldParameters.tsx b/src/app/(main)/reports/[reportId]/FieldParameters.tsx similarity index 66% rename from src/app/(main)/reports/insights/InsightsFieldParameters.tsx rename to src/app/(main)/reports/[reportId]/FieldParameters.tsx index 798a828cd..ded9dee7b 100644 --- a/src/app/(main)/reports/insights/InsightsFieldParameters.tsx +++ b/src/app/(main)/reports/[reportId]/FieldParameters.tsx @@ -1,4 +1,4 @@ -import { useMessages } from 'components/hooks'; +import { useFields, useMessages } from 'components/hooks'; import Icons from 'components/icons'; import { useContext } from 'react'; import { Button, FormRow, Icon, Popup, PopupTrigger } from 'react-basics'; @@ -7,24 +7,12 @@ import ParameterList from '../[reportId]/ParameterList'; import PopupForm from '../[reportId]/PopupForm'; import { ReportContext } from '../[reportId]/Report'; -export function InsightsFieldParameters() { +export function FieldParameters() { const { report, updateReport } = useContext(ReportContext); const { formatMessage, labels } = useMessages(); const { parameters } = report || {}; const { fields } = parameters || {}; - - const fieldOptions = [ - { name: 'url', type: 'string', label: formatMessage(labels.url) }, - { name: 'title', type: 'string', label: formatMessage(labels.pageTitle) }, - { name: 'referrer', type: 'string', label: formatMessage(labels.referrer) }, - { name: 'query', type: 'string', label: formatMessage(labels.query) }, - { name: 'browser', type: 'string', label: formatMessage(labels.browser) }, - { name: 'os', type: 'string', label: formatMessage(labels.os) }, - { name: 'device', type: 'string', label: formatMessage(labels.device) }, - { name: 'country', type: 'string', label: formatMessage(labels.country) }, - { name: 'region', type: 'string', label: formatMessage(labels.region) }, - { name: 'city', type: 'string', label: formatMessage(labels.city) }, - ]; + const { fields: fieldOptions } = useFields(); const handleAdd = (value: { name: any }) => { if (!fields.find(({ name }) => name === value.name)) { @@ -72,4 +60,4 @@ export function InsightsFieldParameters() { ); } -export default InsightsFieldParameters; +export default FieldParameters; diff --git a/src/app/(main)/reports/insights/InsightsFilterParameters.module.css b/src/app/(main)/reports/[reportId]/FilterParameters.module.css similarity index 95% rename from src/app/(main)/reports/insights/InsightsFilterParameters.module.css rename to src/app/(main)/reports/[reportId]/FilterParameters.module.css index 8b1795d21..022c0d7e6 100644 --- a/src/app/(main)/reports/insights/InsightsFilterParameters.module.css +++ b/src/app/(main)/reports/[reportId]/FilterParameters.module.css @@ -34,3 +34,7 @@ border-radius: 5px; white-space: nowrap; } + +.edit { + margin-top: 20px; +} diff --git a/src/app/(main)/reports/[reportId]/FilterParameters.tsx b/src/app/(main)/reports/[reportId]/FilterParameters.tsx new file mode 100644 index 000000000..cd7a555ef --- /dev/null +++ b/src/app/(main)/reports/[reportId]/FilterParameters.tsx @@ -0,0 +1,113 @@ +import { useContext } from 'react'; +import { safeDecodeURIComponent } from 'next-basics'; +import { useMessages, useFormat, useFilters, useFields } from 'components/hooks'; +import Icons from 'components/icons'; +import { Button, FormRow, Icon, Popup, PopupTrigger } from 'react-basics'; +import FilterSelectForm from '../[reportId]/FilterSelectForm'; +import ParameterList from '../[reportId]/ParameterList'; +import PopupForm from '../[reportId]/PopupForm'; +import { ReportContext } from './Report'; +import { OPERATORS } from 'lib/constants'; +import FieldFilterEditForm from '../[reportId]/FieldFilterEditForm'; +import styles from './FilterParameters.module.css'; + +export function FilterParameters() { + const { report, updateReport } = useContext(ReportContext); + const { formatMessage, labels } = useMessages(); + const { formatValue } = useFormat(); + const { filterLabels } = useFilters(); + const { parameters } = report || {}; + const { websiteId, filters } = parameters || {}; + const { fields } = useFields(); + + const handleAdd = (value: { name: any }) => { + if (!filters.find(({ name }) => name === value.name)) { + updateReport({ parameters: { filters: filters.concat(value) } }); + } + }; + + const handleRemove = (name: string) => { + updateReport({ parameters: { filters: filters.filter(f => f.name !== name) } }); + }; + + const handleChange = filter => { + updateReport({ + parameters: { + filters: filters.map(f => { + if (filter.name === f.name) { + return filter; + } + return f; + }), + }, + }); + }; + + const AddButton = () => { + return ( + + + + + !filters.find(f => f.name === name))} + onChange={handleAdd} + /> + + + + ); + }; + + return ( + }> + + {filters.map(({ name, filter, value }: { name: string; filter: string; value: string }) => { + const label = fields.find(f => f.name === name)?.label; + const isEquals = [OPERATORS.equals, OPERATORS.notEquals].includes(filter as any); + return ( + handleRemove(name)}> + + + ); + })} + + + ); +} + +const FilterParameter = ({ name, label, filter, value, type = 'string', onChange }) => { + return ( + +
+
{label}
+
{filter}
+
{safeDecodeURIComponent(value)}
+
+ + + + + +
+ ); +}; + +export default FilterParameters; diff --git a/src/app/(main)/reports/[reportId]/FilterSelectForm.tsx b/src/app/(main)/reports/[reportId]/FilterSelectForm.tsx index 3d209fc14..f43ac5f6e 100644 --- a/src/app/(main)/reports/[reportId]/FilterSelectForm.tsx +++ b/src/app/(main)/reports/[reportId]/FilterSelectForm.tsx @@ -1,59 +1,37 @@ import { useState } from 'react'; -import { Loading } from 'react-basics'; -import { subDays } from 'date-fns'; import FieldSelectForm from './FieldSelectForm'; -import FieldFilterForm from './FieldFilterForm'; -import { useApi } from 'components/hooks'; - -function useValues(websiteId: string, type: string) { - const now = Date.now(); - const { get, useQuery } = useApi(); - const { data, error, isLoading } = useQuery({ - queryKey: ['websites:values', websiteId, type], - queryFn: () => - get(`/websites/${websiteId}/values`, { - type, - startAt: +subDays(now, 90), - endAt: now, - }), - enabled: !!(websiteId && type), - }); - - return { data, error, isLoading }; -} +import FieldFilterEditForm from './FieldFilterEditForm'; export interface FilterSelectFormProps { - websiteId: string; + websiteId?: string; fields: any[]; - onSelect?: (key: any) => void; + onChange?: (filter: { name: string; type: string; filter: string; value: string }) => void; allowFilterSelect?: boolean; } export default function FilterSelectForm({ websiteId, fields, - onSelect, + onChange, allowFilterSelect, }: FilterSelectFormProps) { const [field, setField] = useState<{ name: string; label: string; type: string }>(); - const { data, isLoading } = useValues(websiteId, field?.name); if (!field) { return ; } - if (isLoading) { - return ; - } + const { name, label, type } = field; return ( - ); } diff --git a/src/app/(main)/reports/[reportId]/ParameterList.tsx b/src/app/(main)/reports/[reportId]/ParameterList.tsx index 7fe123818..046e85dce 100644 --- a/src/app/(main)/reports/[reportId]/ParameterList.tsx +++ b/src/app/(main)/reports/[reportId]/ParameterList.tsx @@ -20,9 +20,17 @@ export function ParameterList({ children }: ParameterListProps) { ); } -const Item = ({ children, onRemove }: { children?: ReactNode; onRemove?: () => void }) => { +const Item = ({ + children, + onClick, + onRemove, +}: { + children?: ReactNode; + onClick?: () => void; + onRemove?: () => void; +}) => { return ( -
+
{children} diff --git a/src/app/(main)/reports/event-data/EventDataParameters.tsx b/src/app/(main)/reports/event-data/EventDataParameters.tsx index efa9fb675..adc182748 100644 --- a/src/app/(main)/reports/event-data/EventDataParameters.tsx +++ b/src/app/(main)/reports/event-data/EventDataParameters.tsx @@ -60,10 +60,9 @@ export function EventDataParameters() { } }; - const handleRemove = (group: string, index: number) => { + const handleRemove = (group: string) => { const data = [...parameterData[group]]; - data.splice(index, 1); - updateReport({ parameters: { [group]: data } }); + updateReport({ parameters: { [group]: data.filter(({ name }) => name !== group) } }); }; const AddButton = ({ group, onAdd }) => { @@ -104,29 +103,28 @@ export function EventDataParameters() { label={label} action={} > - handleRemove(group, index)} - > - {({ name, value }) => { + + {parameterData[group].map(({ name, value }) => { return ( -
- {group === REPORT_PARAMETERS.fields && ( - <> -
{name}
-
{value}
- - )} - {group === REPORT_PARAMETERS.filters && ( - <> -
{name}
-
{value[0]}
-
{value[1]}
- - )} -
+ handleRemove(group)}> +
+ {group === REPORT_PARAMETERS.fields && ( + <> +
{name}
+
{value}
+ + )} + {group === REPORT_PARAMETERS.filters && ( + <> +
{name}
+
{value[0]}
+
{value[1]}
+ + )} +
+
); - }} + })}
); diff --git a/src/app/(main)/reports/funnel/FunnelParameters.tsx b/src/app/(main)/reports/funnel/FunnelParameters.tsx index 6eefbaae4..7c4aa8454 100644 --- a/src/app/(main)/reports/funnel/FunnelParameters.tsx +++ b/src/app/(main)/reports/funnel/FunnelParameters.tsx @@ -38,11 +38,9 @@ export function FunnelParameters() { updateReport({ parameters: { urls: parameters.urls.concat(url) } }); }; - const handleRemoveUrl = (index: number, e: any) => { - e.stopPropagation(); + const handleRemoveUrl = (url: string) => { const urls = [...parameters.urls]; - urls.splice(index, 1); - updateReport({ parameters: { urls } }); + updateReport({ parameters: { urls: urls.filter(n => n.url !== url) } }); }; const AddUrlButton = () => { @@ -72,10 +70,11 @@ export function FunnelParameters() { }> - handleRemoveUrl(index, e)} - /> + + {urls.map(url => { + return handleRemoveUrl(url)} />; + })} + diff --git a/src/app/(main)/reports/insights/InsightsFilterParameters.tsx b/src/app/(main)/reports/insights/InsightsFilterParameters.tsx deleted file mode 100644 index 47554469c..000000000 --- a/src/app/(main)/reports/insights/InsightsFilterParameters.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { useMessages, useFormat, useFilters } from 'components/hooks'; -import Icons from 'components/icons'; -import { useContext } from 'react'; -import { Button, FormRow, Icon, Popup, PopupTrigger } from 'react-basics'; -import FilterSelectForm from '../[reportId]/FilterSelectForm'; -import ParameterList from '../[reportId]/ParameterList'; -import PopupForm from '../[reportId]/PopupForm'; -import { ReportContext } from '../[reportId]/Report'; -import styles from './InsightsFilterParameters.module.css'; -import { safeDecodeURIComponent } from 'next-basics'; -import { OPERATORS } from 'lib/constants'; - -export function InsightsFilterParameters() { - const { report, updateReport } = useContext(ReportContext); - const { formatMessage, labels } = useMessages(); - const { formatValue } = useFormat(); - const { filterLabels } = useFilters(); - const { parameters } = report || {}; - const { websiteId, filters } = parameters || {}; - - const fieldOptions = [ - { name: 'url', type: 'string', label: formatMessage(labels.url) }, - { name: 'title', type: 'string', label: formatMessage(labels.pageTitle) }, - { name: 'referrer', type: 'string', label: formatMessage(labels.referrer) }, - { name: 'query', type: 'string', label: formatMessage(labels.query) }, - { name: 'browser', type: 'string', label: formatMessage(labels.browser) }, - { name: 'os', type: 'string', label: formatMessage(labels.os) }, - { name: 'device', type: 'string', label: formatMessage(labels.device) }, - { name: 'country', type: 'string', label: formatMessage(labels.country) }, - { name: 'region', type: 'string', label: formatMessage(labels.region) }, - { name: 'city', type: 'string', label: formatMessage(labels.city) }, - ]; - - const handleAdd = (value: { name: any }) => { - if (!filters.find(({ name }) => name === value.name)) { - updateReport({ parameters: { filters: filters.concat(value) } }); - } - }; - - const handleRemove = (name: string) => { - updateReport({ parameters: { filters: filters.filter(f => f.name !== name) } }); - }; - - const AddButton = () => { - return ( - - - - - !filters.find(f => f.name === name))} - onSelect={handleAdd} - /> - - - - ); - }; - - return ( - }> - - {filters.map(({ name, filter, value }) => { - const label = fieldOptions.find(f => f.name === name)?.label; - const isEquals = [OPERATORS.equals, OPERATORS.notEquals].includes(filter); - return ( - handleRemove(name)}> -
-
{label}
-
{filterLabels[filter]}
-
- {safeDecodeURIComponent(isEquals ? formatValue(value, name) : value)} -
-
-
- ); - })} -
-
- ); -} - -export default InsightsFilterParameters; diff --git a/src/app/(main)/reports/insights/InsightsParameters.tsx b/src/app/(main)/reports/insights/InsightsParameters.tsx index 22c57ff0c..7f58de6a4 100644 --- a/src/app/(main)/reports/insights/InsightsParameters.tsx +++ b/src/app/(main)/reports/insights/InsightsParameters.tsx @@ -3,8 +3,8 @@ import { useContext } from 'react'; import { Form, FormButtons, SubmitButton } from 'react-basics'; import BaseParameters from '../[reportId]/BaseParameters'; import { ReportContext } from '../[reportId]/Report'; -import InsightsFieldParameters from './InsightsFieldParameters'; -import InsightsFilterParameters from './InsightsFilterParameters'; +import FieldParameters from '../[reportId]/FieldParameters'; +import FilterParameters from '../[reportId]/FilterParameters'; export function InsightsParameters() { const { report, runReport, isRunning } = useContext(ReportContext); @@ -22,8 +22,8 @@ export function InsightsParameters() { return (
- {parametersSelected && } - {parametersSelected && } + {parametersSelected && } + {parametersSelected && } {formatMessage(labels.runQuery)} diff --git a/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx b/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx index 998c73c46..c7e4cc534 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx @@ -1,7 +1,7 @@ import { Button, Icon, Icons, Popup, PopupTrigger, Text } from 'react-basics'; import PopupForm from 'app/(main)/reports/[reportId]/PopupForm'; import FilterSelectForm from 'app/(main)/reports/[reportId]/FilterSelectForm'; -import { useMessages, useNavigation } from 'components/hooks'; +import { useFields, useMessages, useNavigation } from 'components/hooks'; export function WebsiteFilterButton({ websiteId, @@ -12,17 +12,7 @@ export function WebsiteFilterButton({ }) { const { formatMessage, labels } = useMessages(); const { renderUrl, router } = useNavigation(); - - const fieldOptions = [ - { name: 'url', type: 'string', label: formatMessage(labels.url) }, - { name: 'referrer', type: 'string', label: formatMessage(labels.referrer) }, - { name: 'browser', type: 'string', label: formatMessage(labels.browser) }, - { name: 'os', type: 'string', label: formatMessage(labels.os) }, - { name: 'device', type: 'string', label: formatMessage(labels.device) }, - { name: 'country', type: 'string', label: formatMessage(labels.country) }, - { name: 'region', type: 'string', label: formatMessage(labels.region) }, - { name: 'city', type: 'string', label: formatMessage(labels.city) }, - ]; + const { fields } = useFields(); const handleAddFilter = ({ name, value }) => { router.push(renderUrl({ [name]: value })); @@ -42,8 +32,8 @@ export function WebsiteFilterButton({ { + fields={fields} + onChange={value => { handleAddFilter(value); close(); }} diff --git a/src/components/hooks/index.ts b/src/components/hooks/index.ts index a737ba204..df4fbd88f 100644 --- a/src/components/hooks/index.ts +++ b/src/components/hooks/index.ts @@ -16,10 +16,12 @@ export * from './queries/useWebsite'; export * from './queries/useWebsites'; export * from './queries/useWebsiteEvents'; export * from './queries/useWebsiteMetrics'; +export * from './queries/useWebsiteValues'; export * from './useCountryNames'; export * from './useDateRange'; export * from './useDocumentClick'; export * from './useEscapeKey'; +export * from './useFields'; export * from './useFilters'; export * from './useForceUpdate'; export * from './useFormat'; diff --git a/src/components/hooks/queries/useWebsiteValues.ts b/src/components/hooks/queries/useWebsiteValues.ts new file mode 100644 index 000000000..ab287c076 --- /dev/null +++ b/src/components/hooks/queries/useWebsiteValues.ts @@ -0,0 +1,20 @@ +import { useApi } from 'components/hooks'; +import { subDays } from 'date-fns'; + +export function useWebsiteValues(websiteId: string, type: string) { + const now = Date.now(); + const { get, useQuery } = useApi(); + + return useQuery({ + queryKey: ['websites:values', websiteId, type], + queryFn: () => + get(`/websites/${websiteId}/values`, { + type, + startAt: +subDays(now, 90), + endAt: now, + }), + enabled: !!(websiteId && type), + }); +} + +export default useWebsiteValues; diff --git a/src/components/hooks/useFields.ts b/src/components/hooks/useFields.ts new file mode 100644 index 000000000..05d2b4588 --- /dev/null +++ b/src/components/hooks/useFields.ts @@ -0,0 +1,22 @@ +import { useMessages } from './useMessages'; + +export function useFields() { + const { formatMessage, labels } = useMessages(); + + const fields = [ + { name: 'url', type: 'string', label: formatMessage(labels.url) }, + { name: 'title', type: 'string', label: formatMessage(labels.pageTitle) }, + { name: 'referrer', type: 'string', label: formatMessage(labels.referrer) }, + { name: 'query', type: 'string', label: formatMessage(labels.query) }, + { name: 'browser', type: 'string', label: formatMessage(labels.browser) }, + { name: 'os', type: 'string', label: formatMessage(labels.os) }, + { name: 'device', type: 'string', label: formatMessage(labels.device) }, + { name: 'country', type: 'string', label: formatMessage(labels.country) }, + { name: 'region', type: 'string', label: formatMessage(labels.region) }, + { name: 'city', type: 'string', label: formatMessage(labels.city) }, + ]; + + return { fields }; +} + +export default useFields; diff --git a/src/components/messages.ts b/src/components/messages.ts index 4c5f5b86f..996aef6cd 100644 --- a/src/components/messages.ts +++ b/src/components/messages.ts @@ -148,6 +148,7 @@ export const labels = defineMessages({ url: { id: 'label.url', defaultMessage: 'URL' }, urls: { id: 'label.urls', defaultMessage: 'URLs' }, add: { id: 'label.add', defaultMessage: 'Add' }, + update: { id: 'label.update', defaultMessage: 'Update' }, window: { id: 'label.window', defaultMessage: 'Window' }, runQuery: { id: 'label.run-query', defaultMessage: 'Run query' }, field: { id: 'label.field', defaultMessage: 'Field' },