change(ui): apply session url series by default when switching on clickmap
This commit is contained in:
parent
7995e665cd
commit
41b8915bb3
3 changed files with 188 additions and 207 deletions
|
|
@ -3,126 +3,128 @@ import { metricOf, issueOptions } from 'App/constants/filterOptions';
|
|||
import { FilterKey } from 'Types/filter/filterType';
|
||||
import { useStore } from 'App/mstore';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { Button, Icon } from 'UI'
|
||||
import { Button, Icon } from 'UI';
|
||||
import FilterSeries from '../FilterSeries';
|
||||
import { confirm, Tooltip, Input } from 'UI';
|
||||
import Select from 'Shared/Select'
|
||||
import { withSiteId, dashboardMetricDetails, metricDetails } from 'App/routes'
|
||||
import Select from 'Shared/Select';
|
||||
import { withSiteId, dashboardMetricDetails, metricDetails } from 'App/routes';
|
||||
import MetricTypeDropdown from './components/MetricTypeDropdown';
|
||||
import MetricSubtypeDropdown from './components/MetricSubtypeDropdown';
|
||||
import { TIMESERIES, TABLE, CLICKMAP } from 'App/constants/card'
|
||||
import { pageUrlOperators } from 'App/constants/filterOptions'
|
||||
import { TIMESERIES, TABLE, CLICKMAP } from 'App/constants/card';
|
||||
import { pageUrlOperators } from 'App/constants/filterOptions';
|
||||
import FilterAutoComplete from 'Shared/Filters/FilterAutoComplete';
|
||||
import { clickmapFilter } from 'App/types/filter/newFilter';
|
||||
import { toJS } from 'mobx'
|
||||
import { toJS } from 'mobx';
|
||||
import { List } from 'immutable';
|
||||
|
||||
interface Props {
|
||||
history: any;
|
||||
match: any;
|
||||
onDelete: () => void;
|
||||
history: any;
|
||||
match: any;
|
||||
onDelete: () => void;
|
||||
}
|
||||
|
||||
const metricIcons = {
|
||||
timeseries: 'graph-up',
|
||||
table: 'table',
|
||||
funnel: 'funnel',
|
||||
}
|
||||
timeseries: 'graph-up',
|
||||
table: 'table',
|
||||
funnel: 'funnel',
|
||||
};
|
||||
|
||||
function WidgetForm(props: Props) {
|
||||
const {
|
||||
history,
|
||||
match: {
|
||||
params: { siteId, dashboardId },
|
||||
},
|
||||
} = props;
|
||||
const { metricStore, dashboardStore } = useStore();
|
||||
const isSaving = metricStore.isSaving;
|
||||
const metric: any = metricStore.instance;
|
||||
|
||||
const { history, match: { params: { siteId, dashboardId } } } = props;
|
||||
const { metricStore, dashboardStore } = useStore();
|
||||
const isSaving = metricStore.isSaving;
|
||||
const metric: any = metricStore.instance
|
||||
const timeseriesOptions = metricOf.filter((i) => i.type === 'timeseries');
|
||||
const tableOptions = metricOf.filter((i) => i.type === 'table');
|
||||
const isTable = metric.metricType === 'table';
|
||||
const isFunnel = metric.metricType === 'funnel';
|
||||
const canAddSeries = metric.series.length < 3;
|
||||
const eventsLength = metric.series[0].filter.filters.filter((i: any) => i.isEvent).length;
|
||||
const cannotSaveFunnel = isFunnel && (!metric.series[0] || eventsLength <= 1);
|
||||
|
||||
const timeseriesOptions = metricOf.filter(i => i.type === 'timeseries');
|
||||
const tableOptions = metricOf.filter(i => i.type === 'table');
|
||||
const isTable = metric.metricType === 'table';
|
||||
const isFunnel = metric.metricType === 'funnel';
|
||||
const canAddSeries = metric.series.length < 3;
|
||||
const eventsLength = metric.series[0].filter.filters.filter((i: any) => i.isEvent).length
|
||||
const cannotSaveFunnel = isFunnel && (!metric.series[0] || eventsLength <= 1);
|
||||
const writeOption = ({ value, name }: any) => {
|
||||
value = Array.isArray(value) ? value : value.value;
|
||||
const obj: any = { [name]: value };
|
||||
|
||||
const writeOption = ({ value, name }: any) => {
|
||||
value = Array.isArray(value) ? value : value.value
|
||||
const obj: any = { [ name ]: value };
|
||||
if (name === 'metricValue') {
|
||||
obj['metricValue'] = value;
|
||||
|
||||
if (name === 'metricValue') {
|
||||
obj['metricValue'] = value;
|
||||
|
||||
// handle issues (remove all when other option is selected)
|
||||
if (Array.isArray(obj['metricValue']) && obj['metricValue'].length > 1) {
|
||||
obj['metricValue'] = obj['metricValue'].filter(i => i.value !== 'all');
|
||||
}
|
||||
}
|
||||
|
||||
if (name === 'metricOf') {
|
||||
// if (value === FilterKey.ISSUE) {
|
||||
// obj['metricValue'] = [{ value: 'all', label: 'All' }];
|
||||
// }
|
||||
}
|
||||
|
||||
if (name === 'metricType') {
|
||||
if (value === TIMESERIES) {
|
||||
obj['metricOf'] = timeseriesOptions[0].value;
|
||||
obj['viewType'] = 'lineChart';
|
||||
} else if (value === TABLE) {
|
||||
obj['metricOf'] = tableOptions[0].value;
|
||||
obj['viewType'] = 'table';
|
||||
}
|
||||
if (value === CLICKMAP) {
|
||||
obj['viewType'] = 'chart'
|
||||
}
|
||||
}
|
||||
|
||||
metricStore.merge(obj);
|
||||
};
|
||||
|
||||
const onSelect = (_: any, option: Record<string, any>) => writeOption({ value: { value: option.value }, name: option.name})
|
||||
|
||||
const onSave = () => {
|
||||
const wasCreating = !metric.exists()
|
||||
metricStore.save(metric, dashboardId)
|
||||
.then((metric: any) => {
|
||||
if (wasCreating) {
|
||||
if (parseInt(dashboardId) > 0) {
|
||||
history.replace(withSiteId(dashboardMetricDetails(dashboardId, metric.metricId), siteId));
|
||||
const dashboard = dashboardStore.getDashboard(parseInt(dashboardId))
|
||||
dashboardStore.addWidgetToDashboard(dashboard, [metric.metricId])
|
||||
} else {
|
||||
history.replace(withSiteId(metricDetails(metric.metricId), siteId));
|
||||
}
|
||||
}
|
||||
});
|
||||
// handle issues (remove all when other option is selected)
|
||||
if (Array.isArray(obj['metricValue']) && obj['metricValue'].length > 1) {
|
||||
obj['metricValue'] = obj['metricValue'].filter((i) => i.value !== 'all');
|
||||
}
|
||||
}
|
||||
|
||||
const onDelete = async () => {
|
||||
if (await confirm({
|
||||
header: 'Confirm',
|
||||
confirmButton: 'Yes, delete',
|
||||
confirmation: `Are you sure you want to permanently delete this metric?`
|
||||
})) {
|
||||
metricStore.delete(metric).then(props.onDelete);
|
||||
}
|
||||
if (name === 'metricOf') {
|
||||
// if (value === FilterKey.ISSUE) {
|
||||
// obj['metricValue'] = [{ value: 'all', label: 'All' }];
|
||||
// }
|
||||
}
|
||||
const updateClickMapURL = (_, item) => {
|
||||
console.log('updating filter', item)
|
||||
const newValues = {
|
||||
value: item
|
||||
}
|
||||
metric.series[0].filter.updateFilter(0, newValues)
|
||||
console.log(toJS(metric.series))
|
||||
}
|
||||
console.log(metric.series, metric.series[0].filter)
|
||||
return (
|
||||
<div className="p-6">
|
||||
<div className="form-group">
|
||||
<label className="font-medium">Metric Type</label>
|
||||
<div className="flex items-center">
|
||||
<MetricTypeDropdown onSelect={writeOption} />
|
||||
<MetricSubtypeDropdown onSelect={writeOption} />
|
||||
|
||||
{/* {metric.metricType === 'timeseries' && (
|
||||
if (name === 'metricType') {
|
||||
if (value === TIMESERIES) {
|
||||
obj['metricOf'] = timeseriesOptions[0].value;
|
||||
obj['viewType'] = 'lineChart';
|
||||
} else if (value === TABLE) {
|
||||
obj['metricOf'] = tableOptions[0].value;
|
||||
obj['viewType'] = 'table';
|
||||
}
|
||||
if (value === CLICKMAP) {
|
||||
obj['viewType'] = 'chart';
|
||||
if (metric.series[0].filter.filters.length < 1) {
|
||||
metric.series[0].filter.addFilter({
|
||||
...clickmapFilter,
|
||||
value: [''],
|
||||
},)
|
||||
}
|
||||
}
|
||||
}
|
||||
metricStore.merge(obj);
|
||||
};
|
||||
|
||||
const onSave = () => {
|
||||
const wasCreating = !metric.exists();
|
||||
metricStore.save(metric, dashboardId).then((metric: any) => {
|
||||
if (wasCreating) {
|
||||
if (parseInt(dashboardId) > 0) {
|
||||
history.replace(withSiteId(dashboardMetricDetails(dashboardId, metric.metricId), siteId));
|
||||
const dashboard = dashboardStore.getDashboard(parseInt(dashboardId));
|
||||
dashboardStore.addWidgetToDashboard(dashboard, [metric.metricId]);
|
||||
} else {
|
||||
history.replace(withSiteId(metricDetails(metric.metricId), siteId));
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onDelete = async () => {
|
||||
if (
|
||||
await confirm({
|
||||
header: 'Confirm',
|
||||
confirmButton: 'Yes, delete',
|
||||
confirmation: `Are you sure you want to permanently delete this metric?`,
|
||||
})
|
||||
) {
|
||||
metricStore.delete(metric).then(props.onDelete);
|
||||
}
|
||||
};
|
||||
|
||||
console.log(toJS(metric));
|
||||
return (
|
||||
<div className="p-6">
|
||||
<div className="form-group">
|
||||
<label className="font-medium">Metric Type</label>
|
||||
<div className="flex items-center">
|
||||
<MetricTypeDropdown onSelect={writeOption} />
|
||||
<MetricSubtypeDropdown onSelect={writeOption} />
|
||||
|
||||
{/* {metric.metricType === 'timeseries' && (
|
||||
<>
|
||||
<span className="mx-3">of</span>
|
||||
<Select
|
||||
|
|
@ -134,7 +136,7 @@ function WidgetForm(props: Props) {
|
|||
</>
|
||||
)} */}
|
||||
|
||||
{/* {metric.metricType === 'table' && (
|
||||
{/* {metric.metricType === 'table' && (
|
||||
<>
|
||||
<span className="mx-3">of</span>
|
||||
<Select
|
||||
|
|
@ -146,113 +148,92 @@ function WidgetForm(props: Props) {
|
|||
</>
|
||||
)} */}
|
||||
|
||||
{metric.metricOf === FilterKey.ISSUE && (
|
||||
<>
|
||||
<span className="mx-3">issue type</span>
|
||||
<Select
|
||||
name="metricValue"
|
||||
options={issueOptions}
|
||||
value={metric.metricValue}
|
||||
onChange={ writeOption }
|
||||
isMulti={true}
|
||||
placeholder="All Issues"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{metric.metricOf === FilterKey.ISSUE && (
|
||||
<>
|
||||
<span className="mx-3">issue type</span>
|
||||
<Select
|
||||
name="metricValue"
|
||||
options={issueOptions}
|
||||
value={metric.metricValue}
|
||||
onChange={writeOption}
|
||||
isMulti={true}
|
||||
placeholder="All Issues"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{metric.metricType === 'table' && !(metric.metricOf === FilterKey.ERRORS || metric.metricOf === FilterKey.SESSIONS) && (
|
||||
<>
|
||||
<span className="mx-3">showing</span>
|
||||
<Select
|
||||
name="metricFormat"
|
||||
options={[
|
||||
{ value: 'sessionCount', label: 'Session Count' },
|
||||
]}
|
||||
defaultValue={ metric.metricFormat }
|
||||
onChange={ writeOption }
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{metric.metricType === CLICKMAP && (
|
||||
<div className='flex items-center'>
|
||||
<div className="mx-3">Where Visited URL</div>
|
||||
<Select name="clickMapUrl"
|
||||
options={pageUrlOperators.reverse()}
|
||||
defaultValue={pageUrlOperators.reverse()[0].value}
|
||||
onChange={ () => null }
|
||||
/>
|
||||
{/* <Input placeholder="Enter URL or path to select"
|
||||
/> */}
|
||||
<FilterAutoComplete
|
||||
value={metric.series[0].filter.filters[0]?.value || ''} // ?
|
||||
endpoint="/events/search"
|
||||
params={{ type: clickmapFilter.key }}
|
||||
headerText={''}
|
||||
placeholder={clickmapFilter.placeholder}
|
||||
onSelect={updateClickMapURL}
|
||||
icon={clickmapFilter.icon}
|
||||
hideOrText
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<div className="flex items-center font-medium py-2">
|
||||
{`${(isTable || isFunnel) ? 'Filter by' : 'Chart Series'}`}
|
||||
{!isTable && !isFunnel && (
|
||||
<Button
|
||||
className="ml-2"
|
||||
variant="text-primary"
|
||||
onClick={() => metric.addSeries()}
|
||||
disabled={!canAddSeries}
|
||||
>ADD</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{metric.series.length > 0 && metric.series.slice(0, (isTable || isFunnel) ? 1 : metric.series.length).map((series: any, index: number) => (
|
||||
<div className="mb-2" key={series.name}>
|
||||
<FilterSeries
|
||||
observeChanges={() => metric.updateKey('hasChanged', true)}
|
||||
hideHeader={ isTable }
|
||||
seriesIndex={index}
|
||||
series={series}
|
||||
onRemoveSeries={() => metric.removeSeries(index)}
|
||||
canDelete={metric.series.length > 1}
|
||||
emptyMessage={isTable ?
|
||||
'Filter data using any event or attribute. Use Add Step button below to do so.' :
|
||||
'Add user event or filter to define the series by clicking Add Step.'
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="form-groups flex items-center justify-between">
|
||||
<Tooltip
|
||||
title="Cannot save funnel metric without at least 2 events"
|
||||
disabled={!cannotSaveFunnel}
|
||||
>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={onSave}
|
||||
disabled={isSaving || cannotSaveFunnel}
|
||||
>
|
||||
{metric.exists() ? 'Update' : 'Create'}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<div className="flex items-center">
|
||||
{metric.exists() && (
|
||||
<Button variant="text-primary" onClick={onDelete}>
|
||||
<Icon name="trash" size="14" className="mr-2" color="teal"/>
|
||||
Delete
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{metric.metricType === 'table' &&
|
||||
!(metric.metricOf === FilterKey.ERRORS || metric.metricOf === FilterKey.SESSIONS) && (
|
||||
<>
|
||||
<span className="mx-3">showing</span>
|
||||
<Select
|
||||
name="metricFormat"
|
||||
options={[{ value: 'sessionCount', label: 'Session Count' }]}
|
||||
defaultValue={metric.metricFormat}
|
||||
onChange={writeOption}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<div className="flex items-center font-medium py-2">
|
||||
{`${isTable || isFunnel ? 'Filter by' : 'Chart Series'}`}
|
||||
{!isTable && !isFunnel && (
|
||||
<Button
|
||||
className="ml-2"
|
||||
variant="text-primary"
|
||||
onClick={() => metric.addSeries()}
|
||||
disabled={!canAddSeries}
|
||||
>
|
||||
ADD
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{metric.series.length > 0 &&
|
||||
metric.series
|
||||
.slice(0, isTable || isFunnel ? 1 : metric.series.length)
|
||||
.map((series: any, index: number) => (
|
||||
<div className="mb-2" key={series.name}>
|
||||
<FilterSeries
|
||||
observeChanges={() => metric.updateKey('hasChanged', true)}
|
||||
hideHeader={isTable}
|
||||
seriesIndex={index}
|
||||
series={series}
|
||||
onRemoveSeries={() => metric.removeSeries(index)}
|
||||
canDelete={metric.series.length > 1}
|
||||
emptyMessage={
|
||||
isTable
|
||||
? 'Filter data using any event or attribute. Use Add Step button below to do so.'
|
||||
: 'Add user event or filter to define the series by clicking Add Step.'
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="form-groups flex items-center justify-between">
|
||||
<Tooltip
|
||||
title="Cannot save funnel metric without at least 2 events"
|
||||
disabled={!cannotSaveFunnel}
|
||||
>
|
||||
<Button variant="primary" onClick={onSave} disabled={isSaving || cannotSaveFunnel}>
|
||||
{metric.exists() ? 'Update' : 'Create'}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<div className="flex items-center">
|
||||
{metric.exists() && (
|
||||
<Button variant="text-primary" onClick={onDelete}>
|
||||
<Icon name="trash" size="14" className="mr-2" color="teal" />
|
||||
Delete
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default observer(WidgetForm);
|
||||
|
|
|
|||
|
|
@ -275,5 +275,5 @@ export enum FilterKey {
|
|||
RESOURCE_FETCH_TIME = 'resourceFetchTime',
|
||||
SLOWEST_RESOURCES = 'slowestResources',
|
||||
|
||||
CLICKMAP_URL = 'clickmapUrl'
|
||||
CLICKMAP_URL = 'clickMapUrl'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ export const clickmapFilter = {
|
|||
key: FilterKey.LOCATION,
|
||||
type: FilterType.MULTIPLE,
|
||||
category: FilterCategory.INTERACTIONS,
|
||||
label: '', placeholder: 'Enter URL or path to select', operator: 'is', operatorOptions: filterOptions.pageUrlOperators, icon: 'filters/location', isEvent: true }
|
||||
label: 'Visited URL', placeholder: 'Enter URL or path to select', operator: filterOptions.pageUrlOperators[0].value, operatorOptions: filterOptions.pageUrlOperators, icon: 'filters/location', isEvent: true }
|
||||
|
||||
const mapFilters = (list) => {
|
||||
return list.reduce((acc, filter) => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue