diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 6cf0839..0000000 --- a/.babelrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-react" - ], - "plugins": [ - ["@babel/plugin-proposal-decorators", { "legacy": true }], - ["@babel/plugin-proposal-class-properties", { "loose" : true }], - "@babel/plugin-syntax-dynamic-import" - ] -} \ No newline at end of file diff --git a/chrome/manifest.json b/chrome/manifest.json index c25ba9f..31a712c 100644 --- a/chrome/manifest.json +++ b/chrome/manifest.json @@ -1,12 +1,13 @@ { - "version": "1.0.0", + "version": "2.0.0", "name": "Eventrix devtools", "short_name": "Eventrix devtools", "description": "Extension for Eventrix", - "permissions": [], + "permissions": ["activeTab", "scripting"], + "host_permissions": [""], "devtools_page": "devtools.html", - "browser_action": { - "default_icon": { + "action": { + "default_assets/icon": { "16": "images/eventrix_16x16.png", "32": "images/eventrix_32x32.png", "48": "images/eventrix_48x48.png", @@ -21,5 +22,5 @@ "64": "images/eventrix_64x64.png", "128": "images/eventrix_128x128.png" }, - "manifest_version": 2 -} \ No newline at end of file + "manifest_version": 3 +} diff --git a/chrome/panel.html b/chrome/panel.html index 5b82c93..a0044da 100644 --- a/chrome/panel.html +++ b/chrome/panel.html @@ -8,4 +8,4 @@
- \ No newline at end of file + diff --git a/index.html b/index.html index 7d74e61..da87c73 100644 --- a/index.html +++ b/index.html @@ -1,9 +1,13 @@ - + + - + + + + Eventrix -
- +
+ - \ No newline at end of file + diff --git a/package.json b/package.json index 51d137a..b948d2c 100644 --- a/package.json +++ b/package.json @@ -1,40 +1,26 @@ { "name": "eventrix-tools", - "version": "1.0.1", - "description": "React project manager", + "version": "2.0.0", + "description": "Eventrix devtools", "main": "index.js", "private": true, "scripts": { "test": "jest", - "start": "webpack-dev-server --config webpack.config.js", - "build": "webpack --config webpack.config.js" + "start": "vite", + "build": "vite build" }, "author": "", "license": "ISC", "devDependencies": { - "@babel/cli": "^7.7.0", - "@babel/core": "^7.7.4", - "@babel/plugin-proposal-class-properties": "^7.7.4", - "@babel/plugin-proposal-decorators": "^7.12.12", - "@babel/plugin-syntax-decorators": "^7.12.1", - "@babel/plugin-syntax-dynamic-import": "^7.2.0", - "@babel/polyfill": "^7.0.0", - "@babel/preset-env": "^7.7.4", - "@babel/preset-react": "^7.0.0", - "babel-loader": "^8.0.6", - "babel-plugin-inline-react-svg": "^1.0.1", - "classnames": "^2.2.6", - "css-loader": "^2.1.0", - "directory-named-webpack-plugin": "^4.0.1", - "file-loader": "^6.2.0", - "node-sass": "^4.11.0", - "resolve-url-loader": "^3.1.2", - "sass-loader": "^7.1.0", - "style-loader": "^0.23.1", - "url-loader": "^4.1.1", - "webpack": "^4.41.2", - "webpack-cli": "^3.3.10", - "webpack-dev-server": "^3.7.2" + "@types/react": "^18.2.15", + "@types/react-dom": "^18.2.7", + "@vitejs/plugin-react-swc": "^3.3.2", + "eslint": "^8.45.0", + "eslint-plugin-react": "^7.32.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.3", + "sass": "^1.68.0", + "vite": "^4.4.5" }, "jest": { "verbose": true, @@ -53,18 +39,18 @@ ] }, "dependencies": { - "@material-ui/core": "^4.11.3", - "@material-ui/icons": "^4.11.2", - "@material-ui/lab": "^4.0.0-alpha.39", - "axios": "^0.19.0", - "browser-storage-db": "^1.0.0", - "eventrix": "^2.0.1", - "form-schema-validation": "^1.17.4", + "@emotion/react": "^11.11.1", + "@emotion/styled": "^11.11.0", + "@iconify/react": "^4.1.1", + "@mui/material": "^5.14.3", + "classnames": "^2.3.2", + "eventrix": "^2.9.1", + "lodash": "^4.17.21", "moment": "^2.29.1", - "react": "^16.13.1", - "react-components-form": "^3.8.1", - "react-dom": "^16.13.1", - "react-object-inspector": "^0.2.1", - "react-router-dom": "^4.3.1" + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-inspector": "^6.0.2", + "react-router": "^6.3.0", + "react-router-dom": "^6.3.0" } } diff --git a/public/assets/eventrix_128x128.png b/public/assets/eventrix_128x128.png new file mode 100644 index 0000000..a3bac6f Binary files /dev/null and b/public/assets/eventrix_128x128.png differ diff --git a/public/assets/eventrix_16x16.png b/public/assets/eventrix_16x16.png new file mode 100644 index 0000000..825d3d2 Binary files /dev/null and b/public/assets/eventrix_16x16.png differ diff --git a/public/assets/eventrix_32x32.png b/public/assets/eventrix_32x32.png new file mode 100644 index 0000000..28f4147 Binary files /dev/null and b/public/assets/eventrix_32x32.png differ diff --git a/public/assets/eventrix_48x48.png b/public/assets/eventrix_48x48.png new file mode 100644 index 0000000..153bf3c Binary files /dev/null and b/public/assets/eventrix_48x48.png differ diff --git a/public/assets/eventrix_64x64.png b/public/assets/eventrix_64x64.png new file mode 100644 index 0000000..ff270f8 Binary files /dev/null and b/public/assets/eventrix_64x64.png differ diff --git a/public/assets/logo_devtools.svg b/public/assets/logo_devtools.svg new file mode 100644 index 0000000..5792ea5 --- /dev/null +++ b/public/assets/logo_devtools.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/devtools.html b/public/devtools.html new file mode 100644 index 0000000..3630600 --- /dev/null +++ b/public/devtools.html @@ -0,0 +1,10 @@ + + + + + Eventrix devtools + + + + + diff --git a/public/devtools.js b/public/devtools.js new file mode 100644 index 0000000..d24e003 --- /dev/null +++ b/public/devtools.js @@ -0,0 +1,5 @@ +chrome.devtools.panels.create('Eventrix', + 'assets/eventrix_16x16.png', + 'index.html', + null +); diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000..d6db131 --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,26 @@ +{ + "version": "2.0.0", + "name": "Eventrix devtools", + "short_name": "Eventrix devtools", + "description": "Extension for Eventrix", + "permissions": ["activeTab", "scripting"], + "host_permissions": [""], + "devtools_page": "devtools.html", + "action": { + "default_assets/icon": { + "16": "assets/eventrix_16x16.png", + "32": "assets/eventrix_32x32.png", + "48": "assets/eventrix_48x48.png", + "64": "assets/eventrix_64x64.png", + "128": "assets/eventrix_128x128.png" + } + }, + "icons": { + "16": "assets/eventrix_16x16.png", + "32": "assets/eventrix_32x32.png", + "48": "assets/eventrix_48x48.png", + "64": "assets/eventrix_64x64.png", + "128": "assets/eventrix_128x128.png" + }, + "manifest_version": 3 +} diff --git a/src/DevtoolsPanel/App.css b/src/DevtoolsPanel/App.css new file mode 100644 index 0000000..293d3b1 --- /dev/null +++ b/src/DevtoolsPanel/App.css @@ -0,0 +1,3 @@ +body { + margin: 0; +} diff --git a/src/DevtoolsPanel/App.jsx b/src/DevtoolsPanel/App.jsx index d16c3ba..7d50eba 100644 --- a/src/DevtoolsPanel/App.jsx +++ b/src/DevtoolsPanel/App.jsx @@ -1,54 +1,112 @@ -import React from 'react'; -import StorageIcon from '@material-ui/icons/Storage'; -import DateRangeIcon from '@material-ui/icons/DateRange'; -import HistoryIcon from '@material-ui/icons/History'; -import ReceiverIcon from '@material-ui/icons/SettingsInputAntenna'; -import ListenerIcon from '@material-ui/icons/WifiTethering'; +import React, {useCallback} from 'react'; import CurrentState from "./modules/CurrentState"; import StateHistory from "./modules/StateHistory"; -import EventsHistory from "./modules/EventsHistory"; -import Receivers from "./modules/Receivers"; -import Listeners from "./modules/Listeners"; import Route from "./components/Route"; -import RouteLink from "./components/RouteLink/RouteLink"; import { ROUTES } from "./constants/routes"; - -import styles from './App.scss'; +import {Stack} from "@mui/material"; +import Menu from "./modules/Menu"; +import Divider from "@mui/material/Divider"; +import StateListenersStats from "./modules/StateListenersStats"; +import StatsBox from "./components/StatsBox"; +import './App.css'; +import {DateRangeIcon, EmitIcon, HistoryIcon, StorageIcon} from "./components/icons"; +import Header from "./components/Header"; +import {useEmit} from "eventrix"; +import { + EVENTS_HISTORY_FETCH, + RESET_EMITTER, + STATE_FETCH, + STATE_HISTORY_FETCH, + STATE_HISTORY_RESET, + EVENTS_HISTORY_RESET +} from "./events"; +import StateHistoryPreview from "./modules/StateHistory/StateHistoryPreview"; +import StateStats from "./modules/StateHistory/StateStats"; +import EventsHistory from "./modules/EventsHistory"; +import EventsStats from "./modules/EventsHistory/EventsStats"; +import EventsHistoryPreview from "./modules/EventsHistory/EventsHistoryPreview"; +import Emitter from "./modules/Emitter"; const App = () => { + const emit = useEmit(); + const fetchState = useCallback(() => { emit(STATE_FETCH) }, [emit]); + const fetchStateHistory = useCallback(() => { emit(STATE_HISTORY_FETCH) }, [emit]); + const fetchEventsHistory = useCallback(() => { emit(EVENTS_HISTORY_FETCH) }, [emit]); + + const resetStateHistory = useCallback(() => { emit(STATE_HISTORY_RESET) }, [emit]); + const resetEventsHistory = useCallback(() => { emit(EVENTS_HISTORY_RESET) }, [emit]); + const resetEmitter = useCallback(() => { emit(RESET_EMITTER) }, [emit]); + return ( -
-
-
-

Eventrix

-
devtools
-
- CURRENT STATE - STATE HISTORY - EVENTS HISTORY - RECEIVERS - LISTENERS -
-
+ + + + - +
} + refreshAction={fetchState} + /> + + + + + + + - +
} + resetAction={resetStateHistory} + refreshAction={fetchStateHistory} + /> + + + + + + + + + + - - - - +
} + resetAction={resetEventsHistory} + refreshAction={fetchEventsHistory} + /> + + + + + + + + + + - - + +
} + resetAction={resetEmitter} + /> + + + + -
-
+ + ) }; diff --git a/src/DevtoolsPanel/App.scss b/src/DevtoolsPanel/App.scss deleted file mode 100644 index 25faa9f..0000000 --- a/src/DevtoolsPanel/App.scss +++ /dev/null @@ -1,69 +0,0 @@ -body { - margin: 0; - font-family: sans-serif; -} - -.container { - background: #FFF; - display: flex; - flex-wrap: nowrap; -} - -.title { - display: block; - padding: 8px 12px; - - h1 { - font-size: 26px; - font-weight: bold; - color: #FFF; - text-transform: uppercase; - width: 100%; - text-align: left; - margin: 0; - } - - div { - text-align: right; - width: 100%; - font-size: 13px; - color: #4c7fff; - } -} - -.navigation { - width: 200px; - height: 100vh; - background: #1b1b1b; - border-right: 1px solid #070707; -} - -.menuItem { - width: calc(100% - 20px); - display: flex; - align-items: center; - justify-content: flex-start; - padding: 10px; - border-bottom: 1px solid #4b4b4b; - font-size: 13px; - color: #FFFFFF; - - svg { - margin-right: 10px; - } - - &:hover { - background: #2d53a5; - cursor: pointer; - } -} - -.activeMenuItem { - @extend .menuItem; - - background: #305cc8; -} - -.content { - width: 100%; -} \ No newline at end of file diff --git a/src/DevtoolsPanel/components/AutoRefreshModeButton/AutoRefreshModeButton.jsx b/src/DevtoolsPanel/components/AutoRefreshModeButton/AutoRefreshModeButton.jsx deleted file mode 100644 index e601ba2..0000000 --- a/src/DevtoolsPanel/components/AutoRefreshModeButton/AutoRefreshModeButton.jsx +++ /dev/null @@ -1,25 +0,0 @@ -import React, {useCallback} from 'react'; -import { useEventrixState, useEmit } from 'eventrix'; -import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord'; -import Button from '../Button'; -import {TURN_OFF_AUTO_REFRESH_MODE, TURN_ON_AUTO_REFRESH_MODE} from '../../events'; -import styles from './AutoRefreshModeButton.scss'; - -const AutoRefreshModeButton = ({ type }) => { - const [isAutoRefreshModeActive] = useEventrixState(`autoRefreshMode.${type}`); - const emit = useEmit(); - const toggleAutoRefreshMode = useCallback(() => { - if (isAutoRefreshModeActive) { - emit(TURN_OFF_AUTO_REFRESH_MODE, { refreshType: type }); - } else { - emit(TURN_ON_AUTO_REFRESH_MODE, { refreshType: type }); - } - }, [isAutoRefreshModeActive, emit, type]); - return ( - - ) -}; - -export default AutoRefreshModeButton; diff --git a/src/DevtoolsPanel/components/AutoRefreshModeButton/AutoRefreshModeButton.scss b/src/DevtoolsPanel/components/AutoRefreshModeButton/AutoRefreshModeButton.scss deleted file mode 100644 index 548597e..0000000 --- a/src/DevtoolsPanel/components/AutoRefreshModeButton/AutoRefreshModeButton.scss +++ /dev/null @@ -1,7 +0,0 @@ -.active { - color: green; -} - -.disabled { - color: red; -} \ No newline at end of file diff --git a/src/DevtoolsPanel/components/AutoRefreshModeButton/index.js b/src/DevtoolsPanel/components/AutoRefreshModeButton/index.js deleted file mode 100644 index 4c83886..0000000 --- a/src/DevtoolsPanel/components/AutoRefreshModeButton/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './AutoRefreshModeButton'; diff --git a/src/DevtoolsPanel/components/Button/Button.jsx b/src/DevtoolsPanel/components/Button/Button.jsx deleted file mode 100644 index bd48f4f..0000000 --- a/src/DevtoolsPanel/components/Button/Button.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -import styles from './Button.scss'; - -const Button = ({ children, onClick, kind = 'default' }) => { - const kinds = { - default: styles.default, - primary: styles.primary, - secondary: styles.secondary, - positive: styles.positive, - negative: styles.negative, - }; - return ( - - ) -}; - -export default Button; diff --git a/src/DevtoolsPanel/components/Button/Button.scss b/src/DevtoolsPanel/components/Button/Button.scss deleted file mode 100644 index 2d2388f..0000000 --- a/src/DevtoolsPanel/components/Button/Button.scss +++ /dev/null @@ -1,79 +0,0 @@ -.buttonBase { - border-radius: 4px; - border: 1px solid #333; - padding: 8px 12px; - outline: none; - font-size: 13px; - display: flex; - align-items: center; - justify-content: center; - - &:hover { - cursor: pointer; - } -} - -.default { - @extend .buttonBase; - - border-color: #aaaaaa; - background: #dddddd; - color: #333; - - &:hover { - background: #c9c9c9; - color: #2b2b2b; - } -} - -.primary { - @extend .buttonBase; - - border-color: #1e1e1e; - background: #232322; - color: #f0f0f0; - - &:hover { - background: #0f0f0e; - color: #ffffff; - } -} - -.secondary { - @extend .buttonBase; - - border-color: #2d54a5; - background: #305bc8; - color: #ebebeb; - - &:hover { - background: #2d53a5; - color: #ffffff; - } -} - -.positive { - @extend .buttonBase; - - border-color: #008710; - background: #009b0f; - color: #ebebeb; - - &:hover { - background: #008710; - color: #ffffff; - } -} - -.negative { - @extend .buttonBase; - - border-color: #912325; - background: #a52225; - color: #ebebeb; - - &:hover { - background: #912325; - color: #ffffff; - } -} \ No newline at end of file diff --git a/src/DevtoolsPanel/components/Button/index.js b/src/DevtoolsPanel/components/Button/index.js deleted file mode 100644 index efe8c80..0000000 --- a/src/DevtoolsPanel/components/Button/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Button'; diff --git a/src/DevtoolsPanel/components/Dropdown/Dropdown.jsx b/src/DevtoolsPanel/components/Dropdown/Dropdown.jsx new file mode 100644 index 0000000..6442a7f --- /dev/null +++ b/src/DevtoolsPanel/components/Dropdown/Dropdown.jsx @@ -0,0 +1,56 @@ +import React, {useCallback, useEffect, useRef, useState} from 'react'; +import {Button, Stack} from "@mui/material"; + +const useClickOutsideListener = (ref, callback) => { + const clickOutsideListener = useCallback((e) => { + if(!ref.current.contains(e.target)) { + callback(); + } + }, [ref, callback]); + + useEffect(() => { + window.addEventListener('click', clickOutsideListener); + return () => { + window.removeEventListener('click', clickOutsideListener); + } + }, [clickOutsideListener, ref]); +} + +const dropdownStyles = (theme) => ({ + position: "absolute", + top: "calc(100% + 10px)", + background: theme.palette.background.paper, + width: "250px", + maxWidth: theme.breakpoints.between('xs', 'md') ? "calc(100vw - 150px)" : "calc(100vw - 360px)", + padding: 1, + borderRadius: 1, + boxShadow: 1, + right: 0, + zIndex: 1, +}); + +const Dropdown = ({ children }) => { + const [isFilterTooltipOpened, setFiltersTooltipOpened] = useState(false); + const filtersRef = useRef(); + + const toggleFiltersTooltip = useCallback(() => { + setFiltersTooltipOpened(!isFilterTooltipOpened); + }, [isFilterTooltipOpened, setFiltersTooltipOpened]); + + useClickOutsideListener(filtersRef, () => { + setFiltersTooltipOpened(false); + }); + + return ( + + + {isFilterTooltipOpened && + + {children} + + } + + ); +} + +export default Dropdown; diff --git a/src/DevtoolsPanel/components/Dropdown/index.js b/src/DevtoolsPanel/components/Dropdown/index.js new file mode 100644 index 0000000..e69de29 diff --git a/src/DevtoolsPanel/components/Header/Header.jsx b/src/DevtoolsPanel/components/Header/Header.jsx new file mode 100644 index 0000000..92efb96 --- /dev/null +++ b/src/DevtoolsPanel/components/Header/Header.jsx @@ -0,0 +1,24 @@ +import React from 'react'; +import {Button, Stack, Typography} from "@mui/material"; +import {ClearIcon, RefreshIcon} from "../icons"; + +const Header = ({ title, icon, resetAction, refreshAction }) => { + return ( + + + {icon} + {title} + + + {!!resetAction && } + {!!refreshAction && } + + + ) +}; + +export default Header; diff --git a/src/DevtoolsPanel/components/Header/index.js b/src/DevtoolsPanel/components/Header/index.js new file mode 100644 index 0000000..579f1ac --- /dev/null +++ b/src/DevtoolsPanel/components/Header/index.js @@ -0,0 +1 @@ +export { default } from './Header'; diff --git a/src/DevtoolsPanel/components/Iconify.jsx b/src/DevtoolsPanel/components/Iconify.jsx new file mode 100644 index 0000000..c829bb2 --- /dev/null +++ b/src/DevtoolsPanel/components/Iconify.jsx @@ -0,0 +1,10 @@ +import {forwardRef} from "react"; +import { Icon } from "@iconify/react"; +import { Box } from "@mui/material"; + +// eslint-disable-next-line react/prop-types,react/display-name +const Iconify = forwardRef(({ icon, width = 20, sx, ...other }, ref) => ( + +)); + +export default Iconify; diff --git a/src/DevtoolsPanel/components/ModuleHeader/ModuleHeader.jsx b/src/DevtoolsPanel/components/ModuleHeader/ModuleHeader.jsx deleted file mode 100644 index 263367f..0000000 --- a/src/DevtoolsPanel/components/ModuleHeader/ModuleHeader.jsx +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import styles from './ModuleHeader.scss'; - -const ModuleHeader = ({ children, icon, title }) => { - return ( -
-

{icon} {title}

-
- {children} -
-
- ) -}; - -export default ModuleHeader; diff --git a/src/DevtoolsPanel/components/ModuleHeader/ModuleHeader.scss b/src/DevtoolsPanel/components/ModuleHeader/ModuleHeader.scss deleted file mode 100644 index cf4e600..0000000 --- a/src/DevtoolsPanel/components/ModuleHeader/ModuleHeader.scss +++ /dev/null @@ -1,32 +0,0 @@ -.moduleHeader { - padding: 9px; - border-bottom: 1px solid #333; - display: flex; - flex-wrap: nowrap; - align-items: center; - background: #1b1b1b; - color: #FFFFFF; - - h2 { - font-size: 23px; - width: 100%; - margin: 0; - display: flex; - align-items: center; - - svg { - margin-right: 10px; - } - } - - .actionButtons { - width: 600px; - display: flex; - align-items: center; - justify-content: flex-end; - - button { - margin-left: 10px; - } - } -} \ No newline at end of file diff --git a/src/DevtoolsPanel/components/ModuleHeader/index.js b/src/DevtoolsPanel/components/ModuleHeader/index.js deleted file mode 100644 index 985d0ac..0000000 --- a/src/DevtoolsPanel/components/ModuleHeader/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ModuleHeader'; diff --git a/src/DevtoolsPanel/components/RouteLink/RouteLink.jsx b/src/DevtoolsPanel/components/RouteLink/RouteLink.jsx deleted file mode 100644 index 36ffc2b..0000000 --- a/src/DevtoolsPanel/components/RouteLink/RouteLink.jsx +++ /dev/null @@ -1,30 +0,0 @@ -import React, { useCallback } from 'react'; -import { useEventrixState } from "eventrix"; - -const RouteLink = ({ children, to, component, className, activeClassName }) => { - const [currentRoute, setCurrentRoute] = useEventrixState('currentRoute'); - const isActive = currentRoute === to; - const redirect = useCallback((e) => { - e.preventDefault(); - e.stopPropagation(); - if (!isActive) { - setCurrentRoute(to) - } - }, [isActive, to, setCurrentRoute]); - - if (component) { - const LinkComponent = component; - return ( - - {children} - - ); - } - return ( - - {children} - - ); -}; - -export default RouteLink; diff --git a/src/DevtoolsPanel/components/RouteLink/index.js b/src/DevtoolsPanel/components/RouteLink/index.js deleted file mode 100644 index 2410460..0000000 --- a/src/DevtoolsPanel/components/RouteLink/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Link'; diff --git a/src/DevtoolsPanel/components/SearchBox/SearchBox.jsx b/src/DevtoolsPanel/components/SearchBox/SearchBox.jsx index f83f4c6..73cfe0b 100644 --- a/src/DevtoolsPanel/components/SearchBox/SearchBox.jsx +++ b/src/DevtoolsPanel/components/SearchBox/SearchBox.jsx @@ -1,50 +1,19 @@ -import React, {useCallback, useEffect, useRef, useState} from 'react'; +import React from 'react'; import SearchField from "./SearchField"; -import styles from './SearchBox.scss'; -import Button from "../Button"; -import classnames from "classnames"; +import {Stack} from "@mui/material"; +import Dropdown from "../Dropdown/Dropdown"; const SearchBox = ({ placeholder, filtersStateName, label, filters: FilterComponent }) => { - const [isFilterTooltipOpened, setFiltersTooltipOpened] = useState(false); - const filtersRef = useRef(); - - const toggleFiltersTooltip = useCallback(() => { - setFiltersTooltipOpened(!isFilterTooltipOpened); - }, [isFilterTooltipOpened, setFiltersTooltipOpened]); - - const clickOutsideListener = useCallback((e) => { - if(!filtersRef.current.contains(e.target)) { - setFiltersTooltipOpened(false); - } - }, [filtersRef, setFiltersTooltipOpened]); - - useEffect(() => { - window.addEventListener('click', clickOutsideListener); - return () => { - window.removeEventListener('click', clickOutsideListener); - } - }, [clickOutsideListener, filtersRef]); - return ( -
+ {FilterComponent ? -
- -
- -
-
+ + + : null } -
+ ) }; diff --git a/src/DevtoolsPanel/components/SearchBox/SearchBox.scss b/src/DevtoolsPanel/components/SearchBox/SearchBox.scss deleted file mode 100644 index f384b2f..0000000 --- a/src/DevtoolsPanel/components/SearchBox/SearchBox.scss +++ /dev/null @@ -1,52 +0,0 @@ -.SearchBox { - padding: 9px; - border-bottom: 1px solid #333; - display: flex; - flex-wrap: nowrap; - align-items: center; - justify-content: space-between; - - .filters { - position: relative; - margin-left: 10px; - } - - .filtersTooltip { - position: absolute; - top: calc(100% + 10px); - right: 0; - background: #ffffff; - padding: 10px; - border: 1px solid #dddddd; - border-radius: 4px; - width: 350px; - display: none; - - &:after { - position: absolute; - right: 21px; - top: -9px; - content: ' '; - width: 0; - height: 0; - border-left: 9px solid transparent; - border-right: 9px solid transparent; - border-bottom: 9px solid #ffffff; - } - &:before { - position: absolute; - right: 20px; - top: -10px; - content: ' '; - width: 0; - height: 0; - border-left: 10px solid transparent; - border-right: 10px solid transparent; - border-bottom: 10px solid #dddddd; - } - } - - .opened { - display: flex; - } -} \ No newline at end of file diff --git a/src/DevtoolsPanel/components/SearchBox/SearchField.jsx b/src/DevtoolsPanel/components/SearchBox/SearchField.jsx index 74b2185..480241b 100644 --- a/src/DevtoolsPanel/components/SearchBox/SearchField.jsx +++ b/src/DevtoolsPanel/components/SearchBox/SearchField.jsx @@ -1,5 +1,5 @@ import React, {useCallback} from 'react'; -import TextField from '@material-ui/core/TextField'; +import TextField from '@mui/material/TextField'; import {useEventrixState} from "eventrix"; const SearchField = ({ placeholder, filtersStateName, label = 'Search', filters: FilterComponent }) => { diff --git a/src/DevtoolsPanel/components/StatsBox.jsx b/src/DevtoolsPanel/components/StatsBox.jsx new file mode 100644 index 0000000..a77f1e9 --- /dev/null +++ b/src/DevtoolsPanel/components/StatsBox.jsx @@ -0,0 +1,47 @@ +import React, {useState} from "react"; +import {IconButton, Stack, styled, Typography} from "@mui/material"; +import {HideStatsIcon, ShowStatsIcon} from "./icons"; +import Divider from "@mui/material/Divider"; +import Paper from "@mui/material/Paper"; + +const StyledBoxWrapper = styled('div')(({ theme }) => ({ + position: "relative", + width: "50px", + height: "45px", +})); + +const StyledBox = styled(Paper)(({ theme, opened }) => ({ + position: "absolute", + top: 0, + right: 0, + width: opened ? + theme.breakpoints.between('xs', 'md') ? "calc(100vw - 80px)" : "calc(100vw - 230px)" : + "50px", + maxWidth: "450px", + height: opened ? "calc(100vh - 90px)" : "35px", + padding: 2, + zIndex: 2 +})); +const StatsBox = ({ children, title }) => { + const [isStatsBoxOpen, setIsStatsBoxOpen] = useState(false); + return ( + + + + + {isStatsBoxOpen && {title}} + setIsStatsBoxOpen(!isStatsBoxOpen)}> + {isStatsBoxOpen ? : } + + + {isStatsBoxOpen && <> + + {children} + } + + + + ) +} + +export default StatsBox; diff --git a/src/DevtoolsPanel/components/icons.jsx b/src/DevtoolsPanel/components/icons.jsx new file mode 100644 index 0000000..04e81a3 --- /dev/null +++ b/src/DevtoolsPanel/components/icons.jsx @@ -0,0 +1,16 @@ +import React from "react"; +import Iconify from "./Iconify"; + +export const StorageIcon = ({ width }) => ; +export const DateRangeIcon = ({ width }) => ; +export const HistoryIcon = ({ width }) => ; +export const ReceiverIcon = ({ width }) => ; +export const ListenerIcon = ({ width }) => ; +export const FiberManualRecordIcon = ({ width }) => ; +export const RefreshIcon = ({ width }) => ; +export const TimeIcon = ({ width }) => ; +export const EmitIcon = ({ width }) => ; +export const ShowStatsIcon = ({ width }) => ; +export const HideStatsIcon = ({ width }) => ; +export const ClearIcon = ({ width }) => ; +export const CloseIcon = ({ width }) => ; diff --git a/src/DevtoolsPanel/constants/routes.js b/src/DevtoolsPanel/constants/routes.js index 68f4ab2..0112a63 100644 --- a/src/DevtoolsPanel/constants/routes.js +++ b/src/DevtoolsPanel/constants/routes.js @@ -2,6 +2,6 @@ export const ROUTES = { CURRENT_STATE: 'currentState', STATE_HISTORY: 'stateHistory', EVENTS_HISTORY: 'eventsHistory', - RECEIVERS: 'receivers', - LISTENERS: 'listeners', -}; \ No newline at end of file + EMITTER: 'emitter', + ANALYZER: 'analyzer', +}; diff --git a/src/DevtoolsPanel/events.js b/src/DevtoolsPanel/events.js index 786547a..71be00e 100644 --- a/src/DevtoolsPanel/events.js +++ b/src/DevtoolsPanel/events.js @@ -1,8 +1,10 @@ export const EVENTS_HISTORY_FETCH = 'Events:history.fetch'; +export const EVENTS_HISTORY_RESET = 'Events:history.reset'; export const EVENTS_HISTORY_FETCH_SUCCESS = 'Events:history.fetch.success'; export const EVENTS_HISTORY_FETCH_FAILED = 'Events:history.fetch.failed'; export const STATE_HISTORY_FETCH = 'State:history.fetch'; +export const STATE_HISTORY_RESET = 'State:history.reset'; export const STATE_HISTORY_FETCH_SUCCESS = 'State:history.fetch.success'; export const STATE_HISTORY_FETCH_FAILED = 'State:history.fetch.failed'; @@ -23,4 +25,7 @@ export const STATE_LISTENERS_FETCH_SUCCESS = 'StateListeners:fetch.success'; export const STATE_LISTENERS_FETCH_FAILED = 'StateListeners:fetch.failed'; export const TURN_ON_AUTO_REFRESH_MODE = 'AutoRefreshMode:turnOn'; -export const TURN_OFF_AUTO_REFRESH_MODE = 'AutoRefreshMode:turnOff'; \ No newline at end of file +export const TURN_OFF_AUTO_REFRESH_MODE = 'AutoRefreshMode:turnOff'; + +export const RESET_EMITTER = 'RESET_EMITTER'; +export const EMITTER_EMIT = 'EMITTER_EMIT'; diff --git a/src/DevtoolsPanel/modules/CurrentState/CurrentState.jsx b/src/DevtoolsPanel/modules/CurrentState/CurrentState.jsx index 66928a5..8d77685 100644 --- a/src/DevtoolsPanel/modules/CurrentState/CurrentState.jsx +++ b/src/DevtoolsPanel/modules/CurrentState/CurrentState.jsx @@ -1,79 +1,22 @@ import React, {useCallback, useEffect} from 'react'; import { useEmit, useEventrixState } from 'eventrix'; -import RefreshIcon from '@material-ui/icons/Refresh'; -import StorageIcon from '@material-ui/icons/Storage'; -import ObjectInspector from "react-object-inspector"; -import {STATE_FETCH, STATE_LISTENERS_FETCH} from "../../events"; -import ModuleHeader from "../../components/ModuleHeader"; -import Button from '../../components/Button'; -import AutoRefreshModeButton from "../../components/AutoRefreshModeButton"; -import styles from './CurrentState.scss'; -import Tooltip from "@material-ui/core/Tooltip/Tooltip"; -import Chip from "@material-ui/core/Chip"; -import ListenerIcon from '@material-ui/icons/WifiTethering'; -import ReceiverIcon from '@material-ui/icons/SettingsInputAntenna'; -import Divider from "@material-ui/core/Divider"; +import { ObjectInspector } from "react-inspector"; +import {Stack} from "@mui/material"; + +import {STATE_FETCH} from "../../events"; const CurrentState = () => { const emit = useEmit(); const [currentState = []] = useEventrixState('currentState'); - const [listenersList = []] = useEventrixState('stateListeners'); const fetchState = useCallback(() => { emit(STATE_FETCH) }, [emit]); - const fetchStateListeners = useCallback(() => { emit(STATE_LISTENERS_FETCH) }, [emit]); - const fetchAll = useCallback(() => { - fetchState(); - fetchStateListeners(); - }, [fetchState, fetchStateListeners]); useEffect(() => { - fetchAll() - }, [fetchAll]); + fetchState() + }, [fetchState]); return ( -
- } title="Current state"> - - - -
-
- -
-
-

States that are listening

- -
- {listenersList.map((item)=> ( -
-
{item.stateName}
-
- - } - size="small" - label={item.receivers || 0} - variant="outlined" - /> - - - } - size="small" - label={item.listeners || 0} - variant="outlined" - /> - -
-
- ))} -
-
-
-
+ + + ) }; diff --git a/src/DevtoolsPanel/modules/CurrentState/CurrentState.scss b/src/DevtoolsPanel/modules/CurrentState/CurrentState.scss deleted file mode 100644 index 3465e71..0000000 --- a/src/DevtoolsPanel/modules/CurrentState/CurrentState.scss +++ /dev/null @@ -1,86 +0,0 @@ -.moduleContainer { - -} - -.moduleHeader { - padding: 10px; - border-bottom: 1px solid #333; - display: flex; - flex-wrap: nowrap; - align-items: center; - background: #1b1b1b; - color: #FFFFFF; - - h2 { - font-size: 23px; - width: 100%; - margin: 0; - display: flex; - align-items: center; - - svg { - margin-right: 10px; - } - } - - .actionButtons { - width: 200px; - } -} - -.moduleContent { - display: flex; - padding: 10px; - overflow: auto; - max-height: calc(100vh - 82px); -} - -.statePreview { - width: 50%; -} - -.stateListenersList { - width: 50%; - h4 { - margin-bottom: 15px; - margin-top: 10px; - font-size: 18px; - } -} - -.list { - width: 100%; - height: calc(100vh - 121px); - overflow: auto; -} - -.listItem { - padding: 10px; - border-bottom: 1px solid #c3c3c3; - display: flex; - align-items: center; - - &:hover { - background: #e1e1e1; - cursor: pointer; - } - - .name { - width: 100%; - font-size: 12px; - } - - .counters { - display: flex; - align-items: center; - justify-content: flex-end; - - & > div { - margin-left: 10px; - } - } -} - -.activeListItem { - background: #bcd5ff; -} \ No newline at end of file diff --git a/src/DevtoolsPanel/modules/Emitter/Emitter.jsx b/src/DevtoolsPanel/modules/Emitter/Emitter.jsx new file mode 100644 index 0000000..5d62a90 --- /dev/null +++ b/src/DevtoolsPanel/modules/Emitter/Emitter.jsx @@ -0,0 +1,31 @@ +import React, {useState} from 'react'; +import {useEmit, useEvent, useEventrixState} from 'eventrix'; +import {Button, Stack} from "@mui/material"; + +import TextField from "@mui/material/TextField"; +import TextareaField from "./TextareaField"; +import {EMITTER_EMIT, RESET_EMITTER} from "../../events"; + +const Emitter = () => { + const emit = useEmit(); + const [eventName, setEventName] = useEventrixState('emitter.eventName'); + const [eventPayload, setEventPayload] = useEventrixState('emitter.eventPayload'); + + useEvent(RESET_EMITTER, () => { + setEventName(''); + setEventPayload(''); + }); + return ( + + + setEventName(e.target.value)} value={eventName} label="Event name" /> + setEventPayload(e.target.value)} value={eventPayload} label="Event payload" /> + + + + + + ) +}; + +export default Emitter; diff --git a/src/DevtoolsPanel/modules/Emitter/TextareaField.jsx b/src/DevtoolsPanel/modules/Emitter/TextareaField.jsx new file mode 100644 index 0000000..3eed5e5 --- /dev/null +++ b/src/DevtoolsPanel/modules/Emitter/TextareaField.jsx @@ -0,0 +1,94 @@ +import React from 'react'; +import TextareaAutosize from '@mui/material/TextareaAutosize'; +import {Stack, styled} from '@mui/material'; + +const StyledTextarea = styled(TextareaAutosize)( + ({ theme, error }) => { + const hasError = error === 'true'; + return` + font-family: ${theme.typography.fontFamily}; + font-size: ${theme.typography.body1.fontSize}; + font-weight: ${theme.typography.fontWeightRegular}; + line-height: 1.5; + padding: ${theme.spacing(1.5)}; + border-radius: ${theme.shape.borderRadius}px; + color: ${theme.palette.mode === 'dark' ? theme.palette.grey[300] : theme.palette.grey[900]}; + background: transparent; + border: 1px solid ${ + theme.palette.mode === 'dark' ? + hasError ? theme.palette.error.main : theme.palette.grey[700] : + hasError ? theme.palette.error.main : theme.palette.grey[300] + }; + box-shadow: 0px 2px 2px ${theme.palette.mode === 'dark' ? theme.palette.grey[900] : theme.palette.grey[100]}; + + &:hover { + border-color: ${hasError ? theme.palette.error.main : theme.palette.grey[700]}; + } + + &:focus { + border-color: ${hasError ? theme.palette.error.main : theme.palette.primary.main}; + border-width: 2px; + } + + // firefox + &:focus-visible { + outline: 0; + } + `}, +); + +const StyledLabel = styled('label')( + ({ theme, error }) => { + const hasError = error === 'true'; + return` + width: fit-content; + font-family: ${theme.typography.fontFamily}; + font-size: ${theme.typography.body2.fontSize}; + font-weight: ${theme.typography.fontWeightRegular}; + line-height: 1.5; + padding: ${theme.spacing(0.5)}; + border-radius: ${theme.shape.borderRadius}px; + color: ${hasError ? theme.palette.error.main : theme.palette.text.secondary}; + margin-bottom: ${theme.spacing(-3)} !important; + margin-left: ${theme.spacing(1)} !important; + background: ${theme.palette.background.paper}; + z-index: 1; + // firefox + &:focus-visible { + outline: 0; + } + `}, +) + +const TextareaField = ({ + name, + required = false, + label, + placeholder = '', + type = "text", + defaultValue = "", + inputProps = {}, + onChange = () => {}, + value = '', + ...restProps +}) => { + return ( + + {!!label && + + {required ? '*' : ''}{label} + + } + + + ); +}; + +export default TextareaField; diff --git a/src/DevtoolsPanel/modules/Emitter/index.js b/src/DevtoolsPanel/modules/Emitter/index.js new file mode 100644 index 0000000..2b8b98e --- /dev/null +++ b/src/DevtoolsPanel/modules/Emitter/index.js @@ -0,0 +1 @@ +export { default } from './Emitter'; diff --git a/src/DevtoolsPanel/modules/EventsHistory/EventsHistory.jsx b/src/DevtoolsPanel/modules/EventsHistory/EventsHistory.jsx index 802c399..60a7cd5 100644 --- a/src/DevtoolsPanel/modules/EventsHistory/EventsHistory.jsx +++ b/src/DevtoolsPanel/modules/EventsHistory/EventsHistory.jsx @@ -1,44 +1,70 @@ -import React, { useCallback, useEffect } from 'react'; -import { useEmit } from 'eventrix'; -import RefreshIcon from '@material-ui/icons/Refresh'; -import DateRangeIcon from '@material-ui/icons/DateRange'; +import React, { useEffect } from 'react'; +import { useEventrixState} from 'eventrix'; -import { EVENTS_HISTORY_FETCH } from "../../events"; -import Button from "../../components/Button"; -import ModuleHeader from "../../components/ModuleHeader"; -import AutoRefreshModeButton from "../../components/AutoRefreshModeButton"; -import styles from './EventsHistory.scss'; import SearchBox from "../../components/SearchBox"; -import EventsHistoryList from "./EventsHistoryList"; -import EventsHistoryPreview from "./EventsHistoryPreview"; -import EventsStats from "./EventsStats"; import Filters from "./Filters"; +import { ListenerIcon, ReceiverIcon } from "../../components/icons"; +import {List, ListItem, ListItemButton, Stack} from "@mui/material"; +import ListItemText from "@mui/material/ListItemText"; +import Tooltip from "@mui/material/Tooltip"; +import Chip from "@mui/material/Chip"; -const EventsHistory = () => { - const emit = useEmit(); - const fetchHistory = useCallback(() => { emit(EVENTS_HISTORY_FETCH) }, [emit]); - useEffect(() => { fetchHistory() }, [fetchHistory]); +const EventsHistory = ({ fetchEventsHistory }) => { + const [eventsHistory = []] = useEventrixState('eventsHistory'); + const [eventsHistoryFilters] = useEventrixState('eventsHistoryFilters'); + const [selectedItem, setItem] = useEventrixState('eventsHistoryPreview'); + const list = eventsHistory.filter(item => { + let matched = true; + const { search, filters } = eventsHistoryFilters; + if (filters.withoutSetStateEvents) { + matched = item.name.indexOf('setState:') !== 0; + } + return item.name.toLowerCase().includes(search.toLowerCase()) && matched; + }); + useEffect(() => { + fetchEventsHistory() + }, [fetchEventsHistory]); return ( -
- } title="Events history"> - - - -
-
- - -
- - -
-
+ + + + + {list.map((item, index) => ( + setItem(item)} + disablePadding + > + + + + + } + size="small" + label={item.receiversCount || 0} + variant="outlined" + /> + + + } + size="small" + label={item.listenersCount || 0} + variant="outlined" + /> + + + + + ))} + + + ) }; diff --git a/src/DevtoolsPanel/modules/EventsHistory/EventsHistory.scss b/src/DevtoolsPanel/modules/EventsHistory/EventsHistory.scss deleted file mode 100644 index d0ec3b9..0000000 --- a/src/DevtoolsPanel/modules/EventsHistory/EventsHistory.scss +++ /dev/null @@ -1,85 +0,0 @@ -.moduleContainer { - -} - -.moduleContent { - padding: 10px; - display: flex; -} - -.list { - min-width: 500px; -} - -.listContent { - min-width: 400px; - height: calc(100vh - 150px); - overflow: auto; -} - - -.preview { - width: 100%; - padding: 0 20px; - overflow: auto; -} - -.listItem { - padding: 10px; - border-bottom: 1px solid #c3c3c3; - display: flex; - align-items: center; - - &:hover { - background: #e1e1e1; - cursor: pointer; - } - - .name { - width: 100%; - font-size: 12px; - } - - .counters { - display: flex; - align-items: center; - justify-content: flex-end; - - & > div { - margin-left: 10px; - } - } -} - -.stateStats { - min-width: 500px; - - h4 { - margin-bottom: 15px; - margin-top: 10px; - font-size: 18px; - } -} - -.statsList { - height: calc(100vh - 126px); -} - -.activeListItem { - background: #bcd5ff; -} - -.previewCounters { - display: flex; - margin-bottom: 10px; - - & > div { - margin-right: 10px; - } -} - -.dataPreview { - overflow: auto; - max-height: calc(100vh - 215px); - padding: 10px; -} \ No newline at end of file diff --git a/src/DevtoolsPanel/modules/EventsHistory/EventsHistoryList.jsx b/src/DevtoolsPanel/modules/EventsHistory/EventsHistoryList.jsx deleted file mode 100644 index 6acbdcf..0000000 --- a/src/DevtoolsPanel/modules/EventsHistory/EventsHistoryList.jsx +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react'; -import { useEventrixState } from 'eventrix'; -import classnames from 'classnames'; -import ReceiverIcon from '@material-ui/icons/SettingsInputAntenna'; -import ListenerIcon from '@material-ui/icons/WifiTethering'; -import Tooltip from '@material-ui/core/Tooltip'; -import Chip from '@material-ui/core/Chip'; - -import styles from './EventsHistory.scss'; - -const EventsHistoryList = ({}) => { - const [eventsHistory = []] = useEventrixState('eventsHistory'); - const [eventsHistoryFilters] = useEventrixState('eventsHistoryFilters'); - const [currentEvent, setCurrentEvent] = useEventrixState('eventsHistoryPreview'); - const list = eventsHistory.filter(item => { - let matched = true; - const { search, filters } = eventsHistoryFilters; - if (filters.withoutSetStateEvents) { - matched = item.name.indexOf('setState:') !== 0; - } - return item.name.toLowerCase().includes(search.toLowerCase()) && matched; - }); - return ( -
- {list.map((item, index)=> ( -
setCurrentEvent(item)} - className={classnames({ - [styles.listItem]: true, - [styles.activeListItem]: currentEvent === item, - })} - > -
{item.name}
-
- - } - size="small" - label={item.receiversCount || 0} - variant="outlined" - /> - - - } - size="small" - label={item.listenersCount || 0} - variant="outlined" - /> - -
-
- ))} -
- ) -}; - -export default EventsHistoryList; diff --git a/src/DevtoolsPanel/modules/EventsHistory/EventsHistoryPreview.jsx b/src/DevtoolsPanel/modules/EventsHistory/EventsHistoryPreview.jsx index 9c1227e..cdfa85b 100644 --- a/src/DevtoolsPanel/modules/EventsHistory/EventsHistoryPreview.jsx +++ b/src/DevtoolsPanel/modules/EventsHistory/EventsHistoryPreview.jsx @@ -1,46 +1,56 @@ import React from 'react'; -import { useEventrixState } from 'eventrix'; import moment from 'moment'; -import ObjectInspector from "react-object-inspector"; -import ReceiverIcon from '@material-ui/icons/SettingsInputAntenna'; -import ListenerIcon from '@material-ui/icons/WifiTethering'; -import TimeIcon from '@material-ui/icons/Schedule'; -import Chip from '@material-ui/core/Chip'; -import Divider from '@material-ui/core/Divider'; +import Chip from '@mui/material/Chip'; +import Divider from '@mui/material/Divider'; +import { useEventrixState } from 'eventrix'; +import { ObjectInspector } from "react-inspector"; +import {IconButton, Paper, Stack, Typography} from "@mui/material"; -import styles from './EventsHistory.scss'; +import {CloseIcon, ListenerIcon, ReceiverIcon, TimeIcon} from "../../components/icons"; +import {contentStyles, paperStyles} from "./EventsHistoryPreview.styles"; const EventsHistoryPreview = () => { - const [currentEvent] = useEventrixState('eventsHistoryPreview'); + const [currentEvent, setCurrentEvent] = useEventrixState('eventsHistoryPreview'); + if (!currentEvent) { + return null; + } return ( -
- {currentEvent && -
-

{currentEvent.name}

-
- } - label={`Receivers: ${currentEvent.receiversCount || 0}`} - variant="outlined" - /> - } - label={`Listeners: ${currentEvent.listenersCount || 0}`} - variant="outlined" - /> - } - label={`Time: ${moment(currentEvent.timestamp || 0).format('HH:mm:ss')}`} - variant="outlined" - /> -
+ + + + + setCurrentEvent(null)}> + + + {currentEvent.name} + + + } + label={currentEvent.receiversCount || 0} + size="small" + variant="outlined" + /> + } + label={currentEvent.listenersCount || 0} + size="small" + variant="outlined" + /> + } + label={moment(currentEvent.timestamp || 0).format('HH:mm:ss')} + size="small" + variant="outlined" + /> + + -
+ -
-
- } -
+ + + ) }; diff --git a/src/DevtoolsPanel/modules/EventsHistory/EventsHistoryPreview.styles.js b/src/DevtoolsPanel/modules/EventsHistory/EventsHistoryPreview.styles.js new file mode 100644 index 0000000..f95aab9 --- /dev/null +++ b/src/DevtoolsPanel/modules/EventsHistory/EventsHistoryPreview.styles.js @@ -0,0 +1,14 @@ +export const paperStyles = (theme) => ({ + height: "calc(100vh - 126px)", + position: "absolute", + top: 0, + right: 0, + width: theme.breakpoints.between('xs', 'md') ? "calc(100vw - 80px)" : "calc(100vw - 230px)", + maxWidth: "600px", + zIndex: 1 +}); + +export const contentStyles = (theme) => ({ + height: "calc(100vh - 210px)", + overflow: "auto", +}); diff --git a/src/DevtoolsPanel/modules/EventsHistory/EventsStats.jsx b/src/DevtoolsPanel/modules/EventsHistory/EventsStats.jsx index a162604..f1c1e4a 100644 --- a/src/DevtoolsPanel/modules/EventsHistory/EventsStats.jsx +++ b/src/DevtoolsPanel/modules/EventsHistory/EventsStats.jsx @@ -1,42 +1,44 @@ import React from 'react'; import { useEventrixState } from 'eventrix'; -import classnames from 'classnames'; -import SettingsRemoteIcon from '@material-ui/icons/SettingsRemote'; -import Tooltip from '@material-ui/core/Tooltip'; -import Chip from '@material-ui/core/Chip'; -import Divider from '@material-ui/core/Divider'; +import Tooltip from '@mui/material/Tooltip'; +import Chip from '@mui/material/Chip'; import {getEventsEmitStats} from "./helpers"; -import styles from './EventsHistory.scss'; +import {EmitIcon} from "../../components/icons"; +import {Stack, Typography} from "@mui/material"; + +const wrapperStyles = { + width: "100%", + height: "calc(100vh - 145px)", + overflowX: "auto" +} const EventsStats = () => { const [eventsHistory = []] = useEventrixState('eventsHistory'); return ( -
-

Emitted events stats

- -
- {getEventsEmitStats(eventsHistory).map((item)=> ( -
-
{item.name}
-
- - } - size="small" - label={item.count || 0} - variant="outlined" - /> - -
-
- ))} -
-
- ) + + {getEventsEmitStats(eventsHistory).map((item) => ( + + {item.name} + + + } + size="small" + label={item.count || 0} + variant="outlined" + /> + + + + ))} + + ); }; export default EventsStats; diff --git a/src/DevtoolsPanel/modules/EventsHistory/Filters.jsx b/src/DevtoolsPanel/modules/EventsHistory/Filters.jsx index fc5ef3f..0d8637e 100644 --- a/src/DevtoolsPanel/modules/EventsHistory/Filters.jsx +++ b/src/DevtoolsPanel/modules/EventsHistory/Filters.jsx @@ -1,8 +1,9 @@ import React, { useCallback } from 'react'; import { useEventrixState } from 'eventrix'; -import FormControlLabel from '@material-ui/core/FormControlLabel'; -import Checkbox from '@material-ui/core/Checkbox'; -import Tooltip from '@material-ui/core/Tooltip'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import Checkbox from '@mui/material/Checkbox'; +import Tooltip from '@mui/material/Tooltip'; +import {Stack} from "@mui/material"; const Filters = () => { const [filters = {}, setFilters] = useEventrixState('eventsHistoryFilters.filters'); @@ -11,7 +12,7 @@ const Filters = () => { setFilters({ ...filters, withoutSetStateEvents: !withoutSetStateEvents }); }, [filters.withoutSetStateEvents, setFilters]); return ( -
+ { label="without set state events" /> -
+ ) }; diff --git a/src/DevtoolsPanel/modules/Listeners/Listeners.jsx b/src/DevtoolsPanel/modules/Listeners/Listeners.jsx deleted file mode 100644 index dbec05b..0000000 --- a/src/DevtoolsPanel/modules/Listeners/Listeners.jsx +++ /dev/null @@ -1,73 +0,0 @@ -import React, {useCallback, useEffect, useState} from 'react'; -import { useEmit, useEventrixState } from 'eventrix'; -import classnames from 'classnames'; -import RefreshIcon from '@material-ui/icons/Refresh'; -import ListenerIcon from '@material-ui/icons/WifiTethering'; -import Tooltip from '@material-ui/core/Tooltip'; -import Chip from '@material-ui/core/Chip'; - -import { LISTENERS_FETCH } from "../../events"; -import Button from "../../components/Button"; -import ModuleHeader from "../../components/ModuleHeader"; -import AutoRefreshModeButton from "../../components/AutoRefreshModeButton"; -import styles from './Listeners.scss'; - -const Listeners = () => { - const emit = useEmit(); - const [listenersList = []] = useEventrixState('listeners'); - const [currentState, setCurrentState] = useState(); - const fetchListeners = useCallback(() => { emit(LISTENERS_FETCH) }, [emit]); - useEffect(() => { fetchListeners() }, [fetchListeners]); - return ( -
- } title="Listeners"> - - - -
-
- {listenersList.map((item, index)=> ( -
setCurrentState(item)} - className={classnames({ - [styles.listItem]: true, - [styles.activeListItem]: currentState === item, - })} - > -
{item.eventName}
-
- - } - size="small" - label={item.count || 0} - variant="outlined" - /> - -
-
- ))} -
-
- {currentState && -
-

{currentState.eventName}

-
- } - label={`Listeners: ${currentState.count || 0}`} - variant="outlined" - /> -
-
- } -
-
-
- ) -}; - -export default Listeners; diff --git a/src/DevtoolsPanel/modules/Listeners/Listeners.scss b/src/DevtoolsPanel/modules/Listeners/Listeners.scss deleted file mode 100644 index 2ebecb4..0000000 --- a/src/DevtoolsPanel/modules/Listeners/Listeners.scss +++ /dev/null @@ -1,66 +0,0 @@ -.moduleContainer { - -} - -.moduleContent { - padding: 10px; - display: flex; -} - -.preview { - width: 100%; - padding: 0 20px; - overflow: auto; -} - -.list { - width: 600px; - height: calc(100vh - 80px); - overflow: auto; -} - -.listItem { - padding: 10px; - border-bottom: 1px solid #c3c3c3; - display: flex; - align-items: center; - - &:hover { - background: #e1e1e1; - cursor: pointer; - } - - .name { - width: 100%; - font-size: 12px; - } - - .counters { - display: flex; - align-items: center; - justify-content: flex-end; - - & > div { - margin-left: 10px; - } - } -} - -.activeListItem { - background: #bcd5ff; -} - -.previewCounters { - display: flex; - margin-bottom: 10px; - - & > div { - margin-right: 10px; - } -} - -.dataPreview { - overflow: auto; - max-height: calc(100vh - 215px); - padding: 10px; -} diff --git a/src/DevtoolsPanel/modules/Listeners/index.js b/src/DevtoolsPanel/modules/Listeners/index.js deleted file mode 100644 index fa03eef..0000000 --- a/src/DevtoolsPanel/modules/Listeners/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Listeners'; diff --git a/src/DevtoolsPanel/modules/Menu/Menu.jsx b/src/DevtoolsPanel/modules/Menu/Menu.jsx new file mode 100644 index 0000000..a9538e2 --- /dev/null +++ b/src/DevtoolsPanel/modules/Menu/Menu.jsx @@ -0,0 +1,70 @@ +import * as React from 'react'; +import MenuList from '@mui/material/MenuList'; +import MenuItem from '@mui/material/MenuItem'; +import ListItemText from '@mui/material/ListItemText'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import { + DateRangeIcon, EmitIcon, + HistoryIcon, + ListenerIcon, + ReceiverIcon, + StorageIcon +} from "../../components/icons"; +import {ROUTES} from "../../constants/routes"; +import {useEventrixState} from "eventrix"; +import Tooltip from "@mui/material/Tooltip"; +import {Stack, useMediaQuery, useTheme} from "@mui/material"; +import {itemTextStyles, logoStyles, navbarStyles} from "./Menu.styles"; + +const routesList = [ + { + path: ROUTES.CURRENT_STATE, + label: 'Current State', + icon: + }, + { + path: ROUTES.STATE_HISTORY, + label: 'State History', + icon: + }, + { + path: ROUTES.EVENTS_HISTORY, + label: 'Events History', + icon: + }, + { + path: ROUTES.EMITTER, + label: 'Emitter', + icon: + } +] + + + +const Menu = () => { + const [currentRoute, setCurrentRoute] = useEventrixState('currentRoute'); + const theme = useTheme(); + const isSmallScreen = useMediaQuery(theme.breakpoints.between('xs', 'md')); + + return ( + + + Eventrix devtools + + + {routesList.map(({path, label, icon}) => ( + setCurrentRoute(path)} selected={currentRoute === path}> + + + {icon} + + + {label} + + ))} + + + ); +} + +export default Menu; diff --git a/src/DevtoolsPanel/modules/Menu/Menu.styles.js b/src/DevtoolsPanel/modules/Menu/Menu.styles.js new file mode 100644 index 0000000..cc37c66 --- /dev/null +++ b/src/DevtoolsPanel/modules/Menu/Menu.styles.js @@ -0,0 +1,36 @@ +export const itemTextStyles = { + display: { + xs: 'none', + sm: 'none', + md: 'flex', + } +} + +export const navbarStyles = { + width: { + xs: '50px', + sm: '50px', + md: '230px', + }, +} + +export const logoStyles = { + width: { + xs: '50px', + sm: '50px', + md: '130px', + }, + img: { + width: { + xs: '32px', + sm: '32px', + md: '130px', + } + }, + paddingX: { + xs: 1.5, + sm: 1.5, + md: 2, + }, + paddingY: 1 +} diff --git a/src/DevtoolsPanel/modules/Menu/index.js b/src/DevtoolsPanel/modules/Menu/index.js new file mode 100644 index 0000000..a6de24c --- /dev/null +++ b/src/DevtoolsPanel/modules/Menu/index.js @@ -0,0 +1 @@ +export { default } from './Menu'; diff --git a/src/DevtoolsPanel/modules/Receivers/Receivers.jsx b/src/DevtoolsPanel/modules/Receivers/Receivers.jsx deleted file mode 100644 index 216e322..0000000 --- a/src/DevtoolsPanel/modules/Receivers/Receivers.jsx +++ /dev/null @@ -1,73 +0,0 @@ -import React, {useCallback, useEffect, useState} from 'react'; -import { useEmit, useEventrixState } from 'eventrix'; -import classnames from 'classnames'; -import RefreshIcon from '@material-ui/icons/Refresh'; -import ReceiverIcon from '@material-ui/icons/SettingsInputAntenna'; -import Tooltip from '@material-ui/core/Tooltip'; -import Chip from '@material-ui/core/Chip'; - -import { RECEIVERS_FETCH } from "../../events"; -import Button from "../../components/Button"; -import ModuleHeader from "../../components/ModuleHeader"; -import AutoRefreshModeButton from "../../components/AutoRefreshModeButton"; -import styles from './Receivers.scss'; - -const Receivers = () => { - const emit = useEmit(); - const [receiversList = []] = useEventrixState('receivers'); - const [currentState, setCurrentState] = useState(); - const fetchReceivers = useCallback(() => { emit(RECEIVERS_FETCH) }, [emit]); - useEffect(() => { fetchReceivers() }, [fetchReceivers]); - return ( -
- } title="Receivers"> - - - -
-
- {receiversList.map((item, index)=> ( -
setCurrentState(item)} - className={classnames({ - [styles.listItem]: true, - [styles.activeListItem]: currentState === item, - })} - > -
{item.eventName}
-
- - } - size="small" - label={item.count || 0} - variant="outlined" - /> - -
-
- ))} -
-
- {currentState && -
-

{currentState.eventName}

-
- } - label={`Receivers: ${currentState.count || 0}`} - variant="outlined" - /> -
-
- } -
-
-
- ) -}; - -export default Receivers; diff --git a/src/DevtoolsPanel/modules/Receivers/Receivers.scss b/src/DevtoolsPanel/modules/Receivers/Receivers.scss deleted file mode 100644 index bf51792..0000000 --- a/src/DevtoolsPanel/modules/Receivers/Receivers.scss +++ /dev/null @@ -1,66 +0,0 @@ -.moduleContainer { - -} - -.moduleContent { - padding: 10px; - display: flex; -} - -.list { - width: 600px; - height: calc(100vh - 80px); - overflow: auto; -} - -.preview { - width: 100%; - padding: 0 20px; - overflow: auto; -} - -.listItem { - padding: 10px; - border-bottom: 1px solid #c3c3c3; - display: flex; - align-items: center; - - &:hover { - background: #e1e1e1; - cursor: pointer; - } - - .name { - width: 100%; - font-size: 12px; - } - - .counters { - display: flex; - align-items: center; - justify-content: flex-end; - - & > div { - margin-left: 10px; - } - } -} - -.activeListItem { - background: #bcd5ff; -} - -.previewCounters { - display: flex; - margin-bottom: 10px; - - & > div { - margin-right: 10px; - } -} - -.dataPreview { - overflow: auto; - max-height: calc(100vh - 215px); - padding: 10px; -} diff --git a/src/DevtoolsPanel/modules/Receivers/index.js b/src/DevtoolsPanel/modules/Receivers/index.js deleted file mode 100644 index d4b5e18..0000000 --- a/src/DevtoolsPanel/modules/Receivers/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Receivers'; diff --git a/src/DevtoolsPanel/modules/StateHistory/StateHistory.jsx b/src/DevtoolsPanel/modules/StateHistory/StateHistory.jsx index 1184ea5..40af9ec 100644 --- a/src/DevtoolsPanel/modules/StateHistory/StateHistory.jsx +++ b/src/DevtoolsPanel/modules/StateHistory/StateHistory.jsx @@ -1,39 +1,60 @@ -import React, {useCallback, useEffect} from 'react'; -import { useEmit } from 'eventrix'; -import HistoryIcon from '@material-ui/icons/History'; -import RefreshIcon from '@material-ui/icons/Refresh'; - -import {STATE_HISTORY_FETCH} from "../../events"; -import Button from "../../components/Button"; -import ModuleHeader from "../../components/ModuleHeader"; -import AutoRefreshModeButton from "../../components/AutoRefreshModeButton"; -import styles from './StateHistory.scss'; +import React, {useEffect} from 'react'; import SearchBox from "../../components/SearchBox"; -import StateStats from "./StateStats"; -import StateHistoryPreview from "./StateHistoryPreview"; -import StateHistoryList from "./StateHistoryList"; +import {List, ListItem, ListItemButton, Stack} from "@mui/material"; +import {useEventrixState} from "eventrix"; +import Tooltip from "@mui/material/Tooltip"; +import Chip from "@mui/material/Chip"; +import {ListenerIcon, ReceiverIcon} from "../../components/icons"; +import ListItemText from "@mui/material/ListItemText"; -const StateHistory = () => { - const emit = useEmit(); - const fetchHistory = useCallback(() => { emit(STATE_HISTORY_FETCH) }, [emit]); - useEffect(() => { fetchHistory() }, [fetchHistory]); +const StateHistory = ({ fetchStateHistory }) => { + const [stateHistory = []] = useEventrixState('stateHistory'); + const [stateHistoryFilters] = useEventrixState('stateHistoryFilters'); + const [selectedItem, setItem] = useEventrixState('stateHistoryPreview'); + const list = stateHistory.filter((item) => { + const { search } = stateHistoryFilters; + return item.path.toLowerCase().includes(search.toLowerCase()); + }); + useEffect(() => { + fetchStateHistory(); + }, [fetchStateHistory]); return ( -
- } title="State history"> - - - -
-
- - -
- - -
-
+ + + + + {list.map((item, index) => ( + setItem(item)} + disablePadding + > + + + + + } + size="small" + label={item.receiversCount || 0} + variant="outlined" + /> + + + } + size="small" + label={item.listenersCount || 0} + variant="outlined" + /> + + + + + ))} + + + ) }; diff --git a/src/DevtoolsPanel/modules/StateHistory/StateHistory.scss b/src/DevtoolsPanel/modules/StateHistory/StateHistory.scss deleted file mode 100644 index 9e35d19..0000000 --- a/src/DevtoolsPanel/modules/StateHistory/StateHistory.scss +++ /dev/null @@ -1,84 +0,0 @@ -.moduleContainer { - -} - -.moduleContent { - padding: 10px; - display: flex; -} - -.list { - min-width: 400px; -} - -.listContent { - min-width: 400px; - height: calc(100vh - 150px); - overflow: auto; -} - -.preview { - width: 100%; - padding: 0 20px; - overflow: auto; -} - -.listItem { - padding: 10px; - border-bottom: 1px solid #c3c3c3; - display: flex; - align-items: center; - - &:hover { - background: #e1e1e1; - cursor: pointer; - } - - .name { - width: 100%; - font-size: 12px; - } - - .counters { - display: flex; - align-items: center; - justify-content: flex-end; - - & > div { - margin-left: 10px; - } - } -} - -.stateStats { - min-width: 400px; - - h4 { - margin-bottom: 15px; - margin-top: 10px; - font-size: 18px; - } -} - -.statsList { - height: calc(100vh - 126px); -} - -.activeListItem { - background: #bcd5ff; -} - -.previewCounters { - display: flex; - margin-bottom: 10px; - - & > div { - margin-right: 10px; - } -} - -.dataPreview { - overflow: auto; - max-height: calc(100vh - 215px); - padding: 10px; -} diff --git a/src/DevtoolsPanel/modules/StateHistory/StateHistoryList.jsx b/src/DevtoolsPanel/modules/StateHistory/StateHistoryList.jsx deleted file mode 100644 index 1d73f16..0000000 --- a/src/DevtoolsPanel/modules/StateHistory/StateHistoryList.jsx +++ /dev/null @@ -1,55 +0,0 @@ -import React from 'react'; -import { useEventrixState } from 'eventrix'; -import classnames from 'classnames'; -import ReceiverIcon from '@material-ui/icons/SettingsInputAntenna'; -import ListenerIcon from '@material-ui/icons/WifiTethering'; -import Tooltip from '@material-ui/core/Tooltip'; -import Chip from '@material-ui/core/Chip'; - -import styles from './StateHistory.scss'; - -const StateHistoryList = ({}) => { - const [stateHistory = []] = useEventrixState('stateHistory'); - const [stateHistoryFilters] = useEventrixState('stateHistoryFilters'); - const [currentState, setCurrentState] = useEventrixState('stateHistoryPreview'); - const list = stateHistory.filter((item) => { - const { search } = stateHistoryFilters; - return item.path.toLowerCase().includes(search.toLowerCase()); - }); - return ( -
- {list.map((item, index)=> ( -
setCurrentState(item)} - className={classnames({ - [styles.listItem]: true, - [styles.activeListItem]: currentState === item, - })} - > -
{item.path}
-
- - } - size="small" - label={item.receiversCount || 0} - variant="outlined" - /> - - - } - size="small" - label={item.listenersCount || 0} - variant="outlined" - /> - -
-
- ))} -
- ) -}; - -export default StateHistoryList; diff --git a/src/DevtoolsPanel/modules/StateHistory/StateHistoryPreview.jsx b/src/DevtoolsPanel/modules/StateHistory/StateHistoryPreview.jsx index 4ac6aae..fb54e5b 100644 --- a/src/DevtoolsPanel/modules/StateHistory/StateHistoryPreview.jsx +++ b/src/DevtoolsPanel/modules/StateHistory/StateHistoryPreview.jsx @@ -1,46 +1,56 @@ import React from 'react'; -import { useEventrixState } from 'eventrix'; import moment from 'moment'; -import ObjectInspector from "react-object-inspector"; -import ReceiverIcon from '@material-ui/icons/SettingsInputAntenna'; -import ListenerIcon from '@material-ui/icons/WifiTethering'; -import TimeIcon from '@material-ui/icons/Schedule'; -import Chip from '@material-ui/core/Chip'; -import Divider from '@material-ui/core/Divider'; +import Chip from '@mui/material/Chip'; +import Divider from '@mui/material/Divider'; +import { useEventrixState } from 'eventrix'; +import { ObjectInspector } from "react-inspector"; +import {Stack, Typography, Paper, IconButton} from "@mui/material"; -import styles from './StateHistory.scss'; +import {contentStyles, paperStyles} from "./StateHistoryPreview.styles"; +import {CloseIcon, ListenerIcon, ReceiverIcon, TimeIcon} from "../../components/icons"; const StateHistoryPreview = () => { - const [currentState] = useEventrixState('stateHistoryPreview'); + const [currentState, setCurrentState] = useEventrixState('stateHistoryPreview'); + if (!currentState) { + return null; + } return ( -
- {currentState && -
-

{currentState.path}

-
- } - label={`Receivers: ${currentState.receiversCount || 0}`} - variant="outlined" - /> - } - label={`Listeners: ${currentState.listenersCount || 0}`} - variant="outlined" - /> - } - label={`Time: ${moment(currentState.timestamp || 0).format('HH:mm:ss')}`} - variant="outlined" - /> -
+ + + + + setCurrentState(null)}> + + + {currentState.path} + + + } + label={currentState.receiversCount || 0} + size="small" + variant="outlined" + /> + } + label={currentState.listenersCount || 0} + size="small" + variant="outlined" + /> + } + label={moment(currentState.timestamp || 0).format('HH:mm:ss')} + size="small" + variant="outlined" + /> + + -
+ -
-
- } -
+ + + ) }; diff --git a/src/DevtoolsPanel/modules/StateHistory/StateHistoryPreview.styles.js b/src/DevtoolsPanel/modules/StateHistory/StateHistoryPreview.styles.js new file mode 100644 index 0000000..f95aab9 --- /dev/null +++ b/src/DevtoolsPanel/modules/StateHistory/StateHistoryPreview.styles.js @@ -0,0 +1,14 @@ +export const paperStyles = (theme) => ({ + height: "calc(100vh - 126px)", + position: "absolute", + top: 0, + right: 0, + width: theme.breakpoints.between('xs', 'md') ? "calc(100vw - 80px)" : "calc(100vw - 230px)", + maxWidth: "600px", + zIndex: 1 +}); + +export const contentStyles = (theme) => ({ + height: "calc(100vh - 210px)", + overflow: "auto", +}); diff --git a/src/DevtoolsPanel/modules/StateHistory/StateStats.jsx b/src/DevtoolsPanel/modules/StateHistory/StateStats.jsx index c26df69..67e530e 100644 --- a/src/DevtoolsPanel/modules/StateHistory/StateStats.jsx +++ b/src/DevtoolsPanel/modules/StateHistory/StateStats.jsx @@ -1,42 +1,44 @@ import React from 'react'; +import Chip from '@mui/material/Chip'; import { useEventrixState } from 'eventrix'; -import classnames from 'classnames'; -import RefreshIcon from '@material-ui/icons/Refresh'; -import Tooltip from '@material-ui/core/Tooltip'; -import Chip from '@material-ui/core/Chip'; -import Divider from '@material-ui/core/Divider'; +import Tooltip from '@mui/material/Tooltip'; +import {Stack, Typography} from "@mui/material"; -import styles from './StateHistory.scss'; import { getStateUpdateStats } from "./helpers"; +import {RefreshIcon} from "../../components/icons"; + +const wrapperStyles = { + width: "100%", + height: "calc(100vh - 145px)", + overflowX: "auto" +} const StateStats = () => { const [stateHistory = []] = useEventrixState('stateHistory'); return ( -
-

States update stats

- -
- {getStateUpdateStats(stateHistory).map((item)=> ( -
-
{item.stateName}
-
- - } - size="small" - label={item.count || 0} - variant="outlined" - /> - -
-
- ))} -
-
- ) + + {getStateUpdateStats(stateHistory).map((item)=> ( + + {item.stateName} + + + } + size="small" + label={item.count || 0} + variant="outlined" + /> + + + + ))} + + ); }; export default StateStats; diff --git a/src/DevtoolsPanel/modules/StateListenersStats/StateListenersStats.jsx b/src/DevtoolsPanel/modules/StateListenersStats/StateListenersStats.jsx new file mode 100644 index 0000000..75a0fb0 --- /dev/null +++ b/src/DevtoolsPanel/modules/StateListenersStats/StateListenersStats.jsx @@ -0,0 +1,59 @@ +import React, {useCallback, useEffect} from 'react'; +import { useEmit, useEventrixState } from 'eventrix'; +import Tooltip from "@mui/material/Tooltip/Tooltip"; +import {Stack, Typography} from "@mui/material"; +import Chip from "@mui/material/Chip"; +import {ReceiverIcon} from '../../components/icons'; +import { ListenerIcon } from '../../components/icons'; +import {STATE_LISTENERS_FETCH} from "../../events"; + +const wrapperStyles = { + width: "100%", + height: "calc(100vh - 145px)", + overflowX: "auto" +} + +const StateListenersStats = () => { + const emit = useEmit(); + const [listenersList = []] = useEventrixState('stateListeners'); + const fetchStateListeners = useCallback(() => { emit(STATE_LISTENERS_FETCH) }, [emit]); + + useEffect(() => { + fetchStateListeners() + }, [fetchStateListeners]); + + return ( + + {listenersList.map((item)=> ( + + {item.stateName} + + + } + size="small" + label={item.receivers || 0} + variant="outlined" + /> + + + } + size="small" + label={item.listeners || 0} + variant="outlined" + /> + + + + ))} + + ) +}; + +export default StateListenersStats; diff --git a/src/DevtoolsPanel/modules/StateListenersStats/index.js b/src/DevtoolsPanel/modules/StateListenersStats/index.js new file mode 100644 index 0000000..aed663a --- /dev/null +++ b/src/DevtoolsPanel/modules/StateListenersStats/index.js @@ -0,0 +1 @@ +export { default } from './StateListenersStats'; diff --git a/src/DevtoolsPanel/services/debugger.js b/src/DevtoolsPanel/services/debugger.js index 406fd23..a27f36a 100644 --- a/src/DevtoolsPanel/services/debugger.js +++ b/src/DevtoolsPanel/services/debugger.js @@ -1,21 +1,35 @@ -import { useEventrix, fetchToState, receiver } from 'eventrix'; +import {EventsReceiver, fetchToStateReceiver} from 'eventrix'; import { - EVENTS_HISTORY_FETCH, + EMITTER_EMIT, + EVENTS_HISTORY_FETCH, EVENTS_HISTORY_RESET, LISTENERS_FETCH, RECEIVERS_FETCH, STATE_FETCH, - STATE_HISTORY_FETCH, STATE_LISTENERS_FETCH, + STATE_HISTORY_FETCH, STATE_HISTORY_RESET, STATE_LISTENERS_FETCH, TURN_OFF_AUTO_REFRESH_MODE, TURN_ON_AUTO_REFRESH_MODE } from '../events'; -import { WINDOW_EVENTRIX_DEBUGGER_NAME } from '../constants'; -import eventsHistory from "../../mockedData/eventsHistory"; -// import receiversCounts from "../../mockedData/receiversCount"; -// import listenersCount from "../../mockedData/listenersCount"; +import {WINDOW_EVENTRIX_DEBUGGER_NAME} from '../constants'; -@useEventrix class DebuggerService { - constructor() { + constructor({ eventrix }) { + this.eventrix = eventrix; + this.receivers = [ + new EventsReceiver(TURN_ON_AUTO_REFRESH_MODE, this.turnOnAutoRefreshMode), + new EventsReceiver(TURN_OFF_AUTO_REFRESH_MODE, this.turnOffAutoRefreshMode), + new EventsReceiver(EMITTER_EMIT, this.emitEvent), + fetchToStateReceiver(EVENTS_HISTORY_FETCH, 'eventsHistory', this.getEventsHistory), + fetchToStateReceiver(EVENTS_HISTORY_RESET, 'eventsHistory', this.resetEventsHistory), + fetchToStateReceiver(STATE_HISTORY_FETCH, 'stateHistory', this.getStateHistory), + fetchToStateReceiver(STATE_HISTORY_RESET, 'stateHistory', this.resetStateHistory), + fetchToStateReceiver(STATE_FETCH, 'currentState', this.getCurrentState), + fetchToStateReceiver(RECEIVERS_FETCH, 'receivers', this.getReceivers), + fetchToStateReceiver(LISTENERS_FETCH, 'listeners', this.getListeners), + fetchToStateReceiver(STATE_LISTENERS_FETCH, 'stateListeners', this.getStateListeners), + ]; + this.receivers.forEach(receiver => { + this.eventrix.useReceiver(receiver); + }); this.autoRefreshHandler = { currentState: null, stateHistory: null, @@ -23,9 +37,8 @@ class DebuggerService { }; } - @receiver(TURN_ON_AUTO_REFRESH_MODE) - turnOnAutoRefreshMode(eventName, eventData, stateManager) { - const { refreshType } = eventData; + turnOnAutoRefreshMode = (eventName, eventData, stateManager) => { + const {refreshType} = eventData; if (!this.autoRefreshHandler[refreshType]) { if (refreshType === 'currentState') { this.autoRefreshHandler[refreshType] = setInterval(() => { @@ -57,9 +70,8 @@ class DebuggerService { stateManager.setState(`autoRefreshMode.${refreshType}`, true); } - @receiver(TURN_OFF_AUTO_REFRESH_MODE) turnOffAutoRefreshMode(eventName, eventData, stateManager) { - const { refreshType } = eventData; + const {refreshType} = eventData; if (this.autoRefreshHandler[refreshType]) { clearInterval(this.autoRefreshHandler[refreshType]); this.autoRefreshHandler[refreshType] = null; @@ -67,8 +79,7 @@ class DebuggerService { stateManager.setState(`autoRefreshMode.${refreshType}`, false); } - @fetchToState(EVENTS_HISTORY_FETCH, 'eventsHistory') - getEventsHistory() { + getEventsHistory = () => { return new Promise((resolve) => { chrome.devtools.inspectedWindow.eval( `${WINDOW_EVENTRIX_DEBUGGER_NAME}.eventsHistory`, @@ -79,8 +90,7 @@ class DebuggerService { }) } - @fetchToState(STATE_HISTORY_FETCH, 'stateHistory') - getStateHistory() { + getStateHistory = () => { return new Promise((resolve) => { chrome.devtools.inspectedWindow.eval( `${WINDOW_EVENTRIX_DEBUGGER_NAME}.stateHistory`, @@ -91,8 +101,7 @@ class DebuggerService { }) } - @fetchToState(STATE_FETCH, 'currentState') - getCurrentState() { + getCurrentState = () => { return new Promise((resolve) => { chrome.devtools.inspectedWindow.eval( `${WINDOW_EVENTRIX_DEBUGGER_NAME}.getState()`, @@ -103,8 +112,7 @@ class DebuggerService { }) } - @fetchToState(RECEIVERS_FETCH, 'receivers') - getReceivers() { + getReceivers = () => { return new Promise((resolve) => { chrome.devtools.inspectedWindow.eval( `${WINDOW_EVENTRIX_DEBUGGER_NAME}.getAllEventsReceiversCount()`, @@ -115,8 +123,7 @@ class DebuggerService { }) } - @fetchToState(LISTENERS_FETCH, 'listeners') - getListeners() { + getListeners = () => { return new Promise((resolve) => { chrome.devtools.inspectedWindow.eval( `${WINDOW_EVENTRIX_DEBUGGER_NAME}.getAllEventsListenersCount()`, @@ -127,8 +134,50 @@ class DebuggerService { }) } - @fetchToState(STATE_LISTENERS_FETCH, 'stateListeners') - getStateListeners() { + isJSON = (str) => { + if (str.length === 0) return false; + const firstChar = str[0]; + const lastChar = str[str.length - 1]; + const isObject = firstChar === '{' && lastChar === '}'; + const isArray = firstChar === '[' && lastChar === ']'; + return isObject || isArray; + } + + emitEvent = (name, { eventName, eventPayload }) => { + const parsedEventPayload = this.isJSON(eventPayload) ? JSON.parse(eventPayload) : eventPayload; + return new Promise((resolve) => { + chrome.devtools.inspectedWindow.eval( + `${WINDOW_EVENTRIX_DEBUGGER_NAME}.eventrix.emit(${eventName}, ${parsedEventPayload})`, + (result = [], isException) => { + resolve(result || []); + } + ); + }) + } + + resetStateHistory = () => { + return new Promise((resolve) => { + chrome.devtools.inspectedWindow.eval( + `${WINDOW_EVENTRIX_DEBUGGER_NAME}.stateHistory = []`, + (result = [], isException) => { + resolve([]); + } + ); + }) + } + + resetEventsHistory = () => { + return new Promise((resolve) => { + chrome.devtools.inspectedWindow.eval( + `${WINDOW_EVENTRIX_DEBUGGER_NAME}.eventsHistory = []`, + (result = [], isException) => { + resolve([]); + } + ); + }) + } + + getStateListeners = () => { return Promise.all([ this.getReceivers(), this.getListeners(), diff --git a/src/devtools.js b/src/devtools.js deleted file mode 100644 index 387ddc5..0000000 --- a/src/devtools.js +++ /dev/null @@ -1,5 +0,0 @@ -chrome.devtools.panels.create('Eventrix', - 'images/eventrix_16x16.png', - 'panel.html', - null -); \ No newline at end of file diff --git a/src/panel.jsx b/src/index.jsx similarity index 64% rename from src/panel.jsx rename to src/index.jsx index 3bfda14..790b218 100644 --- a/src/panel.jsx +++ b/src/index.jsx @@ -1,9 +1,9 @@ import React from 'react'; -import ReactDOM from 'react-dom'; +import ReactDOM from 'react-dom/client'; import { Eventrix, EventrixProvider } from 'eventrix'; import App from './DevtoolsPanel/App'; import DebuggerService from './DevtoolsPanel/services/debugger'; -// import DebuggerService from './mockedData/services/debugger'; +import DevDebuggerService from './mockedData/services/debugger'; import { ROUTES } from "./DevtoolsPanel/constants/routes"; const eventrixInstance = new Eventrix({ @@ -20,12 +20,15 @@ const eventrixInstance = new Eventrix({ stateHistoryPreview: null, stateHistoryFilters: { search: '' }, }); -const debuggerService = new DebuggerService({ eventrix: eventrixInstance }); -// const debuggerService = new DebuggerService({ eventrix: eventrixInstance }); -ReactDOM.render( +if(import.meta.env.MODE === 'development') { + new DevDebuggerService({ eventrix: eventrixInstance }) +} else { + new DebuggerService({eventrix: eventrixInstance}); +} + +ReactDOM.createRoot(document.getElementById('root')).render( - , - document.getElementById('root') -); \ No newline at end of file + +); diff --git a/src/mockedData/services/debugger.js b/src/mockedData/services/debugger.js index 6a566dc..da9325c 100644 --- a/src/mockedData/services/debugger.js +++ b/src/mockedData/services/debugger.js @@ -1,10 +1,11 @@ -import { useEventrix, fetchToState, receiver } from 'eventrix'; +import { EventsReceiver, fetchToStateReceiver} from 'eventrix'; import { - EVENTS_HISTORY_FETCH, + EMITTER_EMIT, + EVENTS_HISTORY_FETCH, EVENTS_HISTORY_RESET, LISTENERS_FETCH, RECEIVERS_FETCH, STATE_FETCH, - STATE_HISTORY_FETCH, + STATE_HISTORY_FETCH, STATE_HISTORY_RESET, STATE_LISTENERS_FETCH, TURN_OFF_AUTO_REFRESH_MODE, TURN_ON_AUTO_REFRESH_MODE @@ -14,10 +15,27 @@ import stateHistory from '../stateHistory'; import currentState from '../currentState'; import receiversCounts from '../receiversCount'; import listenersCount from '../listenersCount'; +import {WINDOW_EVENTRIX_DEBUGGER_NAME} from "../../DevtoolsPanel/constants"; -@useEventrix class DebuggerService { - constructor() { + constructor({ eventrix }) { + this.eventrix = eventrix; + this.receivers = [ + new EventsReceiver(TURN_ON_AUTO_REFRESH_MODE, this.turnOnAutoRefreshMode), + new EventsReceiver(TURN_OFF_AUTO_REFRESH_MODE, this.turnOffAutoRefreshMode), + new EventsReceiver(EMITTER_EMIT, this.emitEvent), + fetchToStateReceiver(EVENTS_HISTORY_FETCH, 'eventsHistory', this.getEventsHistory), + fetchToStateReceiver(EVENTS_HISTORY_RESET, 'eventsHistory', this.resetEventsHistory), + fetchToStateReceiver(STATE_HISTORY_FETCH, 'stateHistory', this.getStateHistory), + fetchToStateReceiver(STATE_HISTORY_RESET, 'stateHistory', this.resetStateHistory), + fetchToStateReceiver(STATE_FETCH, 'currentState', this.getCurrentState), + fetchToStateReceiver(RECEIVERS_FETCH, 'receivers', this.getReceivers), + fetchToStateReceiver(LISTENERS_FETCH, 'listeners', this.getListeners), + fetchToStateReceiver(STATE_LISTENERS_FETCH, 'stateListeners', this.getStateListeners), + ]; + this.receivers.forEach(receiver => { + this.eventrix.useReceiver(receiver); + }); this.autoRefreshHandler = { currentState: null, stateHistory: null, @@ -25,8 +43,7 @@ class DebuggerService { }; } - @receiver(TURN_ON_AUTO_REFRESH_MODE) - turnOnAutoRefreshMode(eventName, eventData, stateManager) { + turnOnAutoRefreshMode = (eventName, eventData, stateManager) => { const { refreshType } = eventData; if (!this.autoRefreshHandler[refreshType]) { if (refreshType === 'currentState') { @@ -48,8 +65,7 @@ class DebuggerService { stateManager.setState(`autoRefreshMode.${refreshType}`, true); } - @receiver(TURN_OFF_AUTO_REFRESH_MODE) - turnOffAutoRefreshMode(eventName, eventData, stateManager) { + turnOffAutoRefreshMode = (eventName, eventData, stateManager) => { const { refreshType } = eventData; if (this.autoRefreshHandler[refreshType]) { clearInterval(this.autoRefreshHandler[refreshType]); @@ -58,33 +74,39 @@ class DebuggerService { stateManager.setState(`autoRefreshMode.${refreshType}`, false); } - @fetchToState(EVENTS_HISTORY_FETCH, 'eventsHistory') - getEventsHistory() { + getEventsHistory = () => { return Promise.resolve(eventsHistory.reverse()); } - @fetchToState(STATE_HISTORY_FETCH, 'stateHistory') - getStateHistory() { + getStateHistory = () => { return Promise.resolve(stateHistory.reverse()); } - @fetchToState(STATE_FETCH, 'currentState') - getCurrentState() { + getCurrentState = () => { return Promise.resolve(currentState); } - @fetchToState(RECEIVERS_FETCH, 'receivers') - getReceivers() { + getReceivers = () => { return Promise.resolve(receiversCounts); } - @fetchToState(LISTENERS_FETCH, 'listeners') - getListeners() { + getListeners = () => { return Promise.resolve(listenersCount); } - @fetchToState(STATE_LISTENERS_FETCH, 'stateListeners') - getStateListeners() { + emitEvent = () => { + new Promise.resolve(true); + } + + resetStateHistory = () => { + return Promise.resolve([]) + } + + resetEventsHistory = () => { + return Promise.resolve([]) + } + + getStateListeners = () => { return Promise.all([ this.getReceivers(), this.getListeners(), diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..4126959 --- /dev/null +++ b/vite.config.js @@ -0,0 +1,7 @@ +import {defineConfig} from 'vite' +import react from '@vitejs/plugin-react-swc' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], +}) diff --git a/webpack.config.js b/webpack.config.js deleted file mode 100644 index 65679f1..0000000 --- a/webpack.config.js +++ /dev/null @@ -1,75 +0,0 @@ -const DirectoryNamedWebpackPlugin = require('directory-named-webpack-plugin'); -const path = require('path'); - -module.exports = { - mode: "production", - target: 'web', - entry: { - panel: "./src/panel.jsx", - devtools: "./src/devtools.js", - }, - output: { - filename: "[name].js", - path: path.resolve(__dirname, 'chrome') - }, - module: { - rules: [ - { - test: /\.(js|jsx)$/, - exclude: /node_modules/, - use: { - loader: 'babel-loader', - } - }, - { - test: /\.scss$/, - use:[ - 'style-loader', - { - loader: 'css-loader', - options: { - modules: true, - localIdentName: '[name]__[local]___[hash:base64:5]', - }, - }, - { - loader: 'resolve-url-loader', - }, - { - loader: 'sass-loader', - options: { - modules: true, - localIdentName: '[name]__[local]___[hash:base64:5]', - sourceMap: true, - sourceMapContents: false - }, - } - ], - }, - { - test: /\.(png|jpg|gif)$/i, - use: [ - { - loader: 'url-loader', - options: { - limit: 8192, - }, - }, - ], - }, - ] - }, - resolve: { - modules: [process.cwd(), 'node_modules', path.resolve(__dirname,'src')], - extensions: ['.js', '.jsx'], - plugins: [new DirectoryNamedWebpackPlugin(true)], - }, - devServer: { - port: 9010, - historyApiFallback: true, - watchOptions: { - poll: true - }, - watchContentBase: true, - } -}; \ No newline at end of file