fix(ui): change dashboards overview
This commit is contained in:
parent
0f3f883a27
commit
d8129ab8e9
15 changed files with 261 additions and 122 deletions
|
|
@ -0,0 +1,73 @@
|
|||
import { observer } from 'mobx-react-lite';
|
||||
import React from 'react';
|
||||
import { NoContent, Pagination } from 'UI';
|
||||
import { useStore } from 'App/mstore';
|
||||
import { getRE } from 'App/utils';
|
||||
import { sliceListPerPage } from 'App/utils';
|
||||
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
|
||||
import DashboardListItem from './DashboardListItem';
|
||||
|
||||
const filterList = <T extends Record<string, any>>(list: T[], searchQuery: string): T[] => {
|
||||
const filterRE = getRE(searchQuery, 'i');
|
||||
console.log(filterRE)
|
||||
let _list = list.filter((w: T) => {
|
||||
console.log(w.name, w.owner, w.description, filterRE.test(w.name))
|
||||
return filterRE.test(w.name) || filterRE.test(w.owner) || filterRE.test(w.description);
|
||||
});
|
||||
return _list
|
||||
}
|
||||
|
||||
function DashboardList() {
|
||||
const { dashboardStore } = useStore();
|
||||
const [shownDashboards, setDashboards] = React.useState([]);
|
||||
const dashboards = dashboardStore.dashboards;
|
||||
const dashboardsSearch = dashboardStore.dashboardsSearch;
|
||||
|
||||
React.useEffect(() => {
|
||||
setDashboards(filterList(dashboards, dashboardsSearch))
|
||||
}, [dashboardsSearch])
|
||||
|
||||
const list = dashboardsSearch !== '' ? shownDashboards : dashboards;
|
||||
const lenth = list.length;
|
||||
|
||||
return (
|
||||
<NoContent
|
||||
show={lenth === 0}
|
||||
title={
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<AnimatedSVG name={ICONS.NO_RESULTS} size={170} />
|
||||
<div className="mt-6 text-2xl">No data available.</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="mt-3 border-b">
|
||||
<div className="grid grid-cols-12 p-4 font-medium">
|
||||
<div className="col-span-8">Title</div>
|
||||
<div className="col-span-2">Visibility</div>
|
||||
<div className="col-span-2 text-right">Created</div>
|
||||
</div>
|
||||
|
||||
{sliceListPerPage(list, dashboardStore.page - 1, dashboardStore.pageSize).map((dashboard: any) => (
|
||||
<React.Fragment key={dashboard.dashboardId}>
|
||||
<DashboardListItem dashboard={dashboard} />
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="w-full flex items-center justify-between pt-4">
|
||||
<div className="text-disabled-text">
|
||||
Showing <span className="font-semibold">{Math.min(list.length, dashboardStore.pageSize)}</span> out of <span className="font-semibold">{list.length}</span> Dashboards
|
||||
</div>
|
||||
<Pagination
|
||||
page={dashboardStore.page}
|
||||
totalPages={Math.ceil(lenth / dashboardStore.pageSize)}
|
||||
onPageChange={(page) => dashboardStore.updateKey('page', page)}
|
||||
limit={dashboardStore.pageSize}
|
||||
debounceRequest={100}
|
||||
/>
|
||||
</div>
|
||||
</NoContent>
|
||||
);
|
||||
}
|
||||
|
||||
export default observer(DashboardList);
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
import React from 'react';
|
||||
import { Icon } from 'UI';
|
||||
import { connect } from 'react-redux';
|
||||
import{ IDashboard } from "App/mstore/types/dashboard";
|
||||
import { checkForRecent } from 'App/date';
|
||||
import { withSiteId, dashboardSelected } from 'App/routes';
|
||||
import { useStore } from 'App/mstore';
|
||||
import { withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
|
||||
interface Props extends RouteComponentProps {
|
||||
dashboard: IDashboard;
|
||||
siteId: string;
|
||||
}
|
||||
|
||||
function DashboardListItem(props: Props) {
|
||||
const { dashboard, siteId, history } = props;
|
||||
const { dashboardStore } = useStore();
|
||||
|
||||
const onItemClick = () => {
|
||||
dashboardStore.selectDashboardById(dashboard.dashboardId);
|
||||
const path = withSiteId(dashboardSelected(dashboard.dashboardId), siteId);
|
||||
history.push(path);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<div className="grid grid-cols-12 p-4 border-t select-none">
|
||||
<div className="col-span-8 flex items-start">
|
||||
<div className="flex items-center link capitalize-first" onClick={onItemClick}>
|
||||
<div className="w-9 h-9 rounded-full bg-tealx-lightest flex items-center justify-center mr-2">
|
||||
<Icon name="columns-gap" size="16" color="tealx" />
|
||||
</div>
|
||||
<div>
|
||||
{dashboard.name}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* <div><Label className="capitalize">{metric.metricType}</Label></div> */}
|
||||
<div className="col-span-2">
|
||||
<div className="flex items-center">
|
||||
<Icon name={dashboard.isPublic ? "user-friends" : "person-fill"} className="mr-2" />
|
||||
<span>{dashboard.isPublic ? 'Team' : 'Private'}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-2 text-right">
|
||||
{checkForRecent(dashboard.createdAt, 'LLL dd, yyyy, hh:mm a')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-disabled-text px-4 pb-2">
|
||||
{dashboard.description}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(state => ({ siteId: state.getIn([ 'site', 'siteId' ]) }))(withRouter(DashboardListItem))
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { useStore } from 'App/mstore';
|
||||
import { Icon } from 'UI';
|
||||
import { debounce } from 'App/utils';
|
||||
|
||||
let debounceUpdate: any = () => {}
|
||||
|
||||
function DashboardSearch() {
|
||||
const { dashboardStore } = useStore();
|
||||
const [query, setQuery] = useState(dashboardStore.dashboardsSearch);
|
||||
useEffect(() => {
|
||||
debounceUpdate = debounce((key: string, value: any) => dashboardStore.updateKey(key, value), 500);
|
||||
}, [])
|
||||
|
||||
// @ts-ignore
|
||||
const write = ({ target: { value } }) => {
|
||||
setQuery(value);
|
||||
debounceUpdate('dashboardsSearch', value);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<Icon name="search" className="absolute top-0 bottom-0 ml-2 m-auto" size="16" />
|
||||
<input
|
||||
value={query}
|
||||
name="dashboardsSearch"
|
||||
className="bg-white p-2 border border-borderColor-gray-light-shade rounded w-full pl-10"
|
||||
placeholder="Filter by title or description"
|
||||
onChange={write}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default observer(DashboardSearch);
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import React from 'react';
|
||||
import { Button, PageTitle, Icon, Link } from 'UI';
|
||||
import withPageTitle from 'HOCs/withPageTitle';
|
||||
import DashboardList from './DashboardList';
|
||||
import DashboardSearch from './DashboardSearch';
|
||||
|
||||
function DashboardsView() {
|
||||
return (
|
||||
<div style={{ maxWidth: '1300px', margin: 'auto'}} className="bg-white rounded p-4">
|
||||
<div className="flex items-center mb-4 justify-between px-4">
|
||||
<div className="flex items-baseline mr-3">
|
||||
<PageTitle title="Dashboards" className="" />
|
||||
</div>
|
||||
<Link to={'/metrics/create'}><Button variant="primary">Create Dashboard</Button></Link>
|
||||
<div className="ml-auto w-1/4">
|
||||
<DashboardSearch />
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-xl text-disabled-text flex items-center pl-4">
|
||||
<Icon name="info-circle-fill" className="mr-2" size={18} />
|
||||
A dashboard is a custom visualization using your OpenReplay data.
|
||||
</div>
|
||||
<DashboardList />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default withPageTitle('Dashboards - OpenReplay')(DashboardsView);
|
||||
|
|
@ -0,0 +1 @@
|
|||
export { default } from './DashboardsView';
|
||||
|
|
@ -16,6 +16,7 @@ import DashboardView from '../DashboardView';
|
|||
import MetricsView from '../MetricsView';
|
||||
import WidgetView from '../WidgetView';
|
||||
import WidgetSubDetailsView from '../WidgetSubDetailsView';
|
||||
import DashboardsView from '../DashboardList';
|
||||
|
||||
function DashboardViewSelected({ siteId, dashboardId }) {
|
||||
return (
|
||||
|
|
@ -44,8 +45,8 @@ function DashboardRouter(props: Props) {
|
|||
<WidgetSubDetailsView siteId={siteId} {...props} />
|
||||
</Route>
|
||||
|
||||
<Route exact strict path={withSiteId(dashboard(), siteId)}>
|
||||
<DashboardView siteId={siteId} dashboardId={dashboardId} />
|
||||
<Route exact path={withSiteId(dashboard(), siteId)}>
|
||||
<DashboardsView />
|
||||
</Route>
|
||||
|
||||
<Route exact strict path={withSiteId(dashboardMetricDetails(dashboardId), siteId)}>
|
||||
|
|
|
|||
|
|
@ -1,113 +1,40 @@
|
|||
//@ts-nocheck
|
||||
import { useObserver } from 'mobx-react-lite';
|
||||
import React from 'react';
|
||||
import { SideMenuitem, SideMenuHeader, Icon, Popup, Button } from 'UI';
|
||||
import { useStore } from 'App/mstore';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { withSiteId, dashboardSelected, metrics } from 'App/routes';
|
||||
import { useModal } from 'App/components/Modal';
|
||||
import DashbaordListModal from '../DashbaordListModal';
|
||||
import DashboardModal from '../DashboardModal';
|
||||
import cn from 'classnames';
|
||||
import { SideMenuitem, SideMenuHeader } from 'UI';
|
||||
import { withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import { withSiteId, metrics, dashboard } from 'App/routes';
|
||||
import { connect } from 'react-redux';
|
||||
import { compose } from 'redux'
|
||||
import { setShowAlerts } from 'Duck/dashboard';
|
||||
// import stl from 'Shared/MainSearchBar/mainSearchBar.module.css';
|
||||
|
||||
const SHOW_COUNT = 8;
|
||||
|
||||
interface Props {
|
||||
interface Props extends RouteComponentProps {
|
||||
siteId: string
|
||||
history: any
|
||||
setShowAlerts: (show: boolean) => void
|
||||
}
|
||||
function DashboardSideMenu(props: RouteComponentProps<Props>) {
|
||||
function DashboardSideMenu(props: Props) {
|
||||
const { history, siteId, setShowAlerts } = props;
|
||||
const { hideModal, showModal } = useModal();
|
||||
const { dashboardStore } = useStore();
|
||||
const dashboardId = useObserver(() => dashboardStore.selectedDashboard?.dashboardId);
|
||||
const dashboardsPicked = useObserver(() => dashboardStore.dashboards.slice(0, SHOW_COUNT));
|
||||
const remainingDashboardsCount = dashboardStore.dashboards.length - SHOW_COUNT;
|
||||
const isMetric = history.location.pathname.includes('metrics');
|
||||
const isDashboards = history.location.pathname.includes('dashboard');
|
||||
|
||||
const redirect = (path) => {
|
||||
const redirect = (path: string) => {
|
||||
history.push(path);
|
||||
}
|
||||
|
||||
const onItemClick = (dashboard) => {
|
||||
dashboardStore.selectDashboardById(dashboard.dashboardId);
|
||||
const path = withSiteId(dashboardSelected(dashboard.dashboardId), parseInt(siteId));
|
||||
history.push(path);
|
||||
};
|
||||
|
||||
const onAddDashboardClick = (e) => {
|
||||
dashboardStore.initDashboard();
|
||||
showModal(<DashboardModal siteId={siteId} />, { right: true })
|
||||
}
|
||||
|
||||
const togglePinned = (dashboard, e) => {
|
||||
e.stopPropagation();
|
||||
dashboardStore.updatePinned(dashboard.dashboardId);
|
||||
}
|
||||
|
||||
return useObserver(() => (
|
||||
return (
|
||||
<div>
|
||||
<SideMenuHeader
|
||||
className="mb-4 flex items-center"
|
||||
text="DASHBOARDS"
|
||||
button={
|
||||
<Button onClick={onAddDashboardClick} variant="text-primary">
|
||||
<>
|
||||
<Icon name="plus" size="16" color="main" />
|
||||
<span className="ml-1" style={{ textTransform: 'none' }}>Create</span>
|
||||
</>
|
||||
</Button>
|
||||
}
|
||||
text="Preferences"
|
||||
/>
|
||||
{dashboardsPicked.map((item: any) => (
|
||||
<SideMenuitem
|
||||
key={ item.dashboardId }
|
||||
active={item.dashboardId === dashboardId && !isMetric}
|
||||
title={ item.name }
|
||||
iconName={ item.icon }
|
||||
onClick={() => onItemClick(item)}
|
||||
className="group"
|
||||
leading = {(
|
||||
<div className="ml-2 flex items-center cursor-default">
|
||||
{item.isPublic && (
|
||||
<Popup delay={500} content="Visible to the team" hideOnClick>
|
||||
<div className="p-1"><Icon name="user-friends" color="gray-light" size="16" /></div>
|
||||
</Popup>
|
||||
)}
|
||||
{item.isPinned && <div className="p-1 pointer-events-none"><Icon name="pin-fill" size="16" /></div>}
|
||||
{!item.isPinned && (
|
||||
<Popup
|
||||
delay={500}
|
||||
content="Set as default dashboard"
|
||||
hideOnClick={true}
|
||||
>
|
||||
<div
|
||||
className={cn("p-1 invisible group-hover:visible cursor-pointer")}
|
||||
onClick={(e) => togglePinned(item, e)}
|
||||
>
|
||||
<Icon name="pin-fill" size="16" color="gray-light" />
|
||||
</div>
|
||||
</Popup>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
<div>
|
||||
{remainingDashboardsCount > 0 && (
|
||||
<div
|
||||
className="my-2 py-2 color-teal cursor-pointer"
|
||||
onClick={() => showModal(<DashbaordListModal siteId={siteId} />, {})}
|
||||
>
|
||||
{remainingDashboardsCount} More
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<SideMenuitem
|
||||
active={isDashboards}
|
||||
id="menu-manage-alerts"
|
||||
title="Dashboards"
|
||||
iconName="columns-gap"
|
||||
onClick={() => redirect(withSiteId(dashboard(), siteId))}
|
||||
/>
|
||||
</div>
|
||||
<div className="border-t w-full my-2" />
|
||||
<div className="w-full">
|
||||
<SideMenuitem
|
||||
|
|
@ -128,10 +55,10 @@ function DashboardSideMenu(props: RouteComponentProps<Props>) {
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withRouter,
|
||||
connect(null, { setShowAlerts }),
|
||||
)(DashboardSideMenu) as React.FunctionComponent<RouteComponentProps<Props>>
|
||||
)(DashboardSideMenu)
|
||||
|
|
|
|||
|
|
@ -15,8 +15,10 @@ import withPageTitle from "HOCs/withPageTitle";
|
|||
import withReport from "App/components/hocs/withReport";
|
||||
import DashboardOptions from "../DashboardOptions";
|
||||
import SelectDateRange from "Shared/SelectDateRange";
|
||||
// @ts-ignore
|
||||
import DashboardIcon from "../../../../svg/dashboard-icn.svg";
|
||||
import { Tooltip } from "react-tippy";
|
||||
import Breadcrumb from 'Shared/Breadcrumb';
|
||||
|
||||
interface IProps {
|
||||
siteId: string;
|
||||
|
|
@ -69,6 +71,10 @@ function DashboardView(props: Props) {
|
|||
dashboardStore.selectDefaultDashboard();
|
||||
}, [siteId])
|
||||
|
||||
useEffect(() => {
|
||||
dashboardStore.selectDashboardById(dashboardId);
|
||||
}, [dashboardId])
|
||||
|
||||
const onAddWidgets = () => {
|
||||
dashboardStore.initDashboard(dashboard);
|
||||
showModal(
|
||||
|
|
@ -138,15 +144,6 @@ function DashboardView(props: Props) {
|
|||
</div>
|
||||
}
|
||||
size="small"
|
||||
subtext={
|
||||
<Button
|
||||
variant="primary"
|
||||
size="small"
|
||||
onClick={onAddDashboardClick}
|
||||
>
|
||||
+ Create Dashboard
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<div style={{ maxWidth: "1300px", margin: "auto" }}>
|
||||
<DashboardEditModal
|
||||
|
|
@ -154,6 +151,15 @@ function DashboardView(props: Props) {
|
|||
closeHandler={() => setShowEditModal(false)}
|
||||
focusTitle={focusTitle}
|
||||
/>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{
|
||||
label: 'Dashboards',
|
||||
to: withSiteId('/dashboard', siteId),
|
||||
},
|
||||
{ label: dashboard && dashboard.name || '' },
|
||||
]}
|
||||
/>
|
||||
<div className="flex items-center mb-4 justify-between">
|
||||
<div className="flex items-center" style={{ flex: 3 }}>
|
||||
<PageTitle
|
||||
|
|
|
|||
|
|
@ -7,33 +7,31 @@ import MetricListItem from '../MetricListItem';
|
|||
import { sliceListPerPage } from 'App/utils';
|
||||
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
|
||||
|
||||
interface Props { }
|
||||
function MetricsList(props: Props) {
|
||||
function MetricsList() {
|
||||
const { metricStore } = useStore();
|
||||
const metrics = useObserver(() => metricStore.metrics);
|
||||
const metricsSearch = useObserver(() => metricStore.metricsSearch);
|
||||
const filterList = (list) => {
|
||||
const filterList = <T extends Record<string, any>>(list: T[]): T[] => {
|
||||
const filterRE = getRE(metricsSearch, 'i');
|
||||
let _list = list.filter(w => {
|
||||
const dashbaordNames = w.dashboards.map(d => d.name).join(' ');
|
||||
let _list = list.filter((w: T) => {
|
||||
const dashbaordNames = w.dashboards.map((d: any) => d.name).join(' ');
|
||||
return filterRE.test(w.name) || filterRE.test(w.metricType) || filterRE.test(w.owner) || filterRE.test(dashbaordNames);
|
||||
});
|
||||
return _list
|
||||
}
|
||||
const list: any = metricsSearch !== '' ? filterList(metrics) : metrics;
|
||||
const list = metricsSearch !== '' ? filterList(metrics) : metrics;
|
||||
const lenth = list.length;
|
||||
|
||||
useEffect(() => {
|
||||
metricStore.updateKey('sessionsPage', 1);
|
||||
}, [])
|
||||
|
||||
console.log(list, list.length)
|
||||
return useObserver(() => (
|
||||
<NoContent
|
||||
show={lenth === 0}
|
||||
title={
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<AnimatedSVG name={ICONS.NO_RESULTS} size="170" />
|
||||
<AnimatedSVG name={ICONS.NO_RESULTS} size={170} />
|
||||
<div className="mt-6 text-2xl">No data available.</div>
|
||||
</div>
|
||||
}
|
||||
|
|
@ -41,7 +39,6 @@ function MetricsList(props: Props) {
|
|||
<div className="mt-3 border-b rounded bg-white">
|
||||
<div className="grid grid-cols-12 p-4 font-medium">
|
||||
<div className="col-span-3">Title</div>
|
||||
{/* <div>Type</div> */}
|
||||
<div className="col-span-3">Owner</div>
|
||||
<div className="col-span-4">Visibility</div>
|
||||
<div className="col-span-2 text-right">Last Modified</div>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ function MetricsSearch(props) {
|
|||
debounceUpdate = debounce((key, value) => metricStore.updateKey(key, value), 500);
|
||||
}, [])
|
||||
|
||||
const write = ({ target: { name, value } }) => {
|
||||
const write = ({ target: { value } }) => {
|
||||
setQuery(value);
|
||||
debounceUpdate('metricsSearch', value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ interface Props {
|
|||
subtext?: any;
|
||||
icon?: string;
|
||||
iconSize?: number;
|
||||
size?: number;
|
||||
size?: string;
|
||||
show?: boolean;
|
||||
children?: any;
|
||||
image?: any;
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ function SideMenuitem({
|
|||
iconBg = false,
|
||||
iconColor = "gray-dark",
|
||||
iconSize = 18,
|
||||
className,
|
||||
className = '',
|
||||
iconName = null,
|
||||
title,
|
||||
active = false,
|
||||
disabled = false,
|
||||
onClick,
|
||||
deleteHandler,
|
||||
deleteHandler = null,
|
||||
leading = null,
|
||||
...props
|
||||
}) {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,11 @@ export interface IDashboardSotre {
|
|||
|
||||
showAlertModal: boolean;
|
||||
|
||||
page: number
|
||||
pageSize: number
|
||||
dashboardsSearch: string
|
||||
sort: any
|
||||
|
||||
selectWidgetsByCategory: (category: string) => void;
|
||||
toggleAllSelectedWidgets: (isSelected: boolean) => void;
|
||||
removeSelectedWidgetByCategory(category: string): void;
|
||||
|
|
@ -115,6 +120,12 @@ export default class DashboardStore implements IDashboardSotre {
|
|||
sessionsLoading: boolean = false;
|
||||
showAlertModal: boolean = false;
|
||||
|
||||
// Pagination
|
||||
page: number = 1
|
||||
pageSize: number = 15
|
||||
dashboardsSearch: string = ''
|
||||
sort: any = {}
|
||||
|
||||
constructor() {
|
||||
makeAutoObservable(this);
|
||||
|
||||
|
|
@ -183,6 +194,7 @@ export default class DashboardStore implements IDashboardSotre {
|
|||
}
|
||||
|
||||
updateKey(key: any, value: any) {
|
||||
console.log(key, value)
|
||||
this[key] = value;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { makeAutoObservable, observable, action, runInAction } from "mobx"
|
|||
import Widget, { IWidget } from "./widget"
|
||||
import { dashboardService } from "App/services"
|
||||
import { toast } from 'react-toastify';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
export interface IDashboard {
|
||||
dashboardId: any
|
||||
|
|
@ -14,6 +15,7 @@ export interface IDashboard {
|
|||
isPinned: boolean
|
||||
currentWidget: IWidget
|
||||
config: any
|
||||
createdAt: Date
|
||||
|
||||
update(data: any): void
|
||||
toJson(): any
|
||||
|
|
@ -44,6 +46,7 @@ export default class Dashboard implements IDashboard {
|
|||
isPinned: boolean = false
|
||||
currentWidget: IWidget = new Widget()
|
||||
config: any = {}
|
||||
createdAt: Date = new Date()
|
||||
|
||||
constructor() {
|
||||
makeAutoObservable(this)
|
||||
|
|
@ -63,8 +66,7 @@ export default class Dashboard implements IDashboard {
|
|||
dashboardId: this.dashboardId,
|
||||
name: this.name,
|
||||
isPublic: this.isPublic,
|
||||
// widgets: this.widgets.map(w => w.toJson())
|
||||
// widgets: this.widgets
|
||||
createdAt: this.createdAt,
|
||||
metrics: this.metrics,
|
||||
description: this.description,
|
||||
}
|
||||
|
|
@ -77,7 +79,8 @@ export default class Dashboard implements IDashboard {
|
|||
this.description = json.description
|
||||
this.isPublic = json.isPublic
|
||||
this.isPinned = json.isPinned
|
||||
this.widgets = json.widgets ? json.widgets.map(w => new Widget().fromJson(w)).sort((a, b) => a.position - b.position) : []
|
||||
this.createdAt = DateTime.fromMillis(new Date(json.createdAt).getTime())
|
||||
this.widgets = json.widgets ? json.widgets.map((w: Widget) => new Widget().fromJson(w)).sort((a: Widget, b: Widget) => a.position - b.position) : []
|
||||
})
|
||||
return this
|
||||
}
|
||||
|
|
|
|||
|
|
@ -239,10 +239,10 @@ export const isGreaterOrEqualVersion = (version, compareTo) => {
|
|||
return major > majorC || (major === majorC && minor > minorC) || (major === majorC && minor === minorC && patch >= patchC);
|
||||
};
|
||||
|
||||
export const sliceListPerPage = (list, page, perPage = 10) => {
|
||||
export const sliceListPerPage = <T extends Array<any>>(list: T, page: number, perPage = 10): T => {
|
||||
const start = page * perPage;
|
||||
const end = start + perPage;
|
||||
return list.slice(start, end);
|
||||
return list.slice(start, end) as T;
|
||||
};
|
||||
|
||||
export const positionOfTheNumber = (min, max, value, length) => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue