refactor: organize frontend components into features/ directories

Moved 43 component files into 9 feature domains:
- features/git/ — commit-dialog, commit-panel, file-editor, git-mount-editor,
  git-toolbar, merge-dialog
- features/project/ — repositories-settings-tab, repository-create-dialog
- features/terminal/ — special-keys-panel, special-keys-strip,
  terminal-session-tabs, terminal
- features/workspace/ — workspace-card, workspace-create-form,
  workspace-header, workspace-instance-chips
- features/session/ — create-session-form, session-card, session-list
- features/tool/ — instance-list, manifest-editor, start-tool-fab,
  start-tool-modal, tool-starter, tools-bottom-sheet
- features/notification/ — event-toast-bridge, notification-center,
  notification-item
- features/settings/ — settings-tab-layout
- features/mobile/ — mobile-action-sheet, mobile-detail-view, mobile-edit-view,
  mobile-fab, mobile-list-view, mobile-nav, mobile-page-header,
  mobile-terminal-header, mobile-terminal-wrapper

Updated all imports across pages and components.
Root components/ now only contains generic UI pieces:
app-shell, code-editor, data-states, icon, protected-route, syntax-highlighter.

Quality gates: verified no remaining old imports.
This commit is contained in:
2026-06-04 12:37:24 +02:00
parent 7224afafd1
commit 1021d61be3
54 changed files with 31 additions and 31 deletions
@@ -0,0 +1,77 @@
import { useEffect, useRef, useState } from "react";
import { useEventContext } from "../state/events";
import {
handleEventToast,
mapEventToCategory,
mapEventToSeverity,
} from "./toast-rules";
import { getUserConfig } from "../api/settings";
import type { UserConfig } from "../api/settings";
interface ToastConfig {
notification_toast_level: string;
notification_mute_categories: string[];
}
export function EventToastBridge(): JSX.Element | null {
const { events } = useEventContext();
const processedRef = useRef<Set<string>>(new Set());
const [config, setConfig] = useState<ToastConfig | null>(null);
useEffect(() => {
getUserConfig()
.then((c) => {
setConfig({
notification_toast_level: c.notification_toast_level ?? "all",
notification_mute_categories: c.notification_mute_categories ?? [],
});
})
.catch(() => {
setConfig({
notification_toast_level: "all",
notification_mute_categories: [],
});
});
const handler = (e: Event) => {
const detail = (e as CustomEvent<Partial<UserConfig>>).detail;
if (detail) {
setConfig((prev) => ({
notification_toast_level:
detail.notification_toast_level ??
prev?.notification_toast_level ??
"all",
notification_mute_categories:
detail.notification_mute_categories ??
prev?.notification_mute_categories ??
[],
}));
}
};
window.addEventListener("userconfig:updated", handler);
return () => window.removeEventListener("userconfig:updated", handler);
}, []);
useEffect(() => {
if (!config) return;
for (const event of events) {
const key = `${event.correlation_id}:${event.timestamp}`;
if (processedRef.current.has(key)) continue;
processedRef.current.add(key);
const category = mapEventToCategory(event);
const severity = mapEventToSeverity(event);
if (config.notification_toast_level === "none") continue;
if (config.notification_toast_level === "errors" && severity !== "error")
continue;
if (config.notification_mute_categories.includes(category)) continue;
handleEventToast(event);
}
}, [events, config]);
return null;
}