Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ scope.
| N.1 | ~~**Code-split the bundle.**~~ ✅ Done — app `949→738 KiB` (#26), popup `478→190 KiB`. Advanced/Migration screens (app) and the non-default popup tabs lazy-load from `dist/chunks/`. | `app` was 949 KiB / `popup` 478 KiB vs a 244 KiB budget. | M |
| N.2 | ~~**Clear the `any` warnings + CI gates.**~~ ✅ Done (#26) — 0 lint warnings; `typecheck`/`lint --max-warnings=0`/`test`/`build` run in CI. | Locked in before it regresses. | S |
| N.3 | **Tests for the new 0.2 flows** — Convert round-trips, Compare, export multi-format, file parsing ✅ (#26); streaming capture ✅; still want scheduled-snapshot scheduling/retention + import dry-run. | These are the features users actually touch now. | M |
| N.4 | **Decide the migration suite's fate.** Either (a) test it to a trustable bar, or (b) gate it behind an explicit "experimental" flag in Settings so the demoted-but-present state isn't a silent liability. | Shipping barely-tested complex code is the biggest correctness risk in the repo. | S–L |
| N.4 | ~~**Decide the migration suite's fate.**~~ ✅ Done — gated behind an **experimental** flag in Settings (default off). The Migration nav hides unless opted in, and direct navigation shows an opt-in notice. Testing it to a trustable bar remains optional future work if it graduates. | Shipping barely-tested complex code was the biggest correctness risk. | S |

---

Expand Down
2 changes: 2 additions & 0 deletions src/core/types/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ export interface UiSettings {
accentColor?: string;
/** User-assigned org colors for visual differentiation, keyed by orgId */
orgColorMap?: Record<string, string>;
/** Opt-in to the experimental, thinly-tested cross-org Migration suite. Default off. */
experimentalMigration?: boolean;
}

/** Saved data template for reusable data pushes */
Expand Down
40 changes: 37 additions & 3 deletions src/ui/app/AppRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export function AppRoot(): VNode {
const [undoPanelOpen, setUndoPanelOpen] = useState(false);
const [showOnboarding, setShowOnboarding] = useState(false);
const [activeProjectId, setActiveProjectId] = useState<string | null>(null);
const [experimentalMigration, setExperimentalMigration] = useState(false);

async function refreshTabs(): Promise<void> {
try {
Expand Down Expand Up @@ -129,6 +130,7 @@ export function AppRoot(): VNode {
const resolved = resolveTheme(savedTheme);
applyTheme(resolved);
applyAccentColor(settings.accentColor);
setExperimentalMigration(settings.experimentalMigration ?? false);
}).catch(e => {
console.error('Failed to load theme:', e);
applyTheme('light');
Expand Down Expand Up @@ -245,15 +247,17 @@ export function AppRoot(): VNode {
{ key: 'convert', label: 'Convert' },
],
},
{
// The Migration suite is experimental (thinly tested) — only surface it
// when the user has opted in via Settings.
...(experimentalMigration ? [{
key: 'migration', label: 'Migration', items: [
{ key: 'migration/projects', label: 'Migration Projects' },
{ key: 'migration/validation', label: 'Migration Validation' },
{ key: 'migration/reports', label: 'Migration Reports' },
{ key: 'migration/templates', label: 'Migration Templates' },
{ key: 'migration/idMaps', label: 'ID Maps' },
],
},
}] as NavGroup[] : []),
{
key: 'extras', label: 'Library', items: [
{ key: 'templates', label: 'Templates' },
Expand Down Expand Up @@ -391,7 +395,37 @@ export function AppRoot(): VNode {
if (route === 'schedules') return <SchedulesScreen sf={sf} />;
if (route === 'diff') return <CompareScreen sf={sf} />;

// ── Migration suite (top-level) ──
// ── Migration suite (top-level, experimental) ──
// Guard direct navigation (legacy aliases, command palette, saved routes)
// when the suite hasn't been enabled in Settings.
if (route.startsWith('migration/') && !experimentalMigration) {
return (
<div class="wl-card">
<div class="wl-cardSection">
<div class="wl-emptyState">
<div class="wl-emptyState__icon">🧪</div>
<p class="wl-emptyState__title">Migration is an experimental feature</p>
<p class="wl-emptyState__desc">
The cross-org Migration suite is still being hardened. Enable it in
Settings to try it.
</p>
<div style="margin-top:12px">
<button
class="wl-buttonBrand"
onClick={() => {
setExperimentalMigration(true);
sf.setUiSettings({ experimentalMigration: true }).catch(() => {});
}}
>
Enable migration tools
</button>
<button class="wl-btn" style="margin-left:8px" onClick={() => setRoute('home')}>Back to Home</button>
</div>
</div>
</div>
</div>
);
}
if (route === 'migration/projects' && activeProjectId) return <MigrationWorkspaceScreen sf={sf} tabId={selectedTabId!} projectId={activeProjectId} onBack={() => setActiveProjectId(null)} />;
if (route === 'migration/projects') return <MigrationProjectsScreen sf={sf} onOpenProject={(id) => setActiveProjectId(id)} />;
if (route === 'migration/validation' && activeProjectId) return <MigrationValidationScreen sf={sf} tabId={selectedTabId!} projectId={activeProjectId} onBack={() => setActiveProjectId(null)} />;
Expand Down
9 changes: 9 additions & 0 deletions src/ui/screens/SettingsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,15 @@ export function SettingsScreen(props: { sf: SfApi; mode: 'app' | 'panel' | 'popu
<span>Panel pinned</span>
</label>

<label class="wl-chip" style="width:fit-content;cursor:pointer" title="Surfaces the cross-org Migration suite, which is still being hardened.">
<input
type="checkbox"
checked={settings.experimentalMigration ?? false}
onChange={(e) => update({ experimentalMigration: (e.currentTarget as HTMLInputElement).checked })}
/>
<span>Experimental: cross-org Migration tools</span>
</label>

<div style="margin-top:12px">
<div style="font-weight:900;margin-bottom:8px">Theme</div>
<div class="wl-muted" style="margin-bottom:8px">Accent Color</div>
Expand Down
Loading