Skip to content

Commit

Permalink
Allow subflows to be created from tab manager and flow tree
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshuaCWebDeveloper committed May 23, 2024
1 parent 69787f1 commit 731ecd2
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 9 deletions.
132 changes: 126 additions & 6 deletions packages/flow-client/src/app/components/builder/tab-manager.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useRef } from 'react';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useDispatch } from 'react-redux';
import styled from 'styled-components';
import { v4 as uuidv4 } from 'uuid';
Expand All @@ -9,17 +9,20 @@ import {
selectActiveFlow,
selectNewFlowCounter,
selectOpenFlows,
selectTheme,
} from '../../redux/modules/builder/builder.slice';
import {
flowActions,
selectFlowEntities,
} from '../../redux/modules/flow/flow.slice';
import { FlowCanvas } from '../flow-canvas/flow-canvas';
import { Theme } from '../../themes';

const StyledTabManager = styled.div`
const StyledTabManager = styled.div<{ dropdownX: number; customTheme: Theme }>`
flex-grow: 1;
display: flex;
flex-direction: column;
position: relative;
text-wrap: nowrap;
.tab-container {
Expand Down Expand Up @@ -60,6 +63,12 @@ const StyledTabManager = styled.div`
text-wrap: nowrap;
transition: background-color 0.3s;
p i {
font-size: 0.7em;
margin-right: 0.5em;
vertical-align: middle;
}
.close-btn {
margin-left: 10px;
color: var(--color-danger);
Expand Down Expand Up @@ -119,6 +128,56 @@ const StyledTabManager = styled.div`
background-color: var(--color-background-element-medium);
}
}
.new-flow-dropdown {
position: absolute;
background-color: var(--color-background-element-light);
border: 1px solid var(--color-border-light);
border-radius: 0px;
box-shadow: 0 2px 5px
rgba(
0,
0,
0,
${props =>
({
dark: 1,
light: 0.2,
}[props.customTheme])}
);
z-index: 100;
top: calc(
var(--builder-tab-container-height) - 2px
); // Position below the button
left: ${props => props.dropdownX}px;
width: auto;
min-width: 150px;
p {
border-bottom: 1px solid var(--color-border-light);
margin: 0;
padding: 4px 10px;
font-weight: bold;
color: var(--color-text-sharp);
}
ul {
list-style: none;
padding: 0;
margin: 0;
li {
padding: 4px 10px;
cursor: pointer;
color: var(--color-text-sharp);
transition: background-color 0.3s;
&:hover {
background-color: var(--color-background-element-medium);
}
}
}
}
`;

export const TabManager = () => {
Expand All @@ -127,8 +186,12 @@ export const TabManager = () => {
const openFlows = useAppSelector(selectOpenFlows);
const activeFlow = useAppSelector(selectActiveFlow);
const flowCounter = useAppSelector(selectNewFlowCounter);
const theme = useAppSelector(selectTheme);

const tabContentRef = useRef<HTMLDivElement>(null);
// State to toggle dropdown visibility
const [showDropdown, setShowDropdown] = useState(false);
const [dropdownX, setDropdownX] = useState(0);

const switchTab = useCallback(
(tabId: string) => {
Expand All @@ -144,7 +207,21 @@ export const TabManager = () => {
[dispatch]
);

const createNewTab = useCallback(() => {
const handleNewTabClick = useCallback(
(e: React.MouseEvent) => {
// Adjust dropdown position to align with the button's horizontal position
setDropdownX(
e.currentTarget.getBoundingClientRect().left -
(document
.querySelector('.tab-manager')
?.getBoundingClientRect().left ?? 0)
);
setShowDropdown(!showDropdown);
},
[showDropdown]
);

const createNewFlow = useCallback(() => {
const flowId = uuidv4();
dispatch(
flowActions.addFlowEntity({
Expand All @@ -158,6 +235,25 @@ export const TabManager = () => {
);
dispatch(builderActions.addNewFlow(flowId));
dispatch(builderActions.setActiveFlow(flowId));
setShowDropdown(false); // Hide dropdown after selection
}, [dispatch, flowCounter]);

const createNewSubflow = useCallback(() => {
const subflowId = uuidv4();
dispatch(
flowActions.addFlowEntity({
id: subflowId,
type: 'subflow',
name: `New Subflow${flowCounter ? ` ${flowCounter}` : ''}`,
category: 'subflows',
color: '#ddaa99',
info: '',
env: [],
})
);
dispatch(builderActions.addNewFlow(subflowId));
dispatch(builderActions.setActiveFlow(subflowId));
setShowDropdown(false); // Hide dropdown after selection
}, [dispatch, flowCounter]);

useEffect(() => {
Expand All @@ -174,7 +270,11 @@ export const TabManager = () => {
}, []);

return (
<StyledTabManager>
<StyledTabManager
dropdownX={dropdownX}
className="tab-manager"
customTheme={theme}
>
<div className="tab-container">
<div
className="tab-content"
Expand All @@ -196,7 +296,16 @@ export const TabManager = () => {
}`}
onClick={() => switchTab(flowEntity.id)}
>
<p>{flowEntity.name}</p>
<p>
{flowEntity.type === 'flow' ? (
<i className="fas fa-map"></i>
) : (
<i className="fas fa-sitemap"></i>
)}

{flowEntity.name}
</p>

<span
className="close-btn"
onClick={e => {
Expand All @@ -211,11 +320,22 @@ export const TabManager = () => {
</div>
</div>

<button className="new-tab" onClick={createNewTab}>
<button className="new-tab" onClick={handleNewTabClick}>
<i className="fa fa-plus"></i>
</button>
</div>

{showDropdown && (
<div className="new-flow-dropdown">
<p>New...</p>

<ul>
<li onClick={createNewFlow}>New Flow</li>
<li onClick={createNewSubflow}>New Subflow</li>
</ul>
</div>
)}

<FlowCanvas key={activeFlow} flowId={activeFlow ?? undefined} />
</StyledTabManager>
);
Expand Down
28 changes: 28 additions & 0 deletions packages/flow-client/src/app/components/flow-tree/flow-tree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,25 @@ export const FlowTree = () => {
dispatch(builderActions.setActiveFlow(flowId));
}, [dispatch, flowCounter, getSelectedDirectory]);

const handleNewSubflow = useCallback(() => {
const subflowId = uuidv4();
dispatch(
flowActions.addFlowEntity({
id: subflowId,
type: 'subflow',
name: `New Subflow${flowCounter ? ` ${flowCounter}` : ''}`,
category: 'subflows',
color: '#ddaa99',
info: '',
env: [],
directory: getSelectedDirectory(),
})
);
dispatch(builderActions.addNewFlow(subflowId));
dispatch(builderActions.setActiveFlow(subflowId));
setSelectedItemId(subflowId);
}, [dispatch, flowCounter, getSelectedDirectory]);

const handleItemSelect = useCallback((item: TreeItemData) => {
setSelectedItemId(item.id);
}, []);
Expand Down Expand Up @@ -155,6 +174,15 @@ export const FlowTree = () => {
>
<i className="fas fa-file-circle-plus"></i>
</button>

<button
className="new-subflow"
onClick={handleNewSubflow}
data-tooltip-content="New Subflow"
data-tooltip-id="action-tooltip"
>
<i className="fas fa-calendar-plus"></i>
</button>
</div>

<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,8 +384,10 @@ export const TreeItem = ({
) : (
<i className="fas fa-chevron-down"></i>
)
) : item.type === 'flow' ? (
<i className="fas fa-map"></i>
) : (
<i className="fas fa-sitemap"></i> // Icon indicating a flow
<i className="fas fa-sitemap"></i>
)}

{isRenaming ? (
Expand Down
6 changes: 4 additions & 2 deletions packages/flow-client/src/app/redux/modules/flow/tree.logic.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { createSelector } from '@reduxjs/toolkit';
import {
DirectoryEntity,
FlowEntity,
SubflowEntity,
selectAllDirectories,
selectAllFlowEntities,
} from './flow.slice';
Expand All @@ -18,7 +20,7 @@ export type TreeDirectory = TreeItem & {
};

export type TreeFile = TreeItem & {
type: 'file';
type: FlowEntity['type'] | SubflowEntity['type'];
};

export type TreeItemData = TreeDirectory | TreeFile;
Expand Down Expand Up @@ -141,7 +143,7 @@ export class TreeLogic {
const item = {
id: entity.id,
name: entity.name,
type: 'file',
type: entity.type,
directory: directoryId,
directoryPath: `${directory.directoryPath}/${directory.name}`,
} as TreeFile;
Expand Down

0 comments on commit 731ecd2

Please sign in to comment.