feat(ui) - network request

This commit is contained in:
Shekar Siri 2022-03-04 20:22:22 +01:00
parent 1de8f42dd2
commit 755d947775
12 changed files with 113 additions and 55 deletions

View file

@ -33,9 +33,6 @@ function SideMenuSection({ title, items, onItemClick, setShowAlerts, siteId }) {
<div className={stl.divider} />
<div className="my-3">
<CustomMetrics />
<div className="color-gray-medium mt-2">
Be proactive by monitoring the metrics you care about the most.
</div>
</div>
</>
);

View file

@ -17,7 +17,7 @@ function CustomMetricPieChart(props: Props) {
const { metric, data = { values: [] }, onClick = () => null } = props;
const onClickHandler = (event) => {
if (event) {
if (event && !event.payload.group) {
const filters = Array<any>();
let filter = { ...filtersMap[metric.metricOf] }
filter.value = [event.payload.name]
@ -91,6 +91,8 @@ function CustomMetricPieChart(props: Props) {
let x = cx + radius * Math.cos(-midAngle * RADIAN);
let y = cy + radius * Math.sin(-midAngle * RADIAN);
const percentage = (value / data.values.reduce((a, b) => a + b.sessionCount, 0)) * 100;
let name = data.values[index].name || 'Unidentified';
name = name.length > 20 ? name.substring(0, 20) + '...' : name;
if (percentage<3){
return null;
}
@ -105,7 +107,7 @@ function CustomMetricPieChart(props: Props) {
dominantBaseline="central"
fill='#666'
>
{data.values[index].name} - ({value})
{name || 'Unidentified'} {value}
</text>
);
}}

View file

@ -1,24 +1,26 @@
import React from 'react'
import { Table } from '../../common';
import { List } from 'immutable';
import { FilterKey } from 'Types/filter/filterType';
import { filtersMap } from 'Types/filter/newFilter';
import { NoContent } from 'UI';
import { tableColumnName } from 'App/constants/filterOptions';
const cols = [
{
key: 'name',
title: 'Resource',
toText: name => name || 'Unidentified',
width: '70%',
},
{
key: 'sessionCount',
title: 'Sessions',
toText: sessions => sessions,
width: '30%',
},
];
const getColumns = (metric) => {
return [
{
key: 'name',
title: tableColumnName[metric.metricOf],
toText: name => name || 'Unidentified',
width: '70%',
},
{
key: 'sessionCount',
title: 'Sessions',
toText: sessions => sessions,
width: '30%',
},
]
}
interface Props {
metric?: any,
@ -49,7 +51,7 @@ function CustomMetriTable(props: Props) {
<NoContent show={data.values && data.values.length === 0} size="small">
<Table
small
cols={ cols }
cols={ getColumns(metric) }
rows={ rows }
rowClass="group"
onRowClick={ onClickHandler }

View file

@ -99,7 +99,7 @@ function CustomMetricWidget(props: Props) {
<div className="flex items-center">
{isTimeSeries && (
<>
<span className="mr-1 color-gray-medium">Visualization</span>
<span className="color-gray-medium mr-2">Visualization</span>
<SegmentSelection
name="viewType"
className="my-3"

View file

@ -181,7 +181,7 @@ function CustomMetricForm(props: Props) {
onRemoveSeries={() => removeSeries(index)}
canDelete={metric.series.size > 1}
emptyMessage={isTable ?
'Filter table data by user environment and metadata attributes. Use add step button below to filter.' :
'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.'
}
/>

View file

@ -13,6 +13,8 @@ interface Props {
onSelect: (e, item) => void;
value: any;
icon?: string;
type?: string;
isMultilple?: boolean;
}
function FilterAutoCompleteLocal(props: Props) {
@ -24,6 +26,8 @@ function FilterAutoCompleteLocal(props: Props) {
onAddValue = () => null,
value = '',
icon = null,
type = "text",
isMultilple = true,
} = props;
const [showModal, setShowModal] = useState(true)
const [query, setQuery] = useState(value);
@ -59,7 +63,7 @@ function FilterAutoCompleteLocal(props: Props) {
onFocus={ () => setShowModal(true)}
value={ query }
autoFocus={ true }
type="text"
type={ type }
placeholder={ placeholder }
onKeyDown={handleKeyDown}
/>
@ -71,7 +75,7 @@ function FilterAutoCompleteLocal(props: Props) {
</div>
</div>
{ !showOrButton && <div className="ml-3">or</div> }
{ !showOrButton && isMultilple && <div className="ml-3">or</div> }
</div>
);
}

View file

@ -63,7 +63,7 @@ function FilterValue(props: Props) {
}
const renderValueFiled = (value, valueIndex) => {
const showOrButton = valueIndex === lastIndex;
const showOrButton = valueIndex === lastIndex && filter.type !== FilterType.NUMBER;
switch(filter.type) {
case FilterType.STRING:
return (
@ -113,17 +113,41 @@ function FilterValue(props: Props) {
maxDuration={ durationValues.maxDuration }
/>
)
case FilterType.NUMBER:
case FilterType.NUMBER_MULTIPLE:
return (
<input
className="w-full px-2 py-1 text-sm leading-tight text-gray-700 rounded-lg"
type="number"
name={`${filter.key}-${valueIndex}`}
<FilterAutoCompleteLocal
value={value}
onChange={(e) => onChange(e, { value: e.target.value }, valueIndex)}
showCloseButton={showCloseButton}
showOrButton={showOrButton}
onAddValue={onAddValue}
onRemoveValue={() => onRemoveValue(valueIndex)}
onSelect={(e, item) => debounceOnSelect(e, item, valueIndex)}
icon={filter.icon}
type="number"
/>
)
case FilterType.NUMBER:
return (
<FilterAutoCompleteLocal
value={value}
showCloseButton={showCloseButton}
showOrButton={showOrButton}
onAddValue={onAddValue}
onRemoveValue={() => onRemoveValue(valueIndex)}
onSelect={(e, item) => debounceOnSelect(e, item, valueIndex)}
icon={filter.icon}
type="number"
isMultilple={false}
/>
// <input
// className="w-full px-2 py-1 text-sm leading-tight text-gray-700 rounded bg-white border"
// type="number"
// name={`${filter.key}-${valueIndex}`}
// value={value}
// placeholder="Enter"
// onChange={(e) => onChange(e, { value: e.target.value }, valueIndex)}
// />
)
case FilterType.MULTIPLE:
return (
<FilterAutoComplete

View file

@ -5,6 +5,7 @@
display: flex;
align-items: center;
height: 26px;
width: 100%;
& .right {
height: 24px;

View file

@ -16,31 +16,36 @@ interface Props {
showOrButton?: boolean;
onRemoveValue?: () => void;
onAddValue?: () => void;
isMultilple?: boolean;
}
function FilterValueDropdown(props: Props) {
const { filter, multiple = false, search = false, options, onChange, value, className = '', showCloseButton = true, showOrButton = true } = props;
const { filter, multiple = false, isMultilple = true, search = false, options, onChange, value, className = '', showCloseButton = true, showOrButton = true } = props;
// const options = []
return (
<div className={stl.wrapper}>
<Dropdown
search={search}
className={ cn(stl.operatorDropdown, className, "filterDropdown") }
options={ options }
name="issue_type"
value={ value }
onChange={ onChange }
placeholder="Select"
fluid
icon={ <Icon className="absolute right-0 mr-2" name="chevron-down" size="12" /> }
/>
<div
className={stl.right}
// onClick={showOrButton ? onRemoveValue : onAddValue}
>
{ showCloseButton && <div onClick={props.onRemoveValue}><Icon name="close" size="12" /></div> }
{ showOrButton && <div onClick={props.onAddValue} className="color-teal"><span className="px-1">or</span></div> }
<div className="relative flex items-center w-full">
<div className={stl.wrapper}>
<Dropdown
search={search}
className={ cn(stl.operatorDropdown, className, "filterDropdown") }
options={ options }
name="issue_type"
value={ value }
onChange={ onChange }
placeholder="Select"
fluid
icon={ <Icon className="absolute right-0 mr-2" name="chevron-down" size="12" /> }
/>
<div
className={stl.right}
// onClick={showOrButton ? onRemoveValue : onAddValue}
>
{ showCloseButton && <div onClick={props.onRemoveValue}><Icon name="close" size="12" /></div> }
{ showOrButton && <div onClick={props.onAddValue} className="color-teal"><span className="px-1">or</span></div> }
</div>
</div>
{ !showOrButton && isMultilple && <div className="ml-3">or</div> }
</div>
);
}

View file

@ -61,6 +61,15 @@ export const metricTypes = [
{ text: 'Table', value: 'table' },
];
export const tableColumnName = {
[FilterKey.USERID]: 'User',
[FilterKey.ISSUE]: 'Issue',
[FilterKey.USER_BROWSER]: 'Browser',
[FilterKey.USER_DEVICE]: 'Device',
[FilterKey.USER_COUNTRY]: 'Country',
[FilterKey.LOCATION]: 'URL',
}
export const metricOf = [
{ text: 'Session Count', value: 'sessionCount', type: 'timeseries' },
{ text: 'Users', value: FilterKey.USERID, type: 'table' },
@ -71,6 +80,18 @@ export const metricOf = [
{ text: 'URL', value: FilterKey.LOCATION, type: 'table' },
]
export const methodOptions = [
{ text: 'GET', value: 'GET' },
{ text: 'POST', value: 'POST' },
{ text: 'PUT', value: 'PUT' },
{ text: 'DELETE', value: 'DELETE' },
{ text: 'PATCH', value: 'PATCH' },
{ text: 'HEAD', value: 'HEAD' },
{ text: 'OPTIONS', value: 'OPTIONS' },
{ text: 'TRACE', value: 'TRACE' },
{ text: 'CONNECT', value: 'CONNECT' },
]
export const issueOptions = [
{ text: 'Click Rage', value: 'click_rage' },
{ text: 'Dead Click', value: 'dead_click' },
@ -97,4 +118,5 @@ export default {
metricTypes,
metricOf,
issueOptions,
methodOptions,
}

View file

@ -107,14 +107,15 @@ export const checkFilterValue = (value) => {
return Array.isArray(value) ? (value.length === 0 ? [""] : value) : [value];
}
export const filterMap = ({category, value, key, operator, sourceOperator, source, custom, isEvent }) => ({
export const filterMap = ({category, value, key, operator, sourceOperator, source, custom, isEvent, subFilters }) => ({
value: checkValues(key, value),
custom,
type: category === FilterCategory.METADATA ? FilterKey.METADATA : key,
operator,
source: category === FilterCategory.METADATA ? key : source,
sourceOperator,
isEvent
isEvent,
filters: subFilters ? subFilters.map(filterMap) : [],
});
const reduceThenFetchResource = actionCreator => (...args) => (dispatch, getState) => {

View file

@ -33,10 +33,10 @@ export const filtersMap = {
[FilterKey.USERANONYMOUSID]: { key: FilterKey.USERANONYMOUSID, type: FilterType.MULTIPLE, category: FilterCategory.USER, label: 'User AnonymousId', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/userid' },
// PERFORMANCE
[FilterKey.FETCH]: { key: FilterKey.FETCH, type: FilterType.SUB_FILTERS, category: FilterCategory.PERFORMANCE, label: 'Fetch Request', subFilters: [
[FilterKey.FETCH]: { key: FilterKey.FETCH, type: FilterType.SUB_FILTERS, category: FilterCategory.PERFORMANCE, operator: 'is', label: 'Network Request', subFilters: [
{ 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' },
{ key: FilterKey.FETCH_METHOD, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'with method', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch' },
{ key: FilterKey.FETCH_METHOD, type: FilterType.MULTIPLE_DROPDOWN, category: FilterCategory.PERFORMANCE, label: 'with method', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch', options: filterOptions.methodOptions },
{ key: FilterKey.FETCH_DURATION, type: FilterType.NUMBER, category: FilterCategory.PERFORMANCE, label: 'with duration', operator: '=', operatorOptions: filterOptions.customOperators, icon: 'filters/fetch' },
{ key: FilterKey.FETCH_REQUEST_BODY, type: FilterType.STRING, category: FilterCategory.PERFORMANCE, label: 'with request body', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch' },
{ key: FilterKey.FETCH_RESPONSE_BODY, type: FilterType.STRING, category: FilterCategory.PERFORMANCE, label: 'with response body', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch' },