feat(ui) - funnels - fitler dropdowns to select

This commit is contained in:
Shekar Siri 2022-05-16 16:26:16 +02:00
parent 97da3f5c1c
commit baa6c916dc
5 changed files with 109 additions and 66 deletions

View file

@ -7,6 +7,7 @@ import { useObserver } from 'mobx-react-lite';
import { Button, Icon } from 'UI'
import FilterSeries from '../FilterSeries';
import { confirm } from 'UI/Confirmation';
import Select from 'Shared/Select'
import { withSiteId, dashboardMetricDetails, metricDetails } from 'App/routes'
import DashboardSelectionModal from '../DashboardSelectionModal/DashboardSelectionModal';
@ -22,18 +23,20 @@ function WidgetForm(props: Props) {
const { metricStore, dashboardStore } = useStore();
const dashboards = dashboardStore.dashboards;
const isSaving = useObserver(() => metricStore.isSaving);
const metric: any = useObserver(() => metricStore.instance);
const metric: any = useObserver(() => 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 _issueOptions = [{ text: 'All', value: 'all' }].concat(issueOptions);
const isErrors = metric.metricType === 'errors';
const isSessions = metric.metricType === 'sessions';
const _issueOptions = [{ label: 'All', value: 'all' }].concat(issueOptions);
const canAddToDashboard = metric.exists() && dashboards.length > 0;
const canAddSeries = metric.series.length < 3;
const write = ({ target: { value, name } }) => metricStore.merge({ [ name ]: value });
const writeOption = (e, { value, name }) => {
// const write = ({ target: { value, name } }) => metricStore.merge({ [ name ]: value });
const writeOption = ({ value: { value }, name }) => {
const obj = { [ name ]: value };
if (name === 'metricValue') {
@ -86,66 +89,98 @@ function WidgetForm(props: Props) {
const onObserveChanges = () => {
// metricStore.fetchMetricChartData(metric);
}
return useObserver(() => (
<div className="p-6">
<div className="form-group">
<label className="font-medium">Metric Type</label>
<div className="flex items-center">
<DropdownPlain
<Select
name="metricType"
options={metricTypes}
value={metricTypes.find(i => i.value === metric.metricType) || metricTypes[0]}
onChange={ writeOption }
/>
{/* <DropdownPlain
name="metricType"
options={metricTypes}
value={ metric.metricType }
onChange={ writeOption }
/>
/> */}
{metric.metricType === 'timeseries' && (
<>
<span className="mx-3">of</span>
<DropdownPlain
<Select
name="metricOf"
options={timeseriesOptions}
defaultValue={metric.metricOf}
onChange={ writeOption }
/>
{/* <DropdownPlain
name="metricOf"
options={timeseriesOptions}
value={ metric.metricOf }
onChange={ writeOption }
/>
/> */}
</>
)}
{metric.metricType === 'table' && (
<>
<span className="mx-3">of</span>
<DropdownPlain
<Select
name="metricOf"
options={tableOptions}
defaultValue={metric.metricOf}
onChange={ writeOption }
/>
{/* <DropdownPlain
name="metricOf"
options={tableOptions}
value={ metric.metricOf }
onChange={ writeOption }
/>
/> */}
</>
)}
{metric.metricOf === FilterKey.ISSUE && (
<>
<span className="mx-3">issue type</span>
<DropdownPlain
<Select
name="metricValue"
options={_issueOptions}
defaultValue={metric.metricValue[0]}
onChange={ writeOption }
/>
{/* <DropdownPlain
name="metricValue"
options={_issueOptions}
value={ metric.metricValue[0] }
onChange={ writeOption }
/>
/> */}
</>
)}
{metric.metricType === 'table' && (
<>
<span className="mx-3">showing</span>
<DropdownPlain
<Select
name="metricFormat"
options={[
{ value: 'sessionCount', label: 'Session Count' },
]}
defaultValue={ metric.metricFormat }
onChange={ writeOption }
/>
{/* <DropdownPlain
name="metricFormat"
options={[
{ value: 'sessionCount', text: 'Session Count' },
]}
value={ metric.metricFormat }
onChange={ writeOption }
/>
/> */}
</>
)}
</div>

View file

@ -10,9 +10,11 @@ interface Props {
plain?: boolean;
components?: any;
styles?: any;
onChange: (value: any) => void;
name?: string;
[x:string]: any;
}
export default function({ styles= {}, alignRight = false, plain = false, options, isSearchable = false, components = {}, defaultValue = '', ...rest }: Props) {
export default function({ name = '', onChange, styles= {}, alignRight = false, plain = false, options, isSearchable = false, components = {}, defaultValue = '', ...rest }: Props) {
const defaultSelected = defaultValue ? options.find(x => x.value === defaultValue) : null;
const customStyles = {
@ -54,6 +56,10 @@ export default function({ styles= {}, alignRight = false, plain = false, options
border: 'solid thin #ddd',
cursor: 'pointer',
transition: 'all 0.5s',
['&:hover']: {
backgroundColor: colors['gray-lightest'],
transition: 'all 0.2s ease-in-out'
}
}
if (plain) {
obj['border'] = '1px solid transparent'
@ -100,6 +106,7 @@ export default function({ styles= {}, alignRight = false, plain = false, options
DropdownIndicator,
...components,
}}
onChange={(value) => onChange({ name, value: value })}
styles={{ ...customStyles, ...styles }}
theme={(theme) => ({
...theme,

View file

@ -60,10 +60,11 @@ export const customOperators = [
]
export const metricTypes = [
{ text: 'Timeseries', value: 'timeseries' },
{ text: 'Table', value: 'table' },
{ text: 'Funnel', value: 'funnel' },
{ text: 'Error', value: 'error' },
{ label: 'Timeseries', value: 'timeseries' },
{ label: 'Table', value: 'table' },
{ label: 'Funnel', value: 'funnel' },
{ label: 'Errors', value: 'errors' },
{ label: 'Sessions', value: 'sessions' },
];
export const tableColumnName = {
@ -76,13 +77,13 @@ export const tableColumnName = {
}
export const metricOf = [
{ text: 'Session Count', value: 'sessionCount', type: 'timeseries' },
{ text: 'Users', value: FilterKey.USERID, type: 'table' },
{ text: 'Issues', value: FilterKey.ISSUE, type: 'table' },
{ text: 'Browsers', value: FilterKey.USER_BROWSER, type: 'table' },
{ text: 'Devices', value: FilterKey.USER_DEVICE, type: 'table' },
{ text: 'Countries', value: FilterKey.USER_COUNTRY, type: 'table' },
{ text: 'URLs', value: FilterKey.LOCATION, type: 'table' },
{ label: 'Session Count', value: 'sessionCount', type: 'timeseries' },
{ label: 'Users', value: FilterKey.USERID, type: 'table' },
{ label: 'Issues', value: FilterKey.ISSUE, type: 'table' },
{ label: 'Browsers', value: FilterKey.USER_BROWSER, type: 'table' },
{ label: 'Devices', value: FilterKey.USER_DEVICE, type: 'table' },
{ label: 'Countries', value: FilterKey.USER_COUNTRY, type: 'table' },
{ label: 'URLs', value: FilterKey.LOCATION, type: 'table' },
]
export const methodOptions = [
@ -98,18 +99,18 @@ export const methodOptions = [
]
export const issueOptions = [
{ text: 'Click Rage', value: IssueType.CLICK_RAGE },
{ text: 'Dead Click', value: IssueType.DEAD_CLICK },
{ text: 'Excessive Scrolling', value: IssueType.EXCESSIVE_SCROLLING },
{ text: 'Bad Request', value: IssueType.BAD_REQUEST },
{ text: 'Missing Resource', value: IssueType.MISSING_RESOURCE },
{ text: 'Memory', value: IssueType.MEMORY },
{ text: 'CPU', value: IssueType.CPU },
{ text: 'Slow Resource', value: IssueType.SLOW_RESOURCE },
{ text: 'Slow Page Load', value: IssueType.SLOW_PAGE_LOAD },
{ text: 'Crash', value: IssueType.CRASH },
{ text: 'Custom', value: IssueType.CUSTOM },
{ text: 'Error', value: IssueType.JS_EXCEPTION },
{ label: 'Click Rage', value: IssueType.CLICK_RAGE },
{ label: 'Dead Click', value: IssueType.DEAD_CLICK },
{ label: 'Excessive Scrolling', value: IssueType.EXCESSIVE_SCROLLING },
{ label: 'Bad Request', value: IssueType.BAD_REQUEST },
{ label: 'Missing Resource', value: IssueType.MISSING_RESOURCE },
{ label: 'Memory', value: IssueType.MEMORY },
{ label: 'CPU', value: IssueType.CPU },
{ label: 'Slow Resource', value: IssueType.SLOW_RESOURCE },
{ label: 'Slow Page Load', value: IssueType.SLOW_PAGE_LOAD },
{ label: 'Crash', value: IssueType.CRASH },
{ label: 'Custom', value: IssueType.CUSTOM },
{ label: 'Error', value: IssueType.JS_EXCEPTION },
]
export default {

View file

@ -90,7 +90,7 @@ export default class MetricStore implements IMetricStore {
// State Actions
init(metric?: IWidget|null) {
const _metric = new Widget().fromJson(sampleJson)
const _metric = new Widget().fromJson(sampleJsonErrors)
this.instance.update(metric || _metric)
// this.instance.update(metric || new Widget())
@ -191,7 +191,7 @@ export default class MetricStore implements IMetricStore {
}
}
const sampleJson = {
const sampleJsonFunnel = {
// metricId: 1,
name: "Funnel Sample",
metricType: 'funnel',
@ -199,31 +199,31 @@ const sampleJson = {
{
name: 'Series 1',
filter: {
eventsOrder: 'then',
filters: [
{
type: 'LOCATION',
operator: 'is',
value: ['/sessions', '/errors', '/users'],
percent: 100,
completed: 60,
dropped: 40,
},
{
type: 'LOCATION',
operator: 'is',
value: ['/sessions'],
percent: 80,
completed: 40,
dropped: 60,
},
{
type: 'CLICK',
operator: 'on',
value: ['DASHBOARDS'],
percent: 80,
completed: 10,
dropped: 90,
}
{ type: 'LOCATION', operator: 'is', value: ['/sessions', '/errors', '/users'], percent: 100, completed: 60, dropped: 40, },
{ type: 'LOCATION', operator: 'is', value: ['/sessions'], percent: 80, completed: 40, dropped: 60, },
{ type: 'CLICK', operator: 'on', value: ['DASHBOARDS'], percent: 80, completed: 10, dropped: 90, }
]
}
}
],
}
const sampleJsonErrors = {
// metricId: 1,
name: "Errors Sample",
metricType: 'errors',
metricFormat: 'sessionCount',
series: [
{
name: 'Series 1',
filter: {
eventsOrder: 'then',
filters: [
{ type: 'LOCATION', operator: 'is', value: ['/sessions', '/errors', '/users'], percent: 100, completed: 60, dropped: 40, },
{ type: 'LOCATION', operator: 'is', value: ['/sessions'], percent: 80, completed: 40, dropped: 60, },
{ type: 'CLICK', operator: 'on', value: ['DASHBOARDS'], percent: 80, completed: 10, dropped: 90, }
]
}
}

View file

@ -138,7 +138,7 @@ export default class Widget implements IWidget {
this.viewType = json.viewType
this.name = json.name
this.series = json.series ? json.series.map((series: any) => new FilterSeries().fromJson(series)) : [],
this.dashboards = json.dashboards
this.dashboards = json.dashboards || []
this.owner = json.ownerEmail
this.lastModified = json.editedAt || json.createdAt ? DateTime.fromMillis(json.editedAt || json.createdAt) : null
this.config = json.config