From 4cad01347fc1dfedaec560eb48cfce667ae75ded Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Wed, 15 Jun 2022 11:23:39 +0200 Subject: [PATCH 1/6] Add story book interaction row with parentId --- .../src/components/Interaction/Interaction.stories.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/addons/interactions/src/components/Interaction/Interaction.stories.tsx b/addons/interactions/src/components/Interaction/Interaction.stories.tsx index 2089cef4a2a0..e8eb8b74b0e6 100644 --- a/addons/interactions/src/components/Interaction/Interaction.stories.tsx +++ b/addons/interactions/src/components/Interaction/Interaction.stories.tsx @@ -49,6 +49,12 @@ export const WithParent: Story = { }, }; +export const WithParent: Story = { + args: { + call: { ...getCall(CallStates.DONE), parentId: 'parent-id' }, + }, +}; + export const Disabled: Story = { args: { ...Done.args, controlStates: { ...SubnavStories.args.controlStates, goto: false } }, }; From 9005d7f928bc35c1bd9b1ea50492fff6b0bd7acc Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Wed, 15 Jun 2022 12:11:00 +0200 Subject: [PATCH 2/6] Better story data --- .../src/components/Interaction/Interaction.stories.tsx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/addons/interactions/src/components/Interaction/Interaction.stories.tsx b/addons/interactions/src/components/Interaction/Interaction.stories.tsx index e8eb8b74b0e6..2089cef4a2a0 100644 --- a/addons/interactions/src/components/Interaction/Interaction.stories.tsx +++ b/addons/interactions/src/components/Interaction/Interaction.stories.tsx @@ -49,12 +49,6 @@ export const WithParent: Story = { }, }; -export const WithParent: Story = { - args: { - call: { ...getCall(CallStates.DONE), parentId: 'parent-id' }, - }, -}; - export const Disabled: Story = { args: { ...Done.args, controlStates: { ...SubnavStories.args.controlStates, goto: false } }, }; From b01fcc0f7a0d092084151774bc09bc4043255a7f Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Wed, 15 Jun 2022 15:50:34 +0200 Subject: [PATCH 3/6] Collapse child interactions --- addons/interactions/src/Panel.tsx | 31 +++++++- .../components/Interaction/Interaction.tsx | 70 +++++++++++++++---- 2 files changed, 86 insertions(+), 15 deletions(-) diff --git a/addons/interactions/src/Panel.tsx b/addons/interactions/src/Panel.tsx index 2778d1c2f1d2..dc06587140f0 100644 --- a/addons/interactions/src/Panel.tsx +++ b/addons/interactions/src/Panel.tsx @@ -28,7 +28,12 @@ interface InteractionsPanelProps { active: boolean; controls: Controls; controlStates: ControlStates; - interactions: (Call & { status?: CallStates })[]; + interactions: (Call & { + status?: CallStates; + childCallIds: Call['id'][]; + isExpanded: boolean; + toggleExpanded: () => void; + })[]; fileName?: string; hasException?: boolean; isPlaying?: boolean; @@ -97,6 +102,9 @@ export const AddonPanelPure: React.FC = React.memo( callsById={calls} controls={controls} controlStates={controlStates} + childCallIds={call.childCallIds} + isExpanded={call.isExpanded} + toggleExpanded={call.toggleExpanded} pausedAt={pausedAt} /> ))} @@ -125,13 +133,32 @@ export const Panel: React.FC = (props) => { const [isPlaying, setPlaying] = React.useState(false); const [isRerunAnimating, setIsRerunAnimating] = React.useState(false); const [scrollTarget, setScrollTarget] = React.useState(); + const [expanded, setExpanded] = React.useState>(new Set()); // Calls are tracked in a ref so we don't needlessly rerender. const calls = React.useRef>>(new Map()); const setCall = ({ status, ...call }: Call) => calls.current.set(call.id, call); const [log, setLog] = React.useState([]); - const interactions = log.map(({ callId, status }) => ({ ...calls.current.get(callId), status })); + const childCallMap = new Map(); + const interactions = log + .filter((call) => { + if (!call.parentId) return true; + childCallMap.set(call.parentId, (childCallMap.get(call.parentId) || []).concat(call.callId)); + return expanded.has(call.parentId); + }) + .map(({ callId, status }) => ({ + ...calls.current.get(callId), + status, + childCallIds: childCallMap.get(callId), + isExpanded: expanded.has(callId), + toggleExpanded: () => + setExpanded((ids) => { + if (ids.has(callId)) ids.delete(callId); + else ids.add(callId); + return new Set(ids); + }), + })); const endRef = React.useRef(); React.useEffect(() => { diff --git a/addons/interactions/src/components/Interaction/Interaction.tsx b/addons/interactions/src/components/Interaction/Interaction.tsx index ec1672027aa7..a7fe2052957e 100644 --- a/addons/interactions/src/components/Interaction/Interaction.tsx +++ b/addons/interactions/src/components/Interaction/Interaction.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { IconButton, Icons, TooltipNote, WithTooltip, Bar } from '@storybook/components'; import { Call, CallStates, ControlStates } from '@storybook/instrumenter'; import { styled, typography } from '@storybook/theming'; import { transparentize } from 'polished'; @@ -55,9 +56,15 @@ const RowContainer = styled('div', { } ); +const RowHeader = styled.div<{ disabled: boolean }>(({ theme, disabled }) => ({ + display: 'flex', + '&:hover': disabled ? {} : { background: theme.background.hoverable }, +})); + const RowLabel = styled('button', { shouldForwardProp: (prop) => !['call'].includes(prop) })< React.ButtonHTMLAttributes & { call: Call } >(({ theme, disabled, call }) => ({ + flex: 1, display: 'grid', background: 'none', border: 0, @@ -68,7 +75,6 @@ const RowLabel = styled('button', { shouldForwardProp: (prop) => !['call'].inclu padding: '8px 15px', textAlign: 'start', cursor: disabled || call.status === CallStates.ERROR ? 'default' : 'pointer', - '&:hover': disabled ? {} : { background: theme.background.hoverable }, '&:focus-visible': { outline: 0, boxShadow: `inset 3px 0 0 0 ${ @@ -81,6 +87,19 @@ const RowLabel = styled('button', { shouldForwardProp: (prop) => !['call'].inclu }, })); +const RowActions = styled.div(({ theme }) => ({ + padding: 6, +})); + +export const StyledIconButton = styled(IconButton as any)(({ theme }) => ({ + color: theme.color.mediumdark, + margin: '0 3px', +})); + +const Note = styled(TooltipNote)(({ theme }) => ({ + fontFamily: theme.typography.fonts.base, +})); + const RowMessage = styled('div')(({ theme }) => ({ padding: '8px 10px 8px 36px', fontSize: typography.size.s1, @@ -112,29 +131,54 @@ export const Interaction = ({ callsById, controls, controlStates, + childCallIds, + isExpanded, + toggleExpanded, pausedAt, }: { call: Call; callsById: Map; controls: Controls; controlStates: ControlStates; + childCallIds?: Call['id'][]; + isExpanded: boolean; + toggleExpanded: () => void; pausedAt?: Call['id']; }) => { const [isHovered, setIsHovered] = React.useState(false); return ( - controls.goto(call.id)} - disabled={!controlStates.goto || !call.interceptable || !!call.parentId} - onMouseEnter={() => controlStates.goto && setIsHovered(true)} - onMouseLeave={() => controlStates.goto && setIsHovered(false)} - > - - - - - + + controls.goto(call.id)} + disabled={!controlStates.goto || !call.interceptable || !!call.parentId} + onMouseEnter={() => controlStates.goto && setIsHovered(true)} + onMouseLeave={() => controlStates.goto && setIsHovered(false)} + > + + + + + + + {childCallIds?.length > 0 && ( + + } + > + + + + + )} + + + {call.status === CallStates.ERROR && call.exception?.callId === call.id && ( )} From d226b56d2d8089ea8c0dc7271b5041c686a65bc1 Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Thu, 16 Jun 2022 15:21:16 +0200 Subject: [PATCH 4/6] Expand by default --- addons/interactions/src/Panel.tsx | 18 +++++++++--------- .../src/components/Interaction/Interaction.tsx | 12 ++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/addons/interactions/src/Panel.tsx b/addons/interactions/src/Panel.tsx index dc06587140f0..fcd6918cfcf5 100644 --- a/addons/interactions/src/Panel.tsx +++ b/addons/interactions/src/Panel.tsx @@ -31,8 +31,8 @@ interface InteractionsPanelProps { interactions: (Call & { status?: CallStates; childCallIds: Call['id'][]; - isExpanded: boolean; - toggleExpanded: () => void; + isCollapsed: boolean; + toggleCollapsed: () => void; })[]; fileName?: string; hasException?: boolean; @@ -103,8 +103,8 @@ export const AddonPanelPure: React.FC = React.memo( controls={controls} controlStates={controlStates} childCallIds={call.childCallIds} - isExpanded={call.isExpanded} - toggleExpanded={call.toggleExpanded} + isCollapsed={call.isCollapsed} + toggleCollapsed={call.toggleCollapsed} pausedAt={pausedAt} /> ))} @@ -133,7 +133,7 @@ export const Panel: React.FC = (props) => { const [isPlaying, setPlaying] = React.useState(false); const [isRerunAnimating, setIsRerunAnimating] = React.useState(false); const [scrollTarget, setScrollTarget] = React.useState(); - const [expanded, setExpanded] = React.useState>(new Set()); + const [collapsed, setCollapsed] = React.useState>(new Set()); // Calls are tracked in a ref so we don't needlessly rerender. const calls = React.useRef>>(new Map()); @@ -145,15 +145,15 @@ export const Panel: React.FC = (props) => { .filter((call) => { if (!call.parentId) return true; childCallMap.set(call.parentId, (childCallMap.get(call.parentId) || []).concat(call.callId)); - return expanded.has(call.parentId); + return !collapsed.has(call.parentId); }) .map(({ callId, status }) => ({ ...calls.current.get(callId), status, childCallIds: childCallMap.get(callId), - isExpanded: expanded.has(callId), - toggleExpanded: () => - setExpanded((ids) => { + isCollapsed: collapsed.has(callId), + toggleCollapsed: () => + setCollapsed((ids) => { if (ids.has(callId)) ids.delete(callId); else ids.add(callId); return new Set(ids); diff --git a/addons/interactions/src/components/Interaction/Interaction.tsx b/addons/interactions/src/components/Interaction/Interaction.tsx index a7fe2052957e..768149e38f04 100644 --- a/addons/interactions/src/components/Interaction/Interaction.tsx +++ b/addons/interactions/src/components/Interaction/Interaction.tsx @@ -132,8 +132,8 @@ export const Interaction = ({ controls, controlStates, childCallIds, - isExpanded, - toggleExpanded, + isCollapsed, + toggleCollapsed, pausedAt, }: { call: Call; @@ -141,8 +141,8 @@ export const Interaction = ({ controls: Controls; controlStates: ControlStates; childCallIds?: Call['id'][]; - isExpanded: boolean; - toggleExpanded: () => void; + isCollapsed: boolean; + toggleCollapsed: () => void; pausedAt?: Call['id']; }) => { const [isHovered, setIsHovered] = React.useState(false); @@ -167,11 +167,11 @@ export const Interaction = ({ hasChrome={false} tooltip={ } > - + From 3b789478d314b29229ffc19ce54c69a3a3245de3 Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Thu, 16 Jun 2022 15:21:37 +0200 Subject: [PATCH 5/6] Tweak anonymous function color --- addons/interactions/src/components/MethodCall.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/addons/interactions/src/components/MethodCall.tsx b/addons/interactions/src/components/MethodCall.tsx index e74e02e6340e..fa792dce56aa 100644 --- a/addons/interactions/src/components/MethodCall.tsx +++ b/addons/interactions/src/components/MethodCall.tsx @@ -272,7 +272,11 @@ export const ClassNode = ({ name }: { name: string }) => { export const FunctionNode = ({ name }: { name: string }) => { const colors = useThemeColors(); - return {name || anonymous}; + return name ? ( + {name} + ) : ( + anonymous + ); }; export const ElementNode = ({ From 7defcafa06924a70681296331cefb9aef6f9c2f7 Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Thu, 16 Jun 2022 15:56:47 +0200 Subject: [PATCH 6/6] Update addons/interactions/src/components/Interaction/Interaction.tsx Co-authored-by: Michael Shilman --- addons/interactions/src/components/Interaction/Interaction.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/interactions/src/components/Interaction/Interaction.tsx b/addons/interactions/src/components/Interaction/Interaction.tsx index 768149e38f04..30922f8dc908 100644 --- a/addons/interactions/src/components/Interaction/Interaction.tsx +++ b/addons/interactions/src/components/Interaction/Interaction.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { IconButton, Icons, TooltipNote, WithTooltip, Bar } from '@storybook/components'; +import { IconButton, Icons, TooltipNote, WithTooltip } from '@storybook/components'; import { Call, CallStates, ControlStates } from '@storybook/instrumenter'; import { styled, typography } from '@storybook/theming'; import { transparentize } from 'polished';