Skip to content

Commit 2415a17

Browse files
committed
feat: Implement Assemble by Parts flow with part DNA locking and scrambler settings
- Added `applyPartLock` function to lock DNA encoding for reused parts based on their amino acid sequence. - Introduced `ScramblerSettings` component for advanced configuration of the scrambling process. - Created `PartAssembler` component to manage the assembly of parts and linkers, including a drag-and-drop interface. - Updated `ResultsView` to handle part locking and integrate scrambler settings. - Enhanced `SequenceAnnotator` and `SequenceInput` components to display part names consistently. - Added persistence for part DNA encoding using local storage. - Introduced default scrambler configuration and validation for user-defined constraints.
1 parent 649d2a2 commit 2415a17

12 files changed

Lines changed: 852 additions & 297 deletions

File tree

frontend/src/App.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@ import ResultsView from './components/ResultsView';
66
import PartSwapper from './components/PartSwapper';
77
import type { Region, ScrambleResult, WorkSession } from './types';
88
import { readRepeatMotif, writeRepeatMotif } from './repeat';
9+
import { clearAutosavedSession, readAutosavedSession } from './sessionStore';
910

1011
const FAST_MODE_ENABLED = false
1112

1213
export default function App() {
13-
const [active, setActive] = useState(0);
14-
const [sequence, setSequence] = useState('');
15-
const [regions, setRegions] = useState<Region[]>([]);
16-
const [result, setResult] = useState<ScrambleResult | null>(null);
17-
const [loadedSession, setLoadedSession] = useState<WorkSession | null>(null);
14+
const [autosaved] = useState(() => readAutosavedSession());
15+
const [active, setActive] = useState(autosaved ? 3 : 0);
16+
const [sequence, setSequence] = useState(autosaved?.sequence ?? '');
17+
const [regions, setRegions] = useState<Region[]>(autosaved?.regions ?? []);
18+
const [result, setResult] = useState<ScrambleResult | null>(autosaved?.result ?? null);
19+
const [assembled, setAssembled] = useState(false);
20+
const [loadedSession, setLoadedSession] = useState<WorkSession | null>(autosaved);
1821
const [fastMode, setFastMode] = useState(false);
1922
const [repeatMotif, setRepeatMotif] = useState<string>(() => readRepeatMotif());
2023

@@ -29,19 +32,22 @@ export default function App() {
2932
// Clear downstream state when sequence changes
3033
setRegions([]);
3134
setResult(null);
35+
setAssembled(false);
3236
setActive(1);
3337
};
3438

3539
const handleAnnotateNext = (r: Region[]) => {
3640
setRegions(r);
3741
setResult(null);
42+
setAssembled(false);
3843
setActive(2);
3944
};
4045

4146
const handleAssembleNext = (seq: string, r: Region[]) => {
4247
setSequence(seq);
4348
setRegions(r);
4449
setResult(null);
50+
setAssembled(true);
4551
setActive(2);
4652
};
4753

@@ -114,6 +120,7 @@ export default function App() {
114120
onBack={() => setActive(1)}
115121
onNext={() => setActive(3)}
116122
fastMode={fastMode}
123+
lockPartDna={assembled}
117124
/>
118125
)}
119126
{active === 3 && (
@@ -122,7 +129,7 @@ export default function App() {
122129
regions={regions}
123130
result={result}
124131
onResultChange={setResult}
125-
onRestart={() => { setSequence(''); setRegions([]); setResult(null); setLoadedSession(null); setActive(0); }}
132+
onRestart={() => { clearAutosavedSession(); setSequence(''); setRegions([]); setResult(null); setLoadedSession(null); setActive(0); }}
126133
initialSession={loadedSession}
127134
fastMode={fastMode}
128135
/>

frontend/src/api.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import type { Region, ScrambleResult } from './types';
1+
import type { Region, ScrambleResult, ScramblerConfig } from './types';
22
import { wasmScrambleConstruct, wasmSwapPart } from './wasm-api';
33

44
export function scrambleConstruct(
55
sequence: string,
66
regions: Region[],
77
fast = false,
8-
config?: Record<string, unknown>
8+
config?: ScramblerConfig
99
): Promise<ScrambleResult> {
1010
const req = JSON.stringify({ sequence, regions, config, fast });
1111
return Promise.resolve(JSON.parse(wasmScrambleConstruct(req)) as ScrambleResult);
@@ -17,12 +17,14 @@ export function swapPart(
1717
regions: Region[],
1818
regionDnas: Record<string, string>,
1919
fast = false,
20+
config?: ScramblerConfig,
2021
): Promise<{ dna: string; swapped_dna: string }> {
2122
const req = JSON.stringify({
2223
new_aa: newAa,
2324
part_name: partName,
2425
regions,
2526
region_dnas: regionDnas,
27+
config,
2628
fast,
2729
});
2830
return Promise.resolve(JSON.parse(wasmSwapPart(req)) as { dna: string; swapped_dna: string });

0 commit comments

Comments
 (0)