feat(ui) - custom metrics
This commit is contained in:
parent
2008d3dc2f
commit
d41299b6fe
14 changed files with 43 additions and 62 deletions
|
|
@ -40,7 +40,7 @@ function FilterSeries(props: Props) {
|
|||
});
|
||||
|
||||
props.updateSeries(seriesIndex, {
|
||||
...series.toData(),
|
||||
...series,
|
||||
filter: {
|
||||
...series.filter,
|
||||
filters: newFilters,
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@
|
|||
border-radius: 3px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: white;
|
||||
& input {
|
||||
height: 28px;
|
||||
height: 24px;
|
||||
font-size: 13px !important;
|
||||
padding: 0 5px !important;
|
||||
border-top-left-radius: 3px;
|
||||
|
|
@ -14,7 +15,7 @@
|
|||
}
|
||||
|
||||
& .right {
|
||||
height: 28px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
padding: 0;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import FilterOperator from '../FilterOperator/FilterOperator';
|
||||
import FilterOperator from '../FilterOperator';
|
||||
import FilterSelection from '../FilterSelection';
|
||||
import FilterValue from '../FilterValue';
|
||||
import { Icon } from 'UI';
|
||||
|
|
@ -12,51 +12,30 @@ interface Props {
|
|||
isFilter?: boolean;
|
||||
}
|
||||
function FitlerItem(props: Props) {
|
||||
const { isFilter = false, filterIndex, filter, onUpdate } = props;
|
||||
const { isFilter = false, filterIndex, filter } = props;
|
||||
|
||||
const replaceFilter = (filter) => {
|
||||
onUpdate(filter);
|
||||
props.onUpdate({ ...filter, value: [""]});
|
||||
};
|
||||
|
||||
// const onAddValue = () => {
|
||||
// const newValues = filter.value.concat("")
|
||||
// onUpdate({ ...filter, value: newValues })
|
||||
// }
|
||||
|
||||
// const onRemoveValue = (valueIndex) => {
|
||||
// const newValues = filter.value.filter((_, _index) => _index !== valueIndex)
|
||||
// onUpdate({ ...filter, value: newValues })
|
||||
// }
|
||||
|
||||
// const onSelect = (e, item, valueIndex) => {
|
||||
// const newValues = filter.value.map((_, _index) => {
|
||||
// if (_index === valueIndex) {
|
||||
// return item.value;
|
||||
// }
|
||||
// return _;
|
||||
// })
|
||||
// onUpdate({ ...filter, value: newValues })
|
||||
// }
|
||||
|
||||
const onOperatorChange = (e, { name, value }) => {
|
||||
console.log('onOperatorChange', name, value)
|
||||
onUpdate({ ...filter, operator: value })
|
||||
props.onUpdate({ ...filter, operator: value })
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center mb-4">
|
||||
<div className="flex items-start mr-auto">
|
||||
{ !isFilter && <div className="mt-1 w-6 h-6 text-xs flex justify-center rounded-full bg-gray-light-shade mr-2">{filterIndex+1}</div> }
|
||||
<div className="flex items-center hover:bg-active-blue -mx-5 px-5 py-2">
|
||||
<div className="flex items-start w-full">
|
||||
{ !isFilter && <div className="mt-1 flex-shrink-0 border w-6 h-6 text-xs flex justify-center rounded-full bg-gray-light-shade mr-2">{filterIndex+1}</div> }
|
||||
<FilterSelection filter={filter} onFilterClick={replaceFilter} />
|
||||
<FilterOperator filter={filter} onChange={onOperatorChange} className="mx-2 flex-shrink-0"/>
|
||||
<FilterValue filter={filter} onUpdate={onUpdate} />
|
||||
<FilterValue filter={filter} onUpdate={props.onUpdate} />
|
||||
</div>
|
||||
<div className="flex self-start mt-2">
|
||||
<div className="flex self-start mt-2 ml-auto">
|
||||
<div
|
||||
className="cursor-pointer p-1"
|
||||
onClick={props.onRemoveFilter}
|
||||
>
|
||||
<Icon name="trash" size="16" />
|
||||
<Icon name="trash" size="14" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ function FilterList(props: Props) {
|
|||
|
||||
{hasFilters && (
|
||||
<>
|
||||
<div className='border-t -mx-5 mb-2' />
|
||||
{hasEvents && <div className='border-t -mx-5 mb-2' />}
|
||||
<div className="mb-2 text-sm color-gray-medium mr-auto">FILTERS</div>
|
||||
{filters.map((filter, filterIndex) => !filter.isEvent ? (
|
||||
<FilterItem
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
.operatorDropdown {
|
||||
font-weight: 400;
|
||||
height: 30px;
|
||||
height: 26px;
|
||||
min-width: 60px;
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
font-size: 13px;
|
||||
/* background-color: rgba(255, 255, 255, 0.8) !important; */
|
||||
background-color: $gray-lightest !important;
|
||||
border: solid thin rgba(34, 36, 38, 0.15) !important;
|
||||
border: solid thin #e9e9e9 !important;
|
||||
border-radius: 4px !important;
|
||||
color: $gray-darkest !important;
|
||||
font-size: 14px !important;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ function FilterOperator(props: Props) {
|
|||
|
||||
return (
|
||||
<Dropdown
|
||||
className={ cn(stl.operatorDropdown, className) }
|
||||
className={ cn(stl.operatorDropdown, className, 'hover:bg-gray-light-shade') }
|
||||
options={ filter.operatorOptions }
|
||||
name="operator"
|
||||
value={ filter.operator }
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ function FilterSelection(props: Props) {
|
|||
>
|
||||
{ children ? React.cloneElement(children, { onClick: () => setShowModal(true)}) : (
|
||||
<div
|
||||
className="rounded py-1 px-3 flex items-center cursor-pointer bg-gray-lightest text-ellipsis"
|
||||
style={{ width: '140px', height: '30px', border: 'solid thin rgba(34, 36, 38, 0.15)'}}
|
||||
className="rounded py-1 px-3 flex items-center cursor-pointer bg-gray-lightest text-ellipsis hover:bg-gray-light-shade"
|
||||
style={{ width: '140px', height: '26px', border: 'solid thin #e9e9e9' }}
|
||||
onClick={() => setShowModal(true)}
|
||||
>
|
||||
<span className="mr-auto truncate">{filter.label}</span>
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ function FilterValue(props: Props) {
|
|||
}
|
||||
|
||||
const renderValueFiled = (value, valueIndex) => {
|
||||
const showCloseButton = filter.value.length > 1;
|
||||
const showOrButton = valueIndex === filter.value.length - 1;
|
||||
switch(filter.type) {
|
||||
case FilterType.DROPDOWN:
|
||||
return (
|
||||
|
|
@ -71,6 +73,10 @@ function FilterValue(props: Props) {
|
|||
filter={filter}
|
||||
options={filter.options}
|
||||
onChange={(e, { name, value }) => onSelect(e, { value }, valueIndex)}
|
||||
onAddValue={onAddValue}
|
||||
onRemoveValue={() => onRemoveValue(valueIndex)}
|
||||
showCloseButton={showCloseButton}
|
||||
showOrButton={showOrButton}
|
||||
/>
|
||||
)
|
||||
case FilterType.DURATION:
|
||||
|
|
@ -97,8 +103,8 @@ function FilterValue(props: Props) {
|
|||
return (
|
||||
<FilterAutoComplete
|
||||
value={value}
|
||||
showCloseButton={filter.value.length > 1}
|
||||
showOrButton={valueIndex === filter.value.length - 1}
|
||||
showCloseButton={showCloseButton}
|
||||
showOrButton={showOrButton}
|
||||
onAddValue={onAddValue}
|
||||
onRemoveValue={() => onRemoveValue(valueIndex)}
|
||||
method={'GET'}
|
||||
|
|
@ -113,7 +119,7 @@ function FilterValue(props: Props) {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
<div className="grid grid-cols-3 gap-3 w-full">
|
||||
{ filter.type === FilterType.DURATION ? (
|
||||
renderValueFiled(filter.value, 0)
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
.wrapper {
|
||||
border: solid thin $gray-light !important;
|
||||
border-radius: 3px;
|
||||
background-color: $gray-lightest !important;
|
||||
background-color: white !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 30px;
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
background-color: $gray-lightest;
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
margin-left: auto;
|
||||
|
||||
& div {
|
||||
/* background-color: red; */
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ function FilterValueDropdown(props: Props) {
|
|||
value={ value }
|
||||
onChange={ onChange }
|
||||
placeholder="Select"
|
||||
fluid
|
||||
icon={ <Icon className="ml-5" name="chevron-down" size="12" /> }
|
||||
/>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ function SaveSearchModal(props: Props) {
|
|||
closeHandler();
|
||||
});
|
||||
}
|
||||
console.log('filter', filter);
|
||||
|
||||
return (
|
||||
<Modal size="tiny" open={ show }>
|
||||
<Modal.Header className={ stl.modalHeader }>
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ function SessionSearch(props) {
|
|||
});
|
||||
|
||||
props.edit({
|
||||
...appliedFilter.filter,
|
||||
...appliedFilter,
|
||||
filters: newFilters,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,10 @@
|
|||
import { List, Map } from 'immutable';
|
||||
import { clean as cleanParams } from 'App/api_client';
|
||||
import ErrorInfo, { RESOLVED, UNRESOLVED, IGNORED } from 'Types/errorInfo';
|
||||
// import { clean as cleanParams } from 'App/api_client';
|
||||
import CustomMetric, { FilterSeries } from 'Types/customMetric'
|
||||
import { createFetch, fetchListType, fetchType, saveType, removeType, editType, createRemove, createEdit } from './funcTools/crud';
|
||||
// import { createEdit, createInit } from './funcTools/crud';
|
||||
import { createRequestReducer, ROOT_KEY } from './funcTools/request';
|
||||
import { array, request, success, failure, createListUpdater, mergeReducers } from './funcTools/tools';
|
||||
import Filter from 'Types/filter';
|
||||
import NewFilter from 'Types/filter/newFilter';
|
||||
import Event from 'Types/filter/event';
|
||||
// import CustomFilter from 'Types/filter/customFilter';
|
||||
|
||||
const name = "custom_metric";
|
||||
const idKey = "metricId";
|
||||
|
|
@ -50,18 +45,15 @@ const initialState = Map({
|
|||
function reducer(state = initialState, action = {}) {
|
||||
switch (action.type) {
|
||||
case EDIT:
|
||||
console.log('EDIT', action);
|
||||
return state.mergeIn([ 'instance' ], CustomMetric(action.instance));
|
||||
case UPDATE_SERIES:
|
||||
console.log('update series', action.series);
|
||||
return state.setIn(['instance', 'series', action.index], FilterSeries(action.series));
|
||||
return state.mergeIn([ 'instance' ], action.instance);
|
||||
case UPDATE_SERIES:
|
||||
return state.mergeIn(['instance', 'series', action.index], action.series);
|
||||
case success(SAVE):
|
||||
return state.set([ 'instance' ], CustomMetric(action.data));
|
||||
return state.mergeIn([ 'instance' ], action.data);
|
||||
case success(REMOVE):
|
||||
console.log('action', action)
|
||||
return state.update('list', list => list.filter(item => item.metricId !== action.id));
|
||||
case success(FETCH):
|
||||
return state.set("instance", ErrorInfo(action.data));
|
||||
return state.set("instance", CustomMetric(action.data));
|
||||
case success(FETCH_LIST):
|
||||
const { data } = action;
|
||||
return state.set("list", List(data.map(CustomMetric)));
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { fetchList as fetchErrorsList } from './errors';
|
|||
|
||||
const ERRORS_ROUTE = errorsRoute();
|
||||
|
||||
const name = "custom_metric";
|
||||
const name = "search";
|
||||
const idKey = "metricId";
|
||||
|
||||
const FETCH_LIST = fetchListType(name);
|
||||
|
|
@ -84,6 +84,7 @@ const filterMap = ({value, type, key, operator, source, custom, isEvent }) => ({
|
|||
});
|
||||
|
||||
const reduceThenFetchResource = actionCreator => (...args) => (dispatch, getState) => {
|
||||
console.log('reduceThenFetchResource', args);
|
||||
dispatch(actionCreator(...args));
|
||||
const filter = getState().getIn([ 'search', 'instance']).toData();
|
||||
filter.filters = filter.filters.map(filterMap);
|
||||
|
|
@ -135,7 +136,7 @@ export function save(instance) {
|
|||
export function fetchList() {
|
||||
return {
|
||||
types: array(FETCH_LIST),
|
||||
call: client => client.get(`/${name}s`),
|
||||
call: client => client.get(`/saved_search`),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue