Skip to content

Add collapse button to devtools #3241

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Mar 26, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
background: #ffffff;
display: inline-block;
/* shadow-1 */
box-shadow:
0px 6px 16px rgba(80, 103, 132, 0.165),
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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
}

.dash-be-error__str {
background-color: #F5F6FA;
background-color: #f5f6fa;
min-width: 386px;
width: 100%;
overflow: auto;
Expand Down Expand Up @@ -177,8 +177,7 @@
background-color: white;
overflow: auto;
border-radius: 6px;
box-shadow:
0px 0.7px 1.4px 0px rgba(0, 0, 0, 0.07),
box-shadow: 0px 0.7px 1.4px 0px rgba(0, 0, 0, 0.07),
0px 1.9px 4px 0px rgba(0, 0, 0, 0.05),
0px 4.5px 10px 0px rgba(0, 0, 0, 0.05);
}
Expand Down
1 change: 1 addition & 0 deletions dash/dash-renderer/src/components/error/icons/Expand.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 39 additions & 20 deletions dash/dash-renderer/src/components/error/menu/DebugMenu.css
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,14 @@
font-size: 14px;
border-radius: 0px;
letter-spacing: normal;
white-space: nowrap;
gap: 6px;
cursor: pointer;
border: none;
background: none;
outline: none;
display: flex;
align-items: center;
}

.dash-debug-menu__popup {
Expand All @@ -52,8 +59,7 @@
align-self: flex-end;
position: relative;
/* Shadow/Small */
box-shadow:
0px 0.7px 1.4px 0px rgba(0, 0, 0, 0.07),
box-shadow: 0px 0.7px 1.4px 0px rgba(0, 0, 0, 0.07),
0px 1.9px 4px 0px rgba(0, 0, 0, 0.05),
0px 4.5px 10px 0px rgba(0, 0, 0, 0.05);
}
Expand Down Expand Up @@ -113,30 +119,28 @@
transition: 0.3s;
box-sizing: border-box;
position: fixed;
bottom: 8px;
right: 8px;
bottom: -1px;
right: -1px;
display: flex;
color: black;
flex-direction: column;
flex-direction: row;
font-family: Verdana, sans-serif !important;
font-size: 14px;
justify-content: center;
justify-content: flex-end;
align-items: center;
z-index: 10000;
border-radius: 5px;
padding: 5px;
border-radius: 5px 0 0 0;
padding: 15px 0;
background-color: #f5f6fa;
box-shadow:
0px 0.8px 0.8px 0px rgba(0, 0, 0, 0.04),
box-shadow: 0px 0.8px 0.8px 0px rgba(0, 0, 0, 0.04),
0px 2.3px 2px 0px rgba(0, 0, 0, 0.03);
border: 1px solid rgba(0, 24, 102, 0.1);
}
.dash-debug-menu__outer--closed {
height: 60px;
width: 60px;
bottom: 37px;
right: 37px;
padding: 0;
.dash-debug-menu__outer.dash-debug-menu__outer--collapsed {
max-width: 50px;
}
.dash-debug-menu__outer.dash-debug-menu__outer--expanded {
max-width: 682px;
}

.dash-debug-menu__upgrade-tooltip {
Expand All @@ -153,6 +157,22 @@
z-index: 1200;
}

.dash-debug-menu__toggle {
color: #7f4bc4;
transition: 0.3s;
}
.dash-debug-menu__toggle--expanded {
transform: rotate(180deg);
}
.dash-debug-menu__error-indicator {
width: 8px;
height: 8px;
background-color: #DC3E42;
border-radius: 100%;
position: absolute;
right: 3px;
top: 13px;
}
.dash-debug-menu__status {
display: flex;
align-items: center;
Expand All @@ -162,7 +182,8 @@
.dash-debug-menu__content {
display: flex;
align-items: stretch;
margin: 10px;
margin-left: 15px;
transition: all 0.5s ease;
}

.dash-debug-menu__version {
Expand All @@ -186,7 +207,6 @@
justify-content: center;
align-items: center;
transition: background-color 0.2s;
cursor: pointer;
font-family: Verdana, sans-serif !important;
font-weight: bold;
color: black;
Expand All @@ -213,8 +233,7 @@
right: 29px;
z-index: 10002;
cursor: pointer;
box-shadow:
0px 0px 1px rgba(0, 0, 0, 0.25),
box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.25),
0px 1px 3px rgba(162, 177, 198, 0.32);
border-radius: 32px;
background-color: white;
Expand Down
160 changes: 96 additions & 64 deletions dash/dash-renderer/src/components/error/menu/DebugMenu.react.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {Component} from 'react';
import React, {useEffect, useState} from 'react';
import PropTypes from 'prop-types';
import {concat} from 'ramda';

Expand All @@ -9,13 +9,23 @@ 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 Expand from '../icons/Expand.svg';
import {VersionInfo} from './VersionInfo.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 isCollapsed = () => {
try {
return localStorage.getItem('dash_debug_menu_collapsed') === 'true';
} catch (e) {
// If localStorage is not available, default to false
return false;
}
};

const MenuContent = ({
hotReload,
connected,
Expand Down Expand Up @@ -77,76 +87,98 @@ const MenuContent = ({
Server
<_StatusIcon className='dash-debug-menu__icon' />
</div>
<div
className='dash-debug-menu__divider'
style={{marginRight: 0}}
/>
</div>
);
};

class DebugMenu extends Component {
constructor(props) {
super(props);
const DebugMenu = ({error, hotReload, config, children}) => {
const [popup, setPopup] = useState('errors');
const [collapsed, setCollapsed] = useState(isCollapsed);

const errCount = error.frontEnd.length + error.backEnd.length;
const connected = error.backEndConnected;

useEffect(() => {
if (errCount > 0 && popup == null) {
setPopup('errors');
}
}, [errCount]);

const toggleErrors = () => {
setPopup(popup == 'errors' ? null : 'errors');
};

const toggleCallbackGraph = () => {
setPopup(popup == 'callbackGraph' ? null : 'callbackGraph');
};

const toggleCollapsed = () => {
setCollapsed(!collapsed);
try {
localStorage.setItem('dash_debug_menu_collapsed', !collapsed);
} catch (e) {
// If localStorage is not available, do nothing
}
};

const errors = concat(error.frontEnd, error.backEnd);

const popupContent = (
<div className='dash-debug-menu__popup'>
{popup == 'callbackGraph' ? <CallbackGraphContainer /> : undefined}
{popup == 'errors' && errCount > 0 ? (
<FrontEndErrorContainer
clickHandler={toggleErrors}
errors={errors}
connected={error.backEndConnected}
/>
) : undefined}
</div>
);

this.state = {
opened: false,
popup: 'errors'
};
}
const menuContent = collapsed ? undefined : (
<MenuContent
popup={popup}
errCount={errCount}
toggleErrors={toggleErrors}
toggleCallbackGraph={toggleCallbackGraph}
config={config}
hotReload={hotReload}
connected={connected}
/>
);

render() {
const {popup} = this.state;
const {error, hotReload, config} = this.props;
const errCount = error.frontEnd.length + error.backEnd.length;
const connected = error.backEndConnected;

const toggleErrors = () => {
this.setState({popup: popup == 'errors' ? null : 'errors'});
};

const toggleCallbackGraph = () => {
this.setState({
popup: popup == 'callbackGraph' ? null : 'callbackGraph'
});
};

const errors = concat(error.frontEnd, error.backEnd);

const popupContent = (
<div className='dash-debug-menu__popup'>
{popup == 'callbackGraph' ? (
<CallbackGraphContainer />
) : undefined}
{popup == 'errors' && errCount > 0 ? (
<FrontEndErrorContainer
clickHandler={toggleErrors}
errors={errors}
connected={error.backEndConnected}
/>
) : undefined}
</div>
);

const menuContent = (
<MenuContent
popup={popup}
errCount={errCount}
toggleErrors={toggleErrors}
toggleCallbackGraph={toggleCallbackGraph}
config={config}
hotReload={hotReload}
connected={connected}
/>
);

return (
<div>
<div className={classes('dash-debug-menu__outer')}>
{popupContent}
{menuContent}
</div>
{this.props.children}
return (
<div>
<div
className={classes(
'dash-debug-menu__outer',
collapsed ? 'collapsed' : 'expanded'
)}
>
{popupContent}
{menuContent}
<button
onClick={toggleCollapsed}
className={classes(
'dash-debug-menu__toggle',
collapsed ? 'collapsed' : 'expanded'
)}
>
<Expand />
{errCount > 0 && collapsed ? (
<div className='dash-debug-menu__error-indicator' />
) : null}
</button>
</div>
);
}
}
{children}
</div>
);
};

DebugMenu.propTypes = {
children: PropTypes.object,
Expand Down