feat(ui) - cards - metric search and other changes
This commit is contained in:
parent
9c86c8f4fc
commit
6ff4d74131
9 changed files with 72 additions and 24 deletions
|
|
@ -5,6 +5,7 @@ import MetricTypeItem, { MetricType } from '../MetricTypeItem/MetricTypeItem';
|
|||
import { TYPES, LIBRARY } from 'App/constants/card';
|
||||
import { withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import { dashboardMetricCreate, metricCreate, withSiteId } from 'App/routes';
|
||||
import { useStore } from 'App/mstore';
|
||||
|
||||
interface Props extends RouteComponentProps {
|
||||
dashboardId: number;
|
||||
|
|
@ -12,13 +13,16 @@ interface Props extends RouteComponentProps {
|
|||
}
|
||||
function MetricTypeList(props: Props) {
|
||||
const { dashboardId, siteId, history } = props;
|
||||
const { metricStore } = useStore();
|
||||
const { hideModal } = useModal();
|
||||
|
||||
const { showModal } = useModal();
|
||||
const onClick = ({ slug }: MetricType) => {
|
||||
hideModal();
|
||||
if (slug === LIBRARY) {
|
||||
return showModal(<MetricsLibraryModal siteId={siteId} dashboardId={dashboardId} />, { right: true, width: 800 });
|
||||
return showModal(<MetricsLibraryModal siteId={siteId} dashboardId={dashboardId} />, { right: true, width: 800, onClose: () => {
|
||||
metricStore.updateKey('metricsSearch', '')
|
||||
} });
|
||||
}
|
||||
|
||||
// TODO redirect to card builder with metricType query param
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import Modal from 'App/components/Modal/Modal';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import MetricsList from '../MetricsList';
|
||||
import { Button } from 'UI';
|
||||
import { Button, Icon } from 'UI';
|
||||
import { useModal } from 'App/components/Modal';
|
||||
import { useStore } from 'App/mstore';
|
||||
import { observer, useObserver } from 'mobx-react-lite';
|
||||
|
|
@ -23,9 +23,22 @@ function MetricsLibraryModal(props: Props) {
|
|||
setSelectedList(list);
|
||||
};
|
||||
|
||||
const onChange = ({ target: { value } }: any) => {
|
||||
metricStore.updateKey('metricsSearch', value)
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal.Header title="Cards Library" />
|
||||
<Modal.Header title="Cards Library">
|
||||
<div className="flex items-center justify-between px-4 pt-4">
|
||||
<div className="text-lg flex items-center font-medium">
|
||||
<div>Cards Library</div>
|
||||
</div>
|
||||
<div>
|
||||
<MetricSearch onChange={onChange} />
|
||||
</div>
|
||||
</div>
|
||||
</Modal.Header>
|
||||
<Modal.Content className="p-4 pb-20">
|
||||
<div className="border">
|
||||
<MetricsList siteId={siteId} onSelectionChange={onSelectionChange} />
|
||||
|
|
@ -40,6 +53,20 @@ function MetricsLibraryModal(props: Props) {
|
|||
|
||||
export default observer(MetricsLibraryModal);
|
||||
|
||||
function MetricSearch({ onChange }: any) {
|
||||
return (
|
||||
<div className="relative">
|
||||
<Icon name="search" className="absolute top-0 bottom-0 ml-2 m-auto" size="16" />
|
||||
<input
|
||||
name="dashboardsSearch"
|
||||
className="bg-white p-2 border border-borderColor-gray-light-shade rounded w-full pl-10"
|
||||
placeholder="Filter by title or owner"
|
||||
onChange={onChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SelectedContent({ dashboardId, selected }: any) {
|
||||
const { hideModal } = useModal();
|
||||
const { metricStore, dashboardStore } = useStore();
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ function WidgetChart(props: Props) {
|
|||
const drillDownFilter = dashboardStore.drillDownFilter;
|
||||
const colors = Styles.customMetricColors;
|
||||
const [loading, setLoading] = useState(true)
|
||||
const isOverviewWidget = metric.metricType === 'predefined' && metric.viewType === 'overview';
|
||||
const isOverviewWidget = metric.metricType === WEB_VITALS;
|
||||
const params = { density: isOverviewWidget ? 7 : 70 }
|
||||
const metricParams = { ...params }
|
||||
const prevMetricRef = useRef<any>();
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import Select from 'Shared/Select';
|
|||
import { withSiteId, dashboardMetricDetails, metricDetails } from 'App/routes';
|
||||
import MetricTypeDropdown from './components/MetricTypeDropdown';
|
||||
import MetricSubtypeDropdown from './components/MetricSubtypeDropdown';
|
||||
import { TIMESERIES, TABLE, CLICKMAP, FUNNEL, ERRORS } from 'App/constants/card';
|
||||
import { TIMESERIES, TABLE, CLICKMAP, FUNNEL, ERRORS, RESOURCE_MONITORING } from 'App/constants/card';
|
||||
import { clickmapFilter } from 'App/types/filter/newFilter';
|
||||
import { renderClickmapThumbnail } from './renderMap'
|
||||
|
||||
|
|
@ -41,7 +41,6 @@ function WidgetForm(props: Props) {
|
|||
const cannotSaveFunnel = isFunnel && (!metric.series[0] || eventsLength <= 1);
|
||||
|
||||
const writeOption = ({ value, name }: any) => {
|
||||
console.log(name, value)
|
||||
value = Array.isArray(value) ? value : value.value;
|
||||
const obj: any = { [name]: value };
|
||||
|
||||
|
|
@ -69,9 +68,10 @@ function WidgetForm(props: Props) {
|
|||
obj['viewType'] = 'table';
|
||||
} else if (value === FUNNEL) {
|
||||
obj['metricOf'] = 'sessionCount';
|
||||
} else if (value === ERRORS) {
|
||||
} else if (value === ERRORS || value === RESOURCE_MONITORING) {
|
||||
obj['viewType'] = 'chart';
|
||||
}
|
||||
}
|
||||
|
||||
if (metric.metricType === CLICKMAP && value !== CLICKMAP) {
|
||||
metric.series[0].filter.removeFilter(0)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ function Modal({ component, className = 'bg-white', props, hideModal }: Props) {
|
|||
document.querySelector('body').style.overflow = 'visible';
|
||||
}
|
||||
});
|
||||
});return component ? (
|
||||
});
|
||||
|
||||
return component ? (
|
||||
ReactDOM.createPortal(
|
||||
<ModalOverlay hideModal={hideModal} left={!props.right} right={props.right}>
|
||||
<div
|
||||
|
|
@ -38,8 +40,12 @@ function Modal({ component, className = 'bg-white', props, hideModal }: Props) {
|
|||
);
|
||||
}
|
||||
|
||||
Modal.Header = ({ title }: { title: string }) => {
|
||||
return (
|
||||
Modal.Header = ({ title, children }: { title?: string, children?: any }) => {
|
||||
return !!children ? (
|
||||
<div>
|
||||
{children}
|
||||
</div>
|
||||
): (
|
||||
<div className="text-lg flex items-center p-4 font-medium">
|
||||
<div>{title}</div>
|
||||
</div>
|
||||
|
|
@ -47,11 +53,22 @@ Modal.Header = ({ title }: { title: string }) => {
|
|||
};
|
||||
|
||||
Modal.Content = ({ children, className = 'p-4' }: { children: any; className?: string }) => {
|
||||
return <div className={cn('overflow-y-auto relative', className)} style={{ height: 'calc(100vh - 52px)'}}>{children}</div>;
|
||||
return (
|
||||
<div
|
||||
className={cn('overflow-y-auto relative', className)}
|
||||
style={{ height: 'calc(100vh - 52px)' }}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Modal.Footer = ({ children, className = ''} : any) => {
|
||||
return <div className={cn('absolute bottom-0 w-full left-0 right-0', className)} style={{ }}>{children}</div>;
|
||||
}
|
||||
Modal.Footer = ({ children, className = '' }: any) => {
|
||||
return (
|
||||
<div className={cn('absolute bottom-0 w-full left-0 right-0', className)} style={{}}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Modal;
|
||||
|
|
|
|||
|
|
@ -146,12 +146,6 @@ export const TYPES: CardType[] = [
|
|||
description: 'Find the adoption of your all features in your app.',
|
||||
slug: WEB_VITALS,
|
||||
subTypes: [
|
||||
{
|
||||
title: 'Resources Count By Type',
|
||||
slug: FilterKey.RESOURCES_COUNT_BY_TYPE,
|
||||
description: '',
|
||||
},
|
||||
{ title: 'Resources Loading Time', slug: FilterKey.RESOURCES_LOADING_TIME, description: '' },
|
||||
{
|
||||
title: 'CPU Load',
|
||||
slug: FilterKey.AVG_CPU,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import Widget from './types/widget';
|
|||
import { metricService, errorService } from 'App/services';
|
||||
import { toast } from 'react-toastify';
|
||||
import Error from './types/error';
|
||||
import { TIMESERIES, TABLE, CLICKMAP, FUNNEL, ERRORS, RESOURCE_MONITORING, PERFORMANCE, WEB_VITALS } from 'App/constants/card';
|
||||
|
||||
export default class MetricStore {
|
||||
isLoading: boolean = false;
|
||||
|
|
@ -58,7 +59,11 @@ export default class MetricStore {
|
|||
}
|
||||
|
||||
changeType(value: string) {
|
||||
this.instance.update({ metricType: value})
|
||||
const obj: any = { metricType: value};
|
||||
if (value === ERRORS || value === RESOURCE_MONITORING || value === PERFORMANCE || value === WEB_VITALS) {
|
||||
obj['viewType'] = 'chart';
|
||||
}
|
||||
this.instance.update(obj)
|
||||
}
|
||||
|
||||
reset(id: string) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { issueOptions } from 'App/constants/filterOptions';
|
|||
import { FilterKey } from 'Types/filter/filterType';
|
||||
import Period, { LAST_24_HOURS } from 'Types/app/period';
|
||||
import { metricService } from "App/services";
|
||||
import { WEB_VITALS } from "App/constants/card";
|
||||
|
||||
export default class Widget {
|
||||
public static get ID_KEY():string { return "metricId" }
|
||||
|
|
@ -134,7 +135,7 @@ export default class Widget {
|
|||
thumbnail: this.thumbnail,
|
||||
config: {
|
||||
...this.config,
|
||||
col: (this.metricType === 'funnel' || this.metricOf === FilterKey.ERRORS || this.metricOf === FilterKey.SESSIONS) ? 4 : 2
|
||||
col: (this.metricType === 'funnel' || this.metricOf === FilterKey.ERRORS || this.metricOf === FilterKey.SESSIONS) ? 4 : (this.metricType === WEB_VITALS ? 1 : 2)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -269,7 +269,7 @@ export enum FilterKey {
|
|||
IMPACTED_SESSIONS_BY_SLOW_PAGES = 'impactedSessionsBySlowPages',
|
||||
|
||||
// Resources
|
||||
BREAKDOWN_OF_LOADED_RESOURCES = 'breakdownOfLoadedResources',
|
||||
BREAKDOWN_OF_LOADED_RESOURCES = 'resourcesCountByType',
|
||||
MISSING_RESOURCES = 'missingResources',
|
||||
RESOURCE_TYPE_VS_RESPONSE_END = 'resourceTypeVsResponseEnd',
|
||||
RESOURCE_FETCH_TIME = 'resourceFetchTime',
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue