mirror of
https://github.com/different-ai/openwork
synced 2026-04-25 17:15:34 +02:00
* refactor(repo): move OpenWork apps into apps and ee layout Rebase the monorepo layout migration onto the latest dev changes so the moved app, desktop, share, and cloud surfaces keep working from their new paths. Carry the latest deeplink, token persistence, build, Vercel, and docs updates forward to avoid stale references and broken deploy tooling. * chore(repo): drop generated desktop artifacts Ignore the moved Tauri target and sidecar paths so local cargo checks do not pollute the branch. Remove the accidentally committed outputs from the repo while keeping the layout migration intact. * fix(release): drop built server cli artifact Stop tracking the locally built apps/server/cli binary so generated server outputs do not leak into commits. Also update the release workflow to check the published scoped package name for @openwork/server before deciding whether npm publish is needed. * fix(workspace): add stable CLI bin wrappers Point the server and router package bins at committed wrapper scripts so workspace installs can create shims before dist outputs exist. Keep the wrappers compatible with built binaries and source checkouts to avoid Vercel install warnings without changing runtime behavior.
5.0 KiB
5.0 KiB
Reload Toast: Persist + Show What Changed
Branch: feat/reload-toast-persist
Priority: P0
Problems
- Toast disappears before user can click
- Toast is vague - just says "Reload required" without specifics
Current Code
File: packages/app/src/app/app.tsx L1799-1834
const [reloadToastDismissedAt, setReloadToastDismissedAt] = createSignal<number | null>(null);
const reloadToastVisible = createMemo(() => {
if (!reloadRequired()) return false; // <-- Hides when reload not required
const lastTriggeredAt = reloadLastTriggeredAt();
const dismissedAt = reloadToastDismissedAt();
if (!lastTriggeredAt) return true;
if (!dismissedAt) return true;
return dismissedAt < lastTriggeredAt;
});
Code findings
- Reload state + reasons live in
packages/app/src/app/system-state.ts:40-45(reloadRequired,reloadReasons,reloadLastTriggeredAt) markReloadRequired(reason)only stores the reason string:packages/app/src/app/system-state.ts:135-139ReloadReasonis a fixed union:packages/app/src/app/types.ts:202("plugins" | "skills" | "mcp" | "config")- Tauri watcher emits
openwork://reload-requiredwith{ reason, path }:packages/desktop/src-tauri/src/workspace/watch.rs:99-124 - UI listener drops
pathand only mapsreason:packages/app/src/app/app.tsx:1870-1902 - Explicit triggers:
- Skills/plugins:
packages/app/src/app/context/extensions.ts:526,549,588,669,750 - MCP:
packages/app/src/app/app.tsx:2557 - Config/model change:
packages/app/src/app/app.tsx:3020,3034 - Tool-driven file writes:
packages/app/src/app/context/session.ts:141-193
- Skills/plugins:
Changes Required
1. Investigate why toast disappears
Add logging to track state changes:
createEffect(() => {
console.log('[ReloadToast] reloadRequired:', reloadRequired());
console.log('[ReloadToast] lastTriggeredAt:', reloadLastTriggeredAt());
console.log('[ReloadToast] dismissedAt:', reloadToastDismissedAt());
});
Possible causes:
reloadRequired()becomes false prematurely (auto-reload?)- Page navigation clears state
- Effect at L1830-1834 clears state
Other auto-clear sites:
clearReloadRequired()inpackages/app/src/app/system-state.ts:141-145- Successful reload clears state in
packages/app/src/app/system-state.ts:281-282 - Workspace change clears reload state in
packages/app/src/app/app.tsx:1928-1933
2. Track what triggered the reload
Update markReloadRequired to accept details:
type ReloadTrigger = {
type: "skill" | "plugin" | "config" | "mcp";
name?: string;
};
const [reloadTrigger, setReloadTrigger] = createSignal<ReloadTrigger | null>(null);
const markReloadRequired = (reason: ReloadReason, trigger?: ReloadTrigger) => {
markReloadRequiredRaw(reason);
if (trigger) {
setReloadTrigger(trigger);
}
};
Note: There is already a path in the Tauri event payload (workspace/watch.rs:119-121). We can parse it to a name (skill/plugin) and pass it as trigger.name.
3. Update toast to show specific change
File: packages/app/src/app/components/reload-workspace-toast.tsx
Add trigger prop:
export type ReloadWorkspaceToastProps = {
// ... existing props
trigger?: { type: string; name?: string } | null;
};
Update description display:
const getDescription = () => {
if (!props.trigger) return props.description;
const { type, name } = props.trigger;
switch (type) {
case "skill":
return `Skill '${name}' was added. Reload to use it.`;
case "plugin":
return `Plugin '${name}' was added. Reload to activate.`;
case "mcp":
return `MCP '${name}' was added. Reload to connect.`;
default:
return "Config changed. Reload to apply.";
}
};
4. Update callers to pass trigger info
Find all places that call markReloadRequired and add trigger details:
- When skill is created:
markReloadRequired("skills", { type: "skill", name: skillName }) - When plugin is added:
markReloadRequired("plugins", { type: "plugin", name: pluginName }) - When MCP is added:
markReloadRequired("mcp", { type: "mcp", name: mcpName })
Concrete hook points:
- Skills:
packages/app/src/app/context/extensions.ts:588,669,750 - Plugins:
packages/app/src/app/context/extensions.ts:526,549 - MCP:
packages/app/src/app/app.tsx:2557 - Config/model changes:
packages/app/src/app/app.tsx:3020,3034 - File watcher:
packages/app/src/app/app.tsx:1870-1902(parseevent.payload.path)
Toast behavior rules
Toast should ONLY hide when:
- User clicks "Dismiss"
- User clicks "Reload" AND reload completes successfully
Toast should NOT auto-hide on:
- Timeout
- Navigation
- Any automatic state change
Testing
- Create a skill → verify toast shows "Skill 'X' was added"
- Add a plugin → verify toast shows "Plugin 'X' was added"
- Change config → verify toast shows "Config changed"
- Wait 30 seconds → verify toast still visible
- Click Dismiss → verify toast hides
- Trigger again → verify toast reappears