feat(status-ui): improve concurrent session workflows
Add in-place session renewal, searchable model selection, clearer progress feedback, tool-result previews, and per-session presentation state. Keep commands, errors, loading, and lifecycle indicators attached to their owning runtime so parallel tabs cannot interfere.
This commit is contained in:
@@ -29,28 +29,46 @@ export function useWorkspace() {
|
||||
const disposed = useRef(true);
|
||||
const refreshGeneration = useRef(0);
|
||||
|
||||
const loadSnapshot = useCallback(async (runtimeId: string) => {
|
||||
if (disposed.current) return;
|
||||
const generation = (loadGeneration.current[runtimeId] ?? 0) + 1;
|
||||
loadGeneration.current[runtimeId] = generation;
|
||||
dispatch({ type: "snapshotRequested", runtimeId, generation });
|
||||
try {
|
||||
const snapshot = await invoke<RuntimeSnapshot>(
|
||||
"get_session_runtime_snapshot",
|
||||
{ runtimeId },
|
||||
);
|
||||
if (!disposed.current)
|
||||
dispatch({ type: "snapshotLoaded", runtimeId, generation, snapshot });
|
||||
} catch (error) {
|
||||
if (!disposed.current)
|
||||
dispatch({
|
||||
type: "snapshotFailed",
|
||||
runtimeId,
|
||||
generation,
|
||||
error: String(error),
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
const loadSnapshot = useCallback(
|
||||
async (runtimeId: string, options: { throwOnError?: boolean } = {}) => {
|
||||
if (disposed.current) return false;
|
||||
const generation = (loadGeneration.current[runtimeId] ?? 0) + 1;
|
||||
loadGeneration.current[runtimeId] = generation;
|
||||
dispatch({ type: "snapshotRequested", runtimeId, generation });
|
||||
try {
|
||||
const snapshot = await invoke<RuntimeSnapshot>(
|
||||
"get_session_runtime_snapshot",
|
||||
{ runtimeId },
|
||||
);
|
||||
if (!disposed.current)
|
||||
dispatch({ type: "snapshotLoaded", runtimeId, generation, snapshot });
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (!disposed.current)
|
||||
dispatch({
|
||||
type: "snapshotFailed",
|
||||
runtimeId,
|
||||
generation,
|
||||
error: String(error),
|
||||
});
|
||||
if (options.throwOnError) throw error;
|
||||
return false;
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const snapshotRetryKey = Object.values(state.runtimesById)
|
||||
.flatMap((runtime) =>
|
||||
runtime.snapshotRetry ? [runtime.summary.runtimeId] : [],
|
||||
)
|
||||
.sort((left, right) => left.localeCompare(right))
|
||||
.join("\n");
|
||||
useEffect(() => {
|
||||
if (!snapshotRetryKey) return;
|
||||
for (const runtimeId of snapshotRetryKey.split("\n"))
|
||||
void loadSnapshot(runtimeId);
|
||||
}, [snapshotRetryKey, loadSnapshot]);
|
||||
|
||||
const scheduleSnapshot = useCallback(
|
||||
(runtimeId: string) => {
|
||||
@@ -177,6 +195,7 @@ export function useWorkspace() {
|
||||
"runtime_opened",
|
||||
"runtime_closed",
|
||||
"runtime_recovered",
|
||||
"runtime_renewed",
|
||||
"runtime_restore_failed",
|
||||
].includes(eventType ?? "")
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user