From 67aa5a04702113015e1c10beb1964264b136aff9 Mon Sep 17 00:00:00 2001 From: James Bradford Date: Tue, 12 Sep 2023 17:24:11 -0700 Subject: [PATCH 01/12] show host name in BeaconRow --- .../src/views/Campaign/Explore/Panels/Beacon/BeaconRow.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/client/src/views/Campaign/Explore/Panels/Beacon/BeaconRow.tsx b/applications/client/src/views/Campaign/Explore/Panels/Beacon/BeaconRow.tsx index 669bdec7..aa4d558d 100644 --- a/applications/client/src/views/Campaign/Explore/Panels/Beacon/BeaconRow.tsx +++ b/applications/client/src/views/Campaign/Explore/Panels/Beacon/BeaconRow.tsx @@ -132,7 +132,7 @@ export const BeaconRow = observer(({ beacon, ...props }) => { color={beacon.meta?.[0]?.current?.color || undefined} /> - {beacon?.computedName || `${beacon.server?.computedName}`} + {beacon?.computedNameWithHost || `${beacon.server?.computedName}`} From 8cb8e69ac9ced545259c05cc7b217fd0f9c5c2e5 Mon Sep 17 00:00:00 2001 From: James Bradford Date: Wed, 13 Sep 2023 09:32:01 -0700 Subject: [PATCH 02/12] Show More Labels: add graph className.hiddenLabel rather than setting display:none; --- .../client/src/views/Campaign/Graph/Graph.tsx | 7 +++++- .../src/views/Campaign/Graph/graph-styles.tsx | 24 +++++++++++++++---- .../src/GraphRenderers/SubGraphRenderer.ts | 2 +- .../src/GraphRenderers/SuperGraphRenderer.ts | 6 ++--- .../graph/src/GraphRenderers/layout-utils.ts | 1 + packages/graph/src/style.css | 3 +++ 6 files changed, 34 insertions(+), 9 deletions(-) diff --git a/applications/client/src/views/Campaign/Graph/Graph.tsx b/applications/client/src/views/Campaign/Graph/Graph.tsx index ad956839..3c027de9 100644 --- a/applications/client/src/views/Campaign/Graph/Graph.tsx +++ b/applications/client/src/views/Campaign/Graph/Graph.tsx @@ -70,7 +70,12 @@ export const Graph = observer((props) => { ) : null} diff --git a/applications/client/src/views/Campaign/Graph/graph-styles.tsx b/applications/client/src/views/Campaign/Graph/graph-styles.tsx index b62e60d5..05051f2a 100644 --- a/applications/client/src/views/Campaign/Graph/graph-styles.tsx +++ b/applications/client/src/views/Campaign/Graph/graph-styles.tsx @@ -19,15 +19,22 @@ export const graphStyles = css` cursor: pointer; /* &:active { cursor: grabbing; } */ } - .${GCN.groupNode} { - /* pointer-events: none; */ // set in code - } + /* .${GCN.groupNode} { pointer-events: none; } // set in GroupGraphRenderer */ &:not(.${GCN.isZooming}) .${GCN.superNode} { transition: r 0.2s cubic-bezier(0, 1, 0, 1); } - .${GCN.occludedLabel}, .${GCN.subNodeNameLabel}:not(.${GCN.selectedFocus}):not(.${GCN.previewedFocus}) { + + /* HIDE LABELS */ + .${GCN.occludedLabel}, .${GCN.hiddenLabel} { display: none; } + .${GCN.subNodeNameLabel} { + // &:not(...) is to avoid incorrectly applied syntax error + &:not(.${GCN.selectedFocus}):not(.${GCN.previewedFocus}) { + display: none; + } + } + .${GCN.parentLinkNode} { display: none; } @@ -164,3 +171,12 @@ export const graphStyles = css` } } `; + +export const showMoreLabelsGraphStyles = css` + .${GCN.hiddenLabel} { + display: initial; // show more labels + } + .${GCN.superNodeCountLabel}.${GCN.hiddenLabel} { + display: none; // but still hide the counts + } +`; diff --git a/packages/graph/src/GraphRenderers/SubGraphRenderer.ts b/packages/graph/src/GraphRenderers/SubGraphRenderer.ts index 4635636b..59281a93 100644 --- a/packages/graph/src/GraphRenderers/SubGraphRenderer.ts +++ b/packages/graph/src/GraphRenderers/SubGraphRenderer.ts @@ -127,7 +127,7 @@ export class SubGraphRenderer extends HierarchicalGraphRenderer { } drawInteraction() { - this.labelSelection?.style('display', (d) => (isInteractionRelated(d) ? '' : 'none')); + this.labelSelection?.classed(classNames.hiddenLabel, (d) => !isInteractionRelated(d)); if (isInteractionFocus(this.parentNode!)) { this.showLayout(); diff --git a/packages/graph/src/GraphRenderers/SuperGraphRenderer.ts b/packages/graph/src/GraphRenderers/SuperGraphRenderer.ts index 9ac9bb73..ba8526b5 100644 --- a/packages/graph/src/GraphRenderers/SuperGraphRenderer.ts +++ b/packages/graph/src/GraphRenderers/SuperGraphRenderer.ts @@ -126,7 +126,7 @@ export class SuperGraphRenderer extends HierarchicalGraphRenderer { .attr('id', assignIdLabel) .each(updateClassName) .classed(classNames.superNodeNameLabel, true) - .style('display', 'none') // start hidden + .classed(classNames.hiddenLabel, true) // start hidden .text(createLabel); this.countLabelSelection = this.rootGroupSelection @@ -177,8 +177,8 @@ export class SuperGraphRenderer extends HierarchicalGraphRenderer { drawInteraction() { this.drawDynamicLayout(); - this.countLabelSelection?.style('display', (d) => (isInteractionFocus(d) ? 'none' : '')); - this.labelSelection?.style('display', (d) => (isInteractionRelated(d) ? '' : 'none')); + this.countLabelSelection?.classed(classNames.hiddenLabel, (d) => isInteractionFocus(d)); + this.labelSelection?.classed(classNames.hiddenLabel, (d) => !isInteractionRelated(d)); super.drawInteraction(); this.graphSelection.selectChildren().sort(interactionSort); } diff --git a/packages/graph/src/GraphRenderers/layout-utils.ts b/packages/graph/src/GraphRenderers/layout-utils.ts index 9060b1f3..48a94577 100644 --- a/packages/graph/src/GraphRenderers/layout-utils.ts +++ b/packages/graph/src/GraphRenderers/layout-utils.ts @@ -237,6 +237,7 @@ export const classNames = { superNodeNameLabel: 'superNodeNameLabel', subNodeNameLabel: 'subNodeNameLabel', occludedLabel: 'occludedLabel', + hiddenLabel: 'hiddenLabel', // Simulation Nodes & Links // keyNode: 'keyNode', diff --git a/packages/graph/src/style.css b/packages/graph/src/style.css index 0d0a4455..f130ffb7 100644 --- a/packages/graph/src/style.css +++ b/packages/graph/src/style.css @@ -56,6 +56,9 @@ text { .subNodeNameLabel:not(.selectedFocus):not(.previewedFocus) { opacity: 0.1; } +.hiddenLabel { + display: none; +} .graphRoot { cursor: grab; From 70dcf409cae5309bb76575ae0f7f6196001c7222 Mon Sep 17 00:00:00 2001 From: James Bradford Date: Wed, 13 Sep 2023 10:48:18 -0700 Subject: [PATCH 03/12] add graph toggleSimpleForces functionality --- .../client/src/views/Campaign/Graph/Graph.tsx | 16 +- .../views/Campaign/Graph/GraphControls.tsx | 232 ++++++++---------- packages/graph/src/GraphHandler.ts | 22 +- 3 files changed, 132 insertions(+), 138 deletions(-) diff --git a/applications/client/src/views/Campaign/Graph/Graph.tsx b/applications/client/src/views/Campaign/Graph/Graph.tsx index 3c027de9..241556a2 100644 --- a/applications/client/src/views/Campaign/Graph/Graph.tsx +++ b/applications/client/src/views/Campaign/Graph/Graph.tsx @@ -4,12 +4,12 @@ import { CampaignLoadingMessage, useStore } from '@redeye/client/store'; import { CoreTokens, Header, Spacer, ThemeClasses, Txt } from '@redeye/ui-styles'; import { observer } from 'mobx-react-lite'; import type { ComponentProps } from 'react'; -import { useEffect, useMemo, useRef } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; import { ErrorBoundary } from 'react-error-boundary'; import { useResizeDetector } from 'react-resize-detector'; import { nodeColorStyles } from './node-colors'; import { graphStyles } from './graph-styles'; -import { GraphControls } from './GraphControls'; +import { GraphControlFunctions, GraphControls } from './GraphControls'; import { LoadingOverlay } from './LoadingOverlay'; type GraphProps = ComponentProps<'div'> & {}; @@ -40,14 +40,20 @@ export const Graph = observer((props) => { } }, [graphRef, store.campaign.isLoading]); - const zoomControls = useMemo( + const [isSimpleForces, setIsSimpleForces] = useState(false); + + const zoomControls: Omit = useMemo( () => ({ zoomIn: () => store.campaign.graph?.zoomIn(), zoomOut: () => store.campaign.graph?.zoomOut(), zoomToFit: () => store.campaign.graph?.zoomToFit(), exportSVG: () => store.campaign.graph?.exportSVG(CoreTokens.Background3), + toggleSimpleForces: (on) => { + store.campaign.graph?.useForceMode(on ? 'simple' : 'graph'); + setIsSimpleForces(on); + }, }), - [] + [setIsSimpleForces] ); const currentMoment = store.settings.momentTz(store.campaign.timeline?.scrubberTime as Date); @@ -79,7 +85,7 @@ export const Graph = observer((props) => { ref={graphRef} className={store.settings.theme === 'dark' ? ThemeClasses.DARK : ThemeClasses.LIGHT} /> - + ); diff --git a/applications/client/src/views/Campaign/Graph/GraphControls.tsx b/applications/client/src/views/Campaign/Graph/GraphControls.tsx index 8363a70a..c7834651 100644 --- a/applications/client/src/views/Campaign/Graph/GraphControls.tsx +++ b/applications/client/src/views/Campaign/Graph/GraphControls.tsx @@ -1,5 +1,5 @@ import { Button, ButtonGroup, Classes, Divider } from '@blueprintjs/core'; -import { Add16, CenterSquare16, Close16, Export16, Help16, Subtract16 } from '@carbon/icons-react'; +import { Add16, CenterSquare16, Close16, Draggable16, Export16, Help16, Subtract16 } from '@carbon/icons-react'; import { css } from '@emotion/react'; import styled from '@emotion/styled'; import { CarbonIcon } from '@redeye/client/components'; @@ -10,144 +10,126 @@ import type { ComponentProps } from 'react'; import { useState } from 'react'; import { graphStyles } from './graph-styles'; -type GraphControlsProps = ComponentProps<'div'> & { +export type GraphControlFunctions = { zoomIn: () => void; zoomOut: () => void; zoomToFit: () => void; exportSVG: () => void; + toggleSimpleForces: (on: boolean) => void; + isSimpleForces: boolean; }; -export const GraphControls = observer(({ zoomIn, zoomOut, zoomToFit, exportSVG, ...props }) => { - const [isOpen, setIsOpen] = useState(false); +export const GraphControls = observer>( + ({ zoomIn, zoomOut, zoomToFit, exportSVG, toggleSimpleForces, isSimpleForces, ...props }) => { + const [isOpen, setIsOpen] = useState(false); - return ( -
- {isOpen ? ( -
+ return ( +
+ {isOpen ? ( +
+
+ ) : ( +
- ) : ( -
- ); -}); +
+ ); + } +); const rootStyle = css` display: flex; diff --git a/packages/graph/src/GraphHandler.ts b/packages/graph/src/GraphHandler.ts index da1605e2..bd748ec6 100644 --- a/packages/graph/src/GraphHandler.ts +++ b/packages/graph/src/GraphHandler.ts @@ -21,7 +21,7 @@ import { SuperGraphRenderer } from './GraphRenderers/SuperGraphRenderer'; import type { HierarchicalGraphRenderer } from './GraphRenderers/HierarchicalGraphRenderer'; import { textOcclusion, textOcclusionSort } from './GraphRenderers/textOcclusion'; import { initializeTesting, noOp } from './utils'; -import { NodeShape } from './GraphRenderers/polygon-utils'; +import type { NodeShape } from './GraphRenderers/polygon-utils'; /** The root graph handler for all subgraphs and interactions */ export class GraphHandler { @@ -65,8 +65,7 @@ export class GraphHandler { previouslyParsedGraphData, }); - this.svg = d3Select(element) - // + this.svg = d3Select(element) // .html('') .classed([classNames.graphRoot, 'dotGrid'].join(' '), true); this.resize(); @@ -354,12 +353,19 @@ export class GraphHandler { */ } - useGraphForces() { - this.graphRoot.callChildrenRecursively('useGraphForces'); - } - useSimpleForces() { - this.graphRoot.callChildrenRecursively('useSimpleForces'); + forceMode: ForceMode = 'graph'; + useForceMode(mode: ForceMode) { + if (mode === 'simple') { + this.graphRoot.callChildrenRecursively('useSimpleForces'); + this.forceMode = 'simple'; + } else { + // if (mode === 'graph') { + this.graphRoot.callChildrenRecursively('useGraphForces'); + this.forceMode = 'graph'; + } } static scaleRadius = (zk: number) => Math.min(zk, (zk - 1) * 0.3 + 1); } + +type ForceMode = 'graph' | 'simple'; From 3cdf0b328f84ec23b9d043478433db45d7245917 Mon Sep 17 00:00:00 2001 From: James Bradford Date: Wed, 13 Sep 2023 11:11:47 -0700 Subject: [PATCH 04/12] Show More Labels: add toggle button; add expanded modes for GraphControls --- .../client/src/views/Campaign/Graph/Graph.tsx | 25 ++--- .../views/Campaign/Graph/GraphControls.tsx | 91 ++++++++++++++----- .../src/views/Campaign/Graph/graph-styles.tsx | 7 ++ 3 files changed, 91 insertions(+), 32 deletions(-) diff --git a/applications/client/src/views/Campaign/Graph/Graph.tsx b/applications/client/src/views/Campaign/Graph/Graph.tsx index 241556a2..6ee49a21 100644 --- a/applications/client/src/views/Campaign/Graph/Graph.tsx +++ b/applications/client/src/views/Campaign/Graph/Graph.tsx @@ -8,8 +8,9 @@ import { useEffect, useMemo, useRef, useState } from 'react'; import { ErrorBoundary } from 'react-error-boundary'; import { useResizeDetector } from 'react-resize-detector'; import { nodeColorStyles } from './node-colors'; -import { graphStyles } from './graph-styles'; -import { GraphControlFunctions, GraphControls } from './GraphControls'; +import { graphStyles, showMoreLabelsGraphStyles } from './graph-styles'; +import type { GraphControlFunctions } from './GraphControls'; +import { GraphControls } from './GraphControls'; import { LoadingOverlay } from './LoadingOverlay'; type GraphProps = ComponentProps<'div'> & {}; @@ -40,9 +41,10 @@ export const Graph = observer((props) => { } }, [graphRef, store.campaign.isLoading]); + const [showMoreLabels, setShowMoreLabels] = useState(false); const [isSimpleForces, setIsSimpleForces] = useState(false); - const zoomControls: Omit = useMemo( + const zoomControls: GraphControlFunctions = useMemo( () => ({ zoomIn: () => store.campaign.graph?.zoomIn(), zoomOut: () => store.campaign.graph?.zoomOut(), @@ -52,8 +54,9 @@ export const Graph = observer((props) => { store.campaign.graph?.useForceMode(on ? 'simple' : 'graph'); setIsSimpleForces(on); }, + setShowMoreLabels, }), - [setIsSimpleForces] + [setIsSimpleForces, setShowMoreLabels] ); const currentMoment = store.settings.momentTz(store.campaign.timeline?.scrubberTime as Date); @@ -76,16 +79,16 @@ export const Graph = observer((props) => { ) : null} - + ); diff --git a/applications/client/src/views/Campaign/Graph/GraphControls.tsx b/applications/client/src/views/Campaign/Graph/GraphControls.tsx index c7834651..c78fcf2b 100644 --- a/applications/client/src/views/Campaign/Graph/GraphControls.tsx +++ b/applications/client/src/views/Campaign/Graph/GraphControls.tsx @@ -1,5 +1,14 @@ import { Button, ButtonGroup, Classes, Divider } from '@blueprintjs/core'; -import { Add16, CenterSquare16, Close16, Draggable16, Export16, Help16, Subtract16 } from '@carbon/icons-react'; +import { + Add16, + CenterSquare16, + Close16, + Export16, + Harbor16, + Help16, + StringText16, + Subtract16, +} from '@carbon/icons-react'; import { css } from '@emotion/react'; import styled from '@emotion/styled'; import { CarbonIcon } from '@redeye/client/components'; @@ -15,12 +24,24 @@ export type GraphControlFunctions = { zoomOut: () => void; zoomToFit: () => void; exportSVG: () => void; + isSimpleForces?: boolean; toggleSimpleForces: (on: boolean) => void; - isSimpleForces: boolean; + showMoreLabels?: boolean; + setShowMoreLabels: (on: boolean) => void; }; export const GraphControls = observer>( - ({ zoomIn, zoomOut, zoomToFit, exportSVG, toggleSimpleForces, isSimpleForces, ...props }) => { + ({ + zoomIn, + zoomOut, + zoomToFit, + exportSVG, + isSimpleForces = false, + toggleSimpleForces, + showMoreLabels = false, + setShowMoreLabels, + ...props + }) => { const [isOpen, setIsOpen] = useState(false); return ( @@ -88,25 +109,59 @@ export const GraphControls = observer - -