feat(ui) - url search - read query params
This commit is contained in:
parent
f0d5238b65
commit
a8760279b9
5 changed files with 252 additions and 93 deletions
|
|
@ -1,68 +1,23 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import React from 'react';
|
||||
import FilterList from 'Shared/Filters/FilterList';
|
||||
import FilterSelection from 'Shared/Filters/FilterSelection';
|
||||
import SaveFilterButton from 'Shared/SaveFilterButton';
|
||||
import { connect } from 'react-redux';
|
||||
import { Button } from 'UI';
|
||||
import { edit, addFilter } from 'Duck/search';
|
||||
import { withRouter } from 'react-router';
|
||||
import { clearSearch, fetchSessions, addFilterByKeyAndValue } from 'Duck/search';
|
||||
import { FilterKey, getFilterKeyTypeByKey } from 'Types/filter/filterType';
|
||||
|
||||
const allowedQueryKeys = [
|
||||
'userOs',
|
||||
'userId',
|
||||
'userBrowser',
|
||||
'userDevice',
|
||||
'userCountry',
|
||||
'startDate',
|
||||
'endDate',
|
||||
'minDuration',
|
||||
'maxDuration',
|
||||
'referrer',
|
||||
'sort',
|
||||
'order',
|
||||
];
|
||||
import SessionSearchQueryParamHandler from 'Shared/SessionSearchQueryParamHandler';
|
||||
|
||||
interface Props {
|
||||
appliedFilter: any;
|
||||
edit: typeof edit;
|
||||
addFilter: typeof addFilter;
|
||||
saveRequestPayloads: boolean;
|
||||
location: any;
|
||||
addFilterByKeyAndValue: typeof addFilterByKeyAndValue;
|
||||
}
|
||||
function SessionSearch(props: Props) {
|
||||
const {
|
||||
appliedFilter,
|
||||
saveRequestPayloads = false,
|
||||
location: { search },
|
||||
} = props;
|
||||
const { appliedFilter, saveRequestPayloads = false } = props;
|
||||
const hasEvents = appliedFilter.filters.filter((i: any) => i.isEvent).size > 0;
|
||||
const hasFilters = appliedFilter.filters.filter((i: any) => !i.isEvent).size > 0;
|
||||
|
||||
useEffect(() => {
|
||||
const queryParams = Object.fromEntries(
|
||||
Object.entries(Object.fromEntries(new URLSearchParams(search))).filter(([key]) =>
|
||||
allowedQueryKeys.includes(key)
|
||||
)
|
||||
);
|
||||
const entires = Object.entries(queryParams);
|
||||
if (entires.length > 0) {
|
||||
entires.forEach(([key, value]) => {
|
||||
if (value !== '') {
|
||||
const filterKey = getFilterKeyTypeByKey(key);
|
||||
const valueArr = value.split('|');
|
||||
const operator = valueArr.shift();
|
||||
console.log('operator', operator, valueArr);
|
||||
if (filterKey) {
|
||||
props.addFilterByKeyAndValue(filterKey, valueArr, operator);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onAddFilter = (filter: any) => {
|
||||
props.addFilter(filter);
|
||||
};
|
||||
|
|
@ -98,48 +53,51 @@ function SessionSearch(props: Props) {
|
|||
});
|
||||
};
|
||||
|
||||
return hasEvents || hasFilters ? (
|
||||
<div className="border bg-white rounded mt-4">
|
||||
<div className="p-5">
|
||||
<FilterList
|
||||
filter={appliedFilter}
|
||||
onUpdateFilter={onUpdateFilter}
|
||||
onRemoveFilter={onRemoveFilter}
|
||||
onChangeEventsOrder={onChangeEventsOrder}
|
||||
saveRequestPayloads={saveRequestPayloads}
|
||||
/>
|
||||
</div>
|
||||
return (
|
||||
<>
|
||||
<SessionSearchQueryParamHandler />
|
||||
{hasEvents || hasFilters ? (
|
||||
<div className="border bg-white rounded mt-4">
|
||||
<div className="p-5">
|
||||
<FilterList
|
||||
filter={appliedFilter}
|
||||
onUpdateFilter={onUpdateFilter}
|
||||
onRemoveFilter={onRemoveFilter}
|
||||
onChangeEventsOrder={onChangeEventsOrder}
|
||||
saveRequestPayloads={saveRequestPayloads}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="border-t px-5 py-1 flex items-center -mx-2">
|
||||
<div>
|
||||
<FilterSelection filter={undefined} onFilterClick={onAddFilter}>
|
||||
{/* <IconButton primaryText label="ADD STEP" icon="plus" /> */}
|
||||
<Button
|
||||
variant="text-primary"
|
||||
className="mr-2"
|
||||
// onClick={() => setshowModal(true)}
|
||||
icon="plus"
|
||||
>
|
||||
ADD STEP
|
||||
</Button>
|
||||
</FilterSelection>
|
||||
<div className="border-t px-5 py-1 flex items-center -mx-2">
|
||||
<div>
|
||||
<FilterSelection filter={undefined} onFilterClick={onAddFilter}>
|
||||
{/* <IconButton primaryText label="ADD STEP" icon="plus" /> */}
|
||||
<Button
|
||||
variant="text-primary"
|
||||
className="mr-2"
|
||||
// onClick={() => setshowModal(true)}
|
||||
icon="plus"
|
||||
>
|
||||
ADD STEP
|
||||
</Button>
|
||||
</FilterSelection>
|
||||
</div>
|
||||
<div className="ml-auto flex items-center">
|
||||
<SaveFilterButton />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="ml-auto flex items-center">
|
||||
<SaveFilterButton />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default withRouter(
|
||||
connect(
|
||||
(state: any) => ({
|
||||
saveRequestPayloads: state.getIn(['site', 'active', 'saveRequestPayloads']),
|
||||
appliedFilter: state.getIn(['search', 'instance']),
|
||||
}),
|
||||
{ edit, addFilter, addFilterByKeyAndValue }
|
||||
)(SessionSearch)
|
||||
);
|
||||
export default connect(
|
||||
(state: any) => ({
|
||||
saveRequestPayloads: state.getIn(['site', 'active', 'saveRequestPayloads']),
|
||||
appliedFilter: state.getIn(['search', 'instance']),
|
||||
}),
|
||||
{ edit, addFilter }
|
||||
)(SessionSearch);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,111 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import { useHistory } from 'react-router';
|
||||
import { connect } from 'react-redux';
|
||||
import { addFilterByKeyAndValue } from 'Duck/search';
|
||||
import { getFilterKeyTypeByKey, setQueryParamKeyFromFilterkey } from 'Types/filter/filterType';
|
||||
|
||||
const allowedQueryKeys = [
|
||||
'userId',
|
||||
'userid',
|
||||
'uid',
|
||||
'usera',
|
||||
|
||||
'clk',
|
||||
'inp',
|
||||
'loc',
|
||||
|
||||
'os',
|
||||
'browser',
|
||||
'device',
|
||||
'platform',
|
||||
'revid',
|
||||
|
||||
'country',
|
||||
|
||||
// 'startDate',
|
||||
// 'endDate',
|
||||
// 'minDuration',
|
||||
// 'maxDuration',
|
||||
'ref',
|
||||
'sort',
|
||||
'order',
|
||||
'ce',
|
||||
'sa',
|
||||
'err',
|
||||
'iss',
|
||||
|
||||
// PERFORMANCE
|
||||
'domc',
|
||||
'lcp',
|
||||
'ttfb',
|
||||
'acpu',
|
||||
'amem',
|
||||
'ff',
|
||||
];
|
||||
|
||||
interface Props {
|
||||
appliedFilter: any;
|
||||
addFilterByKeyAndValue: typeof addFilterByKeyAndValue;
|
||||
}
|
||||
function SessionSearchQueryParamHandler(props: Props) {
|
||||
const { appliedFilter } = props;
|
||||
const history = useHistory();
|
||||
|
||||
const createUrlQuery = (filters: any) => {
|
||||
const query: any = {};
|
||||
filters.forEach((filter: any) => {
|
||||
if (filter.value.length > 0) {
|
||||
const _key = setQueryParamKeyFromFilterkey(filter.key);
|
||||
query[_key] = `${filter.operator}|${filter.value.join('|')}`;
|
||||
}
|
||||
});
|
||||
return query;
|
||||
};
|
||||
|
||||
const addFilter = ([key, value]: [string, string]): void => {
|
||||
if (value !== '') {
|
||||
const filterKey = getFilterKeyTypeByKey(key);
|
||||
const valueArr = value.split('|');
|
||||
const operator = valueArr.shift();
|
||||
// TODO validate operator
|
||||
if (filterKey) {
|
||||
props.addFilterByKeyAndValue(filterKey, valueArr, operator);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const applyFilterFromQuery = () => {
|
||||
const entires = getQueryObject(history.location.search);
|
||||
console.log('entires', entires);
|
||||
if (entires.length > 0) {
|
||||
entires.forEach(addFilter);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
console.log('rerender');
|
||||
applyFilterFromQuery();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const query: any = createUrlQuery(appliedFilter.filters);
|
||||
history.replace({ search: new URLSearchParams(query).toString() });
|
||||
}, [appliedFilter]);
|
||||
return <></>;
|
||||
}
|
||||
|
||||
export default connect(
|
||||
(state: any) => ({
|
||||
appliedFilter: state.getIn(['search', 'instance']),
|
||||
}),
|
||||
{ addFilterByKeyAndValue }
|
||||
)(SessionSearchQueryParamHandler);
|
||||
|
||||
function getQueryObject(search: any) {
|
||||
const queryParams = Object.fromEntries(
|
||||
Object.entries(Object.fromEntries(new URLSearchParams(search))).filter(([key]) =>
|
||||
allowedQueryKeys.includes(key)
|
||||
)
|
||||
);
|
||||
return Object.entries(queryParams);
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
export { default } from './SessionSearchQueryParamHandler';
|
||||
|
|
@ -8,18 +8,107 @@ export enum FilterCategory {
|
|||
PERFORMANCE = 'Performance',
|
||||
}
|
||||
|
||||
export const setQueryParamKeyFromFilterkey = (filterKey: string) => {
|
||||
switch (filterKey) {
|
||||
case FilterKey.USERID:
|
||||
return 'uid';
|
||||
case FilterKey.USERANONYMOUSID:
|
||||
return 'usera';
|
||||
case FilterKey.CLICK:
|
||||
return 'clk';
|
||||
case FilterKey.INPUT:
|
||||
return 'inp';
|
||||
case FilterKey.LOCATION:
|
||||
return 'loc';
|
||||
case FilterKey.USER_OS:
|
||||
return 'os';
|
||||
case FilterKey.USER_BROWSER:
|
||||
return 'browser';
|
||||
case FilterKey.USER_DEVICE:
|
||||
return 'device';
|
||||
case FilterKey.PLATFORM:
|
||||
return 'platform';
|
||||
case FilterKey.REVID:
|
||||
return 'revid';
|
||||
case FilterKey.USER_COUNTRY:
|
||||
return 'country';
|
||||
case FilterKey.REFERRER:
|
||||
return 'ref';
|
||||
case FilterKey.CUSTOM:
|
||||
return 'ce';
|
||||
case FilterKey.STATEACTION:
|
||||
return 'sa';
|
||||
case FilterKey.ERROR:
|
||||
return 'err';
|
||||
case FilterKey.ISSUE:
|
||||
return 'iss';
|
||||
|
||||
// PERFORMANCE
|
||||
case FilterKey.DOM_COMPLETE:
|
||||
return 'domc';
|
||||
case FilterKey.LARGEST_CONTENTFUL_PAINT_TIME:
|
||||
return 'lcp';
|
||||
case FilterKey.TTFB:
|
||||
return 'ttfb';
|
||||
case FilterKey.AVG_CPU_LOAD:
|
||||
return 'acpu';
|
||||
case FilterKey.AVG_MEMORY_USAGE:
|
||||
return 'amem';
|
||||
case FilterKey.FETCH_FAILED:
|
||||
return 'ff';
|
||||
}
|
||||
};
|
||||
|
||||
export const getFilterKeyTypeByKey = (key: string) => {
|
||||
switch (key) {
|
||||
case 'userId':
|
||||
case 'uid':
|
||||
case 'userid':
|
||||
return FilterKey.USERID;
|
||||
case 'userOs':
|
||||
case 'usera':
|
||||
return FilterKey.USERANONYMOUSID;
|
||||
case 'clk':
|
||||
return FilterKey.CLICK;
|
||||
case 'inp':
|
||||
return FilterKey.INPUT;
|
||||
case 'loc':
|
||||
return FilterKey.LOCATION;
|
||||
case 'os':
|
||||
return FilterKey.USER_OS;
|
||||
case 'userBrowser':
|
||||
case 'browser':
|
||||
return FilterKey.USER_BROWSER;
|
||||
case 'userDevice':
|
||||
case 'device':
|
||||
return FilterKey.USER_DEVICE;
|
||||
case 'userCountry':
|
||||
case 'platform':
|
||||
return FilterKey.PLATFORM;
|
||||
case 'revid':
|
||||
return FilterKey.REVID;
|
||||
case 'country':
|
||||
return FilterKey.USER_COUNTRY;
|
||||
case 'ref':
|
||||
return FilterKey.REFERRER;
|
||||
case 'ce':
|
||||
return FilterKey.CUSTOM;
|
||||
case 'sa':
|
||||
return FilterKey.STATEACTION;
|
||||
case 'err':
|
||||
return FilterKey.ERROR;
|
||||
case 'iss':
|
||||
return FilterKey.ISSUE;
|
||||
|
||||
// PERFORMANCE
|
||||
case 'domc':
|
||||
return FilterKey.DOM_COMPLETE;
|
||||
case 'lcp':
|
||||
return FilterKey.LARGEST_CONTENTFUL_PAINT_TIME;
|
||||
case 'ttfb':
|
||||
return FilterKey.TTFB;
|
||||
case 'acpu':
|
||||
return FilterKey.AVG_CPU_LOAD;
|
||||
case 'amem':
|
||||
return FilterKey.AVG_MEMORY_USAGE;
|
||||
case 'ff':
|
||||
return FilterKey.FETCH_FAILED;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export const filters = [
|
|||
{ key: FilterKey.INPUT, type: FilterType.MULTIPLE, category: FilterCategory.INTERACTIONS, label: 'Input', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/input', isEvent: true },
|
||||
{ key: FilterKey.LOCATION, type: FilterType.MULTIPLE, category: FilterCategory.INTERACTIONS, label: 'Path', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/location', isEvent: true },
|
||||
{ key: FilterKey.CUSTOM, type: FilterType.MULTIPLE, category: FilterCategory.JAVASCRIPT, label: 'Custom Events', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/custom', isEvent: true },
|
||||
{ key: FilterKey.REQUEST, type: FilterType.MULTIPLE, category: FilterCategory.JAVASCRIPT, label: 'Fetch', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch', isEvent: true },
|
||||
// { key: FilterKey.REQUEST, type: FilterType.MULTIPLE, category: FilterCategory.JAVASCRIPT, label: 'Fetch', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch', isEvent: true },
|
||||
{ key: FilterKey.FETCH, type: FilterType.SUB_FILTERS, category: FilterCategory.JAVASCRIPT, operator: 'is', label: 'Network Request', filters: [
|
||||
{ key: FilterKey.FETCH_URL, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'with URL', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch' },
|
||||
{ key: FilterKey.FETCH_STATUS_CODE, type: FilterType.NUMBER_MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'with status code', operator: '=', operatorOptions: filterOptions.customOperators, icon: 'filters/fetch' },
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue