@iloveagents/foundry-web-ui 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -5
- package/dist/components/ag-ui-runtime-provider.d.ts +64 -0
- package/dist/components/ag-ui-runtime-provider.js +71 -0
- package/dist/components/app-brand.d.ts +6 -0
- package/dist/components/app-brand.js +13 -0
- package/dist/components/assistant-chat.d.ts +26 -0
- package/dist/components/assistant-chat.js +93 -0
- package/dist/components/chat-attachments.d.ts +25 -0
- package/dist/components/chat-attachments.js +20 -0
- package/dist/components/chat-bubble.d.ts +1 -0
- package/dist/components/chat-bubble.js +103 -0
- package/dist/components/chat-header.d.ts +2 -0
- package/dist/components/chat-header.js +16 -0
- package/dist/components/client-tool-executor.d.ts +12 -0
- package/dist/components/client-tool-executor.js +108 -0
- package/dist/components/collection-empty-state.d.ts +9 -0
- package/dist/components/collection-empty-state.js +6 -0
- package/dist/components/collection-filter-bar.d.ts +19 -0
- package/dist/components/collection-filter-bar.js +28 -0
- package/dist/components/collection-search-input.d.ts +6 -0
- package/dist/components/collection-search-input.js +8 -0
- package/dist/components/collection-skeleton.d.ts +6 -0
- package/dist/components/collection-skeleton.js +10 -0
- package/dist/components/collection-sort-menu.d.ts +10 -0
- package/dist/components/collection-sort-menu.js +9 -0
- package/dist/components/collection-surface.d.ts +8 -0
- package/dist/components/collection-surface.js +5 -0
- package/dist/components/collection-toolbar.d.ts +9 -0
- package/dist/components/collection-toolbar.js +5 -0
- package/dist/components/collection-view-toggle.d.ts +7 -0
- package/dist/components/collection-view-toggle.js +17 -0
- package/dist/components/composer-submit-bridge.d.ts +1 -0
- package/dist/components/composer-submit-bridge.js +15 -0
- package/dist/components/confirm-dialog.d.ts +11 -0
- package/dist/components/confirm-dialog.js +6 -0
- package/dist/components/confirmation-card.d.ts +14 -0
- package/dist/components/confirmation-card.js +12 -0
- package/dist/components/context-badges.d.ts +16 -0
- package/dist/components/context-badges.js +56 -0
- package/dist/components/context-bar.d.ts +41 -0
- package/dist/components/context-bar.js +123 -0
- package/dist/components/form-dialog.d.ts +12 -0
- package/dist/components/form-dialog.js +13 -0
- package/dist/components/global-selection-popover.d.ts +7 -0
- package/dist/components/global-selection-popover.js +167 -0
- package/dist/components/infinite-scroll-sentinel.d.ts +6 -0
- package/dist/components/infinite-scroll-sentinel.js +25 -0
- package/dist/components/json-viewer.d.ts +10 -0
- package/dist/components/json-viewer.js +80 -0
- package/dist/components/loading-indicator.d.ts +4 -0
- package/dist/components/loading-indicator.js +22 -0
- package/dist/components/markdown-text.d.ts +13 -0
- package/dist/components/markdown-text.js +221 -0
- package/dist/components/name-dialog.d.ts +16 -0
- package/dist/components/name-dialog.js +23 -0
- package/dist/components/selection-popover.d.ts +12 -0
- package/dist/components/selection-popover.js +111 -0
- package/dist/components/show-document-tool-ui.d.ts +1 -0
- package/dist/components/show-document-tool-ui.js +53 -0
- package/dist/components/sidebar.d.ts +4 -0
- package/dist/components/sidebar.js +904 -0
- package/dist/components/surface-card.d.ts +9 -0
- package/dist/components/surface-card.js +33 -0
- package/dist/components/theme-runtime-provider.d.ts +15 -0
- package/dist/components/theme-runtime-provider.js +48 -0
- package/dist/components/theme-toggle.d.ts +2 -0
- package/dist/components/theme-toggle.js +19 -0
- package/dist/components/tool-call-card.d.ts +27 -0
- package/dist/components/tool-call-card.js +13 -0
- package/dist/components/tool-fallback.d.ts +26 -0
- package/dist/components/tool-fallback.js +129 -0
- package/dist/components/tool-panel-layout.d.ts +10 -0
- package/dist/components/tool-panel-layout.js +12 -0
- package/dist/components/tool-panel.d.ts +1 -0
- package/dist/components/tool-panel.js +89 -0
- package/dist/components/tooltip-icon-button.d.ts +7 -0
- package/dist/components/tooltip-icon-button.js +9 -0
- package/dist/components/user-menu.d.ts +2 -0
- package/dist/components/user-menu.js +14 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.js +83 -0
- package/dist/lib/ag-ui-adapter.d.ts +29 -0
- package/dist/lib/ag-ui-adapter.js +373 -0
- package/dist/lib/app-store.d.ts +115 -0
- package/dist/lib/app-store.js +199 -0
- package/dist/lib/attachment-adapter.d.ts +20 -0
- package/dist/lib/attachment-adapter.js +99 -0
- package/dist/lib/auth-provider.d.ts +16 -0
- package/dist/lib/auth-provider.js +88 -0
- package/dist/lib/chat-bubble-store.d.ts +30 -0
- package/dist/lib/chat-bubble-store.js +23 -0
- package/dist/lib/chat-lifecycle-store.d.ts +10 -0
- package/{src/lib/chat-lifecycle-store.ts → dist/lib/chat-lifecycle-store.js} +3 -13
- package/dist/lib/client-tools.d.ts +11 -0
- package/dist/lib/client-tools.js +274 -0
- package/dist/lib/composer-submit-store.d.ts +12 -0
- package/dist/lib/composer-submit-store.js +17 -0
- package/dist/lib/dev-store.d.ts +38 -0
- package/dist/lib/dev-store.js +32 -0
- package/dist/lib/nav-config.d.ts +159 -0
- package/dist/lib/nav-config.js +162 -0
- package/dist/lib/nav-dnd.d.ts +8 -0
- package/dist/lib/nav-dnd.js +9 -0
- package/dist/lib/nav-store.d.ts +45 -0
- package/dist/lib/nav-store.js +49 -0
- package/dist/lib/selection-context.d.ts +21 -0
- package/dist/lib/selection-context.js +34 -0
- package/dist/lib/sidebar-store.d.ts +23 -0
- package/dist/lib/sidebar-store.js +98 -0
- package/dist/lib/theme-runtime.d.ts +130 -0
- package/dist/lib/theme-runtime.js +479 -0
- package/dist/lib/theme-store.d.ts +15 -0
- package/dist/lib/theme-store.js +53 -0
- package/dist/lib/tool-panel-store.d.ts +48 -0
- package/dist/lib/tool-panel-store.js +69 -0
- package/dist/lib/use-new-conversation.d.ts +8 -0
- package/dist/lib/use-new-conversation.js +62 -0
- package/dist/lib/use-page-tools.d.ts +27 -0
- package/{src/lib/use-page-tools.ts → dist/lib/use-page-tools.js} +11 -13
- package/dist/styles.css +142 -0
- package/dist/ui/collapsible.d.ts +5 -0
- package/{src/ui/collapsible.tsx → dist/ui/collapsible.js} +0 -2
- package/dist/ui/dialog.d.ts +15 -0
- package/dist/ui/dialog.js +25 -0
- package/dist/ui/dropdown-menu.d.ts +7 -0
- package/dist/ui/dropdown-menu.js +19 -0
- package/dist/ui/popover.d.ts +7 -0
- package/dist/ui/popover.js +10 -0
- package/dist/ui/select.d.ts +4 -0
- package/dist/ui/select.js +9 -0
- package/dist/ui/tooltip.d.ts +7 -0
- package/dist/ui/tooltip.js +10 -0
- package/package.json +31 -12
- package/AGENTS.md +0 -59
- package/CHANGELOG.md +0 -203
- package/CLAUDE.md +0 -1
- package/src/__tests__/no-spaces-imports.test.ts +0 -59
- package/src/__tests__/open-core-guards.test.ts +0 -307
- package/src/__tests__/theme-runtime.test.ts +0 -81
- package/src/__tests__/tool-fallback.test.tsx +0 -109
- package/src/components/__tests__/context-bar.test.ts +0 -112
- package/src/components/ag-ui-runtime-provider.tsx +0 -170
- package/src/components/app-brand.tsx +0 -38
- package/src/components/assistant-chat.tsx +0 -461
- package/src/components/chat-attachments.tsx +0 -68
- package/src/components/chat-bubble.tsx +0 -373
- package/src/components/chat-header.tsx +0 -44
- package/src/components/client-tool-executor.tsx +0 -230
- package/src/components/collection-empty-state.tsx +0 -37
- package/src/components/collection-filter-bar.tsx +0 -168
- package/src/components/collection-search-input.tsx +0 -41
- package/src/components/collection-skeleton.tsx +0 -55
- package/src/components/collection-sort-menu.tsx +0 -62
- package/src/components/collection-surface.tsx +0 -46
- package/src/components/collection-toolbar.tsx +0 -33
- package/src/components/collection-view-toggle.tsx +0 -61
- package/src/components/composer-submit-bridge.tsx +0 -19
- package/src/components/confirm-dialog.tsx +0 -49
- package/src/components/confirmation-card.tsx +0 -32
- package/src/components/context-badges.tsx +0 -136
- package/src/components/context-bar.tsx +0 -238
- package/src/components/form-dialog.tsx +0 -56
- package/src/components/global-selection-popover.tsx +0 -266
- package/src/components/infinite-scroll-sentinel.tsx +0 -48
- package/src/components/json-viewer.tsx +0 -232
- package/src/components/loading-indicator.tsx +0 -40
- package/src/components/markdown-text-citations.test.tsx +0 -108
- package/src/components/markdown-text.tsx +0 -508
- package/src/components/name-dialog.tsx +0 -87
- package/src/components/selection-popover.tsx +0 -156
- package/src/components/show-document-tool-ui.tsx +0 -90
- package/src/components/sidebar.test.tsx +0 -611
- package/src/components/sidebar.tsx +0 -1689
- package/src/components/surface-card.tsx +0 -45
- package/src/components/theme-runtime-provider.tsx +0 -93
- package/src/components/theme-toggle.tsx +0 -27
- package/src/components/tool-call-card.tsx +0 -126
- package/src/components/tool-fallback.tsx +0 -169
- package/src/components/tool-panel-layout.tsx +0 -36
- package/src/components/tool-panel.tsx +0 -233
- package/src/components/tooltip-icon-button.tsx +0 -28
- package/src/components/user-menu.tsx +0 -60
- package/src/index.ts +0 -185
- package/src/lib/__tests__/ag-ui-adapter.test.ts +0 -273
- package/src/lib/__tests__/app-store.test.ts +0 -405
- package/src/lib/__tests__/attachment-adapter.test.ts +0 -48
- package/src/lib/__tests__/chat-bubble-store.test.ts +0 -67
- package/src/lib/__tests__/client-tools.test.ts +0 -124
- package/src/lib/__tests__/dev-store.test.ts +0 -78
- package/src/lib/__tests__/nav-config.test.ts +0 -135
- package/src/lib/__tests__/nav-dnd.test.ts +0 -24
- package/src/lib/__tests__/nav-store.test.ts +0 -59
- package/src/lib/__tests__/selection-context.test.ts +0 -114
- package/src/lib/__tests__/sidebar-store.test.ts +0 -144
- package/src/lib/__tests__/theme-store.test.ts +0 -83
- package/src/lib/__tests__/tool-panel-store.test.ts +0 -61
- package/src/lib/__tests__/use-page-context.test.ts +0 -58
- package/src/lib/ag-ui-adapter.ts +0 -412
- package/src/lib/app-store.ts +0 -361
- package/src/lib/attachment-adapter.ts +0 -92
- package/src/lib/auth-provider.tsx +0 -144
- package/src/lib/chat-bubble-store.ts +0 -46
- package/src/lib/client-tools.ts +0 -293
- package/src/lib/composer-submit-store.ts +0 -32
- package/src/lib/dev-store.ts +0 -69
- package/src/lib/nav-config.ts +0 -329
- package/src/lib/nav-dnd.ts +0 -14
- package/src/lib/nav-store.ts +0 -89
- package/src/lib/selection-context.ts +0 -65
- package/src/lib/sidebar-store.ts +0 -113
- package/src/lib/theme-runtime.ts +0 -660
- package/src/lib/theme-store.ts +0 -67
- package/src/lib/tool-panel-store.ts +0 -121
- package/src/lib/use-new-conversation.test.tsx +0 -168
- package/src/lib/use-new-conversation.ts +0 -64
- package/src/ui/dialog.tsx +0 -109
- package/src/ui/dropdown-menu.tsx +0 -75
- package/src/ui/popover.tsx +0 -34
- package/src/ui/select.tsx +0 -15
- package/src/ui/tooltip.tsx +0 -30
- package/src/vite-env.d.ts +0 -1
- package/tsconfig.json +0 -16
- package/vitest.config.ts +0 -8
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type VariantProps } from "class-variance-authority";
|
|
2
|
+
import type { ComponentPropsWithoutRef } from "react";
|
|
3
|
+
declare const surfaceCardVariants: (props?: ({
|
|
4
|
+
tone?: "default" | "muted" | "empty" | "subtle" | null | undefined;
|
|
5
|
+
radius?: "lg" | "md" | "xl" | null | undefined;
|
|
6
|
+
padding?: "sm" | "lg" | "md" | "xl" | null | undefined;
|
|
7
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
8
|
+
export declare function SurfaceCard({ className, tone, radius, padding, ...props }: ComponentPropsWithoutRef<"div"> & VariantProps<typeof surfaceCardVariants>): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export { surfaceCardVariants };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cva } from "class-variance-authority";
|
|
3
|
+
import { cn } from "@iloveagents/foundry-web-primitives";
|
|
4
|
+
const surfaceCardVariants = cva("border border-border shadow-sm", {
|
|
5
|
+
variants: {
|
|
6
|
+
tone: {
|
|
7
|
+
default: "bg-card",
|
|
8
|
+
subtle: "bg-background/80",
|
|
9
|
+
muted: "bg-muted/10",
|
|
10
|
+
empty: "border-dashed bg-muted/10 text-sm text-muted-foreground",
|
|
11
|
+
},
|
|
12
|
+
radius: {
|
|
13
|
+
md: "rounded-xl",
|
|
14
|
+
lg: "rounded-[1.5rem]",
|
|
15
|
+
xl: "rounded-[2rem]",
|
|
16
|
+
},
|
|
17
|
+
padding: {
|
|
18
|
+
sm: "p-4",
|
|
19
|
+
md: "p-5",
|
|
20
|
+
lg: "p-6",
|
|
21
|
+
xl: "p-7",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
defaultVariants: {
|
|
25
|
+
tone: "default",
|
|
26
|
+
radius: "lg",
|
|
27
|
+
padding: "md",
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
export function SurfaceCard({ className, tone, radius, padding, ...props }) {
|
|
31
|
+
return (_jsx("div", { className: cn(surfaceCardVariants({ tone, radius, padding }), className), ...props }));
|
|
32
|
+
}
|
|
33
|
+
export { surfaceCardVariants };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type CSSProperties, type ReactNode } from "react";
|
|
2
|
+
import type { ThemeMode } from "../lib/theme-store.js";
|
|
3
|
+
import { type ResolvedThemeRuntime, type ThemeLayer } from "../lib/theme-runtime.js";
|
|
4
|
+
export declare function ThemeRuntimeProvider({ layers, mode, children, }: {
|
|
5
|
+
layers: ThemeLayer[];
|
|
6
|
+
mode: ThemeMode;
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export declare function useThemeRuntime(): ResolvedThemeRuntime;
|
|
10
|
+
export declare function ThemeScope({ children, className, style, }: {
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
className?: string;
|
|
13
|
+
style?: CSSProperties;
|
|
14
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export declare function ThemeDocumentMetadata(): null;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useEffect, useMemo, useRef, useState, } from "react";
|
|
3
|
+
import { resolveThemeRuntime, } from "../lib/theme-runtime.js";
|
|
4
|
+
const ThemeRuntimeContext = createContext(null);
|
|
5
|
+
export function ThemeRuntimeProvider({ layers, mode, children, }) {
|
|
6
|
+
const fallback = useRef(resolveThemeRuntime([], "system"));
|
|
7
|
+
const [systemPrefersDark, setSystemPrefersDark] = useState(() => typeof window !== "undefined"
|
|
8
|
+
? window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
9
|
+
: false);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (mode !== "system" || typeof window === "undefined")
|
|
12
|
+
return;
|
|
13
|
+
const media = window.matchMedia("(prefers-color-scheme: dark)");
|
|
14
|
+
const handleChange = (event) => {
|
|
15
|
+
setSystemPrefersDark(event.matches);
|
|
16
|
+
};
|
|
17
|
+
setSystemPrefersDark(media.matches);
|
|
18
|
+
media.addEventListener("change", handleChange);
|
|
19
|
+
return () => media.removeEventListener("change", handleChange);
|
|
20
|
+
}, [mode]);
|
|
21
|
+
const runtime = useMemo(() => {
|
|
22
|
+
try {
|
|
23
|
+
const next = resolveThemeRuntime(layers, mode);
|
|
24
|
+
fallback.current = next;
|
|
25
|
+
return next;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return fallback.current;
|
|
29
|
+
}
|
|
30
|
+
}, [layers, mode, systemPrefersDark]);
|
|
31
|
+
return _jsx(ThemeRuntimeContext.Provider, { value: runtime, children: children });
|
|
32
|
+
}
|
|
33
|
+
export function useThemeRuntime() {
|
|
34
|
+
return useContext(ThemeRuntimeContext) ?? resolveThemeRuntime([], "system");
|
|
35
|
+
}
|
|
36
|
+
export function ThemeScope({ children, className, style, }) {
|
|
37
|
+
const runtime = useThemeRuntime();
|
|
38
|
+
return (_jsx("div", { className: className, style: { ...runtime.variables, fontFamily: "var(--font-body)", ...style }, children: children }));
|
|
39
|
+
}
|
|
40
|
+
export function ThemeDocumentMetadata() {
|
|
41
|
+
const runtime = useThemeRuntime();
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (typeof document === "undefined")
|
|
44
|
+
return;
|
|
45
|
+
document.title = runtime.branding.appTitle || runtime.branding.appName || "Foundry UI";
|
|
46
|
+
}, [runtime.branding.appName, runtime.branding.appTitle]);
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Sun, Moon, Monitor } from "lucide-react";
|
|
3
|
+
import { TooltipIconButton } from "./tooltip-icon-button.js";
|
|
4
|
+
import { useThemeStore } from "../lib/theme-store.js";
|
|
5
|
+
const icons = {
|
|
6
|
+
light: Sun,
|
|
7
|
+
dark: Moon,
|
|
8
|
+
system: Monitor,
|
|
9
|
+
};
|
|
10
|
+
const labels = {
|
|
11
|
+
light: "Light mode",
|
|
12
|
+
dark: "Dark mode",
|
|
13
|
+
system: "System theme",
|
|
14
|
+
};
|
|
15
|
+
export const ThemeToggle = () => {
|
|
16
|
+
const { mode, cycle } = useThemeStore();
|
|
17
|
+
const Icon = icons[mode];
|
|
18
|
+
return (_jsx(TooltipIconButton, { tooltip: labels[mode], size: "icon", onClick: cycle, children: _jsx(Icon, { className: "size-4 text-primary" }) }));
|
|
19
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export type ToolCallStatus = {
|
|
3
|
+
type: "running";
|
|
4
|
+
} | {
|
|
5
|
+
type: "complete";
|
|
6
|
+
} | {
|
|
7
|
+
type: "incomplete";
|
|
8
|
+
reason?: string;
|
|
9
|
+
} | {
|
|
10
|
+
type: "requires-action";
|
|
11
|
+
reason?: string;
|
|
12
|
+
};
|
|
13
|
+
interface ToolCallCardProps {
|
|
14
|
+
icon?: ReactNode;
|
|
15
|
+
title: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
status: ToolCallStatus;
|
|
18
|
+
action?: {
|
|
19
|
+
label: string;
|
|
20
|
+
onClick: () => void;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
};
|
|
23
|
+
children?: ReactNode;
|
|
24
|
+
className?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare function ToolCallCard({ icon, title, description, status, action, children, className, }: ToolCallCardProps): import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Loader2, CheckCircle2, XCircle, AlertCircle, ChevronDown } from "lucide-react";
|
|
3
|
+
import { cn } from "@iloveagents/foundry-web-primitives";
|
|
4
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "../ui/collapsible.js";
|
|
5
|
+
import { useState } from "react";
|
|
6
|
+
export function ToolCallCard({ icon, title, description, status, action, children, className, }) {
|
|
7
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
8
|
+
const isSuccess = status.type === "complete";
|
|
9
|
+
const isError = status.type === "incomplete" && status.reason === "error";
|
|
10
|
+
const isRunning = status.type === "running";
|
|
11
|
+
const requiresAction = status.type === "requires-action";
|
|
12
|
+
return (_jsx(Collapsible, { open: isOpen, onOpenChange: setIsOpen, className: className, children: _jsxs("div", { className: cn("flex items-start gap-3 p-3 rounded-lg border", "bg-muted/50 text-sm transition-colors", isSuccess && "border-primary/30 bg-primary/5", isError && "border-destructive/30 bg-destructive/5", requiresAction && "border-primary/30 bg-primary/5"), children: [_jsxs("div", { className: "flex-shrink-0 mt-0.5", children: [isRunning && _jsx(Loader2, { className: "size-4 text-primary animate-spin" }), isSuccess && _jsx(CheckCircle2, { className: "size-4 text-primary" }), isError && _jsx(XCircle, { className: "size-4 text-destructive" }), requiresAction && _jsx(AlertCircle, { className: "size-4 text-primary" })] }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "flex items-center gap-2", children: [icon && _jsx("span", { className: "text-muted-foreground", children: icon }), _jsx("span", { className: "font-medium text-foreground", children: title }), _jsxs("div", { className: "ml-auto flex items-center gap-1.5", children: [action && !isRunning && (_jsx("button", { type: "button", onClick: action.onClick, disabled: action.disabled, className: cn("h-6 px-2.5 text-xs font-medium rounded-md", "border border-primary/30 text-primary", "hover:bg-primary/10 transition-colors", "disabled:opacity-50 disabled:pointer-events-none"), children: action.label })), children && (_jsx(CollapsibleTrigger, { asChild: true, children: _jsx("button", { type: "button", className: "p-0.5 hover:bg-muted rounded transition-colors", "aria-label": "Toggle details", children: _jsx(ChevronDown, { className: cn("size-4 text-muted-foreground transition-transform", isOpen && "rotate-180") }) }) }))] })] }), description && (_jsx("div", { className: cn("text-xs mt-0.5", isError ? "text-destructive" : "text-primary"), children: description })), children && (_jsx(CollapsibleContent, { children: _jsx("div", { className: "mt-2", children: children }) }))] })] }) }));
|
|
13
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare const ToolFallback: (props: Record<string, unknown>) => import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
/**
|
|
3
|
+
* Heuristically detect a failed tool result. The agent-framework
|
|
4
|
+
* adapter flattens both plain-Python and MCP tool errors into the
|
|
5
|
+
* same ``result`` field without a dedicated error flag, so we have
|
|
6
|
+
* to sniff:
|
|
7
|
+
*
|
|
8
|
+
* - MCP canonical shape: ``{isError: true, content: [...]}``
|
|
9
|
+
* - Python ``@tool`` exception: a string starting with ``"Error:"``
|
|
10
|
+
* (agent-framework's default serialization — see
|
|
11
|
+
* ``agent_framework/_tools.py::_serialize_tool_exception``).
|
|
12
|
+
* - Structured error objects: ``{error: "..."}`` or
|
|
13
|
+
* ``{error: {message: "..."}}`` — what FastMCP's ``ToolError``
|
|
14
|
+
* (re-)raises produce.
|
|
15
|
+
*
|
|
16
|
+
* Keep this narrow. A substring match on ``"Error"`` would false-
|
|
17
|
+
* positive on legitimate results ("…contains the word Error in a
|
|
18
|
+
* heading…"), so anchor patterns to prefix / explicit fields only.
|
|
19
|
+
*/
|
|
20
|
+
export declare function _detectErrorResult(result: unknown): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Pull a user-readable one-liner out of an error result so the card
|
|
23
|
+
* header shows *why* it failed rather than the generic "Execution
|
|
24
|
+
* failed". Matches the shapes enumerated in ``detectErrorResult``.
|
|
25
|
+
*/
|
|
26
|
+
export declare function _extractErrorMessage(result: unknown): string | null;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ToolCallCard } from "./tool-call-card.js";
|
|
3
|
+
import { Wrench } from "lucide-react";
|
|
4
|
+
export const ToolFallback = (props) => {
|
|
5
|
+
const { toolName, args, result, part } = props;
|
|
6
|
+
const rawStatus = part?.status || props.status;
|
|
7
|
+
// Tool results that *describe* a failure (Python ``@tool`` raises an
|
|
8
|
+
// exception → agent-framework serializes it as an error string;
|
|
9
|
+
// FastMCP returns ``{isError: true, content: [...]}``; our own tools
|
|
10
|
+
// sometimes return a plain ``"Error: ..."`` string) arrive here with
|
|
11
|
+
// ``status.type === "complete"`` because the tool-call round-trip
|
|
12
|
+
// succeeded from the transport's point of view. Without sniffing
|
|
13
|
+
// the payload we'd render "Execution complete" in green for a red
|
|
14
|
+
// condition — exactly what the user called out. Normalize to the
|
|
15
|
+
// ``incomplete + reason: "error"`` state the card knows how to
|
|
16
|
+
// show in red with an X-circle.
|
|
17
|
+
const isErrorResult = _detectErrorResult(result);
|
|
18
|
+
const status = isErrorResult
|
|
19
|
+
? { type: "incomplete", reason: "error" }
|
|
20
|
+
: rawStatus;
|
|
21
|
+
let description = "";
|
|
22
|
+
if (status.type === "running") {
|
|
23
|
+
description = `Executing ${toolName}...`;
|
|
24
|
+
}
|
|
25
|
+
else if (status.type === "incomplete" && status.reason === "error") {
|
|
26
|
+
description = _extractErrorMessage(result) ?? "Execution failed";
|
|
27
|
+
}
|
|
28
|
+
else if (status.type === "complete") {
|
|
29
|
+
description = result ? "Execution complete" : "Completed";
|
|
30
|
+
}
|
|
31
|
+
else if (status.type === "requires-action") {
|
|
32
|
+
description = "Waiting for execution...";
|
|
33
|
+
}
|
|
34
|
+
return (_jsxs(ToolCallCard, { icon: _jsx(Wrench, { className: "size-3.5" }), title: formatToolName(toolName), description: description, status: status, className: "w-full", children: [args && Object.keys(args).length > 0 && (_jsx("div", { className: "text-muted-foreground text-xs space-y-1", children: Object.entries(args).map(([key, value]) => (_jsxs("div", { children: [_jsxs("span", { className: "font-medium", children: [key, ":"] }), " ", _jsx("span", { className: "font-mono", children: formatValue(value) })] }, key))) })), (status.type === "complete" ||
|
|
35
|
+
(status.type === "incomplete" && status.reason === "error")) &&
|
|
36
|
+
result != null && (_jsxs("div", { className: "text-muted-foreground text-xs mt-2 pt-2 border-t border-border", children: [_jsxs("div", { className: "font-medium mb-1", children: [status.type === "incomplete" ? "Error" : "Result", ":"] }), _jsx("pre", { className: "font-mono text-xs bg-muted p-2 rounded overflow-x-auto", children: formatResult(result) })] }))] }));
|
|
37
|
+
};
|
|
38
|
+
function formatToolName(toolName) {
|
|
39
|
+
return toolName
|
|
40
|
+
.split("_")
|
|
41
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
42
|
+
.join(" ");
|
|
43
|
+
}
|
|
44
|
+
function formatValue(value) {
|
|
45
|
+
if (typeof value === "string")
|
|
46
|
+
return value;
|
|
47
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
48
|
+
return String(value);
|
|
49
|
+
return JSON.stringify(value);
|
|
50
|
+
}
|
|
51
|
+
function formatResult(result) {
|
|
52
|
+
if (typeof result === "string")
|
|
53
|
+
return result;
|
|
54
|
+
return JSON.stringify(result, null, 2);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Heuristically detect a failed tool result. The agent-framework
|
|
58
|
+
* adapter flattens both plain-Python and MCP tool errors into the
|
|
59
|
+
* same ``result`` field without a dedicated error flag, so we have
|
|
60
|
+
* to sniff:
|
|
61
|
+
*
|
|
62
|
+
* - MCP canonical shape: ``{isError: true, content: [...]}``
|
|
63
|
+
* - Python ``@tool`` exception: a string starting with ``"Error:"``
|
|
64
|
+
* (agent-framework's default serialization — see
|
|
65
|
+
* ``agent_framework/_tools.py::_serialize_tool_exception``).
|
|
66
|
+
* - Structured error objects: ``{error: "..."}`` or
|
|
67
|
+
* ``{error: {message: "..."}}`` — what FastMCP's ``ToolError``
|
|
68
|
+
* (re-)raises produce.
|
|
69
|
+
*
|
|
70
|
+
* Keep this narrow. A substring match on ``"Error"`` would false-
|
|
71
|
+
* positive on legitimate results ("…contains the word Error in a
|
|
72
|
+
* heading…"), so anchor patterns to prefix / explicit fields only.
|
|
73
|
+
*/
|
|
74
|
+
export function _detectErrorResult(result) {
|
|
75
|
+
if (result == null)
|
|
76
|
+
return false;
|
|
77
|
+
if (typeof result === "string") {
|
|
78
|
+
// Python tools: "Error: <message>" (agent-framework default).
|
|
79
|
+
return /^\s*Error:\s/.test(result);
|
|
80
|
+
}
|
|
81
|
+
if (typeof result === "object") {
|
|
82
|
+
const obj = result;
|
|
83
|
+
// MCP Streamable-HTTP canonical shape.
|
|
84
|
+
if (obj.isError === true)
|
|
85
|
+
return true;
|
|
86
|
+
// FastMCP ToolError + some of our hand-rolled paths.
|
|
87
|
+
if (typeof obj.error === "string" && obj.error.length > 0)
|
|
88
|
+
return true;
|
|
89
|
+
if (obj.error &&
|
|
90
|
+
typeof obj.error === "object" &&
|
|
91
|
+
typeof obj.error.message === "string") {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Pull a user-readable one-liner out of an error result so the card
|
|
99
|
+
* header shows *why* it failed rather than the generic "Execution
|
|
100
|
+
* failed". Matches the shapes enumerated in ``detectErrorResult``.
|
|
101
|
+
*/
|
|
102
|
+
export function _extractErrorMessage(result) {
|
|
103
|
+
if (typeof result === "string") {
|
|
104
|
+
// Strip the "Error: " prefix so the header isn't redundant.
|
|
105
|
+
const m = /^\s*Error:\s*(.*)$/s.exec(result);
|
|
106
|
+
return m ? m[1].trim() || "Execution failed" : null;
|
|
107
|
+
}
|
|
108
|
+
if (result && typeof result === "object") {
|
|
109
|
+
const obj = result;
|
|
110
|
+
if (typeof obj.error === "string")
|
|
111
|
+
return obj.error;
|
|
112
|
+
if (obj.error &&
|
|
113
|
+
typeof obj.error === "object" &&
|
|
114
|
+
typeof obj.error.message === "string") {
|
|
115
|
+
return obj.error.message;
|
|
116
|
+
}
|
|
117
|
+
if (Array.isArray(obj.content)) {
|
|
118
|
+
// MCP error: content[].text usually carries the human message.
|
|
119
|
+
for (const item of obj.content) {
|
|
120
|
+
if (item &&
|
|
121
|
+
typeof item === "object" &&
|
|
122
|
+
typeof item.text === "string") {
|
|
123
|
+
return item.text;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout wrapper that adjusts main content when tool panel is open.
|
|
3
|
+
* - Narrow screens (< 1280px): Full-screen overlay, chat hidden
|
|
4
|
+
* - Wide screens (>= 1280px): Side-by-side layout, chat shifts left
|
|
5
|
+
*/
|
|
6
|
+
interface ToolPanelLayoutProps {
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
export declare function ToolPanelLayout({ children }: ToolPanelLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "@iloveagents/foundry-web-primitives";
|
|
3
|
+
import { useToolPanelStore } from "../lib/tool-panel-store.js";
|
|
4
|
+
import { ToolPanel } from "./tool-panel.js";
|
|
5
|
+
export function ToolPanelLayout({ children }) {
|
|
6
|
+
const isOpen = useToolPanelStore((state) => state.isOpen);
|
|
7
|
+
const panelWidth = useToolPanelStore((state) => state.panelWidth);
|
|
8
|
+
const useOverlay = useToolPanelStore((state) => state.useOverlay);
|
|
9
|
+
return (_jsxs("div", { className: "relative h-full flex-1 min-w-0 overflow-hidden", children: [_jsx("div", { className: cn("h-full flex flex-col transition-all duration-300 ease-in-out", useOverlay && isOpen && "hidden"), style: {
|
|
10
|
+
width: isOpen && !useOverlay ? `calc(100% - ${panelWidth}px)` : "100%",
|
|
11
|
+
}, children: children }), _jsx(ToolPanel, {})] }));
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function ToolPanel(): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState, Suspense } from "react";
|
|
3
|
+
import { X, Maximize2, Minimize2, Copy, Check, Pin, PinOff, FolderOpen } from "lucide-react";
|
|
4
|
+
import { useNavigate } from "react-router";
|
|
5
|
+
import { cn } from "@iloveagents/foundry-web-primitives";
|
|
6
|
+
import { useToolPanelStore } from "../lib/tool-panel-store.js";
|
|
7
|
+
import { useAppStore } from "../lib/app-store.js";
|
|
8
|
+
import ReactMarkdown from "react-markdown";
|
|
9
|
+
import remarkGfm from "remark-gfm";
|
|
10
|
+
import { markdownComponents } from "./markdown-text.js";
|
|
11
|
+
import { SelectionPopover } from "./selection-popover.js";
|
|
12
|
+
/** Renders panel content using the renderer registry, then built-in markdown/text. */
|
|
13
|
+
function PanelContentRenderer({ content }) {
|
|
14
|
+
const renderers = useToolPanelStore((s) => s.renderers);
|
|
15
|
+
// Check registered renderers first (e.g., PDF viewer, entity pages, demo pages)
|
|
16
|
+
const customRenderer = renderers.find((r) => r.match(content));
|
|
17
|
+
if (customRenderer) {
|
|
18
|
+
const Component = customRenderer.component;
|
|
19
|
+
return (_jsx(Suspense, { fallback: null, children: _jsx(Component, { content: content }) }));
|
|
20
|
+
}
|
|
21
|
+
// Built-in markdown / text rendering
|
|
22
|
+
return (_jsx("div", { className: "px-6 py-4", children: content.type === "markdown" ? (_jsx("div", { className: "max-w-2xl mx-auto", children: _jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], components: markdownComponents, children: content.content }) })) : (_jsx("div", { className: "whitespace-pre-wrap text-sm text-foreground max-w-2xl mx-auto", children: content.content })) }));
|
|
23
|
+
}
|
|
24
|
+
export function ToolPanel() {
|
|
25
|
+
const isOpen = useToolPanelStore((state) => state.isOpen);
|
|
26
|
+
const content = useToolPanelStore((state) => state.content);
|
|
27
|
+
const closePanel = useToolPanelStore((state) => state.closePanel);
|
|
28
|
+
const panelWidth = useToolPanelStore((state) => state.panelWidth);
|
|
29
|
+
const isFullscreen = useToolPanelStore((state) => state.isFullscreen);
|
|
30
|
+
const toggleFullscreen = useToolPanelStore((state) => state.toggleFullscreen);
|
|
31
|
+
const navigate = useNavigate();
|
|
32
|
+
const contentRef = useRef(null);
|
|
33
|
+
const [copied, setCopied] = useState(false);
|
|
34
|
+
// Pin state for SPACES entities
|
|
35
|
+
const entityId = content?.entityId;
|
|
36
|
+
const contextItems = useAppStore((s) => s.contextItems);
|
|
37
|
+
const addContextItem = useAppStore((s) => s.addContextItem);
|
|
38
|
+
const removeContextItem = useAppStore((s) => s.removeContextItem);
|
|
39
|
+
const entityPin = entityId
|
|
40
|
+
? contextItems.find((i) => i.persistence === "persistent" &&
|
|
41
|
+
i.type === "page" &&
|
|
42
|
+
i.payload.kind === "page" &&
|
|
43
|
+
i.payload.path === `/spaces/${entityId}`)
|
|
44
|
+
: null;
|
|
45
|
+
const isEntityPinned = !!entityPin;
|
|
46
|
+
const handleToggleEntityPin = useCallback(() => {
|
|
47
|
+
if (!entityId || !content)
|
|
48
|
+
return;
|
|
49
|
+
if (entityPin) {
|
|
50
|
+
removeContextItem(entityPin.id);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
addContextItem({
|
|
54
|
+
type: "page",
|
|
55
|
+
label: content.title,
|
|
56
|
+
payload: { kind: "page", path: `/spaces/${entityId}`, label: content.title, meta: {} },
|
|
57
|
+
sourcePage: `/spaces/${entityId}`,
|
|
58
|
+
persistence: "persistent",
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}, [entityId, entityPin, content, addContextItem, removeContextItem]);
|
|
62
|
+
const handleNavigateToEntity = useCallback(() => {
|
|
63
|
+
if (!entityId || !content)
|
|
64
|
+
return;
|
|
65
|
+
navigate(content.type === "page" ? content.content : `/spaces/${entityId}`);
|
|
66
|
+
closePanel();
|
|
67
|
+
}, [entityId, content, navigate, closePanel]);
|
|
68
|
+
const handleCopyAll = useCallback(() => {
|
|
69
|
+
if (!content)
|
|
70
|
+
return;
|
|
71
|
+
navigator.clipboard.writeText(content.content).then(() => {
|
|
72
|
+
setCopied(true);
|
|
73
|
+
setTimeout(() => setCopied(false), 2000);
|
|
74
|
+
});
|
|
75
|
+
}, [content]);
|
|
76
|
+
// Close on Escape key
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
const handleEscape = (e) => {
|
|
79
|
+
if (e.key === "Escape" && isOpen) {
|
|
80
|
+
closePanel();
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
window.addEventListener("keydown", handleEscape);
|
|
84
|
+
return () => window.removeEventListener("keydown", handleEscape);
|
|
85
|
+
}, [isOpen, closePanel]);
|
|
86
|
+
if (!content)
|
|
87
|
+
return null;
|
|
88
|
+
return (_jsxs("div", { "data-tool-panel": true, className: cn("fixed top-0 right-0 z-40", "h-dvh", "bg-background border-l border-border shadow-2xl", "transition-transform duration-300 ease-in-out", "flex flex-col", isOpen ? "translate-x-0" : "translate-x-full"), style: { width: panelWidth }, children: [_jsx("div", { className: "flex-shrink-0 border-b border-border px-6 py-4", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h2", { className: "text-lg font-semibold text-foreground truncate pr-4", children: content.title }), _jsxs("div", { className: "flex items-center gap-1", children: [entityId && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: handleToggleEntityPin, className: cn("flex items-center justify-center", "size-8 rounded-md shrink-0", "hover:bg-muted transition-colors", "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary", isEntityPinned && "text-primary"), "aria-label": isEntityPinned ? "Unpin document" : "Pin document", title: isEntityPinned ? "Unpin document" : "Pin document", children: isEntityPinned ? (_jsx(PinOff, { className: "size-4" })) : (_jsx(Pin, { className: "size-4 text-muted-foreground" })) }), _jsx("button", { type: "button", onClick: handleNavigateToEntity, className: cn("flex items-center justify-center", "size-8 rounded-md shrink-0", "hover:bg-muted transition-colors", "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary"), "aria-label": "Open in navigation", title: "Open in navigation", children: _jsx(FolderOpen, { className: "size-4 text-muted-foreground" }) })] })), _jsx("button", { type: "button", onClick: handleCopyAll, className: cn("flex items-center justify-center", "size-8 rounded-md flex-shrink-0", "hover:bg-muted transition-colors", "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary"), "aria-label": "Copy content", children: copied ? (_jsx(Check, { className: "size-4 text-success" })) : (_jsx(Copy, { className: "size-4 text-muted-foreground" })) }), _jsx("button", { type: "button", onClick: toggleFullscreen, className: cn("flex items-center justify-center", "size-8 rounded-md flex-shrink-0", "hover:bg-muted transition-colors", "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary"), "aria-label": isFullscreen ? "Exit fullscreen" : "Fullscreen", children: isFullscreen ? (_jsx(Minimize2, { className: "size-4 text-muted-foreground" })) : (_jsx(Maximize2, { className: "size-4 text-muted-foreground" })) }), _jsx("button", { type: "button", onClick: closePanel, className: cn("flex items-center justify-center", "size-8 rounded-md flex-shrink-0", "hover:bg-muted transition-colors", "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary"), "aria-label": "Close panel", children: _jsx(X, { className: "size-5 text-muted-foreground" }) })] })] }) }), _jsxs("div", { className: "relative flex-1 overflow-y-auto", ref: contentRef, "data-testid": "tool-panel-content", children: [_jsx(PanelContentRenderer, { content: content }), _jsx(SelectionPopover, { containerRef: contentRef })] })] }));
|
|
89
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ComponentPropsWithRef } from "react";
|
|
2
|
+
import { Button } from "@iloveagents/foundry-web-primitives";
|
|
3
|
+
export type TooltipIconButtonProps = ComponentPropsWithRef<typeof Button> & {
|
|
4
|
+
tooltip: string;
|
|
5
|
+
side?: "top" | "bottom" | "left" | "right";
|
|
6
|
+
};
|
|
7
|
+
export declare const TooltipIconButton: import("react").ForwardRefExoticComponent<Omit<TooltipIconButtonProps, "ref"> & import("react").RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { Slottable } from "@radix-ui/react-slot";
|
|
4
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip.js";
|
|
5
|
+
import { Button } from "@iloveagents/foundry-web-primitives";
|
|
6
|
+
export const TooltipIconButton = forwardRef(({ children, tooltip, side = "bottom", ...rest }, ref) => {
|
|
7
|
+
return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs(Button, { variant: "ghost", size: "icon", ...rest, ref: ref, children: [_jsx(Slottable, { children: children }), _jsx("span", { className: "sr-only", children: tooltip })] }) }), _jsx(TooltipContent, { side: side, children: tooltip })] }));
|
|
8
|
+
});
|
|
9
|
+
TooltipIconButton.displayName = "TooltipIconButton";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { LogOut, User } from "lucide-react";
|
|
3
|
+
import { useStore } from "zustand";
|
|
4
|
+
import { useShallow } from "zustand/react/shallow";
|
|
5
|
+
import { cn } from "@iloveagents/foundry-web-primitives";
|
|
6
|
+
import { authStore } from "@iloveagents/foundry-agent/msal";
|
|
7
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "../ui/dropdown-menu.js";
|
|
8
|
+
import { Button } from "@iloveagents/foundry-web-primitives";
|
|
9
|
+
export const UserMenu = () => {
|
|
10
|
+
const { user, signOut } = useStore(authStore, useShallow((s) => ({ user: s.user, signOut: s.signOut })));
|
|
11
|
+
if (!user)
|
|
12
|
+
return null;
|
|
13
|
+
return (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "ghost", size: "sm", className: "gap-2 rounded-full px-2", children: [user.avatar ? (_jsx("img", { src: user.avatar, alt: user.name, className: "size-6 rounded-full" })) : (_jsx("div", { className: cn("size-6 rounded-full", "bg-primary/10 text-primary", "flex items-center justify-center"), children: _jsx(User, { className: "size-3.5" }) })), _jsx("span", { className: "text-xs text-muted-foreground hidden sm:inline", children: user.name })] }) }), _jsxs(DropdownMenuContent, { align: "end", className: "w-56", children: [_jsx(DropdownMenuLabel, { className: "font-normal", children: _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("p", { className: "text-sm font-medium", children: user.name }), _jsx("p", { className: "text-xs text-muted-foreground", children: user.email })] }) }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { onClick: signOut, className: "text-destructive cursor-pointer", children: [_jsx(LogOut, { className: "size-4" }), "Sign out"] })] })] }));
|
|
14
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export { Sidebar } from "./components/sidebar.js";
|
|
2
|
+
export { ToolPanel } from "./components/tool-panel.js";
|
|
3
|
+
export { ToolPanelLayout } from "./components/tool-panel-layout.js";
|
|
4
|
+
export { MarkdownText, markdownComponents } from "./components/markdown-text.js";
|
|
5
|
+
export { ClientToolExecutor } from "./components/client-tool-executor.js";
|
|
6
|
+
export { AGUIRuntimeProvider, useAGUIAdapter } from "./components/ag-ui-runtime-provider.js";
|
|
7
|
+
export type { AGUIChatConversationFactoryArgs, AGUIHistoryAdapterFactory, } from "./components/ag-ui-runtime-provider.js";
|
|
8
|
+
export { ChatContent, DEFAULT_STARTER_SUGGESTIONS } from "./components/assistant-chat.js";
|
|
9
|
+
export type { ChatContentProps } from "./components/assistant-chat.js";
|
|
10
|
+
export { ChatBubble } from "./components/chat-bubble.js";
|
|
11
|
+
export { ChatHeader } from "./components/chat-header.js";
|
|
12
|
+
export { ComposerAttachment, UserMessageAttachment, userAttachmentComponents, composerAttachmentComponents, } from "./components/chat-attachments.js";
|
|
13
|
+
export { ShowDocumentToolUI } from "./components/show-document-tool-ui.js";
|
|
14
|
+
export { ToolCallCard } from "./components/tool-call-card.js";
|
|
15
|
+
export type { ToolCallStatus } from "./components/tool-call-card.js";
|
|
16
|
+
export { ToolFallback } from "./components/tool-fallback.js";
|
|
17
|
+
export { ConfirmationCard } from "./components/confirmation-card.js";
|
|
18
|
+
export { TooltipIconButton } from "./components/tooltip-icon-button.js";
|
|
19
|
+
export { ComposerContextBadges, SentContextBadges } from "./components/context-badges.js";
|
|
20
|
+
export { ContextPins } from "./components/context-bar.js";
|
|
21
|
+
export { SelectionPopover } from "./components/selection-popover.js";
|
|
22
|
+
export { GlobalSelectionPopover } from "./components/global-selection-popover.js";
|
|
23
|
+
export { LoadingIndicator } from "./components/loading-indicator.js";
|
|
24
|
+
export { ThemeToggle } from "./components/theme-toggle.js";
|
|
25
|
+
export { AppBrand } from "./components/app-brand.js";
|
|
26
|
+
export { CollectionToolbar } from "./components/collection-toolbar.js";
|
|
27
|
+
export { CollectionSearchInput } from "./components/collection-search-input.js";
|
|
28
|
+
export { CollectionFilterBar, type CollectionFilterDefinition, type CollectionFilterOption, type CollectionFilterValue, } from "./components/collection-filter-bar.js";
|
|
29
|
+
export { CollectionSortMenu, type CollectionSortOption, } from "./components/collection-sort-menu.js";
|
|
30
|
+
export { CollectionViewToggle, type CollectionViewMode, } from "./components/collection-view-toggle.js";
|
|
31
|
+
export { CollectionEmptyState } from "./components/collection-empty-state.js";
|
|
32
|
+
export { CollectionSkeleton } from "./components/collection-skeleton.js";
|
|
33
|
+
export { InfiniteScrollSentinel } from "./components/infinite-scroll-sentinel.js";
|
|
34
|
+
export { CollectionSurface } from "./components/collection-surface.js";
|
|
35
|
+
export { ThemeRuntimeProvider, ThemeScope, ThemeDocumentMetadata, useThemeRuntime, } from "./components/theme-runtime-provider.js";
|
|
36
|
+
export { JsonViewer } from "./components/json-viewer.js";
|
|
37
|
+
export { UserMenu } from "./components/user-menu.js";
|
|
38
|
+
export { FormDialog } from "./components/form-dialog.js";
|
|
39
|
+
export { ConfirmDialog } from "./components/confirm-dialog.js";
|
|
40
|
+
export { NameDialog } from "./components/name-dialog.js";
|
|
41
|
+
export { SurfaceCard, surfaceCardVariants } from "./components/surface-card.js";
|
|
42
|
+
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider, } from "./ui/tooltip.js";
|
|
43
|
+
export { Collapsible, CollapsibleTrigger, CollapsibleContent, } from "./ui/collapsible.js";
|
|
44
|
+
export { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuLabel, } from "./ui/dropdown-menu.js";
|
|
45
|
+
export { Dialog, DialogPortal, DialogOverlay, DialogTrigger, DialogClose, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, } from "./ui/dialog.js";
|
|
46
|
+
export { Popover, PopoverTrigger, PopoverAnchor, PopoverContent } from "./ui/popover.js";
|
|
47
|
+
export { Select, selectClassName } from "./ui/select.js";
|
|
48
|
+
export { useAppStore } from "./lib/app-store.js";
|
|
49
|
+
export { useNavStore, type NavFooterAction } from "./lib/nav-store.js";
|
|
50
|
+
export { useToolPanelStore } from "./lib/tool-panel-store.js";
|
|
51
|
+
export type { ToolPanelContent, PdfHighlightRef, PanelRendererEntry, } from "./lib/tool-panel-store.js";
|
|
52
|
+
export { useSidebarStore, SIDEBAR_WIDTH, RAIL_WIDTH } from "./lib/sidebar-store.js";
|
|
53
|
+
export { useChatBubbleStore } from "./lib/chat-bubble-store.js";
|
|
54
|
+
export { useChatLifecycleStore } from "./lib/chat-lifecycle-store.js";
|
|
55
|
+
export { submitComposerText } from "./lib/composer-submit-store.js";
|
|
56
|
+
export { registerSelectionContextResolver, resolveSelectionContext, type SelectionContextInput, type SelectionContextItem, type SelectionContextResolver, type SelectionContextResult, } from "./lib/selection-context.js";
|
|
57
|
+
export { useThemeStore } from "./lib/theme-store.js";
|
|
58
|
+
export type { ThemeMode } from "./lib/theme-store.js";
|
|
59
|
+
export { mergeThemeDefinitions, resolveThemeRuntime, getEffectiveThemeMode, getThemePreset, } from "./lib/theme-runtime.js";
|
|
60
|
+
export type { ThemeDefinition, ThemeLayer, ResolvedThemeRuntime, ThemeColorSlots, ThemeSidebarSlots, ThemeStatusSlots, ThemeChartSlots, ThemeTypographySlots, ThemeRadiusSlots, ThemeAppSlots, ThemeBranding, } from "./lib/theme-runtime.js";
|
|
61
|
+
export { useDevStore } from "./lib/dev-store.js";
|
|
62
|
+
export { DEFAULT_NAV_CONFIG, findNavItem } from "./lib/nav-config.js";
|
|
63
|
+
export type { NavItem, NavItemAction, NavItemDnd, NavGroup, NavGroupCreateAction, NavMatch, CollapsedRailItem, CollapsedRailContext, } from "./lib/nav-config.js";
|
|
64
|
+
export { usePageTools } from "./lib/use-page-tools.js";
|
|
65
|
+
export { useNewConversation } from "./lib/use-new-conversation.js";
|
|
66
|
+
export { AGUIAdapterSDK } from "./lib/ag-ui-adapter.js";
|
|
67
|
+
export { FileAttachmentAdapter } from "./lib/attachment-adapter.js";
|
|
68
|
+
export { AuthProvider } from "./lib/auth-provider.js";
|