1+ import { useCallback , useEffect , useState } from 'react' ;
12import styled from 'styled-components' ;
2- import { useAppDispatch , useAppSelector } from '../../redux/hooks' ;
3- import {
4- EDITING_TYPE ,
5- builderActions ,
6- selectActiveFlow ,
7- } from '../../redux/modules/builder/builder.slice' ;
3+
4+ import { useAppDispatch , useAppLogic , useAppSelector } from '../../redux/hooks' ;
5+ import { selectActiveFlow } from '../../redux/modules/builder/builder.slice' ;
86import {
97 SubflowEntity ,
108 selectFlowEntityById ,
119} from '../../redux/modules/flow/flow.slice' ;
12- import { useCallback } from 'react' ;
1310
1411const StyledWorkspace = styled . div `
1512 display: flex;
@@ -18,25 +15,28 @@ const StyledWorkspace = styled.div`
1815 color: var(--color-text-sharp);
1916 font-size: 0.8em;
2017
21- p {
18+ .row {
2219 display: flex;
20+ align-items: center;
2321 gap: 5px;
2422
2523 margin: 0;
2624
27- .type {
25+ label {
2826 font-weight: bold;
2927 text-transform: capitalize;
28+ flex: 0 0 55px;
3029 }
30+ }
3131
32+ .title {
3233 .name {
3334 text-overflow: ellipsis;
3435 overflow: hidden;
3536 white-space: nowrap;
3637 }
3738
3839 i {
39- margin-left: 5px;
4040 color: var(--color-text-medium);
4141 cursor: pointer;
4242
@@ -45,61 +45,193 @@ const StyledWorkspace = styled.div`
4545 }
4646 }
4747 }
48+
49+ .control-group {
50+ display: flex;
51+ margin-top: 10px;
52+
53+ button,
54+ input {
55+ background-color: var(--color-background-element-light);
56+ border: 1px solid var(--color-border-sharp);
57+ border-right-style: none;
58+ color: var(--color-text-sharp);
59+ cursor: pointer;
60+ padding: 5px 10px;
61+ width: 30px;
62+ height: 30px;
63+
64+ &:first-child {
65+ border-radius: 2px 0 0 2px;
66+ }
67+
68+ &:last-child {
69+ border-right-style: solid;
70+ border-radius: 0 2px 2px 0;
71+ }
72+
73+ &.active,
74+ &:active {
75+ background-color: var(--color-background-element-medium);
76+ color: var(--color-active-text);
77+ }
78+ }
79+
80+ input:focus {
81+ background-color: var(--color-background-element-focus);
82+ outline: 0;
83+ }
84+ }
4885` ;
4986
5087export const Workspace = ( ) => {
5188 const dispatch = useAppDispatch ( ) ;
89+ const builderLogic = useAppLogic ( ) . builder ;
90+ const flowLogic = useAppLogic ( ) . flow ;
5291 const activeFlowId = useAppSelector ( selectActiveFlow ) ;
5392 const activeFlow = useAppSelector ( state =>
5493 activeFlowId ? selectFlowEntityById ( state , activeFlowId ) : null
5594 ) ;
5695
96+ const inputs = ( activeFlow as SubflowEntity ) ?. in ?. length ?? 0 ;
97+ const outputs = ( activeFlow as SubflowEntity ) ?. out ?. length ?? 0 ;
98+ const [ currentOutputs , setCurrentOutputs ] = useState ( outputs ) ;
99+
57100 const handleEditClick = useCallback ( ( ) => {
58- if ( ! activeFlowId || ! activeFlow ) {
101+ if ( ! activeFlowId ) {
59102 return ;
60103 }
61104
62- dispatch (
63- builderActions . setEditing ( {
64- id : activeFlowId ,
65- type : {
66- flow : EDITING_TYPE . FLOW ,
67- subflow : EDITING_TYPE . SUBFLOW ,
68- } [ activeFlow . type ] ,
69- data : {
70- info : activeFlow . info ,
71- name : activeFlow . name ,
72- env : activeFlow . env ,
73- ...{
74- flow : { } ,
75- subflow : {
76- color : ( activeFlow as SubflowEntity ) . color ,
77- icon : ( activeFlow as SubflowEntity ) . icon ,
78- category : ( activeFlow as SubflowEntity ) . category ,
79- inputLabels : ( activeFlow as SubflowEntity )
80- . inputLabels ,
81- outputLabels : ( activeFlow as SubflowEntity )
82- . outputLabels ,
83- } ,
84- } [ activeFlow . type ] ,
85- } ,
86- } )
87- ) ;
88- } , [ dispatch , activeFlowId , activeFlow ] ) ;
105+ dispatch ( builderLogic . editFlowEntityById ( activeFlowId ) ) ;
106+ } , [ dispatch , activeFlowId , builderLogic ] ) ;
107+
108+ const handleInputsChange = useCallback (
109+ ( inputs : number ) => {
110+ if ( ! activeFlowId || ! activeFlow || activeFlow . type !== 'subflow' ) {
111+ return ;
112+ }
113+
114+ dispatch ( flowLogic . updateSubflowInputs ( activeFlow , inputs ) ) ;
115+ } ,
116+ [ activeFlow , activeFlowId , dispatch , flowLogic ]
117+ ) ;
118+
119+ const handleOutputsChange = useCallback (
120+ ( outputs : number ) => {
121+ if ( ! activeFlowId || ! activeFlow || activeFlow . type !== 'subflow' ) {
122+ return ;
123+ }
124+
125+ dispatch ( flowLogic . updateSubflowOutputs ( activeFlow , outputs ) ) ;
126+ } ,
127+ [ activeFlow , activeFlowId , dispatch , flowLogic ]
128+ ) ;
129+
130+ const handleIncrementOutputs = useCallback ( ( ) => {
131+ const newOutputs = currentOutputs + 1 ;
132+ setCurrentOutputs ( newOutputs ) ;
133+ handleOutputsChange ( newOutputs ) ;
134+ } , [ currentOutputs , handleOutputsChange ] ) ;
135+
136+ const handleDecrementOutputs = useCallback ( ( ) => {
137+ const newOutputs = Math . max ( currentOutputs - 1 , 0 ) ;
138+ setCurrentOutputs ( newOutputs ) ;
139+ handleOutputsChange ( newOutputs ) ;
140+ } , [ currentOutputs , handleOutputsChange ] ) ;
141+
142+ const handleCurrentOutputsChange = useCallback (
143+ ( e : React . ChangeEvent < HTMLInputElement > ) => {
144+ const newOutputs = Number ( e . target . value ) ;
145+ setCurrentOutputs (
146+ Math . max ( isNaN ( newOutputs ) ? currentOutputs : newOutputs , 0 )
147+ ) ;
148+ } ,
149+ [ currentOutputs ]
150+ ) ;
151+
152+ const handleOutputsSubmit = useCallback (
153+ ( e : React . FormEvent < HTMLFormElement > ) => {
154+ e . preventDefault ( ) ;
155+ e . currentTarget . querySelector ( 'input' ) ?. blur ( ) ;
156+
157+ handleOutputsChange ( currentOutputs ) ;
158+ } ,
159+ [ currentOutputs , handleOutputsChange ]
160+ ) ;
161+
162+ useEffect ( ( ) => {
163+ setCurrentOutputs ( outputs ) ;
164+ } , [ outputs ] ) ;
89165
90166 return (
91- < StyledWorkspace className = "workspace" >
92- { activeFlow ? (
93- < p >
94- < span className = "type" > { activeFlow . type } :</ span > { ' ' }
95- < span className = "name" > { activeFlow . name } </ span >
96- < i
97- className = "fa-solid fa-pencil"
98- onClick = { handleEditClick }
99- />
100- </ p >
167+ < StyledWorkspace className = { `workspace ${ activeFlow ?. type ?? '' } ` } >
168+ { ! activeFlow ? (
169+ < p className = "empty" > No active workspace</ p >
101170 ) : (
102- < p > No active workspace</ p >
171+ < >
172+ < div className = "row title" >
173+ < label className = "type" > { activeFlow . type } :</ label > { ' ' }
174+ < span className = "name" > { activeFlow . name } </ span >
175+ < i
176+ className = "fa-solid fa-pencil"
177+ onClick = { handleEditClick }
178+ />
179+ </ div >
180+
181+ { activeFlow . type === 'subflow' && (
182+ < >
183+ < div className = "row inputs" >
184+ < label > Inputs: </ label >
185+ < span className = "control-group" >
186+ < button
187+ type = "button"
188+ className = { inputs === 0 ? 'active' : '' }
189+ onClick = { ( ) => handleInputsChange ( 0 ) }
190+ >
191+ 0
192+ </ button >
193+
194+ < button
195+ type = "button"
196+ className = { inputs === 1 ? 'active' : '' }
197+ onClick = { ( ) => handleInputsChange ( 1 ) }
198+ >
199+ 1
200+ </ button >
201+ </ span >
202+ </ div >
203+
204+ < div className = "row outputs" >
205+ < label > Outputs: </ label >
206+ < form
207+ className = "control-group"
208+ onSubmit = { handleOutputsSubmit }
209+ onBlur = { handleOutputsSubmit }
210+ >
211+ < button
212+ type = "button"
213+ onClick = { handleDecrementOutputs }
214+ >
215+ -
216+ </ button >
217+
218+ < input
219+ type = "text"
220+ value = { currentOutputs }
221+ onChange = { handleCurrentOutputsChange }
222+ />
223+
224+ < button
225+ type = "button"
226+ onClick = { handleIncrementOutputs }
227+ >
228+ +
229+ </ button >
230+ </ form >
231+ </ div >
232+ </ >
233+ ) }
234+ </ >
103235 ) }
104236 </ StyledWorkspace >
105237 ) ;
0 commit comments