@@ -51,6 +51,8 @@ const App: React.FC = () => {
5151 const [ messageApi , contextHolder ] = Antd . message . useMessage ( ) ;
5252 const [ generatedCode , setGeneratedCode ] = React . useState < string > ( '' ) ;
5353 const [ toolboxSettingsModalIsOpen , setToolboxSettingsModalIsOpen ] = React . useState ( false ) ;
54+ const [ project , setProject ] = React . useState < commonStorage . Project | null > ( null ) ;
55+ const [ tabItems , setTabItems ] = React . useState < Tabs . TabItem [ ] > ( [ ] ) ;
5456
5557 const [ shownPythonToolboxCategories , setShownPythonToolboxCategories ] = React . useState < Set < string > > ( new Set ( ) ) ;
5658 const blocksEditor = React . useRef < editor . Editor | null > ( null ) ;
@@ -115,160 +117,182 @@ const App: React.FC = () => {
115117 }
116118 } , [ currentModule , shownPythonToolboxCategories ] ) ;
117119
118- const openStorage = async ( ) => {
119- try {
120- const c = await clientSideStorage . openClientSideStorage ( ) ;
121- setStorage ( c ) ;
122- } catch ( e ) {
123- console . log ( 'Failed to open client side storage. Caught the following error...' ) ;
124- console . log ( e ) ;
120+ React . useEffect ( ( ) => {
121+ if ( project ) {
122+ const myTabs : Tabs . TabItem [ ] = [
123+ {
124+ key : project . modulePath ,
125+ title : 'Robot' ,
126+ type : Tabs . TabType . ROBOT
127+ } ] ;
128+ project . mechanisms . forEach ( mechanism => {
129+ myTabs . push (
130+ { key : mechanism . modulePath , title : mechanism . className , type : Tabs . TabType . MECHANISM }
131+ ) ;
132+ } ) ;
133+
134+ project . opModes . forEach ( opmode => {
135+ myTabs . push (
136+ { key : opmode . modulePath , title : opmode . className , type : Tabs . TabType . OPMODE }
137+ ) ;
138+ } ) ;
139+ setTabItems ( myTabs ) ;
140+ }
141+ else {
142+ setTabItems ( [ ] ) ;
125143 }
126- } ;
144+ } , [ project ] ) ;
145+
146+ const openStorage = async ( ) => {
147+ try {
148+ const c = await clientSideStorage . openClientSideStorage ( ) ;
149+ setStorage ( c ) ;
150+ } catch ( e ) {
151+ console . log ( 'Failed to open client side storage. Caught the following error...' ) ;
152+ console . log ( e ) ;
153+ }
154+ } ;
155+
156+ const initializeBlocks = ( ) => {
157+ // Initialize blocks and extended python generator.
158+ const forBlock = Object . create ( null ) ;
159+ CustomBlocks . setup ( forBlock ) ;
160+ Object . assign ( pythonGenerator . forBlock , forBlock ) ;
161+ Object . assign ( extendedPythonGenerator . forBlock , pythonGenerator . forBlock ) ;
162+ initializePythonBlocks ( ) ;
163+ } ;
164+
165+ const initializeShownPythonToolboxCategories = async ( ) => {
166+ if ( ! storage ) {
167+ return ;
168+ }
169+ try {
170+ const value = await storage . fetchEntry ( 'shownPythonToolboxCategories' , '[]' ) ;
171+ const shownCategories : string [ ] = JSON . parse ( value ) ;
172+ setShownPythonToolboxCategories ( new Set ( shownCategories ) ) ;
173+ } catch ( e ) {
174+ console . log ( 'Failed to fetch shownPythonToolboxCategories. Caught the following error...' ) ;
175+ console . log ( e ) ;
176+ }
177+ } ;
127178
128- const initializeBlocks = ( ) => {
129- // Initialize blocks and extended python generator.
130- const forBlock = Object . create ( null ) ;
131- CustomBlocks . setup ( forBlock ) ;
132- Object . assign ( pythonGenerator . forBlock , forBlock ) ;
133- Object . assign ( extendedPythonGenerator . forBlock , pythonGenerator . forBlock ) ;
134- initializePythonBlocks ( ) ;
135- } ;
179+ const handleBlocksChanged = ( event : Blockly . Events . Abstract ) => {
180+ if ( event . isUiEvent ) {
181+ // UI events are things like scrolling, zooming, etc.
182+ // No need to regenerate python code after one of these.
183+ return ;
184+ }
185+ if ( ! event . workspaceId ) {
186+ return ;
187+ }
188+ const blocklyWorkspace = Blockly . common . getWorkspaceById ( event . workspaceId ) ;
189+ if ( ! blocklyWorkspace ) {
190+ return ;
191+ }
192+ if ( ( blocklyWorkspace as Blockly . WorkspaceSvg ) . isDragging ( ) ) {
193+ // Don't regenerate python code mid-drag.
194+ return ;
195+ }
196+ setTriggerPythonRegeneration ( Date . now ( ) ) ;
197+ } ;
136198
137- const initializeShownPythonToolboxCategories = async ( ) => {
138- if ( ! storage ) {
199+ const saveBlocks = async ( ) : Promise < boolean > => {
200+ return new Promise ( async ( resolve , reject ) => {
201+ if ( ! blocksEditor . current ) {
202+ reject ( new Error ( ) ) ;
139203 return ;
140204 }
141205 try {
142- const value = await storage . fetchEntry ( 'shownPythonToolboxCategories' , '[]' ) ;
143- const shownCategories : string [ ] = JSON . parse ( value ) ;
144- setShownPythonToolboxCategories ( new Set ( shownCategories ) ) ;
206+ await blocksEditor . current . saveBlocks ( ) ;
207+ messageApi . open ( {
208+ type : 'success' ,
209+ content : 'Save completed successfully.' ,
210+ } ) ;
211+ resolve ( true ) ;
145212 } catch ( e ) {
146- console . log ( 'Failed to fetch shownPythonToolboxCategories . Caught the following error...' ) ;
213+ console . log ( 'Failed to save the blocks . Caught the following error...' ) ;
147214 console . log ( e ) ;
215+ setAlertErrorMessage ( 'Failed to save the blocks.' ) ;
216+ reject ( new Error ( 'Failed to save the blocks.' ) ) ;
148217 }
149- } ;
150-
151- const handleBlocksChanged = ( event : Blockly . Events . Abstract ) => {
152- if ( event . isUiEvent ) {
153- // UI events are things like scrolling, zooming, etc.
154- // No need to regenerate python code after one of these.
155- return ;
156- }
157- if ( ! event . workspaceId ) {
158- return ;
159- }
160- const blocklyWorkspace = Blockly . common . getWorkspaceById ( event . workspaceId ) ;
161- if ( ! blocklyWorkspace ) {
162- return ;
163- }
164- if ( ( blocklyWorkspace as Blockly . WorkspaceSvg ) . isDragging ( ) ) {
165- // Don't regenerate python code mid-drag.
166- return ;
167- }
168- setTriggerPythonRegeneration ( Date . now ( ) ) ;
169- } ;
170-
171- const saveBlocks = async ( ) : Promise < boolean > => {
172- return new Promise ( async ( resolve , reject ) => {
173- if ( ! blocksEditor . current ) {
174- reject ( new Error ( ) ) ;
175- return ;
176- }
177- try {
178- await blocksEditor . current . saveBlocks ( ) ;
179- messageApi . open ( {
180- type : 'success' ,
181- content : 'Save completed successfully.' ,
182- } ) ;
183- resolve ( true ) ;
184- } catch ( e ) {
185- console . log ( 'Failed to save the blocks. Caught the following error...' ) ;
186- console . log ( e ) ;
187- setAlertErrorMessage ( 'Failed to save the blocks.' ) ;
188- reject ( new Error ( 'Failed to save the blocks.' ) ) ;
189- }
190- } ) ;
191- } ;
218+ } ) ;
219+ } ;
192220
193- const handleToolboxSettingsClicked = ( ) => {
194- setToolboxSettingsModalIsOpen ( true ) ;
195- } ;
221+ const handleToolboxSettingsClicked = ( ) => {
222+ setToolboxSettingsModalIsOpen ( true ) ;
223+ } ;
196224
197- const handleToolboxSettingsOk = async ( updatedShownCategories : Set < string > ) => {
198- if ( ! storage ) {
199- return ;
200- }
201- setShownPythonToolboxCategories ( updatedShownCategories ) ;
202- const array = Array . from ( updatedShownCategories ) ;
203- array . sort ( ) ;
204- storage . saveEntry ( 'shownPythonToolboxCategories' , JSON . stringify ( array ) ) ;
205- } ;
206- const areBlocksModified = ( ) : boolean => {
207- if ( blocksEditor . current ) {
208- return blocksEditor . current . isModified ( ) ;
209- }
210- return false ;
225+ const handleToolboxSettingsOk = async ( updatedShownCategories : Set < string > ) => {
226+ if ( ! storage ) {
227+ return ;
228+ }
229+ setShownPythonToolboxCategories ( updatedShownCategories ) ;
230+ const array = Array . from ( updatedShownCategories ) ;
231+ array . sort ( ) ;
232+ storage . saveEntry ( 'shownPythonToolboxCategories' , JSON . stringify ( array ) ) ;
233+ } ;
234+ const areBlocksModified = ( ) : boolean => {
235+ if ( blocksEditor . current ) {
236+ return blocksEditor . current . isModified ( ) ;
211237 }
238+ return false ;
239+ }
212240
213- const myTabs : Tabs . TabItem [ ] = [
214- { key : 'tab1' , title : 'Robot' , type : Tabs . TabType . ROBOT } ,
215- { key : 'tab2' , title : 'Claw' , type : Tabs . TabType . MECHANISM } ,
216- { key : 'tab3' , title : 'ThreeSpecimenAuto' , type : Tabs . TabType . OPMODE } ,
217- { key : 'tab4' , title : 'FieldRelativeTeleop' , type : Tabs . TabType . OPMODE } ,
218- ] ;
219-
220- const { Sider } = Antd . Layout ;
241+ const { Sider } = Antd . Layout ;
221242
222- return (
223- < Antd . ConfigProvider
224- theme = { {
225- algorithm : Antd . theme . darkAlgorithm ,
226- components : {
227- Tree : {
228- directoryNodeSelectedBg : '#1677ff' ,
229- directoryNodeSelectedColor : '#fff' ,
230- nodeSelectedBg : '#1677ff' ,
231- nodeSelectedColor : '#fff' ,
232- nodeHoverBg : '#333' ,
233- nodeHoverColor : '#fff' ,
234- } ,
243+ return (
244+ < Antd . ConfigProvider
245+ theme = { {
246+ algorithm : Antd . theme . darkAlgorithm ,
247+ components : {
248+ Tree : {
249+ directoryNodeSelectedBg : '#1677ff' ,
250+ directoryNodeSelectedColor : '#fff' ,
251+ nodeSelectedBg : '#1677ff' ,
252+ nodeSelectedColor : '#fff' ,
253+ nodeHoverBg : '#333' ,
254+ nodeHoverColor : '#fff' ,
235255 } ,
236- } }
237- >
238- { contextHolder }
256+ } ,
257+ } }
258+ >
259+ { contextHolder }
260+ < Antd . Layout
261+ style = { {
262+ height : '100vh' ,
263+ } } >
264+ < Header
265+ alertErrorMessage = { alertErrorMessage }
266+ setAlertErrorMessage = { setAlertErrorMessage }
267+ project = { project }
268+ />
239269 < Antd . Layout
240270 style = { {
241- height : '100vh' ,
242- } } >
243- < Header
244- alertErrorMessage = { alertErrorMessage }
245- setAlertErrorMessage = { setAlertErrorMessage }
246- />
247- < Antd . Layout
248- style = { {
249- background : '#0F0' ,
250- height : '100%' ,
251- } }
252- >
253- < Sider collapsible collapsed = { leftCollapsed } onCollapse = { ( value : any ) => setLeftCollapsed ( value ) } >
254- < Menu . Component
255- storage = { storage }
256- setAlertErrorMessage = { setAlertErrorMessage }
257- saveBlocks = { saveBlocks }
258- areBlocksModified = { areBlocksModified }
259- currentModule = { currentModule }
260- setCurrentModule = { setCurrentModule }
261- />
262- </ Sider >
263- < Antd . Layout >
264- < Tabs . Component
265- tabList = { myTabs }
266- setAlertErrorMessage = { setAlertErrorMessage }
267- currentModule = { currentModule }
268- setCurrentModule = { setCurrentModule }
269- />
270- < Antd . Splitter >
271- { /*
271+ background : '#0F0' ,
272+ height : '100%' ,
273+ } }
274+ >
275+ < Sider collapsible collapsed = { leftCollapsed } onCollapse = { ( value : any ) => setLeftCollapsed ( value ) } >
276+ < Menu . Component
277+ storage = { storage }
278+ setAlertErrorMessage = { setAlertErrorMessage }
279+ saveBlocks = { saveBlocks }
280+ areBlocksModified = { areBlocksModified }
281+ currentModule = { currentModule }
282+ setCurrentModule = { setCurrentModule }
283+ project = { project }
284+ setProject = { setProject }
285+ />
286+ </ Sider >
287+ < Antd . Layout >
288+ < Tabs . Component
289+ tabList = { tabItems }
290+ setAlertErrorMessage = { setAlertErrorMessage }
291+ currentModule = { currentModule }
292+ setCurrentModule = { setCurrentModule }
293+ />
294+ < Antd . Splitter >
295+ { /*
272296 <Antd.Splitter.Panel collapsible={true}>
273297 <ModuleOutline
274298 storage={storage}
@@ -282,31 +306,31 @@ const App: React.FC = () => {
282306 />
283307 </Antd.Splitter.Panel>
284308 */ }
285- < Antd . Splitter . Panel >
286- < BlocklyComponent ref = { blocklyComponent } />
287- </ Antd . Splitter . Panel >
288- < Antd . Splitter . Panel min = { 40 } size = { '25%' } collapsible = { true } >
289- < CodeDisplay generatedCode = { generatedCode }
290- messageApi = { messageApi }
291- setAlertErrorMessage = { setAlertErrorMessage }
292- />
293- </ Antd . Splitter . Panel >
294- </ Antd . Splitter >
295- </ Antd . Layout >
309+ < Antd . Splitter . Panel >
310+ < BlocklyComponent ref = { blocklyComponent } />
311+ </ Antd . Splitter . Panel >
312+ < Antd . Splitter . Panel min = { 40 } defaultSize = { '25%' } collapsible = { true } >
313+ < CodeDisplay generatedCode = { generatedCode }
314+ messageApi = { messageApi }
315+ setAlertErrorMessage = { setAlertErrorMessage }
316+ />
317+ </ Antd . Splitter . Panel >
318+ </ Antd . Splitter >
296319 </ Antd . Layout >
297320 </ Antd . Layout >
321+ </ Antd . Layout >
298322
299- < ToolboxSettingsModal
300- isOpen = { toolboxSettingsModalIsOpen }
301- shownCategories = { shownPythonToolboxCategories }
302- onOk = { ( updatedShownCategories : Set < string > ) => {
303- setToolboxSettingsModalIsOpen ( false ) ;
304- handleToolboxSettingsOk ( updatedShownCategories ) ;
305- } }
306- onCancel = { ( ) => setToolboxSettingsModalIsOpen ( false ) }
307- />
308- </ Antd . ConfigProvider >
309- ) ;
323+ < ToolboxSettingsModal
324+ isOpen = { toolboxSettingsModalIsOpen }
325+ shownCategories = { shownPythonToolboxCategories }
326+ onOk = { ( updatedShownCategories : Set < string > ) => {
327+ setToolboxSettingsModalIsOpen ( false ) ;
328+ handleToolboxSettingsOk ( updatedShownCategories ) ;
329+ } }
330+ onCancel = { ( ) => setToolboxSettingsModalIsOpen ( false ) }
331+ />
332+ </ Antd . ConfigProvider >
333+ ) ;
310334} ;
311335
312336export default App ;
0 commit comments