feat(ui) - custom metric edit and other changes
This commit is contained in:
parent
1cde82e27a
commit
22aeb14afd
13 changed files with 219 additions and 76 deletions
|
|
@ -6,6 +6,7 @@ import { setPeriod, setPlatform, fetchMetadataOptions } from 'Duck/dashboard';
|
|||
import { NoContent } from 'UI';
|
||||
import { WIDGET_KEYS } from 'Types/dashboard';
|
||||
import CustomMetrics from 'Shared/CustomMetrics';
|
||||
import SessionListModal from 'Shared/CustomMetrics/SessionListModal';
|
||||
|
||||
import {
|
||||
MissingResources,
|
||||
|
|
@ -188,6 +189,7 @@ export default class Dashboard extends React.PureComponent {
|
|||
<div className={ cn(styles.header, "flex items-center w-full") }>
|
||||
<MetricsFilters />
|
||||
<CustomMetrics />
|
||||
<SessionListModal />
|
||||
</div>
|
||||
<div className="">
|
||||
<NoContent
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Loader, NoContent, Icon } from 'UI';
|
||||
import { widgetHOC, Styles } from '../../common';
|
||||
import { Styles } from '../../common';
|
||||
import { ResponsiveContainer, AreaChart, XAxis, YAxis, CartesianGrid, Area, Tooltip } from 'recharts';
|
||||
import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period';
|
||||
import CustomMetricWidgetHoc from '../../common/CustomMetricWidgetHoc';
|
||||
// import CustomMetricWidgetHoc from '../../common/CustomMetricWidgetHoc';
|
||||
import stl from './CustomMetricWidget.css';
|
||||
import { getChartFormatter } from 'Types/dashboard/helper';
|
||||
import { remove, setAlertMetricId } from 'Duck/customMetrics';
|
||||
import { getChartFormatter, getStartAndEndTimestampsByDensity } from 'Types/dashboard/helper';
|
||||
import { edit, remove, setAlertMetricId, setActiveWidget } from 'Duck/customMetrics';
|
||||
import { confirm } from 'UI/Confirmation';
|
||||
import APIClient from 'App/api_client';
|
||||
import { setShowAlerts } from 'Duck/dashboard';
|
||||
|
|
@ -23,25 +23,23 @@ const customParams = rangeName => {
|
|||
return params
|
||||
}
|
||||
|
||||
interface Period {
|
||||
rangeName: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
metric: any;
|
||||
// loading?: boolean;
|
||||
data?: any;
|
||||
showSync?: boolean;
|
||||
compare?: boolean;
|
||||
period?: Period;
|
||||
period?: any;
|
||||
onClickEdit: (e) => void;
|
||||
remove: (id) => void;
|
||||
setShowAlerts: (showAlerts) => void;
|
||||
setAlertMetricId: (id) => void;
|
||||
onAlertClick: (e) => void;
|
||||
edit: (setDefault?) => void;
|
||||
setActiveWidget: (widget) => void;
|
||||
}
|
||||
function CustomMetricWidget(props: Props) {
|
||||
const { metric, showSync, compare, period = { rangeName: LAST_24_HOURS} } = props;
|
||||
const { metric, showSync, compare, period } = props;
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [data, setData] = useState<any>({ chart: [] })
|
||||
|
||||
|
|
@ -51,7 +49,6 @@ function CustomMetricWidget(props: Props) {
|
|||
const metricParams = { ...params, metricId: metric.metricId, viewType: 'lineChart' }
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
// dataWrapper: (p, period) => SessionsImpactedBySlowRequests({ chart: p})
|
||||
// .update("chart", getChartFormatter(period))
|
||||
|
||||
|
|
@ -64,7 +61,7 @@ function CustomMetricWidget(props: Props) {
|
|||
// console.log('data', data);
|
||||
// const _data = data[0].map(CustomMetric).update("chart", getChartFormatter(period)).toJS();
|
||||
const _data = getChartFormatter(period)(data[0]);
|
||||
console.log('__data', _data)
|
||||
// console.log('__data', _data)
|
||||
setData({ chart: _data });
|
||||
}
|
||||
}).finally(() => setLoading(false));
|
||||
|
|
@ -80,6 +77,12 @@ function CustomMetricWidget(props: Props) {
|
|||
}
|
||||
}
|
||||
|
||||
const clickHandler = (event, index) => {
|
||||
const timestamp = event.activePayload[0].payload.timestamp;
|
||||
const { startTimestamp, endTimestamp } = getStartAndEndTimestampsByDensity(timestamp, period.start, period.end, params.density);
|
||||
props.setActiveWidget({ widget: metric, startTimestamp, endTimestamp, timestamp: event.activePayload[0].payload.timestamp, index })
|
||||
}
|
||||
|
||||
// const onAlertClick = () => {
|
||||
// props.setShowAlerts(true)
|
||||
// props.setAlertMetricId(metric.metricId)
|
||||
|
|
@ -90,10 +93,10 @@ function CustomMetricWidget(props: Props) {
|
|||
<div className="flex items-center mb-10 p-2">
|
||||
<div className="font-medium">{metric.name + ' ' + metric.metricId}</div>
|
||||
<div className="ml-auto flex items-center">
|
||||
<div className="cursor-pointer mr-6" onClick={deleteHandler}>
|
||||
<div className="cursor-pointer mr-6" onClick={deleteHandler}>
|
||||
<Icon name="trash" size="14" />
|
||||
</div>
|
||||
<div className="cursor-pointer mr-6">
|
||||
<div className="cursor-pointer mr-6" onClick={() => props.edit(metric)}>
|
||||
<Icon name="pencil" size="14" />
|
||||
</div>
|
||||
<div className="cursor-pointer" onClick={props.onAlertClick}>
|
||||
|
|
@ -112,6 +115,7 @@ function CustomMetricWidget(props: Props) {
|
|||
data={ data.chart }
|
||||
margin={Styles.chartMargins}
|
||||
syncId={ showSync ? "impactedSessionsBySlowPages" : undefined }
|
||||
onClick={clickHandler}
|
||||
>
|
||||
{gradientDef}
|
||||
<CartesianGrid strokeDasharray="3 3" vertical={ false } stroke="#EEEEEE" />
|
||||
|
|
@ -131,6 +135,7 @@ function CustomMetricWidget(props: Props) {
|
|||
strokeWidth={ 2 }
|
||||
strokeOpacity={ 0.8 }
|
||||
fill={compare ? 'url(#colorCountCompare)' : 'url(#colorCount)'}
|
||||
// onClick={clickHandler}
|
||||
/>
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
|
|
@ -141,4 +146,6 @@ function CustomMetricWidget(props: Props) {
|
|||
);
|
||||
}
|
||||
|
||||
export default connect(null, { remove, setShowAlerts, setAlertMetricId })(CustomMetricWidget);
|
||||
export default connect(state => ({
|
||||
period: state.getIn(['dashboard', 'period']),
|
||||
}), { remove, setShowAlerts, setAlertMetricId, edit, setActiveWidget })(CustomMetricWidget);
|
||||
|
|
@ -47,17 +47,17 @@ function CustomMetricWidget(props: Props) {
|
|||
const metricParams = { ...params, metricId: metric.metricId, viewType: 'lineChart' }
|
||||
|
||||
useEffect(() => {
|
||||
new APIClient()['post']('/custom_metrics/try', { ...metricParams, ...metric.toSaveData() })
|
||||
.then(response => response.json())
|
||||
.then(({ errors, data }) => {
|
||||
if (errors) {
|
||||
console.log('err', errors)
|
||||
} else {
|
||||
const _data = getChartFormatter(period)(data[0]);
|
||||
// console.log('__data', _data)
|
||||
setData({ chart: _data });
|
||||
}
|
||||
}).finally(() => setLoading(false));
|
||||
// new APIClient()['post']('/custom_metrics/try', { ...metricParams, ...metric.toSaveData() })
|
||||
// .then(response => response.json())
|
||||
// .then(({ errors, data }) => {
|
||||
// if (errors) {
|
||||
// console.log('err', errors)
|
||||
// } else {
|
||||
// const _data = getChartFormatter(period)(data[0]);
|
||||
// // console.log('__data', _data)
|
||||
// setData({ chart: _data });
|
||||
// }
|
||||
// }).finally(() => setLoading(false));
|
||||
}, [metric])
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ import { Icon } from 'UI';
|
|||
interface Props {
|
||||
}
|
||||
const CustomMetricWidgetHoc = ({ ...rest }: Props) => BaseComponent => {
|
||||
|
||||
console.log('CustomMetricWidgetHoc', rest);
|
||||
return (
|
||||
<div className={stl.wrapper}>
|
||||
<div className="flex items-center mb-10 p-2">
|
||||
|
|
|
|||
|
|
@ -2,20 +2,23 @@ import React from 'react';
|
|||
import { Form, SegmentSelection, Button, IconButton } from 'UI';
|
||||
import FilterSeries from '../FilterSeries';
|
||||
import { connect } from 'react-redux';
|
||||
import { edit as editMetric, save } from 'Duck/customMetrics';
|
||||
import { edit as editMetric, save, addSeries } from 'Duck/customMetrics';
|
||||
import CustomMetricWidgetPreview from 'App/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview';
|
||||
|
||||
interface Props {
|
||||
metric: any;
|
||||
editMetric: (metric) => void;
|
||||
save: (metric) => void;
|
||||
save: (metric) => Promise<void>;
|
||||
loading: boolean;
|
||||
addSeries: (series?) => void;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
function CustomMetricForm(props: Props) {
|
||||
const { metric, loading } = props;
|
||||
|
||||
const addSeries = () => {
|
||||
props.addSeries();
|
||||
const newSeries = {
|
||||
name: `Series ${metric.series.size + 1}`,
|
||||
type: '',
|
||||
|
|
@ -45,13 +48,17 @@ function CustomMetricForm(props: Props) {
|
|||
const write = ({ target: { value, name } }) => props.editMetric({ ...metric, [ name ]: value })
|
||||
|
||||
const changeConditionTab = (e, { name, value }) => {
|
||||
props.editMetric({ ...metric, [ 'type' ]: value })
|
||||
props.editMetric({[ 'type' ]: value });
|
||||
};
|
||||
|
||||
const save = () => {
|
||||
props.save(metric).then(props.onClose);
|
||||
}
|
||||
|
||||
return (
|
||||
<Form
|
||||
className="relative"
|
||||
onSubmit={() => props.save(metric)}
|
||||
onSubmit={save}
|
||||
>
|
||||
<div className="p-5 pb-20" style={{ height: 'calc(100vh - 60px)', overflowY: 'auto' }}>
|
||||
<div className="form-group">
|
||||
|
|
@ -61,7 +68,7 @@ function CustomMetricForm(props: Props) {
|
|||
className="text-lg"
|
||||
name="name"
|
||||
style={{ fontSize: '18px', padding: '10px', fontWeight: '600'}}
|
||||
// value={ instance && instance.name }
|
||||
value={ metric.name }
|
||||
onChange={ write }
|
||||
placeholder="Metric Title"
|
||||
id="name-field"
|
||||
|
|
@ -104,7 +111,7 @@ function CustomMetricForm(props: Props) {
|
|||
</div>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<IconButton onClick={addSeries} primaryText label="SERIES" icon="plus" />
|
||||
<IconButton type="button" onClick={addSeries} primaryText label="SERIES" icon="plus" />
|
||||
</div>
|
||||
|
||||
<div className="my-4" />
|
||||
|
|
@ -113,8 +120,8 @@ function CustomMetricForm(props: Props) {
|
|||
</div>
|
||||
|
||||
<div className="fixed border-t w-full bottom-0 px-5 py-2 bg-white">
|
||||
<Button loading={loading} primary>
|
||||
Save
|
||||
<Button loading={loading} primary disabled={!metric.validate()}>
|
||||
{ `${metric.exists() ? 'Update' : 'Create'}` }
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
|
|
@ -124,4 +131,4 @@ function CustomMetricForm(props: Props) {
|
|||
export default connect(state => ({
|
||||
metric: state.getIn(['customMetrics', 'instance']),
|
||||
loading: state.getIn(['customMetrics', 'saveRequest', 'loading']),
|
||||
}), { editMetric, save })(CustomMetricForm);
|
||||
}), { editMetric, save, addSeries })(CustomMetricForm);
|
||||
|
|
@ -1,28 +1,23 @@
|
|||
import CustomMetricWidgetPreview from 'App/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview';
|
||||
// import CustomMetricWidgetPreview from 'App/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview';
|
||||
import React, { useState } from 'react';
|
||||
import { IconButton, SlideModal } from 'UI'
|
||||
import { IconButton, SlideModal } from 'UI';
|
||||
import CustomMetricForm from './CustomMetricForm';
|
||||
import { connect } from 'react-redux';
|
||||
import { edit } from 'Duck/customMetrics';
|
||||
import { edit, init } from 'Duck/customMetrics';
|
||||
|
||||
interface Props {
|
||||
metric: any;
|
||||
edit: (metric) => void;
|
||||
instance: any;
|
||||
init: (instance?, setDefault?) => void;
|
||||
}
|
||||
function CustomMetrics(props: Props) {
|
||||
const { metric } = props;
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
|
||||
const onClose = () => {
|
||||
setShowModal(false);
|
||||
}
|
||||
// const [showModal, setShowModal] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="self-start">
|
||||
<IconButton outline icon="plus" label="CREATE METRIC" onClick={() => {
|
||||
setShowModal(true);
|
||||
// props.edit({ name: 'New', series: [{ name: '', filter: {} }], type: '' });
|
||||
}} />
|
||||
<IconButton outline icon="plus" label="CREATE METRIC" onClick={() => props.init()} />
|
||||
|
||||
<SlideModal
|
||||
title={
|
||||
|
|
@ -30,12 +25,12 @@ function CustomMetrics(props: Props) {
|
|||
<span className="mr-3">{ 'Custom Metric' }</span>
|
||||
</div>
|
||||
}
|
||||
isDisplayed={ showModal }
|
||||
onClose={ () => setShowModal(false)}
|
||||
isDisplayed={ !!metric }
|
||||
onClose={ () => props.init(null, false)}
|
||||
// size="medium"
|
||||
content={ (showModal || metric) && (
|
||||
content={ (!!metric) && (
|
||||
<div style={{ backgroundColor: '#f6f6f6' }}>
|
||||
<CustomMetricForm metric={metric} />
|
||||
<CustomMetricForm metric={metric} onClose={() => props.init(null, false)} />
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
|
|
@ -46,4 +41,5 @@ function CustomMetrics(props: Props) {
|
|||
export default connect(state => ({
|
||||
metric: state.getIn(['customMetrics', 'instance']),
|
||||
alertInstance: state.getIn(['alerts', 'instance']),
|
||||
}), { edit })(CustomMetrics);
|
||||
showModal: state.getIn(['customMetrics', 'showModal']),
|
||||
}), { edit, init })(CustomMetrics);
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
.wrapper {
|
||||
padding: 0 20px;
|
||||
background-color: #f6f6f6;
|
||||
min-height: calc(100vh - 59px);
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import { SlideModal, NoContent } from 'UI';
|
||||
import SessionItem from 'Shared/SessionItem';
|
||||
import stl from './SessionListModal.css';
|
||||
import { connect } from 'react-redux';
|
||||
import { fetchSessionList, setActiveWidget } from 'Duck/customMetrics';
|
||||
|
||||
interface Props {
|
||||
loading: boolean;
|
||||
list: any;
|
||||
fetchSessionList: (params) => void;
|
||||
activeWidget: any;
|
||||
setActiveWidget: (widget) => void;
|
||||
}
|
||||
function SessionListModal(props: Props) {
|
||||
const { activeWidget, loading, list } = props;
|
||||
useEffect(() => {
|
||||
if (!activeWidget || !activeWidget.widget) return;
|
||||
props.fetchSessionList({
|
||||
metricId: activeWidget.widget.metricId,
|
||||
startDate: activeWidget.startTimestamp,
|
||||
endDate: activeWidget.endTimestamp
|
||||
});
|
||||
}, [activeWidget]);
|
||||
|
||||
console.log('SessionListModal', activeWidget);
|
||||
return (
|
||||
<SlideModal
|
||||
title={ activeWidget && (
|
||||
<div className="flex items-center">
|
||||
<span className="mr-3">{ 'Custom Metric: ' + activeWidget.widget.name } </span>
|
||||
</div>
|
||||
)}
|
||||
isDisplayed={ !!activeWidget }
|
||||
onClose={ () => props.setActiveWidget(null)}
|
||||
// size="medium"
|
||||
content={ activeWidget && (
|
||||
<div className="p-5">
|
||||
<NoContent
|
||||
show={ !loading && (list.length === 0 || list.size === 0 )}
|
||||
title="No recordings found."
|
||||
>
|
||||
<div className={ stl.wrapper }>
|
||||
{ list && list.map(session => <SessionItem key={ session.sessionId } session={ session } />) }
|
||||
</div>
|
||||
</NoContent>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(state => ({
|
||||
loading: state.getIn(['customMetrics', 'sessionListRequest', 'loading']),
|
||||
list: state.getIn(['customMetrics', 'sessionList']),
|
||||
activeWidget: state.getIn(['customMetrics', 'activeWidget']),
|
||||
}), { fetchSessionList, setActiveWidget })(SessionListModal);
|
||||
|
|
@ -0,0 +1 @@
|
|||
export { default } from './SessionListModal';
|
||||
|
|
@ -29,7 +29,7 @@ const reducer = (state = initialState, action = {}) => {
|
|||
// })
|
||||
// );
|
||||
case FETCH_TRIGGER_OPTIONS.SUCCESS:
|
||||
return state.set('triggerOptions', action.data);
|
||||
return state.set('triggerOptions', action.data.map(({ name, value}) => ({ text: name, value })));
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,18 +1,21 @@
|
|||
import { List, Map } from 'immutable';
|
||||
// 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 { createRequestReducer, ROOT_KEY } from './funcTools/request';
|
||||
import { array, request, success, failure, createListUpdater, mergeReducers } from './funcTools/tools';
|
||||
import Filter from 'Types/filter';
|
||||
import Session from 'Types/session';
|
||||
|
||||
const name = "custom_metric";
|
||||
const idKey = "metricId";
|
||||
|
||||
const FETCH_LIST = fetchListType(name);
|
||||
const FETCH_SESSION_LIST = fetchListType(`${name}/FETCH_SESSION_LIST`);
|
||||
const FETCH = fetchType(name);
|
||||
const SAVE = saveType(name);
|
||||
const EDIT = editType(name);
|
||||
const INIT = `${name}/INIT`;
|
||||
const SET_ACTIVE_WIDGET = `${name}/SET_ACTIVE_WIDGET`;
|
||||
const REMOVE = removeType(name);
|
||||
const UPDATE_SERIES = `${name}/UPDATE_SERIES`;
|
||||
const SET_ALERT_METRIC_ID = `${name}/SET_ALERT_METRIC_ID`;
|
||||
|
|
@ -21,35 +24,46 @@ function chartWrapper(chart = []) {
|
|||
return chart.map(point => ({ ...point, count: Math.max(point.count, 0) }));
|
||||
}
|
||||
|
||||
// const updateItemInList = createListUpdater(idKey);
|
||||
// const updateInstance = (state, instance) => state.getIn([ "instance", idKey ]) === instance[ idKey ]
|
||||
// ? state.mergeIn([ "instance" ], instance)
|
||||
// : state;
|
||||
const updateItemInList = createListUpdater(idKey);
|
||||
const updateInstance = (state, instance) => state.getIn([ "instance", idKey ]) === instance[ idKey ]
|
||||
? state.mergeIn([ "instance" ], instance)
|
||||
: state;
|
||||
|
||||
const defaultInstance = CustomMetric({
|
||||
name: 'New',
|
||||
series: List([
|
||||
{
|
||||
name: 'Session Count',
|
||||
filter: new Filter({ filters: [], eventsOrder: 'and' }),
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
const initialState = Map({
|
||||
list: List(),
|
||||
sessionList: List(),
|
||||
alertMetricId: null,
|
||||
// instance: null,
|
||||
instance: CustomMetric({
|
||||
name: 'New',
|
||||
series: List([
|
||||
{
|
||||
name: 'Session Count',
|
||||
filter: new Filter({ filters: [] }),
|
||||
},
|
||||
])
|
||||
}),
|
||||
instance: null,
|
||||
activeWidget: null,
|
||||
});
|
||||
|
||||
// Metric - Series - [] - filters
|
||||
function reducer(state = initialState, action = {}) {
|
||||
switch (action.type) {
|
||||
case EDIT:
|
||||
return state.mergeIn([ 'instance' ], action.instance);
|
||||
case UPDATE_SERIES:
|
||||
const instance = state.get('instance')
|
||||
if (instance) {
|
||||
return state.mergeIn([ 'instance' ], action.instance);
|
||||
} else {
|
||||
return state.set('instance', action.instance);
|
||||
}
|
||||
case INIT:
|
||||
return state.set('instance', action.instance);
|
||||
case UPDATE_SERIES:
|
||||
return state.mergeIn(['instance', 'series', action.index], action.series);
|
||||
case success(SAVE):
|
||||
return state.mergeIn([ 'instance' ], action.data);
|
||||
return updateItemInList(updateInstance(state, action.data), action.data);
|
||||
// return state.mergeIn([ 'instance' ], action.data);
|
||||
case success(REMOVE):
|
||||
return state.update('list', list => list.filter(item => item.metricId !== action.id));
|
||||
case success(FETCH):
|
||||
|
|
@ -57,6 +71,10 @@ function reducer(state = initialState, action = {}) {
|
|||
case success(FETCH_LIST):
|
||||
const { data } = action;
|
||||
return state.set("list", List(data.map(CustomMetric)));
|
||||
case success(FETCH_SESSION_LIST):
|
||||
return state.set("sessionList", List(action.data).map(Session));
|
||||
case SET_ACTIVE_WIDGET:
|
||||
return state.set("activeWidget", action.widget);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
|
@ -66,6 +84,8 @@ export default mergeReducers(
|
|||
createRequestReducer({
|
||||
[ ROOT_KEY ]: FETCH_LIST,
|
||||
fetch: FETCH,
|
||||
save: SAVE,
|
||||
fetchSessionList: FETCH_SESSION_LIST,
|
||||
}),
|
||||
);
|
||||
|
||||
|
|
@ -89,7 +109,7 @@ export function fetch(id) {
|
|||
export function save(instance) {
|
||||
return {
|
||||
types: SAVE.array,
|
||||
call: client => client.post( `/${ name }s`, instance.toSaveData()),
|
||||
call: client => client.post( `/${ instance.exists() ? name + 's/' + instance[idKey] : name + 's'}`, instance.toSaveData()),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -105,4 +125,39 @@ export function setAlertMetricId(id) {
|
|||
type: SET_ALERT_METRIC_ID,
|
||||
id,
|
||||
};
|
||||
}
|
||||
|
||||
export const addSeries = (series) => (dispatch, getState) => {
|
||||
const instance = getState().getIn([ 'customMetrics', 'instance' ])
|
||||
const _series = series || new FilterSeries({
|
||||
name: 'New',
|
||||
filter: new Filter({ filters: [], eventsOrder: 'and' }),
|
||||
});
|
||||
return dispatch({
|
||||
type: EDIT,
|
||||
instance: {
|
||||
series: instance.series.push(_series)
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export const init = (instnace = null, setDefault = true) => (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: INIT,
|
||||
instance: instnace ? instnace : (setDefault ? defaultInstance : null),
|
||||
});
|
||||
}
|
||||
|
||||
export const fetchSessionList = (params) => (dispatch, getState) => {
|
||||
dispatch({
|
||||
types: array(FETCH_SESSION_LIST),
|
||||
call: client => client.post(`/sessions/search2`, { ...params }),
|
||||
});
|
||||
}
|
||||
|
||||
export const setActiveWidget = (widget) => (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: SET_ACTIVE_WIDGET,
|
||||
widget,
|
||||
});
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import Record from 'Types/Record';
|
||||
import { List } from 'immutable';
|
||||
import Filter from 'Types/filter';
|
||||
import { validateName } from 'App/validate';
|
||||
|
||||
export const FilterSeries = Record({
|
||||
seriesId: undefined,
|
||||
|
|
@ -31,7 +32,7 @@ export default Record({
|
|||
idKey: 'metricId',
|
||||
methods: {
|
||||
validate() {
|
||||
return validateName(this.name, { diacritics: true });
|
||||
return validateName(this.name, { empty: false });
|
||||
},
|
||||
|
||||
toSaveData() {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
export const getDayStartAndEndTimestamps = (date) => {
|
||||
const start = moment(date).startOf('day').valueOf();
|
||||
const end = moment(date).endOf('day').valueOf();
|
||||
return { start, end };
|
||||
};
|
||||
|
||||
// const getPerformanceDensity = (period) => {
|
||||
// switch (period) {
|
||||
|
|
@ -34,4 +39,13 @@ export const getTimeString = (ts, period) => {
|
|||
};
|
||||
|
||||
export const getChartFormatter = period => (data = []) =>
|
||||
data.map(({ timestamp, ...rest }) => ({ time: getTimeString(timestamp, period), ...rest }));
|
||||
data.map(({ timestamp, ...rest }) => ({ time: getTimeString(timestamp, period), ...rest, timestamp }));
|
||||
|
||||
export const getStartAndEndTimestampsByDensity = (current, start, end, density) => {
|
||||
const diff = end - start;
|
||||
const step = diff / density;
|
||||
const currentIndex = Math.floor((current - start) / step);
|
||||
const startTimestamp = parseInt(start + currentIndex * step);
|
||||
const endTimestamp = parseInt(startTimestamp + step);
|
||||
return { startTimestamp, endTimestamp };
|
||||
};
|
||||
Loading…
Add table
Reference in a new issue