Skip to content

Commit edea552

Browse files
committed
Refactors app layout into dedicated providers and shell
Simplifies the main component by extracting layout logic, introducing global providers for future expansions, and ignoring local manifests in .gitignore. Enhances code organization for clarity and maintainability.
1 parent c3cd6dd commit edea552

File tree

4 files changed

+176
-74
lines changed

4 files changed

+176
-74
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,6 @@ editor/dist/
9494

9595
# Ignore build output from possible CI
9696
server/dist/
97+
98+
# Local manifest dumps (registry manifests/diagnostics)
99+
manifests.json

src/App.tsx

Lines changed: 19 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import { createActivity, createStep } from './factories';
1616
import { validateScript, formatErrors, getValidatorStatus } from './validator';
1717
import { editorReducer, initialEditorState, getSelectedNode } from './editorReducer';
1818
import { usePersistedSelections } from './hooks/usePersistedSelections';
19+
import AppProviders from './app/Providers';
20+
import AppShell from './app/AppShell';
1921

2022
type TabType = 'edit' | 'documentation';
2123

@@ -639,84 +641,27 @@ export default function App() {
639641
}
640642

641643
return (
642-
<div className="app-container">
643-
<TopBar
644+
<AppProviders>
645+
<AppShell
644646
selectedFacility={selectedFacility}
645647
selectedFacilityId={selectedFacilityId}
646648
onFacilitySelect={handleFacilitySelect}
649+
activeTab={activeTab}
650+
setActiveTab={setActiveTab}
651+
state={state}
652+
script={script}
653+
isValid={isValid}
654+
validationErrors={validationErrors.errors || validationErrors}
655+
selections={selections}
656+
selectedLocation={selectedLocation}
657+
selectedBayObj={selectedBayObj}
658+
onLoadScript={loadScript}
659+
onDownloadScript={downloadScript}
660+
onLocationSelect={handleLocationSelect}
661+
onBaySelect={handleBaySelect}
662+
dispatch={dispatch}
647663
/>
648-
<TabBar
649-
activeTab={activeTab}
650-
onTabChange={setActiveTab}
651-
/>
652-
{/* <EnvironmentDebug /> */}
653-
{activeTab === 'edit' ? (
654-
<div className="tree-flex">
655-
<DialogManager
656-
showActivityDialog={showActivityDialog}
657-
showStepDialog={showStepDialog}
658-
onCloseActivityDialog={() => setShowActivityDialog(false)}
659-
onCloseStepDialog={() => setShowStepDialog(false)}
660-
onAddActivity={handleAddActivity}
661-
onAddStep={handleAddStep}
662-
parentActivityForAdd={parentActivityForAdd}
663-
/>
664-
<Sidebar
665-
script={script}
666-
selectedRef={state.selectedRef}
667-
isValid={isValid}
668-
validationErrors={validationErrors}
669-
selectedFacilityId={selectedFacilityId}
670-
selectedLocationId={selectedLocation?.id || null}
671-
persistedLocationId={selections?.locationId || null}
672-
selectedBayId={selectedBayId}
673-
persistedBayId={selections?.bayId || null}
674-
selectedBayObj={selectedBayObj}
675-
onLoadScript={loadScript}
676-
onDownloadScript={downloadScript}
677-
onLocationSelect={handleLocationSelect}
678-
onBaySelect={handleBaySelect}
679-
onCloneSelected={() => dispatch({ type: 'CLONE_SELECTED' })}
680-
onShowActivityDialog={() => setShowActivityDialog(true)}
681-
onShowStepDialog={() => setShowStepDialog(true)}
682-
onSelectScript={() => dispatch({ type: 'SELECT_SCRIPT' })}
683-
onSelectActivity={(activityId: string) => dispatch({ type: 'SELECT_ACTIVITY', activityId })}
684-
onSelectStep={(activityId: string, stepId: string) => dispatch({ type: 'SELECT_STEP', activityId, stepId })}
685-
onDeleteActivity={deleteActivity}
686-
onDeleteStep={deleteStep}
687-
parentActivityForAdd={parentActivityForAdd}
688-
/>
689-
<div className="tree-main">
690-
{state.selectedRef?.kind === 'script' ? (
691-
<>
692-
<h2>Script Configuration</h2>
693-
<ScriptEditor
694-
script={script}
695-
onChange={updateScript}
696-
/>
697-
<pre>{JSON.stringify(script, null, 2)}</pre>
698-
</>
699-
) : selectedNode ? (
700-
<NodeEditor
701-
node={selectedNode}
702-
onUpdateActivity={updateActivity}
703-
onUpdateStep={updateStep}
704-
/>
705-
) : (
706-
<div className="empty-node-editor">Select a node to edit its details.</div>
707-
)}
708-
</div>
709-
</div>
710-
) : activeTab === 'documentation' ? (
711-
<div className="documentation-flex">
712-
<DocViewer />
713-
</div>
714-
) : activeTab === 'webhook' ? (
715-
<div className="documentation-flex">
716-
<WebhookView selectedBayDbId={selectedBayObj?.dbId ?? null} />
717-
</div>
718-
) : null}
719-
</div>
664+
</AppProviders>
720665
);
721666
}
722667

src/app/AppShell.tsx

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import React from 'react';
2+
import { TopBar } from '../components/TopBar';
3+
import { TabBar } from '../components/TabBar';
4+
import { Sidebar } from '../components/Sidebar';
5+
import { DialogManager } from '../components/DialogManager';
6+
import { ScriptEditor } from '../components/ScriptEditor';
7+
import { NodeEditor } from '../components/NodeEditor';
8+
import { DocViewer } from '../components/DocViewer';
9+
import WebhookView from '../components/WebhookView';
10+
11+
export type TabType = 'edit' | 'documentation' | 'webhook';
12+
13+
export interface AppShellProps {
14+
// the props below are a subset of the props used by the original App
15+
selectedFacility: any;
16+
selectedFacilityId: string | null;
17+
onFacilitySelect: (f: any) => void;
18+
activeTab: TabType;
19+
setActiveTab: (t: TabType) => void;
20+
// editor state and handlers (kept generic to avoid tight coupling in this step)
21+
state: any;
22+
script: any;
23+
isValid: boolean;
24+
validationErrors: any[];
25+
selections: any;
26+
selectedLocation: any;
27+
selectedBayObj: any;
28+
onLoadScript: () => void;
29+
onDownloadScript: () => void;
30+
onLocationSelect: (l: any) => void;
31+
onBaySelect: (b: any) => void;
32+
dispatch: any;
33+
}
34+
35+
export const AppShell: React.FC<AppShellProps> = (props) => {
36+
const {
37+
selectedFacility,
38+
selectedFacilityId,
39+
onFacilitySelect,
40+
activeTab,
41+
setActiveTab,
42+
state,
43+
script,
44+
isValid,
45+
validationErrors,
46+
selections,
47+
selectedLocation,
48+
selectedBayObj,
49+
onLoadScript,
50+
onDownloadScript,
51+
onLocationSelect,
52+
onBaySelect,
53+
dispatch
54+
} = props;
55+
56+
const selectedNode = (() => {
57+
try { return (state && state.selectedRef && state.selectedRef.kind !== 'script') ? state.selectedRef : null; } catch { return null; }
58+
})();
59+
60+
return (
61+
<div className="app-container">
62+
<TopBar
63+
selectedFacility={selectedFacility}
64+
selectedFacilityId={selectedFacilityId}
65+
onFacilitySelect={onFacilitySelect}
66+
/>
67+
<TabBar
68+
activeTab={activeTab}
69+
onTabChange={setActiveTab}
70+
/>
71+
72+
{activeTab === 'edit' ? (
73+
<div className="tree-flex">
74+
<DialogManager
75+
// dialog props are expected to be provided via dispatch or parent
76+
showActivityDialog={false}
77+
showStepDialog={false}
78+
onCloseActivityDialog={() => {}}
79+
onCloseStepDialog={() => {}}
80+
onAddActivity={() => {}}
81+
onAddStep={() => {}}
82+
parentActivityForAdd={undefined}
83+
/>
84+
<Sidebar
85+
script={script}
86+
selectedRef={state.selectedRef}
87+
selectedNode={selectedNode}
88+
isValid={isValid}
89+
validationErrors={validationErrors}
90+
selectedFacilityId={selectedFacilityId}
91+
selectedLocationId={selectedLocation?.id || null}
92+
persistedLocationId={selections?.locationId || null}
93+
selectedBayId={selectedBayObj?.id || null}
94+
persistedBayId={selections?.bayId || null}
95+
selectedBayObj={selectedBayObj}
96+
onLoadScript={onLoadScript}
97+
onDownloadScript={onDownloadScript}
98+
onLocationSelect={onLocationSelect}
99+
onBaySelect={onBaySelect}
100+
onCloneSelected={() => dispatch({ type: 'CLONE_SELECTED' })}
101+
onShowActivityDialog={() => {}}
102+
onShowStepDialog={() => {}}
103+
onSelectScript={() => dispatch({ type: 'SELECT_SCRIPT' })}
104+
onSelectActivity={(activityId: string) => dispatch({ type: 'SELECT_ACTIVITY', activityId })}
105+
onSelectStep={(activityId: string, stepId: string) => dispatch({ type: 'SELECT_STEP', activityId, stepId })}
106+
onDeleteActivity={(id: string) => dispatch({ type: 'DELETE_ACTIVITY', activityId: id })}
107+
onDeleteStep={(activityId: string, stepId: string) => dispatch({ type: 'DELETE_STEP', activityId, stepId })}
108+
parentActivityForAdd={undefined}
109+
/>
110+
111+
<div className="tree-main">
112+
{state.selectedRef?.kind === 'script' ? (
113+
<>
114+
<h2>Script Configuration</h2>
115+
<ScriptEditor
116+
script={script}
117+
onChange={(s: any) => dispatch({ type: 'LOAD_SCRIPT', script: s })}
118+
/>
119+
<pre>{JSON.stringify(script, null, 2)}</pre>
120+
</>
121+
) : selectedNode ? (
122+
<NodeEditor
123+
node={selectedNode}
124+
onUpdateActivity={(activityId: string, patch: any) => dispatch({ type: 'UPDATE_ACTIVITY', activityId, patch })}
125+
onUpdateStep={(stepId: string, patch: any) => dispatch({ type: 'UPDATE_STEP', stepId, patch })}
126+
/>
127+
) : (
128+
<div className="empty-node-editor">Select a node to edit its details.</div>
129+
)}
130+
</div>
131+
</div>
132+
) : activeTab === 'documentation' ? (
133+
<div className="documentation-flex">
134+
<DocViewer />
135+
</div>
136+
) : activeTab === 'webhook' ? (
137+
<div className="documentation-flex">
138+
<WebhookView selectedBayDbId={selectedBayObj?.dbId ?? null} />
139+
</div>
140+
) : null}
141+
</div>
142+
);
143+
};
144+
145+
export default AppShell;

src/app/Providers.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import React from 'react';
2+
3+
// AppProviders is a small composition point for global providers (Auth, Theme, QueryClient, etc.)
4+
// For now it simply forwards children — this gives us a single place to add providers later.
5+
export const AppProviders: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
6+
return <>{children}</>;
7+
};
8+
9+
export default AppProviders;

0 commit comments

Comments
 (0)