From caa58d1f98be5f8228473f072b19d88216fd6bb6 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Wed, 6 Apr 2022 14:46:28 +0200 Subject: [PATCH] feat(ui) - dashboard - wip --- frontend/app/Router.js | 2 + .../BugFinder/AutoComplete/AutoComplete.js | 2 +- .../DashboardEditModal/DashboardEditModal.tsx | 86 +++++++++++++++++++ .../components/DashboardEditModal/index.ts | 1 + .../DashboardMetricSelection.tsx | 4 +- .../DashboardModal/DashboardModal.tsx | 2 +- .../DashboardRouter/DashboardRouter.tsx | 7 +- .../DashboardView/DashboardView.tsx | 37 ++++++-- .../DashboardWidgetGrid.tsx | 4 +- .../MetricListItem/MetricListItem.tsx | 14 +-- .../components/MetricsList/MetricsList.tsx | 12 +-- .../components/MetricsView/MetricsView.tsx | 10 ++- .../components/WidgetChart/WidgetChart.tsx | 6 +- .../components/WidgetForm/WidgetForm.tsx | 13 ++- .../components/WidgetName/WidgetName.tsx | 57 ++++++++++++ .../Dashboard/components/WidgetName/index.ts | 1 + .../WidgetPreview/WidgetPreview.tsx | 4 +- .../components/WidgetView/WidgetView.tsx | 7 +- .../WidgetWrapper/WidgetWrapper.tsx | 57 +++++++----- .../app/components/ui/ItemMenu/ItemMenu.js | 45 +++------- frontend/app/mstore/dashboardStore.ts | 16 +++- frontend/app/mstore/metricStore.ts | 3 + frontend/app/mstore/types/dashboard.ts | 7 +- frontend/app/mstore/types/widget.ts | 5 ++ frontend/app/routes.js | 2 +- 25 files changed, 310 insertions(+), 94 deletions(-) create mode 100644 frontend/app/components/Dashboard/components/DashboardEditModal/DashboardEditModal.tsx create mode 100644 frontend/app/components/Dashboard/components/DashboardEditModal/index.ts create mode 100644 frontend/app/components/Dashboard/components/WidgetName/WidgetName.tsx create mode 100644 frontend/app/components/Dashboard/components/WidgetName/index.ts diff --git a/frontend/app/Router.js b/frontend/app/Router.js index 22b5b3947..f42f3c456 100644 --- a/frontend/app/Router.js +++ b/frontend/app/Router.js @@ -59,6 +59,7 @@ const METRICS_DETAILS = routes.metricDetails(); const DASHBOARD_PATH = routes.dashboard(); const DASHBOARD_SELECT_PATH = routes.dashboardSelected(); const DASHBOARD_METRIC_CREATE_PATH = routes.dashboardMetricCreate(); +const DASHBOARD_METRIC_DETAILS_PATH = routes.dashboardMetricDetails(); // const WIDGET_PATAH = routes.dashboardMetric(); const SESSIONS_PATH = routes.sessions(); @@ -206,6 +207,7 @@ class Router extends React.Component { + diff --git a/frontend/app/components/BugFinder/AutoComplete/AutoComplete.js b/frontend/app/components/BugFinder/AutoComplete/AutoComplete.js index 6b90786b7..b528e7bb9 100644 --- a/frontend/app/components/BugFinder/AutoComplete/AutoComplete.js +++ b/frontend/app/components/BugFinder/AutoComplete/AutoComplete.js @@ -114,7 +114,7 @@ class AutoComplete extends React.PureComponent { render() { const { ddOpen, query, loading, values } = this.state; - const { + const { optionMapping = defaultOptionMapping, valueToText = defaultValueToText, placeholder = 'Type to search...', diff --git a/frontend/app/components/Dashboard/components/DashboardEditModal/DashboardEditModal.tsx b/frontend/app/components/Dashboard/components/DashboardEditModal/DashboardEditModal.tsx new file mode 100644 index 000000000..e6eae9e4e --- /dev/null +++ b/frontend/app/components/Dashboard/components/DashboardEditModal/DashboardEditModal.tsx @@ -0,0 +1,86 @@ +import { useObserver } from 'mobx-react-lite'; +import React from 'react'; +import { Button, Modal, Form, Icon, Checkbox } from 'UI'; +import { useStore } from 'App/mstore' + +interface Props { + show: boolean; + // dashboard: any; + closeHandler?: () => void; +} +function DashboardEditModal(props: Props) { + const { show, closeHandler } = props; + const { dashboardStore } = useStore(); + const dashboard = useObserver(() => dashboardStore.dashboardInstance); + + const onSave = () => { + dashboardStore.save(dashboard).then(closeHandler); + } + + const write = ({ target: { value, name } }) => dashboard.update({ [ name ]: value }) + const writeOption = (e, { checked, name }) => { + dashboard.update({ [name]: checked }); + } + + return useObserver(() => ( + + +
{ 'Edit Dashboard' }
+ +
+ + +
+ + + + + + +
+ +
dashboard.update({ 'isPublic': !dashboard.isPublic }) }> + + Team can see and edit the dashboard. +
+
+
+
+
+ +
+ + +
+
+
+ )); +} + +export default DashboardEditModal; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/components/DashboardEditModal/index.ts b/frontend/app/components/Dashboard/components/DashboardEditModal/index.ts new file mode 100644 index 000000000..c7f4d7b17 --- /dev/null +++ b/frontend/app/components/Dashboard/components/DashboardEditModal/index.ts @@ -0,0 +1 @@ +export { default } from './DashboardEditModal' \ No newline at end of file diff --git a/frontend/app/components/Dashboard/components/DashboardMetricSelection/DashboardMetricSelection.tsx b/frontend/app/components/Dashboard/components/DashboardMetricSelection/DashboardMetricSelection.tsx index 78f50a45e..475aeaa6d 100644 --- a/frontend/app/components/Dashboard/components/DashboardMetricSelection/DashboardMetricSelection.tsx +++ b/frontend/app/components/Dashboard/components/DashboardMetricSelection/DashboardMetricSelection.tsx @@ -91,10 +91,10 @@ function DashboardMetricSelection(props) { {activeCategory && activeCategory.widgets.map((widget: any) => (
dashboardStore.toggleWidgetSelection(widget)} > - +
))} diff --git a/frontend/app/components/Dashboard/components/DashboardModal/DashboardModal.tsx b/frontend/app/components/Dashboard/components/DashboardModal/DashboardModal.tsx index 07be9fb84..a5ba99dfb 100644 --- a/frontend/app/components/Dashboard/components/DashboardModal/DashboardModal.tsx +++ b/frontend/app/components/Dashboard/components/DashboardModal/DashboardModal.tsx @@ -34,7 +34,7 @@ function DashboardModal(props) { return useObserver(() => (
diff --git a/frontend/app/components/Dashboard/components/DashboardRouter/DashboardRouter.tsx b/frontend/app/components/Dashboard/components/DashboardRouter/DashboardRouter.tsx index 171a36164..9621f1c71 100644 --- a/frontend/app/components/Dashboard/components/DashboardRouter/DashboardRouter.tsx +++ b/frontend/app/components/Dashboard/components/DashboardRouter/DashboardRouter.tsx @@ -7,6 +7,7 @@ import { metricDetails, dashboardSelected, dashboardMetricCreate, + dashboardMetricDetails, withSiteId, dashboard, } from 'App/routes'; @@ -24,13 +25,17 @@ function DashboardRouter(props: Props) {
- + + + + + diff --git a/frontend/app/components/Dashboard/components/DashboardView/DashboardView.tsx b/frontend/app/components/Dashboard/components/DashboardView/DashboardView.tsx index 2b9f9db98..f3dfdabcc 100644 --- a/frontend/app/components/Dashboard/components/DashboardView/DashboardView.tsx +++ b/frontend/app/components/Dashboard/components/DashboardView/DashboardView.tsx @@ -1,7 +1,7 @@ import React, { useEffect } from 'react'; import { observer, useObserver } from 'mobx-react-lite'; import { useStore } from 'App/mstore'; -import { Button, PageTitle, Link, Loader, NoContent } from 'UI'; +import { Button, PageTitle, Link, Loader, NoContent, ItemMenu } from 'UI'; import { withSiteId, dashboardMetricCreate, dashboardSelected, dashboard } from 'App/routes'; import withModal from 'App/components/Modal/withModal'; import DashboardWidgetGrid from '../DashboardWidgetGrid'; @@ -9,6 +9,7 @@ import { confirm } from 'UI/Confirmation'; import { withRouter } from 'react-router-dom'; import { useModal } from 'App/components/Modal'; import DashboardModal from '../DashboardModal'; +import DashboardEditModal from '../DashboardEditModal'; interface Props { siteId: number; @@ -22,16 +23,22 @@ function DashboardView(props: Props) { const { hideModal, showModal } = useModal(); const loading = useObserver(() => dashboardStore.fetchingDashboard); const dashboard: any = dashboardStore.selectedDashboard + const [showEditModal, setShowEditModal] = React.useState(false); useEffect(() => { dashboardStore.fetch(dashboardId) }, []); - const onEditHandler = () => { + const onAddWidgets = () => { dashboardStore.initDashboard(dashboard) showModal(, {}) } + const onEdit = () => { + dashboardStore.initDashboard(dashboard) + setShowEditModal(true) + } + const onDelete = async () => { if (await confirm({ header: 'Confirm', @@ -54,17 +61,37 @@ function DashboardView(props: Props) { size="small" >
+ setShowEditModal(false)} + />
{/* */} - +
- +
- +
diff --git a/frontend/app/components/Dashboard/components/DashboardWidgetGrid/DashboardWidgetGrid.tsx b/frontend/app/components/Dashboard/components/DashboardWidgetGrid/DashboardWidgetGrid.tsx index 9bb7a1ce5..77356a279 100644 --- a/frontend/app/components/Dashboard/components/DashboardWidgetGrid/DashboardWidgetGrid.tsx +++ b/frontend/app/components/Dashboard/components/DashboardWidgetGrid/DashboardWidgetGrid.tsx @@ -5,11 +5,12 @@ import { NoContent, Button, Loader } from 'UI'; import { useObserver } from 'mobx-react-lite'; interface Props { + siteId: string, dashboardId: string; onEditHandler: () => void; } function DashboardWidgetGrid(props) { - const { dashboardId } = props; + const { dashboardId, siteId } = props; const { dashboardStore } = useStore(); const loading = useObserver(() => dashboardStore.isLoading); const dashbaord: any = dashboardStore.selectedDashboard; @@ -36,6 +37,7 @@ function DashboardWidgetGrid(props) { key={item.widgetId} moveListItem={(dragIndex, hoverIndex) => dashbaord.swapWidgetPosition(dragIndex, hoverIndex)} dashboardId={dashboardId} + siteId={siteId} /> ))}
diff --git a/frontend/app/components/Dashboard/components/MetricListItem/MetricListItem.tsx b/frontend/app/components/Dashboard/components/MetricListItem/MetricListItem.tsx index b8e623370..f9f5e6d96 100644 --- a/frontend/app/components/Dashboard/components/MetricListItem/MetricListItem.tsx +++ b/frontend/app/components/Dashboard/components/MetricListItem/MetricListItem.tsx @@ -10,9 +10,9 @@ function DashboardLink({ dashboards}) { return ( dashboards.map(dashboard => ( -
+
ยท
- {dashboard.name} + {dashboard.name}
)) @@ -22,24 +22,24 @@ function DashboardLink({ dashboards}) { function MetricListItem(props: Props) { const { metric } = props; return ( -
-
+
+
{metric.name}
-
+
-
{metric.owner}
+
{metric.owner}
{metric.isPublic ? 'Team' : 'Private'}
-
{metric.lastModified && checkForRecent(metric.lastModified, 'LLL dd, yyyy, hh:mm a')}
+
{metric.lastModified && checkForRecent(metric.lastModified, 'LLL dd, yyyy, hh:mm a')}
); } diff --git a/frontend/app/components/Dashboard/components/MetricsList/MetricsList.tsx b/frontend/app/components/Dashboard/components/MetricsList/MetricsList.tsx index 729844590..dd1af190b 100644 --- a/frontend/app/components/Dashboard/components/MetricsList/MetricsList.tsx +++ b/frontend/app/components/Dashboard/components/MetricsList/MetricsList.tsx @@ -19,13 +19,13 @@ function MetricsList(props: Props) { return useObserver(() => (
-
-
Title
+
+
Title
Type
-
Dashboards
-
Owner
-
Visibility & Edit Access
-
Last Modified
+
Dashboards
+
Owner
+
Visibility
+
Last Modified
{list.map((metric: any) => ( diff --git a/frontend/app/components/Dashboard/components/MetricsView/MetricsView.tsx b/frontend/app/components/Dashboard/components/MetricsView/MetricsView.tsx index 18c1204bb..c6f33fb39 100644 --- a/frontend/app/components/Dashboard/components/MetricsView/MetricsView.tsx +++ b/frontend/app/components/Dashboard/components/MetricsView/MetricsView.tsx @@ -1,12 +1,16 @@ import React from 'react'; import { Button, PageTitle, Icon, Link } from 'UI'; -import { withSiteId, dashboardMetricCreate } from 'App/routes'; +import { withSiteId, metricCreate } from 'App/routes'; import MetricsList from '../MetricsList'; import MetricsSearch from '../MetricsSearch'; import { useStore } from 'App/mstore'; import { useObserver } from 'mobx-react-lite'; -function MetricsView(props) { +interface Props{ + siteId: number; +} +function MetricsView(props: Props) { + const { siteId } = props; const { metricStore } = useStore(); React.useEffect(() => { @@ -16,7 +20,7 @@ function MetricsView(props) {
- {/* */} +
diff --git a/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx b/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx index 2dd27bc9e..b20c3a1b4 100644 --- a/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx +++ b/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx @@ -11,12 +11,12 @@ import { observer, useObserver } from 'mobx-react-lite'; import { Loader } from 'UI'; import { useStore } from 'App/mstore'; interface Props { - // metric: any; + metric: any; } function WidgetChart(props: Props) { - // const metric = useObserver(() => props.metric); + const metric = useObserver(() => props.metric); const { metricStore } = useStore(); - const metric: any = useObserver(() => metricStore.instance); + // const metric: any = useObserver(() => metricStore.instance); const series = useObserver(() => metric.series); const colors = Styles.customMetricColors; const [loading, setLoading] = useState(false) diff --git a/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx b/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx index 05a2ec910..abe92223a 100644 --- a/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx +++ b/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx @@ -8,6 +8,7 @@ import { HelpText, Button, Icon } from 'UI' import FilterSeries from '../FilterSeries'; import { withRouter } from 'react-router-dom'; import { confirm } from 'UI/Confirmation'; +import { withSiteId, dashboardMetricDetails, metricDetails } from 'App/routes' interface Props { history: any; @@ -50,7 +51,17 @@ function WidgetForm(props: Props) { }; const onSave = () => { - metricStore.save(metric, dashboardId); + const wasCreating = !metric.exists() + metricStore.save(metric, dashboardId).then(() => { + if (wasCreating) { + if (parseInt(dashboardId) > 0) { + history.push(withSiteId(dashboardMetricDetails(parseInt(dashboardId)), siteId)); + } else { + history.push(withSiteId(metricDetails(metric.metricId), siteId)); + } + + } + }); } const onDelete = async () => { diff --git a/frontend/app/components/Dashboard/components/WidgetName/WidgetName.tsx b/frontend/app/components/Dashboard/components/WidgetName/WidgetName.tsx new file mode 100644 index 000000000..0cbfafd49 --- /dev/null +++ b/frontend/app/components/Dashboard/components/WidgetName/WidgetName.tsx @@ -0,0 +1,57 @@ +import React, { useState, useRef, useEffect } from 'react'; +import { Icon } from 'UI'; + +interface Props { + name: string; + onUpdate: (name) => void; + seriesIndex?: number; +} +function WidgetName(props: Props) { + const { seriesIndex = 1 } = props; + const [editing, setEditing] = useState(false) + const [name, setName] = useState(props.name) + const ref = useRef(null) + + const write = ({ target: { value, name } }) => { + setName(value) + } + + const onBlur = () => { + setEditing(false) + props.onUpdate(name.trim() === '' ? 'New Widget' : name) + } + + useEffect(() => { + if (editing) { + ref.current.focus() + } + }, [editing]) + + useEffect(() => { + setName(props.name) + }, [props.name]) + + // const { name } = props; + return ( +
+ { editing ? ( + setEditing(true)} + /> + ) : ( +
{ name }
+ )} + +
setEditing(true)}>
+
+ ); +} + +export default WidgetName; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/components/WidgetName/index.ts b/frontend/app/components/Dashboard/components/WidgetName/index.ts new file mode 100644 index 000000000..322cc4441 --- /dev/null +++ b/frontend/app/components/Dashboard/components/WidgetName/index.ts @@ -0,0 +1 @@ +export { default } from './WidgetName'; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/components/WidgetPreview/WidgetPreview.tsx b/frontend/app/components/Dashboard/components/WidgetPreview/WidgetPreview.tsx index a227fce93..2c40dd0f0 100644 --- a/frontend/app/components/Dashboard/components/WidgetPreview/WidgetPreview.tsx +++ b/frontend/app/components/Dashboard/components/WidgetPreview/WidgetPreview.tsx @@ -25,6 +25,8 @@ function WidgetPreview(props: Props) { metric.update({ ...changedDates, rangeName: changedDates.rangeValue }); } + console.log('view', metric.viewType) + return useObserver(() => (
@@ -77,7 +79,7 @@ function WidgetPreview(props: Props) { />
-
+
diff --git a/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx b/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx index a63c58beb..f86e22302 100644 --- a/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx +++ b/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx @@ -7,6 +7,7 @@ import WidgetSessions from '../WidgetSessions'; import { Icon, BackLink, Loader } from 'UI'; import { useObserver } from 'mobx-react-lite'; import { withSiteId } from 'App/routes'; +import WidgetName from '../WidgetName'; interface Props { history: any; match: any @@ -32,7 +33,7 @@ function WidgetView(props: Props) { const onBackHandler = () => { if (dashboardId) { props.history.push(withSiteId(`/dashboard/${dashboardId}`, siteId)); - } { + } else { props.history.push(withSiteId(`/metrics`, siteId)); } } @@ -43,7 +44,9 @@ function WidgetView(props: Props) {
-

{widget.name}

+

+ metricStore.merge({ name })} /> +

setExpanded(!expanded)} diff --git a/frontend/app/components/Dashboard/components/WidgetWrapper/WidgetWrapper.tsx b/frontend/app/components/Dashboard/components/WidgetWrapper/WidgetWrapper.tsx index f426dac6e..c667ae171 100644 --- a/frontend/app/components/Dashboard/components/WidgetWrapper/WidgetWrapper.tsx +++ b/frontend/app/components/Dashboard/components/WidgetWrapper/WidgetWrapper.tsx @@ -6,6 +6,9 @@ import WidgetChart from '../WidgetChart'; import { useObserver } from 'mobx-react-lite'; import { confirm } from 'UI/Confirmation'; import { useStore } from 'App/mstore'; +import LazyLoad from 'react-lazyload'; +import { withRouter } from 'react-router-dom'; +import { withSiteId, dashboardMetricDetails } from 'App/routes'; interface Props { className?: string; @@ -13,11 +16,15 @@ interface Props { index?: number; moveListItem?: any; isPreview?: boolean; + isTemplate?: boolean dashboardId?: string; + siteId?: string, + active?: boolean; + history?: any } function WidgetWrapper(props: Props) { const { dashboardStore } = useStore(); - const { widget, index = 0, moveListItem = null, isPreview = false, dashboardId } = props; + const { active = false, widget, index = 0, moveListItem = null, isPreview = false, isTemplate = false, dashboardId, siteId } = props; const [{ opacity, isDragging }, dragRef] = useDrag({ type: 'item', @@ -47,54 +54,62 @@ function WidgetWrapper(props: Props) { confirmButton: 'Yes, Delete', confirmation: `Are you sure you want to permanently delete this Dashboard?` })) { - dashboardStore.deleteDashboardWidget(dashboardId!, widget.widgetId).then(() => { - - }) + dashboardStore.deleteDashboardWidget(dashboardId!, widget.widgetId); } } + const editHandler = () => { + console.log('clicked', widget.metricId); + } + + const onChartClick = () => { + if (isPreview || isTemplate) return; + props.history.push(withSiteId(dashboardMetricDetails(dashboardId, widget.metricId),siteId)); + } + const ref: any = useRef(null) const dragDropRef: any = dragRef(dropRef(ref)) return useObserver(() => (
- {/* */} -
- {widget.name} +
+ +

{widget.name}

+ {!isPreview && !isTemplate && (
{ - console.log('edit'); - } + text: 'Edit', onClick: editHandler, }, { - text: 'Hide from view' + dashboardId, + text: 'Hide from view', onClick: onDelete }, ]} />
-
+ )} +
-
- + +
+
- {/* */} +
)); } -export default WidgetWrapper; \ No newline at end of file +export default withRouter(WidgetWrapper); \ No newline at end of file diff --git a/frontend/app/components/ui/ItemMenu/ItemMenu.js b/frontend/app/components/ui/ItemMenu/ItemMenu.js index 1d908c33e..1938f5a3c 100644 --- a/frontend/app/components/ui/ItemMenu/ItemMenu.js +++ b/frontend/app/components/ui/ItemMenu/ItemMenu.js @@ -1,35 +1,18 @@ import { Icon } from 'UI'; import styles from './itemMenu.css'; +import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv'; export default class ItemMenu extends React.PureComponent { state = { displayed: false, }; - componentDidMount() { - document.addEventListener('click', this.handleClickOutside); - } - - componentWillUnmount() { - document.removeEventListener('click', this.handleClickOutside); - } - onClick = callback => (e) => { e.stopPropagation(); callback(e); } - handleClickOutside = (e) => { - if (!this.state.displayed) return; - if (e.target !== this.menuBtnRef) { - this.closeMenu(); - } - } - toggleMenu = (e) => { - // e.preventDefault(); - // e.stopPropagation(); - console.log('toggleMenu', e); this.setState({ displayed: !this.state.displayed }); } @@ -41,22 +24,18 @@ export default class ItemMenu extends React.PureComponent { return (
- {/*
{ this.menuBtnRef = ref; } } - className={ styles.menuBtn } - onClick={ this.toggleMenu } - role="button" - tabIndex="-1" - /> */} -
{ this.menuBtnRef = ref; } } - className="w-10 h-10 cursor-pointer bg-white rounded-full flex items-center justify-center hover:bg-gray-lightest" - onClick={ this.toggleMenu } - role="button" - // tabIndex="-1" + - -
+
{ this.menuBtnRef = ref; } } + className="w-10 h-10 cursor-pointer bg-white rounded-full flex items-center justify-center hover:bg-gray-lightest" + onClick={ this.toggleMenu } + role="button" + > + +
+
toJson(): void fromJson(json: any): void - initDashboard(dashboard: IDashboard): void + // initDashboard(dashboard: IDashboard): void addDashboard(dashboard: IDashboard): void removeDashboard(dashboard: IDashboard): void getDashboard(dashboardId: string): void @@ -78,6 +79,7 @@ export default class DashboardStore implements IDashboardSotre { constructor() { makeAutoObservable(this, { widgetCategories: observable.ref, + // dashboardInstance: observable.ref, resetCurrentWidget: action, addDashboard: action, @@ -159,7 +161,7 @@ export default class DashboardStore implements IDashboardSotre { } initDashboard(dashboard: Dashboard) { - this.dashboardInstance = dashboard || new Dashboard() + this.dashboardInstance = dashboard ? new Dashboard().fromJson(dashboard) : new Dashboard() this.selectedWidgets = [] } @@ -208,8 +210,10 @@ export default class DashboardStore implements IDashboardSotre { return dashboardService.saveDashboard(dashboard).then(_dashboard => { runInAction(() => { if (isCreating) { + toast.success('Dashboard created successfully') this.addDashboard(_dashboard) } else { + toast.success('Dashboard updated successfully') this.updateDashboard(_dashboard) } }) @@ -247,10 +251,15 @@ export default class DashboardStore implements IDashboardSotre { deleteDashboard(dashboard: Dashboard): Promise { this.isDeleting = true return dashboardService.deleteDashboard(dashboard.dashboardId).then(() => { + toast.success('Dashboard deleted successfully') runInAction(() => { this.removeDashboard(dashboard) }) - }).finally(() => { + }) + .catch(() => { + toast.error('Dashboard could not be deleted') + }) + .finally(() => { runInAction(() => { this.isDeleting = false }) @@ -364,6 +373,7 @@ export default class DashboardStore implements IDashboardSotre { deleteDashboardWidget(dashboardId: string, widgetId: string) { this.isDeleting = true return dashboardService.deleteWidget(dashboardId, widgetId).then(() => { + toast.success('Widget deleted successfully') runInAction(() => { this.selectedDashboard?.removeWidget(widgetId) }) diff --git a/frontend/app/mstore/metricStore.ts b/frontend/app/mstore/metricStore.ts index 1e3746b9e..d322426a7 100644 --- a/frontend/app/mstore/metricStore.ts +++ b/frontend/app/mstore/metricStore.ts @@ -1,6 +1,7 @@ import { makeAutoObservable, runInAction, observable, action, reaction, computed } from "mobx" import Widget, { IWidget } from "./types/widget"; import { metricService } from "App/services"; +import { toast } from 'react-toastify'; export interface IMetricStore { paginatedList: any; @@ -136,8 +137,10 @@ export default class MetricStore implements IMetricStore { return metricService.saveMetric(metric, dashboardId) .then(() => { if (wasCreating) { + toast.success('Metric created successfully') this.addToList(metric) } else { + toast.success('Metric updated successfully') this.updateInList(metric) } }).finally(() => { diff --git a/frontend/app/mstore/types/dashboard.ts b/frontend/app/mstore/types/dashboard.ts index 46973f9ff..41410b91c 100644 --- a/frontend/app/mstore/types/dashboard.ts +++ b/frontend/app/mstore/types/dashboard.ts @@ -10,6 +10,7 @@ export interface IDashboard { isValid: boolean isPinned: boolean currentWidget: IWidget + config: any update(data: any): void toJson(): any @@ -31,12 +32,13 @@ export default class Dashboard implements IDashboard { public static get ID_KEY():string { return "dashboardId" } dashboardId: any = undefined name: string = "New Dashboard" - isPublic: boolean = false + isPublic: boolean = true widgets: IWidget[] = [] metrics: any[] = [] isValid: boolean = false isPinned: boolean = false currentWidget: IWidget = new Widget() + config: any = {} constructor() { makeAutoObservable(this, { @@ -75,7 +77,7 @@ export default class Dashboard implements IDashboard { return { dashboardId: this.dashboardId, name: this.name, - isPrivate: this.isPublic, + isPublic: this.isPublic, // widgets: this.widgets.map(w => w.toJson()) // widgets: this.widgets metrics: this.metrics @@ -88,6 +90,7 @@ export default class Dashboard implements IDashboard { this.name = json.name this.isPublic = json.isPublic this.isPinned = json.isPinned + this.config = json.config this.widgets = json.widgets ? json.widgets.map(w => new Widget().fromJson(w)) : [] }) return this diff --git a/frontend/app/mstore/types/widget.ts b/frontend/app/mstore/types/widget.ts index 4e6881b58..de7191eb0 100644 --- a/frontend/app/mstore/types/widget.ts +++ b/frontend/app/mstore/types/widget.ts @@ -17,6 +17,7 @@ export interface IWidget { lastModified: Date dashboards: any[] dashboardIds: any[] + config: any position: number data: any @@ -50,6 +51,7 @@ export default class Widget implements IWidget { lastModified: Date = new Date() dashboards: any[] = [] dashboardIds: any[] = [] + config: any = {} position: number = 0 data: any = {} @@ -111,6 +113,8 @@ export default class Widget implements IWidget { this.dashboards = json.dashboards this.owner = json.ownerEmail this.lastModified = DateTime.fromISO(json.editedAt || json.createdAt) + this.config = json.config + this.position = json.config.position }) return this } @@ -122,6 +126,7 @@ export default class Widget implements IWidget { metricOf: this.metricOf, metricValue: this.metricValue, metricType: this.metricType, + viewType: this.viewType, name: this.name, series: this.series.map((series: any) => series.toJson()), } diff --git a/frontend/app/routes.js b/frontend/app/routes.js index 08303f78b..7a6c5379e 100644 --- a/frontend/app/routes.js +++ b/frontend/app/routes.js @@ -104,7 +104,7 @@ export const dashboard = () => '/dashboard'; export const dashboardMetrics = () => '/dashboard/metrics'; export const dashboardSelected = (id = ':dashboardId', hash) => hashed(`/dashboard/${ id }`, hash); -export const dashboardMetricDetails = (id = ':dashboardId', metricId = ':metricId', hash) => hashed(`/dashboard/${ id }/metric/${metricId}`, hash); +export const dashboardMetricDetails = (dashboardId = ':dashboardId', metricId = ':metricId', hash) => hashed(`/dashboard/${ dashboardId }/metric/${metricId}`, hash); export const dashboardMetricCreate = (dashboardId = ':dashboardId', hash) => hashed(`/dashboard/${ dashboardId }/metric/create`, hash); export const metrics = () => `/metrics`; export const metricCreate = () => `/metrics/create`;