@togo-framework/ui 0.1.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/LICENSE +5 -0
- package/README.md +45 -0
- package/dist/chunk-KD4MPGYQ.js +211 -0
- package/dist/chunk-KD4MPGYQ.js.map +1 -0
- package/dist/chunk-XXP2ZYPY.js +2192 -0
- package/dist/chunk-XXP2ZYPY.js.map +1 -0
- package/dist/index.d.ts +3872 -0
- package/dist/index.js +16145 -0
- package/dist/index.js.map +1 -0
- package/dist/shadcn.css +527 -0
- package/dist/shadcn.d.ts +757 -0
- package/dist/shadcn.js +505 -0
- package/dist/shadcn.js.map +1 -0
- package/dist/styles.css +527 -0
- package/dist/theme/index.d.ts +184 -0
- package/dist/theme/index.js +36 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme/tokens.primitive.css +63 -0
- package/dist/theme/tokens.semantic.css +45 -0
- package/package.json +123 -0
- package/public/fonts/ibm-plex-sans/ibm-plex-sans.woff2 +0 -0
- package/public/fonts/jetbrains-mono/jetbrains-mono.woff2 +0 -0
- package/public/fonts/lusail/Lusail-Bold.woff2 +0 -0
- package/public/fonts/lusail/Lusail-Light.woff2 +0 -0
- package/public/fonts/lusail/Lusail-Medium.woff2 +0 -0
- package/public/fonts/lusail/Lusail-Regular.woff2 +0 -0
- package/public/fonts/sora/sora.woff2 +0 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3872 @@
|
|
|
1
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AspectRatio, Avatar, AvatarFallback, AvatarImage, Badge, BadgeProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonProps, Calendar, CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandInputPrimitive, CommandItem, CommandList, CommandSeparator, CommandShortcut, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DirectionalArrow, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, HoverCard, HoverCardContent, HoverCardTrigger, Input, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Label, LinkifyText, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, NativeSelect, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, TextareaProps, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, badgeVariants, buttonVariants, navigationMenuTriggerStyle, toggleVariants, useFormField, useOptionalSidebar, useSidebar } from './shadcn.js';
|
|
2
|
+
import * as React$1 from 'react';
|
|
3
|
+
import React__default, { ReactNode } from 'react';
|
|
4
|
+
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
5
|
+
import { VariantProps } from 'class-variance-authority';
|
|
6
|
+
import { ColumnDef, SortingState, ColumnFiltersState, PaginationState } from '@tanstack/react-table';
|
|
7
|
+
export { ColumnDef, ColumnFiltersState, PaginationState, RowSelectionState, SortingState, VisibilityState } from '@tanstack/react-table';
|
|
8
|
+
import { LucideIcon } from 'lucide-react';
|
|
9
|
+
export { BrandContextValue, BrandTokens, BrandingProvider, BrandingProviderProps, Dir, SENTRA_BRAND, STORAGE_KEY, ThemeBase, ThemeContextValue, ThemeDef, ThemeOverrides, ThemeProvider, ThemeProviderProps, TogoTheme, applyBrand, hexToHSL, isHSL, isValidColor, nudgeL, themeBase, themeInitScript, themes, toHSLSafe, useBrand, useTheme } from './theme/index.js';
|
|
10
|
+
import { ClassValue } from 'clsx';
|
|
11
|
+
export { toast } from 'sonner';
|
|
12
|
+
export { useTranslation } from 'react-i18next';
|
|
13
|
+
import '@radix-ui/react-accordion';
|
|
14
|
+
import '@radix-ui/react-alert-dialog';
|
|
15
|
+
import '@radix-ui/react-aspect-ratio';
|
|
16
|
+
import '@radix-ui/react-avatar';
|
|
17
|
+
import 'react-day-picker';
|
|
18
|
+
import 'embla-carousel-react';
|
|
19
|
+
import 'recharts/types/util/payload/getUniqPayload';
|
|
20
|
+
import 'recharts/types/component/Tooltip';
|
|
21
|
+
import 'recharts/types/util/types';
|
|
22
|
+
import 'recharts/types/component/DefaultTooltipContent';
|
|
23
|
+
import 'recharts';
|
|
24
|
+
import '@radix-ui/react-checkbox';
|
|
25
|
+
import '@radix-ui/react-collapsible';
|
|
26
|
+
import '@radix-ui/react-dialog';
|
|
27
|
+
import '@radix-ui/react-context-menu';
|
|
28
|
+
import 'vaul';
|
|
29
|
+
import '@radix-ui/react-dropdown-menu';
|
|
30
|
+
import 'react-hook-form';
|
|
31
|
+
import '@radix-ui/react-label';
|
|
32
|
+
import '@radix-ui/react-hover-card';
|
|
33
|
+
import 'input-otp';
|
|
34
|
+
import '@radix-ui/react-context';
|
|
35
|
+
import '@radix-ui/react-menubar';
|
|
36
|
+
import '@radix-ui/react-navigation-menu';
|
|
37
|
+
import '@radix-ui/react-popover';
|
|
38
|
+
import '@radix-ui/react-progress';
|
|
39
|
+
import '@radix-ui/react-radio-group';
|
|
40
|
+
import 'react-resizable-panels';
|
|
41
|
+
import '@radix-ui/react-scroll-area';
|
|
42
|
+
import '@radix-ui/react-select';
|
|
43
|
+
import '@radix-ui/react-separator';
|
|
44
|
+
import '@radix-ui/react-tooltip';
|
|
45
|
+
import '@radix-ui/react-slider';
|
|
46
|
+
import '@radix-ui/react-switch';
|
|
47
|
+
import '@radix-ui/react-tabs';
|
|
48
|
+
import '@radix-ui/react-toggle';
|
|
49
|
+
import '@radix-ui/react-toggle-group';
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* EmptyState — a centered "no data" placeholder for tables / lists / panels.
|
|
53
|
+
*
|
|
54
|
+
* Pure + product-agnostic (Rule 25): takes a pre-resolved `title`/`description`
|
|
55
|
+
* (the consumer picks EN/AR via its `language`) and an optional `icon` + action
|
|
56
|
+
* slot. Semantic tokens only; RTL-clean (logical centering).
|
|
57
|
+
*/
|
|
58
|
+
type EmptyStateProps = {
|
|
59
|
+
/** Pre-resolved title string (consumer selects EN/AR). */
|
|
60
|
+
title: string;
|
|
61
|
+
/** Optional pre-resolved supporting line. */
|
|
62
|
+
description?: string;
|
|
63
|
+
/** Optional leading icon (e.g. a lucide-react element). */
|
|
64
|
+
icon?: React$1.ReactNode;
|
|
65
|
+
/** Optional action slot (button / link) rendered below the text. */
|
|
66
|
+
action?: React$1.ReactNode;
|
|
67
|
+
className?: string;
|
|
68
|
+
};
|
|
69
|
+
declare const EmptyState: {
|
|
70
|
+
({ title, description, icon, action, className }: EmptyStateProps): React$1.JSX.Element;
|
|
71
|
+
displayName: string;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* ServiceUnavailable — the graceful "this service/backend dependency is not
|
|
76
|
+
* connected" card. Rendered when an API returns 503 (a DB / NATS / Fort the
|
|
77
|
+
* page depends on is down or unconfigured).
|
|
78
|
+
*
|
|
79
|
+
* This is an EXPECTED state, not an error — styled calm (amber-tinted, not
|
|
80
|
+
* destructive). Pure + product-agnostic: pre-resolved strings in, optional
|
|
81
|
+
* `hint` (e.g. which env var to set) and an action slot.
|
|
82
|
+
*/
|
|
83
|
+
type ServiceUnavailableProps = {
|
|
84
|
+
/** Pre-resolved headline, e.g. "Service not connected". */
|
|
85
|
+
title: string;
|
|
86
|
+
/** Pre-resolved explanation line. */
|
|
87
|
+
description?: string;
|
|
88
|
+
/** Optional secondary hint (e.g. a config key) rendered muted/mono. */
|
|
89
|
+
hint?: React$1.ReactNode;
|
|
90
|
+
/** Optional leading icon. */
|
|
91
|
+
icon?: React$1.ReactNode;
|
|
92
|
+
/** Optional action slot (e.g. a retry / docs button). */
|
|
93
|
+
action?: React$1.ReactNode;
|
|
94
|
+
className?: string;
|
|
95
|
+
};
|
|
96
|
+
declare const ServiceUnavailable: {
|
|
97
|
+
({ title, description, hint, icon, action, className, }: ServiceUnavailableProps): React$1.JSX.Element;
|
|
98
|
+
displayName: string;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* SessionExpired — the graceful "your session expired, sign in again" card,
|
|
103
|
+
* rendered when an API returns 401. Product-agnostic: the consumer passes a
|
|
104
|
+
* pre-resolved title/description/CTA label and a `loginHref` (the library does
|
|
105
|
+
* not import next/link — it renders a plain anchor so it works in any app).
|
|
106
|
+
*/
|
|
107
|
+
type SessionExpiredProps = {
|
|
108
|
+
/** Pre-resolved headline, e.g. "Session expired". */
|
|
109
|
+
title: string;
|
|
110
|
+
/** Pre-resolved explanation line. */
|
|
111
|
+
description?: string;
|
|
112
|
+
/** Pre-resolved CTA label, e.g. "Sign in again". */
|
|
113
|
+
ctaLabel: string;
|
|
114
|
+
/** Where the CTA links (defaults to "/login"). */
|
|
115
|
+
loginHref?: string;
|
|
116
|
+
/** Optional leading icon. */
|
|
117
|
+
icon?: React$1.ReactNode;
|
|
118
|
+
className?: string;
|
|
119
|
+
};
|
|
120
|
+
declare const SessionExpired: {
|
|
121
|
+
({ title, description, ctaLabel, loginHref, icon, className, }: SessionExpiredProps): React$1.JSX.Element;
|
|
122
|
+
displayName: string;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* PageHeader — the standard page title row for admin/ops dashboard pages: an
|
|
127
|
+
* optional leading icon, a title, an optional description line, and an optional
|
|
128
|
+
* trailing `actions` slot (filters, buttons). RTL-clean (logical gap/justify).
|
|
129
|
+
*
|
|
130
|
+
* Pure + product-agnostic: pre-resolved `title`/`description` strings in.
|
|
131
|
+
*/
|
|
132
|
+
type PageHeaderProps = {
|
|
133
|
+
/** Pre-resolved page title (consumer selects EN/AR). */
|
|
134
|
+
title: string;
|
|
135
|
+
/** Optional pre-resolved subtitle. */
|
|
136
|
+
description?: string;
|
|
137
|
+
/** Optional leading icon (sized to ~1.25rem). */
|
|
138
|
+
icon?: React$1.ReactNode;
|
|
139
|
+
/** Optional trailing actions (filters, buttons) — placed at the inline end. */
|
|
140
|
+
actions?: React$1.ReactNode;
|
|
141
|
+
className?: string;
|
|
142
|
+
};
|
|
143
|
+
declare const PageHeader: {
|
|
144
|
+
({ title, description, icon, actions, className }: PageHeaderProps): React$1.JSX.Element;
|
|
145
|
+
displayName: string;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* StatCard — a compact metric tile (label + big value) for dashboard summary
|
|
150
|
+
* strips. `tone` colors the value via semantic tokens (no hex literals).
|
|
151
|
+
*
|
|
152
|
+
* Pure + product-agnostic: pre-resolved `label` string + a value node in.
|
|
153
|
+
*/
|
|
154
|
+
declare const statValueVariants: (props?: ({
|
|
155
|
+
tone?: "default" | "muted" | "success" | "warning" | "danger" | "info" | null | undefined;
|
|
156
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
157
|
+
type StatCardProps = VariantProps<typeof statValueVariants> & {
|
|
158
|
+
/** Pre-resolved metric label (consumer selects EN/AR). */
|
|
159
|
+
label: string;
|
|
160
|
+
/** The metric value — string or number. */
|
|
161
|
+
value: React$1.ReactNode;
|
|
162
|
+
className?: string;
|
|
163
|
+
};
|
|
164
|
+
declare const StatCard: {
|
|
165
|
+
({ label, value, tone, className }: StatCardProps): React$1.JSX.Element;
|
|
166
|
+
displayName: string;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* StatusBadge — a small tinted status pill driven by semantic tokens instead of
|
|
171
|
+
* hardcoded `bg-emerald-500/15` color literals. Use for health / level / state
|
|
172
|
+
* (running, ok, down, error, warn, info, …). Pure + product-agnostic.
|
|
173
|
+
*
|
|
174
|
+
* The consumer maps its domain status → a `tone` and passes a pre-resolved
|
|
175
|
+
* label (EN/AR). This keeps colors centralised and RTL-/theme-safe.
|
|
176
|
+
*/
|
|
177
|
+
declare const statusBadgeVariants: (props?: ({
|
|
178
|
+
tone?: "success" | "warning" | "danger" | "info" | "neutral" | null | undefined;
|
|
179
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
180
|
+
type StatusBadgeTone = NonNullable<VariantProps<typeof statusBadgeVariants>["tone"]>;
|
|
181
|
+
type StatusBadgeProps = VariantProps<typeof statusBadgeVariants> & {
|
|
182
|
+
/** Pre-resolved label (consumer selects EN/AR). */
|
|
183
|
+
children: React$1.ReactNode;
|
|
184
|
+
className?: string;
|
|
185
|
+
};
|
|
186
|
+
declare const StatusBadge: {
|
|
187
|
+
({ tone, children, className }: StatusBadgeProps): React$1.JSX.Element;
|
|
188
|
+
displayName: string;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* DataState — the single wrapper that guarantees a data page renders ONE of the
|
|
193
|
+
* canonical states and NEVER a raw error string. Precedence:
|
|
194
|
+
*
|
|
195
|
+
* loading → unauthorized (401) → unavailable (503) → error → empty → children
|
|
196
|
+
*
|
|
197
|
+
* Pure + product-agnostic (Rule 25): the consumer passes booleans + pre-resolved
|
|
198
|
+
* EN/AR label bundles. The library never fetches and never reads a language
|
|
199
|
+
* context — it just renders the resolved strings.
|
|
200
|
+
*/
|
|
201
|
+
type DataStateLabels = {
|
|
202
|
+
/** Unauthorized (401) card. */
|
|
203
|
+
sessionExpiredTitle: string;
|
|
204
|
+
sessionExpiredDescription?: string;
|
|
205
|
+
signInLabel: string;
|
|
206
|
+
loginHref?: string;
|
|
207
|
+
/** Unavailable (503) card. */
|
|
208
|
+
unavailableTitle: string;
|
|
209
|
+
unavailableDescription?: string;
|
|
210
|
+
unavailableHint?: React$1.ReactNode;
|
|
211
|
+
/** Generic error card. */
|
|
212
|
+
errorTitle: string;
|
|
213
|
+
/** Empty card. */
|
|
214
|
+
emptyTitle: string;
|
|
215
|
+
emptyDescription?: string;
|
|
216
|
+
};
|
|
217
|
+
type DataStateProps = {
|
|
218
|
+
loading?: boolean;
|
|
219
|
+
unauthorized?: boolean;
|
|
220
|
+
unavailable?: boolean;
|
|
221
|
+
/** Pre-resolved error detail (e.g. "HTTP 500"); shown under errorTitle. */
|
|
222
|
+
error?: string | null;
|
|
223
|
+
/** True when the request succeeded but returned no rows. */
|
|
224
|
+
empty?: boolean;
|
|
225
|
+
labels: DataStateLabels;
|
|
226
|
+
/** Optional icon reused across empty/unavailable/session cards. */
|
|
227
|
+
icon?: React$1.ReactNode;
|
|
228
|
+
/** Optional action slot for the empty state (e.g. a "Create" button). */
|
|
229
|
+
emptyAction?: React$1.ReactNode;
|
|
230
|
+
/** Skeleton rendered while `loading`. Defaults to three bars. */
|
|
231
|
+
loadingFallback?: React$1.ReactNode;
|
|
232
|
+
/** The populated content, rendered only when no special state applies. */
|
|
233
|
+
children?: React$1.ReactNode;
|
|
234
|
+
};
|
|
235
|
+
declare const DataState: {
|
|
236
|
+
({ loading, unauthorized, unavailable, error, empty, labels, icon, emptyAction, loadingFallback, children, }: DataStateProps): React$1.JSX.Element;
|
|
237
|
+
displayName: string;
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* DataTable types — shared type definitions for the DataTable component.
|
|
242
|
+
*
|
|
243
|
+
* Design system rules:
|
|
244
|
+
* - Rule 8 — bilingual (EN/AR): column headers carry header_en/header_ar or renderHeader
|
|
245
|
+
* - Rule 16 — Sentra app style: semantic tokens only, logical CSS props
|
|
246
|
+
* - Rule 25 — product-agnostic: NO data fetching, NO context reads
|
|
247
|
+
*/
|
|
248
|
+
|
|
249
|
+
type DataTableLanguage = 'en' | 'ar';
|
|
250
|
+
type DataTableDensity = 'compact' | 'comfortable';
|
|
251
|
+
type DataTableFilterType = 'text' | 'select' | 'date-range' | 'number-range';
|
|
252
|
+
interface DataTableSelectOption {
|
|
253
|
+
label_en: string;
|
|
254
|
+
label_ar?: string;
|
|
255
|
+
value: string;
|
|
256
|
+
}
|
|
257
|
+
interface DataTableColumnFilter<TData = unknown> {
|
|
258
|
+
/** Column accessor key — must match the column `id` / `accessorKey` */
|
|
259
|
+
columnId: string;
|
|
260
|
+
type: DataTableFilterType;
|
|
261
|
+
/** For select filters: the list of options */
|
|
262
|
+
options?: DataTableSelectOption[];
|
|
263
|
+
/** Placeholder shown in text input */
|
|
264
|
+
placeholder_en?: string;
|
|
265
|
+
placeholder_ar?: string;
|
|
266
|
+
}
|
|
267
|
+
interface DataTableColumnMeta {
|
|
268
|
+
/** English column header — takes precedence over `header` string if present */
|
|
269
|
+
header_en?: string;
|
|
270
|
+
/** Arabic column header */
|
|
271
|
+
header_ar?: string;
|
|
272
|
+
/** Whether this column can be resized */
|
|
273
|
+
resizable?: boolean;
|
|
274
|
+
/** Whether this column can be pinned */
|
|
275
|
+
pinnable?: boolean;
|
|
276
|
+
}
|
|
277
|
+
interface DataTableServerState {
|
|
278
|
+
sorting: SortingState;
|
|
279
|
+
columnFilters: ColumnFiltersState;
|
|
280
|
+
pagination: PaginationState;
|
|
281
|
+
globalFilter: string;
|
|
282
|
+
}
|
|
283
|
+
interface DataTableServerCallbacks {
|
|
284
|
+
onStateChange: (state: DataTableServerState) => void;
|
|
285
|
+
}
|
|
286
|
+
interface DataTableBulkAction {
|
|
287
|
+
id: string;
|
|
288
|
+
label_en: string;
|
|
289
|
+
label_ar?: string;
|
|
290
|
+
icon?: React.ReactNode;
|
|
291
|
+
variant?: 'default' | 'destructive' | 'outline';
|
|
292
|
+
onAction: (selectedRowIds: string[]) => void;
|
|
293
|
+
}
|
|
294
|
+
interface DataTableProps<TData> {
|
|
295
|
+
data: TData[];
|
|
296
|
+
columns: ColumnDef<TData, unknown>[];
|
|
297
|
+
/**
|
|
298
|
+
* A function that returns a unique string key for each row.
|
|
299
|
+
* Required for row selection and stable React keys.
|
|
300
|
+
*/
|
|
301
|
+
getRowId?: (row: TData) => string;
|
|
302
|
+
language?: DataTableLanguage;
|
|
303
|
+
filterDefs?: DataTableColumnFilter<TData>[];
|
|
304
|
+
/** Show the global search box above the table */
|
|
305
|
+
showGlobalSearch?: boolean;
|
|
306
|
+
/**
|
|
307
|
+
* Client-side mode (default): DataTable manages pagination state internally.
|
|
308
|
+
* Server-side mode: pass `totalRows` + `serverCallbacks` — state is lifted.
|
|
309
|
+
*/
|
|
310
|
+
pageSize?: number;
|
|
311
|
+
pageSizeOptions?: number[];
|
|
312
|
+
totalRows?: number;
|
|
313
|
+
/**
|
|
314
|
+
* When provided, DataTable enters controlled server-side mode.
|
|
315
|
+
* The component fires `onStateChange` on every sort/filter/page change.
|
|
316
|
+
* Products NEVER fetch inside DataTable — they do it from their own bridge.
|
|
317
|
+
*/
|
|
318
|
+
serverCallbacks?: DataTableServerCallbacks;
|
|
319
|
+
loading?: boolean;
|
|
320
|
+
error?: string | null;
|
|
321
|
+
onRowClick?: (row: TData) => void;
|
|
322
|
+
enableRowSelection?: boolean;
|
|
323
|
+
bulkActions?: DataTableBulkAction[];
|
|
324
|
+
/**
|
|
325
|
+
* Slot: if provided, renders below the clicked row as an expand panel.
|
|
326
|
+
* Receives the row data.
|
|
327
|
+
*/
|
|
328
|
+
renderExpandedRow?: (row: TData) => React.ReactNode;
|
|
329
|
+
enableColumnVisibility?: boolean;
|
|
330
|
+
enableColumnPinning?: boolean;
|
|
331
|
+
enableColumnResizing?: boolean;
|
|
332
|
+
enableSorting?: boolean;
|
|
333
|
+
enableMultiSort?: boolean;
|
|
334
|
+
showDensityToggle?: boolean;
|
|
335
|
+
defaultDensity?: DataTableDensity;
|
|
336
|
+
showCsvExport?: boolean;
|
|
337
|
+
csvFilename?: string;
|
|
338
|
+
className?: string;
|
|
339
|
+
/** Sticky header (default: true) */
|
|
340
|
+
stickyHeader?: boolean;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* DataTable — flagship grid component for the Sentra Design System.
|
|
345
|
+
*
|
|
346
|
+
* Built on @tanstack/react-table over the existing shadcn/ui Table primitive.
|
|
347
|
+
*
|
|
348
|
+
* Features:
|
|
349
|
+
* - Multi-column sorting (keyboard-navigable aria-sort headers)
|
|
350
|
+
* - Per-column filters: text / select / date-range / number-range
|
|
351
|
+
* - Global search box
|
|
352
|
+
* - Column visibility toggle
|
|
353
|
+
* - Column pinning (start/end)
|
|
354
|
+
* - Client-side pagination + controlled server-side mode
|
|
355
|
+
* - Row selection (checkbox) + bulk-action slot
|
|
356
|
+
* - Row click handler + expandable row slot
|
|
357
|
+
* - Density toggle (compact / comfortable)
|
|
358
|
+
* - Sticky header
|
|
359
|
+
* - Loading skeleton (SectionSkeleton)
|
|
360
|
+
* - Empty + error states
|
|
361
|
+
* - CSV export of current view (client-side)
|
|
362
|
+
* - Full RTL (logical props, dir-aware sort icons)
|
|
363
|
+
* - Bilingual: all chrome strings translated EN/AR internally via `language` prop
|
|
364
|
+
* - WCAG 2.1 AA: visible focus rings, aria-sort, aria-label on all controls
|
|
365
|
+
*
|
|
366
|
+
* Design rules:
|
|
367
|
+
* - Rule 8 — bilingual (EN/AR), RTL logical properties
|
|
368
|
+
* - Rule 16 — Sentra app style: semantic tokens only
|
|
369
|
+
* - Rule 25 — product-agnostic: NEVER fetches; data arrives entirely via props
|
|
370
|
+
*/
|
|
371
|
+
|
|
372
|
+
declare function DataTable<TData>({ data, columns, getRowId, language, filterDefs, showGlobalSearch, pageSize: initialPageSize, pageSizeOptions, totalRows, serverCallbacks, loading, error, onRowClick, enableRowSelection, bulkActions, renderExpandedRow, enableColumnVisibility, enableColumnPinning, enableColumnResizing, enableSorting, enableMultiSort, showDensityToggle, defaultDensity, showCsvExport, csvFilename, className, stickyHeader, }: DataTableProps<TData>): React$1.JSX.Element;
|
|
373
|
+
declare namespace DataTable {
|
|
374
|
+
var displayName: string;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
type CardFilter<T> = {
|
|
378
|
+
/** Stable id for the dropdown. */
|
|
379
|
+
key: string;
|
|
380
|
+
/** Localised label, e.g. "Product". */
|
|
381
|
+
label: string;
|
|
382
|
+
/** Value extractor for an item (compared exactly to the selected option). */
|
|
383
|
+
value: (item: T) => string;
|
|
384
|
+
/** Options; the "all" choice is injected automatically. */
|
|
385
|
+
options: {
|
|
386
|
+
value: string;
|
|
387
|
+
label: string;
|
|
388
|
+
}[];
|
|
389
|
+
};
|
|
390
|
+
type CardGridLabels = {
|
|
391
|
+
searchPlaceholder: string;
|
|
392
|
+
all: string;
|
|
393
|
+
emptyTitle: string;
|
|
394
|
+
emptyDescription: string;
|
|
395
|
+
countLabel: (shown: number, total: number) => string;
|
|
396
|
+
};
|
|
397
|
+
type CardGridProps<T> = {
|
|
398
|
+
items: T[];
|
|
399
|
+
getKey: (item: T, index: number) => string;
|
|
400
|
+
renderCard: (item: T) => React.ReactNode;
|
|
401
|
+
/** Concatenated searchable text for an item (lower-cased match). */
|
|
402
|
+
searchText: (item: T) => string;
|
|
403
|
+
filters?: CardFilter<T>[];
|
|
404
|
+
labels: CardGridLabels;
|
|
405
|
+
emptyIcon?: React.ReactNode;
|
|
406
|
+
/** Tailwind grid column classes; sensible default if omitted. */
|
|
407
|
+
gridClassName?: string;
|
|
408
|
+
};
|
|
409
|
+
declare function CardGrid<T>({ items, getKey, renderCard, searchText, filters, labels, emptyIcon, gridClassName, }: CardGridProps<T>): React$1.JSX.Element;
|
|
410
|
+
declare namespace CardGrid {
|
|
411
|
+
var displayName: string;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* MiniBarChart — a dependency-free SVG/flex bar chart.
|
|
416
|
+
*
|
|
417
|
+
* Recharts (via ChartContainer) is overkill for a small sparkline-style chart,
|
|
418
|
+
* so this renders a clean, responsive, semantic-token-styled bar chart from
|
|
419
|
+
* plain data, RTL-safe (flips with `dir`), with an accessible title.
|
|
420
|
+
* Promoted into @prism/ui from motor-web (product-agnostic).
|
|
421
|
+
*/
|
|
422
|
+
type BarPoint = {
|
|
423
|
+
label: string;
|
|
424
|
+
value: number;
|
|
425
|
+
sublabel?: string;
|
|
426
|
+
};
|
|
427
|
+
declare const MiniBarChart: {
|
|
428
|
+
({ data, height, valueFormatter, }: {
|
|
429
|
+
data: BarPoint[];
|
|
430
|
+
height?: number;
|
|
431
|
+
valueFormatter?: (n: number) => string;
|
|
432
|
+
}): React$1.JSX.Element;
|
|
433
|
+
displayName: string;
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* AuthClient — the transport seam that all auth form components call.
|
|
438
|
+
*
|
|
439
|
+
* Fort's web layer passes a concrete implementation backed by Fort's
|
|
440
|
+
* /v1/auth/* API endpoints + the Fort SDK. The forms themselves own NO
|
|
441
|
+
* transport logic — they only call methods on this interface.
|
|
442
|
+
*
|
|
443
|
+
* Design constraints:
|
|
444
|
+
* - Every method returns a plain discriminated result so forms can branch on
|
|
445
|
+
* `challenge` without importing any SDK types.
|
|
446
|
+
* - All methods throw on network / server errors (forms catch and surface the
|
|
447
|
+
* message via AuthErrorAlert).
|
|
448
|
+
* - The interface is intentionally narrow — only what the auth flow screens need.
|
|
449
|
+
*
|
|
450
|
+
* ─── Integration contract for Fort's web (F1) ────────────────────────────────
|
|
451
|
+
*
|
|
452
|
+
* import type { AuthClient } from '@prism/ui'
|
|
453
|
+
* import { fortAuthClient } from './fort-auth-client' // Fort's concrete impl
|
|
454
|
+
*
|
|
455
|
+
* <AuthFlow authClient={fortAuthClient} onSuccess={() => router.push('/dashboard')} />
|
|
456
|
+
*
|
|
457
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
458
|
+
*/
|
|
459
|
+
type LoginResult = {
|
|
460
|
+
challenge: 'otp';
|
|
461
|
+
challenge_token?: string;
|
|
462
|
+
} | {
|
|
463
|
+
challenge: '2fa';
|
|
464
|
+
challenge_token?: string;
|
|
465
|
+
} | {
|
|
466
|
+
challenge: 'none';
|
|
467
|
+
};
|
|
468
|
+
type OtpResult = {
|
|
469
|
+
challenge: '2fa';
|
|
470
|
+
challenge_token?: string;
|
|
471
|
+
} | {
|
|
472
|
+
challenge: 'none';
|
|
473
|
+
};
|
|
474
|
+
type Verify2FAResult = {
|
|
475
|
+
challenge: 'none';
|
|
476
|
+
};
|
|
477
|
+
interface AuthClient {
|
|
478
|
+
/**
|
|
479
|
+
* Sign in with email + password.
|
|
480
|
+
*
|
|
481
|
+
* Returns the next challenge the server requires:
|
|
482
|
+
* - `otp` — email OTP sent; call `verifyOtp` next.
|
|
483
|
+
* - `2fa` — TOTP required; call `verify2FA` next with the challenge_token.
|
|
484
|
+
* - `none` — session established; call `onSuccess`.
|
|
485
|
+
*
|
|
486
|
+
* Throws on bad credentials, locked account, or network error.
|
|
487
|
+
* The error object may carry a `status` number (HTTP status) and a `message`.
|
|
488
|
+
*
|
|
489
|
+
* @param rememberMe - When `true`, the server should issue a long-lived
|
|
490
|
+
* persistent session cookie whose lifetime is determined by the server's
|
|
491
|
+
* `session.remember_me_duration` setting. When `false` or omitted, the
|
|
492
|
+
* server issues a session-scoped cookie that expires on browser close.
|
|
493
|
+
* This parameter is optional so existing concrete implementations that
|
|
494
|
+
* ignore it continue to satisfy the interface without modification.
|
|
495
|
+
*/
|
|
496
|
+
login(email: string, password: string, rememberMe?: boolean): Promise<LoginResult>;
|
|
497
|
+
/**
|
|
498
|
+
* Send (or resend) a one-time password to the given email.
|
|
499
|
+
* Used for both magic-link flows and the OTP step after credentials.
|
|
500
|
+
* Throws on network error.
|
|
501
|
+
*/
|
|
502
|
+
sendOtp(email: string): Promise<void>;
|
|
503
|
+
/**
|
|
504
|
+
* Verify a 6-digit OTP code.
|
|
505
|
+
*
|
|
506
|
+
* `challenge_token` is the opaque token returned by `login()` — pass it
|
|
507
|
+
* back verbatim so the server can correlate the session.
|
|
508
|
+
*
|
|
509
|
+
* Returns the next challenge:
|
|
510
|
+
* - `2fa` — TOTP still required.
|
|
511
|
+
* - `none` — session established; call `onSuccess`.
|
|
512
|
+
*
|
|
513
|
+
* Throws on bad/expired code or too many attempts.
|
|
514
|
+
*/
|
|
515
|
+
verifyOtp(email: string, code: string, challengeToken?: string): Promise<OtpResult>;
|
|
516
|
+
/**
|
|
517
|
+
* Request a password-reset email.
|
|
518
|
+
* The server always responds the same way regardless of whether the account
|
|
519
|
+
* exists (no enumeration). Throws only on network errors.
|
|
520
|
+
*/
|
|
521
|
+
forgotPassword(email: string): Promise<void>;
|
|
522
|
+
/**
|
|
523
|
+
* Set a new password using the reset token extracted from the magic link URL.
|
|
524
|
+
* Throws with status 401/400 when the token is invalid or expired.
|
|
525
|
+
*/
|
|
526
|
+
resetPassword(token: string, newPassword: string): Promise<void>;
|
|
527
|
+
/**
|
|
528
|
+
* Verify a TOTP or recovery code for the 2FA challenge step.
|
|
529
|
+
* The challenge_token should be stored in memory (e.g. component state) after
|
|
530
|
+
* login returns `challenge: '2fa'`.
|
|
531
|
+
*
|
|
532
|
+
* Throws on bad code, already-used recovery code, or too many attempts.
|
|
533
|
+
*/
|
|
534
|
+
verify2FA(code: string, challengeToken?: string): Promise<Verify2FAResult>;
|
|
535
|
+
/**
|
|
536
|
+
* (Optional) Return the OAuth redirect URL for the given provider.
|
|
537
|
+
* Used by the "Sign in with Google" button. Return `undefined` / `null` to
|
|
538
|
+
* hide the button.
|
|
539
|
+
*/
|
|
540
|
+
getOAuthUrl?(provider: 'google' | string): string | null | undefined;
|
|
541
|
+
/**
|
|
542
|
+
* (Optional) Look up which login methods are allowed for a given email.
|
|
543
|
+
*
|
|
544
|
+
* The email-first flow calls this after the user clicks "Continue" on Step A.
|
|
545
|
+
* The returned `methods` array drives which credential options are rendered:
|
|
546
|
+
*
|
|
547
|
+
* 'email_password' — reveal the password field + Sign in button
|
|
548
|
+
* 'magic_link' — show "Send magic link" button (calls sendOtp / sendLoginOtp)
|
|
549
|
+
* 'otp' — show "Email me a code" button (calls sendLoginOtp / sendOtp)
|
|
550
|
+
* 'google_oauth' — show Google sign-in button
|
|
551
|
+
* 'github' — show GitHub sign-in button
|
|
552
|
+
* 'azure' — show Microsoft/Azure sign-in button
|
|
553
|
+
*
|
|
554
|
+
* Fail-open: if this method is undefined OR throws, the form falls back to
|
|
555
|
+
* showing the password field (email_password) so login always works.
|
|
556
|
+
*
|
|
557
|
+
* Return `undefined` to skip role-gating (all methods shown by default).
|
|
558
|
+
*/
|
|
559
|
+
getLoginMethods?(email: string): Promise<{
|
|
560
|
+
methods: string[];
|
|
561
|
+
} | undefined>;
|
|
562
|
+
/**
|
|
563
|
+
* (Optional) Send a passwordless login OTP / magic-link code to the given email.
|
|
564
|
+
*
|
|
565
|
+
* Used by the email-first flow when the user selects "Email me a code" (otp
|
|
566
|
+
* method) or "Send magic link" (magic_link method) on the methods step.
|
|
567
|
+
*
|
|
568
|
+
* When absent, the form falls back to `sendOtp(email)` which already exists
|
|
569
|
+
* on all concrete implementations, so back-compat is preserved — callers that
|
|
570
|
+
* have not yet added this method continue to satisfy the interface.
|
|
571
|
+
*
|
|
572
|
+
* The distinction from `sendOtp` is semantic: `sendLoginOtp` is the initial
|
|
573
|
+
* unauthenticated OTP dispatch triggered by the user choosing a passwordless
|
|
574
|
+
* path; `sendOtp` is the resend call on the OTP verification screen.
|
|
575
|
+
* Implementations may delegate one to the other.
|
|
576
|
+
*/
|
|
577
|
+
sendLoginOtp?(email: string): Promise<void>;
|
|
578
|
+
/**
|
|
579
|
+
* (Optional) One-click developer login.
|
|
580
|
+
*
|
|
581
|
+
* Present only when APP_ENV=development AND the platform has providers.dev=true.
|
|
582
|
+
* The server mints a session for admin@sentra.local without requiring credentials.
|
|
583
|
+
*
|
|
584
|
+
* When this method is defined on the client, LoginForm renders a prominent
|
|
585
|
+
* "Continue as dev" button ABOVE the email form with a divider. It is rendered
|
|
586
|
+
* ONLY when this method is present — concrete implementations in non-dev
|
|
587
|
+
* environments must omit it entirely.
|
|
588
|
+
*
|
|
589
|
+
* Throws on server error (server always 404s in production — rule 14 hard gate).
|
|
590
|
+
*/
|
|
591
|
+
devLogin?(): Promise<void>;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
type AuthLayout = 'split' | 'split-reverse' | 'centered' | 'minimal';
|
|
595
|
+
interface AuthCardBrand {
|
|
596
|
+
/**
|
|
597
|
+
* Optional logo image URL — the preferred brand mark. When provided it
|
|
598
|
+
* replaces the default icon crest.
|
|
599
|
+
*/
|
|
600
|
+
logoUrl?: string;
|
|
601
|
+
/**
|
|
602
|
+
* Optional icon element (e.g. a lucide icon) shown in the crest when no
|
|
603
|
+
* `logoUrl` is given. Defaults to a ShieldCheck mark. Pass `null` to fall
|
|
604
|
+
* back to the text `initial`.
|
|
605
|
+
*/
|
|
606
|
+
icon?: React$1.ReactNode | null;
|
|
607
|
+
/** Text initial — only used when `icon` is explicitly `null` and no logoUrl. */
|
|
608
|
+
initial?: string;
|
|
609
|
+
/**
|
|
610
|
+
* Product name shown in the panel and mobile header. Default: 'Sentra Insight Hub'.
|
|
611
|
+
* Pass a `{ en, ar }` pair to localize the title per language (operator
|
|
612
|
+
* 2026-06-05: the AR title wasn't switching). A bare string is used as-is.
|
|
613
|
+
*/
|
|
614
|
+
name?: string | {
|
|
615
|
+
en: string;
|
|
616
|
+
ar: string;
|
|
617
|
+
};
|
|
618
|
+
/** Tagline shown under the name. Provide both locales. */
|
|
619
|
+
tagline?: {
|
|
620
|
+
en: string;
|
|
621
|
+
ar: string;
|
|
622
|
+
};
|
|
623
|
+
/** Feature bullets shown in the brand panel. Provide both locales for each. */
|
|
624
|
+
bullets?: Array<{
|
|
625
|
+
en: string;
|
|
626
|
+
ar: string;
|
|
627
|
+
}>;
|
|
628
|
+
/** Footer note in the brand panel. Default: lock icon + 'Secure & Encrypted'. */
|
|
629
|
+
secureNote?: {
|
|
630
|
+
en: string;
|
|
631
|
+
ar: string;
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
interface AuthCardProps {
|
|
635
|
+
children: React$1.ReactNode;
|
|
636
|
+
/** Current display language. Default: 'en'. */
|
|
637
|
+
language?: 'en' | 'ar';
|
|
638
|
+
/**
|
|
639
|
+
* Layout variant. Default: 'split'.
|
|
640
|
+
* - split brand panel on the leading side (start), form trailing.
|
|
641
|
+
* - split-reverse brand panel on the trailing side (end), form leading.
|
|
642
|
+
* - centered no brand panel; a single centered card with a compact
|
|
643
|
+
* brand header above it. Good for minimal Fort tenants.
|
|
644
|
+
* - minimal like centered but without the card chrome (bare form,
|
|
645
|
+
* only the brand crest + name). Smallest footprint.
|
|
646
|
+
*/
|
|
647
|
+
layout?: AuthLayout;
|
|
648
|
+
/**
|
|
649
|
+
* Called when the user clicks the language toggle button.
|
|
650
|
+
* If omitted the toggle is hidden.
|
|
651
|
+
*/
|
|
652
|
+
onLanguageToggle?: () => void;
|
|
653
|
+
/** Brand customisation. Defaults to Sentra copy if omitted. */
|
|
654
|
+
brand?: AuthCardBrand;
|
|
655
|
+
/** Optional extra class on the outer wrapper. */
|
|
656
|
+
className?: string;
|
|
657
|
+
}
|
|
658
|
+
declare const AuthCard: {
|
|
659
|
+
({ children, language, layout, onLanguageToggle, brand: brandProp, className, }: AuthCardProps): React$1.JSX.Element;
|
|
660
|
+
displayName: string;
|
|
661
|
+
};
|
|
662
|
+
|
|
663
|
+
interface AuthFlowProps {
|
|
664
|
+
/** Transport seam — Fort's web passes its concrete implementation. */
|
|
665
|
+
authClient: AuthClient;
|
|
666
|
+
/**
|
|
667
|
+
* Reset token from URL query param.
|
|
668
|
+
* When provided, flow starts at the 'reset' step directly.
|
|
669
|
+
*/
|
|
670
|
+
resetToken?: string;
|
|
671
|
+
/** Called after the user is fully authenticated. */
|
|
672
|
+
onSuccess?: () => void;
|
|
673
|
+
/**
|
|
674
|
+
* Display language. Default: 'en'.
|
|
675
|
+
* Toggling is handled internally unless you pass `onLanguageToggle`.
|
|
676
|
+
*/
|
|
677
|
+
language?: 'en' | 'ar';
|
|
678
|
+
/**
|
|
679
|
+
* Override the language toggle handler.
|
|
680
|
+
* If omitted, AuthFlow toggles internally between 'en' and 'ar'.
|
|
681
|
+
* If `null`, the toggle button is hidden.
|
|
682
|
+
*/
|
|
683
|
+
onLanguageToggle?: (() => void) | null;
|
|
684
|
+
/** Brand customisation forwarded to AuthCard. */
|
|
685
|
+
brand?: AuthCardBrand;
|
|
686
|
+
/**
|
|
687
|
+
* AuthCard layout variant forwarded to AuthCard.
|
|
688
|
+
* 'split' | 'split-reverse' | 'centered' | 'minimal'. Default: 'split'.
|
|
689
|
+
* Lets Fort pick a brand-panel layout (or a panel-less centered card).
|
|
690
|
+
*/
|
|
691
|
+
layout?: AuthLayout;
|
|
692
|
+
/** If true, wraps the flow in an AuthCard (brand panel + card). Default: true. */
|
|
693
|
+
withCard?: boolean;
|
|
694
|
+
/**
|
|
695
|
+
* Whether to show the "Remember me" checkbox on the login step.
|
|
696
|
+
*
|
|
697
|
+
* Forwarded directly to `LoginForm`. Set to `false` when the server's
|
|
698
|
+
* `session.remember_me_enabled` setting is disabled so the checkbox is
|
|
699
|
+
* hidden and `login` is always called with `rememberMe = false`.
|
|
700
|
+
*
|
|
701
|
+
* Default: `true`.
|
|
702
|
+
*/
|
|
703
|
+
showRememberMe?: boolean;
|
|
704
|
+
/**
|
|
705
|
+
* @deprecated — Email-first is now the default and only flow.
|
|
706
|
+
* This prop is accepted but ignored; kept for back-compat so existing
|
|
707
|
+
* callers that pass `emailFirst={true}` continue to compile.
|
|
708
|
+
*/
|
|
709
|
+
emailFirst?: boolean;
|
|
710
|
+
}
|
|
711
|
+
declare const AuthFlow: {
|
|
712
|
+
({ authClient, resetToken, onSuccess, language: languageProp, onLanguageToggle, brand, layout, withCard, showRememberMe, emailFirst: _emailFirst, }: AuthFlowProps): React$1.JSX.Element;
|
|
713
|
+
displayName: string;
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
interface LoginFormProps {
|
|
717
|
+
authClient: AuthClient;
|
|
718
|
+
onSuccess?: () => void;
|
|
719
|
+
on2FA?: (challengeToken?: string) => void;
|
|
720
|
+
onOAuthRedirect?: (url: string) => void;
|
|
721
|
+
onForgotPassword?: () => void;
|
|
722
|
+
language?: 'en' | 'ar';
|
|
723
|
+
showRememberMe?: boolean;
|
|
724
|
+
}
|
|
725
|
+
declare const LoginForm: {
|
|
726
|
+
({ authClient, onSuccess, on2FA, onOAuthRedirect, onForgotPassword, language, showRememberMe, }: LoginFormProps): React$1.JSX.Element;
|
|
727
|
+
displayName: string;
|
|
728
|
+
};
|
|
729
|
+
|
|
730
|
+
interface ForgotFormProps {
|
|
731
|
+
/** Transport seam. */
|
|
732
|
+
authClient: AuthClient;
|
|
733
|
+
/** Called when the user clicks "Back to sign in". Fort's router handles navigation. */
|
|
734
|
+
onBack?: () => void;
|
|
735
|
+
/** Display language. Default: 'en'. */
|
|
736
|
+
language?: 'en' | 'ar';
|
|
737
|
+
}
|
|
738
|
+
declare const ForgotForm: {
|
|
739
|
+
({ authClient, onBack, language }: ForgotFormProps): React$1.JSX.Element;
|
|
740
|
+
displayName: string;
|
|
741
|
+
};
|
|
742
|
+
|
|
743
|
+
interface ResetFormProps {
|
|
744
|
+
/** Reset token extracted from the magic link URL query param. */
|
|
745
|
+
token: string;
|
|
746
|
+
/** Transport seam. */
|
|
747
|
+
authClient: AuthClient;
|
|
748
|
+
/** Called after password is successfully reset. Fort's router may navigate to sign-in. */
|
|
749
|
+
onSuccess?: () => void;
|
|
750
|
+
/** Called when the user clicks "Request a new link". */
|
|
751
|
+
onRequestNewLink?: () => void;
|
|
752
|
+
/** Display language. Default: 'en'. */
|
|
753
|
+
language?: 'en' | 'ar';
|
|
754
|
+
}
|
|
755
|
+
declare const ResetForm: {
|
|
756
|
+
({ token, authClient, onSuccess, onRequestNewLink, language, }: ResetFormProps): React$1.JSX.Element;
|
|
757
|
+
displayName: string;
|
|
758
|
+
};
|
|
759
|
+
|
|
760
|
+
interface TwoFAFormProps {
|
|
761
|
+
/** Transport seam. */
|
|
762
|
+
authClient: AuthClient;
|
|
763
|
+
/**
|
|
764
|
+
* Opaque challenge token from LoginForm's on2FA callback.
|
|
765
|
+
* Pass it directly — the form forwards it to authClient.verify2FA.
|
|
766
|
+
*/
|
|
767
|
+
challengeToken?: string;
|
|
768
|
+
/** Called after successful 2FA verification. */
|
|
769
|
+
onSuccess?: () => void;
|
|
770
|
+
/** Called when the server rejects the code with "too many attempts". */
|
|
771
|
+
onTooManyAttempts?: () => void;
|
|
772
|
+
/** Display language. Default: 'en'. */
|
|
773
|
+
language?: 'en' | 'ar';
|
|
774
|
+
}
|
|
775
|
+
declare const TwoFAForm: {
|
|
776
|
+
({ authClient, challengeToken, onSuccess, onTooManyAttempts, language, }: TwoFAFormProps): React$1.JSX.Element;
|
|
777
|
+
displayName: string;
|
|
778
|
+
};
|
|
779
|
+
|
|
780
|
+
interface AuthErrorAlertProps {
|
|
781
|
+
error: string | null | undefined;
|
|
782
|
+
}
|
|
783
|
+
declare const AuthErrorAlert: {
|
|
784
|
+
({ error }: AuthErrorAlertProps): React$1.JSX.Element | null;
|
|
785
|
+
displayName: string;
|
|
786
|
+
};
|
|
787
|
+
|
|
788
|
+
interface AuthStepHeaderProps {
|
|
789
|
+
icon?: React$1.ReactNode;
|
|
790
|
+
title: string;
|
|
791
|
+
subtitle?: React$1.ReactNode;
|
|
792
|
+
centered?: boolean;
|
|
793
|
+
}
|
|
794
|
+
declare const AuthStepHeader: {
|
|
795
|
+
({ icon, title, subtitle, centered }: AuthStepHeaderProps): React$1.JSX.Element;
|
|
796
|
+
displayName: string;
|
|
797
|
+
};
|
|
798
|
+
|
|
799
|
+
interface OTPBoxGroupProps {
|
|
800
|
+
value: string;
|
|
801
|
+
onChange: (value: string) => void;
|
|
802
|
+
onComplete?: (value: string) => void;
|
|
803
|
+
disabled?: boolean;
|
|
804
|
+
ariaLabel?: string;
|
|
805
|
+
autoFocus?: boolean;
|
|
806
|
+
}
|
|
807
|
+
declare const OTPBoxGroup: {
|
|
808
|
+
({ value, onChange, onComplete, disabled, ariaLabel, autoFocus, }: OTPBoxGroupProps): React$1.JSX.Element;
|
|
809
|
+
displayName: string;
|
|
810
|
+
};
|
|
811
|
+
|
|
812
|
+
interface PasswordInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
813
|
+
language?: 'en' | 'ar';
|
|
814
|
+
}
|
|
815
|
+
declare const PasswordInput: React$1.ForwardRefExoticComponent<PasswordInputProps & React$1.RefAttributes<HTMLInputElement>>;
|
|
816
|
+
|
|
817
|
+
interface PasswordRule {
|
|
818
|
+
id: string;
|
|
819
|
+
label_en: string;
|
|
820
|
+
label_ar: string;
|
|
821
|
+
met: boolean;
|
|
822
|
+
}
|
|
823
|
+
interface PasswordStrengthMeterProps {
|
|
824
|
+
password: string;
|
|
825
|
+
language?: 'en' | 'ar';
|
|
826
|
+
}
|
|
827
|
+
declare function computeRules(password: string): PasswordRule[];
|
|
828
|
+
declare function computeScore(rules: PasswordRule[]): number;
|
|
829
|
+
declare const PasswordStrengthMeter: {
|
|
830
|
+
({ password, language }: PasswordStrengthMeterProps): React$1.JSX.Element;
|
|
831
|
+
displayName: string;
|
|
832
|
+
};
|
|
833
|
+
|
|
834
|
+
type Lang$2 = 'en' | 'ar';
|
|
835
|
+
interface LockScreenUser {
|
|
836
|
+
/** Display name (language-resolved by caller). */
|
|
837
|
+
name?: string | null;
|
|
838
|
+
email: string;
|
|
839
|
+
avatarUrl?: string | null;
|
|
840
|
+
}
|
|
841
|
+
interface LockScreenProps {
|
|
842
|
+
user: LockScreenUser;
|
|
843
|
+
/**
|
|
844
|
+
* Called with the entered PIN when the user submits.
|
|
845
|
+
* Should throw (or reject) if the PIN is wrong so the component can count
|
|
846
|
+
* failed attempts. On success it should resolve without throwing.
|
|
847
|
+
*/
|
|
848
|
+
onUnlock: (pin: string) => Promise<void>;
|
|
849
|
+
/** Called when the user clicks "Not you? Sign out". */
|
|
850
|
+
onSignOut: () => void;
|
|
851
|
+
/** Current UI language. Default: 'en'. */
|
|
852
|
+
language?: Lang$2;
|
|
853
|
+
/**
|
|
854
|
+
* Exact PIN length expected. Accepts 4-6. Default: 6.
|
|
855
|
+
* NOTE: OTPBoxGroup always renders 6 slots; when pinLength < 6 the component
|
|
856
|
+
* auto-submits on the Nth digit instead of the 6th.
|
|
857
|
+
*/
|
|
858
|
+
pinLength?: 4 | 5 | 6;
|
|
859
|
+
/** Max failed attempts before the lockout state. Default: 5. */
|
|
860
|
+
maxAttempts?: number;
|
|
861
|
+
/** Optional extra class on the outer wrapper. */
|
|
862
|
+
className?: string;
|
|
863
|
+
}
|
|
864
|
+
declare const LockScreen: {
|
|
865
|
+
({ user, onUnlock, onSignOut, language, pinLength, maxAttempts, className, }: LockScreenProps): React$1.JSX.Element;
|
|
866
|
+
displayName: string;
|
|
867
|
+
};
|
|
868
|
+
|
|
869
|
+
type Lang$1 = 'en' | 'ar';
|
|
870
|
+
interface PasswordLockScreenUser {
|
|
871
|
+
name?: string | null;
|
|
872
|
+
email: string;
|
|
873
|
+
avatarUrl?: string | null;
|
|
874
|
+
}
|
|
875
|
+
interface UnlockCredentials {
|
|
876
|
+
password: string;
|
|
877
|
+
totp?: string;
|
|
878
|
+
}
|
|
879
|
+
interface PasswordLockScreenProps {
|
|
880
|
+
user: PasswordLockScreenUser;
|
|
881
|
+
/**
|
|
882
|
+
* Called with the entered credentials. Should throw an Error whose message is
|
|
883
|
+
* the server error code (e.g. "invalid_credentials", "totp_required",
|
|
884
|
+
* "invalid_totp", "too_many_attempts").
|
|
885
|
+
*/
|
|
886
|
+
onUnlock: (creds: UnlockCredentials) => Promise<void>;
|
|
887
|
+
/** Called when user clicks "Switch account". */
|
|
888
|
+
onSignOut: () => void;
|
|
889
|
+
/**
|
|
890
|
+
* Called when the server has force-logged-out after too many failures.
|
|
891
|
+
* The session cookies are already cleared; the caller should redirect to login.
|
|
892
|
+
*/
|
|
893
|
+
onForceLogout?: () => void;
|
|
894
|
+
/** UI language. Default: 'en'. */
|
|
895
|
+
language?: Lang$1;
|
|
896
|
+
/** Max failed attempts before lockout state. Default: 5. */
|
|
897
|
+
maxAttempts?: number;
|
|
898
|
+
/**
|
|
899
|
+
* Whether the user has TOTP enrolled. When true the TOTP field is always
|
|
900
|
+
* visible. When false (default), it appears only after a totp_required error.
|
|
901
|
+
*/
|
|
902
|
+
hasTOTP?: boolean;
|
|
903
|
+
/** Optional extra class on the outer wrapper. */
|
|
904
|
+
className?: string;
|
|
905
|
+
}
|
|
906
|
+
declare const PasswordLockScreen: {
|
|
907
|
+
({ user, onUnlock, onSignOut, onForceLogout, language, maxAttempts, hasTOTP: hasTOTPProp, className, }: PasswordLockScreenProps): React$1.JSX.Element;
|
|
908
|
+
displayName: string;
|
|
909
|
+
};
|
|
910
|
+
|
|
911
|
+
interface SidebarUser {
|
|
912
|
+
email: string | null;
|
|
913
|
+
displayName: string | null;
|
|
914
|
+
avatarUrl?: string;
|
|
915
|
+
}
|
|
916
|
+
interface SidebarConversation {
|
|
917
|
+
id: string;
|
|
918
|
+
title_en: string;
|
|
919
|
+
title_ar?: string | null;
|
|
920
|
+
}
|
|
921
|
+
interface AppSidebarProps {
|
|
922
|
+
/** Locale */
|
|
923
|
+
language: 'en' | 'ar';
|
|
924
|
+
isRTL: boolean;
|
|
925
|
+
/** Branding — from BrandingProvider (U1) or direct props */
|
|
926
|
+
appName?: string;
|
|
927
|
+
logo?: string;
|
|
928
|
+
/** Auth */
|
|
929
|
+
user?: SidebarUser | null;
|
|
930
|
+
isAuthLoading?: boolean;
|
|
931
|
+
onSignOut?: () => void | Promise<void>;
|
|
932
|
+
/** Navigation callbacks — product layer provides these */
|
|
933
|
+
onNavigate?: (href: string) => void;
|
|
934
|
+
/** Current pathname — used to highlight active tab and conversations */
|
|
935
|
+
currentPathname?: string;
|
|
936
|
+
/** Chat / conversation data (optional — hides the section when absent) */
|
|
937
|
+
conversations?: SidebarConversation[];
|
|
938
|
+
isConversationsLoading?: boolean;
|
|
939
|
+
/** Tab hrefs */
|
|
940
|
+
assistantHref?: string;
|
|
941
|
+
analysisHref?: string;
|
|
942
|
+
}
|
|
943
|
+
declare const AppSidebar: {
|
|
944
|
+
({ language, isRTL, appName, logo, user, isAuthLoading, onSignOut, onNavigate, currentPathname, conversations, isConversationsLoading, assistantHref, analysisHref, }: AppSidebarProps): React$1.JSX.Element;
|
|
945
|
+
displayName: string;
|
|
946
|
+
};
|
|
947
|
+
|
|
948
|
+
interface AppPageShellProps {
|
|
949
|
+
children: React__default.ReactNode;
|
|
950
|
+
/** Whether the current layout direction is RTL */
|
|
951
|
+
isRTL: boolean;
|
|
952
|
+
/** Called when auth check fails — product layer does the redirect */
|
|
953
|
+
isAuthenticated?: boolean;
|
|
954
|
+
isAuthLoading?: boolean;
|
|
955
|
+
onUnauthenticated?: () => void;
|
|
956
|
+
/** Full nav element rendered above content (UnifiedTopNav in app layer) */
|
|
957
|
+
topNavSlot?: React__default.ReactNode;
|
|
958
|
+
/** Slots for real-time banners rendered between nav and main content
|
|
959
|
+
* (CriticalAlertsBar, NewsChannelBanner, NotificationTicker) */
|
|
960
|
+
realtimeSlotsTop?: React__default.ReactNode;
|
|
961
|
+
/** Slot for the footer ticker (BreakingNewsTicker) */
|
|
962
|
+
realtimeSlotBottom?: React__default.ReactNode;
|
|
963
|
+
/** Backward-compat: copilotSeeds (unused) */
|
|
964
|
+
copilotSeeds?: string[];
|
|
965
|
+
}
|
|
966
|
+
declare const AppPageShell: {
|
|
967
|
+
({ children, isRTL, isAuthenticated, isAuthLoading, onUnauthenticated, topNavSlot, realtimeSlotsTop, realtimeSlotBottom, copilotSeeds: _copilotSeeds, }: AppPageShellProps): React__default.JSX.Element | null;
|
|
968
|
+
displayName: string;
|
|
969
|
+
};
|
|
970
|
+
|
|
971
|
+
type View = 'foryou' | 'dashboard' | 'projects';
|
|
972
|
+
interface ViewToggleProps {
|
|
973
|
+
currentView?: View;
|
|
974
|
+
language: 'en' | 'ar';
|
|
975
|
+
isMobile?: boolean;
|
|
976
|
+
/** Current URL path — used to derive active view */
|
|
977
|
+
currentPathname?: string;
|
|
978
|
+
/** Called with the new view when the user clicks */
|
|
979
|
+
onViewChange: (view: View) => void;
|
|
980
|
+
/** Called to navigate to a path */
|
|
981
|
+
onNavigate?: (path: string) => void;
|
|
982
|
+
}
|
|
983
|
+
declare const ViewToggle: {
|
|
984
|
+
({ language, isMobile, currentPathname, currentView, onViewChange, onNavigate, }: ViewToggleProps): React$1.JSX.Element;
|
|
985
|
+
displayName: string;
|
|
986
|
+
};
|
|
987
|
+
|
|
988
|
+
interface RouteProgressProps {
|
|
989
|
+
/**
|
|
990
|
+
* The current route path. Pass `usePathname()` from the app. Whenever this
|
|
991
|
+
* value changes the bar animates. Required — the app owns the router binding.
|
|
992
|
+
*/
|
|
993
|
+
pathname: string;
|
|
994
|
+
/** Bar height in px. Default 2. */
|
|
995
|
+
height?: number;
|
|
996
|
+
}
|
|
997
|
+
declare const RouteProgress: {
|
|
998
|
+
({ pathname, height }: RouteProgressProps): React$1.JSX.Element;
|
|
999
|
+
displayName: string;
|
|
1000
|
+
};
|
|
1001
|
+
|
|
1002
|
+
interface AppNavItem {
|
|
1003
|
+
key: string;
|
|
1004
|
+
label: string;
|
|
1005
|
+
icon?: React$1.ReactNode;
|
|
1006
|
+
badge?: React$1.ReactNode;
|
|
1007
|
+
active?: boolean;
|
|
1008
|
+
}
|
|
1009
|
+
interface AppNavGroup {
|
|
1010
|
+
label?: string;
|
|
1011
|
+
items: AppNavItem[];
|
|
1012
|
+
}
|
|
1013
|
+
interface AppBrand {
|
|
1014
|
+
name: string;
|
|
1015
|
+
subtitle?: string;
|
|
1016
|
+
icon?: React$1.ReactNode;
|
|
1017
|
+
primary?: string;
|
|
1018
|
+
}
|
|
1019
|
+
interface AppHeaderProps {
|
|
1020
|
+
/** Renders a sidebar collapse trigger at the start. */
|
|
1021
|
+
withSidebarTrigger?: boolean;
|
|
1022
|
+
title?: React$1.ReactNode;
|
|
1023
|
+
/** Center slot (e.g. a search box). */
|
|
1024
|
+
center?: React$1.ReactNode;
|
|
1025
|
+
/** End slot (e.g. actions, user menu, realtime dot). */
|
|
1026
|
+
end?: React$1.ReactNode;
|
|
1027
|
+
className?: string;
|
|
1028
|
+
}
|
|
1029
|
+
/** AppHeader — a product-agnostic top bar: optional sidebar trigger + title (start),
|
|
1030
|
+
* an optional center slot, and an end slot (actions / user menu). Token-themed, RTL. */
|
|
1031
|
+
declare function AppHeader({ withSidebarTrigger, title, center, end, className }: AppHeaderProps): React$1.JSX.Element;
|
|
1032
|
+
interface AppLayoutProps {
|
|
1033
|
+
brand: AppBrand;
|
|
1034
|
+
nav: AppNavGroup[];
|
|
1035
|
+
onNavigate?: (key: string) => void;
|
|
1036
|
+
/** Footer nav (e.g. Profile / Settings). */
|
|
1037
|
+
footer?: AppNavGroup;
|
|
1038
|
+
/** Header slots. */
|
|
1039
|
+
headerTitle?: React$1.ReactNode;
|
|
1040
|
+
headerCenter?: React$1.ReactNode;
|
|
1041
|
+
headerEnd?: React$1.ReactNode;
|
|
1042
|
+
/** Optional floating slot inside the content (e.g. a copilot launcher). */
|
|
1043
|
+
assistant?: React$1.ReactNode;
|
|
1044
|
+
language?: "en" | "ar";
|
|
1045
|
+
defaultSidebarOpen?: boolean;
|
|
1046
|
+
children: React$1.ReactNode;
|
|
1047
|
+
className?: string;
|
|
1048
|
+
}
|
|
1049
|
+
/** AppLayout — the full app shell: a collapsible sidebar (brand + nav groups + footer)
|
|
1050
|
+
* + a top header + content area. Built on the kit Sidebar primitives. Responsive
|
|
1051
|
+
* (off-canvas on mobile), RTL-aware, token-themed. */
|
|
1052
|
+
declare function AppLayout({ brand, nav, onNavigate, footer, headerTitle, headerCenter, headerEnd, assistant, language, defaultSidebarOpen, children, className, }: AppLayoutProps): React$1.JSX.Element;
|
|
1053
|
+
|
|
1054
|
+
interface AdminSubNavItem {
|
|
1055
|
+
key: string;
|
|
1056
|
+
label: string;
|
|
1057
|
+
icon?: React$1.ReactNode;
|
|
1058
|
+
}
|
|
1059
|
+
interface AdminLayoutProps extends Omit<AppLayoutProps, "children"> {
|
|
1060
|
+
/** Secondary section tabs rendered under the header (admin areas). */
|
|
1061
|
+
subNav: AdminSubNavItem[];
|
|
1062
|
+
activeSubNav?: string;
|
|
1063
|
+
onSubNavChange?: (key: string) => void;
|
|
1064
|
+
children: React$1.ReactNode;
|
|
1065
|
+
}
|
|
1066
|
+
/** AdminLayout — AppLayout plus a secondary sub-navigation tab bar under the header,
|
|
1067
|
+
* for admin areas (e.g. Users / Roles / Settings / Audit). Token-themed, RTL. */
|
|
1068
|
+
declare function AdminLayout({ subNav, activeSubNav, onSubNavChange, children, ...appProps }: AdminLayoutProps): React$1.JSX.Element;
|
|
1069
|
+
|
|
1070
|
+
interface DynamicIconProps {
|
|
1071
|
+
name: string | null | undefined;
|
|
1072
|
+
className?: string;
|
|
1073
|
+
size?: number;
|
|
1074
|
+
strokeWidth?: number;
|
|
1075
|
+
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Renders an icon by name string — supports four icon sources:
|
|
1078
|
+
*
|
|
1079
|
+
* 1. Image URL (starts with "http://", "https://", or "/"):
|
|
1080
|
+
* Renders an <img> sized to match a lucide/boxicon of the same h-N class.
|
|
1081
|
+
*
|
|
1082
|
+
* 2. Boxicons brand icons — two accepted formats:
|
|
1083
|
+
* a. Colon-prefix (canonical): "bxl:<name>" → "bxl-<name>" CSS class
|
|
1084
|
+
* b. Legacy hyphen-prefix: "bxl-*" / "bx-*"
|
|
1085
|
+
* Requires boxicons CSS loaded at the app root.
|
|
1086
|
+
*
|
|
1087
|
+
* 3. Lucide icons — two accepted formats:
|
|
1088
|
+
* a. Colon-prefix (canonical): "lucide:<kebab-case>" → PascalCase lookup
|
|
1089
|
+
* b. Legacy bare PascalCase (kept for backward-compat)
|
|
1090
|
+
* Falls back to <Sparkles> when name is null, empty, or unrecognised.
|
|
1091
|
+
*/
|
|
1092
|
+
declare const DynamicIcon: {
|
|
1093
|
+
({ name, className, size, strokeWidth }: DynamicIconProps): React$1.JSX.Element;
|
|
1094
|
+
displayName: string;
|
|
1095
|
+
};
|
|
1096
|
+
|
|
1097
|
+
interface ProfileSession {
|
|
1098
|
+
id: string;
|
|
1099
|
+
device: string;
|
|
1100
|
+
location?: string;
|
|
1101
|
+
lastActive: string;
|
|
1102
|
+
current?: boolean;
|
|
1103
|
+
}
|
|
1104
|
+
interface ProfileViewProps {
|
|
1105
|
+
user: {
|
|
1106
|
+
name?: string;
|
|
1107
|
+
email: string;
|
|
1108
|
+
avatarUrl?: string;
|
|
1109
|
+
roles?: string[];
|
|
1110
|
+
};
|
|
1111
|
+
language?: "en" | "ar";
|
|
1112
|
+
sessions?: ProfileSession[];
|
|
1113
|
+
twoFactorEnabled?: boolean;
|
|
1114
|
+
onSave?: (data: {
|
|
1115
|
+
name: string;
|
|
1116
|
+
email: string;
|
|
1117
|
+
}) => void;
|
|
1118
|
+
onChangePassword?: () => void;
|
|
1119
|
+
onToggle2FA?: (enabled: boolean) => void;
|
|
1120
|
+
onRevokeSession?: (id: string) => void;
|
|
1121
|
+
onChangeAvatar?: () => void;
|
|
1122
|
+
}
|
|
1123
|
+
/** ProfileView — a real settings screen: a section sidebar (Account / Security / Sessions)
|
|
1124
|
+
* beside the active section's content. Product-agnostic (data + callbacks in), RTL + bilingual
|
|
1125
|
+
* via `language`, fully token-themed (dark/light). */
|
|
1126
|
+
declare function ProfileView({ user, language, sessions, twoFactorEnabled, onSave, onChangePassword, onToggle2FA, onRevokeSession, onChangeAvatar, }: ProfileViewProps): React$1.JSX.Element;
|
|
1127
|
+
|
|
1128
|
+
interface ColorPickerProps {
|
|
1129
|
+
/** Current color, hex (e.g. "#7c3aed"). */
|
|
1130
|
+
value: string;
|
|
1131
|
+
onChange: (hex: string) => void;
|
|
1132
|
+
/** Preset swatches shown in the popover. */
|
|
1133
|
+
presets?: string[];
|
|
1134
|
+
/** Optional className for the trigger. */
|
|
1135
|
+
className?: string;
|
|
1136
|
+
disabled?: boolean;
|
|
1137
|
+
"aria-label"?: string;
|
|
1138
|
+
}
|
|
1139
|
+
/** ColorPicker — a swatch trigger that opens a popover with a native color input,
|
|
1140
|
+
* a hex field, and preset swatches. Presentational + controlled. */
|
|
1141
|
+
declare function ColorPicker({ value, onChange, presets, className, disabled, ...rest }: ColorPickerProps): React$1.JSX.Element;
|
|
1142
|
+
|
|
1143
|
+
interface IconPickerProps {
|
|
1144
|
+
/** Current icon name (lucide PascalCase, e.g. "Sparkles"). */
|
|
1145
|
+
value?: string;
|
|
1146
|
+
onChange: (name: string) => void;
|
|
1147
|
+
/** Restrict to a custom icon list (defaults to a curated common set). */
|
|
1148
|
+
icons?: string[];
|
|
1149
|
+
className?: string;
|
|
1150
|
+
disabled?: boolean;
|
|
1151
|
+
}
|
|
1152
|
+
/** IconPicker — a button that opens a searchable grid of lucide icons. Controlled
|
|
1153
|
+
* by `value` (icon name) + `onChange`. Presentational + token-themed. */
|
|
1154
|
+
declare function IconPicker({ value, onChange, icons, className, disabled }: IconPickerProps): React$1.JSX.Element;
|
|
1155
|
+
|
|
1156
|
+
interface MapMarker$1 {
|
|
1157
|
+
lat: number;
|
|
1158
|
+
lng: number;
|
|
1159
|
+
label?: string;
|
|
1160
|
+
/** Marker color (defaults to the brand primary). */
|
|
1161
|
+
color?: string;
|
|
1162
|
+
}
|
|
1163
|
+
interface MapViewProps {
|
|
1164
|
+
center: [number, number];
|
|
1165
|
+
zoom?: number;
|
|
1166
|
+
markers?: MapMarker$1[];
|
|
1167
|
+
/** Height of the map container (CSS value). Default 360px. */
|
|
1168
|
+
height?: number | string;
|
|
1169
|
+
className?: string;
|
|
1170
|
+
/** Tile attribution. Defaults to OpenStreetMap. */
|
|
1171
|
+
attribution?: string;
|
|
1172
|
+
}
|
|
1173
|
+
/** MapView — a real OpenStreetMap powered by leaflet. SSR-safe (leaflet loads in an
|
|
1174
|
+
* effect, client-only). Pass `center`, `zoom`, and `markers`. Themed container; the
|
|
1175
|
+
* tiles are OSM raster. */
|
|
1176
|
+
declare function MapView({ center, zoom, markers, height, className, attribution, }: MapViewProps): React$1.JSX.Element;
|
|
1177
|
+
|
|
1178
|
+
/**
|
|
1179
|
+
* Map component types for sentra-ui.
|
|
1180
|
+
*
|
|
1181
|
+
* The map renderer itself is NOT included in this package to avoid bundling
|
|
1182
|
+
* maplibre-gl (~600 KB gzipped WebGL runtime) as a hard dependency. Products
|
|
1183
|
+
* supply the renderer via the `renderMap` prop (see MapPanel). This keeps the
|
|
1184
|
+
* library tree-shaking-friendly: consumers that never show a map pay zero cost.
|
|
1185
|
+
*/
|
|
1186
|
+
/** A single geographic marker for the map. */
|
|
1187
|
+
interface MapMarker {
|
|
1188
|
+
id: string;
|
|
1189
|
+
/** Longitude */
|
|
1190
|
+
lng: number;
|
|
1191
|
+
/** Latitude */
|
|
1192
|
+
lat: number;
|
|
1193
|
+
/** Marker category — drives color + legend shape */
|
|
1194
|
+
markerType: MapMarkerType;
|
|
1195
|
+
/** English label shown in tooltip */
|
|
1196
|
+
label: string;
|
|
1197
|
+
/** Arabic label (RTL), falls back to label if absent */
|
|
1198
|
+
label_ar?: string;
|
|
1199
|
+
description?: string;
|
|
1200
|
+
description_ar?: string;
|
|
1201
|
+
/** Nominal size in pixels at zoom level 6 (data-driven) */
|
|
1202
|
+
size?: number;
|
|
1203
|
+
}
|
|
1204
|
+
/** All marker types the map legend and styling system understand. */
|
|
1205
|
+
type MapMarkerType = 'strike' | 'launch_site' | 'proxy_force' | 'military_base' | 'air_defense' | 'nuclear' | 'naval' | 'infrastructure';
|
|
1206
|
+
type LegendShapeType = 'diamond' | 'burst' | 'chevron' | 'triangle' | 'hexagon' | 'ring' | 'pill' | 'square';
|
|
1207
|
+
interface LegendItem {
|
|
1208
|
+
/** Marker type key — used to look up color and label */
|
|
1209
|
+
type: MapMarkerType;
|
|
1210
|
+
shape: LegendShapeType;
|
|
1211
|
+
}
|
|
1212
|
+
interface LegendGroup {
|
|
1213
|
+
label: string;
|
|
1214
|
+
label_ar: string;
|
|
1215
|
+
items: LegendItem[];
|
|
1216
|
+
}
|
|
1217
|
+
type AlertSeverity = 'critical' | 'high' | 'medium' | 'low';
|
|
1218
|
+
interface AlertMapItem {
|
|
1219
|
+
id: string;
|
|
1220
|
+
slug: string;
|
|
1221
|
+
title_en: string;
|
|
1222
|
+
title_ar: string | null;
|
|
1223
|
+
severity: AlertSeverity | null;
|
|
1224
|
+
mode: string;
|
|
1225
|
+
scope: string;
|
|
1226
|
+
topics: string[];
|
|
1227
|
+
updated_at: string;
|
|
1228
|
+
}
|
|
1229
|
+
/**
|
|
1230
|
+
* Region preset — used by the region selector and the fly-to handler.
|
|
1231
|
+
* The renderMap slot receives `initialRegion` so the product's map engine can
|
|
1232
|
+
* set its initial viewport.
|
|
1233
|
+
*/
|
|
1234
|
+
interface MapRegionPreset {
|
|
1235
|
+
key: string;
|
|
1236
|
+
label: string;
|
|
1237
|
+
label_ar: string;
|
|
1238
|
+
latitude: number;
|
|
1239
|
+
longitude: number;
|
|
1240
|
+
zoom: number;
|
|
1241
|
+
}
|
|
1242
|
+
/**
|
|
1243
|
+
* Layer toggle entry — sent to the LayersPanel and also passed to renderMap so
|
|
1244
|
+
* the product can show/hide GeoJSON layers.
|
|
1245
|
+
*/
|
|
1246
|
+
interface MapLayer {
|
|
1247
|
+
id: string;
|
|
1248
|
+
label: string;
|
|
1249
|
+
label_ar: string;
|
|
1250
|
+
enabled: boolean;
|
|
1251
|
+
color?: string;
|
|
1252
|
+
}
|
|
1253
|
+
/**
|
|
1254
|
+
* The seam contract the renderMap prop must satisfy.
|
|
1255
|
+
*
|
|
1256
|
+
* The product supplies a renderer (e.g. <Map> from react-map-gl/maplibre) and
|
|
1257
|
+
* receives the full state it needs to wire GeoJSON Sources and Layers. The
|
|
1258
|
+
* sentra-ui package never imports react-map-gl or maplibre-gl.
|
|
1259
|
+
*/
|
|
1260
|
+
interface RenderMapContext {
|
|
1261
|
+
/** Active layers; product hides/shows Source/Layer accordingly */
|
|
1262
|
+
layers: Record<string, boolean>;
|
|
1263
|
+
/** Markers to render as GeoJSON point features */
|
|
1264
|
+
markers: MapMarker[];
|
|
1265
|
+
/** Alert pins from the product's data fetch */
|
|
1266
|
+
alerts: AlertMapItem[];
|
|
1267
|
+
/** Currently active region preset */
|
|
1268
|
+
activeRegion: MapRegionPreset;
|
|
1269
|
+
/** Language code — 'en' | 'ar' */
|
|
1270
|
+
language: string;
|
|
1271
|
+
/** Text direction — 'ltr' | 'rtl' */
|
|
1272
|
+
dir: 'ltr' | 'rtl';
|
|
1273
|
+
/** Whether the host app is in dark theme */
|
|
1274
|
+
isDark: boolean;
|
|
1275
|
+
}
|
|
1276
|
+
interface MapPanelProps {
|
|
1277
|
+
/**
|
|
1278
|
+
* The actual map renderer, supplied by the product.
|
|
1279
|
+
*
|
|
1280
|
+
* Receives full state via RenderMapContext. Return a React node that fills
|
|
1281
|
+
* its container (w-full h-full). Example usage in sentra-next:
|
|
1282
|
+
*
|
|
1283
|
+
* ```tsx
|
|
1284
|
+
* renderMap={(ctx) => (
|
|
1285
|
+
* <SituationMapEmbed
|
|
1286
|
+
* layers={ctx.layers}
|
|
1287
|
+
* alerts={ctx.alerts}
|
|
1288
|
+
* language={ctx.language}
|
|
1289
|
+
* isDark={ctx.isDark}
|
|
1290
|
+
* />
|
|
1291
|
+
* )}
|
|
1292
|
+
* ```
|
|
1293
|
+
*
|
|
1294
|
+
* If omitted, an informational placeholder is shown — useful in Storybook
|
|
1295
|
+
* and tests.
|
|
1296
|
+
*/
|
|
1297
|
+
renderMap?: (ctx: RenderMapContext) => React.ReactNode;
|
|
1298
|
+
/** Markers passed to renderMap ctx — product builds these from its GeoJSON data */
|
|
1299
|
+
markers?: MapMarker[];
|
|
1300
|
+
/** Live alert pins — product fetches these from its bridge endpoint */
|
|
1301
|
+
alerts?: AlertMapItem[];
|
|
1302
|
+
/** Region presets for the region selector bar. Defaults to MENA presets. */
|
|
1303
|
+
regionPresets?: MapRegionPreset[];
|
|
1304
|
+
/** Layer definitions controlling the LayersPanel toggles */
|
|
1305
|
+
layers?: MapLayer[];
|
|
1306
|
+
/** Initial active region key — defaults to 'global' */
|
|
1307
|
+
initialRegion?: string;
|
|
1308
|
+
/** Active language code — 'en' | 'ar' */
|
|
1309
|
+
language?: string;
|
|
1310
|
+
/** Whether host is in dark theme — forwarded to renderMap ctx */
|
|
1311
|
+
isDark?: boolean;
|
|
1312
|
+
/** Called when a layer is toggled */
|
|
1313
|
+
onLayerToggle?: (layerId: string, enabled: boolean) => void;
|
|
1314
|
+
/** Called when alert count changes (useful for badge in host nav) */
|
|
1315
|
+
onAlertCountChange?: (count: number) => void;
|
|
1316
|
+
/** CSS class name applied to the root container */
|
|
1317
|
+
className?: string;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
interface MapLegendProps {
|
|
1321
|
+
/** Language code — 'en' | 'ar'. Controls label language and RTL positioning. */
|
|
1322
|
+
language?: string;
|
|
1323
|
+
/** Override legend groups (marker types + shapes). Defaults to MENA presets. */
|
|
1324
|
+
groups?: LegendGroup[];
|
|
1325
|
+
/**
|
|
1326
|
+
* Marker color map — keys are MapMarkerType strings, values are hex colors.
|
|
1327
|
+
* Defaults to MARKER_COLORS from mapDefaults.
|
|
1328
|
+
*/
|
|
1329
|
+
markerColors?: Partial<Record<MapMarkerType, string>>;
|
|
1330
|
+
/**
|
|
1331
|
+
* Marker label map — keys are MapMarkerType strings.
|
|
1332
|
+
* Defaults to MARKER_LABELS from mapDefaults.
|
|
1333
|
+
*/
|
|
1334
|
+
markerLabels?: Partial<Record<MapMarkerType, {
|
|
1335
|
+
en: string;
|
|
1336
|
+
ar: string;
|
|
1337
|
+
}>>;
|
|
1338
|
+
/** Additional class name on the root element */
|
|
1339
|
+
className?: string;
|
|
1340
|
+
/** Initially collapsed. Defaults to false (expanded). */
|
|
1341
|
+
defaultCollapsed?: boolean;
|
|
1342
|
+
}
|
|
1343
|
+
declare const MapLegend: {
|
|
1344
|
+
({ language, groups, markerColors, markerLabels, className, defaultCollapsed, }: MapLegendProps): React$1.JSX.Element;
|
|
1345
|
+
displayName: string;
|
|
1346
|
+
};
|
|
1347
|
+
|
|
1348
|
+
interface MapLayersPanelProps {
|
|
1349
|
+
/** Layer toggle entries. Defaults to DEFAULT_LAYERS from mapDefaults. */
|
|
1350
|
+
layers?: MapLayer[];
|
|
1351
|
+
/** Language code — 'en' | 'ar' */
|
|
1352
|
+
language?: string;
|
|
1353
|
+
/** Called when a layer toggle changes */
|
|
1354
|
+
onToggle?: (layerId: string, enabled: boolean) => void;
|
|
1355
|
+
/** Additional class name on root */
|
|
1356
|
+
className?: string;
|
|
1357
|
+
}
|
|
1358
|
+
declare const MapLayersPanel: {
|
|
1359
|
+
({ layers, language, onToggle, className, }: MapLayersPanelProps): React$1.JSX.Element;
|
|
1360
|
+
displayName: string;
|
|
1361
|
+
};
|
|
1362
|
+
|
|
1363
|
+
/**
|
|
1364
|
+
* MapPanel — chrome shell for the situation map view.
|
|
1365
|
+
*
|
|
1366
|
+
* Ported from app/src/components/situation-map/SituationMapEmbed.tsx.
|
|
1367
|
+
*
|
|
1368
|
+
* DESIGN DECISION — renderMap seam (option b from the porting spec):
|
|
1369
|
+
* ──────────────────────────────────────────────────────────────────
|
|
1370
|
+
* react-map-gl@7 + maplibre-gl@4 together add ~600 KB gzipped WebGL runtime.
|
|
1371
|
+
* Bundling them into @prism/ui would force every product consumer to pay that
|
|
1372
|
+
* cost even when no map is rendered (e.g. Scout's data-table views).
|
|
1373
|
+
*
|
|
1374
|
+
* Instead, MapPanel exposes a `renderMap` prop that receives a RenderMapContext
|
|
1375
|
+
* object. The product (sentra-next) supplies the actual <Map> component from
|
|
1376
|
+
* react-map-gl/maplibre, which it already depends on. sentra-ui ships zero
|
|
1377
|
+
* map-library bytes.
|
|
1378
|
+
*
|
|
1379
|
+
* Everything else — region selector bar, time-range filter, layers panel,
|
|
1380
|
+
* legend, alert sidebar — is real and fully ported here. The seam is only
|
|
1381
|
+
* the WebGL canvas itself.
|
|
1382
|
+
*
|
|
1383
|
+
* Adaptations from source:
|
|
1384
|
+
* - @/lib/utils → ../../lib/utils
|
|
1385
|
+
* - @/components/ui/* → ../ui/*
|
|
1386
|
+
* - useLanguage → language / dir props
|
|
1387
|
+
* - useTheme → isDark prop
|
|
1388
|
+
* - bridge + useQuery → alerts prop (product fetches and passes)
|
|
1389
|
+
* - WebSocket listener → onAlertCountChange callback
|
|
1390
|
+
* - REGION_PRESETS → regionPresets prop (defaults to DEFAULT_REGION_PRESETS)
|
|
1391
|
+
* - LayersPanel / MapLegend → imported from this module
|
|
1392
|
+
*/
|
|
1393
|
+
|
|
1394
|
+
declare const MapPanel: {
|
|
1395
|
+
({ renderMap, markers, alerts, regionPresets, layers: layersProp, initialRegion, language, isDark, onLayerToggle, onAlertCountChange, className, }: MapPanelProps): React__default.JSX.Element;
|
|
1396
|
+
displayName: string;
|
|
1397
|
+
};
|
|
1398
|
+
|
|
1399
|
+
interface EventMapPanelProps {
|
|
1400
|
+
/** Structured location string — if absent the panel renders nothing */
|
|
1401
|
+
location?: string | null;
|
|
1402
|
+
/** Language code — 'en' | 'ar' */
|
|
1403
|
+
language?: string;
|
|
1404
|
+
}
|
|
1405
|
+
declare const EventMapPanel: {
|
|
1406
|
+
({ location, language }: EventMapPanelProps): React$1.JSX.Element | null;
|
|
1407
|
+
displayName: string;
|
|
1408
|
+
};
|
|
1409
|
+
|
|
1410
|
+
/**
|
|
1411
|
+
* Default configuration constants for the map components.
|
|
1412
|
+
*
|
|
1413
|
+
* These are the same values used in the source app (situation-map-data.ts /
|
|
1414
|
+
* MapLegend.tsx) extracted here so map components are self-contained without
|
|
1415
|
+
* depending on the app's data/ directory.
|
|
1416
|
+
*/
|
|
1417
|
+
|
|
1418
|
+
declare const MARKER_COLORS: Record<MapMarkerType, string>;
|
|
1419
|
+
declare const MARKER_LABELS: Record<MapMarkerType, {
|
|
1420
|
+
en: string;
|
|
1421
|
+
ar: string;
|
|
1422
|
+
}>;
|
|
1423
|
+
declare const DEFAULT_LEGEND_GROUPS: LegendGroup[];
|
|
1424
|
+
declare const DEFAULT_REGION_PRESETS: MapRegionPreset[];
|
|
1425
|
+
declare const DEFAULT_LAYERS: MapLayer[];
|
|
1426
|
+
|
|
1427
|
+
interface GraphNode {
|
|
1428
|
+
id: string;
|
|
1429
|
+
label?: string;
|
|
1430
|
+
group?: string;
|
|
1431
|
+
}
|
|
1432
|
+
interface GraphLink {
|
|
1433
|
+
source: string;
|
|
1434
|
+
target: string;
|
|
1435
|
+
}
|
|
1436
|
+
interface NetworkGraphProps {
|
|
1437
|
+
nodes: GraphNode[];
|
|
1438
|
+
links: GraphLink[];
|
|
1439
|
+
width?: number;
|
|
1440
|
+
height?: number;
|
|
1441
|
+
className?: string;
|
|
1442
|
+
/** Map a group → CSS color. Falls back to a token palette. */
|
|
1443
|
+
groupColor?: (group: string | undefined) => string;
|
|
1444
|
+
/** Node circle radius. */
|
|
1445
|
+
nodeRadius?: number;
|
|
1446
|
+
/** Fired when a node is clicked (not dragged). */
|
|
1447
|
+
onNodeClick?: (node: GraphNode) => void;
|
|
1448
|
+
}
|
|
1449
|
+
/** NetworkGraph — a dependency-free, **live force-directed** SVG graph with
|
|
1450
|
+
* **draggable** nodes. Nodes repel, links act as springs, and the layout settles;
|
|
1451
|
+
* dragging a node pins it to the pointer and reheats the simulation so the graph
|
|
1452
|
+
* reacts dynamically. Pass `nodes` + `links`. */
|
|
1453
|
+
declare function NetworkGraph({ nodes, links, width, height, className, groupColor, nodeRadius, onNodeClick, }: NetworkGraphProps): React$1.JSX.Element;
|
|
1454
|
+
|
|
1455
|
+
type TEntityType = "government" | "individual" | "media" | "institution" | "state" | "organization" | "event" | "venue" | "persona" | "person" | "coalition";
|
|
1456
|
+
type TSentiment = "positive" | "negative" | "neutral" | "unknown";
|
|
1457
|
+
/** Network node/edge shapes for the graph renderer seam */
|
|
1458
|
+
interface NetworkNode {
|
|
1459
|
+
id: string;
|
|
1460
|
+
slug: string;
|
|
1461
|
+
name_en: string;
|
|
1462
|
+
name_ar?: string | null;
|
|
1463
|
+
type: TEntityType;
|
|
1464
|
+
sentiment?: TSentiment | null;
|
|
1465
|
+
image_url?: string | null;
|
|
1466
|
+
}
|
|
1467
|
+
interface NetworkEdge {
|
|
1468
|
+
source: string;
|
|
1469
|
+
target: string;
|
|
1470
|
+
weight: number;
|
|
1471
|
+
relation?: string | null;
|
|
1472
|
+
}
|
|
1473
|
+
interface EntityNetwork {
|
|
1474
|
+
nodes: NetworkNode[];
|
|
1475
|
+
edges: NetworkEdge[];
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
interface EntityNetworkGraphProps {
|
|
1479
|
+
/**
|
|
1480
|
+
* SEAM — host renders the actual graph canvas inside this callback.
|
|
1481
|
+
* Receives the network data so the canvas can build its own graphology Graph.
|
|
1482
|
+
* If omitted, a "graph unavailable" placeholder is shown.
|
|
1483
|
+
*
|
|
1484
|
+
* Example (app side):
|
|
1485
|
+
* renderGraph={(network) => <EntityNetworkGraphCanvas slug={slug} network={network} />}
|
|
1486
|
+
*/
|
|
1487
|
+
renderGraph?: (network: EntityNetwork) => React.ReactNode;
|
|
1488
|
+
/** Network data fetched from GET /api/entities/{slug}/network */
|
|
1489
|
+
network: EntityNetwork | null;
|
|
1490
|
+
isLoading?: boolean;
|
|
1491
|
+
isError?: boolean;
|
|
1492
|
+
onRetry?: () => void;
|
|
1493
|
+
language?: "en" | "ar";
|
|
1494
|
+
isRTL?: boolean;
|
|
1495
|
+
}
|
|
1496
|
+
declare const EntityNetworkGraph: {
|
|
1497
|
+
({ renderGraph, network, isLoading, isError, onRetry, language, isRTL, }: EntityNetworkGraphProps): React$1.JSX.Element;
|
|
1498
|
+
displayName: string;
|
|
1499
|
+
};
|
|
1500
|
+
|
|
1501
|
+
interface ActivityBucket {
|
|
1502
|
+
n: number;
|
|
1503
|
+
}
|
|
1504
|
+
interface PluginCatalogEntry {
|
|
1505
|
+
id: string;
|
|
1506
|
+
slug: string | null;
|
|
1507
|
+
name: string | null;
|
|
1508
|
+
name_en: string | null;
|
|
1509
|
+
name_ar: string | null;
|
|
1510
|
+
description: string | null;
|
|
1511
|
+
description_en: string | null;
|
|
1512
|
+
description_ar: string | null;
|
|
1513
|
+
plugin_type: string | null;
|
|
1514
|
+
/** adk_artifact sub-kind: tool | skill | agent | mcp | memory | persona */
|
|
1515
|
+
adk_kind?: string | null;
|
|
1516
|
+
enabled_globally: boolean | null;
|
|
1517
|
+
nav_icon: string | null;
|
|
1518
|
+
nav_color: string | null;
|
|
1519
|
+
last_active_at: string | null;
|
|
1520
|
+
activity_count: number | null;
|
|
1521
|
+
activity_series: ActivityBucket[] | null;
|
|
1522
|
+
route: string | null;
|
|
1523
|
+
}
|
|
1524
|
+
interface SparklinePoint {
|
|
1525
|
+
n: number;
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
interface PluginCardProps {
|
|
1529
|
+
plugin: PluginCatalogEntry;
|
|
1530
|
+
isRTL: boolean;
|
|
1531
|
+
/**
|
|
1532
|
+
* Resolved Lucide icon component for this plugin.
|
|
1533
|
+
* Host calls resolveIcon(plugin.nav_icon) and passes the result here.
|
|
1534
|
+
*/
|
|
1535
|
+
iconComponent?: LucideIcon;
|
|
1536
|
+
/** When true, render a checkbox for multi-select. */
|
|
1537
|
+
selectable?: boolean;
|
|
1538
|
+
selected?: boolean;
|
|
1539
|
+
onSelectChange?: (id: string, next: boolean) => void;
|
|
1540
|
+
/**
|
|
1541
|
+
* Called when the user clicks "Details". Host navigates to the detail page.
|
|
1542
|
+
* Receives the plugin slug (or id) as argument.
|
|
1543
|
+
*/
|
|
1544
|
+
onDetailClick?: (slugOrId: string) => void;
|
|
1545
|
+
/**
|
|
1546
|
+
* Called when the user clicks "Page" (external route link).
|
|
1547
|
+
* Receives the route string from plugin.route.
|
|
1548
|
+
*/
|
|
1549
|
+
onPageClick?: (route: string) => void;
|
|
1550
|
+
}
|
|
1551
|
+
declare const PluginCard: {
|
|
1552
|
+
({ plugin, isRTL, iconComponent: Icon, selectable, selected, onSelectChange, onDetailClick, onPageClick, }: PluginCardProps): React$1.JSX.Element;
|
|
1553
|
+
displayName: string;
|
|
1554
|
+
};
|
|
1555
|
+
|
|
1556
|
+
interface PluginPageHeaderProps {
|
|
1557
|
+
icon?: LucideIcon;
|
|
1558
|
+
title_en: string;
|
|
1559
|
+
title_ar: string;
|
|
1560
|
+
subtitle_en?: string;
|
|
1561
|
+
subtitle_ar?: string;
|
|
1562
|
+
actions?: React.ReactNode;
|
|
1563
|
+
/** Current UI language. */
|
|
1564
|
+
language: "en" | "ar";
|
|
1565
|
+
}
|
|
1566
|
+
declare const PluginPageHeader: {
|
|
1567
|
+
({ icon: Icon, title_en, title_ar, subtitle_en, subtitle_ar, actions, language, }: PluginPageHeaderProps): React$1.JSX.Element;
|
|
1568
|
+
displayName: string;
|
|
1569
|
+
};
|
|
1570
|
+
|
|
1571
|
+
interface PluginSectionCardProps {
|
|
1572
|
+
icon?: LucideIcon;
|
|
1573
|
+
title_en: string;
|
|
1574
|
+
title_ar: string;
|
|
1575
|
+
description_en?: string;
|
|
1576
|
+
description_ar?: string;
|
|
1577
|
+
/** Optional actions slot at the inline-end of the title row. */
|
|
1578
|
+
actions?: React.ReactNode;
|
|
1579
|
+
/** Adds destructive accent border for dangerous sections. */
|
|
1580
|
+
destructive?: boolean;
|
|
1581
|
+
className?: string;
|
|
1582
|
+
children: React.ReactNode;
|
|
1583
|
+
/** Current UI language. */
|
|
1584
|
+
language: "en" | "ar";
|
|
1585
|
+
}
|
|
1586
|
+
declare const PluginSectionCard: {
|
|
1587
|
+
({ icon: Icon, title_en, title_ar, description_en, description_ar, actions, destructive, className, children, language, }: PluginSectionCardProps): React$1.JSX.Element;
|
|
1588
|
+
displayName: string;
|
|
1589
|
+
};
|
|
1590
|
+
|
|
1591
|
+
interface PluginSparklineProps {
|
|
1592
|
+
pluginId: string;
|
|
1593
|
+
seriesData: SparklinePoint[];
|
|
1594
|
+
hasSeriesData: boolean;
|
|
1595
|
+
color: string;
|
|
1596
|
+
}
|
|
1597
|
+
declare const PluginSparkline: {
|
|
1598
|
+
({ pluginId, seriesData, hasSeriesData, color, }: PluginSparklineProps): React$1.JSX.Element;
|
|
1599
|
+
displayName: string;
|
|
1600
|
+
};
|
|
1601
|
+
|
|
1602
|
+
type SourceBadgeVariant = 'pill' | 'compact';
|
|
1603
|
+
type SourceBadgeSize = 'xs' | 'sm' | 'md';
|
|
1604
|
+
interface SourceBadgeProps {
|
|
1605
|
+
/** Display label (already localised by the product). */
|
|
1606
|
+
label: string;
|
|
1607
|
+
/** DynamicIcon name string — "si:openai", "lucide:zap", "bxl:reddit", a URL, etc. */
|
|
1608
|
+
navIcon?: string | null;
|
|
1609
|
+
/** Optional brand color (hex or CSS color) applied to the icon. */
|
|
1610
|
+
color?: string;
|
|
1611
|
+
variant?: SourceBadgeVariant;
|
|
1612
|
+
href?: string;
|
|
1613
|
+
size?: SourceBadgeSize;
|
|
1614
|
+
className?: string;
|
|
1615
|
+
}
|
|
1616
|
+
declare const SourceBadge: {
|
|
1617
|
+
({ label, navIcon, color, variant, href, size, className, }: SourceBadgeProps): React$1.JSX.Element;
|
|
1618
|
+
displayName: string;
|
|
1619
|
+
};
|
|
1620
|
+
|
|
1621
|
+
/** Appearance placement mode for a plugin. */
|
|
1622
|
+
type AppearanceMode = 'sidebar' | 'header' | 'sideover' | 'fixed' | 'hidden';
|
|
1623
|
+
/** Appearance fields passed into PluginAppearanceSection. */
|
|
1624
|
+
interface PluginAppearanceFields {
|
|
1625
|
+
appearance_mode: AppearanceMode;
|
|
1626
|
+
nav_order: number;
|
|
1627
|
+
/** Only relevant for capability plugins. */
|
|
1628
|
+
is_default_page?: boolean;
|
|
1629
|
+
plugin_type?: string | null;
|
|
1630
|
+
}
|
|
1631
|
+
/** A single workflow step (raw JSONB shape). */
|
|
1632
|
+
type WorkflowStep = Record<string, any>;
|
|
1633
|
+
/** A single workflow source (raw JSONB shape). */
|
|
1634
|
+
type WorkflowSource = Record<string, any>;
|
|
1635
|
+
/** Tab definition for PluginDetailLayout. */
|
|
1636
|
+
interface PluginDetailTab {
|
|
1637
|
+
key: string;
|
|
1638
|
+
label_en: string;
|
|
1639
|
+
label_ar: string;
|
|
1640
|
+
icon?: React.ElementType;
|
|
1641
|
+
/**
|
|
1642
|
+
* Optional section group label (bilingual). Tabs sharing the same section_en
|
|
1643
|
+
* render under one section header in the sub-sidebar (like the mofa-dev
|
|
1644
|
+
* reference: "Overview" / "Settings"). Tabs with no section render in an
|
|
1645
|
+
* unlabelled leading group. Order of first appearance defines section order.
|
|
1646
|
+
*/
|
|
1647
|
+
section_en?: string;
|
|
1648
|
+
section_ar?: string;
|
|
1649
|
+
}
|
|
1650
|
+
/** A pipeline stage for WorkflowPipeline. */
|
|
1651
|
+
interface PipelineLane {
|
|
1652
|
+
key: string;
|
|
1653
|
+
label_en: string;
|
|
1654
|
+
label_ar: string;
|
|
1655
|
+
cards: PipelineCard[];
|
|
1656
|
+
}
|
|
1657
|
+
/** A card inside a pipeline lane. */
|
|
1658
|
+
interface PipelineCard {
|
|
1659
|
+
id: string;
|
|
1660
|
+
title_en: string;
|
|
1661
|
+
title_ar: string;
|
|
1662
|
+
svc?: string;
|
|
1663
|
+
isSynthetic?: boolean;
|
|
1664
|
+
summary: {
|
|
1665
|
+
label: string;
|
|
1666
|
+
value: string;
|
|
1667
|
+
}[];
|
|
1668
|
+
metrics?: {
|
|
1669
|
+
ok_rate: number;
|
|
1670
|
+
p50_ms: number;
|
|
1671
|
+
last_error?: string;
|
|
1672
|
+
};
|
|
1673
|
+
}
|
|
1674
|
+
/** Pipeline model passed to WorkflowPipeline. */
|
|
1675
|
+
interface PipelineModel {
|
|
1676
|
+
stages: PipelineLane[];
|
|
1677
|
+
fetchBranches: PipelineCard[];
|
|
1678
|
+
}
|
|
1679
|
+
/** Metrics for a step keyed by step ID. */
|
|
1680
|
+
interface StepMetrics7d {
|
|
1681
|
+
[stepId: string]: {
|
|
1682
|
+
runs: number;
|
|
1683
|
+
errors: number;
|
|
1684
|
+
avg_duration_ms?: number;
|
|
1685
|
+
};
|
|
1686
|
+
}
|
|
1687
|
+
/** Workflow palette for the Add Item dialog. */
|
|
1688
|
+
interface WorkflowPalette {
|
|
1689
|
+
svc: Array<{
|
|
1690
|
+
slug: string;
|
|
1691
|
+
name_en: string;
|
|
1692
|
+
name_ar: string;
|
|
1693
|
+
}>;
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
type IconKind = 'lucide' | 'react-icons' | 'boxicons' | 'fallback';
|
|
1697
|
+
interface ResolvedIcon {
|
|
1698
|
+
Component: React$1.ElementType;
|
|
1699
|
+
kind: IconKind;
|
|
1700
|
+
}
|
|
1701
|
+
declare const resolveIcon: (navIcon: string | null | undefined) => ResolvedIcon;
|
|
1702
|
+
|
|
1703
|
+
type StepPath = (number | string)[];
|
|
1704
|
+
type AnyStep = Record<string, any>;
|
|
1705
|
+
interface WorkflowStepNodeProps {
|
|
1706
|
+
step: AnyStep;
|
|
1707
|
+
path: StepPath;
|
|
1708
|
+
depth: number;
|
|
1709
|
+
isRTL: boolean;
|
|
1710
|
+
metrics?: StepMetrics7d;
|
|
1711
|
+
editingPath?: string | null;
|
|
1712
|
+
onEditRequest?: (path: StepPath) => void;
|
|
1713
|
+
onDelete?: (path: StepPath) => void;
|
|
1714
|
+
onMove?: (path: StepPath, dir: -1 | 1) => void;
|
|
1715
|
+
onAdd?: (containerPath: StepPath, kind: string) => void;
|
|
1716
|
+
addableKinds?: string[];
|
|
1717
|
+
renderEditor?: (step: AnyStep, path: StepPath) => React.ReactNode;
|
|
1718
|
+
/** Plain-language mode for non-technical readers (friendly badge + sentence,
|
|
1719
|
+
* no raw SQL/code). Default: true. Pass false for the developer view. */
|
|
1720
|
+
humanize?: boolean;
|
|
1721
|
+
}
|
|
1722
|
+
declare const WorkflowStepNode: {
|
|
1723
|
+
({ step, path, depth, isRTL, metrics, editingPath, onEditRequest, onDelete, onMove, onAdd, addableKinds, renderEditor, humanize, }: WorkflowStepNodeProps): React$1.JSX.Element;
|
|
1724
|
+
displayName: string;
|
|
1725
|
+
};
|
|
1726
|
+
|
|
1727
|
+
declare const PIPELINE_STAGES: {
|
|
1728
|
+
key: string;
|
|
1729
|
+
label_en: string;
|
|
1730
|
+
label_ar: string;
|
|
1731
|
+
}[];
|
|
1732
|
+
interface WorkflowPipelineProps {
|
|
1733
|
+
model: PipelineModel;
|
|
1734
|
+
/** Current UI direction. Default false (LTR). */
|
|
1735
|
+
isRTL?: boolean;
|
|
1736
|
+
}
|
|
1737
|
+
declare const WorkflowPipeline: {
|
|
1738
|
+
({ model, isRTL }: WorkflowPipelineProps): React$1.JSX.Element;
|
|
1739
|
+
displayName: string;
|
|
1740
|
+
};
|
|
1741
|
+
|
|
1742
|
+
interface WorkflowEditorProps {
|
|
1743
|
+
/** Raw JSONB workflow_steps array from the DB. */
|
|
1744
|
+
workflowSteps: WorkflowStep[];
|
|
1745
|
+
/** Raw JSONB sources array from the DB. */
|
|
1746
|
+
workflowSources: WorkflowSource[];
|
|
1747
|
+
/** Plugin slug — used in source credential links. */
|
|
1748
|
+
pluginSlug: string;
|
|
1749
|
+
/** Current UI language. */
|
|
1750
|
+
language: 'en' | 'ar';
|
|
1751
|
+
/** Palette for Add dialog SVC items. */
|
|
1752
|
+
palette?: WorkflowPalette;
|
|
1753
|
+
/**
|
|
1754
|
+
* Called when the operator clicks Save.
|
|
1755
|
+
* Returns a Promise — reject to show an error toast.
|
|
1756
|
+
*/
|
|
1757
|
+
onSave: (steps: WorkflowStep[], sources: WorkflowSource[]) => Promise<void>;
|
|
1758
|
+
}
|
|
1759
|
+
declare const WorkflowEditor: {
|
|
1760
|
+
({ workflowSteps, workflowSources, pluginSlug, language, palette, onSave, }: WorkflowEditorProps): React$1.JSX.Element;
|
|
1761
|
+
displayName: string;
|
|
1762
|
+
};
|
|
1763
|
+
|
|
1764
|
+
interface PluginAppearanceSectionProps {
|
|
1765
|
+
/** Current server state — seeds the form on mount / when changed. */
|
|
1766
|
+
appearance: PluginAppearanceFields;
|
|
1767
|
+
/** Called when the operator saves. Return type intentionally void — host handles async. */
|
|
1768
|
+
onSave: (changed: Partial<PluginAppearanceFields>) => void;
|
|
1769
|
+
/** Whether the host is currently persisting. */
|
|
1770
|
+
isPending?: boolean;
|
|
1771
|
+
/** Whether the last save resulted in an error. */
|
|
1772
|
+
isError?: boolean;
|
|
1773
|
+
errorMessage?: string;
|
|
1774
|
+
/** Current UI language. */
|
|
1775
|
+
language: 'en' | 'ar';
|
|
1776
|
+
}
|
|
1777
|
+
declare const PluginAppearanceSection: {
|
|
1778
|
+
({ appearance, onSave, isPending, isError, errorMessage, language, }: PluginAppearanceSectionProps): React$1.JSX.Element;
|
|
1779
|
+
displayName: string;
|
|
1780
|
+
};
|
|
1781
|
+
|
|
1782
|
+
interface TestRunStep {
|
|
1783
|
+
name: string;
|
|
1784
|
+
status: 'ok' | 'error' | 'skipped' | string;
|
|
1785
|
+
detail?: string;
|
|
1786
|
+
duration_ms?: number;
|
|
1787
|
+
count?: number;
|
|
1788
|
+
error?: string;
|
|
1789
|
+
}
|
|
1790
|
+
interface TestRunSavedItem {
|
|
1791
|
+
title?: string;
|
|
1792
|
+
url?: string;
|
|
1793
|
+
language?: string;
|
|
1794
|
+
content_hash?: string;
|
|
1795
|
+
envelope_id?: string;
|
|
1796
|
+
source_id?: string;
|
|
1797
|
+
region?: string;
|
|
1798
|
+
content_en?: string;
|
|
1799
|
+
content_ar?: string;
|
|
1800
|
+
published_at?: string;
|
|
1801
|
+
raw_payload?: any;
|
|
1802
|
+
}
|
|
1803
|
+
interface TestRunCompletePayload {
|
|
1804
|
+
envelopes_saved: number;
|
|
1805
|
+
saved: TestRunSavedItem[];
|
|
1806
|
+
}
|
|
1807
|
+
/** Callbacks for the SSE stream. */
|
|
1808
|
+
interface TestRunCallbacks {
|
|
1809
|
+
onStep: (step: TestRunStep) => void;
|
|
1810
|
+
onComplete: (payload: TestRunCompletePayload) => void;
|
|
1811
|
+
onError: (err: {
|
|
1812
|
+
error: string;
|
|
1813
|
+
}) => void;
|
|
1814
|
+
}
|
|
1815
|
+
interface TestRunPanelProps {
|
|
1816
|
+
/** Plugin slug — passed to onRunRequest. */
|
|
1817
|
+
slug: string;
|
|
1818
|
+
/** Max envelopes to save. Default 5. */
|
|
1819
|
+
maxEnvelopes?: number;
|
|
1820
|
+
/** If true, panel renders as an inline block rather than a Card. */
|
|
1821
|
+
inline?: boolean;
|
|
1822
|
+
/** Current UI language. */
|
|
1823
|
+
language: 'en' | 'ar';
|
|
1824
|
+
/**
|
|
1825
|
+
* Host-provided SSE runner. Must return an AbortController.
|
|
1826
|
+
* Signature mirrors sourceTestRunSSE from the bridge hooks.
|
|
1827
|
+
*/
|
|
1828
|
+
onRunRequest: (slug: string, maxEnvelopes: number, callbacks: TestRunCallbacks) => AbortController;
|
|
1829
|
+
}
|
|
1830
|
+
declare const TestRunPanel: {
|
|
1831
|
+
({ slug, maxEnvelopes, inline, language, onRunRequest, }: TestRunPanelProps): React$1.JSX.Element;
|
|
1832
|
+
displayName: string;
|
|
1833
|
+
};
|
|
1834
|
+
|
|
1835
|
+
interface PluginDetailIdentity {
|
|
1836
|
+
slug?: string | null;
|
|
1837
|
+
name?: string | null;
|
|
1838
|
+
name_en?: string | null;
|
|
1839
|
+
name_ar?: string | null;
|
|
1840
|
+
description?: string | null;
|
|
1841
|
+
description_en?: string | null;
|
|
1842
|
+
description_ar?: string | null;
|
|
1843
|
+
plugin_type?: string | null;
|
|
1844
|
+
version?: string | null;
|
|
1845
|
+
nav_icon?: string | null;
|
|
1846
|
+
nav_color?: string | null;
|
|
1847
|
+
enabled_globally?: boolean | null;
|
|
1848
|
+
}
|
|
1849
|
+
interface PluginActivitySummary {
|
|
1850
|
+
last_active_at?: string | null;
|
|
1851
|
+
activity_count?: number | null;
|
|
1852
|
+
activity_series?: {
|
|
1853
|
+
n: number;
|
|
1854
|
+
}[];
|
|
1855
|
+
}
|
|
1856
|
+
interface PluginDetailLayoutProps {
|
|
1857
|
+
/** Ordered tab list. */
|
|
1858
|
+
tabs: PluginDetailTab[];
|
|
1859
|
+
/** Currently active tab key. */
|
|
1860
|
+
activeTab: string;
|
|
1861
|
+
/** Called when the operator clicks a tab. */
|
|
1862
|
+
onTabChange: (key: string) => void;
|
|
1863
|
+
/** Content for the active tab. */
|
|
1864
|
+
children: React.ReactNode;
|
|
1865
|
+
/** Plugin identity for the hero. */
|
|
1866
|
+
plugin: PluginDetailIdentity;
|
|
1867
|
+
/** Optional activity data for the sparkline analytics block. */
|
|
1868
|
+
activity?: PluginActivitySummary;
|
|
1869
|
+
/** Whether identity data is still loading. */
|
|
1870
|
+
isLoading?: boolean;
|
|
1871
|
+
/** Whether identity fetch errored. */
|
|
1872
|
+
isError?: boolean;
|
|
1873
|
+
/** Current UI language. */
|
|
1874
|
+
language: 'en' | 'ar';
|
|
1875
|
+
}
|
|
1876
|
+
declare const PluginHeroSkeleton: {
|
|
1877
|
+
(): React$1.JSX.Element;
|
|
1878
|
+
displayName: string;
|
|
1879
|
+
};
|
|
1880
|
+
interface PluginHeroProps {
|
|
1881
|
+
plugin: PluginDetailIdentity;
|
|
1882
|
+
activity?: PluginActivitySummary;
|
|
1883
|
+
isRTL: boolean;
|
|
1884
|
+
}
|
|
1885
|
+
declare const PluginHero: {
|
|
1886
|
+
({ plugin, activity, isRTL }: PluginHeroProps): React$1.JSX.Element;
|
|
1887
|
+
displayName: string;
|
|
1888
|
+
};
|
|
1889
|
+
|
|
1890
|
+
declare const PluginDetailLayout: {
|
|
1891
|
+
({ tabs, activeTab, onTabChange, children, plugin, activity, isLoading, isError, language, }: PluginDetailLayoutProps): React$1.JSX.Element;
|
|
1892
|
+
displayName: string;
|
|
1893
|
+
};
|
|
1894
|
+
|
|
1895
|
+
/**
|
|
1896
|
+
* StepOptionsDialog — a type-specific options modal for a single workflow step.
|
|
1897
|
+
*
|
|
1898
|
+
* The form fields are driven by a registry keyed on the step `kind`, so each step
|
|
1899
|
+
* type shows exactly the settings it needs (schedule, condition, query, prompt,
|
|
1900
|
+
* model, …). Unknown kinds fall back to a raw-JSON editor. Presentational +
|
|
1901
|
+
* bilingual (EN/AR) + token-themed + RTL — pass the step and an onSave callback.
|
|
1902
|
+
*/
|
|
1903
|
+
|
|
1904
|
+
type StepFieldType = 'text' | 'textarea' | 'number' | 'select' | 'switch' | 'lines' | 'csv' | 'json';
|
|
1905
|
+
interface StepFieldDef {
|
|
1906
|
+
key: string;
|
|
1907
|
+
type: StepFieldType;
|
|
1908
|
+
label_en: string;
|
|
1909
|
+
label_ar: string;
|
|
1910
|
+
placeholder?: string;
|
|
1911
|
+
options?: {
|
|
1912
|
+
value: string;
|
|
1913
|
+
label: string;
|
|
1914
|
+
}[];
|
|
1915
|
+
}
|
|
1916
|
+
/** kind → field schema. The most common togo/sentra step kinds are covered; any
|
|
1917
|
+
* other kind falls back to the raw-JSON editor. */
|
|
1918
|
+
declare const STEP_FIELD_REGISTRY: Record<string, StepFieldDef[]>;
|
|
1919
|
+
interface StepOptionsDialogProps {
|
|
1920
|
+
open: boolean;
|
|
1921
|
+
/** The step object being edited (any shape with a `kind`). */
|
|
1922
|
+
step: Record<string, any> | null;
|
|
1923
|
+
language?: 'en' | 'ar';
|
|
1924
|
+
onClose: () => void;
|
|
1925
|
+
/** Called with the FULL updated step object when the operator saves. */
|
|
1926
|
+
onSave: (next: Record<string, any>) => void;
|
|
1927
|
+
}
|
|
1928
|
+
declare function StepOptionsDialog({ open, step, language, onClose, onSave }: StepOptionsDialogProps): React$1.JSX.Element;
|
|
1929
|
+
declare namespace StepOptionsDialog {
|
|
1930
|
+
var displayName: string;
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
/**
|
|
1934
|
+
* NestedStepsEditor — multi-level drag-and-drop editor for a workflow step TREE.
|
|
1935
|
+
*
|
|
1936
|
+
* Steps can be reordered within a branch AND moved across nesting levels
|
|
1937
|
+
* (top-level ↔ an `if`'s then/else ↔ a `for_each`'s loop body). Built on
|
|
1938
|
+
* @dnd-kit with one DndContext + a SortableContext per branch; drag-end resolves
|
|
1939
|
+
* the source/target branch by the dragged item's path and moves it immutably.
|
|
1940
|
+
* A gear button opens the per-step options modal (via onEditStep).
|
|
1941
|
+
*/
|
|
1942
|
+
|
|
1943
|
+
type Step = Record<string, any>;
|
|
1944
|
+
interface NestedStepsEditorProps {
|
|
1945
|
+
steps: Step[];
|
|
1946
|
+
language?: 'en' | 'ar';
|
|
1947
|
+
onChange: (steps: Step[]) => void;
|
|
1948
|
+
onEditStep?: (step: Step) => void;
|
|
1949
|
+
onDeleteStep?: (uid: string) => void;
|
|
1950
|
+
className?: string;
|
|
1951
|
+
}
|
|
1952
|
+
declare function NestedStepsEditor({ steps, language, onChange, onEditStep, onDeleteStep, className, }: NestedStepsEditorProps): React$1.JSX.Element;
|
|
1953
|
+
declare namespace NestedStepsEditor {
|
|
1954
|
+
var displayName: string;
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
type WorkflowView = "steps" | "pipeline" | "editor";
|
|
1958
|
+
interface WorkflowStepLike {
|
|
1959
|
+
kind?: string;
|
|
1960
|
+
then?: WorkflowStepLike[];
|
|
1961
|
+
else?: WorkflowStepLike[];
|
|
1962
|
+
steps?: WorkflowStepLike[];
|
|
1963
|
+
[key: string]: unknown;
|
|
1964
|
+
}
|
|
1965
|
+
interface WorkflowProps {
|
|
1966
|
+
/** The workflow as a nested step tree — the single source of truth for every view. */
|
|
1967
|
+
steps: WorkflowStepLike[];
|
|
1968
|
+
/** Controlled active view. */
|
|
1969
|
+
view?: WorkflowView;
|
|
1970
|
+
/** Initial view when uncontrolled. Default "steps". */
|
|
1971
|
+
defaultView?: WorkflowView;
|
|
1972
|
+
onViewChange?: (view: WorkflowView) => void;
|
|
1973
|
+
language?: "en" | "ar";
|
|
1974
|
+
/** Plain-language step descriptions (default true). */
|
|
1975
|
+
humanize?: boolean;
|
|
1976
|
+
/** Enables the Editor view; called when the editor mutates the tree. */
|
|
1977
|
+
onChange?: (steps: WorkflowStepLike[]) => void;
|
|
1978
|
+
onEditStep?: (step: WorkflowStepLike) => void;
|
|
1979
|
+
className?: string;
|
|
1980
|
+
}
|
|
1981
|
+
/** Workflow — the unified workflow component. One nested-step model rendered three ways,
|
|
1982
|
+
* switchable via the header toggle:
|
|
1983
|
+
* • Steps — human-readable vertical step tree (default)
|
|
1984
|
+
* • Pipeline — the same steps as a horizontal flow
|
|
1985
|
+
* • Editor — multi-level drag-and-drop editor with per-step options (enabled when onChange is set)
|
|
1986
|
+
* Pipeline + Editor are derived from the same `steps`, so all three views show one workflow. */
|
|
1987
|
+
declare function Workflow({ steps, view, defaultView, onViewChange, language, humanize, onChange, onEditStep, className, }: WorkflowProps): React$1.JSX.Element;
|
|
1988
|
+
|
|
1989
|
+
/**
|
|
1990
|
+
* types.ts — LogsView data contract
|
|
1991
|
+
*
|
|
1992
|
+
* Rule 25: product-agnostic seam — no fetching, no app/product imports.
|
|
1993
|
+
* Data arrives entirely as props.
|
|
1994
|
+
*/
|
|
1995
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
1996
|
+
interface ServiceLogRow {
|
|
1997
|
+
id: string;
|
|
1998
|
+
/** ISO 8601 timestamp */
|
|
1999
|
+
ts: string;
|
|
2000
|
+
level: LogLevel;
|
|
2001
|
+
/** e.g. 'axon', 'scout-collector', 'firecrawl' */
|
|
2002
|
+
service: string;
|
|
2003
|
+
/** optional subsystem label */
|
|
2004
|
+
component?: string;
|
|
2005
|
+
msg: string;
|
|
2006
|
+
traceId?: string;
|
|
2007
|
+
requestId?: string;
|
|
2008
|
+
userId?: string;
|
|
2009
|
+
/** arbitrary structured metadata */
|
|
2010
|
+
attrs?: Record<string, unknown>;
|
|
2011
|
+
}
|
|
2012
|
+
interface LogsFilter {
|
|
2013
|
+
/** multiselect level filter — empty / undefined = all levels */
|
|
2014
|
+
levels?: string[];
|
|
2015
|
+
service?: string;
|
|
2016
|
+
component?: string;
|
|
2017
|
+
/** ISO date-time lower bound */
|
|
2018
|
+
since?: string;
|
|
2019
|
+
/** ISO date-time upper bound */
|
|
2020
|
+
until?: string;
|
|
2021
|
+
/** full-text search on msg */
|
|
2022
|
+
q?: string;
|
|
2023
|
+
}
|
|
2024
|
+
interface LogsViewProps {
|
|
2025
|
+
logs: ServiceLogRow[];
|
|
2026
|
+
filters: LogsFilter;
|
|
2027
|
+
onFilterChange: (f: LogsFilter) => void;
|
|
2028
|
+
/** EN or AR — drives all chrome labels and RTL direction */
|
|
2029
|
+
language: 'en' | 'ar';
|
|
2030
|
+
loading?: boolean;
|
|
2031
|
+
/** called when the user reaches the bottom / clicks "load more" */
|
|
2032
|
+
onLoadMore?: () => void;
|
|
2033
|
+
hasMore?: boolean;
|
|
2034
|
+
/** options to populate the service dropdown */
|
|
2035
|
+
services?: string[];
|
|
2036
|
+
/** options to populate the component dropdown */
|
|
2037
|
+
components?: string[];
|
|
2038
|
+
/** whether live-tail polling is active */
|
|
2039
|
+
liveTail?: boolean;
|
|
2040
|
+
onToggleLiveTail?: (on: boolean) => void;
|
|
2041
|
+
className?: string;
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
/**
|
|
2045
|
+
* LogsView — presentational per-product log viewer
|
|
2046
|
+
*
|
|
2047
|
+
* Rule 25: purely presentational; NO data fetching, NO context reads,
|
|
2048
|
+
* NO product-specific imports. All data arrives as props.
|
|
2049
|
+
* Rule 16: semantic tokens only (no hex), logical CSS properties (ms/me/ps/pe).
|
|
2050
|
+
* Rule 8: all chrome strings bilingual via `language` prop.
|
|
2051
|
+
* Rule 7: displayName set; event handlers prefixed `handle*`.
|
|
2052
|
+
*/
|
|
2053
|
+
|
|
2054
|
+
declare const LogsView: {
|
|
2055
|
+
({ logs, filters, onFilterChange, language, loading, onLoadMore, hasMore, services, components, liveTail, onToggleLiveTail, className, }: LogsViewProps): React__default.JSX.Element;
|
|
2056
|
+
displayName: string;
|
|
2057
|
+
};
|
|
2058
|
+
|
|
2059
|
+
/**
|
|
2060
|
+
* Error-tracking data contract (Sentry-style). Product-agnostic: every component
|
|
2061
|
+
* is presentational — data arrives via props, no fetching, no app imports.
|
|
2062
|
+
*/
|
|
2063
|
+
type IssueLevel = "fatal" | "error" | "warning" | "info" | "debug";
|
|
2064
|
+
interface StackFrameContextLine {
|
|
2065
|
+
line: number;
|
|
2066
|
+
text: string;
|
|
2067
|
+
/** the line where the error occurred */
|
|
2068
|
+
current?: boolean;
|
|
2069
|
+
}
|
|
2070
|
+
interface StackFrame {
|
|
2071
|
+
filename: string;
|
|
2072
|
+
function?: string;
|
|
2073
|
+
lineno?: number;
|
|
2074
|
+
colno?: number;
|
|
2075
|
+
/** true = application frame (vs. node_modules / framework) */
|
|
2076
|
+
inApp?: boolean;
|
|
2077
|
+
/** optional source context around the frame */
|
|
2078
|
+
context?: StackFrameContextLine[];
|
|
2079
|
+
}
|
|
2080
|
+
interface IssueBreadcrumb {
|
|
2081
|
+
/** ISO 8601 */
|
|
2082
|
+
timestamp: string;
|
|
2083
|
+
type?: "navigation" | "http" | "ui" | "log" | "error" | "info";
|
|
2084
|
+
category?: string;
|
|
2085
|
+
message: string;
|
|
2086
|
+
level?: IssueLevel;
|
|
2087
|
+
}
|
|
2088
|
+
interface IssueTag {
|
|
2089
|
+
key: string;
|
|
2090
|
+
value: string;
|
|
2091
|
+
}
|
|
2092
|
+
interface IssueAssignee {
|
|
2093
|
+
name?: string;
|
|
2094
|
+
email?: string;
|
|
2095
|
+
avatarUrl?: string;
|
|
2096
|
+
}
|
|
2097
|
+
interface Issue$1 {
|
|
2098
|
+
id: string;
|
|
2099
|
+
/** e.g. "TypeError: Cannot read properties of undefined (reading 'id')" */
|
|
2100
|
+
title: string;
|
|
2101
|
+
/** where it happened, e.g. "app/checkout/page.tsx in handleSubmit" */
|
|
2102
|
+
culprit?: string;
|
|
2103
|
+
level: IssueLevel;
|
|
2104
|
+
/** total events (occurrences) */
|
|
2105
|
+
count: number;
|
|
2106
|
+
/** distinct users affected */
|
|
2107
|
+
userCount?: number;
|
|
2108
|
+
/** ISO 8601 */
|
|
2109
|
+
firstSeen: string;
|
|
2110
|
+
lastSeen: string;
|
|
2111
|
+
status?: "unresolved" | "resolved" | "ignored";
|
|
2112
|
+
assignee?: IssueAssignee;
|
|
2113
|
+
environment?: string;
|
|
2114
|
+
project?: string;
|
|
2115
|
+
/** events-over-time buckets for the row sparkline / detail chart */
|
|
2116
|
+
frequency?: number[];
|
|
2117
|
+
stack?: StackFrame[];
|
|
2118
|
+
breadcrumbs?: IssueBreadcrumb[];
|
|
2119
|
+
tags?: IssueTag[];
|
|
2120
|
+
}
|
|
2121
|
+
interface ErrorFilter {
|
|
2122
|
+
/** empty/undefined = all levels */
|
|
2123
|
+
levels?: IssueLevel[];
|
|
2124
|
+
environment?: string;
|
|
2125
|
+
/** ISO lower bound (or a relative key the app resolves) */
|
|
2126
|
+
range?: string;
|
|
2127
|
+
status?: Issue$1["status"];
|
|
2128
|
+
/** full-text search on title/culprit */
|
|
2129
|
+
q?: string;
|
|
2130
|
+
}
|
|
2131
|
+
type IssueSort = "lastSeen" | "firstSeen" | "count" | "userCount";
|
|
2132
|
+
|
|
2133
|
+
type Lang = "en" | "ar";
|
|
2134
|
+
/** Map a Sentry-style level to a StatusBadge tone. */
|
|
2135
|
+
declare function levelTone(level: IssueLevel): "danger" | "warning" | "info" | "neutral";
|
|
2136
|
+
|
|
2137
|
+
interface IssuesListProps {
|
|
2138
|
+
issues: Issue$1[];
|
|
2139
|
+
selectedId?: string | null;
|
|
2140
|
+
onSelectIssue?: (issue: Issue$1) => void;
|
|
2141
|
+
language?: Lang;
|
|
2142
|
+
filter?: ErrorFilter;
|
|
2143
|
+
onFilterChange?: (f: ErrorFilter) => void;
|
|
2144
|
+
sort?: IssueSort;
|
|
2145
|
+
onSortChange?: (s: IssueSort) => void;
|
|
2146
|
+
/** options for the environment dropdown */
|
|
2147
|
+
environments?: string[];
|
|
2148
|
+
className?: string;
|
|
2149
|
+
}
|
|
2150
|
+
/** IssuesList — the Sentry-style "Issues" view: a filter bar + a list of error
|
|
2151
|
+
* groups (level, title + culprit, frequency sparkline, events, users, assignee,
|
|
2152
|
+
* last-seen). Presentational; row click → onSelectIssue. RTL + bilingual. */
|
|
2153
|
+
declare function IssuesList({ issues, selectedId, onSelectIssue, language, filter, onFilterChange, sort, onSortChange, environments, className, }: IssuesListProps): React$1.JSX.Element;
|
|
2154
|
+
|
|
2155
|
+
interface IssueDetailProps {
|
|
2156
|
+
issue: Issue$1;
|
|
2157
|
+
language?: Lang;
|
|
2158
|
+
onResolve?: (issue: Issue$1) => void;
|
|
2159
|
+
onIgnore?: (issue: Issue$1) => void;
|
|
2160
|
+
className?: string;
|
|
2161
|
+
}
|
|
2162
|
+
/** IssueDetail — the error detail pane: title + culprit, level, resolve/ignore,
|
|
2163
|
+
* stats, a frequency chart, then tabbed Stack trace / Breadcrumbs / Tags. */
|
|
2164
|
+
declare function IssueDetail({ issue, language, onResolve, onIgnore, className }: IssueDetailProps): React$1.JSX.Element;
|
|
2165
|
+
|
|
2166
|
+
interface ErrorTrackingPageProps {
|
|
2167
|
+
issues: Issue$1[];
|
|
2168
|
+
language?: Lang;
|
|
2169
|
+
filter?: ErrorFilter;
|
|
2170
|
+
onFilterChange?: (f: ErrorFilter) => void;
|
|
2171
|
+
sort?: IssueSort;
|
|
2172
|
+
onSortChange?: (s: IssueSort) => void;
|
|
2173
|
+
environments?: string[];
|
|
2174
|
+
onResolve?: (issue: Issue$1) => void;
|
|
2175
|
+
onIgnore?: (issue: Issue$1) => void;
|
|
2176
|
+
/** controlled selection (optional) */
|
|
2177
|
+
selectedId?: string | null;
|
|
2178
|
+
onSelectIssue?: (issue: Issue$1) => void;
|
|
2179
|
+
className?: string;
|
|
2180
|
+
}
|
|
2181
|
+
/** ErrorTrackingPage — the Sentry-style master/detail error page: IssuesList on
|
|
2182
|
+
* the start side, IssueDetail on the end side. Responsive: split on desktop,
|
|
2183
|
+
* list→detail drill-down on mobile. Uncontrolled selection unless `selectedId`
|
|
2184
|
+
* is provided. */
|
|
2185
|
+
declare function ErrorTrackingPage({ issues, language, filter, onFilterChange, sort, onSortChange, environments, onResolve, onIgnore, selectedId, onSelectIssue, className, }: ErrorTrackingPageProps): React$1.JSX.Element;
|
|
2186
|
+
|
|
2187
|
+
interface SentraLoadingProps {
|
|
2188
|
+
language?: 'en' | 'ar';
|
|
2189
|
+
dir?: 'ltr' | 'rtl';
|
|
2190
|
+
/** Lucide icon name from the branding icon picker — the platform brand icon. */
|
|
2191
|
+
iconName?: string | null;
|
|
2192
|
+
/**
|
|
2193
|
+
* Platform title pair from Fort branding. The component resolves the active
|
|
2194
|
+
* language itself so every product gets the translated title for free.
|
|
2195
|
+
*/
|
|
2196
|
+
productNameEn?: string | null;
|
|
2197
|
+
productNameAr?: string | null;
|
|
2198
|
+
/** Pre-resolved title override — wins over the En/Ar pair when set. */
|
|
2199
|
+
productName?: string;
|
|
2200
|
+
}
|
|
2201
|
+
declare const SentraLoading: {
|
|
2202
|
+
({ language, dir, iconName, productNameEn, productNameAr, productName, }: SentraLoadingProps): React$1.JSX.Element;
|
|
2203
|
+
displayName: string;
|
|
2204
|
+
};
|
|
2205
|
+
|
|
2206
|
+
/**
|
|
2207
|
+
* ContextualSkeleton — a loading skeleton with a contextual header (spinner +
|
|
2208
|
+
* a bilingual "loading X…" caption) and one of three body shapes: default
|
|
2209
|
+
* (text lines), grid (cards), or timeline (dot + lines rows).
|
|
2210
|
+
*
|
|
2211
|
+
* Pure & product-agnostic (Rule 25): `language` is a prop, no context. Distinct
|
|
2212
|
+
* from SectionSkeleton (which is a single card-shaped block) — this one carries
|
|
2213
|
+
* a caption + variant body for richer loading states.
|
|
2214
|
+
*
|
|
2215
|
+
* Ported from app/src/components/loading/ContextualSkeleton.tsx.
|
|
2216
|
+
*/
|
|
2217
|
+
|
|
2218
|
+
type ContextualSkeletonVariant = 'default' | 'grid' | 'timeline';
|
|
2219
|
+
interface ContextualSkeletonProps {
|
|
2220
|
+
/** Bilingual caption shown next to the spinner, e.g. {en:'Loading alerts…', ar:'…'} */
|
|
2221
|
+
description: {
|
|
2222
|
+
en: string;
|
|
2223
|
+
ar: string;
|
|
2224
|
+
};
|
|
2225
|
+
variant?: ContextualSkeletonVariant;
|
|
2226
|
+
/** Number of text lines for the 'default' variant. Default: 3. */
|
|
2227
|
+
lines?: number;
|
|
2228
|
+
language?: 'en' | 'ar';
|
|
2229
|
+
/**
|
|
2230
|
+
* Optional icon (LucideIcon component) rendered before the caption.
|
|
2231
|
+
* Accepted for API parity with hub callers — visually ignored (spinner
|
|
2232
|
+
* already serves as the loading indicator). Pass it to keep TS happy when
|
|
2233
|
+
* migrating from the old hub ContextualSkeleton.
|
|
2234
|
+
*/
|
|
2235
|
+
icon?: React$1.ComponentType<{
|
|
2236
|
+
className?: string;
|
|
2237
|
+
}>;
|
|
2238
|
+
/**
|
|
2239
|
+
* Bilingual title shown above the skeleton body. Optional — omitted if not provided.
|
|
2240
|
+
*/
|
|
2241
|
+
title?: {
|
|
2242
|
+
en: string;
|
|
2243
|
+
ar: string;
|
|
2244
|
+
};
|
|
2245
|
+
}
|
|
2246
|
+
declare const ContextualSkeleton: {
|
|
2247
|
+
({ description, variant, lines, language, }: ContextualSkeletonProps): React$1.JSX.Element;
|
|
2248
|
+
displayName: string;
|
|
2249
|
+
};
|
|
2250
|
+
|
|
2251
|
+
interface SectionSkeletonProps {
|
|
2252
|
+
title?: string;
|
|
2253
|
+
rows?: number;
|
|
2254
|
+
}
|
|
2255
|
+
declare const SectionSkeleton: {
|
|
2256
|
+
({ title, rows }: SectionSkeletonProps): React$1.JSX.Element;
|
|
2257
|
+
displayName: string;
|
|
2258
|
+
};
|
|
2259
|
+
|
|
2260
|
+
/**
|
|
2261
|
+
* @prism/ui — shared i18next initialisation
|
|
2262
|
+
*
|
|
2263
|
+
* Called once by LanguageProvider. Safe to call multiple times (idempotent via
|
|
2264
|
+
* `i18n.isInitialized` guard). Defaults to EN so every app boots with zero
|
|
2265
|
+
* Arabic strings until the provider explicitly switches to AR.
|
|
2266
|
+
*
|
|
2267
|
+
* Consumers: import `i18n` from here if direct access is needed; prefer the
|
|
2268
|
+
* `useT()` / `useLanguage()` hooks for component-level translation.
|
|
2269
|
+
*
|
|
2270
|
+
* Rules: Rule 8 (bilingual EN/AR), Rule 16 (Sentra style — client component).
|
|
2271
|
+
*/
|
|
2272
|
+
|
|
2273
|
+
declare const SUPPORTED_LANGUAGES: readonly ["en", "ar"];
|
|
2274
|
+
type SupportedLanguage = (typeof SUPPORTED_LANGUAGES)[number];
|
|
2275
|
+
|
|
2276
|
+
interface LanguageContextValue {
|
|
2277
|
+
/** Current locale — 'en' | 'ar' */
|
|
2278
|
+
language: SupportedLanguage;
|
|
2279
|
+
/** Alias used by components ported from the legacy Sentra app */
|
|
2280
|
+
lang: SupportedLanguage;
|
|
2281
|
+
/** true when language === 'ar' */
|
|
2282
|
+
isRTL: boolean;
|
|
2283
|
+
/** Switch language. Updates i18next, document.documentElement dir/lang,
|
|
2284
|
+
* caches the choice to localStorage, and calls onLanguageChange. */
|
|
2285
|
+
setLanguage: (l: SupportedLanguage) => void;
|
|
2286
|
+
/**
|
|
2287
|
+
* Seed the language from the Fort profile AFTER login — but ONLY when the user
|
|
2288
|
+
* has no cached choice yet. The cached selection (the user's explicit toggle)
|
|
2289
|
+
* always wins over profile.lang on reload. Use this instead of setLanguage()
|
|
2290
|
+
* for the post-login profile seed so it doesn't clobber a cached preference.
|
|
2291
|
+
*/
|
|
2292
|
+
seedLanguage: (l: SupportedLanguage) => void;
|
|
2293
|
+
/**
|
|
2294
|
+
* i18next `t()` bound to the current language.
|
|
2295
|
+
* Key format: `"namespace:key"` or just `"key"` (uses defaultNS = 'common').
|
|
2296
|
+
* Supports interpolation: `t('header:updated', { time: '5 min ago' })`.
|
|
2297
|
+
*/
|
|
2298
|
+
t: (key: string, vars?: Record<string, unknown>) => string;
|
|
2299
|
+
}
|
|
2300
|
+
interface LanguageProviderProps {
|
|
2301
|
+
children: ReactNode;
|
|
2302
|
+
/**
|
|
2303
|
+
* Seed language. Defaults to 'en'.
|
|
2304
|
+
* Pass `initialLanguage={profile.lang}` post-login to hydrate from Fort
|
|
2305
|
+
* profile without a flicker (SSR already sets the cookie; the provider
|
|
2306
|
+
* syncs immediately).
|
|
2307
|
+
*/
|
|
2308
|
+
initialLanguage?: SupportedLanguage;
|
|
2309
|
+
/**
|
|
2310
|
+
* Called whenever the user switches language (or on first mount if
|
|
2311
|
+
* initialLanguage differs from the stored preference). Products wire this
|
|
2312
|
+
* to `FortProfileClient.patchProfile({ lang })` to persist the choice.
|
|
2313
|
+
*/
|
|
2314
|
+
onLanguageChange?: (lang: SupportedLanguage) => void;
|
|
2315
|
+
}
|
|
2316
|
+
/** Cookie name must be colon-free (RFC 6265). Mirrors LANG_STORAGE_KEY. */
|
|
2317
|
+
declare const LANG_COOKIE_NAME = "sentra_lang";
|
|
2318
|
+
declare const LanguageProvider: {
|
|
2319
|
+
({ children, initialLanguage, onLanguageChange, }: LanguageProviderProps): React$1.JSX.Element;
|
|
2320
|
+
displayName: string;
|
|
2321
|
+
};
|
|
2322
|
+
|
|
2323
|
+
/**
|
|
2324
|
+
* useT — primary hook. Returns `{ t, language, setLanguage, isRTL }`.
|
|
2325
|
+
* Must be used inside a <LanguageProvider>.
|
|
2326
|
+
*/
|
|
2327
|
+
declare const useT: () => LanguageContextValue;
|
|
2328
|
+
/**
|
|
2329
|
+
* useLanguage — alias for useT. Preferred by components that only need
|
|
2330
|
+
* `language` / `setLanguage` and don't call `t()`.
|
|
2331
|
+
*/
|
|
2332
|
+
declare const useLanguage: () => LanguageContextValue;
|
|
2333
|
+
|
|
2334
|
+
/**
|
|
2335
|
+
* A2UI artifact types — client-side mirror of cortex/internal/copilot/sse.go A2UIArtifact.
|
|
2336
|
+
*
|
|
2337
|
+
* Wire contract (version 1, additive):
|
|
2338
|
+
* {"type":"artifact","artifact":{"version":1,"kind":"table|chart|card|actions|markdown",
|
|
2339
|
+
* "title_en":"...","title_ar":"...","data":{...}}}
|
|
2340
|
+
*
|
|
2341
|
+
* Rule 8: bilingual — both title_en and title_ar carried; renderer picks by language prop.
|
|
2342
|
+
* Rule 25: product-agnostic — no fetching, no context reads, pure typed shapes.
|
|
2343
|
+
*
|
|
2344
|
+
* Adding a new kind: add its data type here, add a case in ArtifactRenderer.tsx.
|
|
2345
|
+
* The unknown-kind fallback in ArtifactRenderer renders a labeled JSON <details> block —
|
|
2346
|
+
* forward-compatible for future kinds without a consumer upgrade.
|
|
2347
|
+
*/
|
|
2348
|
+
/** A column descriptor in an A2UI table artifact. */
|
|
2349
|
+
interface A2UITableColumn {
|
|
2350
|
+
/** Stable accessor key — matches the property names in each row object. */
|
|
2351
|
+
key: string;
|
|
2352
|
+
/** English column header. */
|
|
2353
|
+
label_en: string;
|
|
2354
|
+
/** Arabic column header (optional; falls back to label_en). */
|
|
2355
|
+
label_ar?: string;
|
|
2356
|
+
}
|
|
2357
|
+
/**
|
|
2358
|
+
* Data payload for kind: "table". Two wire shapes are accepted (ArtifactTable
|
|
2359
|
+
* normalizes both):
|
|
2360
|
+
* - SIMPLE (what the model emits): columns: string[], rows: unknown[][]
|
|
2361
|
+
* - RICH: columns: A2UITableColumn[], rows: Array<Record<string, unknown>>
|
|
2362
|
+
*/
|
|
2363
|
+
interface A2UITableData {
|
|
2364
|
+
columns: Array<string | A2UITableColumn>;
|
|
2365
|
+
rows: Array<Record<string, unknown> | unknown[]>;
|
|
2366
|
+
}
|
|
2367
|
+
/** One data series in an A2UI chart. */
|
|
2368
|
+
interface A2UIChartSeries {
|
|
2369
|
+
label_en: string;
|
|
2370
|
+
label_ar?: string;
|
|
2371
|
+
points: Array<{
|
|
2372
|
+
x: string | number;
|
|
2373
|
+
y: number;
|
|
2374
|
+
}>;
|
|
2375
|
+
}
|
|
2376
|
+
/** Data payload for kind: "chart". */
|
|
2377
|
+
interface A2UIChartData {
|
|
2378
|
+
type: 'bar' | 'line' | 'pie';
|
|
2379
|
+
series: A2UIChartSeries[];
|
|
2380
|
+
}
|
|
2381
|
+
/** One field row in an A2UI card. */
|
|
2382
|
+
interface A2UICardField {
|
|
2383
|
+
label: string;
|
|
2384
|
+
value: string | number;
|
|
2385
|
+
}
|
|
2386
|
+
/** Tone for a card metric tile — drives its color coding. */
|
|
2387
|
+
type A2UICardTone = 'positive' | 'negative' | 'neutral';
|
|
2388
|
+
/** A named icon for a metric tile (resolved to a lucide icon by the renderer). */
|
|
2389
|
+
type A2UICardIcon = 'trend' | 'users' | 'clock' | 'source' | 'shield' | 'chart' | 'alert' | 'check' | 'globe';
|
|
2390
|
+
/** One metric tile in the rich card grid. */
|
|
2391
|
+
interface A2UICardMetric {
|
|
2392
|
+
label_en: string;
|
|
2393
|
+
label_ar?: string;
|
|
2394
|
+
value: string | number;
|
|
2395
|
+
/** positive → green, negative → red, neutral → muted. Default neutral. */
|
|
2396
|
+
tone?: A2UICardTone;
|
|
2397
|
+
icon?: A2UICardIcon;
|
|
2398
|
+
/** Optional tiny sparkline values for the tile. */
|
|
2399
|
+
trend?: number[];
|
|
2400
|
+
}
|
|
2401
|
+
/**
|
|
2402
|
+
* Data payload for kind: "card".
|
|
2403
|
+
*
|
|
2404
|
+
* Two shapes are supported:
|
|
2405
|
+
* - Simple: body_en/ar + fields (key/value rows).
|
|
2406
|
+
* - Rich (intelligence card): summary_en/ar headline + a 2-col grid of metric
|
|
2407
|
+
* tiles + a related-items list + a footer recommendation. The renderer prefers
|
|
2408
|
+
* the rich shape when `metrics`/`summary` are present, else falls back to body.
|
|
2409
|
+
*/
|
|
2410
|
+
interface A2UICardData {
|
|
2411
|
+
title_en?: string;
|
|
2412
|
+
title_ar?: string;
|
|
2413
|
+
body_en?: string;
|
|
2414
|
+
body_ar?: string;
|
|
2415
|
+
/** Headline finding sentence (rich card). */
|
|
2416
|
+
summary_en?: string;
|
|
2417
|
+
summary_ar?: string;
|
|
2418
|
+
/** Severity level — maps to SeverityChip tokens when provided. */
|
|
2419
|
+
severity?: 'critical' | 'high' | 'medium' | 'low';
|
|
2420
|
+
/** Key/value detail rows rendered below the body (simple shape). */
|
|
2421
|
+
fields?: A2UICardField[];
|
|
2422
|
+
/** Metric tiles rendered as a 2-column grid (rich shape). */
|
|
2423
|
+
metrics?: A2UICardMetric[];
|
|
2424
|
+
/** Related items list (rich shape). */
|
|
2425
|
+
related_en?: string[];
|
|
2426
|
+
related_ar?: string[];
|
|
2427
|
+
/** Footer recommendation / note (rich shape). */
|
|
2428
|
+
footer_en?: string;
|
|
2429
|
+
footer_ar?: string;
|
|
2430
|
+
}
|
|
2431
|
+
/** One action item in an A2UI actions artifact. */
|
|
2432
|
+
interface A2UIActionItem {
|
|
2433
|
+
id: string;
|
|
2434
|
+
label_en: string;
|
|
2435
|
+
label_ar?: string;
|
|
2436
|
+
/**
|
|
2437
|
+
* When provided, clicking this action sends the prompt as a new user message
|
|
2438
|
+
* via the onAction callback. Use this to pre-fill follow-up questions.
|
|
2439
|
+
*/
|
|
2440
|
+
prompt?: string;
|
|
2441
|
+
}
|
|
2442
|
+
/** Data payload for kind: "actions". */
|
|
2443
|
+
interface A2UIActionsData {
|
|
2444
|
+
items: A2UIActionItem[];
|
|
2445
|
+
}
|
|
2446
|
+
/** Data payload for kind: "markdown". */
|
|
2447
|
+
interface A2UIMarkdownData {
|
|
2448
|
+
content: string;
|
|
2449
|
+
}
|
|
2450
|
+
/** One candidate client returned by the discovery tool. */
|
|
2451
|
+
interface A2UIClientCandidate {
|
|
2452
|
+
name: string;
|
|
2453
|
+
website_url?: string;
|
|
2454
|
+
sector?: string;
|
|
2455
|
+
summary?: string;
|
|
2456
|
+
}
|
|
2457
|
+
/**
|
|
2458
|
+
* Data payload for kind: "client_candidates".
|
|
2459
|
+
* Renders a list of candidate clients the user can pick from.
|
|
2460
|
+
*/
|
|
2461
|
+
interface A2UIClientCandidatesData {
|
|
2462
|
+
candidates: A2UIClientCandidate[];
|
|
2463
|
+
/** Optional prompt shown above the list (instruction / clarification). */
|
|
2464
|
+
prompt?: string;
|
|
2465
|
+
}
|
|
2466
|
+
/** One field entry in a client field picker. */
|
|
2467
|
+
interface A2UIClientField {
|
|
2468
|
+
/** Stable field key (maps to the DB column / API field name). */
|
|
2469
|
+
key: string;
|
|
2470
|
+
/** English label. */
|
|
2471
|
+
label_en: string;
|
|
2472
|
+
/** Arabic label (optional; falls back to label_en). */
|
|
2473
|
+
label_ar?: string;
|
|
2474
|
+
/** Current stored value (may be empty/absent). */
|
|
2475
|
+
current?: string;
|
|
2476
|
+
/** AI-suggested value for this field. */
|
|
2477
|
+
suggested?: string;
|
|
2478
|
+
}
|
|
2479
|
+
/**
|
|
2480
|
+
* Data payload for kind: "client_field_picker".
|
|
2481
|
+
* Lets the user select which fields to fill / confirm before saving.
|
|
2482
|
+
*/
|
|
2483
|
+
interface A2UIClientFieldPickerData {
|
|
2484
|
+
fields: A2UIClientField[];
|
|
2485
|
+
}
|
|
2486
|
+
/** One diff row in a client save confirmation. */
|
|
2487
|
+
interface A2UIClientDiffRow {
|
|
2488
|
+
/** Stable field key. */
|
|
2489
|
+
field: string;
|
|
2490
|
+
/** English label. */
|
|
2491
|
+
label_en: string;
|
|
2492
|
+
/** Arabic label (optional). */
|
|
2493
|
+
label_ar?: string;
|
|
2494
|
+
/** Current stored value (absent = field is new). */
|
|
2495
|
+
old?: string;
|
|
2496
|
+
/** New / proposed value. */
|
|
2497
|
+
new: string;
|
|
2498
|
+
}
|
|
2499
|
+
/**
|
|
2500
|
+
* Data payload for kind: "client_diff_confirm".
|
|
2501
|
+
* Shows a before/after diff the user must confirm before the save is committed.
|
|
2502
|
+
*/
|
|
2503
|
+
interface A2UIClientDiffConfirmData {
|
|
2504
|
+
/** Dialog title in English. */
|
|
2505
|
+
title_en: string;
|
|
2506
|
+
/** Dialog title in Arabic (optional). */
|
|
2507
|
+
title_ar?: string;
|
|
2508
|
+
rows: A2UIClientDiffRow[];
|
|
2509
|
+
/** Confirm button label in English. */
|
|
2510
|
+
confirm_label_en: string;
|
|
2511
|
+
/** Confirm button label in Arabic (optional). */
|
|
2512
|
+
confirm_label_ar?: string;
|
|
2513
|
+
}
|
|
2514
|
+
/** One opening question / starter for a persona chat. */
|
|
2515
|
+
interface A2UIPersonaStarter {
|
|
2516
|
+
/** English chip label. */
|
|
2517
|
+
label_en: string;
|
|
2518
|
+
/** Arabic chip label (optional; falls back to label_en). */
|
|
2519
|
+
label_ar?: string;
|
|
2520
|
+
/** The prompt sent to the copilot when the user clicks this chip. */
|
|
2521
|
+
prompt: string;
|
|
2522
|
+
}
|
|
2523
|
+
/**
|
|
2524
|
+
* Data payload for kind: "persona_starters".
|
|
2525
|
+
* Renders suggested opening questions that launch a persona conversation.
|
|
2526
|
+
*/
|
|
2527
|
+
interface A2UIPersonaStartersData {
|
|
2528
|
+
starters: A2UIPersonaStarter[];
|
|
2529
|
+
}
|
|
2530
|
+
/**
|
|
2531
|
+
* ArtifactInteraction — a structured post-back emitted by interactive artifact
|
|
2532
|
+
* renderers when the user makes a selection or confirms an action.
|
|
2533
|
+
*
|
|
2534
|
+
* Sent from the renderer → ArtifactRenderer → UnifiedCopilotDock →
|
|
2535
|
+
* CopilotProvider.handleArtifactInteract → CopilotRequest.interaction.
|
|
2536
|
+
*
|
|
2537
|
+
* Kind strings used by the four Phase-3 renderers:
|
|
2538
|
+
* "select_candidate" — user picked a client candidate
|
|
2539
|
+
* "pick_fields" — user selected fields to fill/update
|
|
2540
|
+
* "confirm_diff" — user confirmed (or cancelled) a before/after diff save
|
|
2541
|
+
* "persona_start" — user clicked a persona opening prompt chip
|
|
2542
|
+
*
|
|
2543
|
+
* The type is open (string) so future renderers can extend without a breaking
|
|
2544
|
+
* change; consumers should handle unknown kinds defensively.
|
|
2545
|
+
*/
|
|
2546
|
+
interface ArtifactInteraction {
|
|
2547
|
+
kind: 'select_candidate' | 'pick_fields' | 'confirm_diff' | 'persona_start' | string;
|
|
2548
|
+
payload: Record<string, unknown>;
|
|
2549
|
+
}
|
|
2550
|
+
type A2UIKind = 'table' | 'chart' | 'card' | 'actions' | 'markdown' | 'client_candidates' | 'client_field_picker' | 'client_diff_confirm' | 'persona_starters';
|
|
2551
|
+
/**
|
|
2552
|
+
* A2UIArtifact — the versioned structured artifact the Cortex copilot stream emits.
|
|
2553
|
+
*
|
|
2554
|
+
* Mirrors internal/copilot/sse.go A2UIArtifact (version 1).
|
|
2555
|
+
*
|
|
2556
|
+
* `kind` is the rendering discriminator. Renderers pattern-match on it.
|
|
2557
|
+
* Unknown kinds are forwarded to the fallback renderer — never crash.
|
|
2558
|
+
*
|
|
2559
|
+
* `data` is typed per kind. Consumers narrow via `artifact.kind`:
|
|
2560
|
+
*
|
|
2561
|
+
* ```ts
|
|
2562
|
+
* if (artifact.kind === 'table') {
|
|
2563
|
+
* const d = artifact.data as A2UITableData
|
|
2564
|
+
* }
|
|
2565
|
+
* ```
|
|
2566
|
+
*/
|
|
2567
|
+
interface A2UIArtifact$1 {
|
|
2568
|
+
/** Schema version. Currently 1. */
|
|
2569
|
+
version: number;
|
|
2570
|
+
/** Rendering hint: "table" | "chart" | "card" | "actions" | "markdown" | unknown future kinds. */
|
|
2571
|
+
kind: string;
|
|
2572
|
+
/** Display title in English. */
|
|
2573
|
+
title_en?: string;
|
|
2574
|
+
/** Display title in Arabic. Fallback to title_en when absent. */
|
|
2575
|
+
title_ar?: string;
|
|
2576
|
+
/**
|
|
2577
|
+
* Kind-specific payload. Cast to the matching A2UI*Data type after narrowing kind.
|
|
2578
|
+
* Use `unknown` to stay forward-compatible with future kinds.
|
|
2579
|
+
*/
|
|
2580
|
+
data: unknown;
|
|
2581
|
+
}
|
|
2582
|
+
|
|
2583
|
+
interface ArtifactRendererProps {
|
|
2584
|
+
artifact: A2UIArtifact$1;
|
|
2585
|
+
/** Fired when the user clicks an "actions" chip — sends item.prompt as a text message. */
|
|
2586
|
+
onAction?: (item: A2UIActionItem) => void;
|
|
2587
|
+
/**
|
|
2588
|
+
* Fired when an interactive artifact (client_candidates, client_field_picker,
|
|
2589
|
+
* client_diff_confirm, persona_starters) posts a structured interaction.
|
|
2590
|
+
* CopilotProvider wires this to handleArtifactInteract which forwards the
|
|
2591
|
+
* interaction to the dispatch request and suppresses the user bubble.
|
|
2592
|
+
*/
|
|
2593
|
+
onInteract?: (interaction: ArtifactInteraction) => void;
|
|
2594
|
+
language?: 'en' | 'ar';
|
|
2595
|
+
dir?: 'ltr' | 'rtl';
|
|
2596
|
+
}
|
|
2597
|
+
declare const ArtifactRenderer: {
|
|
2598
|
+
({ artifact, onAction, onInteract, language, dir, }: ArtifactRendererProps): React$1.JSX.Element;
|
|
2599
|
+
displayName: string;
|
|
2600
|
+
};
|
|
2601
|
+
|
|
2602
|
+
interface ArtifactTableProps {
|
|
2603
|
+
data: A2UITableData;
|
|
2604
|
+
language?: 'en' | 'ar';
|
|
2605
|
+
dir?: 'ltr' | 'rtl';
|
|
2606
|
+
}
|
|
2607
|
+
declare const ArtifactTable: {
|
|
2608
|
+
({ data, language, dir }: ArtifactTableProps): React$1.JSX.Element;
|
|
2609
|
+
displayName: string;
|
|
2610
|
+
};
|
|
2611
|
+
|
|
2612
|
+
interface ArtifactChartProps {
|
|
2613
|
+
data: A2UIChartData;
|
|
2614
|
+
language?: 'en' | 'ar';
|
|
2615
|
+
dir?: 'ltr' | 'rtl';
|
|
2616
|
+
}
|
|
2617
|
+
declare const ArtifactChart: {
|
|
2618
|
+
({ data, language }: ArtifactChartProps): React$1.JSX.Element;
|
|
2619
|
+
displayName: string;
|
|
2620
|
+
};
|
|
2621
|
+
|
|
2622
|
+
/**
|
|
2623
|
+
* ArtifactCard — renders an A2UI "card" artifact.
|
|
2624
|
+
*
|
|
2625
|
+
* Two layouts:
|
|
2626
|
+
* - **Rich** (intelligence card): a summary headline, a 2-column grid of metric
|
|
2627
|
+
* tiles (label + big value + icon, tone-color-coded green/red/neutral, optional
|
|
2628
|
+
* sparkline), a related-items list, and a footer recommendation. Used when the
|
|
2629
|
+
* payload carries `metrics`/`summary`.
|
|
2630
|
+
* - **Simple**: title + body + key/value fields. Backward-compatible fallback.
|
|
2631
|
+
*
|
|
2632
|
+
* Bilingual (title/summary/related/footer _en/_ar), RTL-safe (logical props),
|
|
2633
|
+
* token-themed for dark/light. displayName set (Rule 7).
|
|
2634
|
+
*/
|
|
2635
|
+
|
|
2636
|
+
interface ArtifactCardProps {
|
|
2637
|
+
data: A2UICardData;
|
|
2638
|
+
/** Outer artifact title (title_en / title_ar from the A2UIArtifact envelope). */
|
|
2639
|
+
artifactTitle?: string;
|
|
2640
|
+
language?: 'en' | 'ar';
|
|
2641
|
+
dir?: 'ltr' | 'rtl';
|
|
2642
|
+
}
|
|
2643
|
+
declare const ArtifactCard: {
|
|
2644
|
+
({ data, artifactTitle, language, dir }: ArtifactCardProps): React$1.JSX.Element;
|
|
2645
|
+
displayName: string;
|
|
2646
|
+
};
|
|
2647
|
+
|
|
2648
|
+
interface ArtifactActionsProps {
|
|
2649
|
+
data: A2UIActionsData;
|
|
2650
|
+
/** Called when the user clicks an action chip. */
|
|
2651
|
+
onAction?: (item: A2UIActionItem) => void;
|
|
2652
|
+
language?: 'en' | 'ar';
|
|
2653
|
+
dir?: 'ltr' | 'rtl';
|
|
2654
|
+
}
|
|
2655
|
+
declare const ArtifactActions: {
|
|
2656
|
+
({ data, onAction, language, dir }: ArtifactActionsProps): React$1.JSX.Element | null;
|
|
2657
|
+
displayName: string;
|
|
2658
|
+
};
|
|
2659
|
+
|
|
2660
|
+
interface ArtifactMarkdownProps {
|
|
2661
|
+
data: A2UIMarkdownData;
|
|
2662
|
+
language?: 'en' | 'ar';
|
|
2663
|
+
dir?: 'ltr' | 'rtl';
|
|
2664
|
+
}
|
|
2665
|
+
declare const ArtifactMarkdown: {
|
|
2666
|
+
({ data, language, dir }: ArtifactMarkdownProps): React$1.JSX.Element | null;
|
|
2667
|
+
displayName: string;
|
|
2668
|
+
};
|
|
2669
|
+
|
|
2670
|
+
interface ArtifactClientCandidatesProps {
|
|
2671
|
+
data: A2UIClientCandidatesData;
|
|
2672
|
+
/** Fired when the user selects a candidate. Carries a "select_candidate" interaction. */
|
|
2673
|
+
onInteract?: (interaction: ArtifactInteraction) => void;
|
|
2674
|
+
language?: 'en' | 'ar';
|
|
2675
|
+
dir?: 'ltr' | 'rtl';
|
|
2676
|
+
}
|
|
2677
|
+
declare const ArtifactClientCandidates: {
|
|
2678
|
+
({ data, onInteract, language, dir, }: ArtifactClientCandidatesProps): React$1.JSX.Element | null;
|
|
2679
|
+
displayName: string;
|
|
2680
|
+
};
|
|
2681
|
+
|
|
2682
|
+
interface ArtifactClientFieldPickerProps {
|
|
2683
|
+
data: A2UIClientFieldPickerData;
|
|
2684
|
+
/** Fired when the user confirms the selected fields. Carries a "pick_fields" interaction. */
|
|
2685
|
+
onInteract?: (interaction: ArtifactInteraction) => void;
|
|
2686
|
+
language?: 'en' | 'ar';
|
|
2687
|
+
dir?: 'ltr' | 'rtl';
|
|
2688
|
+
}
|
|
2689
|
+
declare const ArtifactClientFieldPicker: {
|
|
2690
|
+
({ data, onInteract, language, dir, }: ArtifactClientFieldPickerProps): React$1.JSX.Element | null;
|
|
2691
|
+
displayName: string;
|
|
2692
|
+
};
|
|
2693
|
+
|
|
2694
|
+
interface ArtifactClientDiffConfirmProps {
|
|
2695
|
+
data: A2UIClientDiffConfirmData;
|
|
2696
|
+
/** Fired when the user confirms or cancels the diff. Carries a "confirm_diff" interaction. */
|
|
2697
|
+
onInteract?: (interaction: ArtifactInteraction) => void;
|
|
2698
|
+
language?: 'en' | 'ar';
|
|
2699
|
+
dir?: 'ltr' | 'rtl';
|
|
2700
|
+
}
|
|
2701
|
+
declare const ArtifactClientDiffConfirm: {
|
|
2702
|
+
({ data, onInteract, language, dir, }: ArtifactClientDiffConfirmProps): React$1.JSX.Element | null;
|
|
2703
|
+
displayName: string;
|
|
2704
|
+
};
|
|
2705
|
+
|
|
2706
|
+
interface ArtifactPersonaStartersProps {
|
|
2707
|
+
data: A2UIPersonaStartersData;
|
|
2708
|
+
/** Fired when the user clicks a starter chip. Carries a "persona_start" interaction. */
|
|
2709
|
+
onInteract?: (interaction: ArtifactInteraction) => void;
|
|
2710
|
+
language?: 'en' | 'ar';
|
|
2711
|
+
dir?: 'ltr' | 'rtl';
|
|
2712
|
+
}
|
|
2713
|
+
declare const ArtifactPersonaStarters: {
|
|
2714
|
+
({ data, onInteract, language, dir, }: ArtifactPersonaStartersProps): React$1.JSX.Element | null;
|
|
2715
|
+
displayName: string;
|
|
2716
|
+
};
|
|
2717
|
+
|
|
2718
|
+
/**
|
|
2719
|
+
* Intel component types — shared type definitions for the IntelCard family,
|
|
2720
|
+
* ScopeGauge, ScopesAtAGlance, and FeedHeader.
|
|
2721
|
+
*
|
|
2722
|
+
* Design rules:
|
|
2723
|
+
* - Rule 8 — bilingual (EN/AR): all user-facing text fields carry _en / _ar pairs
|
|
2724
|
+
* - Rule 25 — product-agnostic: pure rendering types, no fetching, no context reads
|
|
2725
|
+
* - Rule 26 — video = metadata only (URL + poster + permalink; never embedded player)
|
|
2726
|
+
*/
|
|
2727
|
+
type IntelSeverity = 'critical' | 'high' | 'medium' | 'low';
|
|
2728
|
+
|
|
2729
|
+
interface SeverityChipProps {
|
|
2730
|
+
severity: IntelSeverity;
|
|
2731
|
+
/** Scope/region name shown as a neutral secondary tag beside the badge */
|
|
2732
|
+
scopeName?: string;
|
|
2733
|
+
language?: 'en' | 'ar';
|
|
2734
|
+
className?: string;
|
|
2735
|
+
}
|
|
2736
|
+
declare const SeverityChip: {
|
|
2737
|
+
({ severity, scopeName, language, className }: SeverityChipProps): React$1.JSX.Element;
|
|
2738
|
+
displayName: string;
|
|
2739
|
+
};
|
|
2740
|
+
|
|
2741
|
+
interface MarkdownContentProps {
|
|
2742
|
+
/** Markdown source — typically an assistant chat message. */
|
|
2743
|
+
content: string;
|
|
2744
|
+
/** Text direction. RTL maps to the Arabic locale of the renderer. Default 'ltr'. */
|
|
2745
|
+
dir?: 'ltr' | 'rtl';
|
|
2746
|
+
/** Extra classes merged onto the wrapper. */
|
|
2747
|
+
className?: string;
|
|
2748
|
+
}
|
|
2749
|
+
/**
|
|
2750
|
+
* MarkdownContent — shared markdown renderer for assistant chat messages
|
|
2751
|
+
* (copilot dock, chat thread, project chat).
|
|
2752
|
+
*
|
|
2753
|
+
* Delegates to the kit's `MarkdownRenderer`, so a full assistant reply parses
|
|
2754
|
+
* over the SAME rich pipeline as standalone markdown: GFM tables render through
|
|
2755
|
+
* the sortable **DataTable** (with CSV export), fenced code blocks become the
|
|
2756
|
+
* **CodeBlock** (copy + PNG export, syntax-highlighted), ```mermaid fences render
|
|
2757
|
+
* as diagrams. Raw HTML is not rendered (no rehype-raw). Artifacts (a2ui blocks)
|
|
2758
|
+
* are stripped by the provider and rendered separately, so an assistant turn
|
|
2759
|
+
* shows BOTH its markdown text and its artifacts.
|
|
2760
|
+
*/
|
|
2761
|
+
declare const MarkdownContent: {
|
|
2762
|
+
({ content, dir, className }: MarkdownContentProps): React$1.JSX.Element;
|
|
2763
|
+
displayName: string;
|
|
2764
|
+
};
|
|
2765
|
+
|
|
2766
|
+
/** Issue lifecycle status. Lowercase string values mirror the SDK / DB enum. */
|
|
2767
|
+
type IssueStatus = "todo" | "in_progress" | "blocked" | "ready_for_review" | "done";
|
|
2768
|
+
/** Issue kind. `change` doubles as a feature request (carries the upvotes). */
|
|
2769
|
+
type IssueType = "bug" | "change" | "question" | "discussion";
|
|
2770
|
+
/** Issue priority. Color-coded AND text-labelled (a11y: never color-only). */
|
|
2771
|
+
type IssuePriority = "low" | "normal" | "high" | "critical";
|
|
2772
|
+
/** Who reported the issue — an authed hub user or an external/anonymous SDK reporter. */
|
|
2773
|
+
type IssueReporterKind = "user" | "external";
|
|
2774
|
+
/** A person reference (reporter / assignee / comment author). */
|
|
2775
|
+
interface IssuePerson {
|
|
2776
|
+
id: string;
|
|
2777
|
+
/** Pre-resolved display name (the host chooses EN/AR before passing it). */
|
|
2778
|
+
name: string;
|
|
2779
|
+
avatarUrl?: string | null;
|
|
2780
|
+
kind?: IssueReporterKind;
|
|
2781
|
+
/** Only set for external reporters. */
|
|
2782
|
+
email?: string | null;
|
|
2783
|
+
}
|
|
2784
|
+
/** A stored attachment on an issue (image / pdf). URL is host-provided. */
|
|
2785
|
+
interface IssueAttachment {
|
|
2786
|
+
/** Download URL (https) supplied by the host's upload endpoint. */
|
|
2787
|
+
url: string;
|
|
2788
|
+
/** Original file name. */
|
|
2789
|
+
name: string;
|
|
2790
|
+
/** MIME type. */
|
|
2791
|
+
contentType: string;
|
|
2792
|
+
/** Size in bytes. */
|
|
2793
|
+
size?: number;
|
|
2794
|
+
/** Pixel dimensions (images only). */
|
|
2795
|
+
width?: number;
|
|
2796
|
+
height?: number;
|
|
2797
|
+
}
|
|
2798
|
+
/** A comment on an issue. `body` is markdown/plain text (host decides rendering). */
|
|
2799
|
+
interface IssueComment {
|
|
2800
|
+
id: string;
|
|
2801
|
+
author: IssuePerson | null;
|
|
2802
|
+
/** Comment body (markdown). Components render it as plain text by default; a
|
|
2803
|
+
* host may pass a `renderBody` prop to plug in its own markdown renderer. */
|
|
2804
|
+
body: string;
|
|
2805
|
+
createdAt: string;
|
|
2806
|
+
}
|
|
2807
|
+
/** Where on the page an issue was pinned by the reporter's element picker.
|
|
2808
|
+
* Mirrors the SDK anchor shape exactly so Motor's SDK + these components agree. */
|
|
2809
|
+
interface IssueAnchor {
|
|
2810
|
+
/** CSS selector of the pinned element (primary anchor). */
|
|
2811
|
+
selector?: string;
|
|
2812
|
+
/** window scroll offset at pin time (fallback when the selector no longer matches). */
|
|
2813
|
+
scrollY: number;
|
|
2814
|
+
/** First ~80 chars of the pinned element's text, for human context. */
|
|
2815
|
+
hint?: string;
|
|
2816
|
+
/** Full URL at pin time (incl. query/hash) — restores tab/panel state. */
|
|
2817
|
+
href?: string;
|
|
2818
|
+
}
|
|
2819
|
+
/** Lightweight per-card aggregate counts (drives the card footer icons). */
|
|
2820
|
+
interface IssueCounts {
|
|
2821
|
+
comments?: number;
|
|
2822
|
+
attachments?: number;
|
|
2823
|
+
children?: number;
|
|
2824
|
+
}
|
|
2825
|
+
/** The full issue shape consumed by the board / card / drawer / detail view.
|
|
2826
|
+
* A host maps its `/api/issues/v1` rows onto this; every field the components
|
|
2827
|
+
* read is here, so there is no hidden data dependency. */
|
|
2828
|
+
interface Issue {
|
|
2829
|
+
id: string;
|
|
2830
|
+
/** Human-facing sequential number (#123). */
|
|
2831
|
+
number: number;
|
|
2832
|
+
title: string;
|
|
2833
|
+
description?: string | null;
|
|
2834
|
+
type: IssueType;
|
|
2835
|
+
status: IssueStatus;
|
|
2836
|
+
priority: IssuePriority;
|
|
2837
|
+
/** Optional area/component tag (e.g. "auth", "billing"). */
|
|
2838
|
+
area?: string | null;
|
|
2839
|
+
/** Route the issue was filed against (normalized pathname). */
|
|
2840
|
+
route?: string | null;
|
|
2841
|
+
/** Page-pin anchor (from the SDK element picker). */
|
|
2842
|
+
anchor?: IssueAnchor | null;
|
|
2843
|
+
reporter?: IssuePerson | null;
|
|
2844
|
+
assignee?: IssuePerson | null;
|
|
2845
|
+
/** Board ordering rank (lexicographic). Used to sort within a status column. */
|
|
2846
|
+
boardRank?: string;
|
|
2847
|
+
voteCount?: number;
|
|
2848
|
+
votedByMe?: boolean;
|
|
2849
|
+
counts?: IssueCounts;
|
|
2850
|
+
comments?: IssueComment[];
|
|
2851
|
+
attachments?: IssueAttachment[];
|
|
2852
|
+
createdAt: string;
|
|
2853
|
+
updatedAt?: string;
|
|
2854
|
+
}
|
|
2855
|
+
|
|
2856
|
+
type Language = "en" | "ar";
|
|
2857
|
+
|
|
2858
|
+
/**
|
|
2859
|
+
* FeedbackButton — the trigger that opens the feedback hub / new-issue flow.
|
|
2860
|
+
*
|
|
2861
|
+
* Pure + product-agnostic (Rule 25): it renders a button and calls `onOpen` (or
|
|
2862
|
+
* `onClick`) — it owns no modal, no portal, no fetch. The host decides what
|
|
2863
|
+
* opening means (mount a FeedbackHub, open a NewIssueModal, etc.). Two layouts:
|
|
2864
|
+
* `variant="floating"` (a fixed FAB pinned to the inline-end / bottom corner,
|
|
2865
|
+
* RTL-aware) and `variant="inline"` (a compact toolbar/nav button). Bilingual
|
|
2866
|
+
* via `language` (Rule 8); token-clean (Rule 16).
|
|
2867
|
+
*
|
|
2868
|
+
* Props contract:
|
|
2869
|
+
* - onOpen() | onClick(): fired when pressed (onOpen preferred; onClick alias)
|
|
2870
|
+
* - language: 'en' | 'ar' — picks the "Feedback" label
|
|
2871
|
+
* - variant: 'floating' (default) | 'inline'
|
|
2872
|
+
* - count: optional unread/open badge count
|
|
2873
|
+
* - label: optional override of the default "Feedback" text
|
|
2874
|
+
*/
|
|
2875
|
+
declare const feedbackButtonVariants: (props?: ({
|
|
2876
|
+
variant?: "inline" | "floating" | null | undefined;
|
|
2877
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
2878
|
+
type FeedbackButtonProps = React$1.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof feedbackButtonVariants> & {
|
|
2879
|
+
onOpen?: () => void;
|
|
2880
|
+
language?: Language;
|
|
2881
|
+
/** Optional open/unread count rendered as a small badge. */
|
|
2882
|
+
count?: number;
|
|
2883
|
+
/** Optional label override (default: "Feedback" / "ملاحظات"). */
|
|
2884
|
+
label?: string;
|
|
2885
|
+
};
|
|
2886
|
+
declare const FeedbackButton: React$1.ForwardRefExoticComponent<React$1.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<(props?: ({
|
|
2887
|
+
variant?: "inline" | "floating" | null | undefined;
|
|
2888
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string> & {
|
|
2889
|
+
onOpen?: () => void;
|
|
2890
|
+
language?: Language;
|
|
2891
|
+
/** Optional open/unread count rendered as a small badge. */
|
|
2892
|
+
count?: number;
|
|
2893
|
+
/** Optional label override (default: "Feedback" / "ملاحظات"). */
|
|
2894
|
+
label?: string;
|
|
2895
|
+
} & React$1.RefAttributes<HTMLButtonElement>>;
|
|
2896
|
+
|
|
2897
|
+
/**
|
|
2898
|
+
* FeedbackHub — the reporter's feedback slide-over: the list of issues they have
|
|
2899
|
+
* filed (optionally scoped to the current route) plus a "Report something new"
|
|
2900
|
+
* entry. This is the lightweight reporter surface (distinct from the full manager
|
|
2901
|
+
* IssueBoard): a reporter opens it from a FeedbackButton to see their open items
|
|
2902
|
+
* and file a new one.
|
|
2903
|
+
*
|
|
2904
|
+
* Pure + product-agnostic (Rule 25): `issues` + the current `route` arrive as
|
|
2905
|
+
* props; selecting an item or starting a new report just fires `onSelectIssue` /
|
|
2906
|
+
* `onNewIssue`. No fetch, no portal beyond the @prism/ui Sheet (which is
|
|
2907
|
+
* RTL-aware). Bilingual via `language` (Rule 8); token-clean (Rule 16).
|
|
2908
|
+
*
|
|
2909
|
+
* Props contract:
|
|
2910
|
+
* - open / onOpenChange: controlled visibility
|
|
2911
|
+
* - issues: Issue[] filed by this reporter (host-supplied)
|
|
2912
|
+
* - language: 'en' | 'ar'
|
|
2913
|
+
* - route: optional current route — when set, shows a "this page" group first
|
|
2914
|
+
* - loading: host-driven loading flag → skeleton rows
|
|
2915
|
+
* - onNewIssue(): start a new report
|
|
2916
|
+
* - onSelectIssue(id): open an existing issue's detail
|
|
2917
|
+
* - title: optional header override (default "Feedback")
|
|
2918
|
+
*/
|
|
2919
|
+
type FeedbackHubProps = {
|
|
2920
|
+
open: boolean;
|
|
2921
|
+
onOpenChange: (open: boolean) => void;
|
|
2922
|
+
issues: Issue[];
|
|
2923
|
+
language?: Language;
|
|
2924
|
+
route?: string;
|
|
2925
|
+
loading?: boolean;
|
|
2926
|
+
onNewIssue?: () => void;
|
|
2927
|
+
onSelectIssue?: (id: string) => void;
|
|
2928
|
+
title?: string;
|
|
2929
|
+
};
|
|
2930
|
+
declare const FeedbackHub: {
|
|
2931
|
+
({ open, onOpenChange, issues, language, route, loading, onNewIssue, onSelectIssue, title, }: FeedbackHubProps): React$1.JSX.Element;
|
|
2932
|
+
displayName: string;
|
|
2933
|
+
};
|
|
2934
|
+
|
|
2935
|
+
/**
|
|
2936
|
+
* MotorFeedbackLauncher — the ONE shared feedback launcher for every Sentra
|
|
2937
|
+
* product dashboard (Sentra hub, Scout, Cortex, Fort, Axon).
|
|
2938
|
+
*
|
|
2939
|
+
* It loads the shared Motor feedback SDK (@sentra/motor-feedback, served as a
|
|
2940
|
+
* static bundle at `sdkSrc`, default /motor-feedback.js) and mounts its
|
|
2941
|
+
* FeedbackHub on this floating trigger. ALL feedback behaviour — the report
|
|
2942
|
+
* form, element anchor, client-side screenshot, attachments, and the POST to
|
|
2943
|
+
* Motor's /api/issues/v1 surface — lives in the Motor SDK. No product
|
|
2944
|
+
* reimplements the feedback form or transport (operator decision 2026-06-14:
|
|
2945
|
+
* "feedback must extend the Motor SDK, not be custom per product").
|
|
2946
|
+
*
|
|
2947
|
+
* The FAB is DRAGGABLE: press-and-drag moves it anywhere on screen and the
|
|
2948
|
+
* position is cached in localStorage (per project), so it survives reloads. A
|
|
2949
|
+
* drag is distinguished from a click by a small movement threshold — a real
|
|
2950
|
+
* click still opens the feedback panel; a drag does not.
|
|
2951
|
+
*
|
|
2952
|
+
* Why the SDK over a bespoke modal: the SDK renders its panel inside a Shadow
|
|
2953
|
+
* DOM mounted on <body>, so it sits on the top stacking layer — immune to the
|
|
2954
|
+
* host app's z-index / transformed ancestors (the old bespoke launcher rendered
|
|
2955
|
+
* *behind* the header). This trigger button also carries a very high z-index so
|
|
2956
|
+
* the FAB itself floats over all app UI.
|
|
2957
|
+
*
|
|
2958
|
+
* Product-agnostic (Rule 25): no app context, no fetch here — `project`,
|
|
2959
|
+
* `publishableKey` (Motor DSN public key), `apiBase`, and `language` all arrive
|
|
2960
|
+
* as props. Renders nothing when `project`/`publishableKey` are empty (Motor
|
|
2961
|
+
* optional → host stays standalone). Bilingual (Rule 8); token-clean (Rule 16).
|
|
2962
|
+
*/
|
|
2963
|
+
type SdkIssueType = "bug" | "change" | "question" | "discussion";
|
|
2964
|
+
type FeedbackHubHandle = {
|
|
2965
|
+
open(): void;
|
|
2966
|
+
close(): void;
|
|
2967
|
+
refresh(): void;
|
|
2968
|
+
destroy(): void;
|
|
2969
|
+
};
|
|
2970
|
+
type MotorFeedbackSdk = {
|
|
2971
|
+
mountFeedbackHub(opts: {
|
|
2972
|
+
trigger: Element;
|
|
2973
|
+
project: string;
|
|
2974
|
+
publishableKey: string;
|
|
2975
|
+
apiBase: string;
|
|
2976
|
+
theme?: "light" | "dark" | "auto";
|
|
2977
|
+
defaultType?: SdkIssueType;
|
|
2978
|
+
title?: string;
|
|
2979
|
+
reporterEmail?: string;
|
|
2980
|
+
reporterName?: string;
|
|
2981
|
+
}): FeedbackHubHandle;
|
|
2982
|
+
};
|
|
2983
|
+
declare global {
|
|
2984
|
+
interface Window {
|
|
2985
|
+
MotorFeedback?: MotorFeedbackSdk;
|
|
2986
|
+
}
|
|
2987
|
+
}
|
|
2988
|
+
type MotorFeedbackLauncherProps = {
|
|
2989
|
+
/** Motor project slug, e.g. "sentra" | "scout" | "cortex" | "fort" | "axon". */
|
|
2990
|
+
project: string;
|
|
2991
|
+
/** Motor DSN public key, e.g. "motor-sentra-dev-key" (NEXT_PUBLIC_MOTOR_DSN). */
|
|
2992
|
+
publishableKey: string;
|
|
2993
|
+
/** Motor issues API base, e.g. http://localhost:8215/api/issues/v1. */
|
|
2994
|
+
apiBase: string;
|
|
2995
|
+
language?: Language;
|
|
2996
|
+
/** Where the Motor SDK bundle is served. Default: /motor-feedback.js */
|
|
2997
|
+
sdkSrc?: string;
|
|
2998
|
+
theme?: "light" | "dark" | "auto";
|
|
2999
|
+
defaultType?: SdkIssueType;
|
|
3000
|
+
/** Pre-fill the reporter identity when the host knows the signed-in user. */
|
|
3001
|
+
reporterEmail?: string;
|
|
3002
|
+
reporterName?: string;
|
|
3003
|
+
/** Optional FAB label override (default: "Feedback" / "ملاحظات"). */
|
|
3004
|
+
label?: string;
|
|
3005
|
+
};
|
|
3006
|
+
declare const MotorFeedbackLauncher: React$1.FC<MotorFeedbackLauncherProps>;
|
|
3007
|
+
|
|
3008
|
+
type FeedbackKind = "bug" | "feature" | "question" | "discussion";
|
|
3009
|
+
interface PickedLocation {
|
|
3010
|
+
selector: string;
|
|
3011
|
+
tag: string;
|
|
3012
|
+
label?: string;
|
|
3013
|
+
}
|
|
3014
|
+
interface FeedbackAttachment {
|
|
3015
|
+
name: string;
|
|
3016
|
+
kind: "file" | "screenshot";
|
|
3017
|
+
}
|
|
3018
|
+
interface FeedbackItem {
|
|
3019
|
+
id: string;
|
|
3020
|
+
kind: FeedbackKind;
|
|
3021
|
+
title: string;
|
|
3022
|
+
details?: string;
|
|
3023
|
+
pageUrl?: string;
|
|
3024
|
+
location?: PickedLocation;
|
|
3025
|
+
attachments?: FeedbackAttachment[];
|
|
3026
|
+
createdAt?: string;
|
|
3027
|
+
}
|
|
3028
|
+
type NewFeedback = Omit<FeedbackItem, "id" | "createdAt">;
|
|
3029
|
+
interface FeedbackWidgetProps {
|
|
3030
|
+
/** Issues already reported on this page (rendered in the panel list). */
|
|
3031
|
+
items?: FeedbackItem[];
|
|
3032
|
+
/** Current page URL (defaults to window.location.href). */
|
|
3033
|
+
pageUrl?: string;
|
|
3034
|
+
onSubmit?: (issue: NewFeedback) => void;
|
|
3035
|
+
onSelectIssue?: (id: string) => void;
|
|
3036
|
+
/** Host-provided screenshot capture (the kit is presentational). Returns a name. */
|
|
3037
|
+
onScreenshot?: () => Promise<string | null> | string | null;
|
|
3038
|
+
language?: "en" | "ar";
|
|
3039
|
+
/** Control the panel externally (otherwise a floating button is shown). */
|
|
3040
|
+
open?: boolean;
|
|
3041
|
+
onOpenChange?: (open: boolean) => void;
|
|
3042
|
+
className?: string;
|
|
3043
|
+
pageSize?: number;
|
|
3044
|
+
}
|
|
3045
|
+
declare function FeedbackWidget({ items, pageUrl, onSubmit, onSelectIssue, onScreenshot, language, open: openProp, onOpenChange, className, pageSize, }: FeedbackWidgetProps): React$1.JSX.Element;
|
|
3046
|
+
|
|
3047
|
+
type LogoVariant = "mark" | "mono";
|
|
3048
|
+
/** brand = gradient · white = reversed (dark bg) · inherit = currentColor (themes with text). */
|
|
3049
|
+
type LogoTone = "brand" | "white" | "inherit";
|
|
3050
|
+
interface LogoProps extends Omit<React$1.HTMLAttributes<HTMLElement>, "color"> {
|
|
3051
|
+
variant?: LogoVariant;
|
|
3052
|
+
tone?: LogoTone;
|
|
3053
|
+
/** Rendered height in px; width derives from the mark's aspect ratio. */
|
|
3054
|
+
size?: number;
|
|
3055
|
+
title?: string;
|
|
3056
|
+
}
|
|
3057
|
+
/** ToGO Logo — the mascot mark or the monogram. `tone="inherit"` masks the shape
|
|
3058
|
+
* with currentColor so it themes with the surrounding text color. */
|
|
3059
|
+
declare function Logo({ variant, tone, size, title, className, style, ...props }: LogoProps): React$1.JSX.Element;
|
|
3060
|
+
declare namespace Logo {
|
|
3061
|
+
var displayName: string;
|
|
3062
|
+
}
|
|
3063
|
+
|
|
3064
|
+
interface WordmarkProps extends React$1.HTMLAttributes<HTMLSpanElement> {
|
|
3065
|
+
/** Font size of the wordmark in px. */
|
|
3066
|
+
size?: number;
|
|
3067
|
+
/** Render the mark/monogram before the wordmark. */
|
|
3068
|
+
withMark?: boolean;
|
|
3069
|
+
markVariant?: LogoVariant;
|
|
3070
|
+
}
|
|
3071
|
+
/** ToGO Wordmark — "To" in Gopher Cyan, "GO" in Cobalt (brand-fixed, theme-independent),
|
|
3072
|
+
* set in the Sora display face. */
|
|
3073
|
+
declare function Wordmark({ size, withMark, markVariant, className, style, ...props }: WordmarkProps): React$1.JSX.Element;
|
|
3074
|
+
declare namespace Wordmark {
|
|
3075
|
+
var displayName: string;
|
|
3076
|
+
}
|
|
3077
|
+
|
|
3078
|
+
interface ModelOption {
|
|
3079
|
+
value: string;
|
|
3080
|
+
label?: string;
|
|
3081
|
+
}
|
|
3082
|
+
interface SectionModel {
|
|
3083
|
+
id: string;
|
|
3084
|
+
title: string;
|
|
3085
|
+
badge?: string;
|
|
3086
|
+
/** AI prompt that powers this section (edited in edit mode). */
|
|
3087
|
+
prompt?: string;
|
|
3088
|
+
/** Selected model id. */
|
|
3089
|
+
model?: string;
|
|
3090
|
+
/** Arbitrary key/value settings. */
|
|
3091
|
+
settings?: Record<string, string>;
|
|
3092
|
+
/** Rendered content in view mode. */
|
|
3093
|
+
content?: React$1.ReactNode;
|
|
3094
|
+
}
|
|
3095
|
+
interface DynamicSectionProps {
|
|
3096
|
+
section: SectionModel;
|
|
3097
|
+
editMode?: boolean;
|
|
3098
|
+
models?: ModelOption[];
|
|
3099
|
+
language?: "en" | "ar";
|
|
3100
|
+
onChange?: (section: SectionModel) => void;
|
|
3101
|
+
onRemove?: () => void;
|
|
3102
|
+
/** Drag handle props (supplied by SectionBoard in edit mode). */
|
|
3103
|
+
handleProps?: React$1.HTMLAttributes<HTMLButtonElement>;
|
|
3104
|
+
className?: string;
|
|
3105
|
+
}
|
|
3106
|
+
declare function DynamicSection({ section, editMode, models, language, onChange, onRemove, handleProps, className, }: DynamicSectionProps): React$1.JSX.Element;
|
|
3107
|
+
interface SectionBoardProps {
|
|
3108
|
+
sections: SectionModel[];
|
|
3109
|
+
editMode?: boolean;
|
|
3110
|
+
models?: ModelOption[];
|
|
3111
|
+
language?: "en" | "ar";
|
|
3112
|
+
columns?: 1 | 2;
|
|
3113
|
+
onChange?: (sections: SectionModel[]) => void;
|
|
3114
|
+
onAddSection?: () => void;
|
|
3115
|
+
className?: string;
|
|
3116
|
+
}
|
|
3117
|
+
/** SectionBoard — an ordered set of dynamic sections. In `editMode` each section is
|
|
3118
|
+
* drag-reorderable (@dnd-kit) and editable (prompt / model / settings via a dialog);
|
|
3119
|
+
* `onChange` fires on reorder and on per-section edits. View mode renders content only.
|
|
3120
|
+
* Token-themed (dark/light), RTL + EN/AR. */
|
|
3121
|
+
declare function SectionBoard({ sections, editMode, models, language, columns, onChange, onAddSection, className, }: SectionBoardProps): React$1.JSX.Element;
|
|
3122
|
+
|
|
3123
|
+
interface MarkdownRendererProps {
|
|
3124
|
+
content: string;
|
|
3125
|
+
language?: "en" | "ar";
|
|
3126
|
+
className?: string;
|
|
3127
|
+
}
|
|
3128
|
+
/** MarkdownTable — renders a GFM table via the kit's DataTable (sortable, searchable,
|
|
3129
|
+
* CSV export). Exported so apps can reuse the markdown-table → DataTable mapping. */
|
|
3130
|
+
declare function MarkdownTable({ node, language }: {
|
|
3131
|
+
node: any;
|
|
3132
|
+
language?: "en" | "ar";
|
|
3133
|
+
}): React$1.JSX.Element;
|
|
3134
|
+
/** CodeBlock — a fenced code block with a language label, Copy, and download-as-PNG.
|
|
3135
|
+
* Exported so apps can render standalone code with the same chrome. */
|
|
3136
|
+
declare function CodeBlock({ lang, children }: {
|
|
3137
|
+
lang?: string;
|
|
3138
|
+
children?: React$1.ReactNode;
|
|
3139
|
+
}): React$1.JSX.Element;
|
|
3140
|
+
/** MarkdownRenderer — GFM markdown with highlighted code, mermaid diagrams, and
|
|
3141
|
+
* token-themed prose (headings/lists/tables/code/quote/links). RTL-aware. */
|
|
3142
|
+
declare function MarkdownRenderer({ content, language, className }: MarkdownRendererProps): React$1.JSX.Element;
|
|
3143
|
+
|
|
3144
|
+
type MarkdownView = "write" | "preview" | "split";
|
|
3145
|
+
interface MarkdownEditorProps {
|
|
3146
|
+
value?: string;
|
|
3147
|
+
defaultValue?: string;
|
|
3148
|
+
onChange?: (value: string) => void;
|
|
3149
|
+
view?: MarkdownView;
|
|
3150
|
+
defaultView?: MarkdownView;
|
|
3151
|
+
onViewChange?: (view: MarkdownView) => void;
|
|
3152
|
+
language?: "en" | "ar";
|
|
3153
|
+
placeholder?: string;
|
|
3154
|
+
minRows?: number;
|
|
3155
|
+
className?: string;
|
|
3156
|
+
}
|
|
3157
|
+
/** MarkdownEditor — toolbar (bold/italic/headings/lists/link/code/quote) + a textarea
|
|
3158
|
+
* with a Write / Preview / Split view toggle (Split shows a live MarkdownRenderer).
|
|
3159
|
+
* Dependency-light (no CodeMirror/Monaco). Controlled or uncontrolled. RTL + EN/AR. */
|
|
3160
|
+
declare function MarkdownEditor({ value, defaultValue, onChange, view, defaultView, onViewChange, language, placeholder, minRows, className, }: MarkdownEditorProps): React$1.JSX.Element;
|
|
3161
|
+
|
|
3162
|
+
declare function cn(...inputs: ClassValue[]): string;
|
|
3163
|
+
|
|
3164
|
+
interface CopilotRequest {
|
|
3165
|
+
[key: string]: any;
|
|
3166
|
+
attachments?: unknown[];
|
|
3167
|
+
intelligenceContext?: {
|
|
3168
|
+
data_summary?: string;
|
|
3169
|
+
[key: string]: unknown;
|
|
3170
|
+
};
|
|
3171
|
+
}
|
|
3172
|
+
interface CopilotEvent {
|
|
3173
|
+
type?: string;
|
|
3174
|
+
[key: string]: any;
|
|
3175
|
+
}
|
|
3176
|
+
/** The streaming client the host injects into CopilotProvider. */
|
|
3177
|
+
interface CopilotClient {
|
|
3178
|
+
copilotDispatch(req: CopilotRequest, opts?: {
|
|
3179
|
+
signal?: AbortSignal;
|
|
3180
|
+
}): AsyncIterable<CopilotEvent>;
|
|
3181
|
+
}
|
|
3182
|
+
|
|
3183
|
+
type DockPosition = 'bottom' | 'left' | 'right' | 'float';
|
|
3184
|
+
interface CopilotQuickAction {
|
|
3185
|
+
label_en: string;
|
|
3186
|
+
label_ar: string;
|
|
3187
|
+
prompt: string;
|
|
3188
|
+
/** Optional lucide-style icon name hint (rendered by the dock when known). */
|
|
3189
|
+
icon?: string;
|
|
3190
|
+
}
|
|
3191
|
+
interface AgentStep {
|
|
3192
|
+
step: string;
|
|
3193
|
+
message: string;
|
|
3194
|
+
query?: string;
|
|
3195
|
+
subQuery?: string;
|
|
3196
|
+
count?: number;
|
|
3197
|
+
highQuality?: number;
|
|
3198
|
+
citations?: string[];
|
|
3199
|
+
sources?: string[];
|
|
3200
|
+
domains?: string[];
|
|
3201
|
+
handles?: string[];
|
|
3202
|
+
duration_ms?: number;
|
|
3203
|
+
done?: boolean;
|
|
3204
|
+
}
|
|
3205
|
+
interface ArtifactPayload {
|
|
3206
|
+
controller_slug: string;
|
|
3207
|
+
title?: string;
|
|
3208
|
+
title_ar?: string;
|
|
3209
|
+
data: unknown;
|
|
3210
|
+
}
|
|
3211
|
+
interface A2UIArtifact {
|
|
3212
|
+
version: number;
|
|
3213
|
+
kind: string;
|
|
3214
|
+
title_en?: string;
|
|
3215
|
+
title_ar?: string;
|
|
3216
|
+
data: unknown;
|
|
3217
|
+
}
|
|
3218
|
+
interface CopilotMessage {
|
|
3219
|
+
id: string;
|
|
3220
|
+
role: 'user' | 'assistant';
|
|
3221
|
+
content: string;
|
|
3222
|
+
content_ar?: string;
|
|
3223
|
+
/** Whether the user message should be hidden (insight-trigger bubbles) */
|
|
3224
|
+
hidden?: boolean;
|
|
3225
|
+
steps?: AgentStep[];
|
|
3226
|
+
citations?: Array<{
|
|
3227
|
+
number: number;
|
|
3228
|
+
title: string;
|
|
3229
|
+
slug: string;
|
|
3230
|
+
type: string;
|
|
3231
|
+
description?: string;
|
|
3232
|
+
}>;
|
|
3233
|
+
briefing?: Record<string, unknown>;
|
|
3234
|
+
/** Legacy controller-slug artifacts (ArtifactViewer). */
|
|
3235
|
+
artifacts?: ArtifactPayload[];
|
|
3236
|
+
/**
|
|
3237
|
+
* A2UI structured artifacts from the Cortex SSE stream (phase 4).
|
|
3238
|
+
* A single message may carry multiple artifacts (emitted before [DONE]).
|
|
3239
|
+
* Rendered by ArtifactRenderer below the message text in the dock.
|
|
3240
|
+
*/
|
|
3241
|
+
a2uiArtifacts?: A2UIArtifact[];
|
|
3242
|
+
}
|
|
3243
|
+
interface ForcedTools {
|
|
3244
|
+
search?: boolean;
|
|
3245
|
+
search_sources?: string[];
|
|
3246
|
+
deep_research?: boolean;
|
|
3247
|
+
}
|
|
3248
|
+
interface SendOptions {
|
|
3249
|
+
thinkingMode?: boolean;
|
|
3250
|
+
insight?: boolean;
|
|
3251
|
+
hideUserMessage?: boolean;
|
|
3252
|
+
forcedTools?: ForcedTools;
|
|
3253
|
+
attachments?: Array<{
|
|
3254
|
+
url?: string;
|
|
3255
|
+
data?: string;
|
|
3256
|
+
name: string;
|
|
3257
|
+
type: string;
|
|
3258
|
+
}>;
|
|
3259
|
+
/**
|
|
3260
|
+
* Structured interaction post-back from an interactive artifact renderer.
|
|
3261
|
+
* When set, CopilotProvider attaches it to the CopilotRequest.interaction
|
|
3262
|
+
* field so the backend can dispatch on the structured payload rather than
|
|
3263
|
+
* the synthesised text message. The user bubble is suppressed via hideUserMessage.
|
|
3264
|
+
*/
|
|
3265
|
+
interaction?: {
|
|
3266
|
+
kind: string;
|
|
3267
|
+
payload: Record<string, unknown>;
|
|
3268
|
+
};
|
|
3269
|
+
}
|
|
3270
|
+
interface CopilotChatState {
|
|
3271
|
+
messages: CopilotMessage[];
|
|
3272
|
+
streamingText: string;
|
|
3273
|
+
isReceiving: boolean;
|
|
3274
|
+
isLoading: boolean;
|
|
3275
|
+
isStreaming: boolean;
|
|
3276
|
+
isFinalizing?: boolean;
|
|
3277
|
+
agentSteps: AgentStep[];
|
|
3278
|
+
streamError: string | null;
|
|
3279
|
+
inputValue: string;
|
|
3280
|
+
onInputChange: (value: string) => void;
|
|
3281
|
+
onSend: (text: string, opts?: SendOptions) => void;
|
|
3282
|
+
onStop?: () => void;
|
|
3283
|
+
onRetry: () => void;
|
|
3284
|
+
onNewConversation: () => void;
|
|
3285
|
+
conversationTitle?: string;
|
|
3286
|
+
conversationId?: string;
|
|
3287
|
+
conversationHistory?: Array<{
|
|
3288
|
+
id: string;
|
|
3289
|
+
title: string;
|
|
3290
|
+
updated_at: string;
|
|
3291
|
+
context_label?: string;
|
|
3292
|
+
}>;
|
|
3293
|
+
onLoadConversation?: (id: string) => void;
|
|
3294
|
+
onFetchHistory?: () => Promise<Array<{
|
|
3295
|
+
id: string;
|
|
3296
|
+
title: string;
|
|
3297
|
+
updated_at: string;
|
|
3298
|
+
context_label?: string;
|
|
3299
|
+
}>>;
|
|
3300
|
+
onDeleteConversation?: (id: string) => Promise<void>;
|
|
3301
|
+
loadedContextType?: string;
|
|
3302
|
+
loadedContextRef?: string;
|
|
3303
|
+
loadedContextLabel?: string;
|
|
3304
|
+
loadedCreatedAt?: string;
|
|
3305
|
+
loadedUpdatedAt?: string;
|
|
3306
|
+
effectiveMode?: string;
|
|
3307
|
+
}
|
|
3308
|
+
/**
|
|
3309
|
+
* A suggestion chip. Either a plain string (back-compat — same text in both
|
|
3310
|
+
* languages) or a bilingual pair so the dock can render the right language.
|
|
3311
|
+
*/
|
|
3312
|
+
type CopilotSuggestion = string | {
|
|
3313
|
+
en: string;
|
|
3314
|
+
ar: string;
|
|
3315
|
+
};
|
|
3316
|
+
interface CopilotDockContext {
|
|
3317
|
+
type: string;
|
|
3318
|
+
contextRef: string;
|
|
3319
|
+
title: string;
|
|
3320
|
+
mode: string;
|
|
3321
|
+
systemContext?: Record<string, unknown>;
|
|
3322
|
+
suggestions: CopilotSuggestion[];
|
|
3323
|
+
entityImageUrl?: string | null;
|
|
3324
|
+
}
|
|
3325
|
+
|
|
3326
|
+
/**
|
|
3327
|
+
* CopilotProvider — @prism/ui F3
|
|
3328
|
+
*
|
|
3329
|
+
* Context provider that wires UnifiedCopilotDock to the cortex-sdk
|
|
3330
|
+
* CortexClient.copilotDispatch() SSE stream. Apps mount this once at their
|
|
3331
|
+
* root (or inside LanguageProvider) and call useCopilot() anywhere to
|
|
3332
|
+
* open/close the dock.
|
|
3333
|
+
*
|
|
3334
|
+
* Wave B additions (2026-06-06):
|
|
3335
|
+
* B1 — Fetches /v1/copilot/config on mount; exposes allowedAgents as dynamic
|
|
3336
|
+
* personas list and allowedTools/allowedSkills for the dock panels.
|
|
3337
|
+
* Falls back to empty/undefined when Cortex is unreachable (nil-safe).
|
|
3338
|
+
* B2 — allowedTools + allowedSkills passed to dock via new prop.
|
|
3339
|
+
* B3 — AR suggestions already fixed (bilingual pair shape). Provider default
|
|
3340
|
+
* suggestions are now bilingual.
|
|
3341
|
+
* B4 — pageContext prop forwarded into CopilotRequest.intelligenceContext.data_summary.
|
|
3342
|
+
*
|
|
3343
|
+
* Architecture:
|
|
3344
|
+
* - Provider manages CopilotChatState (messages, streaming, error).
|
|
3345
|
+
* - onSend → CortexClient.copilotDispatch() → async generator → state updates.
|
|
3346
|
+
* - Language comes from the shared LanguageProvider context so the copilot
|
|
3347
|
+
* always answers in the active locale (EN/AR).
|
|
3348
|
+
* - cortex-sdk is a pure fetch/SSE SDK — no React dependency. Safe in any
|
|
3349
|
+
* runtime (browser, Node 18+, edge).
|
|
3350
|
+
*
|
|
3351
|
+
* Error handling (Rule 14 spirit):
|
|
3352
|
+
* - Network / Cortex unreachable → streamError shown in dock; no crash.
|
|
3353
|
+
* - Each SSE turn is wrapped in try/catch/finally so state always resolves.
|
|
3354
|
+
*
|
|
3355
|
+
* Rules: Rule 7 (displayName), Rule 8 (bilingual), Rule 16 (Sentra style),
|
|
3356
|
+
* Rule 25 (product-agnostic — no product DB/context reads).
|
|
3357
|
+
*/
|
|
3358
|
+
|
|
3359
|
+
interface CopilotConfigTool {
|
|
3360
|
+
slug: string;
|
|
3361
|
+
name: string;
|
|
3362
|
+
name_ar?: string;
|
|
3363
|
+
function_name?: string;
|
|
3364
|
+
}
|
|
3365
|
+
interface CopilotConfigSkill {
|
|
3366
|
+
slug: string;
|
|
3367
|
+
name: string;
|
|
3368
|
+
name_ar?: string;
|
|
3369
|
+
}
|
|
3370
|
+
interface CopilotConfigAgent {
|
|
3371
|
+
slug: string;
|
|
3372
|
+
name: string;
|
|
3373
|
+
/** Arabic name. The Go config handler currently returns only `name` (EN).
|
|
3374
|
+
* When the server starts emitting this field it will be picked up automatically.
|
|
3375
|
+
* Until then, CopilotProvider falls back to the AGENT_AR_NAMES map below.
|
|
3376
|
+
*/
|
|
3377
|
+
name_ar?: string;
|
|
3378
|
+
}
|
|
3379
|
+
/**
|
|
3380
|
+
* Token-scoped branding the dashboard/SDK applies to the copilot dock.
|
|
3381
|
+
* Forwarded verbatim from cortex_api_keys.capabilities.branding (config_handler.go).
|
|
3382
|
+
* All fields optional — an empty object means "use the dock defaults".
|
|
3383
|
+
*/
|
|
3384
|
+
interface CopilotBranding {
|
|
3385
|
+
/** Dock header title (EN). Overrides the default "Copilot". */
|
|
3386
|
+
title?: string;
|
|
3387
|
+
/** Dock header title (AR). */
|
|
3388
|
+
titleAr?: string;
|
|
3389
|
+
/** Accent colour (CSS colour string) applied to the dock's primary surfaces. */
|
|
3390
|
+
primaryColor?: string;
|
|
3391
|
+
/** Input placeholder (EN). */
|
|
3392
|
+
placeholder?: string;
|
|
3393
|
+
/** Input placeholder (AR). */
|
|
3394
|
+
placeholderAr?: string;
|
|
3395
|
+
}
|
|
3396
|
+
/**
|
|
3397
|
+
* Token-scoped UI toggles. Forwarded from capabilities.ui. Each defaults to
|
|
3398
|
+
* "shown" when undefined so an unconfigured token keeps the full surface.
|
|
3399
|
+
*/
|
|
3400
|
+
interface CopilotUIConfig {
|
|
3401
|
+
/** Show the in-dock Tools panel + / command tools group. Default true. */
|
|
3402
|
+
showTools?: boolean;
|
|
3403
|
+
/** Show the in-dock Skills panel + / command skills group. Default true. */
|
|
3404
|
+
showSkills?: boolean;
|
|
3405
|
+
/** Show the @ agent/persona menu + picker. Default true. */
|
|
3406
|
+
showAgents?: boolean;
|
|
3407
|
+
}
|
|
3408
|
+
interface CopilotConfig {
|
|
3409
|
+
allowed_tools: CopilotConfigTool[];
|
|
3410
|
+
allowed_skills: CopilotConfigSkill[];
|
|
3411
|
+
allowed_agents: CopilotConfigAgent[];
|
|
3412
|
+
allowed_mcp: unknown[];
|
|
3413
|
+
branding: CopilotBranding;
|
|
3414
|
+
ui: CopilotUIConfig;
|
|
3415
|
+
limits: {
|
|
3416
|
+
rate_per_min: number | null;
|
|
3417
|
+
monthly_budget: string | null;
|
|
3418
|
+
hard_cap: string | null;
|
|
3419
|
+
};
|
|
3420
|
+
}
|
|
3421
|
+
/**
|
|
3422
|
+
* Options accepted by `useCopilot().open()`.
|
|
3423
|
+
*
|
|
3424
|
+
* Backwards-compatible: bare `open()` (no args) still works unchanged.
|
|
3425
|
+
*/
|
|
3426
|
+
interface OpenCopilotOptions {
|
|
3427
|
+
/**
|
|
3428
|
+
* Pre-fill the dock input with this message text.
|
|
3429
|
+
* When autoSend is false (default), the text is placed in the input field
|
|
3430
|
+
* and focus is moved to it so the user can review before sending.
|
|
3431
|
+
*/
|
|
3432
|
+
message?: string;
|
|
3433
|
+
/**
|
|
3434
|
+
* When true, the message is sent automatically as soon as the dock opens,
|
|
3435
|
+
* without user confirmation. Use for smart-action "اسأل" flows where the
|
|
3436
|
+
* intent is clear from the card context.
|
|
3437
|
+
*/
|
|
3438
|
+
autoSend?: boolean;
|
|
3439
|
+
}
|
|
3440
|
+
interface CopilotContextValue {
|
|
3441
|
+
/**
|
|
3442
|
+
* Open the copilot dock.
|
|
3443
|
+
*
|
|
3444
|
+
* @example bare open (no pre-load)
|
|
3445
|
+
* ```tsx
|
|
3446
|
+
* const { open } = useCopilot()
|
|
3447
|
+
* <button onClick={() => open()}>Copilot</button>
|
|
3448
|
+
* ```
|
|
3449
|
+
*
|
|
3450
|
+
* @example pre-fill input
|
|
3451
|
+
* ```tsx
|
|
3452
|
+
* open({ message: `اشرح هذا الخبر: ${card.title_ar}` })
|
|
3453
|
+
* ```
|
|
3454
|
+
*
|
|
3455
|
+
* @example auto-send
|
|
3456
|
+
* ```tsx
|
|
3457
|
+
* open({ message: `اشرح هذا الخبر: ${card.title_ar}`, autoSend: true })
|
|
3458
|
+
* ```
|
|
3459
|
+
*/
|
|
3460
|
+
open: (opts?: OpenCopilotOptions) => void;
|
|
3461
|
+
/** Close the copilot dock */
|
|
3462
|
+
close: () => void;
|
|
3463
|
+
/** Whether the dock is currently open/expanded */
|
|
3464
|
+
isOpen: boolean;
|
|
3465
|
+
/** Token-scoped config (null while loading or when Cortex is unreachable) */
|
|
3466
|
+
config: CopilotConfig | null;
|
|
3467
|
+
}
|
|
3468
|
+
interface CopilotProviderProps {
|
|
3469
|
+
children: ReactNode;
|
|
3470
|
+
/**
|
|
3471
|
+
* Cortex base URL. Defaults to '/api/v1'.
|
|
3472
|
+
* Apps that proxy Cortex through Next.js rewrites pass the rewrite path here
|
|
3473
|
+
* (e.g. '/api/cortex'). Apps with a separate Cortex service pass the full
|
|
3474
|
+
* service URL (e.g. 'http://cortex:8210').
|
|
3475
|
+
*/
|
|
3476
|
+
baseUrl?: string;
|
|
3477
|
+
/**
|
|
3478
|
+
* Optional Cortex API token (Bearer). When apps proxy Cortex via cookie-auth
|
|
3479
|
+
* (Next.js middleware attaches the token server-side) the token can be omitted.
|
|
3480
|
+
* When a raw token is available client-side, pass it here.
|
|
3481
|
+
*/
|
|
3482
|
+
token?: string;
|
|
3483
|
+
/** Streaming client (replaces the cortex-sdk). Without it the dock renders but cannot dispatch. */
|
|
3484
|
+
client?: CopilotClient;
|
|
3485
|
+
/**
|
|
3486
|
+
* Page-level context fed to the copilot dock (type, title, suggestions, etc.).
|
|
3487
|
+
* Defaults to a generic "global" context. Apps update this by re-rendering
|
|
3488
|
+
* the provider with different context (or by wrapping per-page sub-sections).
|
|
3489
|
+
*/
|
|
3490
|
+
context?: CopilotDockContext;
|
|
3491
|
+
/**
|
|
3492
|
+
* Start the dock in an open/expanded state. Defaults to false.
|
|
3493
|
+
*/
|
|
3494
|
+
defaultOpen?: boolean;
|
|
3495
|
+
/**
|
|
3496
|
+
* B4: Optional markdown description of the current page. When set, the copilot
|
|
3497
|
+
* receives it as intelligenceContext.data_summary in every dispatch so it
|
|
3498
|
+
* "understands the current page" without the user having to explain.
|
|
3499
|
+
*
|
|
3500
|
+
* Apps update this prop on navigation to keep the context current.
|
|
3501
|
+
*
|
|
3502
|
+
* Example: "User is on the Plugins page. 13 plugins are loaded. Active types:
|
|
3503
|
+
* tool, skill, agent. The user can enable/disable plugins here."
|
|
3504
|
+
*/
|
|
3505
|
+
pageContext?: string;
|
|
3506
|
+
/**
|
|
3507
|
+
* Quick-action chips shown in the dock's empty/intro state. Each chip sends
|
|
3508
|
+
* its `prompt` when clicked. Falls back to `context.suggestions` when omitted.
|
|
3509
|
+
*/
|
|
3510
|
+
quickActions?: CopilotQuickAction[];
|
|
3511
|
+
}
|
|
3512
|
+
declare const CopilotProvider: {
|
|
3513
|
+
({ children, baseUrl, token, context, defaultOpen, pageContext, quickActions, client: injectedClient, }: CopilotProviderProps): React__default.JSX.Element;
|
|
3514
|
+
displayName: string;
|
|
3515
|
+
};
|
|
3516
|
+
/**
|
|
3517
|
+
* useCopilot — consume the copilot context.
|
|
3518
|
+
*
|
|
3519
|
+
* Returns `{ open, close, isOpen, config }`.
|
|
3520
|
+
* Must be used inside a <CopilotProvider>.
|
|
3521
|
+
*
|
|
3522
|
+
* @example
|
|
3523
|
+
* ```tsx
|
|
3524
|
+
* const { open } = useCopilot()
|
|
3525
|
+
* <button onClick={open}>Ask AI</button>
|
|
3526
|
+
* ```
|
|
3527
|
+
*/
|
|
3528
|
+
declare const useCopilot: () => CopilotContextValue;
|
|
3529
|
+
|
|
3530
|
+
type SlugChecker = (table: 'entities' | 'alerts' | 'narratives' | 'events', slugs: string[]) => Promise<string[]>;
|
|
3531
|
+
|
|
3532
|
+
interface UnifiedCopilotDockProps {
|
|
3533
|
+
/**
|
|
3534
|
+
* The chat state seam. The product creates this from its useCopilotChat hook
|
|
3535
|
+
* (Sentra) or its own streaming hook (Cortex, Scout). This is the ONLY API
|
|
3536
|
+
* surface that touches actual streaming/network logic.
|
|
3537
|
+
*/
|
|
3538
|
+
chatState: CopilotChatState;
|
|
3539
|
+
/** Page-level context (type, title, suggestions) */
|
|
3540
|
+
context: CopilotDockContext;
|
|
3541
|
+
/**
|
|
3542
|
+
* UI language — 'en' or 'ar'. The product reads this from its LanguageContext
|
|
3543
|
+
* and passes it here. No context import needed in this component.
|
|
3544
|
+
*/
|
|
3545
|
+
language?: 'en' | 'ar';
|
|
3546
|
+
/**
|
|
3547
|
+
* Navigation callback. Called with an absolute path when the user clicks
|
|
3548
|
+
* an internal link (context badge, citation, entity chip, etc.).
|
|
3549
|
+
* The product wires this to router.push (Next.js) or window.location.href.
|
|
3550
|
+
*/
|
|
3551
|
+
onNavigate?: (path: string) => void;
|
|
3552
|
+
/**
|
|
3553
|
+
* Optional: batch slug-check for ChatStructuredData.
|
|
3554
|
+
* When omitted, all slugs are assumed valid.
|
|
3555
|
+
*/
|
|
3556
|
+
onCheckSlugs?: SlugChecker;
|
|
3557
|
+
/**
|
|
3558
|
+
* Optional: navigate to the full-page chat view.
|
|
3559
|
+
* Called when the user clicks the Maximize button.
|
|
3560
|
+
*/
|
|
3561
|
+
onExpandToFullPage?: () => void;
|
|
3562
|
+
/** Pre-fill the input with this text */
|
|
3563
|
+
pendingMessage?: string | null;
|
|
3564
|
+
/** If true, auto-send pendingMessage instead of just filling the input */
|
|
3565
|
+
pendingAutoSend?: boolean;
|
|
3566
|
+
/** Called once the pending message has been consumed */
|
|
3567
|
+
onPendingMessageConsumed?: () => void;
|
|
3568
|
+
/** Quick-action chips shown after the first insight response */
|
|
3569
|
+
followUpChips?: string[];
|
|
3570
|
+
/**
|
|
3571
|
+
* Quick-action chips shown in the empty/intro state (before any messages).
|
|
3572
|
+
* Each chip sends its `prompt` when clicked. When omitted, the dock falls
|
|
3573
|
+
* back to rendering `context.suggestions` as chips (back-compat).
|
|
3574
|
+
*/
|
|
3575
|
+
quickActions?: CopilotQuickAction[];
|
|
3576
|
+
/** Start the dock in expanded state */
|
|
3577
|
+
defaultExpanded?: boolean;
|
|
3578
|
+
/** Assistant greeting shown above suggestion chips when chat is empty */
|
|
3579
|
+
seedGreeting?: string;
|
|
3580
|
+
/** Called when user closes/collapses the dock */
|
|
3581
|
+
onClose?: () => void;
|
|
3582
|
+
/**
|
|
3583
|
+
* Optional: persona list override.
|
|
3584
|
+
* Defaults to analyst/strategist/advisor. Pass empty array to hide the picker.
|
|
3585
|
+
*/
|
|
3586
|
+
personas?: Array<{
|
|
3587
|
+
id: string;
|
|
3588
|
+
label: string;
|
|
3589
|
+
labelAr: string;
|
|
3590
|
+
icon?: string;
|
|
3591
|
+
}>;
|
|
3592
|
+
/**
|
|
3593
|
+
* Token-scoped allowed tools (from /v1/copilot/config). Drives the Tools panel
|
|
3594
|
+
* + the `/` command menu. Undefined = no token restriction (panel hidden or
|
|
3595
|
+
* uses defaults). Each item: { slug, name, function_name? }.
|
|
3596
|
+
*/
|
|
3597
|
+
allowedTools?: Array<{
|
|
3598
|
+
slug: string;
|
|
3599
|
+
name: string;
|
|
3600
|
+
function_name?: string;
|
|
3601
|
+
}>;
|
|
3602
|
+
/**
|
|
3603
|
+
* Token-scoped allowed skills (from /v1/copilot/config). Drives the Skills
|
|
3604
|
+
* panel + the `/` command menu's activate-skill entries. Undefined = none.
|
|
3605
|
+
*/
|
|
3606
|
+
allowedSkills?: Array<{
|
|
3607
|
+
slug: string;
|
|
3608
|
+
name: string;
|
|
3609
|
+
}>;
|
|
3610
|
+
/**
|
|
3611
|
+
* B4: Optional markdown description of the current page. The dock stores
|
|
3612
|
+
* this and CopilotProvider injects it as intelligenceContext.data_summary.
|
|
3613
|
+
* For direct-mount consumers using their own chatState, wire page context
|
|
3614
|
+
* through their own send path. This prop is accepted but not auto-forwarded
|
|
3615
|
+
* from the dock itself (provider handles it).
|
|
3616
|
+
*/
|
|
3617
|
+
pageContext?: string;
|
|
3618
|
+
/**
|
|
3619
|
+
* E: token-scoped branding (from /v1/copilot/config.branding). Optional —
|
|
3620
|
+
* an omitted/empty object keeps the dock defaults. Backwards-compatible.
|
|
3621
|
+
*/
|
|
3622
|
+
branding?: {
|
|
3623
|
+
title?: string;
|
|
3624
|
+
titleAr?: string;
|
|
3625
|
+
primaryColor?: string;
|
|
3626
|
+
placeholder?: string;
|
|
3627
|
+
placeholderAr?: string;
|
|
3628
|
+
};
|
|
3629
|
+
/**
|
|
3630
|
+
* E: token-scoped UI toggles (from /v1/copilot/config.ui). Each defaults to
|
|
3631
|
+
* shown when undefined, so an unconfigured token keeps the full surface.
|
|
3632
|
+
*/
|
|
3633
|
+
uiConfig?: {
|
|
3634
|
+
showTools?: boolean;
|
|
3635
|
+
showSkills?: boolean;
|
|
3636
|
+
showAgents?: boolean;
|
|
3637
|
+
};
|
|
3638
|
+
/**
|
|
3639
|
+
* A2UI: callback fired when the user clicks an action chip in an ArtifactActions
|
|
3640
|
+
* artifact. The item.prompt (when set) should be sent as a new user message.
|
|
3641
|
+
* CopilotProvider wires this automatically — direct mount consumers may pass
|
|
3642
|
+
* their own handler here.
|
|
3643
|
+
*
|
|
3644
|
+
* When omitted the dock provides a default that calls chatState.onSend(item.prompt).
|
|
3645
|
+
*/
|
|
3646
|
+
onArtifactAction?: (item: A2UIActionItem) => void;
|
|
3647
|
+
/**
|
|
3648
|
+
* Phase-3 structured interaction channel. Fired when the user interacts with
|
|
3649
|
+
* a client_candidates, client_field_picker, client_diff_confirm, or
|
|
3650
|
+
* persona_starters artifact. The interaction carries a kind discriminator and
|
|
3651
|
+
* a structured payload — no free-text echo.
|
|
3652
|
+
*
|
|
3653
|
+
* CopilotProvider wires this to handleArtifactInteract (attaches the
|
|
3654
|
+
* interaction to the dispatch request, suppresses the user bubble).
|
|
3655
|
+
* Direct mount consumers may provide their own handler.
|
|
3656
|
+
*
|
|
3657
|
+
* When omitted the dock falls back to sending a synthesised hidden message
|
|
3658
|
+
* via chatState.onSend with { hideUserMessage: true, interaction }.
|
|
3659
|
+
*/
|
|
3660
|
+
onArtifactInteract?: (interaction: ArtifactInteraction) => void;
|
|
3661
|
+
}
|
|
3662
|
+
/**
|
|
3663
|
+
* UnifiedCopilotDock
|
|
3664
|
+
*
|
|
3665
|
+
* Floating AI copilot dock (collapsed bar / expanded panel). Supports three
|
|
3666
|
+
* dock positions (bottom, left, right), streaming agent steps, structured data
|
|
3667
|
+
* blocks, compare-factors cards, attachment uploads, thinking-mode toggle, and
|
|
3668
|
+
* conversation history.
|
|
3669
|
+
*
|
|
3670
|
+
* ALL app-specific dependencies removed:
|
|
3671
|
+
* - useCopilotChat → chatState prop (CopilotChatState seam)
|
|
3672
|
+
* - useAuth → removed (no user avatar needed in shared lib)
|
|
3673
|
+
* - useLanguage → language prop
|
|
3674
|
+
* - useRouter → onNavigate / onExpandToFullPage props
|
|
3675
|
+
* - bridge → onCheckSlugs prop (ChatStructuredData seam)
|
|
3676
|
+
* - Mode type → plain string in CopilotDockContext
|
|
3677
|
+
* - AuthImage → plain <img> or omitted
|
|
3678
|
+
*/
|
|
3679
|
+
declare const UnifiedCopilotDock: {
|
|
3680
|
+
({ chatState, context, language: languageProp, onNavigate, onCheckSlugs, onExpandToFullPage, pendingMessage, pendingAutoSend, onPendingMessageConsumed, followUpChips, quickActions, defaultExpanded, seedGreeting, onClose, personas, allowedTools, allowedSkills, branding, uiConfig, pageContext: _pageContext, onArtifactAction, onArtifactInteract, }: UnifiedCopilotDockProps): React__default.JSX.Element;
|
|
3681
|
+
displayName: string;
|
|
3682
|
+
};
|
|
3683
|
+
|
|
3684
|
+
/**
|
|
3685
|
+
* CopilotLauncher — @prism/ui F3
|
|
3686
|
+
*
|
|
3687
|
+
* A composable button that calls useCopilot().open(). Two variants:
|
|
3688
|
+
*
|
|
3689
|
+
* variant="fab" — floating action button (fixed bottom-right, z-40).
|
|
3690
|
+
* Good for apps without a header slot.
|
|
3691
|
+
* variant="header" — compact icon+label button for embedding in AppHeader's
|
|
3692
|
+
* right cluster or any nav bar.
|
|
3693
|
+
*
|
|
3694
|
+
* Bilingual label from the shared 'nav:copilot' key (EN: "Copilot", AR: "المساعد الذكي").
|
|
3695
|
+
* Language follows the shared LanguageProvider context automatically.
|
|
3696
|
+
*
|
|
3697
|
+
* Rules: Rule 7 (displayName, handle* events), Rule 8 (bilingual),
|
|
3698
|
+
* Rule 16 (Sentra style — Tailwind tokens only).
|
|
3699
|
+
*/
|
|
3700
|
+
|
|
3701
|
+
interface CopilotLauncherProps {
|
|
3702
|
+
/**
|
|
3703
|
+
* "fab" — floating action button (position: fixed, bottom-right).
|
|
3704
|
+
* "header" — compact icon+label for embedding in a top-nav cluster.
|
|
3705
|
+
* Default: "header".
|
|
3706
|
+
*/
|
|
3707
|
+
variant?: 'fab' | 'header';
|
|
3708
|
+
/** Additional Tailwind classes */
|
|
3709
|
+
className?: string;
|
|
3710
|
+
/**
|
|
3711
|
+
* Override label (skips the i18n lookup). Useful when the consuming app
|
|
3712
|
+
* has its own translation layer and wants to pass a pre-resolved string.
|
|
3713
|
+
*/
|
|
3714
|
+
label?: string;
|
|
3715
|
+
}
|
|
3716
|
+
declare const CopilotLauncher: {
|
|
3717
|
+
({ variant, className, label, }: CopilotLauncherProps): React__default.JSX.Element;
|
|
3718
|
+
displayName: string;
|
|
3719
|
+
};
|
|
3720
|
+
|
|
3721
|
+
/**
|
|
3722
|
+
* CopilotSelectionTrigger — smart "Ask Copilot" on text selection.
|
|
3723
|
+
*
|
|
3724
|
+
* Mount this once inside a CopilotProvider. When the user selects text anywhere
|
|
3725
|
+
* on the page (or within an optional `boundarySelector` subtree), a small
|
|
3726
|
+
* floating "Ask Copilot" button appears near the end of the selection. Clicking
|
|
3727
|
+
* it opens the copilot dock pre-filled with the selected text (optionally
|
|
3728
|
+
* auto-sent).
|
|
3729
|
+
*
|
|
3730
|
+
* Opt-in: it renders nothing until there's a qualifying selection.
|
|
3731
|
+
* Accessible: Escape dismisses; the button is a real <button> with an aria-label.
|
|
3732
|
+
* RTL-aware: the bubble offsets toward the selection's leading edge.
|
|
3733
|
+
*
|
|
3734
|
+
* <CopilotProvider client={client}>
|
|
3735
|
+
* …app…
|
|
3736
|
+
* <CopilotSelectionTrigger />
|
|
3737
|
+
* </CopilotProvider>
|
|
3738
|
+
*/
|
|
3739
|
+
|
|
3740
|
+
interface CopilotSelectionTriggerProps {
|
|
3741
|
+
/** Minimum selected character count before the trigger appears. Default 8. */
|
|
3742
|
+
minChars?: number;
|
|
3743
|
+
/** Maximum characters forwarded as the prompt (selection is trimmed). Default 2000. */
|
|
3744
|
+
maxChars?: number;
|
|
3745
|
+
/** Auto-send the prompt on click instead of pre-filling the input. Default false. */
|
|
3746
|
+
autoSend?: boolean;
|
|
3747
|
+
/** Override the button label. Defaults to the i18n "copilot:askCopilot". */
|
|
3748
|
+
label?: string;
|
|
3749
|
+
/**
|
|
3750
|
+
* Limit the trigger to selections inside this element subtree. Pass a CSS
|
|
3751
|
+
* selector (e.g. "[data-copilot-selectable]") or an element ref. When omitted,
|
|
3752
|
+
* the whole document is selectable.
|
|
3753
|
+
*/
|
|
3754
|
+
boundarySelector?: string;
|
|
3755
|
+
/**
|
|
3756
|
+
* Build the prompt from the selected text. Defaults to a short "Explain:"
|
|
3757
|
+
* framing in the active language. Return the raw selection to send it as-is.
|
|
3758
|
+
*/
|
|
3759
|
+
getPrompt?: (selectedText: string, language: 'en' | 'ar') => string;
|
|
3760
|
+
}
|
|
3761
|
+
declare const CopilotSelectionTrigger: {
|
|
3762
|
+
({ minChars, maxChars, autoSend, label, boundarySelector, getPrompt, }: CopilotSelectionTriggerProps): React__default.JSX.Element | null;
|
|
3763
|
+
displayName: string;
|
|
3764
|
+
};
|
|
3765
|
+
|
|
3766
|
+
interface ThreadMessage {
|
|
3767
|
+
id: string;
|
|
3768
|
+
role: 'user' | 'assistant';
|
|
3769
|
+
/** English content — always present */
|
|
3770
|
+
text_en: string;
|
|
3771
|
+
/** Arabic content — used when language === 'ar' */
|
|
3772
|
+
text_ar?: string;
|
|
3773
|
+
/** Legacy controller-slug artifacts (ArtifactViewer). */
|
|
3774
|
+
artifacts?: ArtifactPayload[];
|
|
3775
|
+
/** A2UI structured artifacts from the Cortex SSE stream (table/chart/card/…). */
|
|
3776
|
+
a2uiArtifacts?: A2UIArtifact[];
|
|
3777
|
+
}
|
|
3778
|
+
interface ChatThreadProps {
|
|
3779
|
+
messages: ThreadMessage[];
|
|
3780
|
+
/** The text currently being accumulated from the SSE stream */
|
|
3781
|
+
streamingText?: string;
|
|
3782
|
+
isStreaming?: boolean;
|
|
3783
|
+
/** UI language. Defaults to 'en'. */
|
|
3784
|
+
language?: 'en' | 'ar';
|
|
3785
|
+
/** Text direction. Inferred from language when not provided. */
|
|
3786
|
+
dir?: 'ltr' | 'rtl';
|
|
3787
|
+
}
|
|
3788
|
+
/**
|
|
3789
|
+
* ChatThread
|
|
3790
|
+
*
|
|
3791
|
+
* Renders the full conversation history plus an optional live streaming tail.
|
|
3792
|
+
* Bilingual: reads `text_ar` when language === 'ar', falls back to `text_en`.
|
|
3793
|
+
* RTL-aware: message alignment and avatar order flip for Arabic.
|
|
3794
|
+
* Auto-scrolls to the bottom on new messages or streaming token updates.
|
|
3795
|
+
*
|
|
3796
|
+
* All app deps removed — language/dir are plain props.
|
|
3797
|
+
*/
|
|
3798
|
+
declare const ChatThread: {
|
|
3799
|
+
({ messages, streamingText, isStreaming, language, dir, }: ChatThreadProps): React$1.JSX.Element;
|
|
3800
|
+
displayName: string;
|
|
3801
|
+
};
|
|
3802
|
+
|
|
3803
|
+
interface StreamingMessageProps {
|
|
3804
|
+
text: string;
|
|
3805
|
+
isStreaming: boolean;
|
|
3806
|
+
/** UI language. Defaults to 'en'. */
|
|
3807
|
+
language?: 'en' | 'ar';
|
|
3808
|
+
/** Text direction. Inferred from language when not provided. */
|
|
3809
|
+
dir?: 'ltr' | 'rtl';
|
|
3810
|
+
}
|
|
3811
|
+
/**
|
|
3812
|
+
* StreamingMessage
|
|
3813
|
+
*
|
|
3814
|
+
* Renders an assistant message that may still be receiving SSE token deltas.
|
|
3815
|
+
* While streaming, shows a pulsing cursor at the end.
|
|
3816
|
+
* Content renders as markdown via the shared MarkdownContent primitive
|
|
3817
|
+
* (GFM, skipHtml, links in new tab, RTL-safe logical padding).
|
|
3818
|
+
*
|
|
3819
|
+
* All app deps removed — language/dir are plain props.
|
|
3820
|
+
*/
|
|
3821
|
+
declare const StreamingMessage: {
|
|
3822
|
+
({ text, isStreaming, language, dir }: StreamingMessageProps): React$1.JSX.Element;
|
|
3823
|
+
displayName: string;
|
|
3824
|
+
};
|
|
3825
|
+
|
|
3826
|
+
interface ArtifactViewerProps {
|
|
3827
|
+
artifact: ArtifactPayload;
|
|
3828
|
+
/** UI language. Defaults to 'en'. */
|
|
3829
|
+
language?: 'en' | 'ar';
|
|
3830
|
+
/** Text direction. Inferred from language when not provided. */
|
|
3831
|
+
dir?: 'ltr' | 'rtl';
|
|
3832
|
+
}
|
|
3833
|
+
/**
|
|
3834
|
+
* ArtifactViewer
|
|
3835
|
+
*
|
|
3836
|
+
* Switches on `artifact.controller_slug` to render the appropriate visualisation.
|
|
3837
|
+
* Supported slugs:
|
|
3838
|
+
* - map-of-events
|
|
3839
|
+
* - timeline
|
|
3840
|
+
* - network-graph
|
|
3841
|
+
* - kpi-card
|
|
3842
|
+
*
|
|
3843
|
+
* All others render a JSON fallback. All app dependencies removed — language/dir
|
|
3844
|
+
* are plain props.
|
|
3845
|
+
*/
|
|
3846
|
+
declare const ArtifactViewer: {
|
|
3847
|
+
({ artifact, language, dir }: ArtifactViewerProps): React$1.JSX.Element;
|
|
3848
|
+
displayName: string;
|
|
3849
|
+
};
|
|
3850
|
+
|
|
3851
|
+
interface AgentStepsProps {
|
|
3852
|
+
steps: AgentStep[];
|
|
3853
|
+
isStreaming: boolean;
|
|
3854
|
+
/** UI language. Defaults to 'en'. */
|
|
3855
|
+
language?: 'en' | 'ar';
|
|
3856
|
+
/** Text direction. Inferred from language when not provided. */
|
|
3857
|
+
dir?: 'ltr' | 'rtl';
|
|
3858
|
+
}
|
|
3859
|
+
/**
|
|
3860
|
+
* AgentSteps
|
|
3861
|
+
*
|
|
3862
|
+
* Collapsible list of streaming agent tool-call steps with real-time state
|
|
3863
|
+
* indicators (active/complete/error). Bilingual EN/AR, RTL-aware.
|
|
3864
|
+
*
|
|
3865
|
+
* All app deps removed — language/dir are plain props.
|
|
3866
|
+
*/
|
|
3867
|
+
declare const AgentSteps: {
|
|
3868
|
+
({ steps, isStreaming, language, dir }: AgentStepsProps): React$1.JSX.Element | null;
|
|
3869
|
+
displayName: string;
|
|
3870
|
+
};
|
|
3871
|
+
|
|
3872
|
+
export { type A2UIActionItem, type A2UIActionsData, type A2UIArtifact$1 as A2UIArtifact, type A2UICardData, type A2UICardField, type A2UIChartData, type A2UIChartSeries, type A2UIClientCandidate, type A2UIClientCandidatesData, type A2UIClientDiffConfirmData, type A2UIClientDiffRow, type A2UIClientField, type A2UIClientFieldPickerData, type A2UIKind, type A2UIMarkdownData, type A2UIPersonaStarter, type A2UIPersonaStartersData, type A2UITableColumn, type A2UITableData, type ActivityBucket, AdminLayout, type AdminLayoutProps, type AdminSubNavItem, AgentSteps, type AlertMapItem, type AlertSeverity, type AppBrand, AppHeader, type AppHeaderProps, AppLayout, type AppLayoutProps, type AppNavGroup, type AppNavItem, AppPageShell, type AppPageShellProps, AppSidebar, type AppSidebarProps, type AppearanceMode, ArtifactActions, type ArtifactActionsProps, ArtifactCard, type ArtifactCardProps, ArtifactChart, type ArtifactChartProps, ArtifactClientCandidates, type ArtifactClientCandidatesProps, ArtifactClientDiffConfirm, type ArtifactClientDiffConfirmProps, ArtifactClientFieldPicker, type ArtifactClientFieldPickerProps, type ArtifactInteraction, ArtifactMarkdown, type ArtifactMarkdownProps, ArtifactPersonaStarters, type ArtifactPersonaStartersProps, ArtifactRenderer, type ArtifactRendererProps, ArtifactTable, type ArtifactTableProps, ArtifactViewer, AuthCard, type AuthCardBrand, type AuthClient, AuthErrorAlert, AuthFlow, type AuthLayout, AuthStepHeader, type BarPoint, type CardFilter, CardGrid, type CardGridLabels, ChatThread, CodeBlock, ColorPicker, type ColorPickerProps, ContextualSkeleton, type CopilotClient, type CopilotEvent, CopilotLauncher, CopilotProvider, type CopilotQuickAction, type CopilotRequest, CopilotSelectionTrigger, type CopilotSelectionTriggerProps, DEFAULT_LAYERS, DEFAULT_LEGEND_GROUPS, DEFAULT_REGION_PRESETS, DataState, type DataStateLabels, type DataStateProps, DataTable, type DataTableBulkAction, type DataTableColumnFilter, type DataTableColumnMeta, type DataTableDensity, type DataTableFilterType, type DataTableLanguage, type DataTableProps, type DataTableSelectOption, type DataTableServerCallbacks, type DataTableServerState, type DockPosition, DynamicIcon, DynamicSection, type DynamicSectionProps, EmptyState, type EmptyStateProps, EntityNetworkGraph, type EntityNetworkGraphProps, type ErrorFilter, ErrorTrackingPage, type ErrorTrackingPageProps, EventMapPanel, type EventMapPanelProps, type FeedbackAttachment, FeedbackButton, type FeedbackButtonProps, FeedbackHub, type FeedbackHubProps, type FeedbackItem, type FeedbackKind, FeedbackWidget, type FeedbackWidgetProps, ForgotForm, type GraphLink, type GraphNode, IconPicker, type IconPickerProps, type Issue$1 as Issue, type IssueAssignee, type IssueBreadcrumb, IssueDetail, type IssueDetailProps, type IssueLevel, type IssueSort, type IssueTag, IssuesList, type IssuesListProps, LANG_COOKIE_NAME, type LanguageContextValue, LanguageProvider, type LanguageProviderProps, type LegendGroup, type LegendItem, type LegendShapeType, LockScreen, type LockScreenProps, type LockScreenUser, type LogLevel, LoginForm, type LoginResult, Logo, type LogoProps, type LogoTone, type LogoVariant, type LogsFilter, LogsView, type LogsViewProps, MARKER_COLORS, MARKER_LABELS, type MapLayer, MapLayersPanel, type MapLayersPanelProps, MapLegend, type MapLegendProps, type MapMarker$1 as MapMarker, type MapMarkerType, MapPanel, type MapPanelProps, type MapRegionPreset, MapView, type MapViewProps, MarkdownContent, MarkdownEditor, type MarkdownEditorProps, MarkdownRenderer, type MarkdownRendererProps, MarkdownTable, type MarkdownView, MiniBarChart, type ModelOption, MotorFeedbackLauncher, type MotorFeedbackLauncherProps, NestedStepsEditor, type NestedStepsEditorProps, NetworkGraph, type NetworkGraphProps, type NewFeedback, OTPBoxGroup, type OtpResult, PIPELINE_STAGES, PageHeader, type PageHeaderProps, PasswordInput, PasswordLockScreen, type PasswordLockScreenProps, type PasswordLockScreenUser, type PasswordRule, PasswordStrengthMeter, type PickedLocation, type PipelineCard, type PipelineLane, type PipelineModel, type PluginActivitySummary, type PluginAppearanceFields, PluginAppearanceSection, type PluginAppearanceSectionProps, PluginCard, type PluginCatalogEntry, type PluginDetailIdentity, PluginDetailLayout, type PluginDetailLayoutProps, type PluginDetailTab, PluginHero, PluginHeroSkeleton, PluginPageHeader, PluginSectionCard, PluginSparkline, type ProfileSession, ProfileView, type ProfileViewProps, type RenderMapContext, ResetForm, type ResolvedIcon, RouteProgress, type RouteProgressProps, STEP_FIELD_REGISTRY, SectionBoard, type SectionBoardProps, type SectionModel, SectionSkeleton, SentraLoading, type ServiceLogRow, ServiceUnavailable, type ServiceUnavailableProps, SessionExpired, type SessionExpiredProps, SeverityChip, type SidebarConversation, type SidebarUser, SourceBadge, type SparklinePoint, type StackFrame, type StackFrameContextLine, StatCard, type StatCardProps, StatusBadge, type StatusBadgeProps, type StatusBadgeTone, type Step, type StepFieldDef, type StepFieldType, type StepMetrics7d, StepOptionsDialog, type StepOptionsDialogProps, StreamingMessage, type TestRunCallbacks, type TestRunCompletePayload, TestRunPanel, type TestRunPanelProps, type TestRunSavedItem, type TestRunStep, TwoFAForm, UnifiedCopilotDock, type UnlockCredentials, type Verify2FAResult, type View, ViewToggle, type ViewToggleProps, Wordmark, type WordmarkProps, Workflow, WorkflowEditor, type WorkflowEditorProps, type WorkflowPalette, WorkflowPipeline, type WorkflowPipelineProps, type WorkflowProps, type WorkflowSource, type WorkflowStep, type WorkflowStepLike, WorkflowStepNode, type WorkflowStepNodeProps, type WorkflowView, cn, computeRules, computeScore, feedbackButtonVariants, levelTone, resolveIcon, statValueVariants, statusBadgeVariants, useCopilot, useLanguage, useT };
|