diff --git a/frontend/app/components/Dashboard/WidgetWrapper/WidgetWrapper.tsx b/frontend/app/components/Dashboard/WidgetWrapper/WidgetWrapper.tsx index daade0774..d34eeb08d 100644 --- a/frontend/app/components/Dashboard/WidgetWrapper/WidgetWrapper.tsx +++ b/frontend/app/components/Dashboard/WidgetWrapper/WidgetWrapper.tsx @@ -5,9 +5,9 @@ import { ItemMenu } from 'UI'; function WidgetWrapper(props) { const { widget } = props; - const store: any = useDashboardStore(); - const dashboard = store.selectedDashboard; - const siteId = store.siteId; + // const store: any = useDashboardStore(); + // const dashboard = store.selectedDashboard; + // const siteId = store.siteId; return (
diff --git a/frontend/app/components/Dashboard/components/DashboardMetricSelection/DashboardMetricSelection.tsx b/frontend/app/components/Dashboard/components/DashboardMetricSelection/DashboardMetricSelection.tsx new file mode 100644 index 000000000..ef4a9886e --- /dev/null +++ b/frontend/app/components/Dashboard/components/DashboardMetricSelection/DashboardMetricSelection.tsx @@ -0,0 +1,129 @@ +import React from 'react'; +import WidgetWrapper from '../../WidgetWrapper'; +import { useDashboardStore } from '../../store/store'; +import { useObserver } from 'mobx-react-lite'; +import cn from 'classnames'; +import { Button } from 'UI'; + +function WidgetCategoryItem({ category, isSelected, onClick, selectedWidgetIds, unSelectCategory }) { + const selectedCategoryWidgetsCount = useObserver(() => { + return category.widgets.filter(widget => selectedWidgetIds.includes(widget.widgetId)).length; + }); + return ( +
onClick(category)} + > +
{category.name}
+
{category.description}
+ {selectedCategoryWidgetsCount > 0 && ( +
+ unSelectCategory(category)} /> + {`Selected ${selectedCategoryWidgetsCount} of ${category.widgets.length}`} +
+ )} +
+ ); +} + +function DashboardMetricSelection(props) { + const store: any = useDashboardStore(); + const widgetCategories = store?.widgetCategories; + const widgetTemplates = store?.widgetTemplates; + const [activeCategory, setActiveCategory] = React.useState(widgetCategories[0]); + const [selectedWidgets, setSelectedWidgets] = React.useState([]); + const selectedWidgetIds = selectedWidgets.map((widget: any) => widget.widgetId); + + const removeSelectedWidgetByCategory = (category: any) => { + const categoryWidgetIds = category.widgets.map((widget: any) => widget.widgetId); + const newSelectedWidgets = selectedWidgets.filter((widget: any) => !categoryWidgetIds.includes(widget.widgetId)); + setSelectedWidgets(newSelectedWidgets); + }; + + const toggleWidgetSelection = (widget: any) => { + console.log('toggleWidgetSelection', widget.widgetId); + if (selectedWidgetIds.includes(widget.widgetId)) { + setSelectedWidgets(selectedWidgets.filter((w: any) => w.widgetId !== widget.widgetId)); + } else { + setSelectedWidgets(selectedWidgets.concat(widget)); + } + }; + + const handleWidgetCategoryClick = (category: any) => { + setActiveCategory(category); + }; + + const toggleAllWidgets = ({ target: { checked }}) => { + if (checked == true) { + const allWidgets = widgetCategories.reduce((acc, category) => { + return acc.concat(category.widgets); + }, []); + + setSelectedWidgets(allWidgets); + } else { + setSelectedWidgets([]); + } + } + + return useObserver(() => ( +
+
+
+
Categories
+
+ +
+
+

Errors Tracking

+ 12 +
+ +
+ Showing past 7 days data for visual clue +
+ + Select All +
+
+
+
+
+
+
+ {widgetCategories.map((category, index) => + + )} +
+
+
+
+ {activeCategory.widgets.map((widget: any) => ( +
toggleWidgetSelection(widget)} + > + +
+ ))} +
+
+
+ +
+ +
+
+ )); +} + +export default DashboardMetricSelection; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/components/DashboardMetricSelection/index.ts b/frontend/app/components/Dashboard/components/DashboardMetricSelection/index.ts new file mode 100644 index 000000000..4436d6bfc --- /dev/null +++ b/frontend/app/components/Dashboard/components/DashboardMetricSelection/index.ts @@ -0,0 +1 @@ +export { default } from './DashboardMetricSelection'; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/components/DashboardModal/DashboardModal.tsx b/frontend/app/components/Dashboard/components/DashboardModal/DashboardModal.tsx new file mode 100644 index 000000000..1cb87307a --- /dev/null +++ b/frontend/app/components/Dashboard/components/DashboardModal/DashboardModal.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import WidgetWrapper from '../../WidgetWrapper'; +import { useDashboardStore } from '../../store/store'; +import { observer, useObserver } from 'mobx-react-lite'; +import cn from 'classnames'; +import { Button } from 'UI'; +import DashboardMetricSelection from '../DashboardMetricSelection'; + + + +function DashboardModal(props) { + const store: any = useDashboardStore(); + + + return useObserver(() => ( +
+
+

Add Metric to Dashboard

+
+ +
+ )); +} + +export default observer(DashboardModal); \ No newline at end of file diff --git a/frontend/app/components/Dashboard/components/DashboardModal/index.ts b/frontend/app/components/Dashboard/components/DashboardModal/index.ts new file mode 100644 index 000000000..7082b746b --- /dev/null +++ b/frontend/app/components/Dashboard/components/DashboardModal/index.ts @@ -0,0 +1 @@ +export { default } from './DashboardModal' \ No newline at end of file diff --git a/frontend/app/components/Dashboard/components/DashboardView/DashboardView.tsx b/frontend/app/components/Dashboard/components/DashboardView/DashboardView.tsx index f99c4b537..09e6b5d3c 100644 --- a/frontend/app/components/Dashboard/components/DashboardView/DashboardView.tsx +++ b/frontend/app/components/Dashboard/components/DashboardView/DashboardView.tsx @@ -4,24 +4,17 @@ import { observer } from 'mobx-react-lite'; import { withDashboardStore } from '../../store/store'; import { Button, PageTitle, Link } from 'UI'; import { withSiteId, dashboardMetricCreate } from 'App/routes'; -import { ModalContext } from "App/components/Modal/modalContext"; - -const ModalContent = () => { - let { handleModal } = React.useContext(ModalContext); - return ( -
- Hello this is test -
- ) -} +import withModal from 'App/components/Modal/withModal'; +import DashboardModal from '../DashboardModal' function DashboardView(props) { - let { handleModal } = React.useContext(ModalContext); + // let { handleModal } = React.useContext(ModalContext); const { store } = props; const dashboard = store.selectedDashboard const list = dashboard?.widgets; useEffect(() => { - handleModal() + // handleModal() + props.showModal(DashboardModal) }, []) return (
@@ -36,4 +29,4 @@ function DashboardView(props) { ) } -export default withDashboardStore(observer(DashboardView)); \ No newline at end of file +export default withDashboardStore(withModal(observer(DashboardView))); \ No newline at end of file diff --git a/frontend/app/components/Dashboard/store/dashboardStore.ts b/frontend/app/components/Dashboard/store/dashboardStore.ts index 54e57d31c..0085c8f41 100644 --- a/frontend/app/components/Dashboard/store/dashboardStore.ts +++ b/frontend/app/components/Dashboard/store/dashboardStore.ts @@ -2,14 +2,14 @@ import { makeAutoObservable, runInAction, observable, action, reaction } from "m import Dashboard from "./dashboard" import APIClient from 'App/api_client'; import Widget from "./widget"; - export default class DashboardStore { dashboards: Dashboard[] = [] - widgets: Widget[] = [] + widgetTemplates: any[] = [] selectedDashboard: Dashboard | null = new Dashboard() isLoading: boolean = false siteId: any = null currentWidget: Widget = new Widget() + widgetCategories: any[] = [] private client = new APIClient() @@ -50,16 +50,27 @@ export default class DashboardStore { // this.selectedDashboard?.swapWidgetPosition(2, 0) // }, 3000) - for (let i = 0; i < 8; i++) { - const widget = getRandomWidget(); - widget.position = i; - widget.name = `Widget ${i}`; - widget.isPrivate = [true, false][Math.floor(Math.random() * 2)]; - widget.dashboardIds = [this.selectedDashboard?.dashboardId]; - widget.owner = ["John", "Jane", "Jack", "Jill"][i % 4]; - widget.metricType = ['timeseries', 'table'][Math.floor(Math.random() * 2)]; - this.widgets.push(widget); + for (let i = 0; i < 4; i++) { + const cat: any = { + name: `Category ${i + 1}`, + categoryId: i, + description: `Category ${i + 1} description`, + widgets: [] + } + // const randomBumberBetween = (min: number, max: number) => Math.floor(Math.random() * (max - min + 1)) + min + const randomNumber = Math.floor(Math.random() * (5 - 2 + 1)) + 2 + + for (let j = 0; j < randomNumber; j++) { + const widget: any= {}; + widget.widgetId = `${i}-${j}` + widget.name = `Widget ${i}-${j}`; + widget.metricType = ['timeseries', 'table'][Math.floor(Math.random() * 2)]; + cat.widgets.push(widget); + } + + this.widgetCategories.push(cat) } + } resetCurrentWidget() { diff --git a/frontend/app/components/Modal/Modal.js b/frontend/app/components/Modal/Modal.js index 0d078cc69..af0eff6b3 100644 --- a/frontend/app/components/Modal/Modal.js +++ b/frontend/app/components/Modal/Modal.js @@ -1,23 +1,16 @@ -import React from "react"; -import ReactDOM from "react-dom"; -import { ModalContext } from "./modalContext"; -import ModalOverlay from "./ModalOverlay"; +import React from 'react'; +import ReactDOM from 'react-dom'; -const Modal = () => { - let { modalContent, handleModal, modal } = React.useContext(ModalContext); - if (modal) { +export default class Modal extends React.PureComponent { + constructor(props) { + super(props); + this.el = document.createElement('div'); + } + + render() { return ReactDOM.createPortal( -
- - {modalContent} - -
, - document.querySelector("#modal-root") + this.props.children, + this.el, ); - } else return null; -}; - -export default Modal; + } +} \ No newline at end of file diff --git a/frontend/app/components/Modal/ModalContext.js b/frontend/app/components/Modal/ModalContext.js index 89c453a97..43ab9f8b8 100644 --- a/frontend/app/components/Modal/ModalContext.js +++ b/frontend/app/components/Modal/ModalContext.js @@ -1,18 +1,40 @@ -import React from "react"; -import useModal from "./useModal"; -import Modal from "./modal"; +import React, { Component, createContext } from 'react'; -let ModalContext; -let { Provider } = (ModalContext = React.createContext()); +const ModalContext = createContext({ + component: null, + props: {}, + showModal: () => {}, + hideModal: () => {} +}); -let ModalProvider = ({ children }) => { - let { modal, handleModal, modalContent } = useModal(); - return ( - - - {children} - - ); -}; +export class ModalProvider extends Component { + showModal = (component, props = {}) => { + this.setState({ + component, + props + }); + }; -export { ModalContext, ModalProvider }; + hideModal = () => + this.setState({ + component: null, + props: {} + }); + + state = { + component: null, + props: {}, + showModal: this.showModal, + hideModal: this.hideModal + }; + + render() { + return ( + + {this.props.children} + + ); + } +} + +export const ModalConsumer = ModalContext.Consumer; diff --git a/frontend/app/components/Modal/ModalRoot.js b/frontend/app/components/Modal/ModalRoot.js index 226447af1..98152c59e 100644 --- a/frontend/app/components/Modal/ModalRoot.js +++ b/frontend/app/components/Modal/ModalRoot.js @@ -1,3 +1,6 @@ +import React from 'react'; +import { ModalConsumer } from './ModalContext'; + const ModalRoot = () => ( {({ component: Component, props, hideModal }) => @@ -6,4 +9,4 @@ const ModalRoot = () => ( ); -export default ModalRoot \ No newline at end of file +export default ModalRoot; diff --git a/frontend/app/initialize.js b/frontend/app/initialize.js index 026bb5e76..6460a9eff 100644 --- a/frontend/app/initialize.js +++ b/frontend/app/initialize.js @@ -7,7 +7,8 @@ import store from './store'; import Router from './Router'; import DashboardStore from './components/Dashboard/store'; import { DashboardStoreProvider } from './components/Dashboard/store/store'; -import { ModalProvider } from './components/Modal/modalContext'; +import { ModalProvider } from './components/Modal/ModalContext'; +import ModalRoot from './components/Modal/ModalRoot'; document.addEventListener('DOMContentLoaded', () => { @@ -15,11 +16,12 @@ document.addEventListener('DOMContentLoaded', () => { render( ( - - - - - + + + + + + ), document.getElementById('app'), diff --git a/frontend/app/styles/colors-autogen.css b/frontend/app/styles/colors-autogen.css index c7b3a6ce1..a98c7cef6 100644 --- a/frontend/app/styles/colors-autogen.css +++ b/frontend/app/styles/colors-autogen.css @@ -62,6 +62,37 @@ .color-white { color: $white } .color-borderColor { color: $borderColor } +/* border-color */ +.border-color-main { border-color: $main } +.border-color-gray-light-shade { border-color: $gray-light-shade } +.border-color-gray-lightest { border-color: $gray-lightest } +.border-color-gray-light { border-color: $gray-light } +.border-color-gray-medium { border-color: $gray-medium } +.border-color-gray-dark { border-color: $gray-dark } +.border-color-gray-darkest { border-color: $gray-darkest } +.border-color-teal { border-color: $teal } +.border-color-teal-dark { border-color: $teal-dark } +.border-color-teal-light { border-color: $teal-light } +.border-color-tealx { border-color: $tealx } +.border-color-tealx-light { border-color: $tealx-light } +.border-color-tealx-light-border { border-color: $tealx-light-border } +.border-color-orange { border-color: $orange } +.border-color-yellow { border-color: $yellow } +.border-color-yellow2 { border-color: $yellow2 } +.border-color-orange-dark { border-color: $orange-dark } +.border-color-green { border-color: $green } +.border-color-green2 { border-color: $green2 } +.border-color-green-dark { border-color: $green-dark } +.border-color-red { border-color: $red } +.border-color-red2 { border-color: $red2 } +.border-color-blue { border-color: $blue } +.border-color-blue2 { border-color: $blue2 } +.border-color-active-blue { border-color: $active-blue } +.border-color-active-blue-border { border-color: $active-blue-border } +.border-color-pink { border-color: $pink } +.border-color-white { border-color: $white } +.border-color-borderColor { border-color: $borderColor } + /* color */ .hover-main:hover { color: $main } .hover-gray-light-shade:hover { color: $gray-light-shade } diff --git a/frontend/scripts/colors.js b/frontend/scripts/colors.js index ac8eb69be..6071785a5 100644 --- a/frontend/scripts/colors.js +++ b/frontend/scripts/colors.js @@ -12,6 +12,9 @@ ${ colors.map(color => `.fill-${ color } { fill: $${ color } }`).join('\n') } /* color */ ${ colors.map(color => `.color-${ color } { color: $${ color } }`).join('\n') } +/* border-color */ +${ colors.map(color => `.border-color-${ color } { border-color: $${ color } }`).join('\n') } + /* color */ ${ colors.map(color => `.hover-${ color }:hover { color: $${ color } }`).join('\n') } `)