From 2eb3a4ce2a61dec4c9ee2a327ebefd326c279649 Mon Sep 17 00:00:00 2001 From: Martha Cryan Date: Mon, 13 Jan 2025 16:10:41 -0600 Subject: [PATCH 1/9] Add very basic notifications --- .../error/FrontEnd/FrontEndError.react.js | 5 +- .../FrontEnd/FrontEndErrorContainer.react.js | 180 ++++++++++++++++-- .../error/GlobalErrorContainer.react.js | 6 +- .../components/error/GlobalErrorOverlay.css | 7 +- .../error/GlobalErrorOverlay.react.js | 6 +- .../components/error/menu/DebugMenu.react.js | 6 +- dash/dash.py | 1 + 7 files changed, 180 insertions(+), 31 deletions(-) diff --git a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.react.js b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.react.js index 022b4f7230..8bb3e0fe90 100644 --- a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.react.js +++ b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.react.js @@ -59,7 +59,10 @@ class FrontEndError extends Component { /* eslint-enable no-inline-comments */ return collapsed ? ( -
{errorHeader}
+
+ {errorHeader} + +
) : (
{errorHeader} diff --git a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndErrorContainer.react.js b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndErrorContainer.react.js index 1ff561febb..ccc9cd6da5 100644 --- a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndErrorContainer.react.js +++ b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndErrorContainer.react.js @@ -3,15 +3,60 @@ import './FrontEndError.css'; import PropTypes from 'prop-types'; import {FrontEndError} from './FrontEndError.react'; +const DAY_IN_MS = 86400000; + +function compareVersions(v1, v2) { + const v1Parts = v1.split('.').map(Number); + const v2Parts = v2.split('.').map(Number); + + for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) { + const part1 = v1Parts[i] || 0; + const part2 = v2Parts[i] || 0; + + if (part1 > part2) return 1; + if (part1 < part2) return -1; + } + + return 0; +} + class FrontEndErrorContainer extends Component { constructor(props) { super(props); + + const {config} = props; + + if (!localStorage.getItem('noNotifications')) { + fetch('http://127.0.0.1:8080/sample', { + method: 'POST', + body: JSON.stringify({ + dash_version: config.dash_version + }), + headers: { + 'Content-Type': 'application/json' + } + }).then(response => { + response.json().then(body => { + this.setState({...this.state, notificationInfo: body}); + }); + }); + } + + this.state = { + dismissed: [false * this.props.errors.length], + notificationInfo: [] + }; } render() { - const {errors, connected, errorsOpened, clickHandler} = this.props; + const {errors, errorsOpened} = this.props; + const {dismissed, notificationInfo} = this.state; const errorsLength = errors.length; - if (errorsLength === 0 || !errorsOpened) { + + if ( + (errorsLength === 0 || !errorsOpened) && + notificationInfo.length === 0 + ) { return null; } @@ -19,29 +64,125 @@ class FrontEndErrorContainer extends Component { let cardClasses = 'dash-error-card dash-error-card--container'; const errorElements = errors.map((error, i) => { - return ; + if (dismissed[i]) { + return null; + } + return ( + { + dismissed[i] = true; + this.setState({dismissed: dismissed}); + }} + /> + ); + }); + + const setDontShowAgain = i => { + // Set local storage to record the last dismissed notification + localStorage.setItem('noNotifications', true); + + dismissed[errorsLength + i] = true; + this.setState({dismissed: dismissed}); + }; + + const setRemindMeLater = i => { + // Set local storage to record the last dismissed notification + localStorage.setItem('lastDismissed', Date.now()); + + dismissed[errorsLength + i] = true; + this.setState({dismissed: dismissed}); + }; + + const setSkipThisVersion = i => { + // Set local storage to record the last dismissed version + localStorage.setItem( + 'lastDismissedVersion', + notificationInfo[i].version + ); + + dismissed[errorsLength + i] = true; + this.setState({dismissed: dismissed}); + }; + + const notificationElements = notificationInfo.map((notification, i) => { + const wasDismissedInLastDay = + Date.now() - localStorage.getItem('lastDismissed') < DAY_IN_MS; + const lastDismissedVersion = localStorage.getItem( + 'lastDismissedVersion' + ); + const hasDismissedVersion = + lastDismissedVersion !== null && + compareVersions(lastDismissedVersion, notification.version) == + 0; + if ( + dismissed[errorsLength + i] || + wasDismissedInLastDay || + hasDismissedVersion || + localStorage.getItem('noNotifications') + ) { + return null; + } + return ( +
+

{notification.message}

+
+ {notification.buttons.map(button => { + switch (button) { + case 'dont_show_again': + return ( + + ); + case 'remind_me_later': + return ( + + ); + case 'skip_this_version': + return ( + + ); + default: + return null; + } + })} +
+
+ ); }); + if (inAlertsTray) { cardClasses += ' dash-error-card--alerts-tray'; } + return (
-
-
- 🛑 Errors ( - - {errorsLength} - - ){connected ? null : '\u00a0 🚫 Server Unavailable'} -
-
clickHandler()} - > - × -
+
+ {errorElements} + {notificationElements}
-
{errorElements}
); } @@ -53,7 +194,8 @@ FrontEndErrorContainer.propTypes = { connected: PropTypes.bool, inAlertsTray: PropTypes.any, errorsOpened: PropTypes.any, - clickHandler: PropTypes.func + clickHandler: PropTypes.func, + config: PropTypes.object }; FrontEndErrorContainer.propTypes = { diff --git a/dash/dash-renderer/src/components/error/GlobalErrorContainer.react.js b/dash/dash-renderer/src/components/error/GlobalErrorContainer.react.js index e1572ad6de..579b477b12 100644 --- a/dash/dash-renderer/src/components/error/GlobalErrorContainer.react.js +++ b/dash/dash-renderer/src/components/error/GlobalErrorContainer.react.js @@ -12,7 +12,11 @@ class UnconnectedGlobalErrorContainer extends Component { const {config, error, children} = this.props; return (
- +
{children}
diff --git a/dash/dash-renderer/src/components/error/GlobalErrorOverlay.css b/dash/dash-renderer/src/components/error/GlobalErrorOverlay.css index 763f6a01fd..a7734c888e 100644 --- a/dash/dash-renderer/src/components/error/GlobalErrorOverlay.css +++ b/dash/dash-renderer/src/components/error/GlobalErrorOverlay.css @@ -10,12 +10,8 @@ .dash-error-card { box-sizing: border-box; - background: #ffffff; display: inline-block; /* shadow-1 */ - box-shadow: 0px 6px 16px rgba(80, 103, 132, 0.165), - 0px 2px 6px rgba(80, 103, 132, 0.12), - 0px 0px 1px rgba(80, 103, 132, 0.32); border-radius: 4px; position: fixed; top: 16px; @@ -23,8 +19,7 @@ animation: dash-error-card-animation 0.5s; padding: 24px; text-align: left; - background-color: white; - + background: transparent; } .dash-error-card--alerts-tray { position: absolute; diff --git a/dash/dash-renderer/src/components/error/GlobalErrorOverlay.react.js b/dash/dash-renderer/src/components/error/GlobalErrorOverlay.react.js index ccb581bf84..115bb1567a 100644 --- a/dash/dash-renderer/src/components/error/GlobalErrorOverlay.react.js +++ b/dash/dash-renderer/src/components/error/GlobalErrorOverlay.react.js @@ -11,7 +11,7 @@ export default class GlobalErrorOverlay extends Component { } render() { - const {visible, error, errorsOpened, clickHandler} = this.props; + const {visible, error, errorsOpened, clickHandler, config} = this.props; let frontEndErrors; if (errorsOpened) { @@ -23,6 +23,7 @@ export default class GlobalErrorOverlay extends Component { connected={error.backEndConnected} errorsOpened={errorsOpened} clickHandler={clickHandler} + config={config} /> ); } @@ -44,5 +45,6 @@ GlobalErrorOverlay.propTypes = { visible: PropTypes.bool, error: PropTypes.object, errorsOpened: PropTypes.any, - clickHandler: PropTypes.func + clickHandler: PropTypes.func, + config: PropTypes.object }; diff --git a/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js b/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js index a11ab6085d..5091e77646 100644 --- a/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js +++ b/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js @@ -53,7 +53,7 @@ class DebugMenu extends Component { } render() { const {opened, errorsOpened, callbackGraphOpened} = this.state; - const {error, hotReload} = this.props; + const {error, hotReload, config} = this.props; const errCount = error.frontEnd.length + error.backEnd.length; const connected = error.backEndConnected; @@ -148,6 +148,7 @@ class DebugMenu extends Component { visible={errCount > 0} errorsOpened={errorsOpened} clickHandler={toggleErrors} + config={config} > {this.props.children} @@ -159,7 +160,8 @@ class DebugMenu extends Component { DebugMenu.propTypes = { children: PropTypes.object, error: PropTypes.object, - hotReload: PropTypes.bool + hotReload: PropTypes.bool, + config: PropTypes.object }; export {DebugMenu}; diff --git a/dash/dash.py b/dash/dash.py index 40f65dff5f..46dec05120 100644 --- a/dash/dash.py +++ b/dash/dash.py @@ -766,6 +766,7 @@ def _config(self): "update_title": self.config.update_title, "children_props": ComponentRegistry.children_props, "serve_locally": self.config.serve_locally, + "dash_version": __version__, } if not self.config.serve_locally: config["plotlyjs_url"] = self._plotlyjs_url From 2e77bdfd9540d49e87f2887038a27a60001cc683 Mon Sep 17 00:00:00 2001 From: Martha Cryan Date: Wed, 22 Jan 2025 18:55:15 -0600 Subject: [PATCH 2/9] Update the sample URL --- .../components/error/FrontEnd/FrontEndErrorContainer.react.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndErrorContainer.react.js b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndErrorContainer.react.js index ccc9cd6da5..8f96ed2dac 100644 --- a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndErrorContainer.react.js +++ b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndErrorContainer.react.js @@ -27,7 +27,7 @@ class FrontEndErrorContainer extends Component { const {config} = props; if (!localStorage.getItem('noNotifications')) { - fetch('http://127.0.0.1:8080/sample', { + fetch('https://dash-version.plotly.com:8080/sample', { method: 'POST', body: JSON.stringify({ dash_version: config.dash_version From 00795e3d75546fb36ccf26d5be7aea9594b416fa Mon Sep 17 00:00:00 2001 From: Martha Cryan Date: Mon, 27 Jan 2025 18:12:20 -0600 Subject: [PATCH 3/9] Change debug menu to use text --- .../error/FrontEnd/FrontEndError.css | 13 +- .../error/FrontEnd/FrontEndError.react.js | 5 +- .../FrontEnd/FrontEndErrorContainer.react.js | 175 +---------- .../error/GlobalErrorOverlay.react.js | 1 - .../src/components/error/icons/CheckIcon.svg | 4 +- .../src/components/error/menu/DebugMenu.css | 110 ++----- .../components/error/menu/DebugMenu.react.js | 279 +++++++++++------- 7 files changed, 226 insertions(+), 361 deletions(-) diff --git a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.css b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.css index ec1293a4c6..00d85bc9a0 100644 --- a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.css +++ b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.css @@ -45,11 +45,18 @@ margin: 0px 8px; } .dash-fe-error-top { - height: 20px; - display: flex; - justify-content: space-between; width: 100%; cursor: pointer; + border: 1px solid gray; + border-radius: 2px; +} +.dash-debug-menu__error-count { + font-size: 12px; + color: #fff; + background-color: #C73A3A; + padding: 5px; + border-radius: 3px; + margin: 4px; } .dash-fe-error-top__group:first-child { /* diff --git a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.react.js b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.react.js index 8bb3e0fe90..022b4f7230 100644 --- a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.react.js +++ b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.react.js @@ -59,10 +59,7 @@ class FrontEndError extends Component { /* eslint-enable no-inline-comments */ return collapsed ? ( -
- {errorHeader} - -
+
{errorHeader}
) : (
{errorHeader} diff --git a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndErrorContainer.react.js b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndErrorContainer.react.js index 8f96ed2dac..5fdc3c6a19 100644 --- a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndErrorContainer.react.js +++ b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndErrorContainer.react.js @@ -3,186 +3,32 @@ import './FrontEndError.css'; import PropTypes from 'prop-types'; import {FrontEndError} from './FrontEndError.react'; -const DAY_IN_MS = 86400000; - -function compareVersions(v1, v2) { - const v1Parts = v1.split('.').map(Number); - const v2Parts = v2.split('.').map(Number); - - for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) { - const part1 = v1Parts[i] || 0; - const part2 = v2Parts[i] || 0; - - if (part1 > part2) return 1; - if (part1 < part2) return -1; - } - - return 0; -} - class FrontEndErrorContainer extends Component { constructor(props) { super(props); - - const {config} = props; - - if (!localStorage.getItem('noNotifications')) { - fetch('https://dash-version.plotly.com:8080/sample', { - method: 'POST', - body: JSON.stringify({ - dash_version: config.dash_version - }), - headers: { - 'Content-Type': 'application/json' - } - }).then(response => { - response.json().then(body => { - this.setState({...this.state, notificationInfo: body}); - }); - }); - } - - this.state = { - dismissed: [false * this.props.errors.length], - notificationInfo: [] - }; } render() { - const {errors, errorsOpened} = this.props; - const {dismissed, notificationInfo} = this.state; - const errorsLength = errors.length; - - if ( - (errorsLength === 0 || !errorsOpened) && - notificationInfo.length === 0 - ) { - return null; - } + const {errors, connected} = this.props; const inAlertsTray = this.props.inAlertsTray; let cardClasses = 'dash-error-card dash-error-card--container'; const errorElements = errors.map((error, i) => { - if (dismissed[i]) { - return null; - } - return ( - { - dismissed[i] = true; - this.setState({dismissed: dismissed}); - }} - /> - ); + return ; }); - - const setDontShowAgain = i => { - // Set local storage to record the last dismissed notification - localStorage.setItem('noNotifications', true); - - dismissed[errorsLength + i] = true; - this.setState({dismissed: dismissed}); - }; - - const setRemindMeLater = i => { - // Set local storage to record the last dismissed notification - localStorage.setItem('lastDismissed', Date.now()); - - dismissed[errorsLength + i] = true; - this.setState({dismissed: dismissed}); - }; - - const setSkipThisVersion = i => { - // Set local storage to record the last dismissed version - localStorage.setItem( - 'lastDismissedVersion', - notificationInfo[i].version - ); - - dismissed[errorsLength + i] = true; - this.setState({dismissed: dismissed}); - }; - - const notificationElements = notificationInfo.map((notification, i) => { - const wasDismissedInLastDay = - Date.now() - localStorage.getItem('lastDismissed') < DAY_IN_MS; - const lastDismissedVersion = localStorage.getItem( - 'lastDismissedVersion' - ); - const hasDismissedVersion = - lastDismissedVersion !== null && - compareVersions(lastDismissedVersion, notification.version) == - 0; - if ( - dismissed[errorsLength + i] || - wasDismissedInLastDay || - hasDismissedVersion || - localStorage.getItem('noNotifications') - ) { - return null; - } - return ( -
-

{notification.message}

-
- {notification.buttons.map(button => { - switch (button) { - case 'dont_show_again': - return ( - - ); - case 'remind_me_later': - return ( - - ); - case 'skip_this_version': - return ( - - ); - default: - return null; - } - })} -
-
- ); - }); - if (inAlertsTray) { cardClasses += ' dash-error-card--alerts-tray'; } - return (
-
- {errorElements} - {notificationElements} +
+
+ Errors + {connected ? null : '\u00a0 🚫 Server Unavailable'} +
+
{errorElements}
); } @@ -192,10 +38,7 @@ FrontEndErrorContainer.propTypes = { id: PropTypes.string, errors: PropTypes.array, connected: PropTypes.bool, - inAlertsTray: PropTypes.any, - errorsOpened: PropTypes.any, - clickHandler: PropTypes.func, - config: PropTypes.object + inAlertsTray: PropTypes.any }; FrontEndErrorContainer.propTypes = { diff --git a/dash/dash-renderer/src/components/error/GlobalErrorOverlay.react.js b/dash/dash-renderer/src/components/error/GlobalErrorOverlay.react.js index 115bb1567a..f632d83d83 100644 --- a/dash/dash-renderer/src/components/error/GlobalErrorOverlay.react.js +++ b/dash/dash-renderer/src/components/error/GlobalErrorOverlay.react.js @@ -21,7 +21,6 @@ export default class GlobalErrorOverlay extends Component { diff --git a/dash/dash-renderer/src/components/error/icons/CheckIcon.svg b/dash/dash-renderer/src/components/error/icons/CheckIcon.svg index b5ad358c68..dc2ccbb60d 100644 --- a/dash/dash-renderer/src/components/error/icons/CheckIcon.svg +++ b/dash/dash-renderer/src/components/error/icons/CheckIcon.svg @@ -1,3 +1,3 @@ - - + + diff --git a/dash/dash-renderer/src/components/error/menu/DebugMenu.css b/dash/dash-renderer/src/components/error/menu/DebugMenu.css index b00ab401c2..3fa8370618 100644 --- a/dash/dash-renderer/src/components/error/menu/DebugMenu.css +++ b/dash/dash-renderer/src/components/error/menu/DebugMenu.css @@ -21,11 +21,6 @@ background-color: #108de4; } -.dash-debug-menu__icon { - width: auto; - height: 24px; -} - .dash-debug-menu__outer { transition: 0.3s; box-sizing: border-box; @@ -33,11 +28,11 @@ bottom: 27px; right: 27px; display: flex; + flex-direction: column; justify-content: center; align-items: center; z-index: 10000; - height: 80px; - border-radius: 40px; + border-radius: 5px; padding: 5px 78px 5px 5px; background-color: #fff; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.25), @@ -51,98 +46,55 @@ padding: 0; } +.dash-debug-menu__upgrade-tooltip { + position: absolute; + bottom: 100%; + right: 0; + display: flex; + flex-direction: column; +} + +.dash-debug-menu__upgrade-tooltip button { + background: none; + border: none; +} + .dash-debug-menu__content { display: flex; width: 100%; height: 100%; + align-items: center; } -.dash-debug-menu__button-container { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - width: 74px; +.dash-debug-menu__divider { + width: 1px; + height: 20px; + margin: 10px; + background-color: #e6e6e6; } .dash-debug-menu__button { + background: none; + border: none; + box-shadow: 0 1px #D3DAE6; position: relative; - background-color: #B9C2CE; - border-radius: 100%; - width: 64px; - height: 64px; - font-size: 10px; display: flex; - flex-direction: column; justify-content: center; align-items: center; transition: background-color 0.2s; - color: #fff; cursor: pointer; + font-weight: bold; } .dash-debug-menu__button:hover { - background-color: #a1a9b5; -} -.dash-debug-menu__button--enabled { - background-color: #00CC96; -} -.dash-debug-menu__button.dash-debug-menu__button--enabled:hover { - background-color: #03bb8a; + color: black; } -.dash-debug-menu__button-label { - cursor: inherit; -} - -.dash-debug-menu__button::before { - visibility: hidden; - pointer-events: none; - position: absolute; - box-sizing: border-box; - bottom: 110%; - left: 50%; - margin-left: -60px; - padding: 7px; - width: 120px; - border-radius: 3px; - background-color: rgba(68,68,68,0.7); - color: #fff; - text-align: center; - font-size: 10px; - line-height: 1.2; -} -.dash-debug-menu__button:hover::before { - visibility: visible; -} -.dash-debug-menu__button--callbacks::before { - content: "Toggle Callback Graph"; -} -.dash-debug-menu__button--errors::before { - content: "Toggle Errors"; -} -.dash-debug-menu__button--available, -.dash-debug-menu__button--available:hover { - background-color: #00CC96; - cursor: default; -} -.dash-debug-menu__button--available::before { - content: "Server Available"; -} -.dash-debug-menu__button--unavailable, -.dash-debug-menu__button--unavailable:hover { - background-color: #F1564E; - cursor: default; -} -.dash-debug-menu__button--unavailable::before { - content: "Server Unavailable. Check if the process has halted or crashed."; -} -.dash-debug-menu__button--cold, -.dash-debug-menu__button--cold:hover { - background-color: #FDDA68; - cursor: default; +.dash-debug-menu__button.dash-debug-menu__button--selected { + color: #7F4BC4; + box-shadow: 0 2px #0071C2; } -.dash-debug-menu__button--cold::before { - content: "Hot Reload Disabled"; +.dash-debug-menu__button.dash-debug-menu__button--selected:hover { + color: #5806c4; } .dash-debug-alert { diff --git a/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js b/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js index 5091e77646..8a9e35dcfa 100644 --- a/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js +++ b/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js @@ -1,157 +1,224 @@ import React, {Component} from 'react'; import PropTypes from 'prop-types'; +import {concat} from 'ramda'; import './DebugMenu.css'; -import BellIcon from '../icons/BellIcon.svg'; import CheckIcon from '../icons/CheckIcon.svg'; import ClockIcon from '../icons/ClockIcon.svg'; -import DebugIcon from '../icons/DebugIcon.svg'; -import GraphIcon from '../icons/GraphIcon.svg'; import OffIcon from '../icons/OffIcon.svg'; -import GlobalErrorOverlay from '../GlobalErrorOverlay.react'; import {CallbackGraphContainer} from '../CallbackGraph/CallbackGraphContainer.react'; +import {FrontEndErrorContainer} from '../FrontEnd/FrontEndErrorContainer.react'; const classes = (base, variant, variant2) => `${base} ${base}--${variant}` + (variant2 ? ` ${base}--${variant2}` : ''); -const buttonFactory = ( - enabled, - buttonVariant, - toggle, - _Icon, - iconVariant, - label -) => ( -
-
- <_Icon className={classes('dash-debug-menu__icon', iconVariant)} /> - {label ? ( - - ) : null} -
-
-); +function compareVersions(v1, v2) { + const v1Parts = v1.split('.').map(Number); + const v2Parts = v2.split('.').map(Number); + + for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) { + const part1 = v1Parts[i] || 0; + const part2 = v2Parts[i] || 0; + + if (part1 > part2) return 1; + if (part1 < part2) return -1; + } + + return 0; +} + +function shouldShowUpgradeNotification(currentDashVersion, newDashVersion) { + const lastDismissed = localStorage.getItem('lastDismissed'); + const lastDismissedVersion = localStorage.getItem('lastDismissedVersion'); + + if ( + currentDashVersion == newDashVersion || + localStorage.getItem('noNotifications') || + newDashVersion === undefined + ) { + return false; + } else if ( + lastDismissed && + Date.now() - Number(lastDismissed) > 7 * 24 * 60 * 60 * 1000 + ) { + return true; + } else if (lastDismissedVersion) { + return ( + compareVersions( + localStorage.getItem('lastDismissedVersion'), + newDashVersion + ) < 0 + ); + } else { + return true; + } +} + +async function requestDashVersionInfo(currentDashVersion) { + return fetch('https://dash-version.plotly.com:8080/sample', { + method: 'POST', + body: JSON.stringify({ + dash_version: currentDashVersion + }), + headers: { + 'Content-Type': 'application/json' + } + }).then(response => response.json()); +} class DebugMenu extends Component { constructor(props) { super(props); + const {config} = props; + + requestDashVersionInfo(config.dash_version).then(body => { + this.setState({...this.state, upgradeInfo: body}); + }); this.state = { opened: false, callbackGraphOpened: false, - errorsOpened: true + errorsOpened: true, + upgradeInfo: [] }; } + render() { - const {opened, errorsOpened, callbackGraphOpened} = this.state; + const {callbackGraphOpened, errorsOpened, upgradeInfo} = this.state; const {error, hotReload, config} = this.props; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const setDontShowAgain = i => { + // Set local storage to record the last dismissed notification + localStorage.setItem('noNotifications', true); + this.setState({upgradeTooltipOpened: false}); + }; + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const setRemindMeLater = i => { + // Set local storage to record the last dismissed notification + localStorage.setItem('lastDismissed', Date.now()); + this.setState({upgradeTooltipOpened: false}); + }; + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const setSkipThisVersion = i => { + // Set local storage to record the last dismissed version + localStorage.setItem( + 'lastDismissedVersion', + upgradeInfo[i].version + ); + this.setState({upgradeTooltipOpened: false}); + }; + + const newDashVersion = upgradeInfo[0] + ? upgradeInfo[0].version + : undefined; + const errCount = error.frontEnd.length + error.backEnd.length; const connected = error.backEndConnected; const toggleErrors = () => { - this.setState({errorsOpened: !errorsOpened}); + this.setState({ + errorsOpened: callbackGraphOpened ? true : !errorsOpened, + callbackGraphOpened: false + }); }; - const status = hotReload - ? connected - ? 'available' - : 'unavailable' - : 'cold'; + const toggleCallbackGraph = () => { + this.setState({callbackGraphOpened: !callbackGraphOpened}); + }; + + const toggleShowUpgradeTooltip = () => { + this.setState({ + upgradeTooltipOpened: !this.state.upgradeTooltipOpened + }); + }; + + const errors = concat(error.frontEnd, error.backEnd); + const _StatusIcon = hotReload ? connected ? CheckIcon : OffIcon : ClockIcon; - const menuContent = opened ? ( + const menuContent = (
{callbackGraphOpened ? : null} - {buttonFactory( - callbackGraphOpened, - 'callbacks', - () => { - this.setState({ - callbackGraphOpened: !callbackGraphOpened - }); - }, - GraphIcon, - 'graph', - 'Callbacks' - )} - {buttonFactory( - errorsOpened, - 'errors', - toggleErrors, - BellIcon, - 'bell', - errCount + ' Error' + (errCount === 1 ? '' : 's') - )} - {buttonFactory( - false, - status, - null, - _StatusIcon, - 'indicator', - 'Server' - )} + + +
+
+ {this.state.upgradeTooltipOpened ? ( +
+ + + +
+ ) : null} + v{config.dash_version} + {shouldShowUpgradeNotification( + config.dash_version, + newDashVersion + ) ? ( + + ) : null} +
+
+
+ Server + <_StatusIcon className='dash-debug-menu__icon' /> +
- ) : ( -
); - const alertsLabel = - (errCount || !connected) && !opened ? ( -
-
- {errCount ? ( -
- {'🛑 ' + errCount} -
- ) : null} - {connected ? null : ( -
🚫
- )} -
-
- ) : null; - - const openVariant = opened ? 'open' : 'closed'; - return (
- {alertsLabel} -
+
+ {errorsOpened && errCount > 0 ? ( + + ) : undefined} {menuContent}
-
{ - this.setState({opened: !opened}); - }} - > - -
- 0} - errorsOpened={errorsOpened} - clickHandler={toggleErrors} - config={config} - > - {this.props.children} -
); } From eba85ad622a6a60b2c097aff39c995a15c900f94 Mon Sep 17 00:00:00 2001 From: Martha Cryan Date: Tue, 28 Jan 2025 16:28:23 -0600 Subject: [PATCH 4/9] Add more style from the figma design --- .../error/FrontEnd/FrontEndError.css | 111 ++++++++++++++++++ .../components/error/GlobalErrorOverlay.css | 1 + .../src/components/error/menu/DebugMenu.css | 11 +- .../components/error/menu/DebugMenu.react.js | 9 +- 4 files changed, 128 insertions(+), 4 deletions(-) diff --git a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.css b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.css index 00d85bc9a0..461fa9c2d8 100644 --- a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.css +++ b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.css @@ -12,6 +12,16 @@ margin-right: 10px } +.dash-debug-menu__upgrade-button { + background-color: #A159FF0D; + border: 1px solid #864AD433; + color: #7F4BC4; +} + +.dash-debug-menu__upgrade-button:hover { + background-color: #864AD433; +} + .dash-fe-error__icon-x:hover { color:#a1a9b5; @@ -146,3 +156,104 @@ display: inline-block; white-space: pre-wrap; } + + +.dash-error-menu { + max-width: 50%; + max-height: 60%; + display: contents; + font-family: monospace; + font-size: 14px; + font-variant-ligatures: common-ligatures; + color: rgb(50, 50, 50); +} + +.dash-error-card { + box-sizing: border-box; + display: inline-block; + /* shadow-1 */ + border-radius: 4px; + position: fixed; + top: 16px; + right: 16px; + animation: dash-error-card-animation 0.5s; + padding: 24px; + text-align: left; + background: transparent; + width: 100%; +} +.dash-error-card--alerts-tray { + position: absolute; + top: -300px; + left: -1px; + animation: none; + box-shadow: none; + border: 1px solid #ececec; + border-bottom: 0; + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; + width: 422px; +} +.dash-error-card--container { + padding: 10px 10px; + width: 600px; + max-width: 800px; + max-height: calc(100vh - 50px); + margin: 10px; + overflow: auto; + z-index: 1100; /* above the plotly.js toolbar and Bootstrap components */ +} + +.dash-error-card__topbar { + width: 100%; + height: 32px; + display: flex; + justify-content: center; + align-items: center; + position: relative; +} +.dash-error-card__message { + font-size: 14px; +} + +.dash-error-card__message > strong { + color: #ff4500; +} + +.dash-error-card__content { + box-sizing: border-box; + padding: 10px 10px; + background-color: white; + box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.25), + 0px 1px 3px rgba(162, 177, 198, 0.32); + border-radius: 2px; + margin-bottom: 8px; +} + +.dash-error-card__list-item { + background: #ffffff; + box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.25), + 0px 1px 3px rgba(162, 177, 198, 0.32); + border-radius: 2px; + padding: 10px 10px; + margin-bottom: 10px; + display: flex; + align-items: center; +} + +@keyframes dash-error-card-animation { + from { + opacity: 0; + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -ms-transform: scale(1.1); + transform: scale(1.1); + } + to { + opacity: 1; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} diff --git a/dash/dash-renderer/src/components/error/GlobalErrorOverlay.css b/dash/dash-renderer/src/components/error/GlobalErrorOverlay.css index a7734c888e..fe7e415b7d 100644 --- a/dash/dash-renderer/src/components/error/GlobalErrorOverlay.css +++ b/dash/dash-renderer/src/components/error/GlobalErrorOverlay.css @@ -20,6 +20,7 @@ padding: 24px; text-align: left; background: transparent; + width: 100%; } .dash-error-card--alerts-tray { position: absolute; diff --git a/dash/dash-renderer/src/components/error/menu/DebugMenu.css b/dash/dash-renderer/src/components/error/menu/DebugMenu.css index 3fa8370618..254c201ab6 100644 --- a/dash/dash-renderer/src/components/error/menu/DebugMenu.css +++ b/dash/dash-renderer/src/components/error/menu/DebugMenu.css @@ -52,11 +52,21 @@ right: 0; display: flex; flex-direction: column; + background-color: white; +} + +.dash-debug-menu__status { + margin: 3px; } .dash-debug-menu__upgrade-tooltip button { background: none; border: none; + padding: 5px; + border: 1px solid #d6d6d6; +} +.dash-debug-menu__upgrade-tooltip button:hover { + background-color: #d6d6d6; } .dash-debug-menu__content { @@ -77,7 +87,6 @@ background: none; border: none; box-shadow: 0 1px #D3DAE6; - position: relative; display: flex; justify-content: center; align-items: center; diff --git a/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js b/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js index 8a9e35dcfa..1c631ef7e2 100644 --- a/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js +++ b/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js @@ -174,7 +174,7 @@ class DebugMenu extends Component { Callbacks
-
+
{this.state.upgradeTooltipOpened ? (
) : null}
-
+
Server <_StatusIcon className='dash-debug-menu__icon' />
From 200e30f56083afb26a458ec28a6834f8ba472c82 Mon Sep 17 00:00:00 2001 From: Martha Cryan Date: Tue, 28 Jan 2025 17:17:09 -0600 Subject: [PATCH 5/9] Add in children that had been deleted --- dash/dash-renderer/src/components/error/menu/DebugMenu.react.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js b/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js index 1c631ef7e2..61629500fc 100644 --- a/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js +++ b/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js @@ -217,11 +217,11 @@ class DebugMenu extends Component { clickHandler={toggleErrors} errors={errors} connected={error.backEndConnected} - config={config} /> ) : undefined} {menuContent}
+ {this.props.children}
); } From 91e02dd1d3d8352209836e1951d18547ec8a129a Mon Sep 17 00:00:00 2001 From: Martha Cryan Date: Wed, 29 Jan 2025 11:21:09 -0600 Subject: [PATCH 6/9] Add more style and update wording of buttons --- .../error/FrontEnd/FrontEndError.css | 24 ++++----- .../src/components/error/menu/DebugMenu.css | 51 +++++++++++++++---- .../components/error/menu/DebugMenu.react.js | 21 ++++++-- 3 files changed, 69 insertions(+), 27 deletions(-) diff --git a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.css b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.css index 461fa9c2d8..a643ea8fba 100644 --- a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.css +++ b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.css @@ -16,6 +16,7 @@ background-color: #A159FF0D; border: 1px solid #864AD433; color: #7F4BC4; + margin-left: 10px; } .dash-debug-menu__upgrade-button:hover { @@ -56,9 +57,6 @@ } .dash-fe-error-top { width: 100%; - cursor: pointer; - border: 1px solid gray; - border-radius: 2px; } .dash-debug-menu__error-count { font-size: 12px; @@ -173,9 +171,9 @@ display: inline-block; /* shadow-1 */ border-radius: 4px; - position: fixed; - top: 16px; - right: 16px; + position: absolute; + bottom: 100%; + right: 0; animation: dash-error-card-animation 0.5s; padding: 24px; text-align: left; @@ -195,13 +193,15 @@ width: 422px; } .dash-error-card--container { - padding: 10px 10px; + padding: 10px 0; width: 600px; max-width: 800px; max-height: calc(100vh - 50px); - margin: 10px; + margin: 10px 0; + background-color: white; overflow: auto; z-index: 1100; /* above the plotly.js toolbar and Bootstrap components */ + box-shadow: 0 0 15px 6px #0000000D; } .dash-error-card__topbar { @@ -232,13 +232,13 @@ .dash-error-card__list-item { background: #ffffff; - box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.25), - 0px 1px 3px rgba(162, 177, 198, 0.32); border-radius: 2px; - padding: 10px 10px; - margin-bottom: 10px; display: flex; align-items: center; + border: 1px solid #0018661A; + padding: 10px; + margin: 10px; + cursor: pointer; } @keyframes dash-error-card-animation { diff --git a/dash/dash-renderer/src/components/error/menu/DebugMenu.css b/dash/dash-renderer/src/components/error/menu/DebugMenu.css index 254c201ab6..15e5860477 100644 --- a/dash/dash-renderer/src/components/error/menu/DebugMenu.css +++ b/dash/dash-renderer/src/components/error/menu/DebugMenu.css @@ -33,8 +33,8 @@ align-items: center; z-index: 10000; border-radius: 5px; - padding: 5px 78px 5px 5px; - background-color: #fff; + padding: 5px; + background-color: #F5F6FA; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.25), 0px 1px 3px rgba(162, 177, 198, 0.32); } @@ -48,31 +48,60 @@ .dash-debug-menu__upgrade-tooltip { position: absolute; - bottom: 100%; + bottom: calc(100% + 12px); right: 0; display: flex; flex-direction: column; background-color: white; + border-radius: 3px; + border: 1px solid #0018661A; + padding: 11px; + box-shadow: 0px 0px 14px 5px #00000012; + z-index: 1200; } .dash-debug-menu__status { margin: 3px; + display: flex; + align-items: center; +} +.dash-debug-menu__icon { + margin-left: 5px; } -.dash-debug-menu__upgrade-tooltip button { - background: none; +.dash-debug-menu__upgrade-tooltip button, +.dash-debug-menu__upgrade-tooltip a { + background: white; border: none; - padding: 5px; - border: 1px solid #d6d6d6; + padding: 0 5px; + white-space: nowrap; + color: #7F4BC4; + font-size: 10pt; + text-decoration: none; + font-family: none; + cursor: pointer; + display: flex; } -.dash-debug-menu__upgrade-tooltip button:hover { - background-color: #d6d6d6; + +.dash-debug-menu__upgrade-tooltip:after { + content: " "; + position: absolute; + top: 100%; + left: 50%; + margin-left: -5px; + border-width: 10px; + border-style: solid; + border-color: white transparent transparent transparent; } .dash-debug-menu__content { display: flex; - width: 100%; - height: 100%; + align-items: stretch; +} + +.dash-debug-menu__version { + position: relative; + display: flex; align-items: center; } diff --git a/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js b/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js index 61629500fc..fb88b2c0a8 100644 --- a/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js +++ b/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js @@ -83,6 +83,13 @@ class DebugMenu extends Component { errorsOpened: true, upgradeInfo: [] }; + + // Close the upgrade tooltip if the user clicks outside of it + document.addEventListener('click', () => { + if (this.state.upgradeTooltipOpened) { + this.setState({upgradeTooltipOpened: false}); + } + }); } render() { @@ -174,17 +181,23 @@ class DebugMenu extends Component { Callbacks
-
+
{this.state.upgradeTooltipOpened ? (
+ + Read details +
) : null} From dc5aaae275e211842e009692e06b80ec794e506d Mon Sep 17 00:00:00 2001 From: Martha Cryan Date: Wed, 29 Jan 2025 15:15:17 -0600 Subject: [PATCH 7/9] Add icons for error and callback graph and clean up styles --- .../error/FrontEnd/FrontEndError.css | 24 +++++------- .../error/FrontEnd/FrontEndError.react.js | 6 +-- .../src/components/error/icons/ErrorIcon.svg | 3 ++ .../src/components/error/icons/GraphIcon.svg | 4 +- .../src/components/error/menu/DebugMenu.css | 13 ++++--- .../components/error/menu/DebugMenu.react.js | 39 +++++++++++-------- 6 files changed, 46 insertions(+), 43 deletions(-) create mode 100644 dash/dash-renderer/src/components/error/icons/ErrorIcon.svg mode change 100755 => 100644 dash/dash-renderer/src/components/error/icons/GraphIcon.svg diff --git a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.css b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.css index a643ea8fba..b78b97d5e6 100644 --- a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.css +++ b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.css @@ -1,5 +1,5 @@ .error-container { - margin-top: 10px; + padding: 0 10px; } .dash-fe-error__icon-x { @@ -55,16 +55,13 @@ height: 28px; margin: 0px 8px; } -.dash-fe-error-top { - width: 100%; -} .dash-debug-menu__error-count { font-size: 12px; color: #fff; background-color: #C73A3A; - padding: 5px; + padding: 3px 5px; border-radius: 3px; - margin: 4px; + margin: 0 5px; } .dash-fe-error-top__group:first-child { /* @@ -193,11 +190,11 @@ width: 422px; } .dash-error-card--container { - padding: 10px 0; + padding: 20px; width: 600px; max-width: 800px; - max-height: calc(100vh - 50px); - margin: 10px 0; + max-height: calc(100vh - 125px); + margin-bottom: 7px; background-color: white; overflow: auto; z-index: 1100; /* above the plotly.js toolbar and Bootstrap components */ @@ -222,22 +219,21 @@ .dash-error-card__content { box-sizing: border-box; - padding: 10px 10px; background-color: white; - box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.25), - 0px 1px 3px rgba(162, 177, 198, 0.32); border-radius: 2px; margin-bottom: 8px; + border: 1px solid #0018661A; } -.dash-error-card__list-item { +.dash-fe-error-item { background: #ffffff; border-radius: 2px; display: flex; + justify-content: space-between; align-items: center; border: 1px solid #0018661A; padding: 10px; - margin: 10px; + margin: 10px 0; cursor: pointer; } diff --git a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.react.js b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.react.js index 022b4f7230..b81d6708de 100644 --- a/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.react.js +++ b/dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.react.js @@ -27,7 +27,7 @@ class FrontEndError extends Component { /* eslint-disable no-inline-comments */ const errorHeader = (
this.setState({collapsed: !collapsed})} > @@ -56,10 +56,9 @@ class FrontEndError extends Component {
); - /* eslint-enable no-inline-comments */ return collapsed ? ( -
{errorHeader}
+ <>{errorHeader} ) : (
{errorHeader} @@ -137,7 +136,6 @@ function UnconnectedErrorContent({error, base}) { * browser's dev tools. */ width: 'calc(600px - 67px)', - height: '75vh', border: 'none' }} /> diff --git a/dash/dash-renderer/src/components/error/icons/ErrorIcon.svg b/dash/dash-renderer/src/components/error/icons/ErrorIcon.svg new file mode 100644 index 0000000000..6ba3a3735a --- /dev/null +++ b/dash/dash-renderer/src/components/error/icons/ErrorIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/dash/dash-renderer/src/components/error/icons/GraphIcon.svg b/dash/dash-renderer/src/components/error/icons/GraphIcon.svg old mode 100755 new mode 100644 index ebe40eb706..0e4cf42f29 --- a/dash/dash-renderer/src/components/error/icons/GraphIcon.svg +++ b/dash/dash-renderer/src/components/error/icons/GraphIcon.svg @@ -1,3 +1,3 @@ - - + + diff --git a/dash/dash-renderer/src/components/error/menu/DebugMenu.css b/dash/dash-renderer/src/components/error/menu/DebugMenu.css index 15e5860477..1eb6a62ee0 100644 --- a/dash/dash-renderer/src/components/error/menu/DebugMenu.css +++ b/dash/dash-renderer/src/components/error/menu/DebugMenu.css @@ -66,14 +66,14 @@ align-items: center; } .dash-debug-menu__icon { - margin-left: 5px; + margin: 0 5px; } .dash-debug-menu__upgrade-tooltip button, .dash-debug-menu__upgrade-tooltip a { background: white; border: none; - padding: 0 5px; + padding: 2px 5px; white-space: nowrap; color: #7F4BC4; font-size: 10pt; @@ -97,6 +97,7 @@ .dash-debug-menu__content { display: flex; align-items: stretch; + margin: 10px; } .dash-debug-menu__version { @@ -106,10 +107,10 @@ } .dash-debug-menu__divider { - width: 1px; - height: 20px; - margin: 10px; - background-color: #e6e6e6; + width: 1.5px; + height: 26px; + margin: 0px 13px; + background-color: #0015594D; } .dash-debug-menu__button { diff --git a/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js b/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js index fb88b2c0a8..b989bbcec3 100644 --- a/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js +++ b/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js @@ -6,6 +6,8 @@ import './DebugMenu.css'; import CheckIcon from '../icons/CheckIcon.svg'; import ClockIcon from '../icons/ClockIcon.svg'; +import ErrorIcon from '../icons/ErrorIcon.svg'; +import GraphIcon from '../icons/GraphIcon.svg'; import OffIcon from '../icons/OffIcon.svg'; import {CallbackGraphContainer} from '../CallbackGraph/CallbackGraphContainer.react'; @@ -79,21 +81,23 @@ class DebugMenu extends Component { this.state = { opened: false, - callbackGraphOpened: false, - errorsOpened: true, + popup: 'errors', upgradeInfo: [] }; // Close the upgrade tooltip if the user clicks outside of it - document.addEventListener('click', () => { - if (this.state.upgradeTooltipOpened) { + document.addEventListener('click', e => { + if ( + this.state.upgradeTooltipOpened && + !e.target.closest('.dash-debug-menu__upgrade-button') + ) { this.setState({upgradeTooltipOpened: false}); } }); } render() { - const {callbackGraphOpened, errorsOpened, upgradeInfo} = this.state; + const {popup, upgradeInfo, upgradeTooltipOpened} = this.state; const {error, hotReload, config} = this.props; // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -128,19 +132,18 @@ class DebugMenu extends Component { const connected = error.backEndConnected; const toggleErrors = () => { - this.setState({ - errorsOpened: callbackGraphOpened ? true : !errorsOpened, - callbackGraphOpened: false - }); + this.setState({popup: popup == 'errors' ? null : 'errors'}); }; const toggleCallbackGraph = () => { - this.setState({callbackGraphOpened: !callbackGraphOpened}); + this.setState({ + popup: popup == 'callbackGraph' ? null : 'callbackGraph' + }); }; const toggleShowUpgradeTooltip = () => { this.setState({ - upgradeTooltipOpened: !this.state.upgradeTooltipOpened + upgradeTooltipOpened: !upgradeTooltipOpened }); }; @@ -154,15 +157,16 @@ class DebugMenu extends Component { const menuContent = (
- {callbackGraphOpened ? : null} + {popup == 'callbackGraph' ? : null}
@@ -210,7 +215,7 @@ class DebugMenu extends Component { className='dash-debug-menu__upgrade-button' onClick={toggleShowUpgradeTooltip} > - Upgrade to v{newDashVersion} + Dash update available - v{newDashVersion} ) : null}
@@ -225,7 +230,7 @@ class DebugMenu extends Component { return (
- {errorsOpened && errCount > 0 ? ( + {popup == 'errors' && errCount > 0 ? ( Date: Wed, 29 Jan 2025 16:03:54 -0600 Subject: [PATCH 8/9] Update logic for remind me later/skip this version --- .../components/error/menu/DebugMenu.react.js | 46 +++++++++---------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js b/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js index b989bbcec3..9f18148219 100644 --- a/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js +++ b/dash/dash-renderer/src/components/error/menu/DebugMenu.react.js @@ -15,6 +15,7 @@ import {FrontEndErrorContainer} from '../FrontEnd/FrontEndErrorContainer.react'; const classes = (base, variant, variant2) => `${base} ${base}--${variant}` + (variant2 ? ` ${base}--${variant2}` : ''); +const DAY_IN_MS = 86400000; function compareVersions(v1, v2) { const v1Parts = v1.split('.').map(Number); @@ -43,18 +44,20 @@ function shouldShowUpgradeNotification(currentDashVersion, newDashVersion) { return false; } else if ( lastDismissed && - Date.now() - Number(lastDismissed) > 7 * 24 * 60 * 60 * 1000 + Date.now() - Number(lastDismissed) > DAY_IN_MS ) { return true; - } else if (lastDismissedVersion) { - return ( - compareVersions( - localStorage.getItem('lastDismissedVersion'), - newDashVersion - ) < 0 - ); - } else { + } else if ( + lastDismissedVersion && + !lastDismissed && + compareVersions( + localStorage.getItem('lastDismissedVersion'), + newDashVersion + ) < 0 + ) { return true; + } else { + return !lastDismissed && !lastDismissedVersion; } } @@ -89,7 +92,9 @@ class DebugMenu extends Component { document.addEventListener('click', e => { if ( this.state.upgradeTooltipOpened && - !e.target.closest('.dash-debug-menu__upgrade-button') + !e.target.matches( + '.dash-debug-menu__version, .dash-debug-menu__version *' + ) ) { this.setState({upgradeTooltipOpened: false}); } @@ -99,35 +104,28 @@ class DebugMenu extends Component { render() { const {popup, upgradeInfo, upgradeTooltipOpened} = this.state; const {error, hotReload, config} = this.props; + const newDashVersion = upgradeInfo[0] + ? upgradeInfo[0].version + : undefined; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const setDontShowAgain = i => { + const setDontShowAgain = () => { // Set local storage to record the last dismissed notification localStorage.setItem('noNotifications', true); this.setState({upgradeTooltipOpened: false}); }; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const setRemindMeLater = i => { + const setRemindMeLater = () => { // Set local storage to record the last dismissed notification localStorage.setItem('lastDismissed', Date.now()); this.setState({upgradeTooltipOpened: false}); }; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const setSkipThisVersion = i => { + const setSkipThisVersion = () => { // Set local storage to record the last dismissed version - localStorage.setItem( - 'lastDismissedVersion', - upgradeInfo[i].version - ); + localStorage.setItem('lastDismissedVersion', newDashVersion); this.setState({upgradeTooltipOpened: false}); }; - const newDashVersion = upgradeInfo[0] - ? upgradeInfo[0].version - : undefined; - const errCount = error.frontEnd.length + error.backEnd.length; const connected = error.backEndConnected; From b6b421e132a53834fbfc3c8f7ae8a2ee0d07ebde Mon Sep 17 00:00:00 2001 From: Martha Cryan Date: Wed, 29 Jan 2025 16:13:07 -0600 Subject: [PATCH 9/9] Update style of icons --- dash/dash-renderer/src/components/error/icons/CheckIcon.svg | 2 +- dash/dash-renderer/src/components/error/icons/OffIcon.svg | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dash/dash-renderer/src/components/error/icons/CheckIcon.svg b/dash/dash-renderer/src/components/error/icons/CheckIcon.svg index dc2ccbb60d..1c56347c25 100644 --- a/dash/dash-renderer/src/components/error/icons/CheckIcon.svg +++ b/dash/dash-renderer/src/components/error/icons/CheckIcon.svg @@ -1,3 +1,3 @@ - + diff --git a/dash/dash-renderer/src/components/error/icons/OffIcon.svg b/dash/dash-renderer/src/components/error/icons/OffIcon.svg index 44f805eb6d..32c59923e8 100644 --- a/dash/dash-renderer/src/components/error/icons/OffIcon.svg +++ b/dash/dash-renderer/src/components/error/icons/OffIcon.svg @@ -1,3 +1,3 @@ - - + +