Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 4ee0a38

Browse files
ohltylergithub-actions[bot]
authored andcommittedMay 30, 2024·
Add a Tools collapsible panel (#162)
Signed-off-by: Tyler Ohlsen <ohltyler@amazon.com> (cherry picked from commit 8a965a3)
1 parent 8f1f02b commit 4ee0a38

File tree

12 files changed

+299
-195
lines changed

12 files changed

+299
-195
lines changed
 

‎public/pages/workflow_detail/components/header.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export function WorkflowDetailHeader(props: WorkflowDetailHeaderProps) {
4141

4242
return (
4343
<EuiPageHeader
44+
style={{ marginTop: '-8px' }}
4445
pageTitle={
4546
<EuiFlexGroup direction="row" alignItems="flexEnd" gutterSize="m">
4647
<EuiFlexItem grow={false}>{getTitle()}</EuiFlexItem>
@@ -55,7 +56,7 @@ export function WorkflowDetailHeader(props: WorkflowDetailHeaderProps) {
5556
Export
5657
</EuiButton>,
5758
]}
58-
bottomBorder={true}
59+
bottomBorder={false}
5960
/>
6061
);
6162
}

‎public/pages/workflow_detail/resizable_workspace.tsx

+125-115
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,20 @@
66
import React, { useRef, useState, useEffect } from 'react';
77
import { useSelector } from 'react-redux';
88
import { useHistory } from 'react-router-dom';
9-
import { useReactFlow } from 'reactflow';
109
import { Form, Formik, FormikProps } from 'formik';
1110
import * as yup from 'yup';
12-
import { EuiFlexGroup, EuiFlexItem, EuiResizableContainer } from '@elastic/eui';
11+
import {
12+
EuiFlexGroup,
13+
EuiFlexItem,
14+
EuiPanel,
15+
EuiResizableContainer,
16+
EuiTitle,
17+
} from '@elastic/eui';
1318
import { getCore } from '../../services';
1419

1520
import {
1621
Workflow,
17-
ReactFlowComponent,
1822
WORKFLOW_STATE,
19-
ReactFlowEdge,
2023
WorkflowFormValues,
2124
WorkflowSchema,
2225
WorkflowConfig,
@@ -35,20 +38,22 @@ import {
3538
updateWorkflow,
3639
useAppDispatch,
3740
} from '../../store';
41+
import { WorkflowInputs } from './workflow_inputs';
42+
import { configToTemplateFlows } from './utils';
3843
import { Workspace } from './workspace';
3944

4045
// styling
4146
import './workspace/workspace-styles.scss';
4247
import '../../global-styles.scss';
43-
import { WorkflowInputs } from './workflow_inputs';
44-
import { configToTemplateFlows } from './utils';
48+
import { Tools } from './tools';
4549

4650
interface ResizableWorkspaceProps {
4751
isNewWorkflow: boolean;
4852
workflow?: Workflow;
4953
}
5054

5155
const WORKFLOW_INPUTS_PANEL_ID = 'workflow_inputs_panel_id';
56+
const TOOLS_PANEL_ID = 'tools_panel_id';
5257

5358
/**
5459
* The overall workspace component that maintains state related to the 2 resizable
@@ -75,21 +80,29 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
7580
// Validation states
7681
const [formValidOnSubmit, setFormValidOnSubmit] = useState<boolean>(true);
7782

78-
// Component details side panel state
79-
const [isDetailsPanelOpen, setisDetailsPanelOpen] = useState<boolean>(true);
80-
const collapseFn = useRef(
83+
// Workflow inputs side panel state
84+
const [isWorkflowInputsPanelOpen, setIsWorkflowInputsPanelOpen] = useState<
85+
boolean
86+
>(true);
87+
const collapseFnHorizontal = useRef(
8188
(id: string, options: { direction: 'left' | 'right' }) => {}
8289
);
83-
const onToggleChange = () => {
84-
collapseFn.current(WORKFLOW_INPUTS_PANEL_ID, { direction: 'left' });
85-
setisDetailsPanelOpen(!isDetailsPanelOpen);
90+
const onToggleWorkflowInputsChange = () => {
91+
collapseFnHorizontal.current(WORKFLOW_INPUTS_PANEL_ID, {
92+
direction: 'left',
93+
});
94+
setIsWorkflowInputsPanelOpen(!isWorkflowInputsPanelOpen);
8695
};
8796

88-
// Selected component state
89-
const reactFlowInstance = useReactFlow();
90-
const [selectedComponent, setSelectedComponent] = useState<
91-
ReactFlowComponent
92-
>();
97+
// Tools side panel state
98+
const [isToolsPanelOpen, setIsToolsPanelOpen] = useState<boolean>(true);
99+
const collapseFnVertical = useRef(
100+
(id: string, options: { direction: 'top' | 'bottom' }) => {}
101+
);
102+
const onToggleToolsChange = () => {
103+
collapseFnVertical.current(TOOLS_PANEL_ID, { direction: 'bottom' });
104+
setIsToolsPanelOpen(!isToolsPanelOpen);
105+
};
93106

94107
// Save/provision/deprovision button state
95108
const isSaveable =
@@ -116,31 +129,6 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
116129
const isLoadingGlobal =
117130
loading || isProvisioning || isDeprovisioning || isSaving || isCreating;
118131

119-
/**
120-
* Custom listener on when nodes are selected / de-selected. Passed to
121-
* downstream ReactFlow components you can listen using
122-
* the out-of-the-box useOnSelectionChange hook.
123-
* - populate panel content appropriately
124-
* - open the panel if a node is selected and the panel is closed
125-
* - it is assumed that only one node can be selected at once
126-
*/
127-
function onSelectionChange({
128-
nodes,
129-
edges,
130-
}: {
131-
nodes: ReactFlowComponent[];
132-
edges: ReactFlowEdge[];
133-
}) {
134-
if (nodes && nodes.length > 0) {
135-
setSelectedComponent(nodes[0]);
136-
if (!isDetailsPanelOpen) {
137-
onToggleChange();
138-
}
139-
} else {
140-
setSelectedComponent(undefined);
141-
}
142-
}
143-
144132
// Hook to update some default values for the workflow, if applicable.
145133
// We need to handle different scenarios:
146134
// 1. Rendering backend-only-created workflow / an already-created workflow with no ui_metadata.
@@ -171,19 +159,6 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
171159
}
172160
}, [props.workflow]);
173161

174-
// Hook to updated the selected ReactFlow component
175-
useEffect(() => {
176-
reactFlowInstance?.setNodes((nodes: ReactFlowComponent[]) =>
177-
nodes.map((node) => {
178-
node.data = {
179-
...node.data,
180-
selected: node.id === selectedComponent?.id ? true : false,
181-
};
182-
return node;
183-
})
184-
);
185-
}, [selectedComponent]);
186-
187162
// Initialize the form state to an existing workflow, if applicable.
188163
useEffect(() => {
189164
if (workflow?.ui_metadata?.config) {
@@ -194,10 +169,6 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
194169
}
195170
}, [workflow]);
196171

197-
// TODO: leave as a placeholder for now. Current functionality is the workflow
198-
// is readonly and only reacts/changes when the underlying form is updated.
199-
function onNodesChange(nodes: ReactFlowComponent[]): void {}
200-
201172
/**
202173
* Function to pass down to the Formik <Form> components as a listener to propagate
203174
* form changes to this parent component to re-enable save button, etc.
@@ -275,41 +246,20 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
275246
>
276247
{(formikProps) => (
277248
<Form>
278-
{/*
279-
TODO: finalize where/how to show invalidations
280-
*/}
281-
{/* {!formValidOnSubmit && (
282-
<EuiCallOut
283-
title="There are empty or invalid fields"
284-
color="danger"
285-
iconType="alert"
286-
style={{ marginBottom: '16px' }}
287-
>
288-
Please address the highlighted fields and try saving again.
289-
</EuiCallOut>
290-
)}
291-
{isDeprovisionable && isDirty && (
292-
<EuiCallOut
293-
title="The configured flow has been provisioned"
294-
color="warning"
295-
iconType="alert"
296-
style={{ marginBottom: '16px' }}
297-
>
298-
Changes cannot be saved until the workflow has first been
299-
deprovisioned.
300-
</EuiCallOut>
301-
)} */}
302249
<EuiResizableContainer
303250
direction="horizontal"
304251
className="stretch-absolute"
305252
style={{
306-
marginLeft: '-8px',
253+
marginLeft: isWorkflowInputsPanelOpen ? '-8px' : '0px',
254+
marginTop: '-8px',
307255
}}
308256
>
309257
{(EuiResizablePanel, EuiResizableButton, { togglePanel }) => {
310258
if (togglePanel) {
311-
collapseFn.current = (panelId: string, { direction }) =>
312-
togglePanel(panelId, { direction });
259+
collapseFnHorizontal.current = (
260+
panelId: string,
261+
{ direction }
262+
) => togglePanel(panelId, { direction });
313263
}
314264

315265
return (
@@ -320,46 +270,106 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
320270
initialSize={50}
321271
minSize="25%"
322272
paddingSize="s"
323-
onToggleCollapsedInternal={() => onToggleChange()}
273+
onToggleCollapsedInternal={() =>
274+
onToggleWorkflowInputsChange()
275+
}
324276
>
325-
<EuiFlexGroup
326-
direction="column"
327-
gutterSize="s"
328-
className="workspace-panel"
329-
>
330-
<EuiFlexItem>
331-
<WorkflowInputs
332-
workflow={props.workflow}
333-
formikProps={formikProps}
334-
onFormChange={onFormChange}
335-
validateAndSubmit={validateAndSubmit}
336-
/>
337-
</EuiFlexItem>
338-
</EuiFlexGroup>
277+
<WorkflowInputs
278+
workflow={props.workflow}
279+
formikProps={formikProps}
280+
onFormChange={onFormChange}
281+
validateAndSubmit={validateAndSubmit}
282+
/>
339283
</EuiResizablePanel>
340284
<EuiResizableButton />
341285
<EuiResizablePanel
342-
style={{ marginRight: '-16px' }}
286+
style={{
287+
marginRight: '-32px',
288+
marginBottom: isToolsPanelOpen ? '0px' : '24px',
289+
}}
343290
mode="main"
344291
initialSize={60}
345292
minSize="25%"
346293
paddingSize="s"
347294
>
348-
<EuiFlexGroup
349-
direction="column"
350-
gutterSize="s"
295+
<EuiResizableContainer
351296
className="workspace-panel"
297+
direction="vertical"
298+
style={{
299+
marginLeft: '-8px',
300+
marginTop: '-8px',
301+
padding: 'none',
302+
}}
352303
>
353-
<EuiFlexItem>
354-
<Workspace
355-
id="ingest"
356-
workflow={workflow}
357-
readonly={false}
358-
onNodesChange={onNodesChange}
359-
onSelectionChange={onSelectionChange}
360-
/>
361-
</EuiFlexItem>
362-
</EuiFlexGroup>
304+
{(
305+
EuiResizablePanel,
306+
EuiResizableButton,
307+
{ togglePanel }
308+
) => {
309+
if (togglePanel) {
310+
collapseFnVertical.current = (
311+
panelId: string,
312+
{ direction }
313+
) =>
314+
// ignore is added since docs are incorrectly missing "top" and "bottom"
315+
// as valid direction options for vertically-configured resizable panels.
316+
// @ts-ignore
317+
togglePanel(panelId, { direction });
318+
}
319+
320+
return (
321+
<>
322+
<EuiResizablePanel
323+
mode="main"
324+
initialSize={60}
325+
minSize="25%"
326+
paddingSize="s"
327+
style={{ marginBottom: '-8px' }}
328+
>
329+
<EuiFlexGroup
330+
direction="column"
331+
gutterSize="s"
332+
style={{ height: '100%' }}
333+
>
334+
<EuiFlexItem>
335+
<Workspace
336+
id="ingest"
337+
workflow={workflow}
338+
readonly={false}
339+
/>
340+
</EuiFlexItem>
341+
</EuiFlexGroup>
342+
</EuiResizablePanel>
343+
<EuiResizableButton />
344+
<EuiResizablePanel
345+
id={TOOLS_PANEL_ID}
346+
mode="collapsible"
347+
initialSize={50}
348+
minSize="25%"
349+
paddingSize="s"
350+
onToggleCollapsedInternal={() =>
351+
onToggleToolsChange()
352+
}
353+
style={{ marginBottom: '-24px' }}
354+
>
355+
<EuiFlexGroup
356+
direction="column"
357+
gutterSize="s"
358+
style={{
359+
height: '100%',
360+
}}
361+
>
362+
<EuiFlexItem>
363+
<EuiPanel paddingSize="m">
364+
<Tools workflow={workflow} />
365+
</EuiPanel>
366+
</EuiFlexItem>
367+
</EuiFlexGroup>
368+
</EuiResizablePanel>
369+
</>
370+
);
371+
}}
372+
</EuiResizableContainer>
363373
</EuiResizablePanel>
364374
</>
365375
);

‎public/pages/workflow_detail/resources/resources.tsx

-38
This file was deleted.

‎public/pages/workflow_detail/resources/index.ts ‎public/pages/workflow_detail/tools/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
export { Resources } from './resources';
6+
export * from './tools';

0 commit comments

Comments
 (0)
Please sign in to comment.