Skip to content

Commit 1c8992f

Browse files
committed
[act.lab.ρ.D8+] separate the discovery lab from the legacy shell
FEP and Field now share one exact navigation model and one independent build served on 1370. The legacy 1360 shell remains untouched, while each scientific workspace can switch directly to the other and return through the unified landing page. The commit also preserves the fail-closed FEP state machine and adds route-level regression coverage.
1 parent 1ea4630 commit 1c8992f

25 files changed

Lines changed: 1402 additions & 941 deletions

‎scripts/build-discovery-lab.mjs‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import fs from 'node:fs/promises';
2+
import path from 'node:path';
3+
import * as esbuild from 'esbuild';
4+
5+
const repo = path.resolve(import.meta.dirname, '..');
6+
const source = path.join(repo, 'src/app.frontend.facets.molstar-rdkit.editable');
7+
const output = path.join(repo, 'build/discovery-lab');
8+
const production = process.argv.includes('--prd');
9+
10+
await fs.rm(output, { recursive: true, force: true });
11+
await fs.mkdir(output, { recursive: true });
12+
13+
for (const [entry, outfile] of [
14+
['discovery-lab/discovery-lab.ts', 'discovery-lab.js'],
15+
['fep-workbench/fep-workbench.ts', 'fep-workbench.js'],
16+
['field-workbench/field-workbench.ts', 'field-workbench.js'],
17+
]) {
18+
await esbuild.build({
19+
entryPoints: [path.join(source, entry)],
20+
outfile: path.join(output, outfile),
21+
bundle: true,
22+
platform: 'browser',
23+
minify: production,
24+
minifyIdentifiers: false,
25+
sourcemap: !production,
26+
define: {
27+
'process.env.NODE_ENV': JSON.stringify(production ? 'production' : 'development'),
28+
'process.env.DEBUG': 'false',
29+
},
30+
});
31+
}
32+
33+
for (const [from, to] of [
34+
['discovery-lab/index.html', 'index.html'],
35+
['discovery-lab/discovery-lab.css', 'discovery-lab.css'],
36+
['fep-workbench/fep-workbench.html', 'fep-workbench.html'],
37+
['fep-workbench/fep-workbench.css', 'fep-workbench.css'],
38+
['field-workbench/field-workbench.html', 'field-workbench.html'],
39+
['field-workbench/field-workbench.css', 'field-workbench.css'],
40+
]) await fs.copyFile(path.join(source, from), path.join(output, to));
41+
42+
await fs.cp(path.join(source, 'fonts'), path.join(output, 'fonts'), { recursive: true });
43+
await fs.cp(path.join(source, 'assets/rdkit'), path.join(output, 'assets/rdkit'), { recursive: true });
44+
await fs.copyFile(path.join(repo, 'examples/docking/receptor_1.pdb'), path.join(output, 'assets/receptor.pdb'));
45+
await fs.copyFile(path.join(repo, 'examples/docking/ligands_1.sdf'), path.join(output, 'assets/ligand.sdf'));
46+
47+
console.log(`Discovery Lab built at ${output}`);

‎src/app.frontend.facets.molstar-rdkit.editable/discovery-lab/discovery-lab.css‎

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const query = new URLSearchParams(location.search);
2+
const apiBase = query.get('api') || `http://${location.hostname}:8901`;
3+
const state = document.getElementById('backend-state');
4+
const url = document.getElementById('backend-url');
5+
if (url) url.textContent = apiBase;
6+
7+
void fetch(`${apiBase}/health`, { signal: AbortSignal.timeout(5000) }).then(response => {
8+
if (!response.ok) throw new Error(String(response.status));
9+
if (state) { state.textContent = '● BACKEND LINKED'; state.classList.add('live'); }
10+
}).catch(() => {
11+
if (state) state.textContent = 'BACKEND UNAVAILABLE';
12+
});
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width,initial-scale=1">
6+
<title>DIRAC · Discovery Lab</title>
7+
<link rel="stylesheet" href="./discovery-lab.css">
8+
</head>
9+
<body>
10+
<main class="discovery-home">
11+
<header>
12+
<div class="brand-mark" aria-hidden="true"><i></i></div>
13+
<div><small>DIRAC</small><h1>DISCOVERY LAB</h1></div>
14+
<span id="backend-state" role="status">CHECKING BACKEND</span>
15+
</header>
16+
<section class="intro">
17+
<p>One scientific workspace. Two connected instruments.</p>
18+
<strong>FEP qualification and molecular-field comparison share the same backend and visual language.</strong>
19+
</section>
20+
<nav aria-label="Discovery Lab workspaces">
21+
<a href="./fep-workbench.html">
22+
<span>01</span><small>FREE ENERGY</small><h2>FEP</h2>
23+
<p>Build campaigns, review receptor-aligned poses, inspect mappings, and qualify governed OpenFE runs.</p>
24+
<b>OPEN FEP →</b>
25+
</a>
26+
<a href="./field-workbench.html">
27+
<span>02</span><small>MOLECULAR FIELDS</small><h2>FIELD</h2>
28+
<p>Compare parent and proposal in linked 2D, 3D, receptor-pocket, MEP, and MLP views.</p>
29+
<b>OPEN FIELD →</b>
30+
</a>
31+
</nav>
32+
<footer><span>BACKEND · <code id="backend-url">—</code></span><span>INITIAL WORKSPACES · 2</span></footer>
33+
</main>
34+
<script src="./discovery-lab.js"></script>
35+
</body>
36+
</html>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export type DiscoveryWorkspace = 'fep' | 'field';
2+
3+
export const DISCOVERY_WORKSPACE_ROUTES = Object.freeze({
4+
fep: './fep-workbench.html',
5+
field: './field-workbench.html',
6+
});
7+
8+
const WORKSPACES: ReadonlyArray<{ id: DiscoveryWorkspace; label: string }> = [
9+
{ id: 'fep', label: 'FEP' },
10+
{ id: 'field', label: 'FIELD' },
11+
];
12+
13+
/** One navigation contract shared by the two initial Discovery Lab workspaces. */
14+
export function discoveryWorkspaceNavigation(active: DiscoveryWorkspace): string {
15+
return `<nav class="discovery-workspace-nav" aria-label="Discovery Lab workspaces">${WORKSPACES.map(workspace => {
16+
const selected = workspace.id === active;
17+
return `<a class="discovery-workspace-link${selected ? ' active' : ''}" href="${DISCOVERY_WORKSPACE_ROUTES[workspace.id]}"${selected ? ' aria-current="page"' : ''}>${workspace.label}</a>`;
18+
}).join('')}</nav>`;
19+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { describe, expect, it } from '@jest/globals';
2+
import { DISCOVERY_WORKSPACE_ROUTES, discoveryWorkspaceNavigation } from '../discovery-navigation';
3+
4+
describe('Discovery Lab navigation', () => {
5+
it('starts with exactly the FEP and Field workspaces', () => {
6+
expect(Object.keys(DISCOVERY_WORKSPACE_ROUTES)).toEqual(['fep', 'field']);
7+
});
8+
9+
it.each(['fep', 'field'] as const)('links both workspaces and marks %s as current', active => {
10+
const markup = discoveryWorkspaceNavigation(active);
11+
expect(markup).toContain(`href="${DISCOVERY_WORKSPACE_ROUTES.fep}"`);
12+
expect(markup).toContain(`href="${DISCOVERY_WORKSPACE_ROUTES.field}"`);
13+
expect(markup.match(/aria-current="page"/g)).toHaveLength(1);
14+
expect(markup).toContain(`href="${DISCOVERY_WORKSPACE_ROUTES[active]}" aria-current="page"`);
15+
});
16+
});

‎src/app.frontend.facets.molstar-rdkit.editable/fep-workbench/fep-workbench.css‎

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎src/app.frontend.facets.molstar-rdkit.editable/fep-workbench/fep-workbench.html‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
<head>
44
<meta charset="utf-8">
55
<meta name="viewport" content="width=device-width,initial-scale=1">
6-
<base href="/">
6+
<base href="./">
77
<title>DIRAC · FEP Lab</title>
8-
<link rel="stylesheet" href="time-tunnel/fep-workbench.css">
8+
<link rel="stylesheet" href="./fep-workbench.css">
99
</head>
1010
<body>
1111
<div id="fep-lab"></div>
12-
<script src="time-tunnel/fep-workbench.js"></script>
12+
<script src="./fep-workbench.js"></script>
1313
</body>
1414
</html>

0 commit comments

Comments
 (0)