From 9e25f8ef691fdeee74f2ea36a6415f2b719fece3 Mon Sep 17 00:00:00 2001 From: sylenien Date: Wed, 21 Sep 2022 15:10:13 +0200 Subject: [PATCH] change(ui): small ui fixes, new border for assist etc --- .../Dashboard/components/Alerts/NewAlert.tsx | 10 ++-- .../DashboardList/DashboardList.tsx | 2 +- .../DashboardRouter/DashboardRouter.tsx | 8 ++- .../components/MetricsList/MetricsList.tsx | 16 ++--- frontend/app/components/Header/Header.js | 24 ++++---- .../app/components/Session_/PlayerBlock.js | 3 +- frontend/app/mstore/dashboardStore.ts | 23 +++++--- frontend/app/mstore/metricStore.ts | 59 +++++++------------ frontend/app/mstore/types/dashboard.ts | 2 +- frontend/app/mstore/types/widget.ts | 2 +- .../StatedScreen/Screen/BaseScreen.ts | 20 +++++-- .../StatedScreen/Screen/screen.module.css | 4 +- .../managers/AssistManager.ts | 2 + 13 files changed, 91 insertions(+), 84 deletions(-) diff --git a/frontend/app/components/Dashboard/components/Alerts/NewAlert.tsx b/frontend/app/components/Dashboard/components/Alerts/NewAlert.tsx index c44d1c31b..aee10e143 100644 --- a/frontend/app/components/Dashboard/components/Alerts/NewAlert.tsx +++ b/frontend/app/components/Dashboard/components/Alerts/NewAlert.tsx @@ -146,7 +146,7 @@ const NewAlert = (props: IProps) => { // @ts-ignore .toJS(); - + const writeQueryOption = ( e: React.ChangeEvent, @@ -196,7 +196,7 @@ const NewAlert = (props: IProps) => { > - +
{ title="Notify Through" description="You'll be noticed in app notifications. Additionally opt in to receive alerts on:" content={ - {
-
- +
diff --git a/frontend/app/components/Dashboard/components/DashboardList/DashboardList.tsx b/frontend/app/components/Dashboard/components/DashboardList/DashboardList.tsx index bdb9d6b7a..7bb716733 100644 --- a/frontend/app/components/Dashboard/components/DashboardList/DashboardList.tsx +++ b/frontend/app/components/Dashboard/components/DashboardList/DashboardList.tsx @@ -9,7 +9,7 @@ import DashboardListItem from './DashboardListItem'; function DashboardList() { const { dashboardStore } = useStore(); const [shownDashboards, setDashboards] = React.useState([]); - const dashboards = dashboardStore.dashboards; + const dashboards = dashboardStore.sortedDashboards; const dashboardsSearch = dashboardStore.dashboardsSearch; React.useEffect(() => { diff --git a/frontend/app/components/Dashboard/components/DashboardRouter/DashboardRouter.tsx b/frontend/app/components/Dashboard/components/DashboardRouter/DashboardRouter.tsx index a7c2d62fd..419ac64b2 100644 --- a/frontend/app/components/Dashboard/components/DashboardRouter/DashboardRouter.tsx +++ b/frontend/app/components/Dashboard/components/DashboardRouter/DashboardRouter.tsx @@ -74,11 +74,13 @@ function DashboardRouter(props: Props) { - - + + {/* @ts-ignore */} + - + + {/* @ts-ignore */} diff --git a/frontend/app/components/Dashboard/components/MetricsList/MetricsList.tsx b/frontend/app/components/Dashboard/components/MetricsList/MetricsList.tsx index e6eb66b97..2869f5240 100644 --- a/frontend/app/components/Dashboard/components/MetricsList/MetricsList.tsx +++ b/frontend/app/components/Dashboard/components/MetricsList/MetricsList.tsx @@ -1,18 +1,18 @@ -import { useObserver } from 'mobx-react-lite'; +import { observer } from 'mobx-react-lite'; import React, { useEffect } from 'react'; import { NoContent, Pagination, Icon } from 'UI'; import { useStore } from 'App/mstore'; import { filterList } from 'App/utils'; import MetricListItem from '../MetricListItem'; import { sliceListPerPage } from 'App/utils'; -import { IWidget } from 'App/mstore/types/widget'; +import Widget from 'App/mstore/types/widget'; function MetricsList({ siteId }: { siteId: string }) { const { metricStore } = useStore(); - const metrics = useObserver(() => metricStore.metrics); - const metricsSearch = useObserver(() => metricStore.metricsSearch); + const metrics = metricStore.sortedWidgets; + const metricsSearch = metricStore.metricsSearch; - const filterByDashboard = (item: IWidget, searchRE: RegExp) => { + const filterByDashboard = (item: Widget, searchRE: RegExp) => { const dashboardsStr = item.dashboards.map((d: any) => d.name).join(' '); return searchRE.test(dashboardsStr); }; @@ -26,7 +26,7 @@ function MetricsList({ siteId }: { siteId: string }) { metricStore.updateKey('sessionsPage', 1); }, []); - return useObserver(() => ( + return (
- )); + ); } -export default MetricsList; +export default observer(MetricsList); diff --git a/frontend/app/components/Header/Header.js b/frontend/app/components/Header/Header.js index 60536ba24..6159197b1 100644 --- a/frontend/app/components/Header/Header.js +++ b/frontend/app/components/Header/Header.js @@ -2,12 +2,13 @@ import React, { useEffect, useState } from 'react'; import { connect } from 'react-redux'; import { NavLink, withRouter } from 'react-router-dom'; import cn from 'classnames'; -import { +import { sessions, metrics, assist, client, dashboard, + alerts, withSiteId, CLIENT_DEFAULT_TAB, } from 'App/routes'; @@ -28,18 +29,19 @@ import { useStore } from 'App/mstore'; import { useObserver } from 'mobx-react-lite'; const DASHBOARD_PATH = dashboard(); +const ALERTS_PATH = alerts(); const METRICS_PATH = metrics(); const SESSIONS_PATH = sessions(); const ASSIST_PATH = assist(); const CLIENT_PATH = client(CLIENT_DEFAULT_TAB); const Header = (props) => { - const { - sites, location, account, + const { + sites, location, account, onLogoutClick, siteId, boardingCompletion = 100, showAlerts = false, } = props; - + const name = account.get('name').split(" ")[0]; const [hideDiscover, setHideDiscover] = useState(false) const { userStore, notificationStore } = useStore(); @@ -52,7 +54,7 @@ const Header = (props) => { useEffect(() => { if (!account.id || initialDataFetched) return; - + setTimeout(() => { Promise.all([ userStore.fetchLimits(), @@ -101,9 +103,11 @@ const Header = (props) => { className={ styles.nav } activeClassName={ styles.active } isActive={ (_, location) => { - return location.pathname.includes(DASHBOARD_PATH) || location.pathname.includes(METRICS_PATH); + return location.pathname.includes(DASHBOARD_PATH) + || location.pathname.includes(METRICS_PATH) + || location.pathname.includes(ALERTS_PATH) }} - > + > { 'Dashboards' }
@@ -111,18 +115,18 @@ const Header = (props) => {
{ (boardingCompletion < 100 && !hideDiscover) && ( - + setHideDiscover(true)} />
)} - +
- +
diff --git a/frontend/app/components/Session_/PlayerBlock.js b/frontend/app/components/Session_/PlayerBlock.js index 562ea8958..68d2c51c8 100644 --- a/frontend/app/components/Session_/PlayerBlock.js +++ b/frontend/app/components/Session_/PlayerBlock.js @@ -1,9 +1,8 @@ import React from 'react'; import cn from "classnames"; import { connect } from 'react-redux'; -import { } from 'Player'; import { - NONE, OVERVIEW, + NONE, } from 'Duck/components/player'; import Player from './Player'; import SubHeader from './Subheader'; diff --git a/frontend/app/mstore/dashboardStore.ts b/frontend/app/mstore/dashboardStore.ts index 2fc6f696c..14e899c35 100644 --- a/frontend/app/mstore/dashboardStore.ts +++ b/frontend/app/mstore/dashboardStore.ts @@ -1,6 +1,7 @@ import { makeAutoObservable, runInAction, + computed, } from "mobx"; import Dashboard from "./types/dashboard"; import Widget from "./types/widget"; @@ -64,6 +65,11 @@ export default class DashboardStore { this.drillDownFilter.updateKey("endTimestamp", timeStamps.endTimestamp); } + @computed + get sortedDashboards() { + return [...this.dashboards].sort((a, b) => b.createdAt - a.createdAt) + } + toggleAllSelectedWidgets(isSelected: boolean) { if (isSelected) { const allWidgets = this.widgetCategories.reduce((acc, cat) => { @@ -89,7 +95,7 @@ export default class DashboardStore { } removeSelectedWidgetByCategory = (category: any) => { - const categoryWidgetIds = category.widgets.map((w) => w.metricId); + const categoryWidgetIds = category.widgets.map((w: Widget) => w.metricId); this.selectedWidgets = this.selectedWidgets.filter( (widget: any) => !categoryWidgetIds.includes(widget.metricId) ); @@ -119,7 +125,8 @@ export default class DashboardStore { this.selectedWidgets = []; } - updateKey(key: any, value: any) { + updateKey(key: string, value: any) { + // @ts-ignore this[key] = value; } @@ -138,7 +145,7 @@ export default class DashboardStore { .getDashboards() .then((list: any) => { runInAction(() => { - this.dashboards = list.map((d) => + this.dashboards = list.map((d: Record) => new Dashboard().fromJson(d) ); }); @@ -168,7 +175,7 @@ export default class DashboardStore { this.fetchingDashboard = value; } - save(dashboard: IDashboard): Promise { + save(dashboard: Dashboard): Promise { this.isSaving = true; const isCreating = !dashboard.dashboardId; @@ -205,7 +212,7 @@ export default class DashboardStore { }); } - saveMetric(metric: IWidget, dashboardId: string): Promise { + saveMetric(metric: Widget, dashboardId: string): Promise { const isCreating = !metric.widgetId; return dashboardService .saveMetric(metric, dashboardId) @@ -252,7 +259,7 @@ export default class DashboardStore { fromJson(json: any) { runInAction(() => { - this.dashboards = json.dashboards.map((d) => + this.dashboards = json.dashboards.map((d: Record) => new Dashboard().fromJson(d) ); }); @@ -367,7 +374,7 @@ export default class DashboardStore { }); } - addWidgetToDashboard(dashboard: IDashboard, metricIds: any): Promise { + addWidgetToDashboard(dashboard: Dashboard, metricIds: any): Promise { this.isSaving = true; return dashboardService .addWidget(dashboard, metricIds) @@ -399,7 +406,7 @@ export default class DashboardStore { } fetchMetricChartData( - metric: IWidget, + metric: Widget, data: any, isWidget: boolean = false, period: Record diff --git a/frontend/app/mstore/metricStore.ts b/frontend/app/mstore/metricStore.ts index 9baa8e274..11bcf8894 100644 --- a/frontend/app/mstore/metricStore.ts +++ b/frontend/app/mstore/metricStore.ts @@ -1,5 +1,5 @@ -import { makeAutoObservable, runInAction, observable, action, reaction, computed } from "mobx" -import Widget, { IWidget } from "./types/widget"; +import { makeAutoObservable, computed } from "mobx" +import Widget from "./types/widget"; import { metricService, errorService } from "App/services"; import { toast } from 'react-toastify'; import Error from "./types/error"; @@ -8,8 +8,8 @@ export default class MetricStore { isLoading: boolean = false isSaving: boolean = false - metrics: IWidget[] = [] - instance: IWidget = new Widget() + metrics: Widget[] = [] + instance = new Widget() page: number = 1 pageSize: number = 10 @@ -20,41 +20,21 @@ export default class MetricStore { sessionsPageSize: number = 10 constructor() { - makeAutoObservable(this, { - isLoading: observable, - metrics: observable, - instance: observable, - page: observable, - pageSize: observable, - metricsSearch: observable, - sort: observable, + makeAutoObservable(this) + } - init: action, - updateKey: action, - merge: action, - reset: action, - addToList: action, - updateInList: action, - findById: action, - removeById: action, - - save: action, - fetchList: action, - fetch: action, - delete: action, - - fetchError: action, - - paginatedList: computed, - }) + @computed + get sortedWidgets() { + return [...this.metrics].sort((a, b) => b.lastModified - a.lastModified) } // State Actions - init(metric?: IWidget|null) { + init(metric?: Widget | null) { this.instance.update(metric || new Widget()) } updateKey(key: string, value: any) { + // @ts-ignore this[key] = value } @@ -70,33 +50,36 @@ export default class MetricStore { } } - addToList(metric: IWidget) { + addToList(metric: Widget) { this.metrics.push(metric) } - updateInList(metric: IWidget) { - const index = this.metrics.findIndex((m: IWidget) => m[Widget.ID_KEY] === metric[Widget.ID_KEY]) + updateInList(metric: Widget) { + // @ts-ignore + const index = this.metrics.findIndex((m: Widget) => m[Widget.ID_KEY] === metric[Widget.ID_KEY]) if (index >= 0) { this.metrics[index] = metric } } findById(id: string) { + // @ts-ignore return this.metrics.find(m => m[Widget.ID_KEY] === id) } removeById(id: string): void { + // @ts-ignore this.metrics = this.metrics.filter(m => m[Widget.ID_KEY] !== id) } - get paginatedList(): IWidget[] { + get paginatedList(): Widget[] { const start = (this.page - 1) * this.pageSize const end = start + this.pageSize return this.metrics.slice(start, end) } // API Communication - save(metric: IWidget, dashboardId?: string): Promise { + save(metric: Widget, dashboardId?: string): Promise { const wasCreating = !metric.exists() this.isSaving = true return new Promise((resolve, reject) => { @@ -143,10 +126,12 @@ export default class MetricStore { }) } - delete(metric: IWidget) { + delete(metric: Widget) { this.isSaving = true + // @ts-ignore return metricService.deleteMetric(metric[Widget.ID_KEY]) .then(() => { + // @ts-ignore this.removeById(metric[Widget.ID_KEY]) toast.success('Metric deleted successfully') }).finally(() => { diff --git a/frontend/app/mstore/types/dashboard.ts b/frontend/app/mstore/types/dashboard.ts index eed78a02b..0213f9b0d 100644 --- a/frontend/app/mstore/types/dashboard.ts +++ b/frontend/app/mstore/types/dashboard.ts @@ -15,7 +15,7 @@ export default class Dashboard { isValid: boolean = false currentWidget: Widget = new Widget() config: any = {} - createdAt: Date = new Date() + createdAt: number = new Date().getTime() constructor() { makeAutoObservable(this) diff --git a/frontend/app/mstore/types/widget.ts b/frontend/app/mstore/types/widget.ts index 01afcdc30..c43cf76e2 100644 --- a/frontend/app/mstore/types/widget.ts +++ b/frontend/app/mstore/types/widget.ts @@ -24,7 +24,7 @@ export default class Widget { sessions: [] = [] isPublic: boolean = true owner: string = "" - lastModified: Date = new Date() + lastModified: number = new Date().getTime() dashboards: any[] = [] dashboardIds: any[] = [] config: any = {} diff --git a/frontend/app/player/MessageDistributor/StatedScreen/Screen/BaseScreen.ts b/frontend/app/player/MessageDistributor/StatedScreen/Screen/BaseScreen.ts index 39dda161d..08a36c610 100644 --- a/frontend/app/player/MessageDistributor/StatedScreen/Screen/BaseScreen.ts +++ b/frontend/app/player/MessageDistributor/StatedScreen/Screen/BaseScreen.ts @@ -23,7 +23,7 @@ function getElementsFromInternalPoint(doc: Document, { x, y }: Point): Element[] } if (typeof doc.elementsFromPoint === 'function') { - return doc.elementsFromPoint(x, y) + return doc.elementsFromPoint(x, y) } const el = doc.elementFromPoint(x, y) return el ? [ el ] : [] @@ -53,10 +53,13 @@ function isIframe(el: Element): el is HTMLIFrameElement { } export default abstract class BaseScreen { - public readonly overlay: HTMLDivElement; - private readonly iframe: HTMLIFrameElement; - protected readonly screen: HTMLDivElement; + public readonly overlay: HTMLDivElement; + + private readonly iframe: HTMLIFrameElement; + protected readonly screen: HTMLDivElement; + protected readonly controlButton: HTMLDivElement; protected parentElement: HTMLElement | null = null; + constructor() { const iframe = document.createElement('iframe'); iframe.className = styles.iframe; @@ -83,7 +86,7 @@ export default abstract class BaseScreen { this.parentElement = parentElement; // parentElement.onresize = this.scale; - window.addEventListener('resize', this.scale); + window.addEventListener('resize', this.scale); this.scale(); /* == For the Inspecting Document content == */ @@ -101,6 +104,11 @@ export default abstract class BaseScreen { }) } + toggleRemoteControlStatus(isEnabled: boolean ) { + const styles = isEnabled ? { border: '2px dashed blue' } : { border: 'unset'} + return Object.assign(this.screen.style, styles) + } + get window(): WindowProxy | null { return this.iframe.contentWindow; } @@ -145,7 +153,7 @@ export default abstract class BaseScreen { } getElementFromInternalPoint({ x, y }: Point): Element | null { - // elementFromPoint && elementFromPoints require viewpoint-related coordinates, + // elementFromPoint && elementFromPoints require viewpoint-related coordinates, // not document-related return this.document?.elementFromPoint(x, y) || null; } diff --git a/frontend/app/player/MessageDistributor/StatedScreen/Screen/screen.module.css b/frontend/app/player/MessageDistributor/StatedScreen/Screen/screen.module.css index 696b38e7a..f9a2d2d8a 100644 --- a/frontend/app/player/MessageDistributor/StatedScreen/Screen/screen.module.css +++ b/frontend/app/player/MessageDistributor/StatedScreen/Screen/screen.module.css @@ -18,5 +18,5 @@ left: 0; right: 0; bottom: 0; - z-index: 10; -} \ No newline at end of file + z-index: 10; +} diff --git a/frontend/app/player/MessageDistributor/managers/AssistManager.ts b/frontend/app/player/MessageDistributor/managers/AssistManager.ts index a72c9c0c8..5a4945fbe 100644 --- a/frontend/app/player/MessageDistributor/managers/AssistManager.ts +++ b/frontend/app/player/MessageDistributor/managers/AssistManager.ts @@ -295,11 +295,13 @@ export default class AssistManager { this.md.overlay.addEventListener("mousemove", this.onMouseMove) this.md.overlay.addEventListener("click", this.onMouseClick) this.md.overlay.addEventListener("wheel", this.onWheel) + this.md.toggleRemoteControlStatus(true) update({ remoteControl: RemoteControlStatus.Enabled }) } else { this.md.overlay.removeEventListener("mousemove", this.onMouseMove) this.md.overlay.removeEventListener("click", this.onMouseClick) this.md.overlay.removeEventListener("wheel", this.onWheel) + this.md.toggleRemoteControlStatus(false) update({ remoteControl: RemoteControlStatus.Disabled }) this.toggleAnnotation(false) }