feat(ui) - dashboard improvements - api - integration

This commit is contained in:
Shekar Siri 2022-12-12 13:46:52 +05:30 committed by sylenien
parent 7bd6ee3065
commit 7818bc88ee
12 changed files with 173 additions and 32 deletions

View file

@ -25,7 +25,7 @@ const siteIdRequiredPaths = [
'/heatmaps',
'/custom_metrics',
'/dashboards',
'/metrics',
'/cards',
'/unprocessed',
'/notes',
// '/custom_metrics/sessions',

View file

@ -56,7 +56,7 @@ function DashboardWidgetGrid(props: Props) {
>
<div className="grid gap-4 grid-cols-4 items-start pb-10" id={props.id}>{smallWidgets.length > 0 ? (
<>
<div className="font-semibold text-xl py-4 flex items-center gap-2col-span-4">
<div className="font-semibold text-xl py-4 flex items-center gap-2 col-span-4">
<Icon name="grid-horizontal" size={26} />
Web Vitals
</div>
@ -82,7 +82,7 @@ function DashboardWidgetGrid(props: Props) {
) : null}
{smallWidgets.length > 0 && regularWidgets.length > 0 ? (
<div className="font-semibold text-xl py-4 flex items-center gap-2col-span-4">
<div className="font-semibold text-xl py-4 flex items-center gap-2 col-span-4">
<Icon name="grid-horizontal" size={26} />
All Metrics
</div>

View file

@ -39,19 +39,20 @@ function MetricListItem(props: Props) {
const path = withSiteId(`/metrics/${metric.metricId}`, siteId);
history.push(path);
};
return (
<div
className="grid grid-cols-12 py-4 border-t select-none items-center hover:bg-active-blue cursor-pointer px-6"
onClick={onItemClick}
>
<div className="col-span-4 flex items-center">
<Checkbox
{/* <Checkbox
name="slack"
className="mr-4"
type="checkbox"
checked={selected}
onClick={toggleSelection}
/>
/> */}
<div className="flex items-center">
<MetricTypeIcon type={metric.metricType} />
<div className="link capitalize-first">{metric.name}</div>

View file

@ -4,7 +4,7 @@ import MetricsLibraryModal from '../MetricsLibraryModal';
import MetricTypeItem, { MetricType } from '../MetricTypeItem/MetricTypeItem';
import { TYPES, LIBRARY } from 'App/constants/card';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { dashboardMetricCreate, withSiteId } from 'App/routes';
import { dashboardMetricCreate, metricCreate, withSiteId } from 'App/routes';
interface Props extends RouteComponentProps {
dashboardId: number;
@ -23,7 +23,11 @@ function MetricTypeList(props: Props) {
// TODO redirect to card builder with metricType query param
const path = withSiteId(dashboardMetricCreate(dashboardId + ''), siteId);
history.push(path);
const queryString = new URLSearchParams({ type: slug }).toString();
history.push({
pathname: path,
search: `?${queryString}`
});
};
return (

View file

@ -1,5 +1,5 @@
import React from 'react';
import { Icon, PageTitle, Button, Link } from 'UI';
import { Icon, PageTitle, Button, Link, SegmentSelection } from 'UI';
import MetricsSearch from '../MetricsSearch';
import Select from 'Shared/Select';
import { useStore } from 'App/mstore';
@ -8,6 +8,9 @@ import { useObserver } from 'mobx-react-lite';
function MetricViewHeader() {
const { metricStore } = useStore();
const sort = useObserver(() => metricStore.sort);
const listView = useObserver(() => metricStore.listView);
return (
<div>
<div className="flex items-center mb-4 justify-between px-6">
@ -15,9 +18,21 @@ function MetricViewHeader() {
<PageTitle title="Metrics" className="" />
</div>
<div className="ml-auto flex items-center">
<Link to={'/metrics/create'}>
{/* <Link to={'/metrics/create'}>
<Button variant="primary">Create</Button>
</Link>
</Link> */}
<SegmentSelection
name="viewType"
className="my-3"
primary
icons={true}
onSelect={ () => metricStore.updateKey('listView', !listView) }
value={{ value: listView ? 'list' : 'grid' }}
list={ [
{ value: 'list', name: '', icon: 'graph-up-arrow' },
{ value: 'grid', name: '', icon: 'hash' },
]}
/>
<div className="mx-2">
<Select
options={[

View file

@ -0,0 +1,14 @@
import React from 'react';
interface Props {
}
function MetricsGrid(props: Props) {
return (
<div className="grid grid-cols-3 gap-4">
</div>
);
}
export default MetricsGrid;

View file

@ -0,0 +1 @@
export { default } from './MetricsGrid'

View file

@ -0,0 +1,40 @@
import React from 'react';
import MetricListItem from '../MetricListItem';
import WidgetWrapper from 'App/components/Dashboard/components/WidgetWrapper';
interface Props {
list: any;
siteId: any;
selectedList: any;
toggleSelection?: (metricId: any) => void;
}
function GridView(props: Props) {
const { siteId, list, selectedList, toggleSelection } = props;
return (
<div className="grid grid-cols-3 gap-4 m-4">
{list.map((metric: any) => (
<React.Fragment key={metric.metricId}>
<WidgetWrapper
key={metric.metricId}
widget={metric}
active={selectedList.includes(metric.metricId)}
isTemplate={true}
isWidget={metric.metricType === 'predefined'}
onClick={() => toggleSelection(parseInt(metric.metricId))}
/>
{/* <MetricListItem
metric={metric}
siteId={siteId}
selected={selectedList.includes(parseInt(metric.metricId))}
toggleSelection={(e: any) => {
e.stopPropagation();
toggleSelection(parseInt(metric.metricId));
}}
/> */}
</React.Fragment>
))}
</div>
);
}
export default GridView;

View file

@ -0,0 +1,45 @@
import React from 'react';
import MetricListItem from '../MetricListItem';
import { Checkbox } from 'UI';
interface Props {
list: any;
siteId: any;
selectedList: any;
toggleSelection?: (metricId: any) => void;
}
function ListView(props: Props) {
const { siteId, list, selectedList, toggleSelection } = props;
return (
<div>
<div className="grid grid-cols-12 py-2 font-medium px-6">
{/* <div className="col-span-4 flex items-center">
<Checkbox
name="slack"
className="mr-4"
type="checkbox"
checked={false}
onClick={() => selectedList(list.map((i: any) => i.metricId))}
/>
<span>Title</span>
</div> */}
<div className="col-span-4">Owner</div>
<div className="col-span-2">Visibility</div>
<div className="col-span-2 text-right">Last Modified</div>
</div>
{list.map((metric: any) => (
<MetricListItem
metric={metric}
siteId={siteId}
selected={selectedList.includes(parseInt(metric.metricId))}
toggleSelection={(e: any) => {
e.stopPropagation();
toggleSelection(parseInt(metric.metricId));
}}
/>
))}
</div>
);
}
export default ListView;

View file

@ -1,4 +1,4 @@
import { observer } from 'mobx-react-lite';
import { observer, useObserver } from 'mobx-react-lite';
import React, { useEffect, useState } from 'react';
import { NoContent, Pagination, Icon, Checkbox } from 'UI';
import { useStore } from 'App/mstore';
@ -6,6 +6,8 @@ import { filterList } from 'App/utils';
import MetricListItem from '../MetricListItem';
import { sliceListPerPage } from 'App/utils';
import Widget from 'App/mstore/types/widget';
import GridView from './GridView';
import ListView from './ListView';
function MetricsList({
siteId,
@ -17,6 +19,7 @@ function MetricsList({
const { metricStore } = useStore();
const metrics = metricStore.sortedWidgets;
const metricsSearch = metricStore.metricsSearch;
const listView = useObserver(() => metricStore.listView);
const [selectedMetrics, setSelectedMetrics] = useState<any>([]);
useEffect(() => {
@ -61,6 +64,22 @@ function MetricsList({
</div>
}
>
{listView ? (
<ListView
siteId={siteId}
list={sliceListPerPage(list, metricStore.page - 1, metricStore.pageSize)}
selectedList={selectedMetrics}
toggleSelection={toggleMetricSelection}
/>
) : (
<GridView
siteId={siteId}
list={sliceListPerPage(list, metricStore.page - 1, metricStore.pageSize)}
selectedList={selectedMetrics}
toggleSelection={toggleMetricSelection}
/>
)}
{/*
<div className="mt-3 rounded bg-white">
<div className="grid grid-cols-12 py-2 font-medium px-6">
<div className="col-span-4 flex items-center">
@ -78,20 +97,21 @@ function MetricsList({
<div className="col-span-2 text-right">Last Modified</div>
</div>
{sliceListPerPage(list, metricStore.page - 1, metricStore.pageSize).map((metric: any) => (
<React.Fragment key={metric.metricId}>
<MetricListItem
metric={metric}
siteId={siteId}
selected={selectedMetrics.includes(parseInt(metric.metricId))}
toggleSelection={(e: any) => {
e.stopPropagation();
toggleMetricSelection(parseInt(metric.metricId));
}}
/>
</React.Fragment>
))}
{sliceListPerPage(list, metricStore.page - 1, metricStore.pageSize).map((metric: any) => (
// <React.Fragment key={metric.metricId}>
// <MetricListItem
// metric={metric}
// siteId={siteId}
// selected={selectedMetrics.includes(parseInt(metric.metricId))}
// toggleSelection={(e: any) => {
// e.stopPropagation();
// toggleMetricSelection(parseInt(metric.metricId));
// }}
// />
// </React.Fragment>
))}
</div>
*/}
<div className="w-full flex items-center justify-between py-4 px-6 border-t">
<div className="text-disabled-text">

View file

@ -18,6 +18,7 @@ export default class MetricStore {
sessionsPage: number = 1;
sessionsPageSize: number = 10;
listView?: boolean = false
constructor() {
makeAutoObservable(this);

View file

@ -18,7 +18,7 @@ export default class MetricService {
* @returns {Promise<any>}
*/
getMetrics(): Promise<any> {
return this.client.get('/metrics')
return this.client.post('/cards/search', { limit: 100 })
.then((response: { json: () => any; }) => response.json())
.then((response: { data: any; }) => response.data || []);
}
@ -29,7 +29,7 @@ export default class MetricService {
* @returns {Promise<any>}
*/
getMetric(metricId: string): Promise<any> {
return this.client.get('/metrics/' + metricId)
return this.client.get('/cards/' + metricId)
.then(fetchErrorCheck)
.then((response: { data: any; }) => response.data || {});
}
@ -43,7 +43,7 @@ export default class MetricService {
const data = metric.toJson()
const isCreating = !data[Widget.ID_KEY];
const method = isCreating ? 'post' : 'put';
const url = isCreating ? '/metrics' : '/metrics/' + data[Widget.ID_KEY];
const url = isCreating ? '/cards' : '/cards/' + data[Widget.ID_KEY];
return this.client[method](url, data)
.then(fetchErrorCheck)
.then((response: { data: any; }) => response.data || {})
@ -55,7 +55,7 @@ export default class MetricService {
* @returns {Promise<any>}
*/
deleteMetric(metricId: string): Promise<any> {
return this.client.delete('/metrics/' + metricId)
return this.client.delete('/cards/' + metricId)
.then((response: { json: () => any; }) => response.json())
.then((response: { data: any; }) => response.data);
}
@ -66,13 +66,13 @@ export default class MetricService {
* @returns {Promise<any>}
*/
getTemplates(): Promise<any> {
return this.client.get('/metrics/templates')
return this.client.get('/cards/templates')
.then((response: { json: () => any; }) => response.json())
.then((response: { data: any; }) => response.data || []);
}
getMetricChartData(metric: Widget, data: any, isWidget: boolean = false): Promise<any> {
const path = isWidget ? `/metrics/${metric.metricId}/chart` : `/metrics/try`;
const path = isWidget ? `/cards/${metric.metricId}/chart` : `/cards/try`;
return this.client.post(path, data)
.then(fetchErrorCheck)
.then((response: { data: any; }) => response.data || {});
@ -84,13 +84,13 @@ export default class MetricService {
* @returns
*/
fetchSessions(metricId: string, filter: any): Promise<any> {
return this.client.post(metricId ? `/metrics/${metricId}/sessions` : '/metrics/try/sessions', filter)
return this.client.post(metricId ? `/cards/${metricId}/sessions` : '/cards/try/sessions', filter)
.then((response: { json: () => any; }) => response.json())
.then((response: { data: any; }) => response.data || []);
}
fetchIssues(filter: string): Promise<any> {
return this.client.post(`/metrics/try/issues`, filter)
return this.client.post(`/cards/try/issues`, filter)
.then((response: { json: () => any; }) => response.json())
.then((response: { data: any; }) => response.data || {});
}