@fayz-ai/admin 0.11.0 → 0.14.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/dist/{CommandPalette-2AL327XQ.js → CommandPalette-U7MMA2WH.js} +27 -4
- package/dist/CommandPalette-U7MMA2WH.js.map +1 -0
- package/dist/SubscriptionPage-4KP7DKA2.js +7 -0
- package/dist/{SubscriptionPage-NLZAZO4P.js.map → SubscriptionPage-4KP7DKA2.js.map} +1 -1
- package/dist/app/AdminShell.d.ts.map +1 -1
- package/dist/app/admin-app.d.ts.map +1 -1
- package/dist/app/config.d.ts +7 -0
- package/dist/app/config.d.ts.map +1 -1
- package/dist/{chunk-5O2UJAQ7.js → chunk-B6NVEKAJ.js} +2 -6
- package/dist/chunk-B6NVEKAJ.js.map +1 -0
- package/dist/components/billing/SubscriptionPage.d.ts.map +1 -1
- package/dist/components/chat/AssistantInvite.d.ts +10 -0
- package/dist/components/chat/AssistantInvite.d.ts.map +1 -1
- package/dist/components/chat/ChatFab.d.ts.map +1 -1
- package/dist/components/chat/ConfirmActionCard.d.ts.map +1 -1
- package/dist/components/chat/fab-anchor.d.ts +15 -0
- package/dist/components/chat/fab-anchor.d.ts.map +1 -0
- package/dist/components/connect/ConnectorsTab.d.ts.map +1 -1
- package/dist/components/connect/connector-map.generated.d.ts.map +1 -1
- package/dist/components/layout/CommandPalette.d.ts +5 -2
- package/dist/components/layout/CommandPalette.d.ts.map +1 -1
- package/dist/components/organization/PermissionProfilesTab.d.ts.map +1 -1
- package/dist/components/organization/TeamTab.d.ts.map +1 -1
- package/dist/components/plugins/PluginSettingsPanel.d.ts +11 -1
- package/dist/components/plugins/PluginSettingsPanel.d.ts.map +1 -1
- package/dist/components/settings/FieldRulesSettings.d.ts.map +1 -1
- package/dist/components/settings/SettingsPage.d.ts.map +1 -1
- package/dist/components/shared/PersonLink.d.ts +8 -1
- package/dist/components/shared/PersonLink.d.ts.map +1 -1
- package/dist/components/shared/RecordPickerModal.d.ts +7 -1
- package/dist/components/shared/RecordPickerModal.d.ts.map +1 -1
- package/dist/crud/CrudDetailPage.d.ts.map +1 -1
- package/dist/crud/CrudListView.d.ts +17 -4
- package/dist/crud/CrudListView.d.ts.map +1 -1
- package/dist/crud/CrudPage.d.ts +4 -1
- package/dist/crud/CrudPage.d.ts.map +1 -1
- package/dist/crud/archetype-lookup.d.ts +13 -0
- package/dist/crud/archetype-lookup.d.ts.map +1 -1
- package/dist/crud/archetypes/OrderDetailView.d.ts.map +1 -1
- package/dist/crud/archetypes/OrderFormView.d.ts +4 -1
- package/dist/crud/archetypes/OrderFormView.d.ts.map +1 -1
- package/dist/crud/archetypes/OrderListView.d.ts +1 -1
- package/dist/crud/archetypes/OrderListView.d.ts.map +1 -1
- package/dist/hooks/useAuth.d.ts.map +1 -1
- package/dist/hooks/useGlobalSearch.d.ts +3 -1
- package/dist/hooks/useGlobalSearch.d.ts.map +1 -1
- package/dist/hooks/useModuleNavigation.d.ts.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1542 -1128
- package/dist/index.js.map +1 -1
- package/dist/lib/assistant-invite.d.ts +18 -0
- package/dist/lib/assistant-invite.d.ts.map +1 -1
- package/dist/lib/cache.d.ts +2 -17
- package/dist/lib/cache.d.ts.map +1 -1
- package/dist/plugins/QuickActionsButton.d.ts +13 -4
- package/dist/plugins/QuickActionsButton.d.ts.map +1 -1
- package/dist/plugins/WidgetSlot.d.ts +12 -1
- package/dist/plugins/WidgetSlot.d.ts.map +1 -1
- package/dist/projects/ProjectsSettings.d.ts.map +1 -1
- package/dist/stores/createCrudStore.d.ts +8 -0
- package/dist/stores/createCrudStore.d.ts.map +1 -1
- package/dist/theme/utils.d.ts.map +1 -1
- package/dist/types/entity-lookup.d.ts +9 -0
- package/dist/types/entity-lookup.d.ts.map +1 -1
- package/package.json +9 -9
- package/dist/CommandPalette-2AL327XQ.js.map +0 -1
- package/dist/SubscriptionPage-NLZAZO4P.js +0 -7
- package/dist/chunk-5O2UJAQ7.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -2,8 +2,8 @@ export { getScheduleBlockConfig, setScheduleBlockConfig, subscribeScheduleBlockC
|
|
|
2
2
|
import { getFayzSupabaseClientOptional, createFayzSupabaseClient, createSupabaseOrgAdapter, createMockOrgAdapter, getFayzSupabaseClient } from './chunk-OI7RYSTM.js';
|
|
3
3
|
export { createFayzSupabaseClient, createMockOrgAdapter, createSupabaseOrgAdapter, getFayzSupabaseClient, getFayzSupabaseClientOptional } from './chunk-OI7RYSTM.js';
|
|
4
4
|
export { ImportWizard } from './chunk-UMRN6427.js';
|
|
5
|
-
import { useLimitGuard, invalidateLimit, useLimit, useUpgradeModalStore,
|
|
6
|
-
export { AccessProvider, UPGRADE_URL, agentDenial, checkAccess, getAccessSnapshot, guardLimit, invalidateLimit, isEntitledByPlan, resolveAccess, useAccess, useAccessOptional, useLimit, useLimitGuard, useModuleNavAccess, useUpgradeModalStore } from './chunk-
|
|
5
|
+
import { useLimitGuard, invalidateLimit, useLimit, useUpgradeModalStore, cn as cn$1, checkAccess, guardLimit, featureDisplayName, PlanFeatureItem, useAccessOptional, AccessProvider, CORE_LIMIT_DECLARATIONS, entityDerivedLimitDeclarations, getPlanEntitlements, resolvePlanCurrency } from './chunk-B6NVEKAJ.js';
|
|
6
|
+
export { AccessProvider, UPGRADE_URL, agentDenial, checkAccess, getAccessSnapshot, guardLimit, invalidateLimit, isEntitledByPlan, resolveAccess, useAccess, useAccessOptional, useLimit, useLimitGuard, useModuleNavAccess, useUpgradeModalStore } from './chunk-B6NVEKAJ.js';
|
|
7
7
|
import { useTranslation as useTranslation$1 } from './chunk-YUHCC7JY.js';
|
|
8
8
|
import { useBillingStore, resolvePlanBadge } from './chunk-VN5NTK26.js';
|
|
9
9
|
export { useBillingStore } from './chunk-VN5NTK26.js';
|
|
@@ -11,23 +11,23 @@ import { useOrganizationStore, useTenantOptional, OrgProvider, useOrgAdapterOpti
|
|
|
11
11
|
export { ORG_CACHE_TTL_MS, OrgProvider, clearOrgSnapshot, getPersistedOrgId, readOrgSnapshot, useOrgAdapter, useOrgAdapterOptional, useOrganizationStore, useTenant, useTenantOptional } from './chunk-PNAJODZM.js';
|
|
12
12
|
import { usePermissionOptional, usePermissionsStore, PermissionsProvider } from './chunk-VTEP2AQX.js';
|
|
13
13
|
export { PermissionsProvider, useHasPermission, usePermission, usePermissionOptional, usePermissions, usePermissionsStore } from './chunk-VTEP2AQX.js';
|
|
14
|
-
import * as
|
|
15
|
-
import
|
|
16
|
-
import { hashRouterAdapter, getSupabaseClientOptional, deriveEntityKey, registerEntity, getActiveTenantId, resolveDataProvider, bulkRemove, emitDomainEvent, entityEventKey, useTranslation, useDataChanged, exportCSV, formatDateTime as formatDateTime$1, formatDate as formatDate$1, formatCurrency as formatCurrency$1,
|
|
14
|
+
import * as React65 from 'react';
|
|
15
|
+
import React65__default, { createContext, useMemo, useState, useRef, useCallback, useEffect, useContext } from 'react';
|
|
16
|
+
import { hashRouterAdapter, getSupabaseClientOptional, deriveEntityKey, registerEntity, getActiveTenantId, resolveDataProvider, bulkRemove, emitDomainEvent, entityEventKey, useTranslation, useDataChanged, emitDataChanged, exportCSV, formatDateTime as formatDateTime$1, formatDate as formatDate$1, formatCurrency as formatCurrency$1, bulkCreate, matchesRange, isConnectorCategory, reportAppError, usePluginRuntimeOptional, getWidgetsForZone, resolvePluginComponent, setCurrentLocale, resolvePluginRuntime, PluginRuntimeProvider, I18nProvider, getAllEntities, defineApp, registerScaffold, getCountry, DEFAULT_COUNTRY, useActiveTenantId, maskPhone, useConnectorsForPlugin, renderApp as renderApp$1, unmaskPhone, parseRangeFilter, isFilterObject, connectionKey, useManifest, usePluginRuntime, installGlobalErrorHandlers, mergeTranslations, coreTranslations, attachPersistentCache, getPersistentCache, createMockProvider, listConnections, connectorPlanes, connectorPermissions, connectorEntities, preferredPlane, connectorDirection, searchEverything, registerEventSink, getComponent, getPluginFactory, connectorSettings, groupedPermissions, invocationPlane, missingRequiredSettings, isSettingSet, connectorSubscribesTo, eventKeyMatches } from '@fayz-ai/core';
|
|
17
17
|
export { ConnectorRuntimeTokenUnavailableError, createSafeDataProvider, formatDate, formatDateTime, getActiveLocale, getActiveTenantId, getConnectorRuntimeTokenSource, getCurrentLocale, getSupabaseClientOptional, preloadLocale, resolveBackendEnv, setConnectorRuntimeTokenSource, setCurrentLocale, tl, useActiveTenantId } from '@fayz-ai/core';
|
|
18
18
|
import { usePasswordSetupGate, SetPasswordPage, AuthGate, AuthProvider, createAuthRuntime } from '@fayz-ai/plugin-auth';
|
|
19
19
|
export { LoginPage } from '@fayz-ai/plugin-auth';
|
|
20
|
-
import { toast, usePageTrailParent, navigateToCrumb, Button, PageHeader, ConfirmDialog, FilterChip, Dropdown, DropdownTrigger, Hint, cn, DropdownContent, DropdownLabel, DropdownItem, DropdownSeparator,
|
|
20
|
+
import { toast, usePageTrailParent, navigateToCrumb, Button, PageHeader, ConfirmDialog, FilterChip, Dropdown, DropdownTrigger, Hint, cn, DropdownContent, DropdownLabel, DropdownItem, DropdownSeparator, RefreshButton, PageHeaderActions, PageTabs, StatTiles, Card, BulkActionBar, DataTable, Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, ModalFooter, Badge, useModuleLayout, ICON_MAP, getLucideIcon, Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetBody, useLayoutStore, Skeleton, Input, useSaveBar, useBackHandler, SubpageHeader, Separator, Tabs, TabsList, TabsTrigger, TabsContent, CardContent, ToastProvider, NavTransitionProvider, ListView, Thumbnail, SearchSelect, CurrencyInput, SearchField, ChevronPager, Popover, PopoverTrigger, PopoverContent, PhoneLink, normalizePhone, ModalPortal, ModalOverlay, ModalBody, SearchCombobox, usePageTrail, AppShellSkeleton, ModuleLayoutProvider, AppShell, PageTransition, PageRail, RailNavItem, createFayzTheme, Checkbox, MarkdownEditor, Switch, Markdown, PageTrail, Avatar, AvatarImage, AvatarFallback, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, CardTitle, CardDescription, DropdownSub, DropdownSubTrigger, DropdownSubContent, DropdownRadioGroup, DropdownRadioItem, CardHeader, CardFooter } from '@fayz-ai/ui';
|
|
21
21
|
export { createFayzTheme, fayzThemePresets } from '@fayz-ai/ui';
|
|
22
22
|
import * as LucideIcons3 from 'lucide-react';
|
|
23
|
-
import { Globe, Store, LayoutTemplate, Trash2, Upload, Search, ArrowDown, ArrowUp, ArrowUpDown, Check,
|
|
23
|
+
import { Globe, Store, LayoutTemplate, Trash2, Upload, Search, ArrowDown, ArrowUp, ArrowUpDown, Check, Download, ChevronLeft, ChevronRight, AlertTriangle, Pencil, Plus, ChevronDown, Inbox, Package, X, Sparkles, Plug, Loader2, ArrowDownToLine, ArrowUpFromLine, CheckCircle2, Crown, ArrowRight, ArrowLeft, SquarePen, Settings2, MessageSquare, RotateCcw, Copy, ChevronsUpDown, ExternalLink, PenSquare, RefreshCw, XCircle, Clock, Star, Edit, Eye, ShoppingBag, Settings, Mail, MessageCircle, Cake, Calendar, TableProperties, Mic, BookOpen, Paperclip, ShieldCheck, Infinity, Play, Square, StickyNote, ArrowUpRight, Pause, CalendarDays, CircleCheckBig, UserX, Ban, CircleAlert, CircleEllipsis, FileText, CircleDashed, Power, File, FileImage, FileSpreadsheet, AlertCircle, CreditCard, Users, MapPin, SlidersHorizontal, Puzzle, Building2, User, Shield, Palette, ShieldAlert, UserCog, LogOut, Bell, PinOff, Pin, ImagePlus, Database, Radio, Zap, Save, UserPlus, MoreHorizontal, Sun, Moon, Monitor, Languages, CheckCheck, Info, CheckSquare2, Camera, KeyRound, Bug, Wrench, Heart, Briefcase, BarChart3, Tag, Truck } from 'lucide-react';
|
|
24
24
|
import { create, useStore } from 'zustand';
|
|
25
25
|
import { useAuthStore, useAuth } from '@fayz-ai/auth';
|
|
26
26
|
export { useAuth } from '@fayz-ai/auth';
|
|
27
|
+
import { createPortal } from 'react-dom';
|
|
28
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
27
29
|
import { profileHasSystemPermission, mergeLimitDeclarations } from '@fayz-ai/core/access';
|
|
28
30
|
import { createFayzAgentClient } from '@fayz-ai/sdk/agent';
|
|
29
|
-
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
30
|
-
import { createPortal } from 'react-dom';
|
|
31
31
|
import { getConnectorCredentialSink, ConnectorOAuthStarterMissingError } from '@fayz-ai/sdk';
|
|
32
32
|
export { ConnectorCredentialSinkError, ConnectorOAuthError, ConnectorOAuthStarterMissingError, createFayzConnectorCredentialSink, createFayzConnectorOAuthStarter, fayz, fayzConnectorOAuth, getConnectorCredentialSink, getConnectorOAuthStarter, setConnectorCredentialSink, setConnectorOAuthStarter, startConnectorOAuth } from '@fayz-ai/sdk';
|
|
33
33
|
import { createFayzEventsClient } from '@fayz-ai/sdk/events';
|
|
@@ -843,7 +843,7 @@ function getServerVersion() {
|
|
|
843
843
|
return 0;
|
|
844
844
|
}
|
|
845
845
|
function useAssistantActivity() {
|
|
846
|
-
|
|
846
|
+
React65.useSyncExternalStore(subscribe, getVersion, getServerVersion);
|
|
847
847
|
return pickActivity(activities);
|
|
848
848
|
}
|
|
849
849
|
function pickActivity(list) {
|
|
@@ -853,18 +853,18 @@ function pickActivity(list) {
|
|
|
853
853
|
return pool.find((a) => a.kind === "recording") ?? pool[0];
|
|
854
854
|
}
|
|
855
855
|
function useAssistantLaunchers() {
|
|
856
|
-
|
|
856
|
+
React65.useSyncExternalStore(subscribe, getVersion, getServerVersion);
|
|
857
857
|
return launchers;
|
|
858
858
|
}
|
|
859
859
|
function usePublishAssistantActivity(activity) {
|
|
860
860
|
const id = activity?.id;
|
|
861
861
|
const key = activity ? `${activity.id}|${activity.kind}|${activity.label}|${activity.state}|${activity.elapsedMs ?? ""}|${(activity.actions ?? []).map((a) => a.intent).join(",")}` : null;
|
|
862
|
-
const ref =
|
|
862
|
+
const ref = React65.useRef(activity);
|
|
863
863
|
ref.current = activity;
|
|
864
|
-
|
|
864
|
+
React65.useEffect(() => {
|
|
865
865
|
if (ref.current) publishAssistantActivity(ref.current);
|
|
866
866
|
}, [key]);
|
|
867
|
-
|
|
867
|
+
React65.useEffect(() => {
|
|
868
868
|
if (!id) return;
|
|
869
869
|
return () => withdrawAssistantActivity(id);
|
|
870
870
|
}, [id]);
|
|
@@ -872,12 +872,12 @@ function usePublishAssistantActivity(activity) {
|
|
|
872
872
|
function useRegisterAssistantLauncher(launcher) {
|
|
873
873
|
const id = launcher?.id;
|
|
874
874
|
const key = launcher ? `${launcher.id}|${launcher.label}|${launcher.disabled ? "1" : "0"}` : null;
|
|
875
|
-
const ref =
|
|
875
|
+
const ref = React65.useRef(launcher);
|
|
876
876
|
ref.current = launcher;
|
|
877
|
-
|
|
877
|
+
React65.useEffect(() => {
|
|
878
878
|
if (ref.current) registerAssistantLauncher(ref.current);
|
|
879
879
|
}, [key]);
|
|
880
|
-
|
|
880
|
+
React65.useEffect(() => {
|
|
881
881
|
if (!id) return;
|
|
882
882
|
return () => unregisterAssistantLauncher(id);
|
|
883
883
|
}, [id]);
|
|
@@ -941,17 +941,17 @@ function useRightRailPanel(panel) {
|
|
|
941
941
|
const icon = panel?.icon;
|
|
942
942
|
const badgeCount = panel?.badge?.count;
|
|
943
943
|
const badgeTone = panel?.badge?.tone;
|
|
944
|
-
const initial =
|
|
945
|
-
|
|
944
|
+
const initial = React65.useRef({ label, icon });
|
|
945
|
+
React65.useEffect(() => {
|
|
946
946
|
if (!id || !Component2) return;
|
|
947
947
|
register({ id, label: initial.current.label ?? id, order, Component: Component2, icon: initial.current.icon });
|
|
948
948
|
return () => unregister(id);
|
|
949
949
|
}, [id, order, Component2, register, unregister]);
|
|
950
|
-
|
|
950
|
+
React65.useEffect(() => {
|
|
951
951
|
if (!id) return;
|
|
952
952
|
updateMeta(id, { label, icon });
|
|
953
953
|
}, [id, label, icon, updateMeta]);
|
|
954
|
-
|
|
954
|
+
React65.useEffect(() => {
|
|
955
955
|
if (!id) return;
|
|
956
956
|
updateBadge(id, badgeCount !== void 0 ? { count: badgeCount, tone: badgeTone } : void 0);
|
|
957
957
|
}, [id, badgeCount, badgeTone, updateBadge]);
|
|
@@ -997,15 +997,29 @@ function rememberDismissal(id) {
|
|
|
997
997
|
var useAssistantInviteStore = create((set, get) => ({
|
|
998
998
|
invite: null,
|
|
999
999
|
stage: "dock",
|
|
1000
|
+
dockBox: null,
|
|
1001
|
+
leaving: null,
|
|
1000
1002
|
setInvite: (invite, id) => {
|
|
1001
1003
|
if (!invite) {
|
|
1002
1004
|
if (id && get().invite?.id !== id) return;
|
|
1003
|
-
|
|
1005
|
+
const { invite: going, dockBox } = get();
|
|
1006
|
+
set({
|
|
1007
|
+
invite: null,
|
|
1008
|
+
stage: "dock",
|
|
1009
|
+
dockBox: null,
|
|
1010
|
+
leaving: going && dockBox ? { invite: going, box: dockBox } : null
|
|
1011
|
+
});
|
|
1004
1012
|
return;
|
|
1005
1013
|
}
|
|
1006
1014
|
const hero = invite.auto !== false && !dismissedIds().includes(invite.id);
|
|
1007
|
-
set({ invite, stage: hero ? "hero" : "dock" });
|
|
1015
|
+
set({ invite, stage: hero ? "hero" : "dock", leaving: null });
|
|
1016
|
+
},
|
|
1017
|
+
setDockBox: (box) => {
|
|
1018
|
+
const current = get().dockBox;
|
|
1019
|
+
if (current?.left === box?.left && current?.width === box?.width) return;
|
|
1020
|
+
set({ dockBox: box });
|
|
1008
1021
|
},
|
|
1022
|
+
endLeave: () => set({ leaving: null }),
|
|
1009
1023
|
dismiss: () => {
|
|
1010
1024
|
const { invite } = get();
|
|
1011
1025
|
if (invite) rememberDismissal(invite.id);
|
|
@@ -1013,85 +1027,480 @@ var useAssistantInviteStore = create((set, get) => ({
|
|
|
1013
1027
|
}
|
|
1014
1028
|
}));
|
|
1015
1029
|
|
|
1016
|
-
// src/
|
|
1017
|
-
var
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1030
|
+
// src/components/chat/fab-anchor.ts
|
|
1031
|
+
var FAB_MARGIN_RIGHT = 21;
|
|
1032
|
+
var FAB_SIZE = 48;
|
|
1033
|
+
var DOCK_MAX_WIDTH = 640;
|
|
1034
|
+
var MORPH_MS = 380;
|
|
1035
|
+
var MORPH_EASE = "cubic-bezier(0.22, 1, 0.36, 1)";
|
|
1036
|
+
function fabRightEdge(railOpen, railWidth) {
|
|
1037
|
+
if (typeof window === "undefined") return 0;
|
|
1038
|
+
return window.innerWidth - (railOpen ? railWidth + FAB_MARGIN_RIGHT : FAB_MARGIN_RIGHT);
|
|
1039
|
+
}
|
|
1040
|
+
function AssistantInvite({ className, ...def }) {
|
|
1041
|
+
const setInvite = useAssistantInviteStore((s) => s.setInvite);
|
|
1042
|
+
const stage = useAssistantInviteStore((s) => s.stage);
|
|
1043
|
+
const dismiss = useAssistantInviteStore((s) => s.dismiss);
|
|
1044
|
+
const railOpen = useRightRailStore((s) => s.open);
|
|
1045
|
+
const hasAssistant = useRightRailStore((s) => s.panels.some((p) => p.id === "chat"));
|
|
1046
|
+
const { id, persona, headline, pitch, description, placeholder, auto } = def;
|
|
1047
|
+
const suggestions = def.suggestions;
|
|
1048
|
+
const suggestionKey = JSON.stringify(suggestions ?? []);
|
|
1049
|
+
React65.useEffect(() => {
|
|
1050
|
+
if (!hasAssistant) return;
|
|
1051
|
+
setInvite({
|
|
1052
|
+
id,
|
|
1053
|
+
persona,
|
|
1054
|
+
headline,
|
|
1055
|
+
pitch,
|
|
1056
|
+
description,
|
|
1057
|
+
placeholder,
|
|
1058
|
+
auto,
|
|
1059
|
+
suggestions: JSON.parse(suggestionKey)
|
|
1060
|
+
});
|
|
1061
|
+
return () => setInvite(null, id);
|
|
1062
|
+
}, [hasAssistant, id, persona, headline, pitch, description, placeholder, auto, suggestionKey, setInvite]);
|
|
1063
|
+
const anchorRef = React65.useRef(null);
|
|
1064
|
+
const [box, setBox] = React65.useState(null);
|
|
1065
|
+
const docked = stage === "dock" && !railOpen && hasAssistant;
|
|
1066
|
+
const showing = hasAssistant && (stage === "hero" || docked);
|
|
1067
|
+
React65.useEffect(() => {
|
|
1068
|
+
if (!showing) return;
|
|
1069
|
+
const el = anchorRef.current;
|
|
1070
|
+
if (!el) return;
|
|
1071
|
+
const measure = () => {
|
|
1072
|
+
const rect = el.getBoundingClientRect();
|
|
1073
|
+
setBox({ left: rect.left, width: rect.width, top: rect.top });
|
|
1074
|
+
};
|
|
1075
|
+
measure();
|
|
1076
|
+
const observer = new ResizeObserver(measure);
|
|
1077
|
+
observer.observe(el);
|
|
1078
|
+
window.addEventListener("resize", measure);
|
|
1079
|
+
window.addEventListener("scroll", measure, true);
|
|
1080
|
+
return () => {
|
|
1081
|
+
observer.disconnect();
|
|
1082
|
+
window.removeEventListener("resize", measure);
|
|
1083
|
+
window.removeEventListener("scroll", measure, true);
|
|
1084
|
+
};
|
|
1085
|
+
}, [showing]);
|
|
1086
|
+
const setDockBox = useAssistantInviteStore((s) => s.setDockBox);
|
|
1087
|
+
const wide = useWideViewport();
|
|
1088
|
+
React65.useEffect(() => {
|
|
1089
|
+
if (!docked || !wide || !box) {
|
|
1090
|
+
setDockBox(null);
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
setDockBox({ left: box.left + box.width / 2, width: Math.min(box.width, DOCK_MAX_WIDTH) });
|
|
1094
|
+
}, [docked, wide, box?.left, box?.width, setDockBox]);
|
|
1095
|
+
if (!hasAssistant) return null;
|
|
1096
|
+
const floating = box && stage === "hero" ? /* @__PURE__ */ jsx(InviteHero, { def, box, onDismiss: dismiss }) : box && docked ? /* @__PURE__ */ jsx(InviteDock, { def, left: box.left + box.width / 2, maxWidth: box.width }) : null;
|
|
1097
|
+
return /* @__PURE__ */ jsx("div", { ref: anchorRef, className: cn$1("h-0 w-full", className), "aria-hidden": !showing, children: floating && typeof document !== "undefined" ? createPortal(floating, document.body) : null });
|
|
1098
|
+
}
|
|
1099
|
+
function useAsk() {
|
|
1100
|
+
const queuePrompt = useChatStore((s) => s.queuePrompt);
|
|
1101
|
+
const dismiss = useAssistantInviteStore((s) => s.dismiss);
|
|
1102
|
+
return React65.useCallback(
|
|
1103
|
+
(text) => {
|
|
1104
|
+
const trimmed = text.trim();
|
|
1105
|
+
if (!trimmed) return;
|
|
1106
|
+
dismiss();
|
|
1107
|
+
queuePrompt(trimmed);
|
|
1038
1108
|
},
|
|
1109
|
+
[queuePrompt, dismiss]
|
|
1110
|
+
);
|
|
1111
|
+
}
|
|
1112
|
+
function InviteHero({
|
|
1113
|
+
def,
|
|
1114
|
+
box,
|
|
1115
|
+
onDismiss
|
|
1116
|
+
}) {
|
|
1117
|
+
const { t } = useTranslation$1();
|
|
1118
|
+
const user = useAuthStore((s) => s.user);
|
|
1119
|
+
const ask = useAsk();
|
|
1120
|
+
const [draft, setDraft] = React65.useState("");
|
|
1121
|
+
const name = (user?.fullName || user?.email || "").split(/[\s@]/)[0];
|
|
1122
|
+
React65.useEffect(() => {
|
|
1123
|
+
const onKey = (event) => {
|
|
1124
|
+
if (event.key === "Escape") onDismiss();
|
|
1125
|
+
};
|
|
1126
|
+
window.addEventListener("keydown", onKey);
|
|
1127
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
1128
|
+
}, [onDismiss]);
|
|
1129
|
+
return /* @__PURE__ */ jsxs(
|
|
1130
|
+
"section",
|
|
1039
1131
|
{
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1132
|
+
className: cn$1(
|
|
1133
|
+
"fixed z-30 flex flex-col items-center justify-center overflow-y-auto px-4 pb-14 text-center",
|
|
1134
|
+
"bg-background/95 backdrop-blur-sm motion-safe:animate-in motion-safe:fade-in-0"
|
|
1135
|
+
),
|
|
1136
|
+
style: { left: box.left, width: box.width, top: box.top, bottom: 0 },
|
|
1137
|
+
"aria-label": def.persona ?? t("chat.defaultTitle"),
|
|
1138
|
+
children: [
|
|
1139
|
+
/* @__PURE__ */ jsx(
|
|
1140
|
+
"button",
|
|
1141
|
+
{
|
|
1142
|
+
type: "button",
|
|
1143
|
+
onClick: onDismiss,
|
|
1144
|
+
"aria-label": t("assistant.invite.dismiss"),
|
|
1145
|
+
title: t("assistant.invite.dismiss"),
|
|
1146
|
+
className: "absolute right-1 top-2 inline-flex h-8 w-8 items-center justify-center rounded-lg text-muted-foreground/60 transition-colors hover:bg-muted hover:text-foreground",
|
|
1147
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
|
|
1148
|
+
}
|
|
1149
|
+
),
|
|
1150
|
+
/* @__PURE__ */ jsx("h2", { className: "max-w-2xl text-balance text-[26px] font-semibold leading-tight tracking-tight text-foreground sm:text-[32px]", children: def.headline.replace("{{name}}", name) }),
|
|
1151
|
+
/* @__PURE__ */ jsx(
|
|
1152
|
+
InviteComposer,
|
|
1153
|
+
{
|
|
1154
|
+
className: "mt-7 w-full max-w-3xl",
|
|
1155
|
+
placeholder: def.placeholder ?? t("assistant.invite.placeholder"),
|
|
1156
|
+
value: draft,
|
|
1157
|
+
onChange: setDraft,
|
|
1158
|
+
onSubmit: () => {
|
|
1159
|
+
ask(draft);
|
|
1160
|
+
setDraft("");
|
|
1161
|
+
},
|
|
1162
|
+
size: "lg"
|
|
1163
|
+
}
|
|
1164
|
+
),
|
|
1165
|
+
def.suggestions && def.suggestions.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-4 flex flex-wrap items-center justify-center gap-2", children: def.suggestions.slice(0, 4).map((suggestion) => /* @__PURE__ */ jsx(
|
|
1166
|
+
"button",
|
|
1167
|
+
{
|
|
1168
|
+
type: "button",
|
|
1169
|
+
onClick: () => ask(suggestion.prompt ?? suggestion.label),
|
|
1170
|
+
className: cn$1(
|
|
1171
|
+
"rounded-full border border-border/70 bg-card px-4 py-2 text-[13px] text-foreground/80 transition-colors",
|
|
1172
|
+
"hover:border-border hover:bg-muted hover:text-foreground",
|
|
1173
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
1174
|
+
),
|
|
1175
|
+
children: suggestion.label
|
|
1176
|
+
},
|
|
1177
|
+
suggestion.label
|
|
1178
|
+
)) })
|
|
1179
|
+
]
|
|
1180
|
+
}
|
|
1181
|
+
);
|
|
1182
|
+
}
|
|
1183
|
+
function useMorphIn(skip = false) {
|
|
1184
|
+
const [entered, setEntered] = React65.useState(() => skip || prefersReducedMotion());
|
|
1185
|
+
React65.useEffect(() => {
|
|
1186
|
+
if (entered) return;
|
|
1187
|
+
let second = 0;
|
|
1188
|
+
const first = requestAnimationFrame(() => {
|
|
1189
|
+
second = requestAnimationFrame(() => setEntered(true));
|
|
1190
|
+
});
|
|
1191
|
+
return () => {
|
|
1192
|
+
cancelAnimationFrame(first);
|
|
1193
|
+
cancelAnimationFrame(second);
|
|
1194
|
+
};
|
|
1195
|
+
}, [entered]);
|
|
1196
|
+
return entered;
|
|
1197
|
+
}
|
|
1198
|
+
function prefersReducedMotion() {
|
|
1199
|
+
return typeof window !== "undefined" && !!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
1200
|
+
}
|
|
1201
|
+
var lastDockExit = null;
|
|
1202
|
+
var RESUME_WINDOW_MS = 700;
|
|
1203
|
+
function useWideViewport() {
|
|
1204
|
+
const [wide, setWide] = React65.useState(
|
|
1205
|
+
() => typeof window !== "undefined" && !!window.matchMedia?.("(min-width: 768px)").matches
|
|
1206
|
+
);
|
|
1207
|
+
React65.useEffect(() => {
|
|
1208
|
+
const query = window.matchMedia?.("(min-width: 768px)");
|
|
1209
|
+
if (!query) return;
|
|
1210
|
+
const sync = () => setWide(query.matches);
|
|
1211
|
+
sync();
|
|
1212
|
+
query.addEventListener("change", sync);
|
|
1213
|
+
return () => query.removeEventListener("change", sync);
|
|
1214
|
+
}, []);
|
|
1215
|
+
return wide;
|
|
1216
|
+
}
|
|
1217
|
+
function morphStyles(box, railOpen, railWidth) {
|
|
1218
|
+
const rightEdge = box.left + box.width / 2;
|
|
1219
|
+
const dx = fabRightEdge(railOpen, railWidth) - rightEdge;
|
|
1220
|
+
return {
|
|
1221
|
+
open: {
|
|
1222
|
+
transform: "translateX(-50%)",
|
|
1223
|
+
clipPath: "inset(0 round 9999px)"
|
|
1045
1224
|
},
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
label: "Use",
|
|
1050
|
-
type: "select",
|
|
1051
|
-
options: ["both", "shipping", "billing"],
|
|
1052
|
-
hint: "Defaults to 'both'."
|
|
1225
|
+
collapsed: {
|
|
1226
|
+
transform: `translateX(calc(-50% + ${dx}px))`,
|
|
1227
|
+
clipPath: `inset(0 0 0 ${Math.max(0, box.width - FAB_SIZE)}px round 9999px)`
|
|
1053
1228
|
},
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1229
|
+
transition: `transform ${MORPH_MS}ms ${MORPH_EASE}, clip-path ${MORPH_MS}ms ${MORPH_EASE}`
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
function InviteDock({ def, left, maxWidth }) {
|
|
1233
|
+
const { t } = useTranslation$1();
|
|
1234
|
+
const ask = useAsk();
|
|
1235
|
+
const setOpen = useChatStore((s) => s.setOpen);
|
|
1236
|
+
const railOpen = useRightRailStore((s) => s.open);
|
|
1237
|
+
const railWidth = useRightRailStore((s) => s.width);
|
|
1238
|
+
const [draft, setDraft] = React65.useState("");
|
|
1239
|
+
const resumed = React65.useRef(
|
|
1240
|
+
!!lastDockExit && lastDockExit.id === def.id && Date.now() - lastDockExit.at < RESUME_WINDOW_MS
|
|
1241
|
+
).current;
|
|
1242
|
+
React65.useEffect(() => () => {
|
|
1243
|
+
lastDockExit = { id: def.id, at: Date.now() };
|
|
1244
|
+
}, [def.id]);
|
|
1245
|
+
const entered = useMorphIn(resumed);
|
|
1246
|
+
const width = Math.min(maxWidth, DOCK_MAX_WIDTH);
|
|
1247
|
+
const morph = morphStyles({ left, width }, railOpen, railWidth);
|
|
1248
|
+
const [settled, setSettled] = React65.useState(resumed);
|
|
1249
|
+
React65.useEffect(() => {
|
|
1250
|
+
if (!entered || settled) return;
|
|
1251
|
+
const id = setTimeout(() => setSettled(true), MORPH_MS + 60);
|
|
1252
|
+
return () => clearTimeout(id);
|
|
1253
|
+
}, [entered, settled]);
|
|
1254
|
+
return /* @__PURE__ */ jsx(
|
|
1255
|
+
"div",
|
|
1064
1256
|
{
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1257
|
+
className: "fixed bottom-4 z-40 hidden md:block",
|
|
1258
|
+
style: {
|
|
1259
|
+
left,
|
|
1260
|
+
width,
|
|
1261
|
+
// Arrives as the FAB and unrolls leftward into a composer. The circle it
|
|
1262
|
+
// grows out of is the one that just disappeared from that exact spot.
|
|
1263
|
+
...entered ? morph.open : morph.collapsed,
|
|
1264
|
+
transition: prefersReducedMotion() ? void 0 : morph.transition,
|
|
1265
|
+
...settled ? { transform: "none", clipPath: "none", marginLeft: -width / 2 } : null
|
|
1266
|
+
},
|
|
1267
|
+
children: /* @__PURE__ */ jsx(
|
|
1268
|
+
InviteComposer,
|
|
1269
|
+
{
|
|
1270
|
+
tone: "glass",
|
|
1271
|
+
className: "fayz-assistant-glow",
|
|
1272
|
+
placeholder: def.placeholder ?? t("assistant.invite.placeholder"),
|
|
1273
|
+
value: draft,
|
|
1274
|
+
onChange: setDraft,
|
|
1275
|
+
onSubmit: () => {
|
|
1276
|
+
if (draft.trim()) {
|
|
1277
|
+
ask(draft);
|
|
1278
|
+
setDraft("");
|
|
1279
|
+
} else {
|
|
1280
|
+
setOpen(true);
|
|
1281
|
+
}
|
|
1282
|
+
},
|
|
1283
|
+
onFocusAction: () => setOpen(true),
|
|
1284
|
+
label: def.persona
|
|
1285
|
+
}
|
|
1286
|
+
)
|
|
1069
1287
|
}
|
|
1070
|
-
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
{
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1288
|
+
);
|
|
1289
|
+
}
|
|
1290
|
+
function InviteComposer({
|
|
1291
|
+
className,
|
|
1292
|
+
placeholder,
|
|
1293
|
+
value,
|
|
1294
|
+
onChange,
|
|
1295
|
+
onSubmit,
|
|
1296
|
+
onFocusAction,
|
|
1297
|
+
label,
|
|
1298
|
+
size = "md",
|
|
1299
|
+
tone = "card"
|
|
1300
|
+
}) {
|
|
1301
|
+
const { t } = useTranslation$1();
|
|
1302
|
+
const glass = tone === "glass";
|
|
1303
|
+
return /* @__PURE__ */ jsxs(
|
|
1304
|
+
"form",
|
|
1305
|
+
{
|
|
1306
|
+
onSubmit: (event) => {
|
|
1307
|
+
event.preventDefault();
|
|
1308
|
+
onSubmit();
|
|
1309
|
+
},
|
|
1310
|
+
className: cn$1(
|
|
1311
|
+
"relative flex items-center gap-2.5 pl-4 pr-2",
|
|
1312
|
+
glass ? "fayz-assistant-surface rounded-full bg-primary text-primary-foreground focus-within:-translate-y-0.5" : "rounded-2xl border border-border/70 bg-card transition-shadow focus-within:border-border focus-within:shadow-md",
|
|
1313
|
+
size === "lg" ? "py-2.5" : "py-2",
|
|
1314
|
+
className
|
|
1315
|
+
),
|
|
1316
|
+
children: [
|
|
1317
|
+
/* @__PURE__ */ jsx(
|
|
1318
|
+
Sparkles,
|
|
1319
|
+
{
|
|
1320
|
+
className: cn$1(
|
|
1321
|
+
"relative shrink-0",
|
|
1322
|
+
glass ? "text-primary-foreground drop-shadow-sm" : "text-primary",
|
|
1323
|
+
size === "lg" ? "h-5 w-5" : "h-[18px] w-[18px]"
|
|
1324
|
+
)
|
|
1325
|
+
}
|
|
1326
|
+
),
|
|
1327
|
+
/* @__PURE__ */ jsx(
|
|
1328
|
+
"input",
|
|
1329
|
+
{
|
|
1330
|
+
value,
|
|
1331
|
+
onChange: (event) => onChange(event.target.value),
|
|
1332
|
+
placeholder,
|
|
1333
|
+
"aria-label": label ?? placeholder,
|
|
1334
|
+
className: cn$1(
|
|
1335
|
+
"relative min-w-0 flex-1 bg-transparent focus:outline-none",
|
|
1336
|
+
// Glass text and placeholder come from .fayz-assistant-surface: on a
|
|
1337
|
+
// tinted bar the label is not decoration, so it cannot depend on a
|
|
1338
|
+
// utility class the app's Tailwind build may never have generated.
|
|
1339
|
+
!glass && "text-foreground placeholder:text-muted-foreground/70",
|
|
1340
|
+
size === "lg" ? "py-1.5 text-[15px]" : "text-sm"
|
|
1341
|
+
)
|
|
1342
|
+
}
|
|
1343
|
+
),
|
|
1344
|
+
/* @__PURE__ */ jsx(
|
|
1345
|
+
"button",
|
|
1346
|
+
{
|
|
1347
|
+
type: "submit",
|
|
1348
|
+
onClick: () => {
|
|
1349
|
+
if (!value.trim()) onFocusAction?.();
|
|
1350
|
+
},
|
|
1351
|
+
"aria-label": t("chat.send"),
|
|
1352
|
+
"data-ready": value.trim() ? "true" : "false",
|
|
1353
|
+
className: cn$1(
|
|
1354
|
+
"relative inline-flex shrink-0 items-center justify-center rounded-full",
|
|
1355
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
1356
|
+
// Opaque in both states, and coloured from CSS: a translucent circle
|
|
1357
|
+
// let the page's own lines print through it, and a primary-on-primary
|
|
1358
|
+
// arrow — what an ungenerated utility leaves behind — is no button.
|
|
1359
|
+
glass ? "fayz-assistant-send" : cn$1(
|
|
1360
|
+
"transition-colors",
|
|
1361
|
+
value.trim() ? "bg-primary text-primary-foreground hover:opacity-90" : "bg-muted text-muted-foreground hover:bg-muted/80",
|
|
1362
|
+
size === "lg" ? "h-9 w-9" : "h-8 w-8"
|
|
1363
|
+
)
|
|
1364
|
+
),
|
|
1365
|
+
children: /* @__PURE__ */ jsx(ArrowUp, { className: "h-4 w-4" })
|
|
1366
|
+
}
|
|
1367
|
+
)
|
|
1368
|
+
]
|
|
1369
|
+
}
|
|
1370
|
+
);
|
|
1371
|
+
}
|
|
1372
|
+
function InviteMorphBack() {
|
|
1373
|
+
const leaving = useAssistantInviteStore((s) => s.leaving);
|
|
1374
|
+
return leaving ? /* @__PURE__ */ jsx(MorphBackPill, {}, leaving.invite.id) : null;
|
|
1375
|
+
}
|
|
1376
|
+
function MorphBackPill() {
|
|
1377
|
+
const leaving = useAssistantInviteStore((s) => s.leaving);
|
|
1378
|
+
const endLeave = useAssistantInviteStore((s) => s.endLeave);
|
|
1379
|
+
const railOpen = useRightRailStore((s) => s.open);
|
|
1380
|
+
const railWidth = useRightRailStore((s) => s.width);
|
|
1381
|
+
const { t } = useTranslation$1();
|
|
1382
|
+
const collapsed = useMorphIn();
|
|
1383
|
+
React65.useEffect(() => {
|
|
1384
|
+
if (prefersReducedMotion()) {
|
|
1385
|
+
endLeave();
|
|
1386
|
+
return;
|
|
1387
|
+
}
|
|
1388
|
+
const timer = setTimeout(endLeave, MORPH_MS + 40);
|
|
1389
|
+
return () => clearTimeout(timer);
|
|
1390
|
+
}, [endLeave]);
|
|
1391
|
+
if (!leaving || typeof document === "undefined") return null;
|
|
1392
|
+
const morph = morphStyles(leaving.box, railOpen, railWidth);
|
|
1393
|
+
return createPortal(
|
|
1394
|
+
/* @__PURE__ */ jsx(
|
|
1395
|
+
"div",
|
|
1396
|
+
{
|
|
1397
|
+
"aria-hidden": true,
|
|
1398
|
+
className: "pointer-events-none fixed bottom-4 z-40 hidden md:block",
|
|
1399
|
+
style: {
|
|
1400
|
+
left: leaving.box.left,
|
|
1401
|
+
width: leaving.box.width,
|
|
1402
|
+
...collapsed ? morph.collapsed : morph.open,
|
|
1403
|
+
transition: morph.transition
|
|
1404
|
+
},
|
|
1405
|
+
children: /* @__PURE__ */ jsx(
|
|
1406
|
+
InviteComposer,
|
|
1407
|
+
{
|
|
1408
|
+
tone: "glass",
|
|
1409
|
+
className: collapsed ? "fayz-assistant-leaving" : void 0,
|
|
1410
|
+
placeholder: leaving.invite.placeholder ?? t("assistant.invite.placeholder"),
|
|
1411
|
+
value: "",
|
|
1412
|
+
onChange: () => {
|
|
1413
|
+
},
|
|
1414
|
+
onSubmit: () => {
|
|
1415
|
+
},
|
|
1416
|
+
label: leaving.invite.persona
|
|
1417
|
+
}
|
|
1418
|
+
)
|
|
1419
|
+
}
|
|
1420
|
+
),
|
|
1421
|
+
document.body
|
|
1422
|
+
);
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
// src/app/core-entities.ts
|
|
1426
|
+
var addressEntity = {
|
|
1427
|
+
name: "Address",
|
|
1428
|
+
namePlural: "Addresses",
|
|
1429
|
+
icon: "MapPin",
|
|
1430
|
+
data: {
|
|
1431
|
+
table: "addresses",
|
|
1432
|
+
tenantScoped: true,
|
|
1433
|
+
tenantIdColumn: "tenant_id",
|
|
1434
|
+
searchColumns: ["label", "street", "district", "city", "postal_code", "recipient"]
|
|
1435
|
+
},
|
|
1436
|
+
fields: [
|
|
1437
|
+
// owner_id/owner_type are how an address attaches to its person. They are
|
|
1438
|
+
// required and described rather than hidden: the agent reaches this table
|
|
1439
|
+
// from a record it already has in hand ("adiciona o endereço X pra ele"),
|
|
1440
|
+
// so the id it must pass is the one it just searched for or created.
|
|
1441
|
+
{
|
|
1442
|
+
key: "owner_id",
|
|
1443
|
+
label: "Owner record id",
|
|
1444
|
+
type: "text",
|
|
1445
|
+
required: true,
|
|
1446
|
+
hint: "Id of the person (client, contact, supplier, staff\u2026) this address belongs to."
|
|
1447
|
+
},
|
|
1448
|
+
{
|
|
1449
|
+
key: "owner_type",
|
|
1450
|
+
label: "Owner kind",
|
|
1451
|
+
type: "select",
|
|
1452
|
+
options: ["person", "location", "tenant"],
|
|
1453
|
+
hint: "Defaults to 'person'. Only set it for an address that belongs to a business location or to the tenant itself."
|
|
1454
|
+
},
|
|
1455
|
+
{ key: "label", label: "Label", type: "text", searchable: true, hint: "Casa, Trabalho, Dep\xF3sito\u2026" },
|
|
1456
|
+
{
|
|
1457
|
+
key: "kind",
|
|
1458
|
+
label: "Use",
|
|
1459
|
+
type: "select",
|
|
1460
|
+
options: ["both", "shipping", "billing"],
|
|
1461
|
+
hint: "Defaults to 'both'."
|
|
1462
|
+
},
|
|
1463
|
+
{ key: "postal_code", label: "Postal code", type: "text", required: true, searchable: true, hint: "CEP." },
|
|
1464
|
+
{ key: "street", label: "Street", type: "text", required: true, searchable: true },
|
|
1465
|
+
{ key: "number", label: "Number", type: "text" },
|
|
1466
|
+
{ key: "complement", label: "Complement", type: "text" },
|
|
1467
|
+
{ key: "district", label: "District", type: "text", searchable: true, hint: "Bairro." },
|
|
1468
|
+
{ key: "city", label: "City", type: "text", required: true, searchable: true },
|
|
1469
|
+
{ key: "state", label: "State", type: "text", required: true, hint: "Two-letter UF." },
|
|
1470
|
+
{ key: "country", label: "Country", type: "text", hint: "Defaults to 'BR'." },
|
|
1471
|
+
{ key: "recipient", label: "Recipient", type: "text", searchable: true, hint: "Who receives, if not the owner." },
|
|
1472
|
+
{ key: "phone", label: "Phone", type: "text" },
|
|
1473
|
+
{
|
|
1474
|
+
key: "is_default",
|
|
1475
|
+
label: "Default address",
|
|
1476
|
+
type: "boolean",
|
|
1477
|
+
hint: "Only one default per owner and kind \u2014 clear the previous one before setting this."
|
|
1478
|
+
}
|
|
1479
|
+
]
|
|
1480
|
+
};
|
|
1481
|
+
var CORE_QUERY_ENTITIES = [
|
|
1482
|
+
{
|
|
1483
|
+
key: "address",
|
|
1484
|
+
entity: addressEntity,
|
|
1485
|
+
writable: true,
|
|
1486
|
+
agentHint: "`address` holds the street address of a PERSON (client, contact, supplier, staff). A person record has NO street/city/postal_code fields of its own. To read where someone lives, search `address` with filters {\"owner_id\": <the person's id>} \u2014 a person with no address field is not a person without an address. To record one, create an `address` with owner_id set to the person's id. Never write an address into a notes field."
|
|
1487
|
+
}
|
|
1488
|
+
];
|
|
1489
|
+
|
|
1490
|
+
// src/lib/core-ai-tools.ts
|
|
1491
|
+
var coreAITools = [
|
|
1492
|
+
{
|
|
1493
|
+
id: "core.business-summary",
|
|
1494
|
+
name: "getBusinessSummary",
|
|
1495
|
+
description: "Returns a summary of the current business: name, plan, vertical, team size, and key metrics.",
|
|
1496
|
+
icon: "Building2",
|
|
1497
|
+
mode: "read",
|
|
1498
|
+
parameters: { type: "object", properties: {}, required: [] },
|
|
1499
|
+
category: "Core",
|
|
1500
|
+
suggestions: [
|
|
1501
|
+
{ label: "How's my business doing today?" }
|
|
1502
|
+
]
|
|
1503
|
+
},
|
|
1095
1504
|
{
|
|
1096
1505
|
id: "core.team-members",
|
|
1097
1506
|
name: "getTeamMembers",
|
|
@@ -1507,12 +1916,12 @@ function detectActivePluginId(runtime) {
|
|
|
1507
1916
|
function useAITools() {
|
|
1508
1917
|
const runtime = usePluginRuntimeOptional();
|
|
1509
1918
|
const access = useAccessOptional();
|
|
1510
|
-
const surfaceVersion =
|
|
1919
|
+
const surfaceVersion = React65.useSyncExternalStore(subscribeSurfaces, getSurfaceVersion, getSurfaceVersion);
|
|
1511
1920
|
const features = usePermissionsStore((s) => s.features);
|
|
1512
1921
|
const profiles = usePermissionsStore((s) => s.profiles);
|
|
1513
1922
|
const hasSystem = useSystemPermission();
|
|
1514
1923
|
const canManagePermissions = hasSystem("manage_permissions");
|
|
1515
|
-
return
|
|
1924
|
+
return React65.useMemo(() => {
|
|
1516
1925
|
const hasPermission = runtime?.context.hasPermission;
|
|
1517
1926
|
const can = access.can;
|
|
1518
1927
|
const verticalId = runtime?.context.tenant?.verticalId;
|
|
@@ -1595,8 +2004,8 @@ function navigateTo(to) {
|
|
|
1595
2004
|
adapter.navigate(normalizeAdminPath(to));
|
|
1596
2005
|
}
|
|
1597
2006
|
function useAdminPath() {
|
|
1598
|
-
const [path, setPath] =
|
|
1599
|
-
|
|
2007
|
+
const [path, setPath] = React65.useState(() => normalizeAdminPath(adapter.getCurrentPath() || "/"));
|
|
2008
|
+
React65.useEffect(() => {
|
|
1600
2009
|
return adapter.onPathChange((p) => {
|
|
1601
2010
|
setPath(normalizeAdminPath(p || "/"));
|
|
1602
2011
|
if (typeof window !== "undefined") window.scrollTo(0, 0);
|
|
@@ -2843,6 +3252,20 @@ async function executeRpcTool(rpcName, args, userId) {
|
|
|
2843
3252
|
|
|
2844
3253
|
// src/components/connect/connector-map.generated.ts
|
|
2845
3254
|
var SDK_INTEGRATIONS = [
|
|
3255
|
+
{
|
|
3256
|
+
slug: "99food",
|
|
3257
|
+
name: "99Food",
|
|
3258
|
+
description: "Traga para a cozinha cada pedido feito no 99Food, e avise o 99Food quando ele for confirmado e sair.",
|
|
3259
|
+
icon: "Bike",
|
|
3260
|
+
logoUrl: "https://assets.fayz.ai/connectors/99food.jpeg",
|
|
3261
|
+
category: "marketplace",
|
|
3262
|
+
direction: "inbound",
|
|
3263
|
+
planes: ["sync"],
|
|
3264
|
+
moduleId: "orders",
|
|
3265
|
+
status: "available",
|
|
3266
|
+
connectorId: "99food",
|
|
3267
|
+
declaredBy: { pluginId: "orders", package: "@fayz-ai/plugin-orders" }
|
|
3268
|
+
},
|
|
2846
3269
|
{
|
|
2847
3270
|
slug: "abacatepay",
|
|
2848
3271
|
name: "AbacatePay",
|
|
@@ -2912,6 +3335,20 @@ var SDK_INTEGRATIONS = [
|
|
|
2912
3335
|
status: "soon",
|
|
2913
3336
|
declaredBy: { pluginId: "agenda", package: "@fayz-ai/plugin-agenda" }
|
|
2914
3337
|
},
|
|
3338
|
+
{
|
|
3339
|
+
slug: "cielo",
|
|
3340
|
+
name: "Cielo",
|
|
3341
|
+
description: "Traga para o Financeiro tudo que entrou na Cielo \u2014 cr\xE9dito, d\xE9bito e Pix \u2014 com a taxa e a data do repasse.",
|
|
3342
|
+
icon: "CreditCard",
|
|
3343
|
+
logoUrl: "https://assets.fayz.ai/connectors/cielo.jpg",
|
|
3344
|
+
category: "payments",
|
|
3345
|
+
direction: "inbound",
|
|
3346
|
+
planes: ["sync"],
|
|
3347
|
+
moduleId: "financial",
|
|
3348
|
+
status: "available",
|
|
3349
|
+
connectorId: "cielo",
|
|
3350
|
+
declaredBy: { pluginId: "financial", package: "@fayz-ai/plugin-financial" }
|
|
3351
|
+
},
|
|
2915
3352
|
{
|
|
2916
3353
|
slug: "google-analytics",
|
|
2917
3354
|
name: "Google Analytics",
|
|
@@ -2980,6 +3417,34 @@ var SDK_INTEGRATIONS = [
|
|
|
2980
3417
|
status: "soon",
|
|
2981
3418
|
declaredBy: { pluginId: "crm", package: "@fayz-ai/plugin-crm" }
|
|
2982
3419
|
},
|
|
3420
|
+
{
|
|
3421
|
+
slug: "ifood",
|
|
3422
|
+
name: "iFood",
|
|
3423
|
+
description: "Traga para a cozinha cada pedido feito no iFood, e avise o iFood quando ele for confirmado e sair.",
|
|
3424
|
+
icon: "Bike",
|
|
3425
|
+
logoUrl: "https://assets.fayz.ai/connectors/ifood.jpg",
|
|
3426
|
+
category: "marketplace",
|
|
3427
|
+
direction: "inbound",
|
|
3428
|
+
planes: ["sync"],
|
|
3429
|
+
moduleId: "orders",
|
|
3430
|
+
status: "available",
|
|
3431
|
+
connectorId: "ifood",
|
|
3432
|
+
declaredBy: { pluginId: "orders", package: "@fayz-ai/plugin-orders" }
|
|
3433
|
+
},
|
|
3434
|
+
{
|
|
3435
|
+
slug: "keeta",
|
|
3436
|
+
name: "Keeta",
|
|
3437
|
+
description: "Traga para a cozinha cada pedido feito no Keeta, e avise o Keeta quando ele for confirmado e sair.",
|
|
3438
|
+
icon: "Bike",
|
|
3439
|
+
logoUrl: "https://assets.fayz.ai/connectors/keeta.jpeg",
|
|
3440
|
+
category: "marketplace",
|
|
3441
|
+
direction: "inbound",
|
|
3442
|
+
planes: ["sync"],
|
|
3443
|
+
moduleId: "orders",
|
|
3444
|
+
status: "available",
|
|
3445
|
+
connectorId: "keeta",
|
|
3446
|
+
declaredBy: { pluginId: "orders", package: "@fayz-ai/plugin-orders" }
|
|
3447
|
+
},
|
|
2983
3448
|
{
|
|
2984
3449
|
slug: "kiwify",
|
|
2985
3450
|
name: "Kiwify",
|
|
@@ -3037,11 +3502,16 @@ var SDK_INTEGRATIONS = [
|
|
|
3037
3502
|
},
|
|
3038
3503
|
{
|
|
3039
3504
|
slug: "mercadopago",
|
|
3040
|
-
name: "
|
|
3505
|
+
name: "Mercado Pago",
|
|
3506
|
+
description: "Traga para o Financeiro tudo que entrou no Mercado Pago \u2014 Pix, cart\xE3o e maquininha \u2014 com a taxa e a data do repasse.",
|
|
3507
|
+
icon: "CreditCard",
|
|
3041
3508
|
logoUrl: "https://assets.fayz.ai/connectors/mercadopago.png",
|
|
3042
3509
|
category: "payments",
|
|
3510
|
+
direction: "inbound",
|
|
3511
|
+
planes: ["sync"],
|
|
3043
3512
|
moduleId: "financial",
|
|
3044
|
-
status: "
|
|
3513
|
+
status: "available",
|
|
3514
|
+
connectorId: "mercadopago",
|
|
3045
3515
|
declaredBy: { pluginId: "financial", package: "@fayz-ai/plugin-financial" }
|
|
3046
3516
|
},
|
|
3047
3517
|
{
|
|
@@ -3062,6 +3532,20 @@ var SDK_INTEGRATIONS = [
|
|
|
3062
3532
|
status: "soon",
|
|
3063
3533
|
declaredBy: { pluginId: "financial", package: "@fayz-ai/plugin-financial" }
|
|
3064
3534
|
},
|
|
3535
|
+
{
|
|
3536
|
+
slug: "pagbank",
|
|
3537
|
+
name: "PagBank",
|
|
3538
|
+
description: "Traga para o Financeiro tudo que entrou no PagBank \u2014 Pix, cart\xE3o e maquininha \u2014 com a taxa e a data do repasse.",
|
|
3539
|
+
icon: "CreditCard",
|
|
3540
|
+
logoUrl: "https://assets.fayz.ai/connectors/pagbank_pagseguro.png",
|
|
3541
|
+
category: "payments",
|
|
3542
|
+
direction: "inbound",
|
|
3543
|
+
planes: ["sync"],
|
|
3544
|
+
moduleId: "financial",
|
|
3545
|
+
status: "available",
|
|
3546
|
+
connectorId: "pagbank",
|
|
3547
|
+
declaredBy: { pluginId: "financial", package: "@fayz-ai/plugin-financial" }
|
|
3548
|
+
},
|
|
3065
3549
|
{
|
|
3066
3550
|
slug: "ranklayer",
|
|
3067
3551
|
name: "RankLayer",
|
|
@@ -3106,10 +3590,15 @@ var SDK_INTEGRATIONS = [
|
|
|
3106
3590
|
{
|
|
3107
3591
|
slug: "stone",
|
|
3108
3592
|
name: "Stone",
|
|
3593
|
+
description: "Traga para o Financeiro tudo que entrou na Stone \u2014 cr\xE9dito, d\xE9bito, Pix e vale \u2014 com a taxa e a data do repasse.",
|
|
3594
|
+
icon: "CreditCard",
|
|
3109
3595
|
logoUrl: "https://assets.fayz.ai/connectors/stone.jpeg",
|
|
3110
3596
|
category: "payments",
|
|
3597
|
+
direction: "inbound",
|
|
3598
|
+
planes: ["sync"],
|
|
3111
3599
|
moduleId: "financial",
|
|
3112
|
-
status: "
|
|
3600
|
+
status: "available",
|
|
3601
|
+
connectorId: "stone",
|
|
3113
3602
|
declaredBy: { pluginId: "financial", package: "@fayz-ai/plugin-financial" }
|
|
3114
3603
|
},
|
|
3115
3604
|
{
|
|
@@ -3163,6 +3652,20 @@ var SDK_INTEGRATIONS = [
|
|
|
3163
3652
|
status: "soon",
|
|
3164
3653
|
declaredBy: { pluginId: "reputation", package: "@fayz-ai/plugin-reputation" }
|
|
3165
3654
|
},
|
|
3655
|
+
{
|
|
3656
|
+
slug: "vindi",
|
|
3657
|
+
name: "Vindi",
|
|
3658
|
+
description: "Pix e boleto pela Vindi. A loja recebe na conta dela, com o cliente pagando sem sair da p\xE1gina.",
|
|
3659
|
+
icon: "CreditCard",
|
|
3660
|
+
logoUrl: "https://assets.fayz.ai/connectors/vindi.png",
|
|
3661
|
+
category: "payments",
|
|
3662
|
+
direction: "outbound",
|
|
3663
|
+
planes: ["request", "sync"],
|
|
3664
|
+
moduleId: "shop",
|
|
3665
|
+
status: "available",
|
|
3666
|
+
connectorId: "vindi",
|
|
3667
|
+
declaredBy: { pluginId: "shop", package: "@fayz-ai/plugin-shop" }
|
|
3668
|
+
},
|
|
3166
3669
|
{
|
|
3167
3670
|
slug: "whatsapp",
|
|
3168
3671
|
name: "WhatsApp",
|
|
@@ -3527,8 +4030,8 @@ function loadCatalog() {
|
|
|
3527
4030
|
return catalogPromise;
|
|
3528
4031
|
}
|
|
3529
4032
|
function useConnectorCatalog() {
|
|
3530
|
-
const [catalog, setCatalog] =
|
|
3531
|
-
|
|
4033
|
+
const [catalog, setCatalog] = React65__default.useState(null);
|
|
4034
|
+
React65__default.useEffect(() => {
|
|
3532
4035
|
let cancelled = false;
|
|
3533
4036
|
void loadCatalog().then((list) => {
|
|
3534
4037
|
if (!cancelled) setCatalog(list);
|
|
@@ -3552,7 +4055,7 @@ function refreshConnectors() {
|
|
|
3552
4055
|
_revisionListeners.forEach((listener) => listener());
|
|
3553
4056
|
}
|
|
3554
4057
|
function useConnectorsRevision() {
|
|
3555
|
-
return
|
|
4058
|
+
return React65__default.useSyncExternalStore(
|
|
3556
4059
|
(listener) => {
|
|
3557
4060
|
_revisionListeners.add(listener);
|
|
3558
4061
|
return () => _revisionListeners.delete(listener);
|
|
@@ -3571,11 +4074,11 @@ function loadGrants(key, fetcher) {
|
|
|
3571
4074
|
}
|
|
3572
4075
|
function useInstalledModuleIds() {
|
|
3573
4076
|
const runtime = usePluginRuntimeOptional();
|
|
3574
|
-
return
|
|
4077
|
+
return React65__default.useMemo(() => (runtime?.plugins ?? []).map((p) => p.id), [runtime]);
|
|
3575
4078
|
}
|
|
3576
4079
|
function useInstalledDefinitions(hostPluginId) {
|
|
3577
4080
|
const runtime = usePluginRuntimeOptional();
|
|
3578
|
-
return
|
|
4081
|
+
return React65__default.useMemo(() => {
|
|
3579
4082
|
const byHost = runtime?.connectorsByHost;
|
|
3580
4083
|
if (!byHost) return [];
|
|
3581
4084
|
if (hostPluginId) return byHost.get(hostPluginId) ?? [];
|
|
@@ -3588,12 +4091,12 @@ function useConnectors(options = {}) {
|
|
|
3588
4091
|
const catalog = useConnectorCatalog();
|
|
3589
4092
|
const tenant = useTenantOptional();
|
|
3590
4093
|
const tenantId2 = tenant?.org?.id;
|
|
3591
|
-
const connection =
|
|
3592
|
-
const [installed, setInstalled] =
|
|
3593
|
-
const [grants, setGrants] =
|
|
3594
|
-
const [error, setError] =
|
|
4094
|
+
const connection = React65__default.useMemo(() => resolveFayzAgentConnection(), []);
|
|
4095
|
+
const [installed, setInstalled] = React65__default.useState(null);
|
|
4096
|
+
const [grants, setGrants] = React65__default.useState(null);
|
|
4097
|
+
const [error, setError] = React65__default.useState(null);
|
|
3595
4098
|
const nonce = useConnectorsRevision();
|
|
3596
|
-
const call =
|
|
4099
|
+
const call = React65__default.useCallback(
|
|
3597
4100
|
async (path, init) => {
|
|
3598
4101
|
if (!connection) throw new Error("Este app n\xE3o est\xE1 ligado a um projeto Fayz.");
|
|
3599
4102
|
const supabase = getFayzSupabaseClientOptional();
|
|
@@ -3613,7 +4116,7 @@ function useConnectors(options = {}) {
|
|
|
3613
4116
|
},
|
|
3614
4117
|
[connection]
|
|
3615
4118
|
);
|
|
3616
|
-
|
|
4119
|
+
React65__default.useEffect(() => {
|
|
3617
4120
|
let cancelled = false;
|
|
3618
4121
|
void loadConnectorStatuses(definitions, tenantId2).then((list) => {
|
|
3619
4122
|
if (!cancelled) setInstalled(list);
|
|
@@ -3622,7 +4125,7 @@ function useConnectors(options = {}) {
|
|
|
3622
4125
|
cancelled = true;
|
|
3623
4126
|
};
|
|
3624
4127
|
}, [definitions, tenantId2, nonce]);
|
|
3625
|
-
|
|
4128
|
+
React65__default.useEffect(() => {
|
|
3626
4129
|
if (!includeGrants || !connection || !tenantId2) {
|
|
3627
4130
|
setGrants(includeGrants ? null : []);
|
|
3628
4131
|
return;
|
|
@@ -3646,7 +4149,7 @@ function useConnectors(options = {}) {
|
|
|
3646
4149
|
cancelled = true;
|
|
3647
4150
|
};
|
|
3648
4151
|
}, [call, tenantId2, includeGrants, connection, nonce]);
|
|
3649
|
-
const revokeGrant =
|
|
4152
|
+
const revokeGrant = React65__default.useCallback(
|
|
3650
4153
|
async (connector) => {
|
|
3651
4154
|
const response = await call(`/${connector.id}`, { method: "DELETE" });
|
|
3652
4155
|
if (!response.ok) {
|
|
@@ -3659,7 +4162,7 @@ function useConnectors(options = {}) {
|
|
|
3659
4162
|
[call]
|
|
3660
4163
|
);
|
|
3661
4164
|
const waitingGrants = includeGrants && !!connection && !!tenantId2 && grants === null;
|
|
3662
|
-
const connectors =
|
|
4165
|
+
const connectors = React65__default.useMemo(() => {
|
|
3663
4166
|
if (installed === null || waitingGrants) return null;
|
|
3664
4167
|
return buildConnectorList({
|
|
3665
4168
|
installed,
|
|
@@ -4294,7 +4797,6 @@ ${JSON.stringify(snapshot.length === 1 ? snapshot[0] : snapshot)}` : void 0
|
|
|
4294
4797
|
startNewConversation
|
|
4295
4798
|
};
|
|
4296
4799
|
}
|
|
4297
|
-
var FAB_MARGIN_RIGHT = 21;
|
|
4298
4800
|
var TEASER_MAX_PER_SESSION = 2;
|
|
4299
4801
|
var KEY_DISMISSED2 = "fayz.agent.teaser.dismissed";
|
|
4300
4802
|
var KEY_SHOWN = "fayz.agent.teaser.shown";
|
|
@@ -4325,14 +4827,14 @@ function recordTeaser(label) {
|
|
|
4325
4827
|
store.setItem(KEY_SHOWN, String(teaserShownCount() + 1));
|
|
4326
4828
|
store.setItem(KEY_SEEN, JSON.stringify([...teaserSeen(), label].slice(-12)));
|
|
4327
4829
|
}
|
|
4328
|
-
function
|
|
4830
|
+
function prefersReducedMotion2() {
|
|
4329
4831
|
return typeof window !== "undefined" && !!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
4330
4832
|
}
|
|
4331
4833
|
function TypewriterText({ text, speed = 26, onDone }) {
|
|
4332
|
-
const [displayed, setDisplayed] =
|
|
4333
|
-
const indexRef =
|
|
4334
|
-
|
|
4335
|
-
if (
|
|
4834
|
+
const [displayed, setDisplayed] = React65.useState("");
|
|
4835
|
+
const indexRef = React65.useRef(0);
|
|
4836
|
+
React65.useEffect(() => {
|
|
4837
|
+
if (prefersReducedMotion2()) {
|
|
4336
4838
|
setDisplayed(text);
|
|
4337
4839
|
onDone?.();
|
|
4338
4840
|
return;
|
|
@@ -4415,11 +4917,11 @@ function ChatFab({ className, apiEndpoint, systemPrompt, agent, voice, mobile })
|
|
|
4415
4917
|
const { contextualSuggestions } = useAITools();
|
|
4416
4918
|
const { sendMessage } = useChat({ apiEndpoint, systemPrompt, agent });
|
|
4417
4919
|
const { t } = useTranslation$1();
|
|
4418
|
-
const [phase, setPhase] =
|
|
4419
|
-
const [activeSuggestion, setActiveSuggestion] =
|
|
4420
|
-
const timersRef =
|
|
4421
|
-
const prevSuggestionRef =
|
|
4422
|
-
|
|
4920
|
+
const [phase, setPhase] = React65.useState("idle");
|
|
4921
|
+
const [activeSuggestion, setActiveSuggestion] = React65.useState(null);
|
|
4922
|
+
const timersRef = React65.useRef([]);
|
|
4923
|
+
const prevSuggestionRef = React65.useRef(null);
|
|
4924
|
+
React65.useEffect(ensureStyles, []);
|
|
4423
4925
|
const clearTimers = () => {
|
|
4424
4926
|
timersRef.current.forEach(clearTimeout);
|
|
4425
4927
|
timersRef.current = [];
|
|
@@ -4430,10 +4932,11 @@ function ChatFab({ className, apiEndpoint, systemPrompt, agent, voice, mobile })
|
|
|
4430
4932
|
const topSuggestion = contextualSuggestions[0] ?? null;
|
|
4431
4933
|
const topLabel = topSuggestion?.label ?? null;
|
|
4432
4934
|
const invited = useAssistantInviteStore((s) => !!s.invite && s.stage === "dock");
|
|
4433
|
-
const
|
|
4935
|
+
const morphingBack = useAssistantInviteStore((s) => !!s.leaving);
|
|
4936
|
+
const [wide, setWide] = React65.useState(
|
|
4434
4937
|
() => typeof window !== "undefined" && !!window.matchMedia?.("(min-width: 768px)").matches
|
|
4435
4938
|
);
|
|
4436
|
-
|
|
4939
|
+
React65.useEffect(() => {
|
|
4437
4940
|
const query = window.matchMedia?.("(min-width: 768px)");
|
|
4438
4941
|
if (!query) return;
|
|
4439
4942
|
const sync = () => setWide(query.matches);
|
|
@@ -4442,7 +4945,7 @@ function ChatFab({ className, apiEndpoint, systemPrompt, agent, voice, mobile })
|
|
|
4442
4945
|
return () => query.removeEventListener("change", sync);
|
|
4443
4946
|
}, []);
|
|
4444
4947
|
const teaserAllowed = !hasMessages && !activity && !invited && !teaserDismissed() && teaserShownCount() < TEASER_MAX_PER_SESSION;
|
|
4445
|
-
|
|
4948
|
+
React65.useEffect(() => {
|
|
4446
4949
|
if (expanded || !topSuggestion || !topLabel || !teaserAllowed || teaserSeen().includes(topLabel)) {
|
|
4447
4950
|
if (phase !== "idle") {
|
|
4448
4951
|
clearTimers();
|
|
@@ -4473,16 +4976,16 @@ function ChatFab({ className, apiEndpoint, systemPrompt, agent, voice, mobile })
|
|
|
4473
4976
|
}, 9e3);
|
|
4474
4977
|
return clearTimers;
|
|
4475
4978
|
}, [topLabel, expanded, teaserAllowed]);
|
|
4476
|
-
|
|
4979
|
+
React65.useEffect(() => {
|
|
4477
4980
|
if (expanded && phase !== "idle") {
|
|
4478
4981
|
clearTimers();
|
|
4479
4982
|
setPhase("idle");
|
|
4480
4983
|
}
|
|
4481
4984
|
}, [expanded]);
|
|
4482
|
-
const [entrance, setEntrance] =
|
|
4483
|
-
|
|
4985
|
+
const [entrance, setEntrance] = React65.useState("pending");
|
|
4986
|
+
React65.useEffect(() => {
|
|
4484
4987
|
if (!currentOrg || entrance !== "pending") return;
|
|
4485
|
-
if (
|
|
4988
|
+
if (prefersReducedMotion2()) {
|
|
4486
4989
|
setEntrance("done");
|
|
4487
4990
|
return;
|
|
4488
4991
|
}
|
|
@@ -4490,9 +4993,19 @@ function ChatFab({ className, apiEndpoint, systemPrompt, agent, voice, mobile })
|
|
|
4490
4993
|
const timer = setTimeout(() => setEntrance("done"), 1600);
|
|
4491
4994
|
return () => clearTimeout(timer);
|
|
4492
4995
|
}, [currentOrg, entrance]);
|
|
4493
|
-
const
|
|
4996
|
+
const [poppingBack, setPoppingBack] = React65.useState(false);
|
|
4997
|
+
const wasMorphing = React65.useRef(false);
|
|
4998
|
+
React65.useEffect(() => {
|
|
4999
|
+
const was = wasMorphing.current;
|
|
5000
|
+
wasMorphing.current = morphingBack;
|
|
5001
|
+
if (!was || morphingBack || prefersReducedMotion2()) return;
|
|
5002
|
+
setPoppingBack(true);
|
|
5003
|
+
const timer = setTimeout(() => setPoppingBack(false), 620);
|
|
5004
|
+
return () => clearTimeout(timer);
|
|
5005
|
+
}, [morphingBack]);
|
|
5006
|
+
const entering = (entrance === "playing" || poppingBack) && !expanded;
|
|
4494
5007
|
if (!currentOrg) return null;
|
|
4495
|
-
if (invited && wide && !expanded && !activity) return
|
|
5008
|
+
if ((invited || morphingBack) && wide && !expanded && !activity) return /* @__PURE__ */ jsx(InviteMorphBack, {});
|
|
4496
5009
|
const resolveLabel = (s, index) => {
|
|
4497
5010
|
const key = `chat.suggestion.${s.toolId}.${index}`;
|
|
4498
5011
|
const translated = t(key);
|
|
@@ -4516,433 +5029,213 @@ function ChatFab({ className, apiEndpoint, systemPrompt, agent, voice, mobile })
|
|
|
4516
5029
|
addTimer(() => setPhase("idle"), 400);
|
|
4517
5030
|
};
|
|
4518
5031
|
const showPill = phase === "expanding" || phase === "typing" || phase === "visible";
|
|
4519
|
-
return /* @__PURE__ */ jsxs(
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
children: [
|
|
4535
|
-
activity && !expanded && /* @__PURE__ */ jsxs(
|
|
4536
|
-
"div",
|
|
4537
|
-
{
|
|
4538
|
-
className: cn$1(
|
|
4539
|
-
"absolute bottom-0 right-0 flex items-center overflow-hidden rounded-full shadow-lg",
|
|
4540
|
-
activity.state === "done" ? "bg-primary text-primary-foreground" : "bg-foreground text-background"
|
|
4541
|
-
),
|
|
4542
|
-
style: {
|
|
4543
|
-
paddingRight: "3rem",
|
|
4544
|
-
height: "3rem",
|
|
4545
|
-
animation: "fabPillGrow 500ms cubic-bezier(0.22, 1, 0.36, 1) forwards"
|
|
4546
|
-
},
|
|
4547
|
-
children: [
|
|
4548
|
-
/* @__PURE__ */ jsxs(
|
|
4549
|
-
"button",
|
|
4550
|
-
{
|
|
4551
|
-
type: "button",
|
|
4552
|
-
onClick: () => setOpen(true),
|
|
4553
|
-
title: activity.label,
|
|
4554
|
-
className: "flex min-w-0 items-center gap-2 py-1 pl-4 pr-1 text-left transition-opacity hover:opacity-90",
|
|
4555
|
-
children: [
|
|
4556
|
-
/* @__PURE__ */ jsxs("span", { className: "relative inline-flex h-2 w-2 shrink-0", children: [
|
|
4557
|
-
activity.state === "running" && /* @__PURE__ */ jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-red-500 opacity-70" }),
|
|
4558
|
-
/* @__PURE__ */ jsx(
|
|
4559
|
-
"span",
|
|
4560
|
-
{
|
|
4561
|
-
className: cn$1(
|
|
4562
|
-
"relative inline-flex h-2 w-2 rounded-full",
|
|
4563
|
-
activity.state === "done" ? "bg-background" : "bg-red-500"
|
|
4564
|
-
)
|
|
4565
|
-
}
|
|
4566
|
-
)
|
|
4567
|
-
] }),
|
|
4568
|
-
/* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col", children: [
|
|
4569
|
-
/* @__PURE__ */ jsx("span", { className: "max-w-[11rem] truncate text-[10px] uppercase tracking-wide opacity-60", children: activity.label }),
|
|
4570
|
-
activity.elapsedMs !== void 0 && /* @__PURE__ */ jsx("span", { className: "text-[13px] font-semibold tabular-nums leading-tight", children: formatActivityElapsed(activity.elapsedMs) })
|
|
4571
|
-
] })
|
|
4572
|
-
]
|
|
4573
|
-
}
|
|
4574
|
-
),
|
|
4575
|
-
(activity.actions ?? []).filter((action) => action.primary).map((action) => {
|
|
4576
|
-
const Icon = FAB_INTENT_ICON[action.intent];
|
|
4577
|
-
return /* @__PURE__ */ jsx(
|
|
4578
|
-
"button",
|
|
4579
|
-
{
|
|
4580
|
-
type: "button",
|
|
4581
|
-
onClick: (event) => {
|
|
4582
|
-
event.stopPropagation();
|
|
4583
|
-
void action.run();
|
|
4584
|
-
},
|
|
4585
|
-
"aria-label": action.label,
|
|
4586
|
-
title: action.label,
|
|
4587
|
-
className: "mr-1.5 inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full opacity-70 transition-opacity hover:bg-white/15 hover:opacity-100",
|
|
4588
|
-
children: /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5" })
|
|
4589
|
-
},
|
|
4590
|
-
action.intent
|
|
4591
|
-
);
|
|
4592
|
-
})
|
|
4593
|
-
]
|
|
4594
|
-
}
|
|
5032
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5033
|
+
/* @__PURE__ */ jsx(InviteMorphBack, {}),
|
|
5034
|
+
/* @__PURE__ */ jsxs(
|
|
5035
|
+
"div",
|
|
5036
|
+
{
|
|
5037
|
+
className: cn$1(
|
|
5038
|
+
"fixed z-50 md:block md:bottom-4",
|
|
5039
|
+
// Anchored to the CONTENT, not the screen: with the rail open the FAB
|
|
5040
|
+
// slides left and keeps its bottom-right spot relative to the app —
|
|
5041
|
+
// outside the column — gliding in step with the aside's width tween.
|
|
5042
|
+
"motion-safe:transition-[right] motion-safe:duration-200 motion-safe:ease-out",
|
|
5043
|
+
// On a phone the open panel is full-screen and carries its own close
|
|
5044
|
+
// button — a floating FAB there only lands on top of the composer.
|
|
5045
|
+
mobile && !expanded ? "block bottom-[calc(1rem+env(safe-area-inset-bottom))]" : "hidden bottom-4",
|
|
5046
|
+
className
|
|
4595
5047
|
),
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
// button used to float in.
|
|
4605
|
-
"bg-primary text-primary-foreground"
|
|
4606
|
-
),
|
|
4607
|
-
style: {
|
|
4608
|
-
paddingRight: "3rem",
|
|
4609
|
-
height: "3rem",
|
|
4610
|
-
animation: showPill ? "fabPillGrow 650ms cubic-bezier(0.22, 1, 0.36, 1) forwards" : "fabPillShrink 400ms cubic-bezier(0.55, 0, 1, 0.45) forwards"
|
|
4611
|
-
},
|
|
4612
|
-
children: [
|
|
4613
|
-
/* @__PURE__ */ jsxs(
|
|
4614
|
-
"button",
|
|
4615
|
-
{
|
|
4616
|
-
onClick: handleSuggestionClick,
|
|
4617
|
-
className: "flex min-w-0 flex-1 flex-col items-start justify-center py-1 pl-5 pr-1 text-left transition-opacity hover:opacity-90",
|
|
4618
|
-
children: [
|
|
4619
|
-
/* @__PURE__ */ jsx("span", { className: "text-[7px] font-semibold uppercase tracking-widest opacity-50", children: t("chat.fab.tryIt") }),
|
|
4620
|
-
/* @__PURE__ */ jsx(
|
|
4621
|
-
"span",
|
|
4622
|
-
{
|
|
4623
|
-
className: cn$1(
|
|
4624
|
-
"min-h-[1.15em] whitespace-nowrap text-[13px] font-medium transition-opacity",
|
|
4625
|
-
phase === "expanding" ? "opacity-0 duration-200" : "opacity-100 duration-300"
|
|
4626
|
-
),
|
|
4627
|
-
children: phase === "typing" && activeSuggestion ? /* @__PURE__ */ jsx(TypewriterText, { text: `"${activeLabel}"`, onDone: () => setPhase("visible") }) : phase === "visible" && activeSuggestion ? `"${activeLabel}"` : "\xA0"
|
|
4628
|
-
}
|
|
4629
|
-
)
|
|
4630
|
-
]
|
|
4631
|
-
}
|
|
5048
|
+
style: { right: railOpen ? railWidth + FAB_MARGIN_RIGHT : FAB_MARGIN_RIGHT },
|
|
5049
|
+
children: [
|
|
5050
|
+
activity && !expanded && /* @__PURE__ */ jsxs(
|
|
5051
|
+
"div",
|
|
5052
|
+
{
|
|
5053
|
+
className: cn$1(
|
|
5054
|
+
"absolute bottom-0 right-0 flex items-center overflow-hidden rounded-full shadow-lg",
|
|
5055
|
+
activity.state === "done" ? "bg-primary text-primary-foreground" : "bg-foreground text-background"
|
|
4632
5056
|
),
|
|
4633
|
-
|
|
4634
|
-
"
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
}
|
|
4642
|
-
)
|
|
4643
|
-
]
|
|
4644
|
-
}
|
|
4645
|
-
),
|
|
4646
|
-
/* @__PURE__ */ jsxs(
|
|
4647
|
-
"button",
|
|
4648
|
-
{
|
|
4649
|
-
onClick: () => {
|
|
4650
|
-
if (expanded) {
|
|
4651
|
-
closeRail();
|
|
4652
|
-
setOpen(false);
|
|
4653
|
-
} else {
|
|
4654
|
-
setOpen(true);
|
|
4655
|
-
}
|
|
4656
|
-
},
|
|
4657
|
-
className: cn$1(
|
|
4658
|
-
"relative z-10 flex h-12 w-12 items-center justify-center transition-all duration-200",
|
|
4659
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
4660
|
-
"rounded-full bg-primary text-primary-foreground shadow-lg hover:scale-105 hover:shadow-xl"
|
|
4661
|
-
),
|
|
4662
|
-
"aria-label": expanded ? t("chat.fab.close") : t("chat.fab.open"),
|
|
4663
|
-
"aria-expanded": expanded,
|
|
4664
|
-
style: entering ? { animation: "fabEnter 600ms cubic-bezier(0.34, 1.56, 0.64, 1) both" } : void 0,
|
|
4665
|
-
children: [
|
|
4666
|
-
entering && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4667
|
-
/* @__PURE__ */ jsx(
|
|
4668
|
-
"span",
|
|
5057
|
+
style: {
|
|
5058
|
+
paddingRight: "3rem",
|
|
5059
|
+
height: "3rem",
|
|
5060
|
+
animation: "fabPillGrow 500ms cubic-bezier(0.22, 1, 0.36, 1) forwards"
|
|
5061
|
+
},
|
|
5062
|
+
children: [
|
|
5063
|
+
/* @__PURE__ */ jsxs(
|
|
5064
|
+
"button",
|
|
4669
5065
|
{
|
|
4670
|
-
"
|
|
4671
|
-
|
|
4672
|
-
|
|
5066
|
+
type: "button",
|
|
5067
|
+
onClick: () => setOpen(true),
|
|
5068
|
+
title: activity.label,
|
|
5069
|
+
className: "flex min-w-0 items-center gap-2 py-1 pl-4 pr-1 text-left transition-opacity hover:opacity-90",
|
|
5070
|
+
children: [
|
|
5071
|
+
/* @__PURE__ */ jsxs("span", { className: "relative inline-flex h-2 w-2 shrink-0", children: [
|
|
5072
|
+
activity.state === "running" && /* @__PURE__ */ jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-red-500 opacity-70" }),
|
|
5073
|
+
/* @__PURE__ */ jsx(
|
|
5074
|
+
"span",
|
|
5075
|
+
{
|
|
5076
|
+
className: cn$1(
|
|
5077
|
+
"relative inline-flex h-2 w-2 rounded-full",
|
|
5078
|
+
activity.state === "done" ? "bg-background" : "bg-red-500"
|
|
5079
|
+
)
|
|
5080
|
+
}
|
|
5081
|
+
)
|
|
5082
|
+
] }),
|
|
5083
|
+
/* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col", children: [
|
|
5084
|
+
/* @__PURE__ */ jsx("span", { className: "max-w-[11rem] truncate text-[10px] uppercase tracking-wide opacity-60", children: activity.label }),
|
|
5085
|
+
activity.elapsedMs !== void 0 && /* @__PURE__ */ jsx("span", { className: "text-[13px] font-semibold tabular-nums leading-tight", children: formatActivityElapsed(activity.elapsedMs) })
|
|
5086
|
+
] })
|
|
5087
|
+
]
|
|
5088
|
+
}
|
|
5089
|
+
),
|
|
5090
|
+
(activity.actions ?? []).filter((action) => action.primary).map((action) => {
|
|
5091
|
+
const Icon = FAB_INTENT_ICON[action.intent];
|
|
5092
|
+
return /* @__PURE__ */ jsx(
|
|
5093
|
+
"button",
|
|
5094
|
+
{
|
|
5095
|
+
type: "button",
|
|
5096
|
+
onClick: (event) => {
|
|
5097
|
+
event.stopPropagation();
|
|
5098
|
+
void action.run();
|
|
5099
|
+
},
|
|
5100
|
+
"aria-label": action.label,
|
|
5101
|
+
title: action.label,
|
|
5102
|
+
className: "mr-1.5 inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full opacity-70 transition-opacity hover:bg-white/15 hover:opacity-100",
|
|
5103
|
+
children: /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5" })
|
|
5104
|
+
},
|
|
5105
|
+
action.intent
|
|
5106
|
+
);
|
|
5107
|
+
})
|
|
5108
|
+
]
|
|
5109
|
+
}
|
|
5110
|
+
),
|
|
5111
|
+
(showPill || phase === "collapsing") && !expanded && /* @__PURE__ */ jsxs(
|
|
5112
|
+
"div",
|
|
5113
|
+
{
|
|
5114
|
+
className: cn$1(
|
|
5115
|
+
"absolute bottom-0 right-0 flex items-center overflow-hidden rounded-full shadow-lg",
|
|
5116
|
+
// Same fill as the FAB: the pill is the FAB stretching out, not a
|
|
5117
|
+
// second black object parked next to a purple one. Reserving
|
|
5118
|
+
// exactly the circle's width also closes the dead gap the dismiss
|
|
5119
|
+
// button used to float in.
|
|
5120
|
+
"bg-primary text-primary-foreground"
|
|
5121
|
+
),
|
|
5122
|
+
style: {
|
|
5123
|
+
paddingRight: "3rem",
|
|
5124
|
+
height: "3rem",
|
|
5125
|
+
animation: showPill ? "fabPillGrow 650ms cubic-bezier(0.22, 1, 0.36, 1) forwards" : "fabPillShrink 400ms cubic-bezier(0.55, 0, 1, 0.45) forwards"
|
|
5126
|
+
},
|
|
5127
|
+
children: [
|
|
5128
|
+
/* @__PURE__ */ jsxs(
|
|
5129
|
+
"button",
|
|
5130
|
+
{
|
|
5131
|
+
onClick: handleSuggestionClick,
|
|
5132
|
+
className: "flex min-w-0 flex-1 flex-col items-start justify-center py-1 pl-5 pr-1 text-left transition-opacity hover:opacity-90",
|
|
5133
|
+
children: [
|
|
5134
|
+
/* @__PURE__ */ jsx("span", { className: "text-[7px] font-semibold uppercase tracking-widest opacity-50", children: t("chat.fab.tryIt") }),
|
|
5135
|
+
/* @__PURE__ */ jsx(
|
|
5136
|
+
"span",
|
|
5137
|
+
{
|
|
5138
|
+
className: cn$1(
|
|
5139
|
+
"min-h-[1.15em] whitespace-nowrap text-[13px] font-medium transition-opacity",
|
|
5140
|
+
phase === "expanding" ? "opacity-0 duration-200" : "opacity-100 duration-300"
|
|
5141
|
+
),
|
|
5142
|
+
children: phase === "typing" && activeSuggestion ? /* @__PURE__ */ jsx(TypewriterText, { text: `"${activeLabel}"`, onDone: () => setPhase("visible") }) : phase === "visible" && activeSuggestion ? `"${activeLabel}"` : "\xA0"
|
|
5143
|
+
}
|
|
5144
|
+
)
|
|
5145
|
+
]
|
|
4673
5146
|
}
|
|
4674
5147
|
),
|
|
4675
5148
|
/* @__PURE__ */ jsx(
|
|
4676
|
-
"
|
|
5149
|
+
"button",
|
|
4677
5150
|
{
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
5151
|
+
onClick: dismissTeaser,
|
|
5152
|
+
"aria-label": t("chat.fab.dismiss"),
|
|
5153
|
+
title: t("chat.fab.dismiss"),
|
|
5154
|
+
className: "mr-1.5 inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full opacity-50 transition-opacity hover:bg-black/10 hover:opacity-100",
|
|
5155
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
|
|
4681
5156
|
}
|
|
4682
5157
|
)
|
|
4683
|
-
]
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
{
|
|
4694
|
-
|
|
4695
|
-
className: "absolute -right-0.5 -top-0.5 flex h-3 w-3 items-center justify-center",
|
|
4696
|
-
children: [
|
|
4697
|
-
activity.state === "running" && /* @__PURE__ */ jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-red-500 opacity-70" }),
|
|
4698
|
-
/* @__PURE__ */ jsx("span", { className: "relative inline-flex h-2.5 w-2.5 rounded-full border-2 border-primary bg-red-500" })
|
|
4699
|
-
]
|
|
5158
|
+
]
|
|
5159
|
+
}
|
|
5160
|
+
),
|
|
5161
|
+
/* @__PURE__ */ jsxs(
|
|
5162
|
+
"button",
|
|
5163
|
+
{
|
|
5164
|
+
onClick: () => {
|
|
5165
|
+
if (expanded) {
|
|
5166
|
+
closeRail();
|
|
5167
|
+
setOpen(false);
|
|
5168
|
+
} else {
|
|
5169
|
+
setOpen(true);
|
|
4700
5170
|
}
|
|
5171
|
+
},
|
|
5172
|
+
className: cn$1(
|
|
5173
|
+
"relative z-10 flex h-12 w-12 items-center justify-center",
|
|
5174
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
5175
|
+
// Same material as the docked composer — the two are one object in
|
|
5176
|
+
// two shapes, and the morph between them only reads if the surface
|
|
5177
|
+
// does not change on the way.
|
|
5178
|
+
"fayz-assistant-surface rounded-full bg-primary text-primary-foreground hover:scale-105"
|
|
4701
5179
|
),
|
|
4702
|
-
expanded ?
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
return () => {
|
|
4757
|
-
observer.disconnect();
|
|
4758
|
-
window.removeEventListener("resize", measure);
|
|
4759
|
-
window.removeEventListener("scroll", measure, true);
|
|
4760
|
-
};
|
|
4761
|
-
}, [showing]);
|
|
4762
|
-
if (!hasAssistant) return null;
|
|
4763
|
-
const floating = box && stage === "hero" ? /* @__PURE__ */ jsx(InviteHero, { def, box, onDismiss: dismiss }) : box && docked ? /* @__PURE__ */ jsx(InviteDock, { def, left: box.left + box.width / 2, maxWidth: box.width }) : null;
|
|
4764
|
-
return /* @__PURE__ */ jsx("div", { ref: anchorRef, className: cn$1("h-0 w-full", className), "aria-hidden": !showing, children: floating && typeof document !== "undefined" ? createPortal(floating, document.body) : null });
|
|
4765
|
-
}
|
|
4766
|
-
function useAsk() {
|
|
4767
|
-
const queuePrompt = useChatStore((s) => s.queuePrompt);
|
|
4768
|
-
const dismiss = useAssistantInviteStore((s) => s.dismiss);
|
|
4769
|
-
return React63.useCallback(
|
|
4770
|
-
(text) => {
|
|
4771
|
-
const trimmed = text.trim();
|
|
4772
|
-
if (!trimmed) return;
|
|
4773
|
-
dismiss();
|
|
4774
|
-
queuePrompt(trimmed);
|
|
4775
|
-
},
|
|
4776
|
-
[queuePrompt, dismiss]
|
|
4777
|
-
);
|
|
4778
|
-
}
|
|
4779
|
-
function InviteHero({
|
|
4780
|
-
def,
|
|
4781
|
-
box,
|
|
4782
|
-
onDismiss
|
|
4783
|
-
}) {
|
|
4784
|
-
const { t } = useTranslation$1();
|
|
4785
|
-
const user = useAuthStore((s) => s.user);
|
|
4786
|
-
const ask = useAsk();
|
|
4787
|
-
const [draft, setDraft] = React63.useState("");
|
|
4788
|
-
const name = (user?.fullName || user?.email || "").split(/[\s@]/)[0];
|
|
4789
|
-
React63.useEffect(() => {
|
|
4790
|
-
const onKey = (event) => {
|
|
4791
|
-
if (event.key === "Escape") onDismiss();
|
|
4792
|
-
};
|
|
4793
|
-
window.addEventListener("keydown", onKey);
|
|
4794
|
-
return () => window.removeEventListener("keydown", onKey);
|
|
4795
|
-
}, [onDismiss]);
|
|
4796
|
-
return /* @__PURE__ */ jsxs(
|
|
4797
|
-
"section",
|
|
4798
|
-
{
|
|
4799
|
-
className: cn$1(
|
|
4800
|
-
"fixed z-30 flex flex-col items-center justify-center overflow-y-auto px-4 pb-14 text-center",
|
|
4801
|
-
"bg-background/95 backdrop-blur-sm motion-safe:animate-in motion-safe:fade-in-0"
|
|
4802
|
-
),
|
|
4803
|
-
style: { left: box.left, width: box.width, top: box.top, bottom: 0 },
|
|
4804
|
-
"aria-label": def.persona ?? t("chat.defaultTitle"),
|
|
4805
|
-
children: [
|
|
4806
|
-
/* @__PURE__ */ jsx(
|
|
4807
|
-
"button",
|
|
4808
|
-
{
|
|
4809
|
-
type: "button",
|
|
4810
|
-
onClick: onDismiss,
|
|
4811
|
-
"aria-label": t("assistant.invite.dismiss"),
|
|
4812
|
-
title: t("assistant.invite.dismiss"),
|
|
4813
|
-
className: "absolute right-1 top-2 inline-flex h-8 w-8 items-center justify-center rounded-lg text-muted-foreground/60 transition-colors hover:bg-muted hover:text-foreground",
|
|
4814
|
-
children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
|
|
4815
|
-
}
|
|
4816
|
-
),
|
|
4817
|
-
/* @__PURE__ */ jsx("h2", { className: "max-w-2xl text-balance text-[26px] font-semibold leading-tight tracking-tight text-foreground sm:text-[32px]", children: def.headline.replace("{{name}}", name) }),
|
|
4818
|
-
/* @__PURE__ */ jsx(
|
|
4819
|
-
InviteComposer,
|
|
4820
|
-
{
|
|
4821
|
-
className: "mt-7 w-full max-w-3xl",
|
|
4822
|
-
placeholder: def.placeholder ?? t("assistant.invite.placeholder"),
|
|
4823
|
-
value: draft,
|
|
4824
|
-
onChange: setDraft,
|
|
4825
|
-
onSubmit: () => {
|
|
4826
|
-
ask(draft);
|
|
4827
|
-
setDraft("");
|
|
4828
|
-
},
|
|
4829
|
-
size: "lg"
|
|
4830
|
-
}
|
|
4831
|
-
),
|
|
4832
|
-
def.suggestions && def.suggestions.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-4 flex flex-wrap items-center justify-center gap-2", children: def.suggestions.slice(0, 4).map((suggestion) => /* @__PURE__ */ jsx(
|
|
4833
|
-
"button",
|
|
4834
|
-
{
|
|
4835
|
-
type: "button",
|
|
4836
|
-
onClick: () => ask(suggestion.prompt ?? suggestion.label),
|
|
4837
|
-
className: cn$1(
|
|
4838
|
-
"rounded-full border border-border/70 bg-card px-4 py-2 text-[13px] text-foreground/80 transition-colors",
|
|
4839
|
-
"hover:border-border hover:bg-muted hover:text-foreground",
|
|
4840
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
4841
|
-
),
|
|
4842
|
-
children: suggestion.label
|
|
4843
|
-
},
|
|
4844
|
-
suggestion.label
|
|
4845
|
-
)) })
|
|
4846
|
-
]
|
|
4847
|
-
}
|
|
4848
|
-
);
|
|
4849
|
-
}
|
|
4850
|
-
function InviteDock({ def, left, maxWidth }) {
|
|
4851
|
-
const { t } = useTranslation$1();
|
|
4852
|
-
const ask = useAsk();
|
|
4853
|
-
const setOpen = useChatStore((s) => s.setOpen);
|
|
4854
|
-
const [draft, setDraft] = React63.useState("");
|
|
4855
|
-
return /* @__PURE__ */ jsx(
|
|
4856
|
-
"div",
|
|
4857
|
-
{
|
|
4858
|
-
className: "fixed bottom-4 z-40 hidden md:block",
|
|
4859
|
-
style: { left, width: Math.min(maxWidth, 640), transform: "translateX(-50%)" },
|
|
4860
|
-
children: /* @__PURE__ */ jsx(
|
|
4861
|
-
InviteComposer,
|
|
4862
|
-
{
|
|
4863
|
-
className: "shadow-lg motion-safe:animate-slide-in-from-bottom",
|
|
4864
|
-
placeholder: def.placeholder ?? t("assistant.invite.placeholder"),
|
|
4865
|
-
value: draft,
|
|
4866
|
-
onChange: setDraft,
|
|
4867
|
-
onSubmit: () => {
|
|
4868
|
-
if (draft.trim()) {
|
|
4869
|
-
ask(draft);
|
|
4870
|
-
setDraft("");
|
|
4871
|
-
} else {
|
|
4872
|
-
setOpen(true);
|
|
4873
|
-
}
|
|
4874
|
-
},
|
|
4875
|
-
onFocusAction: () => setOpen(true),
|
|
4876
|
-
label: def.persona
|
|
4877
|
-
}
|
|
4878
|
-
)
|
|
4879
|
-
}
|
|
4880
|
-
);
|
|
4881
|
-
}
|
|
4882
|
-
function InviteComposer({
|
|
4883
|
-
className,
|
|
4884
|
-
placeholder,
|
|
4885
|
-
value,
|
|
4886
|
-
onChange,
|
|
4887
|
-
onSubmit,
|
|
4888
|
-
onFocusAction,
|
|
4889
|
-
label,
|
|
4890
|
-
size = "md"
|
|
4891
|
-
}) {
|
|
4892
|
-
const { t } = useTranslation$1();
|
|
4893
|
-
return /* @__PURE__ */ jsxs(
|
|
4894
|
-
"form",
|
|
4895
|
-
{
|
|
4896
|
-
onSubmit: (event) => {
|
|
4897
|
-
event.preventDefault();
|
|
4898
|
-
onSubmit();
|
|
4899
|
-
},
|
|
4900
|
-
className: cn$1(
|
|
4901
|
-
"flex items-center gap-2 rounded-2xl border border-border/70 bg-card pl-4 pr-2 transition-shadow",
|
|
4902
|
-
"focus-within:border-border focus-within:shadow-md",
|
|
4903
|
-
size === "lg" ? "py-2.5" : "py-1.5",
|
|
4904
|
-
className
|
|
4905
|
-
),
|
|
4906
|
-
children: [
|
|
4907
|
-
/* @__PURE__ */ jsx(Sparkles, { className: cn$1("shrink-0 text-primary", size === "lg" ? "h-5 w-5" : "h-4 w-4") }),
|
|
4908
|
-
/* @__PURE__ */ jsx(
|
|
4909
|
-
"input",
|
|
4910
|
-
{
|
|
4911
|
-
value,
|
|
4912
|
-
onChange: (event) => onChange(event.target.value),
|
|
4913
|
-
placeholder,
|
|
4914
|
-
"aria-label": label ?? placeholder,
|
|
4915
|
-
className: cn$1(
|
|
4916
|
-
"min-w-0 flex-1 bg-transparent text-foreground placeholder:text-muted-foreground/70 focus:outline-none",
|
|
4917
|
-
size === "lg" ? "py-1.5 text-[15px]" : "text-[13.5px]"
|
|
4918
|
-
)
|
|
4919
|
-
}
|
|
4920
|
-
),
|
|
4921
|
-
/* @__PURE__ */ jsx(
|
|
4922
|
-
"button",
|
|
4923
|
-
{
|
|
4924
|
-
type: "submit",
|
|
4925
|
-
onClick: () => {
|
|
4926
|
-
if (!value.trim()) onFocusAction?.();
|
|
4927
|
-
},
|
|
4928
|
-
"aria-label": t("chat.send"),
|
|
4929
|
-
className: cn$1(
|
|
4930
|
-
"inline-flex shrink-0 items-center justify-center rounded-full transition-colors",
|
|
4931
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
4932
|
-
value.trim() ? "bg-primary text-primary-foreground hover:opacity-90" : "bg-muted text-muted-foreground hover:bg-muted/80",
|
|
4933
|
-
size === "lg" ? "h-9 w-9" : "h-7 w-7"
|
|
4934
|
-
),
|
|
4935
|
-
children: /* @__PURE__ */ jsx(ArrowUp, { className: size === "lg" ? "h-4 w-4" : "h-3.5 w-3.5" })
|
|
4936
|
-
}
|
|
4937
|
-
)
|
|
4938
|
-
]
|
|
4939
|
-
}
|
|
4940
|
-
);
|
|
5180
|
+
"aria-label": expanded ? t("chat.fab.close") : t("chat.fab.open"),
|
|
5181
|
+
"aria-expanded": expanded,
|
|
5182
|
+
style: entering ? { animation: "fabEnter 600ms cubic-bezier(0.34, 1.56, 0.64, 1) both" } : void 0,
|
|
5183
|
+
children: [
|
|
5184
|
+
entering && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5185
|
+
/* @__PURE__ */ jsx(
|
|
5186
|
+
"span",
|
|
5187
|
+
{
|
|
5188
|
+
"aria-hidden": true,
|
|
5189
|
+
className: "absolute inset-0 rounded-full bg-primary/40",
|
|
5190
|
+
style: { animation: "fabEnterRing 900ms ease-out 250ms both" }
|
|
5191
|
+
}
|
|
5192
|
+
),
|
|
5193
|
+
/* @__PURE__ */ jsx(
|
|
5194
|
+
"span",
|
|
5195
|
+
{
|
|
5196
|
+
"aria-hidden": true,
|
|
5197
|
+
className: "absolute inset-0 rounded-full bg-primary/25",
|
|
5198
|
+
style: { animation: "fabEnterRing 1100ms ease-out 450ms both" }
|
|
5199
|
+
}
|
|
5200
|
+
)
|
|
5201
|
+
] }),
|
|
5202
|
+
isStreaming && !expanded && /* @__PURE__ */ jsx(
|
|
5203
|
+
"span",
|
|
5204
|
+
{
|
|
5205
|
+
"aria-hidden": true,
|
|
5206
|
+
className: "absolute inset-0 rounded-full bg-primary motion-safe:[animation:fabHalo_1.8s_ease-out_infinite]"
|
|
5207
|
+
}
|
|
5208
|
+
),
|
|
5209
|
+
activity && activity.state !== "done" && expanded && /* @__PURE__ */ jsxs(
|
|
5210
|
+
"span",
|
|
5211
|
+
{
|
|
5212
|
+
"aria-hidden": true,
|
|
5213
|
+
className: "absolute -right-0.5 -top-0.5 flex h-3 w-3 items-center justify-center",
|
|
5214
|
+
children: [
|
|
5215
|
+
activity.state === "running" && /* @__PURE__ */ jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-red-500 opacity-70" }),
|
|
5216
|
+
/* @__PURE__ */ jsx("span", { className: "relative inline-flex h-2.5 w-2.5 rounded-full border-2 border-primary bg-red-500" })
|
|
5217
|
+
]
|
|
5218
|
+
}
|
|
5219
|
+
),
|
|
5220
|
+
expanded ? /* @__PURE__ */ jsx(X, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(
|
|
5221
|
+
Sparkles,
|
|
5222
|
+
{
|
|
5223
|
+
className: "relative h-5 w-5",
|
|
5224
|
+
style: entering ? { animation: "fabEnterIcon 700ms cubic-bezier(0.34, 1.56, 0.64, 1) 120ms both" } : void 0
|
|
5225
|
+
}
|
|
5226
|
+
)
|
|
5227
|
+
]
|
|
5228
|
+
}
|
|
5229
|
+
)
|
|
5230
|
+
]
|
|
5231
|
+
}
|
|
5232
|
+
)
|
|
5233
|
+
] });
|
|
4941
5234
|
}
|
|
4942
5235
|
var MAX_SUGGESTIONS = 5;
|
|
4943
5236
|
function ChatSuggestions({ suggestions, onSelect, onDismiss, compact }) {
|
|
4944
5237
|
const { t } = useTranslation$1();
|
|
4945
|
-
const [open, setOpen] =
|
|
5238
|
+
const [open, setOpen] = React65.useState(true);
|
|
4946
5239
|
const visible = suggestions.slice(0, compact ? 3 : MAX_SUGGESTIONS);
|
|
4947
5240
|
if (!visible.length) return null;
|
|
4948
5241
|
return /* @__PURE__ */ jsxs(
|
|
@@ -5021,8 +5314,8 @@ function SuggestionRow({
|
|
|
5021
5314
|
detail,
|
|
5022
5315
|
onSelect
|
|
5023
5316
|
}) {
|
|
5024
|
-
const labelRef =
|
|
5025
|
-
const [showDetail, setShowDetail] =
|
|
5317
|
+
const labelRef = React65.useRef(null);
|
|
5318
|
+
const [showDetail, setShowDetail] = React65.useState(false);
|
|
5026
5319
|
const evaluate = () => {
|
|
5027
5320
|
const el = labelRef.current;
|
|
5028
5321
|
const clipped = !!el && el.scrollWidth > el.clientWidth + 1;
|
|
@@ -5112,8 +5405,8 @@ function ChatToolsPanel({ toolGroups, onClose }) {
|
|
|
5112
5405
|
}
|
|
5113
5406
|
function AutoApprovalsSection() {
|
|
5114
5407
|
const { t } = useTranslation$1();
|
|
5115
|
-
const [rules, setRules] =
|
|
5116
|
-
|
|
5408
|
+
const [rules, setRules] = React65.useState(() => listAutoApprovals());
|
|
5409
|
+
React65.useEffect(() => subscribeAutoApprovals(() => setRules(listAutoApprovals())), []);
|
|
5117
5410
|
if (!rules.length) return null;
|
|
5118
5411
|
return /* @__PURE__ */ jsxs("div", { className: "border-b border-border/40 px-3 py-2.5", children: [
|
|
5119
5412
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-1 pb-1.5", children: [
|
|
@@ -5180,9 +5473,9 @@ function ConnectorMark({
|
|
|
5180
5473
|
connector,
|
|
5181
5474
|
size = "md"
|
|
5182
5475
|
}) {
|
|
5183
|
-
const candidates =
|
|
5184
|
-
const [attempt, setAttempt] =
|
|
5185
|
-
|
|
5476
|
+
const candidates = React65__default.useMemo(() => markCandidates(connector), [connector.logoUrl, connector.name]);
|
|
5477
|
+
const [attempt, setAttempt] = React65__default.useState(0);
|
|
5478
|
+
React65__default.useEffect(() => setAttempt(0), [connector.id]);
|
|
5186
5479
|
const box = size === "sm" ? "h-9 w-9" : "h-10 w-10";
|
|
5187
5480
|
const glyph = size === "sm" ? "h-4 w-4" : "h-5 w-5";
|
|
5188
5481
|
if (connector.builtIn) {
|
|
@@ -5452,15 +5745,15 @@ function ConnectorSyncActions({
|
|
|
5452
5745
|
actions,
|
|
5453
5746
|
onRan
|
|
5454
5747
|
}) {
|
|
5455
|
-
const [running, setRunning] =
|
|
5456
|
-
const [open, setOpen] =
|
|
5457
|
-
const [pending, setPending] =
|
|
5458
|
-
const [hidden, setHidden] =
|
|
5459
|
-
const [queued, setQueued] =
|
|
5460
|
-
const [nonce, setNonce] =
|
|
5461
|
-
const [expanded, setExpanded] =
|
|
5462
|
-
const [resolved, setResolved] =
|
|
5463
|
-
|
|
5748
|
+
const [running, setRunning] = React65__default.useState(null);
|
|
5749
|
+
const [open, setOpen] = React65__default.useState(null);
|
|
5750
|
+
const [pending, setPending] = React65__default.useState(null);
|
|
5751
|
+
const [hidden, setHidden] = React65__default.useState(() => /* @__PURE__ */ new Set());
|
|
5752
|
+
const [queued, setQueued] = React65__default.useState({});
|
|
5753
|
+
const [nonce, setNonce] = React65__default.useState(0);
|
|
5754
|
+
const [expanded, setExpanded] = React65__default.useState(false);
|
|
5755
|
+
const [resolved, setResolved] = React65__default.useState(false);
|
|
5756
|
+
React65__default.useEffect(() => {
|
|
5464
5757
|
let cancelled = false;
|
|
5465
5758
|
setResolved(false);
|
|
5466
5759
|
void Promise.all(
|
|
@@ -5645,10 +5938,10 @@ function formatRelative(iso, t) {
|
|
|
5645
5938
|
}
|
|
5646
5939
|
function useConnectorRuns(connector) {
|
|
5647
5940
|
const listRuns = connector.definition?.listRuns;
|
|
5648
|
-
const [runs, setRuns] =
|
|
5649
|
-
const [loading, setLoading] =
|
|
5650
|
-
const [nonce, setNonce] =
|
|
5651
|
-
|
|
5941
|
+
const [runs, setRuns] = React65__default.useState([]);
|
|
5942
|
+
const [loading, setLoading] = React65__default.useState(!!listRuns);
|
|
5943
|
+
const [nonce, setNonce] = React65__default.useState(0);
|
|
5944
|
+
React65__default.useEffect(() => {
|
|
5652
5945
|
if (!listRuns) {
|
|
5653
5946
|
setRuns([]);
|
|
5654
5947
|
setLoading(false);
|
|
@@ -5670,7 +5963,7 @@ function useConnectorRuns(connector) {
|
|
|
5670
5963
|
return {
|
|
5671
5964
|
runs,
|
|
5672
5965
|
loading,
|
|
5673
|
-
reload:
|
|
5966
|
+
reload: React65__default.useCallback(() => setNonce((n) => n + 1), []),
|
|
5674
5967
|
failing: isFailing(runs)
|
|
5675
5968
|
};
|
|
5676
5969
|
}
|
|
@@ -5882,13 +6175,13 @@ function ConnectorSettingsPanel({
|
|
|
5882
6175
|
const { t } = useTranslation$1();
|
|
5883
6176
|
const def = connector.definition;
|
|
5884
6177
|
const settings = def ? connectorSettings(def) : [];
|
|
5885
|
-
const [values, setValues] =
|
|
6178
|
+
const [values, setValues] = React65__default.useState(
|
|
5886
6179
|
() => initialValues(settings, {})
|
|
5887
6180
|
);
|
|
5888
|
-
const [loaded, setLoaded] =
|
|
5889
|
-
const [saving, setSaving] =
|
|
5890
|
-
const [dirty, setDirty] =
|
|
5891
|
-
|
|
6181
|
+
const [loaded, setLoaded] = React65__default.useState(false);
|
|
6182
|
+
const [saving, setSaving] = React65__default.useState(false);
|
|
6183
|
+
const [dirty, setDirty] = React65__default.useState(false);
|
|
6184
|
+
React65__default.useEffect(() => {
|
|
5892
6185
|
if (settings.length === 0 || !def?.getSettings) return;
|
|
5893
6186
|
let cancelled = false;
|
|
5894
6187
|
setLoaded(false);
|
|
@@ -6139,13 +6432,13 @@ function ConnectorInstall({
|
|
|
6139
6432
|
}) {
|
|
6140
6433
|
const { t } = useTranslation$1();
|
|
6141
6434
|
const def = connector.definition;
|
|
6142
|
-
const [plane, setPlane] =
|
|
6435
|
+
const [plane, setPlane] = React65__default.useState(
|
|
6143
6436
|
connector.planes.includes("agentic") ? "agentic" : connector.planes[0]
|
|
6144
6437
|
);
|
|
6145
|
-
const [values, setValues] =
|
|
6146
|
-
const secrets =
|
|
6147
|
-
const [busy, setBusy] =
|
|
6148
|
-
|
|
6438
|
+
const [values, setValues] = React65__default.useState({});
|
|
6439
|
+
const secrets = React65__default.useRef({});
|
|
6440
|
+
const [busy, setBusy] = React65__default.useState(null);
|
|
6441
|
+
React65__default.useEffect(() => {
|
|
6149
6442
|
setValues({});
|
|
6150
6443
|
secrets.current = {};
|
|
6151
6444
|
setBusy(null);
|
|
@@ -6186,13 +6479,13 @@ function ConnectorHome({
|
|
|
6186
6479
|
const needsSetup = connector.state === "needs_setup";
|
|
6187
6480
|
const settingsAvailable = hasOperatingSettings(connector);
|
|
6188
6481
|
const runsAvailable = hasRunHistory(connector);
|
|
6189
|
-
const [tab, setTab] =
|
|
6482
|
+
const [tab, setTab] = React65__default.useState(
|
|
6190
6483
|
needsSetup && settingsAvailable ? "settings" : "overview"
|
|
6191
6484
|
);
|
|
6192
|
-
const [busy, setBusy] =
|
|
6485
|
+
const [busy, setBusy] = React65__default.useState(null);
|
|
6193
6486
|
const run = useRunner(setBusy, onChanged);
|
|
6194
6487
|
const runs = useConnectorRuns(connector);
|
|
6195
|
-
|
|
6488
|
+
React65__default.useEffect(() => {
|
|
6196
6489
|
setTab(needsSetup && settingsAvailable ? "settings" : "overview");
|
|
6197
6490
|
setBusy(null);
|
|
6198
6491
|
}, [connector.id]);
|
|
@@ -6269,7 +6562,7 @@ function ConnectorHome({
|
|
|
6269
6562
|
}
|
|
6270
6563
|
function useRunner(setBusy, onChanged) {
|
|
6271
6564
|
const { t } = useTranslation$1();
|
|
6272
|
-
return
|
|
6565
|
+
return React65__default.useCallback(
|
|
6273
6566
|
async (kind, fn, okMessage) => {
|
|
6274
6567
|
setBusy(kind);
|
|
6275
6568
|
try {
|
|
@@ -6378,7 +6671,7 @@ function ConnectPanel({
|
|
|
6378
6671
|
const tenantId2 = useTenantOptional()?.org?.id;
|
|
6379
6672
|
const needsSink = needsCredentialSink(def);
|
|
6380
6673
|
const sinkMissing = needsSink && !getConnectorCredentialSink();
|
|
6381
|
-
const [formKey, setFormKey] =
|
|
6674
|
+
const [formKey, setFormKey] = React65__default.useState(0);
|
|
6382
6675
|
if (def.authKind === "oauth") {
|
|
6383
6676
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
6384
6677
|
/* @__PURE__ */ jsx(Note, { children: t("connectors.authorize.oauthOnly") }),
|
|
@@ -6510,7 +6803,7 @@ function GrantRevoke({
|
|
|
6510
6803
|
onRevoke
|
|
6511
6804
|
}) {
|
|
6512
6805
|
const { t } = useTranslation$1();
|
|
6513
|
-
const [revoking, setRevoking] =
|
|
6806
|
+
const [revoking, setRevoking] = React65__default.useState(false);
|
|
6514
6807
|
if (connector.revocable === false) {
|
|
6515
6808
|
return /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("connectors.partOfApp") });
|
|
6516
6809
|
}
|
|
@@ -6549,13 +6842,13 @@ function ConnectorsPanel({ onClose }) {
|
|
|
6549
6842
|
const { connectors, reload, revokeGrant, agentAvailable, tenantReady } = useConnectors();
|
|
6550
6843
|
const selectedId = useConnectorsSurface((s) => s.selected);
|
|
6551
6844
|
const select = useConnectorsSurface((s) => s.select);
|
|
6552
|
-
const [query, setQuery] =
|
|
6553
|
-
const [failure, setFailure] =
|
|
6554
|
-
const selected =
|
|
6845
|
+
const [query, setQuery] = React65__default.useState("");
|
|
6846
|
+
const [failure, setFailure] = React65__default.useState(null);
|
|
6847
|
+
const selected = React65__default.useMemo(
|
|
6555
6848
|
() => (connectors ?? []).find((c) => c.id === selectedId) ?? null,
|
|
6556
6849
|
[connectors, selectedId]
|
|
6557
6850
|
);
|
|
6558
|
-
const filtered =
|
|
6851
|
+
const filtered = React65__default.useMemo(
|
|
6559
6852
|
() => filterConnectors(connectors ?? [], "outbound", query),
|
|
6560
6853
|
[connectors, query]
|
|
6561
6854
|
);
|
|
@@ -6657,20 +6950,20 @@ function useDictation({
|
|
|
6657
6950
|
onInterim
|
|
6658
6951
|
}) {
|
|
6659
6952
|
const resolvedLocale = locale ?? (typeof navigator !== "undefined" ? navigator.language || "pt-BR" : "pt-BR");
|
|
6660
|
-
const [state, setState] =
|
|
6661
|
-
const [error, setError] =
|
|
6662
|
-
const sessionRef =
|
|
6663
|
-
const callbacks =
|
|
6953
|
+
const [state, setState] = React65.useState("idle");
|
|
6954
|
+
const [error, setError] = React65.useState(null);
|
|
6955
|
+
const sessionRef = React65.useRef(null);
|
|
6956
|
+
const callbacks = React65.useRef({ onTranscript, onInterim });
|
|
6664
6957
|
callbacks.current = { onTranscript, onInterim };
|
|
6665
|
-
const supported =
|
|
6958
|
+
const supported = React65.useMemo(
|
|
6666
6959
|
() => isDictationSupported(!!transcribeEndpoint),
|
|
6667
6960
|
[transcribeEndpoint]
|
|
6668
6961
|
);
|
|
6669
|
-
const finish =
|
|
6962
|
+
const finish = React65.useCallback(() => {
|
|
6670
6963
|
sessionRef.current = null;
|
|
6671
6964
|
setState("idle");
|
|
6672
6965
|
}, []);
|
|
6673
|
-
const start =
|
|
6966
|
+
const start = React65.useCallback(() => {
|
|
6674
6967
|
if (sessionRef.current || !supported) return;
|
|
6675
6968
|
stopSpeaking();
|
|
6676
6969
|
setError(null);
|
|
@@ -6691,28 +6984,28 @@ function useDictation({
|
|
|
6691
6984
|
}
|
|
6692
6985
|
);
|
|
6693
6986
|
}, [finish, resolvedLocale, supported, transcribeEndpoint]);
|
|
6694
|
-
const stop =
|
|
6987
|
+
const stop = React65.useCallback(() => {
|
|
6695
6988
|
if (!sessionRef.current) return;
|
|
6696
6989
|
if (transcribeEndpoint) setState("transcribing");
|
|
6697
6990
|
sessionRef.current.stop();
|
|
6698
6991
|
}, [transcribeEndpoint]);
|
|
6699
|
-
const cancel =
|
|
6992
|
+
const cancel = React65.useCallback(() => {
|
|
6700
6993
|
sessionRef.current?.cancel();
|
|
6701
6994
|
sessionRef.current = null;
|
|
6702
6995
|
setState("idle");
|
|
6703
6996
|
setError(null);
|
|
6704
6997
|
}, []);
|
|
6705
|
-
const toggle =
|
|
6998
|
+
const toggle = React65.useCallback(() => {
|
|
6706
6999
|
if (state === "listening" || state === "transcribing") stop();
|
|
6707
7000
|
else start();
|
|
6708
7001
|
}, [state, start, stop]);
|
|
6709
|
-
|
|
7002
|
+
React65.useEffect(() => () => sessionRef.current?.cancel(), []);
|
|
6710
7003
|
return { supported, state, error, start, stop, cancel, toggle, clearError: () => setError(null) };
|
|
6711
7004
|
}
|
|
6712
7005
|
function useMicLevels(active2, bandCount = 28, externalStream) {
|
|
6713
|
-
const levelsRef =
|
|
6714
|
-
const [available, setAvailable] =
|
|
6715
|
-
|
|
7006
|
+
const levelsRef = React65.useRef(new Float32Array(bandCount));
|
|
7007
|
+
const [available, setAvailable] = React65.useState(false);
|
|
7008
|
+
React65.useEffect(() => {
|
|
6716
7009
|
if (!active2) {
|
|
6717
7010
|
levelsRef.current.fill(0);
|
|
6718
7011
|
setAvailable(false);
|
|
@@ -6781,8 +7074,8 @@ var KIND_ICON = {
|
|
|
6781
7074
|
binary: File
|
|
6782
7075
|
};
|
|
6783
7076
|
function useFileDrop(enabled, onFiles) {
|
|
6784
|
-
const [dragging, setDragging] =
|
|
6785
|
-
const depth =
|
|
7077
|
+
const [dragging, setDragging] = React65.useState(false);
|
|
7078
|
+
const depth = React65.useRef(0);
|
|
6786
7079
|
const carriesFiles = (event) => Array.from(event.dataTransfer?.types ?? []).includes("Files");
|
|
6787
7080
|
const reset = () => {
|
|
6788
7081
|
depth.current = 0;
|
|
@@ -6842,7 +7135,7 @@ function AttachmentChips({
|
|
|
6842
7135
|
onRemove
|
|
6843
7136
|
}) {
|
|
6844
7137
|
const { t } = useTranslation$1();
|
|
6845
|
-
const [openId, setOpenId] =
|
|
7138
|
+
const [openId, setOpenId] = React65.useState(null);
|
|
6846
7139
|
if (!attachments.length) return null;
|
|
6847
7140
|
const opened = attachments.find((a) => a.id === openId);
|
|
6848
7141
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -6953,8 +7246,8 @@ function ChatComposer({
|
|
|
6953
7246
|
onToggleSuggestions
|
|
6954
7247
|
}) {
|
|
6955
7248
|
const { t } = useTranslation$1();
|
|
6956
|
-
const [input, setInput] =
|
|
6957
|
-
const textareaRef =
|
|
7249
|
+
const [input, setInput] = React65.useState("");
|
|
7250
|
+
const textareaRef = React65.useRef(null);
|
|
6958
7251
|
const voiceStartRequested = useChatStore((s) => s.voiceStartRequested);
|
|
6959
7252
|
const consumeVoiceStart = useChatStore((s) => s.consumeVoiceStart);
|
|
6960
7253
|
const draft = useChatStore((s) => s.draft);
|
|
@@ -6962,13 +7255,13 @@ function ChatComposer({
|
|
|
6962
7255
|
const attachments = useChatStore((s) => s.attachments);
|
|
6963
7256
|
const addAttachments = useChatStore((s) => s.addAttachments);
|
|
6964
7257
|
const removeAttachment = useChatStore((s) => s.removeAttachment);
|
|
6965
|
-
const fileInputRef =
|
|
7258
|
+
const fileInputRef = React65.useRef(null);
|
|
6966
7259
|
const autoSend = voice?.autoSend === true;
|
|
6967
7260
|
const micEnabled = voice?.input !== false;
|
|
6968
7261
|
const canAttach = isConfigured && !blocked && !isStreaming;
|
|
6969
7262
|
const parsing = attachments.some((a) => a.status === "parsing");
|
|
6970
7263
|
const readyAttachments = attachments.filter((a) => a.status === "ready").length;
|
|
6971
|
-
const submit =
|
|
7264
|
+
const submit = React65.useCallback(
|
|
6972
7265
|
(text) => {
|
|
6973
7266
|
const trimmed = text.trim();
|
|
6974
7267
|
if (!trimmed && !readyAttachments || parsing || isStreaming || !isConfigured || blocked) return;
|
|
@@ -7001,7 +7294,7 @@ function ChatComposer({
|
|
|
7001
7294
|
const WAVEFORM_BANDS = 56;
|
|
7002
7295
|
const activity = useAssistantActivity();
|
|
7003
7296
|
const sessionRecording = activity?.kind === "recording" && activity.state === "running";
|
|
7004
|
-
const sessionStream =
|
|
7297
|
+
const sessionStream = React65.useMemo(
|
|
7005
7298
|
() => sessionRecording ? activity?.stream?.() ?? null : null,
|
|
7006
7299
|
[sessionRecording, activity]
|
|
7007
7300
|
);
|
|
@@ -7013,12 +7306,12 @@ function ChatComposer({
|
|
|
7013
7306
|
);
|
|
7014
7307
|
const sessionPause = activity?.actions?.find((a) => a.intent === "pause" || a.intent === "resume");
|
|
7015
7308
|
const sessionOwnsMic = activity?.kind === "recording" && (activity.state === "running" || activity.state === "paused");
|
|
7016
|
-
|
|
7309
|
+
React65.useEffect(() => {
|
|
7017
7310
|
if (!voiceStartRequested) return;
|
|
7018
7311
|
consumeVoiceStart();
|
|
7019
7312
|
if (showMic) dictation.start();
|
|
7020
7313
|
}, [voiceStartRequested, showMic]);
|
|
7021
|
-
|
|
7314
|
+
React65.useEffect(() => {
|
|
7022
7315
|
if (!draft) return;
|
|
7023
7316
|
setInput(draft);
|
|
7024
7317
|
setDraft("");
|
|
@@ -7028,7 +7321,7 @@ function ChatComposer({
|
|
|
7028
7321
|
el.setSelectionRange(draft.length, draft.length);
|
|
7029
7322
|
}
|
|
7030
7323
|
}, [draft, setDraft]);
|
|
7031
|
-
|
|
7324
|
+
React65.useLayoutEffect(() => {
|
|
7032
7325
|
const el = textareaRef.current;
|
|
7033
7326
|
if (!el) return;
|
|
7034
7327
|
const style = getComputedStyle(el);
|
|
@@ -7225,8 +7518,8 @@ function LiveWaveform({
|
|
|
7225
7518
|
compact,
|
|
7226
7519
|
tone = "primary"
|
|
7227
7520
|
}) {
|
|
7228
|
-
const barsRef =
|
|
7229
|
-
|
|
7521
|
+
const barsRef = React65.useRef([]);
|
|
7522
|
+
React65.useEffect(() => {
|
|
7230
7523
|
if (!live) return;
|
|
7231
7524
|
let frame = 0;
|
|
7232
7525
|
const draw = () => {
|
|
@@ -7507,7 +7800,7 @@ function ConnectorSuggestionCard({ card }) {
|
|
|
7507
7800
|
const setOpen = useChatStore((s) => s.setOpen);
|
|
7508
7801
|
const category = categoryLabel(card.category);
|
|
7509
7802
|
const live = isConnectorState(card.state) ? card.state : null;
|
|
7510
|
-
const go =
|
|
7803
|
+
const go = React65.useCallback(() => {
|
|
7511
7804
|
if (panelAvailable && card.id) {
|
|
7512
7805
|
openConnectorsPanel({ id: card.id });
|
|
7513
7806
|
return;
|
|
@@ -7564,7 +7857,7 @@ function humanizeToolName(name) {
|
|
|
7564
7857
|
}
|
|
7565
7858
|
function ToolCallRow({ call }) {
|
|
7566
7859
|
const { t } = useTranslation$1();
|
|
7567
|
-
const [open, setOpen] =
|
|
7860
|
+
const [open, setOpen] = React65.useState(false);
|
|
7568
7861
|
const failed = call.declined || /"error"\s*:/.test(call.result ?? "");
|
|
7569
7862
|
return /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-xl border border-border/50 bg-muted/30", children: [
|
|
7570
7863
|
/* @__PURE__ */ jsxs(
|
|
@@ -7627,7 +7920,7 @@ function ToolCallRow({ call }) {
|
|
|
7627
7920
|
}
|
|
7628
7921
|
function MessageBubble({ message, isPending }) {
|
|
7629
7922
|
const isUser = message.role === "user";
|
|
7630
|
-
const routedLinks =
|
|
7923
|
+
const routedLinks = React65.useMemo(
|
|
7631
7924
|
() => (message.links ?? []).filter(
|
|
7632
7925
|
(l) => !!l.path || !!resolveEntityRoute(l.archetype, l.kind, l.entityKey)
|
|
7633
7926
|
),
|
|
@@ -7702,9 +7995,9 @@ function ConfirmActionCard({
|
|
|
7702
7995
|
onResolve
|
|
7703
7996
|
}) {
|
|
7704
7997
|
const { t } = useTranslation$1();
|
|
7705
|
-
const schema = action.fields ?? [];
|
|
7998
|
+
const schema = React65.useMemo(() => action.fields ?? [], [action.fields]);
|
|
7706
7999
|
const partial = action.partial === true;
|
|
7707
|
-
const seedValues =
|
|
8000
|
+
const seedValues = React65.useCallback(
|
|
7708
8001
|
(params) => {
|
|
7709
8002
|
if (partial) return { ...params };
|
|
7710
8003
|
const seeded = {};
|
|
@@ -7713,17 +8006,17 @@ function ConfirmActionCard({
|
|
|
7713
8006
|
},
|
|
7714
8007
|
[schema, partial]
|
|
7715
8008
|
);
|
|
7716
|
-
const [values, setValues] =
|
|
7717
|
-
const [showAll, setShowAll] =
|
|
7718
|
-
|
|
8009
|
+
const [values, setValues] = React65.useState(() => seedValues(action.params));
|
|
8010
|
+
const [showAll, setShowAll] = React65.useState(false);
|
|
8011
|
+
React65.useEffect(() => setValues(seedValues(action.params)), [action.params, seedValues]);
|
|
7719
8012
|
const isSet = (v) => v !== void 0 && v !== null && v !== "";
|
|
7720
|
-
const primaryKeys =
|
|
8013
|
+
const primaryKeys = React65.useMemo(() => {
|
|
7721
8014
|
const keys = Object.keys(action.params).filter((k) => isSet(action.params[k]));
|
|
7722
8015
|
if (partial) return keys;
|
|
7723
8016
|
for (const f of schema) if (f.required && !keys.includes(f.key)) keys.push(f.key);
|
|
7724
8017
|
return keys;
|
|
7725
8018
|
}, [action.params, schema, partial]);
|
|
7726
|
-
const extraKeys =
|
|
8019
|
+
const extraKeys = React65.useMemo(
|
|
7727
8020
|
() => schema.map((f) => f.key).filter((k) => !primaryKeys.includes(k) && k !== "id"),
|
|
7728
8021
|
[schema, primaryKeys]
|
|
7729
8022
|
);
|
|
@@ -7740,20 +8033,20 @@ function ConfirmActionCard({
|
|
|
7740
8033
|
const translatedTool = t(toolKey);
|
|
7741
8034
|
const heading = action.title ?? (translatedTool !== toolKey ? translatedTool : humanizeToolName(action.toolName));
|
|
7742
8035
|
const ruleLabel = action.scopeLabel ?? heading;
|
|
7743
|
-
const missingRequiredKeys =
|
|
8036
|
+
const missingRequiredKeys = React65.useMemo(
|
|
7744
8037
|
() => partial ? [] : schema.filter((f) => f.required && !isSet(values[f.key])).map((f) => f.key),
|
|
7745
8038
|
[schema, values, partial]
|
|
7746
8039
|
);
|
|
7747
8040
|
const canConfirm = missingRequiredKeys.length === 0;
|
|
7748
|
-
const submitted =
|
|
8041
|
+
const submitted = React65.useCallback(
|
|
7749
8042
|
() => partial ? Object.fromEntries(Object.entries(values).filter(([, v]) => isSet(v))) : values,
|
|
7750
8043
|
[partial, values]
|
|
7751
8044
|
);
|
|
7752
|
-
const approve =
|
|
8045
|
+
const approve = React65.useCallback(() => {
|
|
7753
8046
|
if (canConfirm) onResolve(true, submitted());
|
|
7754
8047
|
}, [canConfirm, onResolve, submitted]);
|
|
7755
|
-
const decline =
|
|
7756
|
-
const approveAlways =
|
|
8048
|
+
const decline = React65.useCallback(() => onResolve(false), [onResolve]);
|
|
8049
|
+
const approveAlways = React65.useCallback(() => {
|
|
7757
8050
|
if (!canConfirm) return;
|
|
7758
8051
|
grantAutoApproval({
|
|
7759
8052
|
toolName: action.toolName,
|
|
@@ -7763,7 +8056,7 @@ function ConfirmActionCard({
|
|
|
7763
8056
|
});
|
|
7764
8057
|
onResolve(true, submitted());
|
|
7765
8058
|
}, [canConfirm, action.toolName, action.scope, ruleLabel, destructive, onResolve, submitted]);
|
|
7766
|
-
|
|
8059
|
+
React65.useEffect(() => {
|
|
7767
8060
|
const handler = (event) => {
|
|
7768
8061
|
const target = event.target;
|
|
7769
8062
|
const typing = target?.tagName === "INPUT" || target?.tagName === "TEXTAREA" || target?.tagName === "SELECT";
|
|
@@ -8097,7 +8390,7 @@ function UpgradePrompt({ feature, inline, className }) {
|
|
|
8097
8390
|
const currentPlan = plans.find((p) => p.id === currentPlanId);
|
|
8098
8391
|
const currentPrice = currentPlan?.price ?? 0;
|
|
8099
8392
|
const currentPlanName = currentPlan?.name ?? tr("billing.free", "Free");
|
|
8100
|
-
const featureName =
|
|
8393
|
+
const featureName = React65.useMemo(() => {
|
|
8101
8394
|
if (!feature) return null;
|
|
8102
8395
|
const label = features.find((f) => f.id === feature)?.label;
|
|
8103
8396
|
if (label) return featureDisplayName(label);
|
|
@@ -8105,7 +8398,7 @@ function UpgradePrompt({ feature, inline, className }) {
|
|
|
8105
8398
|
const named = t(key);
|
|
8106
8399
|
return named && named !== key ? named : featureDisplayName(feature);
|
|
8107
8400
|
}, [features, feature, t]);
|
|
8108
|
-
const unlockingPlans =
|
|
8401
|
+
const unlockingPlans = React65.useMemo(
|
|
8109
8402
|
() => plans.filter((p) => p.id !== currentPlanId && p.price > currentPrice && planUnlocks(p, feature)).sort((a, b) => a.price - b.price),
|
|
8110
8403
|
[plans, currentPlanId, currentPrice, feature]
|
|
8111
8404
|
);
|
|
@@ -8283,30 +8576,30 @@ function ChatConversation({
|
|
|
8283
8576
|
usable && !pendingAction && !isStreaming,
|
|
8284
8577
|
addAttachments
|
|
8285
8578
|
);
|
|
8286
|
-
|
|
8579
|
+
React65.useEffect(ensureIntroStyles, []);
|
|
8287
8580
|
const conversationsLoaded = useChatStore((s) => s.conversationsLoaded);
|
|
8288
|
-
const hasHistoryBackend =
|
|
8581
|
+
const hasHistoryBackend = React65.useMemo(
|
|
8289
8582
|
() => !apiEndpoint && !!resolveFayzAgentConnection(agent),
|
|
8290
8583
|
[apiEndpoint, agent]
|
|
8291
8584
|
);
|
|
8292
8585
|
const conversationsPending = hasHistoryBackend && !conversationsLoaded;
|
|
8293
|
-
const [view, setView] =
|
|
8586
|
+
const [view, setView] = React65.useState(
|
|
8294
8587
|
() => useChatStore.getState().messages.length > 0 ? "thread" : "list"
|
|
8295
8588
|
);
|
|
8296
|
-
const [drawer, setDrawer] =
|
|
8297
|
-
const [atBottom, setAtBottom] =
|
|
8298
|
-
const scrollRef =
|
|
8589
|
+
const [drawer, setDrawer] = React65.useState("none");
|
|
8590
|
+
const [atBottom, setAtBottom] = React65.useState(true);
|
|
8591
|
+
const scrollRef = React65.useRef(null);
|
|
8299
8592
|
const hasMessages = messages.length > 0;
|
|
8300
8593
|
const totalTools = toolGroups.reduce((sum, g) => sum + g.tools.length, 0);
|
|
8301
|
-
const scrollToBottom =
|
|
8594
|
+
const scrollToBottom = React65.useCallback((behavior = "smooth") => {
|
|
8302
8595
|
const el = scrollRef.current;
|
|
8303
8596
|
if (!el) return;
|
|
8304
8597
|
el.scrollTo({ top: el.scrollHeight, behavior });
|
|
8305
8598
|
}, []);
|
|
8306
|
-
|
|
8599
|
+
React65.useEffect(() => {
|
|
8307
8600
|
if (atBottom) scrollToBottom();
|
|
8308
8601
|
}, [messages, activeTools, pendingAction, atBottom, scrollToBottom]);
|
|
8309
|
-
|
|
8602
|
+
React65.useEffect(() => {
|
|
8310
8603
|
loadConversations();
|
|
8311
8604
|
setSuggestionsOpen(useChatStore.getState().messages.length === 0);
|
|
8312
8605
|
return () => stopSpeaking();
|
|
@@ -8323,7 +8616,7 @@ function ChatConversation({
|
|
|
8323
8616
|
};
|
|
8324
8617
|
const queuedPrompt = useChatStore((s) => s.queuedPrompt);
|
|
8325
8618
|
const consumeQueuedPrompt = useChatStore((s) => s.consumeQueuedPrompt);
|
|
8326
|
-
|
|
8619
|
+
React65.useEffect(() => {
|
|
8327
8620
|
if (!queuedPrompt) return;
|
|
8328
8621
|
const prompt = consumeQueuedPrompt();
|
|
8329
8622
|
if (prompt && usable) send(prompt);
|
|
@@ -8331,7 +8624,7 @@ function ChatConversation({
|
|
|
8331
8624
|
const toggleDrawer = (next) => setDrawer((current) => current === next ? "none" : next);
|
|
8332
8625
|
const connectorsPending = useConnectorsSurface((s) => s.pending);
|
|
8333
8626
|
const consumeConnectorsRequest = useConnectorsSurface((s) => s.consume);
|
|
8334
|
-
|
|
8627
|
+
React65.useEffect(() => {
|
|
8335
8628
|
if (!connectorsPending) return;
|
|
8336
8629
|
setDrawer("connectors");
|
|
8337
8630
|
consumeConnectorsRequest();
|
|
@@ -8618,7 +8911,7 @@ function HeaderButton({
|
|
|
8618
8911
|
function useDelegateToAssistant() {
|
|
8619
8912
|
const queuePrompt = useChatStore((s) => s.queuePrompt);
|
|
8620
8913
|
const openPanel = useRightRailStore((s) => s.openPanel);
|
|
8621
|
-
return
|
|
8914
|
+
return React65.useCallback(
|
|
8622
8915
|
(prompt) => {
|
|
8623
8916
|
queuePrompt(prompt);
|
|
8624
8917
|
openPanel("chat");
|
|
@@ -8677,12 +8970,12 @@ function NotesPanel() {
|
|
|
8677
8970
|
const user = useAuthStore((s) => s.user);
|
|
8678
8971
|
const currentOrg = useOrganizationStore((s) => s.currentOrg);
|
|
8679
8972
|
const key = storageKey2(currentOrg?.id ?? "local", user?.id ?? "anon");
|
|
8680
|
-
const [notes, setNotes] =
|
|
8681
|
-
const [openId, setOpenId] =
|
|
8682
|
-
const [search, setSearch] =
|
|
8683
|
-
const [preview, setPreview] =
|
|
8684
|
-
const [confirmingDelete, setConfirmingDelete] =
|
|
8685
|
-
|
|
8973
|
+
const [notes, setNotes] = React65.useState(() => loadNotes(key));
|
|
8974
|
+
const [openId, setOpenId] = React65.useState(null);
|
|
8975
|
+
const [search, setSearch] = React65.useState("");
|
|
8976
|
+
const [preview, setPreview] = React65.useState(false);
|
|
8977
|
+
const [confirmingDelete, setConfirmingDelete] = React65.useState(null);
|
|
8978
|
+
React65.useEffect(() => {
|
|
8686
8979
|
setNotes(loadNotes(key));
|
|
8687
8980
|
setOpenId(null);
|
|
8688
8981
|
}, [key]);
|
|
@@ -8915,10 +9208,10 @@ ${note.content}`
|
|
|
8915
9208
|
function NoteTodosSection({ noteId, noteTitle, tr }) {
|
|
8916
9209
|
const adapter2 = useNotesTasksBridge((s) => s.adapter);
|
|
8917
9210
|
const delegate = useDelegateToAssistant();
|
|
8918
|
-
const [todos, setTodos] =
|
|
8919
|
-
const [draft, setDraft] =
|
|
8920
|
-
const [busy, setBusy] =
|
|
8921
|
-
|
|
9211
|
+
const [todos, setTodos] = React65.useState([]);
|
|
9212
|
+
const [draft, setDraft] = React65.useState("");
|
|
9213
|
+
const [busy, setBusy] = React65.useState(false);
|
|
9214
|
+
React65.useEffect(() => {
|
|
8922
9215
|
if (!adapter2) return;
|
|
8923
9216
|
let alive = true;
|
|
8924
9217
|
adapter2.listTodos(noteId).then((rows) => {
|
|
@@ -9069,11 +9362,11 @@ function NotesRailPanel() {
|
|
|
9069
9362
|
const currentOrg = useOrganizationStore((s) => s.currentOrg);
|
|
9070
9363
|
const key = storageKey2(currentOrg?.id ?? "local", user?.id ?? "anon");
|
|
9071
9364
|
const count = useNotesCount((s) => s.count);
|
|
9072
|
-
|
|
9365
|
+
React65.useEffect(() => {
|
|
9073
9366
|
useNotesCount.getState().setCount(loadNotes(key).length);
|
|
9074
9367
|
}, [key]);
|
|
9075
9368
|
useRightRailPanel(
|
|
9076
|
-
|
|
9369
|
+
React65.useMemo(
|
|
9077
9370
|
() => ({ id: "notes", label, icon: StickyNote, order: 30, badge: { count }, Component: NotesPanel }),
|
|
9078
9371
|
[label, count]
|
|
9079
9372
|
)
|
|
@@ -9487,7 +9780,13 @@ var BOOT_THEME_STORAGE_KEY = "fayz:boot-theme";
|
|
|
9487
9780
|
function persistBootPalette(colors) {
|
|
9488
9781
|
if (typeof localStorage === "undefined") return;
|
|
9489
9782
|
try {
|
|
9490
|
-
localStorage.setItem(BOOT_THEME_STORAGE_KEY, JSON.stringify({
|
|
9783
|
+
localStorage.setItem(BOOT_THEME_STORAGE_KEY, JSON.stringify({
|
|
9784
|
+
sidebar: colors.sidebar,
|
|
9785
|
+
// The boot script seeds --sidebar-foreground too: the React skeleton's
|
|
9786
|
+
// spinner draws in it, and the default (dark-on-light) token is
|
|
9787
|
+
// invisible on a seeded dark rail.
|
|
9788
|
+
sidebarForeground: colors.sidebarForeground
|
|
9789
|
+
}));
|
|
9491
9790
|
} catch {
|
|
9492
9791
|
}
|
|
9493
9792
|
}
|
|
@@ -9698,12 +9997,13 @@ function useGlobalSearch() {
|
|
|
9698
9997
|
);
|
|
9699
9998
|
const generation = useRef(0);
|
|
9700
9999
|
const search = useCallback(
|
|
9701
|
-
async (query, onPartial) => {
|
|
10000
|
+
async (query, onPartial, opts) => {
|
|
9702
10001
|
const token = ++generation.current;
|
|
9703
10002
|
return searchEverything(query, {
|
|
9704
10003
|
targets,
|
|
9705
10004
|
limit: 30,
|
|
9706
10005
|
perTarget: 5,
|
|
10006
|
+
fresh: opts?.fresh,
|
|
9707
10007
|
onPartial: onPartial ? (partial) => {
|
|
9708
10008
|
if (token === generation.current) onPartial(partial);
|
|
9709
10009
|
} : void 0
|
|
@@ -9720,7 +10020,7 @@ function useGlobalSearch() {
|
|
|
9720
10020
|
);
|
|
9721
10021
|
return { search, select, canOpen, targetCount: targets.length };
|
|
9722
10022
|
}
|
|
9723
|
-
var RouteErrorBoundary = class extends
|
|
10023
|
+
var RouteErrorBoundary = class extends React65.Component {
|
|
9724
10024
|
constructor() {
|
|
9725
10025
|
super(...arguments);
|
|
9726
10026
|
this.state = { crashed: false, report: null };
|
|
@@ -9762,7 +10062,7 @@ var RouteErrorBoundary = class extends React63.Component {
|
|
|
9762
10062
|
}
|
|
9763
10063
|
};
|
|
9764
10064
|
function RouteErrorScreen({ report, tr, onBack, onRetry, backLabel }) {
|
|
9765
|
-
const [copied, setCopied] =
|
|
10065
|
+
const [copied, setCopied] = React65.useState(false);
|
|
9766
10066
|
const copyDetails = () => {
|
|
9767
10067
|
if (!report || typeof navigator === "undefined" || !navigator.clipboard) return;
|
|
9768
10068
|
const details = [
|
|
@@ -9809,16 +10109,21 @@ function RouteErrorScreen({ report, tr, onBack, onRetry, backLabel }) {
|
|
|
9809
10109
|
] })
|
|
9810
10110
|
] });
|
|
9811
10111
|
}
|
|
10112
|
+
var WidgetSurfaceContext = React65.createContext("rail");
|
|
10113
|
+
function useWidgetSurface() {
|
|
10114
|
+
return React65.useContext(WidgetSurfaceContext);
|
|
10115
|
+
}
|
|
9812
10116
|
function WidgetSlot({
|
|
9813
10117
|
zone,
|
|
9814
10118
|
contextOverrides,
|
|
10119
|
+
surface,
|
|
9815
10120
|
...props
|
|
9816
10121
|
}) {
|
|
9817
10122
|
const runtime = usePluginRuntimeOptional();
|
|
9818
10123
|
if (!runtime) return null;
|
|
9819
10124
|
const widgets = getWidgetsForZone(runtime, zone, contextOverrides);
|
|
9820
10125
|
if (!widgets.length) return null;
|
|
9821
|
-
return /* @__PURE__ */ jsx(
|
|
10126
|
+
return /* @__PURE__ */ jsx(WidgetSurfaceContext.Provider, { value: surface ?? "rail", children: widgets.map((widget, i) => {
|
|
9822
10127
|
const Component2 = resolvePluginComponent(widget);
|
|
9823
10128
|
if (!Component2) return null;
|
|
9824
10129
|
const w = widget;
|
|
@@ -9850,7 +10155,7 @@ function useNavContribution(id, entries2) {
|
|
|
9850
10155
|
const setContribution = useNavContributionsStore((s) => s.setContribution);
|
|
9851
10156
|
const clearContribution = useNavContributionsStore((s) => s.clearContribution);
|
|
9852
10157
|
const key = JSON.stringify(entries2);
|
|
9853
|
-
|
|
10158
|
+
React65.useEffect(() => {
|
|
9854
10159
|
setContribution(id, entries2);
|
|
9855
10160
|
return () => clearContribution(id);
|
|
9856
10161
|
}, [id, key]);
|
|
@@ -9880,7 +10185,7 @@ function useContextualNav(nav) {
|
|
|
9880
10185
|
const setNav = useContextualNavStore((s) => s.setNav);
|
|
9881
10186
|
const clearNav = useContextualNavStore((s) => s.clearNav);
|
|
9882
10187
|
const key = nav ? JSON.stringify(nav) : null;
|
|
9883
|
-
|
|
10188
|
+
React65.useEffect(() => {
|
|
9884
10189
|
if (!nav) return;
|
|
9885
10190
|
setNav(nav);
|
|
9886
10191
|
return () => clearNav(nav.base);
|
|
@@ -10031,10 +10336,10 @@ function SeuSiteWidget({ fallback, onEdit }) {
|
|
|
10031
10336
|
const load = useFayzProjectsStore((s) => s.load);
|
|
10032
10337
|
const loadedFor = useFayzProjectsStore((s) => s.loadedFor);
|
|
10033
10338
|
const collapsed = useLayoutStore((s) => s.sidebarCollapsed);
|
|
10034
|
-
const [selectedId, setSelectedId] =
|
|
10035
|
-
const [hovered, setHovered] =
|
|
10036
|
-
const [primed, setPrimed] =
|
|
10037
|
-
const closeTimer =
|
|
10339
|
+
const [selectedId, setSelectedId] = React65.useState(null);
|
|
10340
|
+
const [hovered, setHovered] = React65.useState(false);
|
|
10341
|
+
const [primed, setPrimed] = React65.useState(false);
|
|
10342
|
+
const closeTimer = React65.useRef(null);
|
|
10038
10343
|
const cancelClose = () => {
|
|
10039
10344
|
if (closeTimer.current) {
|
|
10040
10345
|
clearTimeout(closeTimer.current);
|
|
@@ -10050,8 +10355,8 @@ function SeuSiteWidget({ fallback, onEdit }) {
|
|
|
10050
10355
|
cancelClose();
|
|
10051
10356
|
closeTimer.current = setTimeout(() => setHovered(false), 140);
|
|
10052
10357
|
};
|
|
10053
|
-
|
|
10054
|
-
|
|
10358
|
+
React65.useEffect(() => () => cancelClose(), []);
|
|
10359
|
+
React65.useEffect(() => {
|
|
10055
10360
|
if (loadedFor !== (currentOrgId ?? null)) void load(currentOrgId);
|
|
10056
10361
|
}, [currentOrgId, loadedFor, load]);
|
|
10057
10362
|
const active2 = projects.find((p) => p.id === selectedId) ?? defaultProjectOf(projects) ?? synthFromFallback(fallback);
|
|
@@ -10140,10 +10445,10 @@ function SitePreview({
|
|
|
10140
10445
|
onEdit,
|
|
10141
10446
|
tr
|
|
10142
10447
|
}) {
|
|
10143
|
-
const [nonce, setNonce] =
|
|
10144
|
-
const [loading, setLoading] =
|
|
10448
|
+
const [nonce, setNonce] = React65.useState(0);
|
|
10449
|
+
const [loading, setLoading] = React65.useState(true);
|
|
10145
10450
|
const url = project.previewUrl;
|
|
10146
|
-
|
|
10451
|
+
React65.useEffect(() => {
|
|
10147
10452
|
setLoading(true);
|
|
10148
10453
|
}, [nonce, url]);
|
|
10149
10454
|
const action = "flex items-center gap-1.5 rounded-button px-2 py-1 text-[11.5px] font-medium text-sidebar-foreground/80 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground disabled:cursor-not-allowed disabled:opacity-40";
|
|
@@ -10240,8 +10545,8 @@ function RightRail({ frame = true }) {
|
|
|
10240
10545
|
const openPanel = useRightRailStore((s) => s.openPanel);
|
|
10241
10546
|
const close = useRightRailStore((s) => s.close);
|
|
10242
10547
|
const setWidth = useRightRailStore((s) => s.setWidth);
|
|
10243
|
-
const rootRef =
|
|
10244
|
-
|
|
10548
|
+
const rootRef = React65.useRef(null);
|
|
10549
|
+
React65.useEffect(() => {
|
|
10245
10550
|
if (!open) return;
|
|
10246
10551
|
const el = rootRef.current;
|
|
10247
10552
|
if (!el) return;
|
|
@@ -10466,9 +10771,9 @@ var TYPE_COLORS = {
|
|
|
10466
10771
|
fix: "text-success"
|
|
10467
10772
|
};
|
|
10468
10773
|
function ChangelogFeed({ changelogUrl, className }) {
|
|
10469
|
-
const [entries2, setEntries] =
|
|
10470
|
-
const [loading, setLoading] =
|
|
10471
|
-
|
|
10774
|
+
const [entries2, setEntries] = React65.useState([]);
|
|
10775
|
+
const [loading, setLoading] = React65.useState(false);
|
|
10776
|
+
React65.useEffect(() => {
|
|
10472
10777
|
if (!changelogUrl) return;
|
|
10473
10778
|
setLoading(true);
|
|
10474
10779
|
fetch(changelogUrl).then((r) => r.json()).then((data) => setEntries(data)).catch(() => setEntries([])).finally(() => setLoading(false));
|
|
@@ -10531,7 +10836,7 @@ function NotificationInbox({
|
|
|
10531
10836
|
changelogUrl,
|
|
10532
10837
|
className
|
|
10533
10838
|
}) {
|
|
10534
|
-
const [activeTab, setActiveTab] =
|
|
10839
|
+
const [activeTab, setActiveTab] = React65.useState("inbox");
|
|
10535
10840
|
const unreadCount = notifications.filter((n) => !n.read).length;
|
|
10536
10841
|
const inboxNotifications = notifications.filter((n) => n.category !== "changelog");
|
|
10537
10842
|
return /* @__PURE__ */ jsxs("div", { className: cn$1("flex w-80 flex-col", className), children: [
|
|
@@ -10627,15 +10932,15 @@ function NotificationInbox({
|
|
|
10627
10932
|
] });
|
|
10628
10933
|
}
|
|
10629
10934
|
function ConnectConsentPage({ appName, logo }) {
|
|
10630
|
-
const [state, setState] =
|
|
10631
|
-
const [tenantId2, setTenantId] =
|
|
10632
|
-
const request =
|
|
10935
|
+
const [state, setState] = React65__default.useState({ status: "loading" });
|
|
10936
|
+
const [tenantId2, setTenantId] = React65__default.useState("");
|
|
10937
|
+
const request = React65__default.useMemo(
|
|
10633
10938
|
() => new URLSearchParams(window.location.search).get("request") ?? "",
|
|
10634
10939
|
[]
|
|
10635
10940
|
);
|
|
10636
|
-
const connection =
|
|
10941
|
+
const connection = React65__default.useMemo(() => resolveFayzAgentConnection(), []);
|
|
10637
10942
|
const product = appName ?? document.title ?? "este app";
|
|
10638
|
-
const authorizedFetch =
|
|
10943
|
+
const authorizedFetch = React65__default.useCallback(
|
|
10639
10944
|
async (path, init) => {
|
|
10640
10945
|
if (!connection) throw new Error("Este app n\xE3o est\xE1 ligado a um projeto Fayz.");
|
|
10641
10946
|
const supabase = getFayzSupabaseClientOptional();
|
|
@@ -10659,7 +10964,7 @@ function ConnectConsentPage({ appName, logo }) {
|
|
|
10659
10964
|
},
|
|
10660
10965
|
[connection]
|
|
10661
10966
|
);
|
|
10662
|
-
|
|
10967
|
+
React65__default.useEffect(() => {
|
|
10663
10968
|
let cancelled = false;
|
|
10664
10969
|
(async () => {
|
|
10665
10970
|
if (!request) {
|
|
@@ -10900,25 +11205,25 @@ function AddConnectorPanel({
|
|
|
10900
11205
|
onSelect
|
|
10901
11206
|
}) {
|
|
10902
11207
|
const { t } = useTranslation$1();
|
|
10903
|
-
const [query, setQuery] =
|
|
11208
|
+
const [query, setQuery] = React65__default.useState("");
|
|
10904
11209
|
const modules = useInstalledModuleIds();
|
|
10905
11210
|
const catalog = useConnectorCatalog();
|
|
10906
11211
|
const scoped = !!categories?.length;
|
|
10907
|
-
const addable =
|
|
11212
|
+
const addable = React65__default.useMemo(
|
|
10908
11213
|
() => inCategories(addableConnectors(connectors ?? []), categories),
|
|
10909
11214
|
[connectors, categories]
|
|
10910
11215
|
);
|
|
10911
|
-
const shelf =
|
|
11216
|
+
const shelf = React65__default.useMemo(() => {
|
|
10912
11217
|
if (connectors === null) return [];
|
|
10913
11218
|
return inCategories(
|
|
10914
11219
|
shelfIntegrations({ present: connectors, installedModules: modules, catalog: catalog ?? [] }),
|
|
10915
11220
|
categories
|
|
10916
11221
|
);
|
|
10917
11222
|
}, [connectors, modules, catalog, categories]);
|
|
10918
|
-
const filtered =
|
|
10919
|
-
const filteredShelf =
|
|
10920
|
-
const soon =
|
|
10921
|
-
const elsewhere =
|
|
11223
|
+
const filtered = React65__default.useMemo(() => filterConnectors(addable, "all", query), [addable, query]);
|
|
11224
|
+
const filteredShelf = React65__default.useMemo(() => filterAvailable(shelf, query), [shelf, query]);
|
|
11225
|
+
const soon = React65__default.useMemo(() => comingSoonHere(filteredShelf), [filteredShelf]);
|
|
11226
|
+
const elsewhere = React65__default.useMemo(() => withAnotherModule(filteredShelf), [filteredShelf]);
|
|
10922
11227
|
const searchable = addable.length + shelf.length > 6;
|
|
10923
11228
|
return /* @__PURE__ */ jsx(Modal, { open, onOpenChange, children: /* @__PURE__ */ jsxs(ModalContent, { size: "2xl", children: [
|
|
10924
11229
|
/* @__PURE__ */ jsxs(ModalHeader, { children: [
|
|
@@ -11077,20 +11382,20 @@ function AddConnectorButton({ onClick }) {
|
|
|
11077
11382
|
function ConnectorsTab() {
|
|
11078
11383
|
const { t } = useTranslation$1();
|
|
11079
11384
|
const { connectors, error, reload, revokeGrant, agentAvailable, tenantReady } = useConnectors();
|
|
11080
|
-
const [adding, setAdding] =
|
|
11081
|
-
const [selected, setSelected] =
|
|
11082
|
-
const [filter, setFilter] =
|
|
11083
|
-
const [failure, setFailure] =
|
|
11385
|
+
const [adding, setAdding] = React65__default.useState(false);
|
|
11386
|
+
const [selected, setSelected] = React65__default.useState(null);
|
|
11387
|
+
const [filter, setFilter] = React65__default.useState("all");
|
|
11388
|
+
const [failure, setFailure] = React65__default.useState(null);
|
|
11084
11389
|
const assistantAvailable = useConnectorsPanelAvailable();
|
|
11085
|
-
const openJourney =
|
|
11390
|
+
const openJourney = React65__default.useCallback(
|
|
11086
11391
|
(connector) => {
|
|
11087
11392
|
if (assistantAvailable) openConnectorsPanel(connector);
|
|
11088
11393
|
else setSelected(connector);
|
|
11089
11394
|
},
|
|
11090
11395
|
[assistantAvailable]
|
|
11091
11396
|
);
|
|
11092
|
-
const visible =
|
|
11093
|
-
|
|
11397
|
+
const visible = React65__default.useMemo(() => filterConnectors(connectors ?? [], filter), [connectors, filter]);
|
|
11398
|
+
React65__default.useEffect(() => {
|
|
11094
11399
|
if (!selected || !connectors) return;
|
|
11095
11400
|
const fresh = connectors.find((c) => c.id === selected.id);
|
|
11096
11401
|
if (fresh && fresh !== selected) setSelected(fresh);
|
|
@@ -11103,23 +11408,17 @@ function ConnectorsTab() {
|
|
|
11103
11408
|
return /* @__PURE__ */ jsx(Empty, { title: t("connectors.noOrg"), body: t("connectors.noOrgBody") });
|
|
11104
11409
|
}
|
|
11105
11410
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
11106
|
-
/* @__PURE__ */
|
|
11107
|
-
|
|
11108
|
-
|
|
11109
|
-
|
|
11110
|
-
|
|
11111
|
-
|
|
11112
|
-
|
|
11113
|
-
|
|
11114
|
-
|
|
11115
|
-
|
|
11116
|
-
|
|
11117
|
-
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
|
|
11118
|
-
t("connectors.add")
|
|
11119
|
-
]
|
|
11120
|
-
}
|
|
11121
|
-
)
|
|
11122
|
-
] }),
|
|
11411
|
+
/* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsxs(
|
|
11412
|
+
"button",
|
|
11413
|
+
{
|
|
11414
|
+
onClick: () => setAdding(true),
|
|
11415
|
+
className: "inline-flex shrink-0 items-center gap-1.5 rounded-lg bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90",
|
|
11416
|
+
children: [
|
|
11417
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
|
|
11418
|
+
t("connectors.add")
|
|
11419
|
+
]
|
|
11420
|
+
}
|
|
11421
|
+
) }),
|
|
11123
11422
|
/* @__PURE__ */ jsx(
|
|
11124
11423
|
AddConnectorPanel,
|
|
11125
11424
|
{
|
|
@@ -11136,7 +11435,7 @@ function ConnectorsTab() {
|
|
|
11136
11435
|
(connectors?.length ?? 0) > 4 && /* @__PURE__ */ jsx(Filters, { value: filter, onChange: setFilter }),
|
|
11137
11436
|
connectors === null && /* @__PURE__ */ jsx(ConnectionsSkeleton, {}),
|
|
11138
11437
|
connectors !== null && visible.length === 0 && /* @__PURE__ */ jsx(Empty, { title: t("connectors.emptyTitle"), body: t("connectors.emptyBody") }),
|
|
11139
|
-
visible.length > 0 && /* @__PURE__ */ jsx("ul", { className: "divide-y divide-border overflow-hidden rounded-
|
|
11438
|
+
visible.length > 0 && /* @__PURE__ */ jsx("ul", { className: "fayz-glass-surface divide-y divide-border overflow-hidden rounded-card border bg-card text-card-foreground shadow-sm", children: visible.map((c) => /* @__PURE__ */ jsx(ConnectorRow, { connector: c, onOpen: openJourney }, c.id)) }),
|
|
11140
11439
|
/* @__PURE__ */ jsx(
|
|
11141
11440
|
ConnectorDetail,
|
|
11142
11441
|
{
|
|
@@ -11171,7 +11470,7 @@ function Filters({ value, onChange }) {
|
|
|
11171
11470
|
)) });
|
|
11172
11471
|
}
|
|
11173
11472
|
function ConnectionsSkeleton() {
|
|
11174
|
-
return /* @__PURE__ */ jsx("ul", { className: "divide-y divide-border overflow-hidden rounded-
|
|
11473
|
+
return /* @__PURE__ */ jsx("ul", { className: "fayz-glass-surface divide-y divide-border overflow-hidden rounded-card border bg-card text-card-foreground shadow-sm", "aria-hidden": true, children: [0, 1].map((i) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-4 p-4", children: [
|
|
11175
11474
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-10 shrink-0 rounded-lg" }),
|
|
11176
11475
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-2 py-0.5", children: [
|
|
11177
11476
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-40" }),
|
|
@@ -11250,7 +11549,7 @@ function oauthFailureMessage(t, result) {
|
|
|
11250
11549
|
function useConnectorOAuthReturn() {
|
|
11251
11550
|
const { t } = useTranslation$1();
|
|
11252
11551
|
const runtime = usePluginRuntimeOptional();
|
|
11253
|
-
|
|
11552
|
+
React65__default.useEffect(() => {
|
|
11254
11553
|
if (typeof window === "undefined") return;
|
|
11255
11554
|
const result = readConnectorOAuthReturn(window.location.search);
|
|
11256
11555
|
if (!result) return;
|
|
@@ -11285,8 +11584,8 @@ function ConnectorDeliveries({
|
|
|
11285
11584
|
limit = 10
|
|
11286
11585
|
}) {
|
|
11287
11586
|
const { t } = useTranslation$1();
|
|
11288
|
-
const [rows, setRows] =
|
|
11289
|
-
|
|
11587
|
+
const [rows, setRows] = React65__default.useState(null);
|
|
11588
|
+
React65__default.useEffect(() => {
|
|
11290
11589
|
let cancelled = false;
|
|
11291
11590
|
void load({ limit }).then((r) => {
|
|
11292
11591
|
if (!cancelled) setRows(r);
|
|
@@ -11360,11 +11659,11 @@ var CURRENCIES = [
|
|
|
11360
11659
|
function CompanySettings({ tenant, onSave }) {
|
|
11361
11660
|
const { t } = useTranslation$1();
|
|
11362
11661
|
const { locale: uiLocale, setLocale: setUiLocale } = useLocaleStore();
|
|
11363
|
-
const [name, setName] =
|
|
11364
|
-
const [timezone, setTimezone] =
|
|
11365
|
-
const [currency, setCurrency] =
|
|
11366
|
-
const [saving, setSaving] =
|
|
11367
|
-
|
|
11662
|
+
const [name, setName] = React65.useState(tenant?.name ?? "");
|
|
11663
|
+
const [timezone, setTimezone] = React65.useState(tenant?.settings?.timezone ?? "UTC");
|
|
11664
|
+
const [currency, setCurrency] = React65.useState(tenant?.settings?.currency ?? "USD");
|
|
11665
|
+
const [saving, setSaving] = React65.useState(false);
|
|
11666
|
+
React65.useEffect(() => {
|
|
11368
11667
|
if (tenant) {
|
|
11369
11668
|
setName(tenant.name);
|
|
11370
11669
|
setTimezone(tenant.settings?.timezone ?? "UTC");
|
|
@@ -11502,10 +11801,10 @@ function getInitials(name) {
|
|
|
11502
11801
|
}
|
|
11503
11802
|
function UserProfile({ user, onSave, onAvatarChange }) {
|
|
11504
11803
|
const { t } = useTranslation$1();
|
|
11505
|
-
const [fullName, setFullName] =
|
|
11506
|
-
const [saving, setSaving] =
|
|
11507
|
-
const fileInputRef =
|
|
11508
|
-
|
|
11804
|
+
const [fullName, setFullName] = React65.useState(user?.fullName ?? "");
|
|
11805
|
+
const [saving, setSaving] = React65.useState(false);
|
|
11806
|
+
const fileInputRef = React65.useRef(null);
|
|
11807
|
+
React65.useEffect(() => {
|
|
11509
11808
|
if (user) {
|
|
11510
11809
|
setFullName(user.fullName);
|
|
11511
11810
|
}
|
|
@@ -11610,8 +11909,8 @@ function UserProfile({ user, onSave, onAvatarChange }) {
|
|
|
11610
11909
|
function ConnectedUserProfile() {
|
|
11611
11910
|
const user = useAuthStore((s) => s.user);
|
|
11612
11911
|
const setUser = useAuthStore((s) => s.setUser);
|
|
11613
|
-
const [profile, setProfile] =
|
|
11614
|
-
|
|
11912
|
+
const [profile, setProfile] = React65.useState(null);
|
|
11913
|
+
React65.useEffect(() => {
|
|
11615
11914
|
const supabase = getFayzSupabaseClientOptional();
|
|
11616
11915
|
if (!user || !supabase) return;
|
|
11617
11916
|
let cancelled = false;
|
|
@@ -11711,9 +12010,9 @@ function SecuritySettings({
|
|
|
11711
12010
|
onTenantSecurityChange
|
|
11712
12011
|
}) {
|
|
11713
12012
|
const { t } = useTranslation$1();
|
|
11714
|
-
const [resetting, setResetting] =
|
|
11715
|
-
const [resetSent, setResetSent] =
|
|
11716
|
-
const [savingTenant, setSavingTenant] =
|
|
12013
|
+
const [resetting, setResetting] = React65.useState(false);
|
|
12014
|
+
const [resetSent, setResetSent] = React65.useState(false);
|
|
12015
|
+
const [savingTenant, setSavingTenant] = React65.useState(false);
|
|
11717
12016
|
const handleResetPassword = async () => {
|
|
11718
12017
|
if (!onResetPassword) return;
|
|
11719
12018
|
setResetting(true);
|
|
@@ -11889,8 +12188,8 @@ function FileUploadField({
|
|
|
11889
12188
|
hint
|
|
11890
12189
|
}) {
|
|
11891
12190
|
const { t } = useTranslation$1();
|
|
11892
|
-
const inputRef =
|
|
11893
|
-
const [preview, setPreview] =
|
|
12191
|
+
const inputRef = React65.useRef(null);
|
|
12192
|
+
const [preview, setPreview] = React65.useState(null);
|
|
11894
12193
|
const handleChange = (e) => {
|
|
11895
12194
|
const file = e.target.files?.[0];
|
|
11896
12195
|
if (file) {
|
|
@@ -11957,14 +12256,14 @@ function FileUploadField({
|
|
|
11957
12256
|
}
|
|
11958
12257
|
function BrandingSettings({ branding, onSave }) {
|
|
11959
12258
|
const { t } = useTranslation$1();
|
|
11960
|
-
const [primaryColor, setPrimaryColor] =
|
|
11961
|
-
const [accentColor, setAccentColor] =
|
|
11962
|
-
const [logoFile, setLogoFile] =
|
|
11963
|
-
const [faviconFile, setFaviconFile] =
|
|
11964
|
-
const [logoUrl, setLogoUrl] =
|
|
11965
|
-
const [faviconUrl, setFaviconUrl] =
|
|
11966
|
-
const [saving, setSaving] =
|
|
11967
|
-
|
|
12259
|
+
const [primaryColor, setPrimaryColor] = React65.useState(branding?.primaryColor ?? "#000000");
|
|
12260
|
+
const [accentColor, setAccentColor] = React65.useState(branding?.accentColor ?? "#6366f1");
|
|
12261
|
+
const [logoFile, setLogoFile] = React65.useState(null);
|
|
12262
|
+
const [faviconFile, setFaviconFile] = React65.useState(null);
|
|
12263
|
+
const [logoUrl, setLogoUrl] = React65.useState(branding?.logoUrl ?? "");
|
|
12264
|
+
const [faviconUrl, setFaviconUrl] = React65.useState(branding?.faviconUrl ?? "");
|
|
12265
|
+
const [saving, setSaving] = React65.useState(false);
|
|
12266
|
+
React65.useEffect(() => {
|
|
11968
12267
|
if (branding) {
|
|
11969
12268
|
setPrimaryColor(branding.primaryColor ?? "#000000");
|
|
11970
12269
|
setAccentColor(branding.accentColor ?? "#6366f1");
|
|
@@ -12170,9 +12469,9 @@ function ProjectsSettings() {
|
|
|
12170
12469
|
const projects = useFayzProjectsStore((s) => s.projects);
|
|
12171
12470
|
const load = useFayzProjectsStore((s) => s.load);
|
|
12172
12471
|
const refresh = useFayzProjectsStore((s) => s.refresh);
|
|
12173
|
-
const [adding, setAdding] =
|
|
12174
|
-
const [editing, setEditing] =
|
|
12175
|
-
|
|
12472
|
+
const [adding, setAdding] = React65.useState(false);
|
|
12473
|
+
const [editing, setEditing] = React65.useState(null);
|
|
12474
|
+
React65.useEffect(() => {
|
|
12176
12475
|
void load(currentOrgId);
|
|
12177
12476
|
}, [currentOrgId, load]);
|
|
12178
12477
|
const onCreate = async (input) => {
|
|
@@ -12194,16 +12493,10 @@ function ProjectsSettings() {
|
|
|
12194
12493
|
await refresh();
|
|
12195
12494
|
};
|
|
12196
12495
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
12197
|
-
/* @__PURE__ */ jsxs(
|
|
12198
|
-
/* @__PURE__ */
|
|
12199
|
-
|
|
12200
|
-
|
|
12201
|
-
] }),
|
|
12202
|
-
!adding && /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: () => setAdding(true), children: [
|
|
12203
|
-
/* @__PURE__ */ jsx(Plus, { className: "mr-1.5 h-4 w-4" }),
|
|
12204
|
-
" Adicionar"
|
|
12205
|
-
] })
|
|
12206
|
-
] }),
|
|
12496
|
+
!adding && /* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: () => setAdding(true), children: [
|
|
12497
|
+
/* @__PURE__ */ jsx(Plus, { className: "mr-1.5 h-4 w-4" }),
|
|
12498
|
+
" Adicionar"
|
|
12499
|
+
] }) }),
|
|
12207
12500
|
adding && /* @__PURE__ */ jsx(ProjectForm, { onCancel: () => setAdding(false), onSubmit: onCreate }),
|
|
12208
12501
|
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
12209
12502
|
projects.length === 0 && !adding && /* @__PURE__ */ jsx("p", { className: "rounded-card border border-dashed border-border p-6 text-center text-sm text-muted-foreground", children: "Nenhum projeto ainda. Adicione o site do cliente (id do projeto fayz + URLs de preview e editor)." }),
|
|
@@ -12244,12 +12537,12 @@ function ProjectRow({ project, onEdit, onDelete, onSetDefault }) {
|
|
|
12244
12537
|
] });
|
|
12245
12538
|
}
|
|
12246
12539
|
function ProjectForm({ initial, onCancel, onSubmit }) {
|
|
12247
|
-
const [name, setName] =
|
|
12248
|
-
const [kind, setKind] =
|
|
12249
|
-
const [fayzProjectId, setFayzProjectId] =
|
|
12250
|
-
const [previewUrl, setPreviewUrl] =
|
|
12251
|
-
const [isDefault, setIsDefault] =
|
|
12252
|
-
const [storefrontEnabled, setStorefrontEnabled] =
|
|
12540
|
+
const [name, setName] = React65.useState(initial?.name ?? "");
|
|
12541
|
+
const [kind, setKind] = React65.useState(initial?.kind ?? "site");
|
|
12542
|
+
const [fayzProjectId, setFayzProjectId] = React65.useState(initial?.fayzProjectId ?? "");
|
|
12543
|
+
const [previewUrl, setPreviewUrl] = React65.useState(initial?.previewUrl ?? "");
|
|
12544
|
+
const [isDefault, setIsDefault] = React65.useState(initial?.isDefault ?? false);
|
|
12545
|
+
const [storefrontEnabled, setStorefrontEnabled] = React65.useState(initial?.storefrontEnabled ?? false);
|
|
12253
12546
|
const submit = () => onSubmit({
|
|
12254
12547
|
name: name.trim() || "Meu site",
|
|
12255
12548
|
kind,
|
|
@@ -12286,12 +12579,25 @@ function ProjectForm({ initial, onCancel, onSubmit }) {
|
|
|
12286
12579
|
] })
|
|
12287
12580
|
] });
|
|
12288
12581
|
}
|
|
12582
|
+
function useIsWide() {
|
|
12583
|
+
const query = "(min-width: 768px)";
|
|
12584
|
+
const [wide, setWide] = React65.useState(
|
|
12585
|
+
() => typeof window === "undefined" ? true : window.matchMedia(query).matches
|
|
12586
|
+
);
|
|
12587
|
+
React65.useEffect(() => {
|
|
12588
|
+
const mq = window.matchMedia(query);
|
|
12589
|
+
const onChange = () => setWide(mq.matches);
|
|
12590
|
+
mq.addEventListener("change", onChange);
|
|
12591
|
+
return () => mq.removeEventListener("change", onChange);
|
|
12592
|
+
}, []);
|
|
12593
|
+
return wide;
|
|
12594
|
+
}
|
|
12289
12595
|
function useCoreSettingsTabs({
|
|
12290
12596
|
showCompany = true,
|
|
12291
12597
|
showBranding = true
|
|
12292
12598
|
} = {}) {
|
|
12293
12599
|
const { t } = useTranslation$1();
|
|
12294
|
-
return
|
|
12600
|
+
return React65.useMemo(() => [
|
|
12295
12601
|
...showCompany ? [{ id: "general", label: t("settings.general"), icon: /* @__PURE__ */ jsx(Building2, { className: "h-4 w-4" }), iconName: "Building2", component: /* @__PURE__ */ jsx(ConnectedCompanySettings, {}) }] : [],
|
|
12296
12602
|
{ id: "profile", label: t("settings.profile"), icon: /* @__PURE__ */ jsx(User, { className: "h-4 w-4" }), iconName: "User", component: /* @__PURE__ */ jsx(ConnectedUserProfile, {}) },
|
|
12297
12603
|
{ id: "security", label: t("settings.security"), icon: /* @__PURE__ */ jsx(Shield, { className: "h-4 w-4" }), iconName: "Shield", component: /* @__PURE__ */ jsx(ConnectedSecuritySettings, {}) },
|
|
@@ -12317,6 +12623,7 @@ function SettingsPage({
|
|
|
12317
12623
|
activeTabId
|
|
12318
12624
|
}) {
|
|
12319
12625
|
const { t } = useTranslation$1();
|
|
12626
|
+
const wide = useIsWide();
|
|
12320
12627
|
const defaultTabs = useCoreSettingsTabs({ showCompany, showBranding });
|
|
12321
12628
|
const baseTabs = tabs ?? defaultTabs;
|
|
12322
12629
|
const resolvedTabs = extraTabs ? [...baseTabs, ...extraTabs] : baseTabs;
|
|
@@ -12329,10 +12636,10 @@ function SettingsPage({
|
|
|
12329
12636
|
}
|
|
12330
12637
|
return null;
|
|
12331
12638
|
}
|
|
12332
|
-
const [activeTab, setActiveTab] =
|
|
12639
|
+
const [activeTab, setActiveTab] = React65.useState(() => {
|
|
12333
12640
|
return getTabFromHash() ?? defaultTab ?? null;
|
|
12334
12641
|
});
|
|
12335
|
-
|
|
12642
|
+
React65.useEffect(() => {
|
|
12336
12643
|
const handler = () => {
|
|
12337
12644
|
const tab = getTabFromHash();
|
|
12338
12645
|
if (tab) setActiveTab(tab);
|
|
@@ -12355,7 +12662,7 @@ function SettingsPage({
|
|
|
12355
12662
|
setActiveTab(null);
|
|
12356
12663
|
window.location.hash = "/settings";
|
|
12357
12664
|
};
|
|
12358
|
-
const sections =
|
|
12665
|
+
const sections = React65.useMemo(() => {
|
|
12359
12666
|
const out = [];
|
|
12360
12667
|
for (const tab of resolvedTabs) {
|
|
12361
12668
|
const heading = tab.isPlugin ? tab.group ?? t("common.plugins") : null;
|
|
@@ -12382,40 +12689,39 @@ function SettingsPage({
|
|
|
12382
12689
|
) }, tab.id)) })
|
|
12383
12690
|
] }, section.key)) });
|
|
12384
12691
|
return /* @__PURE__ */ jsxs("div", { className: cn$1("fz-container space-y-6", className), children: [
|
|
12385
|
-
!controlled && showingContent && /* @__PURE__ */ jsxs(
|
|
12692
|
+
!controlled && showingContent && !wide && /* @__PURE__ */ jsxs(
|
|
12386
12693
|
"button",
|
|
12387
12694
|
{
|
|
12388
12695
|
onClick: handleBack,
|
|
12389
|
-
className: "flex items-center gap-1.5 text-sm text-muted-foreground transition-colors hover:text-foreground
|
|
12696
|
+
className: "flex items-center gap-1.5 text-sm text-muted-foreground transition-colors hover:text-foreground",
|
|
12390
12697
|
children: [
|
|
12391
12698
|
/* @__PURE__ */ jsx(ArrowLeft, { className: "h-4 w-4" }),
|
|
12392
12699
|
t("settings.title")
|
|
12393
12700
|
]
|
|
12394
12701
|
}
|
|
12395
12702
|
),
|
|
12396
|
-
!showingContent && /* @__PURE__ */ jsxs("div", {
|
|
12703
|
+
!showingContent && !wide && /* @__PURE__ */ jsxs("div", { children: [
|
|
12397
12704
|
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold tracking-tight", children: t("settings.title") }),
|
|
12398
12705
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("settings.subtitle") })
|
|
12399
12706
|
] }),
|
|
12400
12707
|
beforeContent,
|
|
12401
|
-
/* @__PURE__ */
|
|
12402
|
-
|
|
12403
|
-
|
|
12708
|
+
!hideNav && /* @__PURE__ */ jsx(PageRail, { children: /* @__PURE__ */ jsx("nav", { className: "hidden w-52 shrink-0 overflow-y-auto border-r border-border p-3 md:block", children: sections.map((section, i) => /* @__PURE__ */ jsxs("div", { className: i > 0 ? "mt-3 border-t border-border pt-3" : void 0, children: [
|
|
12709
|
+
section.heading && /* @__PURE__ */ jsx("p", { className: "px-3 pb-1 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: section.heading }),
|
|
12710
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: section.items.map((tab) => /* @__PURE__ */ jsx(
|
|
12711
|
+
RailNavItem,
|
|
12404
12712
|
{
|
|
12405
|
-
|
|
12406
|
-
|
|
12407
|
-
|
|
12408
|
-
|
|
12409
|
-
|
|
12410
|
-
|
|
12411
|
-
|
|
12412
|
-
|
|
12413
|
-
|
|
12414
|
-
|
|
12415
|
-
|
|
12416
|
-
|
|
12417
|
-
] }),
|
|
12418
|
-
/* @__PURE__ */ jsx("div", { className: "md:hidden", children: showingContent ? /* @__PURE__ */ jsx("div", { className: "fz-container", children: activeContent }) : settingsIndex }),
|
|
12713
|
+
item: {
|
|
12714
|
+
id: tab.id,
|
|
12715
|
+
label: tab.label,
|
|
12716
|
+
icon: tab.iconName,
|
|
12717
|
+
active: desktopTab === tab.id,
|
|
12718
|
+
onClick: () => handleSelectTab(tab.id)
|
|
12719
|
+
}
|
|
12720
|
+
},
|
|
12721
|
+
tab.id
|
|
12722
|
+
)) })
|
|
12723
|
+
] }, section.key)) }) }),
|
|
12724
|
+
wide ? /* @__PURE__ */ jsx("div", { className: "fz-container min-w-0", children: withTrail(desktopTabDef?.component ?? null, desktopTabDef) }) : showingContent ? /* @__PURE__ */ jsx("div", { className: "fz-container", children: activeContent }) : settingsIndex,
|
|
12419
12725
|
afterContent
|
|
12420
12726
|
] });
|
|
12421
12727
|
}
|
|
@@ -12434,10 +12740,10 @@ function InviteMemberDialog({ open, onOpenChange, defaultEmail }) {
|
|
|
12434
12740
|
const profiles = usePermissionsStore((s) => s.profiles);
|
|
12435
12741
|
const setInvites = useInviteStore((s) => s.setInvites);
|
|
12436
12742
|
const { user } = useAuthStore();
|
|
12437
|
-
const [emails, setEmails] =
|
|
12438
|
-
const [profileId, setProfileId] =
|
|
12439
|
-
const [sending, setSending] =
|
|
12440
|
-
const [sent, setSent] =
|
|
12743
|
+
const [emails, setEmails] = React65.useState([defaultEmail ?? ""]);
|
|
12744
|
+
const [profileId, setProfileId] = React65.useState(profiles[1]?.id ?? profiles[0]?.id ?? "");
|
|
12745
|
+
const [sending, setSending] = React65.useState(false);
|
|
12746
|
+
const [sent, setSent] = React65.useState(false);
|
|
12441
12747
|
const addEmail = () => setEmails((prev) => [...prev, ""]);
|
|
12442
12748
|
const updateEmail = (idx, value) => {
|
|
12443
12749
|
setEmails((prev) => {
|
|
@@ -12534,14 +12840,14 @@ function TeamTab() {
|
|
|
12534
12840
|
const { user } = useAuthStore();
|
|
12535
12841
|
const hasSystemPermission = useSystemPermission();
|
|
12536
12842
|
const personMode = teamPersonKinds.length > 0 && typeof adapter2?.listTeam === "function";
|
|
12537
|
-
const [team, setTeam] =
|
|
12538
|
-
const [inviteOpen, setInviteOpen] =
|
|
12843
|
+
const [team, setTeam] = React65.useState(null);
|
|
12844
|
+
const [inviteOpen, setInviteOpen] = React65.useState(false);
|
|
12539
12845
|
const guardSeats = useLimitGuard("users");
|
|
12540
12846
|
const handleOpenInvite = async () => {
|
|
12541
12847
|
if (await guardSeats(1) === "blocked") return;
|
|
12542
12848
|
setInviteOpen(true);
|
|
12543
12849
|
};
|
|
12544
|
-
const reloadTeam =
|
|
12850
|
+
const reloadTeam = React65.useCallback(async () => {
|
|
12545
12851
|
if (!adapter2 || !currentOrg) return;
|
|
12546
12852
|
if (personMode && adapter2.listTeam) {
|
|
12547
12853
|
setTeam(await adapter2.listTeam(currentOrg.id, teamPersonKinds));
|
|
@@ -12549,12 +12855,12 @@ function TeamTab() {
|
|
|
12549
12855
|
setMembers(await adapter2.listMembers(currentOrg.id));
|
|
12550
12856
|
}
|
|
12551
12857
|
}, [adapter2, currentOrg?.id, personMode, teamPersonKinds, setMembers]);
|
|
12552
|
-
|
|
12858
|
+
React65.useEffect(() => {
|
|
12553
12859
|
if (personMode && adapter2?.listTeam && currentOrg) {
|
|
12554
12860
|
dedup("team:people:" + currentOrg.id, () => adapter2.listTeam(currentOrg.id, teamPersonKinds)).then(setTeam).catch(() => setTeam([]));
|
|
12555
12861
|
}
|
|
12556
12862
|
}, [personMode, adapter2, currentOrg?.id, teamPersonKinds.join(",")]);
|
|
12557
|
-
|
|
12863
|
+
React65.useEffect(() => {
|
|
12558
12864
|
if (adapter2 && currentOrg) {
|
|
12559
12865
|
dedup("team:invites:" + currentOrg.id, () => adapter2.listInvites(currentOrg.id)).then(setInvites).catch(() => {
|
|
12560
12866
|
});
|
|
@@ -12629,18 +12935,13 @@ function TeamTab() {
|
|
|
12629
12935
|
const pendingInvites = invites.filter((i) => i.status === "pending");
|
|
12630
12936
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
12631
12937
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
12632
|
-
/* @__PURE__ */
|
|
12633
|
-
|
|
12634
|
-
|
|
12635
|
-
|
|
12636
|
-
|
|
12637
|
-
|
|
12638
|
-
|
|
12639
|
-
}, children: [
|
|
12640
|
-
/* @__PURE__ */ jsx(UserPlus, { className: "h-4 w-4 mr-1" }),
|
|
12641
|
-
t("organization.team.invite")
|
|
12642
|
-
] })
|
|
12643
|
-
] }),
|
|
12938
|
+
canManageTeam && /* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: () => {
|
|
12939
|
+
void handleOpenInvite();
|
|
12940
|
+
}, children: [
|
|
12941
|
+
/* @__PURE__ */ jsx(UserPlus, { className: "h-4 w-4 mr-1" }),
|
|
12942
|
+
t("organization.team.invite")
|
|
12943
|
+
] }) }),
|
|
12944
|
+
/* @__PURE__ */ jsx("p", { className: "mb-4 text-sm text-muted-foreground", children: t("organization.team.memberCount", { count: String(rows.length), plural: rows.length !== 1 ? "s" : "" }) }),
|
|
12644
12945
|
/* @__PURE__ */ jsx(Card, { className: "overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full", children: [
|
|
12645
12946
|
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b bg-muted/50", children: [
|
|
12646
12947
|
/* @__PURE__ */ jsx("th", { className: "text-left p-3 text-sm font-medium text-muted-foreground", children: t("organization.team.member") }),
|
|
@@ -12762,13 +13063,13 @@ var SYSTEM_PERMISSIONS = [
|
|
|
12762
13063
|
];
|
|
12763
13064
|
function PermissionMatrixEditor({ features, profile, onSave, onCancel, saving, isNew, parentLabel }) {
|
|
12764
13065
|
const { t } = useTranslation$1();
|
|
12765
|
-
const [name, setName] =
|
|
12766
|
-
const [description, setDescription] =
|
|
12767
|
-
const [systemPerms, setSystemPerms] =
|
|
12768
|
-
const [grants, setGrants] =
|
|
12769
|
-
const [collapsed, setCollapsed] =
|
|
12770
|
-
const [search, setSearch] =
|
|
12771
|
-
const initial =
|
|
13066
|
+
const [name, setName] = React65.useState(profile?.name ?? "");
|
|
13067
|
+
const [description, setDescription] = React65.useState(profile?.description ?? "");
|
|
13068
|
+
const [systemPerms, setSystemPerms] = React65.useState(profile?.systemPermissions ?? []);
|
|
13069
|
+
const [grants, setGrants] = React65.useState(profile?.grants ?? {});
|
|
13070
|
+
const [collapsed, setCollapsed] = React65.useState(/* @__PURE__ */ new Set());
|
|
13071
|
+
const [search, setSearch] = React65.useState("");
|
|
13072
|
+
const initial = React65.useRef({
|
|
12772
13073
|
name: profile?.name ?? "",
|
|
12773
13074
|
description: profile?.description ?? "",
|
|
12774
13075
|
systemPerms: JSON.stringify(profile?.systemPermissions ?? []),
|
|
@@ -12806,7 +13107,7 @@ function PermissionMatrixEditor({ features, profile, onSave, onCancel, saving, i
|
|
|
12806
13107
|
saveLabel: isNew ? t("organization.permissions.createProfile") : t("organization.permissions.updateProfile")
|
|
12807
13108
|
});
|
|
12808
13109
|
useBackHandler(onCancel);
|
|
12809
|
-
const groups =
|
|
13110
|
+
const groups = React65.useMemo(() => {
|
|
12810
13111
|
const filtered = search ? features.filter((f) => f.label.toLowerCase().includes(search.toLowerCase())) : features;
|
|
12811
13112
|
const map = /* @__PURE__ */ new Map();
|
|
12812
13113
|
for (const f of filtered) {
|
|
@@ -12875,7 +13176,7 @@ function PermissionMatrixEditor({ features, profile, onSave, onCancel, saving, i
|
|
|
12875
13176
|
}
|
|
12876
13177
|
) }) })
|
|
12877
13178
|
] }, sp.id)),
|
|
12878
|
-
Array.from(groups.entries()).map(([groupName, groupFeatures]) => /* @__PURE__ */ jsxs(
|
|
13179
|
+
Array.from(groups.entries()).map(([groupName, groupFeatures]) => /* @__PURE__ */ jsxs(React65.Fragment, { children: [
|
|
12879
13180
|
/* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: 5, className: "p-2 px-3", children: /* @__PURE__ */ jsxs(
|
|
12880
13181
|
"button",
|
|
12881
13182
|
{
|
|
@@ -12916,11 +13217,11 @@ function PermissionProfilesTab() {
|
|
|
12916
13217
|
const startImpersonation = usePermissionsStore((s) => s.startImpersonation);
|
|
12917
13218
|
const canPreview = (realProfile?.systemPermissions ?? []).includes("manage_permissions") ?? false;
|
|
12918
13219
|
const { t } = useTranslation$1();
|
|
12919
|
-
const [editingProfile, setEditingProfile] =
|
|
12920
|
-
const [creating, setCreating] =
|
|
12921
|
-
const [duplicateSource, setDuplicateSource] =
|
|
12922
|
-
const [saving, setSaving] =
|
|
12923
|
-
const [error, setError] =
|
|
13220
|
+
const [editingProfile, setEditingProfile] = React65.useState(null);
|
|
13221
|
+
const [creating, setCreating] = React65.useState(false);
|
|
13222
|
+
const [duplicateSource, setDuplicateSource] = React65.useState(null);
|
|
13223
|
+
const [saving, setSaving] = React65.useState(false);
|
|
13224
|
+
const [error, setError] = React65.useState(null);
|
|
12924
13225
|
const handleDuplicate = (profile) => {
|
|
12925
13226
|
setEditingProfile(null);
|
|
12926
13227
|
setCreating(false);
|
|
@@ -12930,7 +13231,7 @@ function PermissionProfilesTab() {
|
|
|
12930
13231
|
isSystem: false
|
|
12931
13232
|
});
|
|
12932
13233
|
};
|
|
12933
|
-
const memberCountByProfile =
|
|
13234
|
+
const memberCountByProfile = React65.useMemo(() => {
|
|
12934
13235
|
const counts = {};
|
|
12935
13236
|
for (const m of members) {
|
|
12936
13237
|
counts[m.profileId] = (counts[m.profileId] ?? 0) + 1;
|
|
@@ -12987,16 +13288,10 @@ function PermissionProfilesTab() {
|
|
|
12987
13288
|
);
|
|
12988
13289
|
}
|
|
12989
13290
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
12990
|
-
/* @__PURE__ */ jsxs(
|
|
12991
|
-
/* @__PURE__ */
|
|
12992
|
-
|
|
12993
|
-
|
|
12994
|
-
] }),
|
|
12995
|
-
/* @__PURE__ */ jsxs(Button, { onClick: () => setCreating(true), size: "sm", children: [
|
|
12996
|
-
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-1" }),
|
|
12997
|
-
t("organization.permissions.createProfile")
|
|
12998
|
-
] })
|
|
12999
|
-
] }),
|
|
13291
|
+
/* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsxs(Button, { onClick: () => setCreating(true), size: "sm", children: [
|
|
13292
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-1" }),
|
|
13293
|
+
t("organization.permissions.createProfile")
|
|
13294
|
+
] }) }),
|
|
13000
13295
|
error && /* @__PURE__ */ jsx("p", { className: "rounded-lg border border-destructive/40 bg-destructive/5 px-3 py-2 text-sm text-destructive", children: error }),
|
|
13001
13296
|
/* @__PURE__ */ jsx("div", { className: "grid gap-3", children: profiles.length === 0 ? (
|
|
13002
13297
|
// Roles load via central org hydration; show skeletons until they arrive.
|
|
@@ -13695,7 +13990,7 @@ function SubjectFormLayout({ fields, allFields, fieldGroups, values, onChange, r
|
|
|
13695
13990
|
const IconComponent = getLucideIcon(entityIcon ?? "Heart") ?? Heart;
|
|
13696
13991
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
13697
13992
|
/* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(CardContent, { className: "pt-5", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-5", children: [
|
|
13698
|
-
/* @__PURE__ */ jsx("div", { className: "flex h-20 w-20 shrink-0 items-center justify-center rounded-2xl bg-primary/10 text-primary", children:
|
|
13993
|
+
/* @__PURE__ */ jsx("div", { className: "flex h-20 w-20 shrink-0 items-center justify-center rounded-2xl bg-primary/10 text-primary", children: React65__default.createElement(IconComponent, { className: "h-8 w-8" }) }),
|
|
13699
13994
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-4", children: [
|
|
13700
13995
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-4", children: [
|
|
13701
13996
|
nameField && /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-1.5", children: [
|
|
@@ -14043,11 +14338,11 @@ function ImageSlot({
|
|
|
14043
14338
|
canEdit
|
|
14044
14339
|
}) {
|
|
14045
14340
|
const t = useTranslation();
|
|
14046
|
-
const inputRef =
|
|
14047
|
-
const [url, setUrl] =
|
|
14048
|
-
const [busy, setBusy] =
|
|
14049
|
-
const [error, setError] =
|
|
14050
|
-
|
|
14341
|
+
const inputRef = React65__default.useRef(null);
|
|
14342
|
+
const [url, setUrl] = React65__default.useState(() => image.get(row));
|
|
14343
|
+
const [busy, setBusy] = React65__default.useState(false);
|
|
14344
|
+
const [error, setError] = React65__default.useState(null);
|
|
14345
|
+
React65__default.useEffect(() => {
|
|
14051
14346
|
setUrl(image.get(row));
|
|
14052
14347
|
}, [image.get(row)]);
|
|
14053
14348
|
const pick = () => {
|
|
@@ -14141,7 +14436,7 @@ function CrudFormPage({ entityDef, mode, initialData, onSubmit, onCancel, namePl
|
|
|
14141
14436
|
const computeInit = () => mode === "edit" && initialData ? { ...getDefaultValues(formFields), ...initialData } : getDefaultValues(formFields);
|
|
14142
14437
|
const [values, setValues] = useState(computeInit);
|
|
14143
14438
|
const [saving, setSaving] = useState(false);
|
|
14144
|
-
const initialRef =
|
|
14439
|
+
const initialRef = React65__default.useRef(JSON.stringify(values));
|
|
14145
14440
|
useEffect(() => {
|
|
14146
14441
|
const init = computeInit();
|
|
14147
14442
|
setValues(init);
|
|
@@ -14512,6 +14807,57 @@ function LimitGate({ limitKey, children, className }) {
|
|
|
14512
14807
|
}
|
|
14513
14808
|
);
|
|
14514
14809
|
}
|
|
14810
|
+
function QuickActionsButton({ actions, label, variant: variantProp, className }) {
|
|
14811
|
+
const [open, setOpen] = useState(false);
|
|
14812
|
+
const ref = useRef(null);
|
|
14813
|
+
const moduleLayout = useModuleLayout();
|
|
14814
|
+
const variant = variantProp ?? (moduleLayout === "tabs" ? "default" : "outline");
|
|
14815
|
+
useEffect(() => {
|
|
14816
|
+
function handler(e) {
|
|
14817
|
+
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
14818
|
+
}
|
|
14819
|
+
document.addEventListener("mousedown", handler);
|
|
14820
|
+
return () => document.removeEventListener("mousedown", handler);
|
|
14821
|
+
}, []);
|
|
14822
|
+
if (actions.length === 0) return null;
|
|
14823
|
+
return /* @__PURE__ */ jsxs("div", { ref, className: cn("relative", className), children: [
|
|
14824
|
+
/* @__PURE__ */ jsxs(
|
|
14825
|
+
Button,
|
|
14826
|
+
{
|
|
14827
|
+
variant,
|
|
14828
|
+
size: "sm",
|
|
14829
|
+
onClick: () => setOpen(!open),
|
|
14830
|
+
className: cn(open && variant === "outline" && "bg-muted"),
|
|
14831
|
+
children: [
|
|
14832
|
+
/* @__PURE__ */ jsx(Plus, { className: cn("h-3.5 w-3.5 transition-transform duration-200", open && "rotate-45") }),
|
|
14833
|
+
/* @__PURE__ */ jsx("span", { children: label ?? "New" }),
|
|
14834
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: cn("-mr-0.5 h-3.5 w-3.5 opacity-70 transition-transform duration-200", open && "rotate-180") })
|
|
14835
|
+
]
|
|
14836
|
+
}
|
|
14837
|
+
),
|
|
14838
|
+
open && /* @__PURE__ */ jsx("div", { className: "fayz-glass-surface absolute top-full right-0 z-50 mt-2 w-64 rounded-xl border bg-popover shadow-lg overflow-hidden animate-in fade-in-0 zoom-in-95 origin-top-right", children: /* @__PURE__ */ jsx("div", { className: "p-1.5", children: actions.map((action) => {
|
|
14839
|
+
const Icon = action.icon ? ICON_MAP[action.icon] ?? Plus : Plus;
|
|
14840
|
+
return /* @__PURE__ */ jsxs(
|
|
14841
|
+
"button",
|
|
14842
|
+
{
|
|
14843
|
+
onClick: () => {
|
|
14844
|
+
action.action();
|
|
14845
|
+
setOpen(false);
|
|
14846
|
+
},
|
|
14847
|
+
className: "w-full flex items-center gap-3 rounded-lg px-3 py-2.5 text-left hover:bg-muted/50 transition-colors group",
|
|
14848
|
+
children: [
|
|
14849
|
+
/* @__PURE__ */ jsx("div", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-muted group-hover:bg-primary/10 transition-colors shrink-0", children: /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 text-muted-foreground group-hover:text-primary transition-colors" }) }),
|
|
14850
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
14851
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: action.label }),
|
|
14852
|
+
action.description && /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground leading-tight", children: action.description })
|
|
14853
|
+
] })
|
|
14854
|
+
]
|
|
14855
|
+
},
|
|
14856
|
+
action.id
|
|
14857
|
+
);
|
|
14858
|
+
}) }) })
|
|
14859
|
+
] });
|
|
14860
|
+
}
|
|
14515
14861
|
var ALL_TAB = "__all__";
|
|
14516
14862
|
function getEntityIcon(name) {
|
|
14517
14863
|
const icons = LucideIcons3;
|
|
@@ -14542,12 +14888,14 @@ function CrudListView({
|
|
|
14542
14888
|
onExport,
|
|
14543
14889
|
feature,
|
|
14544
14890
|
readOnly,
|
|
14891
|
+
embedded,
|
|
14545
14892
|
emptyMessage,
|
|
14546
14893
|
navTabs,
|
|
14547
14894
|
activeNavTab,
|
|
14548
14895
|
headerActions,
|
|
14549
14896
|
stats,
|
|
14550
14897
|
onRefresh,
|
|
14898
|
+
refreshFromCache,
|
|
14551
14899
|
onSort,
|
|
14552
14900
|
onSortField,
|
|
14553
14901
|
onSortDir,
|
|
@@ -14608,22 +14956,35 @@ function CrudListView({
|
|
|
14608
14956
|
}] : []
|
|
14609
14957
|
];
|
|
14610
14958
|
const selectable = display === "table" && barActions.length > 0;
|
|
14611
|
-
const
|
|
14612
|
-
const headerTabs = navTabs?.length ? navTabs.map((t2) => ({ value: t2.id, label: t2.label, icon: t2.icon })) :
|
|
14613
|
-
|
|
14614
|
-
...facetTab.options.map((o) => ({ value: o.value, label: o.label }))
|
|
14615
|
-
] : null;
|
|
14616
|
-
const headerTabValue = navTabs?.length ? activeNavTab ?? navTabs[0].id : activeFilters?.[facetTab?.field ?? ""] ?? ALL_TAB;
|
|
14959
|
+
const hasSelection = selectable && selectedIds.length > 0;
|
|
14960
|
+
const headerTabs = navTabs?.length ? navTabs.map((t2) => ({ value: t2.id, label: t2.label, icon: t2.icon })) : null;
|
|
14961
|
+
const headerTabValue = activeNavTab ?? navTabs?.[0]?.id ?? ALL_TAB;
|
|
14617
14962
|
const onHeaderTabChange = (next) => {
|
|
14618
|
-
|
|
14619
|
-
else if (facetTab) onFacetChange?.(facetTab.field, next === ALL_TAB ? void 0 : next);
|
|
14963
|
+
navTabs?.find((t2) => t2.id === next)?.onSelect();
|
|
14620
14964
|
};
|
|
14621
|
-
const pillFacets = facets
|
|
14622
|
-
const
|
|
14623
|
-
const
|
|
14624
|
-
|
|
14965
|
+
const pillFacets = facets;
|
|
14966
|
+
const newLabel = addLabel ?? t("crud.list.addEntity", { entity: entityDef.name });
|
|
14967
|
+
const plainNewLabel = newLabel.replace(/^\+\s*/, "");
|
|
14968
|
+
const newButton = onNew && !readOnly ? onImport ? /* @__PURE__ */ jsx(
|
|
14969
|
+
QuickActionsButton,
|
|
14970
|
+
{
|
|
14971
|
+
variant: "default",
|
|
14972
|
+
label: plainNewLabel,
|
|
14973
|
+
actions: [
|
|
14974
|
+
{ id: "new", label: plainNewLabel, description: t("crud.list.newHint"), icon: "Plus", action: onNew },
|
|
14975
|
+
{ id: "import", label: t("crud.import.action"), description: t("crud.import.hint"), icon: "Upload", action: onImport }
|
|
14976
|
+
]
|
|
14977
|
+
}
|
|
14978
|
+
) : /* @__PURE__ */ jsx(Button, { onClick: onNew, children: newLabel }) : onImport ? /* @__PURE__ */ jsxs(Button, { variant: "outline", onClick: onImport, children: [
|
|
14979
|
+
/* @__PURE__ */ jsx(Upload, { className: "mr-2 h-4 w-4" }),
|
|
14980
|
+
t("crud.import.action")
|
|
14981
|
+
] }) : null;
|
|
14982
|
+
const gate = (node) => {
|
|
14983
|
+
const roleGated = feature ? /* @__PURE__ */ jsx(PermissionGate, { feature, action: "create", children: node }) : node;
|
|
14625
14984
|
return entityDef.limitKey ? /* @__PURE__ */ jsx(LimitGate, { limitKey: entityDef.limitKey, children: roleGated }) : roleGated;
|
|
14626
|
-
}
|
|
14985
|
+
};
|
|
14986
|
+
const gatedNewButton = newButton ? gate(newButton) : null;
|
|
14987
|
+
const gatedCreateButton = onNew && !readOnly ? gate(/* @__PURE__ */ jsx(Button, { onClick: onNew, children: newLabel })) : null;
|
|
14627
14988
|
const isFiltered = Boolean(search?.trim()) || Object.values(activeFilters ?? {}).some((v) => v != null);
|
|
14628
14989
|
const EmptyIcon = getEntityIcon(entityDef.icon);
|
|
14629
14990
|
const emptyState = /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1 py-6", children: [
|
|
@@ -14631,18 +14992,13 @@ function CrudListView({
|
|
|
14631
14992
|
/* @__PURE__ */ jsx("p", { className: "text-base font-semibold text-foreground", children: emptyMessage ?? (isFiltered ? t("crud.list.emptyFiltered", { entities: namePlural.toLowerCase() }) : t("crud.list.empty", { entities: namePlural.toLowerCase() })) }),
|
|
14632
14993
|
!isFiltered && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
14633
14994
|
/* @__PURE__ */ jsx("p", { className: "max-w-sm text-sm text-muted-foreground", children: t("crud.list.emptyHint", { entities: namePlural.toLowerCase() }) }),
|
|
14634
|
-
|
|
14995
|
+
gatedCreateButton && /* @__PURE__ */ jsx("div", { className: "mt-3", children: gatedCreateButton })
|
|
14635
14996
|
] })
|
|
14636
14997
|
] });
|
|
14637
|
-
const actions = /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
14998
|
+
const actions = headerActions || gatedNewButton ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
14638
14999
|
headerActions,
|
|
14639
|
-
onImport && /* @__PURE__ */ jsxs(Button, { variant: "outline", onClick: onImport, children: [
|
|
14640
|
-
/* @__PURE__ */ jsx(Upload, { className: "mr-2 h-4 w-4" }),
|
|
14641
|
-
t("crud.import.action")
|
|
14642
|
-
] }),
|
|
14643
|
-
onImport && gatedNewButton && /* @__PURE__ */ jsx("span", { className: "h-6 w-px bg-border", "aria-hidden": true }),
|
|
14644
15000
|
gatedNewButton
|
|
14645
|
-
] });
|
|
15001
|
+
] }) : null;
|
|
14646
15002
|
const sortableColumns = useMemo(() => {
|
|
14647
15003
|
const declared = entityDef.fields.filter((f) => f.sortable !== false).map((f) => ({ key: f.key, label: f.label }));
|
|
14648
15004
|
const has = new Set(declared.map((f) => f.key));
|
|
@@ -14711,7 +15067,16 @@ function CrudListView({
|
|
|
14711
15067
|
] })
|
|
14712
15068
|
] })
|
|
14713
15069
|
] }),
|
|
14714
|
-
onRefresh && /* @__PURE__ */ jsx(
|
|
15070
|
+
onRefresh && /* @__PURE__ */ jsx(
|
|
15071
|
+
RefreshButton,
|
|
15072
|
+
{
|
|
15073
|
+
onRefresh,
|
|
15074
|
+
fromCache: refreshFromCache,
|
|
15075
|
+
label: t("crud.list.refresh"),
|
|
15076
|
+
labelCached: t("crud.list.refreshCached"),
|
|
15077
|
+
className: iconBtn
|
|
15078
|
+
}
|
|
15079
|
+
),
|
|
14715
15080
|
onExport && /* @__PURE__ */ jsx(Hint, { label: t("crud.export.action"), children: /* @__PURE__ */ jsx("button", { type: "button", "aria-label": t("crud.export.action"), onClick: onExport, className: iconBtn, children: /* @__PURE__ */ jsx(Download, { className: "h-4 w-4" }) }) })
|
|
14716
15081
|
] }) : null;
|
|
14717
15082
|
const rows = items?.length ?? 0;
|
|
@@ -14754,18 +15119,21 @@ function CrudListView({
|
|
|
14754
15119
|
] })
|
|
14755
15120
|
] }) : null;
|
|
14756
15121
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
14757
|
-
/* @__PURE__ */
|
|
14758
|
-
|
|
14759
|
-
|
|
14760
|
-
|
|
14761
|
-
|
|
14762
|
-
|
|
14763
|
-
|
|
14764
|
-
|
|
14765
|
-
|
|
14766
|
-
|
|
14767
|
-
|
|
14768
|
-
|
|
15122
|
+
actions && (embedded ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center justify-end gap-3", children: actions }) : /* @__PURE__ */ jsx(PageHeaderActions, { children: actions })),
|
|
15123
|
+
headerTabs && // The same band a module's sub-nav draws, closed by the hairline that
|
|
15124
|
+
// crosses the page. Alunos ▸ Equipe and Financeiro ▸ Mensalidades are
|
|
15125
|
+
// the same kind of move — switching what the page shows — so they are
|
|
15126
|
+
// the same object on screen.
|
|
15127
|
+
/* @__PURE__ */ jsx(
|
|
15128
|
+
PageTabs,
|
|
15129
|
+
{
|
|
15130
|
+
className: "mb-0",
|
|
15131
|
+
tabs: headerTabs,
|
|
15132
|
+
value: headerTabValue,
|
|
15133
|
+
onChange: onHeaderTabChange,
|
|
15134
|
+
"aria-label": namePlural
|
|
15135
|
+
}
|
|
15136
|
+
),
|
|
14769
15137
|
error && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-destructive/30 bg-destructive/5 px-4 py-3 text-sm", children: [
|
|
14770
15138
|
/* @__PURE__ */ jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-destructive" }),
|
|
14771
15139
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
@@ -14775,16 +15143,6 @@ function CrudListView({
|
|
|
14775
15143
|
onRefresh && /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", className: "ml-auto shrink-0", onClick: onRefresh, children: t("crud.list.refresh") })
|
|
14776
15144
|
] }),
|
|
14777
15145
|
stats && stats.length > 0 && /* @__PURE__ */ jsx(StatTiles, { tiles: stats, loading: isInitialLoad }),
|
|
14778
|
-
selectable && /* @__PURE__ */ jsx(
|
|
14779
|
-
BulkActionBar,
|
|
14780
|
-
{
|
|
14781
|
-
count: selectedIds.length,
|
|
14782
|
-
total: items?.length ?? 0,
|
|
14783
|
-
onSelectAll: () => setRawSelection((items ?? []).map((r) => r.id)),
|
|
14784
|
-
onClear: () => setRawSelection([]),
|
|
14785
|
-
actions: barActions
|
|
14786
|
-
}
|
|
14787
|
-
),
|
|
14788
15146
|
display === "cards" ? (
|
|
14789
15147
|
// The card grid keeps the search box floating above it: there is no
|
|
14790
15148
|
// table chrome for a toolbar to sit flush against.
|
|
@@ -14821,11 +15179,21 @@ function CrudListView({
|
|
|
14821
15179
|
same rows, so a search box floating on the page background above a
|
|
14822
15180
|
separate table card read as two unrelated controls. */
|
|
14823
15181
|
/* @__PURE__ */ jsxs(Card, { className: "overflow-hidden", children: [
|
|
14824
|
-
(searchBox || facetChips || tableTools) && /* @__PURE__ */
|
|
15182
|
+
(searchBox || facetChips || tableTools || hasSelection) && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2 border-b border-border px-3 py-2", children: hasSelection ? /* @__PURE__ */ jsx(
|
|
15183
|
+
BulkActionBar,
|
|
15184
|
+
{
|
|
15185
|
+
variant: "inline",
|
|
15186
|
+
count: selectedIds.length,
|
|
15187
|
+
total: items?.length ?? 0,
|
|
15188
|
+
onSelectAll: () => setRawSelection((items ?? []).map((r) => r.id)),
|
|
15189
|
+
onClear: () => setRawSelection([]),
|
|
15190
|
+
actions: barActions
|
|
15191
|
+
}
|
|
15192
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
14825
15193
|
/* @__PURE__ */ jsx("div", { className: "min-w-[10rem] flex-1", children: searchBox }),
|
|
14826
15194
|
facetChips,
|
|
14827
15195
|
tableTools
|
|
14828
|
-
] }),
|
|
15196
|
+
] }) }),
|
|
14829
15197
|
/* @__PURE__ */ jsx(
|
|
14830
15198
|
DataTable,
|
|
14831
15199
|
{
|
|
@@ -15221,7 +15589,7 @@ function AddressesTab({ item }) {
|
|
|
15221
15589
|
)
|
|
15222
15590
|
] });
|
|
15223
15591
|
}
|
|
15224
|
-
var ScheduleEditor =
|
|
15592
|
+
var ScheduleEditor = React65__default.lazy(
|
|
15225
15593
|
() => import('./ScheduleEditor-S3QI5MHO.js').then((m) => ({ default: m.ScheduleEditor }))
|
|
15226
15594
|
);
|
|
15227
15595
|
function ComingSoon({ icon: Icon, title, description }) {
|
|
@@ -15302,7 +15670,7 @@ function ScheduleTab({ item }) {
|
|
|
15302
15670
|
}
|
|
15303
15671
|
);
|
|
15304
15672
|
}
|
|
15305
|
-
return /* @__PURE__ */ jsx(
|
|
15673
|
+
return /* @__PURE__ */ jsx(React65__default.Suspense, { fallback: null, children: /* @__PURE__ */ jsx(ScheduleEditor, { assigneeId: item.id }) });
|
|
15306
15674
|
}
|
|
15307
15675
|
var PERSON_DETAIL_TABS = [
|
|
15308
15676
|
{ id: "schedule", label: "Schedule", icon: "CalendarDays", component: ScheduleTab, visibleFor: ["staff"] },
|
|
@@ -15608,6 +15976,10 @@ var SUBJECT_DETAIL_TABS = [
|
|
|
15608
15976
|
{ id: "history", label: "History", component: SubjectHistoryTab },
|
|
15609
15977
|
{ id: "documents", label: "Documents", component: SubjectDocumentsTab }
|
|
15610
15978
|
];
|
|
15979
|
+
function ActionSlot({ embedded, children }) {
|
|
15980
|
+
if (embedded) return /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-1.5", children });
|
|
15981
|
+
return /* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5", children }) });
|
|
15982
|
+
}
|
|
15611
15983
|
function formatValue3(field, value, t) {
|
|
15612
15984
|
if (value == null || value === "") return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/50", children: "\u2014" });
|
|
15613
15985
|
if (field.renderCell) return field.renderCell(value, {});
|
|
@@ -15679,7 +16051,7 @@ function InlineEditor({
|
|
|
15679
16051
|
}) {
|
|
15680
16052
|
const [draft, setDraft] = useState(value ?? "");
|
|
15681
16053
|
const [saving, setSaving] = useState(false);
|
|
15682
|
-
const inputRef =
|
|
16054
|
+
const inputRef = React65__default.useRef(null);
|
|
15683
16055
|
useEffect(() => {
|
|
15684
16056
|
inputRef.current?.focus();
|
|
15685
16057
|
if (inputRef.current instanceof HTMLInputElement) inputRef.current.select();
|
|
@@ -15955,7 +16327,7 @@ function CrudDetailPage({
|
|
|
15955
16327
|
const newHash = value === "overview" ? detailPath : `${detailPath}/${value}`;
|
|
15956
16328
|
window.history.replaceState(null, "", `#${newHash}`);
|
|
15957
16329
|
}, [basePath, item.id, embedded]);
|
|
15958
|
-
const headerNode =
|
|
16330
|
+
const headerNode = React65__default.useMemo(
|
|
15959
16331
|
() => embedded ? null : /* @__PURE__ */ jsx(SubpageHeader, { title: displayValue, parentLabel: namePlural, onBack }),
|
|
15960
16332
|
[embedded, displayValue, namePlural, onBack]
|
|
15961
16333
|
);
|
|
@@ -15981,7 +16353,7 @@ function CrudDetailPage({
|
|
|
15981
16353
|
] }),
|
|
15982
16354
|
subtitleValue && /* @__PURE__ */ jsx("p", { className: `text-muted-foreground mt-0.5 ${embedded ? "text-xs" : ""}`, children: subtitleValue })
|
|
15983
16355
|
] }),
|
|
15984
|
-
/* @__PURE__ */ jsxs(
|
|
16356
|
+
/* @__PURE__ */ jsxs(ActionSlot, { embedded, children: [
|
|
15985
16357
|
/* @__PURE__ */ jsx(WidgetSlot, { zone: headerActionsZone, item, entityId, embedded }),
|
|
15986
16358
|
onEdit && /* @__PURE__ */ jsxs(Button, { variant: "outline", size: embedded ? "xs" : "sm", onClick: onEdit, className: embedded ? "h-7 px-2 text-xs gap-1" : "", children: [
|
|
15987
16359
|
/* @__PURE__ */ jsx(Edit, { className: embedded ? "h-3 w-3" : "h-4 w-4 mr-1.5" }),
|
|
@@ -16008,7 +16380,7 @@ function CrudDetailPage({
|
|
|
16008
16380
|
})
|
|
16009
16381
|
] }),
|
|
16010
16382
|
/* @__PURE__ */ jsx(TabsContent, { value: "overview", className: embedded ? "mt-2" : "mt-4", children: /* @__PURE__ */ jsx(OverviewTab, { entityDef, item, compact: embedded, onFieldSave }) }),
|
|
16011
|
-
customTabs.map((tab) => /* @__PURE__ */ jsx(TabsContent, { value: tab.id, className: "mt-4", children: tab.component ?
|
|
16383
|
+
customTabs.map((tab) => /* @__PURE__ */ jsx(TabsContent, { value: tab.id, className: "mt-4", children: tab.component ? React65__default.createElement(tab.component, { item, entityDef, ...tab.props ?? {} }) : /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(CardContent, { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: t("common.noContent") }) }) }) }, tab.id))
|
|
16012
16384
|
] }),
|
|
16013
16385
|
/* @__PURE__ */ jsx(WidgetSlot, { zone: widgetZone }),
|
|
16014
16386
|
legacyWidgetZone !== widgetZone && /* @__PURE__ */ jsx(WidgetSlot, { zone: legacyWidgetZone }),
|
|
@@ -16060,7 +16432,7 @@ function useFieldRules(entityKey) {
|
|
|
16060
16432
|
};
|
|
16061
16433
|
}, [entityKey, fieldRules]);
|
|
16062
16434
|
}
|
|
16063
|
-
var ImportWizard2 =
|
|
16435
|
+
var ImportWizard2 = React65__default.lazy(
|
|
16064
16436
|
() => import('./ImportWizard-CISHGNQC.js').then((m) => ({ default: m.ImportWizard }))
|
|
16065
16437
|
);
|
|
16066
16438
|
var PAGE_SIZE = 50;
|
|
@@ -16172,7 +16544,7 @@ function useCrudColumns(entityDef, options) {
|
|
|
16172
16544
|
return tanCols;
|
|
16173
16545
|
}, [cols, displayField, options?.basePath, options?.onDelete, options?.feature, options?.readOnly]);
|
|
16174
16546
|
}
|
|
16175
|
-
function CrudPage({ entityDef: rawEntityDef, useStore, basePath, display, feature, readOnly, navTabs, activeNavTab, stats }) {
|
|
16547
|
+
function CrudPage({ entityDef: rawEntityDef, useStore, basePath, display, feature, readOnly, navTabs, activeNavTab, stats, embedded }) {
|
|
16176
16548
|
const store = useStore();
|
|
16177
16549
|
const t = useTranslation();
|
|
16178
16550
|
const normalizedBasePath = normalizeCrudBasePath(basePath);
|
|
@@ -16449,13 +16821,16 @@ function CrudPage({ entityDef: rawEntityDef, useStore, basePath, display, featur
|
|
|
16449
16821
|
onExport: handleExport,
|
|
16450
16822
|
feature,
|
|
16451
16823
|
readOnly,
|
|
16824
|
+
embedded,
|
|
16452
16825
|
navTabs,
|
|
16453
16826
|
activeNavTab,
|
|
16454
16827
|
stats: stats?.(store.items, store.total),
|
|
16455
16828
|
error: store.error,
|
|
16456
16829
|
onRefresh: () => {
|
|
16457
|
-
|
|
16830
|
+
emitDataChanged(entityDef.data?.table ? { table: entityDef.data.table, op: "unknown" } : { op: "unknown" });
|
|
16831
|
+
return store.refresh();
|
|
16458
16832
|
},
|
|
16833
|
+
refreshFromCache: store.fromCache,
|
|
16459
16834
|
onSort: handleSort,
|
|
16460
16835
|
onSortField: handleSortField,
|
|
16461
16836
|
onSortDir: handleSortDir,
|
|
@@ -16519,7 +16894,7 @@ function CrudPage({ entityDef: rawEntityDef, useStore, basePath, display, featur
|
|
|
16519
16894
|
displayValue: deleteItem ? deleteItem[displayField] : void 0
|
|
16520
16895
|
}
|
|
16521
16896
|
),
|
|
16522
|
-
/* @__PURE__ */ jsx(
|
|
16897
|
+
/* @__PURE__ */ jsx(React65__default.Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
|
|
16523
16898
|
ImportWizard2,
|
|
16524
16899
|
{
|
|
16525
16900
|
open: importOpen,
|
|
@@ -16615,6 +16990,7 @@ function createCrudStore(dataProvider, entity) {
|
|
|
16615
16990
|
query: {},
|
|
16616
16991
|
error: null,
|
|
16617
16992
|
errorAt: 0,
|
|
16993
|
+
fromCache: false,
|
|
16618
16994
|
async fetch() {
|
|
16619
16995
|
const currentKey = queryKey(get().query);
|
|
16620
16996
|
if (inflightFetch && currentKey === lastQueryKey) {
|
|
@@ -16628,7 +17004,13 @@ function createCrudStore(dataProvider, entity) {
|
|
|
16628
17004
|
const promise = (async () => {
|
|
16629
17005
|
try {
|
|
16630
17006
|
const result = await dataProvider.list(get().query);
|
|
16631
|
-
set({
|
|
17007
|
+
set({
|
|
17008
|
+
items: result.data,
|
|
17009
|
+
total: result.total,
|
|
17010
|
+
loading: false,
|
|
17011
|
+
error: null,
|
|
17012
|
+
fromCache: Boolean(result.cached || result.stale)
|
|
17013
|
+
});
|
|
16632
17014
|
} catch (err) {
|
|
16633
17015
|
set({
|
|
16634
17016
|
items: get().items ?? [],
|
|
@@ -16644,6 +17026,10 @@ function createCrudStore(dataProvider, entity) {
|
|
|
16644
17026
|
inflightFetch = promise;
|
|
16645
17027
|
return promise;
|
|
16646
17028
|
},
|
|
17029
|
+
async refresh() {
|
|
17030
|
+
invalidate();
|
|
17031
|
+
return get().fetch();
|
|
17032
|
+
},
|
|
16647
17033
|
async create(data) {
|
|
16648
17034
|
const item = await dataProvider.create(data);
|
|
16649
17035
|
emit3("created", { record_id: item?.id, record_name: displayName(item) });
|
|
@@ -17000,7 +17386,7 @@ function FieldRulesSettings({ entities, rules: initialRules, onSave }) {
|
|
|
17000
17386
|
const [saving, setSaving] = useState(false);
|
|
17001
17387
|
const [search, setSearch] = useState("");
|
|
17002
17388
|
const [showMore, setShowMore] = useState(false);
|
|
17003
|
-
|
|
17389
|
+
React65.useEffect(() => {
|
|
17004
17390
|
setDraft(initialRules);
|
|
17005
17391
|
}, [initialRules]);
|
|
17006
17392
|
const isDirty = useMemo(
|
|
@@ -17121,16 +17507,10 @@ function FieldRulesSettings({ entities, rules: initialRules, onSave }) {
|
|
|
17121
17507
|
entity.entityKey
|
|
17122
17508
|
));
|
|
17123
17509
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
17124
|
-
/* @__PURE__ */ jsxs(
|
|
17125
|
-
/* @__PURE__ */
|
|
17126
|
-
|
|
17127
|
-
|
|
17128
|
-
] }),
|
|
17129
|
-
/* @__PURE__ */ jsxs(Button, { onClick: handleSave, disabled: !isDirty || saving, className: "shrink-0", children: [
|
|
17130
|
-
saving && /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
17131
|
-
t("common.save")
|
|
17132
|
-
] })
|
|
17133
|
-
] }),
|
|
17510
|
+
/* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsxs(Button, { onClick: handleSave, disabled: !isDirty || saving, className: "shrink-0", children: [
|
|
17511
|
+
saving && /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
17512
|
+
t("common.save")
|
|
17513
|
+
] }) }),
|
|
17134
17514
|
entities.length > 4 && /* @__PURE__ */ jsxs("div", { className: "relative max-w-sm", children: [
|
|
17135
17515
|
/* @__PURE__ */ jsx(Search, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-muted-foreground" }),
|
|
17136
17516
|
/* @__PURE__ */ jsx(
|
|
@@ -17277,7 +17657,7 @@ function UpgradeModal() {
|
|
|
17277
17657
|
}
|
|
17278
17658
|
function LimitProbe({ limitKey, onReport }) {
|
|
17279
17659
|
const info = useLimit(limitKey);
|
|
17280
|
-
|
|
17660
|
+
React65.useEffect(() => {
|
|
17281
17661
|
onReport(limitKey, info);
|
|
17282
17662
|
}, [limitKey, info, onReport]);
|
|
17283
17663
|
return null;
|
|
@@ -17290,16 +17670,16 @@ function SoftLimitBanner({ keys }) {
|
|
|
17290
17670
|
if (params) for (const [k, val] of Object.entries(params)) v = v.replace(`{${k}}`, String(val)).replace(`{{${k}}}`, String(val));
|
|
17291
17671
|
return v;
|
|
17292
17672
|
};
|
|
17293
|
-
const [over, setOver] =
|
|
17294
|
-
const [dismissed, setDismissed] =
|
|
17295
|
-
const report =
|
|
17673
|
+
const [over, setOver] = React65.useState({});
|
|
17674
|
+
const [dismissed, setDismissed] = React65.useState({});
|
|
17675
|
+
const report = React65.useCallback((key, info) => {
|
|
17296
17676
|
const isOver = !info.unlimited && !info.loading && info.used > info.max;
|
|
17297
17677
|
setOver((prev) => {
|
|
17298
17678
|
if (isOver === Boolean(prev[key])) return prev;
|
|
17299
17679
|
return { ...prev, [key]: isOver };
|
|
17300
17680
|
});
|
|
17301
17681
|
}, []);
|
|
17302
|
-
const monitored =
|
|
17682
|
+
const monitored = React65.useMemo(() => Array.from(new Set(keys)), [keys]);
|
|
17303
17683
|
const activeKey = monitored.find((k) => over[k] && !dismissed[k]);
|
|
17304
17684
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
17305
17685
|
monitored.map((k) => /* @__PURE__ */ jsx(LimitProbe, { limitKey: k, onReport: report }, k)),
|
|
@@ -17322,11 +17702,11 @@ function SoftLimitBanner({ keys }) {
|
|
|
17322
17702
|
] })
|
|
17323
17703
|
] });
|
|
17324
17704
|
}
|
|
17325
|
-
var CommandPalette =
|
|
17326
|
-
() => import('./CommandPalette-
|
|
17705
|
+
var CommandPalette = React65.lazy(
|
|
17706
|
+
() => import('./CommandPalette-U7MMA2WH.js').then((m) => ({ default: m.CommandPalette }))
|
|
17327
17707
|
);
|
|
17328
|
-
var SubscriptionPage =
|
|
17329
|
-
() => import('./SubscriptionPage-
|
|
17708
|
+
var SubscriptionPage = React65.lazy(
|
|
17709
|
+
() => import('./SubscriptionPage-4KP7DKA2.js').then((m) => ({ default: m.SubscriptionPage }))
|
|
17330
17710
|
);
|
|
17331
17711
|
function orgInitials(name) {
|
|
17332
17712
|
const words = name.trim().split(/\s+/).filter(Boolean);
|
|
@@ -17555,9 +17935,9 @@ function AccessDenied({ tr }) {
|
|
|
17555
17935
|
}
|
|
17556
17936
|
function AdminNotifications() {
|
|
17557
17937
|
const { notifications, unreadCount, fetchNotifications, markAsRead, markAllAsRead } = useNotifications();
|
|
17558
|
-
const [open, setOpen] =
|
|
17559
|
-
const fetchedRef =
|
|
17560
|
-
|
|
17938
|
+
const [open, setOpen] = React65.useState(false);
|
|
17939
|
+
const fetchedRef = React65.useRef(false);
|
|
17940
|
+
React65.useEffect(() => {
|
|
17561
17941
|
if (fetchedRef.current) return;
|
|
17562
17942
|
fetchedRef.current = true;
|
|
17563
17943
|
void fetchNotifications();
|
|
@@ -17591,6 +17971,7 @@ function navEntryToItem(entry) {
|
|
|
17591
17971
|
icon: entry.icon ?? "LayoutTemplate",
|
|
17592
17972
|
route: entry.route,
|
|
17593
17973
|
section: entry.section,
|
|
17974
|
+
group: entry.group,
|
|
17594
17975
|
badge: entry.badge,
|
|
17595
17976
|
href: entry.href,
|
|
17596
17977
|
permission: entry.permission
|
|
@@ -17638,6 +18019,7 @@ function pageToNavigationItem(page, fallbackPosition) {
|
|
|
17638
18019
|
icon: page.icon ?? "FileText",
|
|
17639
18020
|
route: page.path,
|
|
17640
18021
|
section: page.section ?? "main",
|
|
18022
|
+
group: page.group,
|
|
17641
18023
|
badge: page.badge,
|
|
17642
18024
|
href: page.href,
|
|
17643
18025
|
permission: page.permission,
|
|
@@ -17672,7 +18054,7 @@ function buildSettingsTabs(pluginTabs, can, hasSystem, t, showOrgSettings, hasBi
|
|
|
17672
18054
|
// sidebar ICON_MAP, which made the settings rail fall back to Home.
|
|
17673
18055
|
icon: /* @__PURE__ */ jsx(CreditCard, { className: "h-4 w-4" }),
|
|
17674
18056
|
iconName: "CreditCard",
|
|
17675
|
-
component: /* @__PURE__ */ jsx(
|
|
18057
|
+
component: /* @__PURE__ */ jsx(React65.Suspense, { fallback: null, children: /* @__PURE__ */ jsx(SubscriptionPage, {}) })
|
|
17676
18058
|
});
|
|
17677
18059
|
}
|
|
17678
18060
|
if (showOrgSettings) {
|
|
@@ -17696,9 +18078,9 @@ function buildSettingsTabs(pluginTabs, can, hasSystem, t, showOrgSettings, hasBi
|
|
|
17696
18078
|
settingsTabs.push({
|
|
17697
18079
|
id: tab.id,
|
|
17698
18080
|
label: translated === labelKey ? tab.label : translated,
|
|
17699
|
-
icon:
|
|
18081
|
+
icon: React65.createElement(IconComp, { className: "h-4 w-4" }),
|
|
17700
18082
|
iconName: tab.icon ?? "Puzzle",
|
|
17701
|
-
component:
|
|
18083
|
+
component: React65.createElement(tab.component),
|
|
17702
18084
|
// Flag plugin-contributed tabs so SettingsPage draws the core/plugins divider.
|
|
17703
18085
|
isPlugin: true,
|
|
17704
18086
|
group: tab.group
|
|
@@ -17712,7 +18094,7 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
17712
18094
|
const can = usePermissionOptional();
|
|
17713
18095
|
const access = useAccessOptional();
|
|
17714
18096
|
const currentProfile = usePermissionsStore((s) => s.currentProfile);
|
|
17715
|
-
const hasSystem =
|
|
18097
|
+
const hasSystem = React65.useCallback(
|
|
17716
18098
|
(perm) => {
|
|
17717
18099
|
if (!currentProfile) return true;
|
|
17718
18100
|
if (currentProfile.id === "owner" || currentProfile.name?.toLowerCase() === "owner") return true;
|
|
@@ -17726,22 +18108,22 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
17726
18108
|
};
|
|
17727
18109
|
const path = useAdminPath();
|
|
17728
18110
|
const { user, signOut } = useAuth();
|
|
17729
|
-
|
|
18111
|
+
React65.useEffect(() => installGlobalErrorHandlers(), []);
|
|
17730
18112
|
const railOpen = useRightRailStore((s) => s.open);
|
|
17731
18113
|
const railHasPanels = useRightRailStore((s) => s.panels.length > 0);
|
|
17732
18114
|
const rightRail = railHasPanels ? /* @__PURE__ */ jsx(RightRail, { frame: contentFrame }) : null;
|
|
17733
18115
|
const setRailMounted = useRightRailStore((s) => s.setMounted);
|
|
17734
|
-
|
|
18116
|
+
React65.useEffect(() => {
|
|
17735
18117
|
setRailMounted(true);
|
|
17736
18118
|
return () => setRailMounted(false);
|
|
17737
18119
|
}, [setRailMounted]);
|
|
17738
18120
|
useConnectorOAuthReturn();
|
|
17739
18121
|
const railWidthLive = useRightRailStore((s) => s.width);
|
|
17740
18122
|
const setSidebarCollapsed = useLayoutStore((s) => s.setSidebarCollapsed);
|
|
17741
|
-
const railAutoCollapsedRef =
|
|
17742
|
-
|
|
18123
|
+
const railAutoCollapsedRef = React65.useRef(false);
|
|
18124
|
+
React65.useEffect(() => {
|
|
17743
18125
|
if (layout !== "sidebar") return;
|
|
17744
|
-
const SIDEBAR_EXPANDED =
|
|
18126
|
+
const SIDEBAR_EXPANDED = 224;
|
|
17745
18127
|
const MIN_CONTENT = 620;
|
|
17746
18128
|
const apply = () => {
|
|
17747
18129
|
if (typeof window === "undefined") return;
|
|
@@ -17761,20 +18143,20 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
17761
18143
|
window.addEventListener("resize", apply);
|
|
17762
18144
|
return () => window.removeEventListener("resize", apply);
|
|
17763
18145
|
}, [railOpen, railWidthLive, layout, setSidebarCollapsed]);
|
|
17764
|
-
const [railWidth] =
|
|
18146
|
+
const [railWidth] = React65.useState(() => readRightRailWidth());
|
|
17765
18147
|
const billingPlans = useBillingStore((s) => s.plans);
|
|
17766
18148
|
const hasBilling = billingPlans.length > 0;
|
|
17767
18149
|
const orgPlan = useTenantOptional()?.org?.plan;
|
|
17768
|
-
const planBadge =
|
|
18150
|
+
const planBadge = React65.useMemo(
|
|
17769
18151
|
() => hasBilling ? resolvePlanBadge(orgPlan, billingPlans) : null,
|
|
17770
18152
|
[hasBilling, orgPlan, billingPlans]
|
|
17771
18153
|
);
|
|
17772
|
-
const softLimitKeys =
|
|
18154
|
+
const softLimitKeys = React65.useMemo(() => {
|
|
17773
18155
|
const plan = billingPlans.find((p) => p.id === (orgPlan || "free"));
|
|
17774
18156
|
return Object.keys(getPlanEntitlements(plan)?.limits ?? {});
|
|
17775
18157
|
}, [billingPlans, orgPlan]);
|
|
17776
18158
|
const navContributions = useNavContributionsStore((s) => s.contributions);
|
|
17777
|
-
const navigation =
|
|
18159
|
+
const navigation = React65.useMemo(() => {
|
|
17778
18160
|
const contributed = Object.values(navContributions).flat();
|
|
17779
18161
|
const flat = [...runtime.navigation, ...contributed].map((entry) => ({ ...navEntryToItem(entry), position: entry.position, indexChild: entry.indexChild })).sort(compareNavigation);
|
|
17780
18162
|
const items = [];
|
|
@@ -17821,7 +18203,7 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
17821
18203
|
}, [runtime.navigation, navContributions, pages, access]);
|
|
17822
18204
|
const commandPaletteOpen = useLayoutStore((s) => s.commandPaletteOpen);
|
|
17823
18205
|
const setCommandPaletteOpen = useLayoutStore((s) => s.setCommandPaletteOpen);
|
|
17824
|
-
const commandItems =
|
|
18206
|
+
const commandItems = React65.useMemo(() => {
|
|
17825
18207
|
const navGroup = tr("layout.commandPalette.navigation", "Navigation");
|
|
17826
18208
|
const items = [];
|
|
17827
18209
|
for (const nav of navigation) {
|
|
@@ -17833,7 +18215,7 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
17833
18215
|
return items;
|
|
17834
18216
|
}, [navigation]);
|
|
17835
18217
|
const globalSearch = useGlobalSearch();
|
|
17836
|
-
const routes =
|
|
18218
|
+
const routes = React65.useMemo(() => {
|
|
17837
18219
|
const list = [];
|
|
17838
18220
|
const entityRouteMap = /* @__PURE__ */ new Map();
|
|
17839
18221
|
for (const r of runtime.routes) {
|
|
@@ -17855,25 +18237,25 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
17855
18237
|
setEntityRouteMap(entityRouteMap);
|
|
17856
18238
|
return list.sort((a, b) => routeScore(b.path) - routeScore(a.path));
|
|
17857
18239
|
}, [runtime.routes, pages, showSettings]);
|
|
17858
|
-
const match =
|
|
18240
|
+
const match = React65.useMemo(() => {
|
|
17859
18241
|
for (const r of routes) {
|
|
17860
18242
|
const params = matchRoute(r.path, path);
|
|
17861
18243
|
if (params) return { route: r, params };
|
|
17862
18244
|
}
|
|
17863
18245
|
return null;
|
|
17864
18246
|
}, [routes, path]);
|
|
17865
|
-
|
|
18247
|
+
React65.useEffect(() => {
|
|
17866
18248
|
if (!match && (path === "/" || path === "") && navigation.length > 0) {
|
|
17867
18249
|
navigateTo(navigation[0].route);
|
|
17868
18250
|
}
|
|
17869
18251
|
}, [match, path, navigation]);
|
|
17870
18252
|
const ActiveComponent = match?.route.Component;
|
|
17871
18253
|
const activeParams = match?.params ?? {};
|
|
17872
|
-
const settingsTabs =
|
|
18254
|
+
const settingsTabs = React65.useMemo(
|
|
17873
18255
|
() => buildSettingsTabs(runtime.settingsTabs, can, hasSystem, t, showOrgSettings, hasBilling),
|
|
17874
18256
|
[runtime.settingsTabs, can, hasSystem, t, showOrgSettings, hasBilling]
|
|
17875
18257
|
);
|
|
17876
|
-
const profileRoute =
|
|
18258
|
+
const profileRoute = React65.useMemo(() => {
|
|
17877
18259
|
const explicit = routes.find((r) => r.path === "/perfil" || r.path === "/profile");
|
|
17878
18260
|
if (explicit) return explicit.path;
|
|
17879
18261
|
return showSettings ? "/settings/profile" : null;
|
|
@@ -17881,7 +18263,7 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
17881
18263
|
const onProfile = profileRoute ? () => navigateTo(profileRoute) : void 0;
|
|
17882
18264
|
const onBilling = hasBilling && showSettings ? () => navigateTo("/settings/subscription") : void 0;
|
|
17883
18265
|
const coreSettingsTabs = useCoreSettingsTabs({ showCompany: showBranding, showBranding });
|
|
17884
|
-
const allSettingsTabs =
|
|
18266
|
+
const allSettingsTabs = React65.useMemo(
|
|
17885
18267
|
() => {
|
|
17886
18268
|
const hidden = new Set(hiddenSettingsTabs ?? []);
|
|
17887
18269
|
return [...coreSettingsTabs, ...settingsTabs].filter((tab) => !hidden.has(tab.id));
|
|
@@ -17893,12 +18275,12 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
17893
18275
|
const contextualNav = useContextualNavStore((s) => s.nav);
|
|
17894
18276
|
const moduleRail = !inSettings && layout === "sidebar" && contextualNav && (path === contextualNav.base || path.startsWith(contextualNav.base + "/")) ? contextualNav : null;
|
|
17895
18277
|
const activeSettingsTab = inSettings ? path === "/settings" ? null : path.slice("/settings/".length).split("/")[0] : void 0;
|
|
17896
|
-
const settingsTabDef =
|
|
18278
|
+
const settingsTabDef = React65.useMemo(() => {
|
|
17897
18279
|
if (!showSettings || !path.startsWith("/settings/")) return void 0;
|
|
17898
18280
|
const id = path.slice("/settings/".length).split("/")[0];
|
|
17899
18281
|
return allSettingsTabs.find((tab) => tab.id === id);
|
|
17900
18282
|
}, [showSettings, path, allSettingsTabs]);
|
|
17901
|
-
const settingsNavigation =
|
|
18283
|
+
const settingsNavigation = React65.useMemo(
|
|
17902
18284
|
() => allSettingsTabs.map((tab) => ({
|
|
17903
18285
|
id: `settings:${tab.id}`,
|
|
17904
18286
|
label: tab.label,
|
|
@@ -17916,20 +18298,20 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
17916
18298
|
const shellUser = user ? { fullName: user.fullName ?? user.email, email: user.email, avatarUrl: user.avatarUrl } : void 0;
|
|
17917
18299
|
const moduleVariant = moduleNav ?? (layout === "sidebar" ? "tabs" : "rail");
|
|
17918
18300
|
const setRailAvailable = useContextualNavStore((s) => s.setRailAvailable);
|
|
17919
|
-
|
|
18301
|
+
React65.useEffect(() => {
|
|
17920
18302
|
setRailAvailable(layout === "sidebar" && moduleVariant !== "rail");
|
|
17921
18303
|
}, [layout, moduleVariant, setRailAvailable]);
|
|
17922
|
-
const activePageTitle =
|
|
18304
|
+
const activePageTitle = React65.useMemo(() => {
|
|
17923
18305
|
if (settingsTabDef) return settingsTabDef.label;
|
|
17924
18306
|
if (path === "/settings" || path.startsWith("/settings/")) return tr("common.settings", "Settings");
|
|
17925
18307
|
if (match?.route.title) return match.route.title;
|
|
17926
|
-
const candidates = [...navigation, ...navigation.flatMap((n) => n.children ?? [])].filter((n) => n.route).sort((a, b) => b.route.length - a.route.length);
|
|
18308
|
+
const candidates = [...navigation, ...navigation.flatMap((n) => n.children ?? [])].filter((n) => n.route).sort((a, b) => b.route.length - a.route.length || (a.children?.length ? 1 : 0) - (b.children?.length ? 1 : 0));
|
|
17927
18309
|
const hit = candidates.find(
|
|
17928
18310
|
(n) => n.route === "/" ? path === "/" || path === "" : path === n.route || path.startsWith(n.route + "/") || path.startsWith(n.route)
|
|
17929
18311
|
);
|
|
17930
18312
|
return hit?.label ?? candidates.find((n) => n.route === "/")?.label ?? "";
|
|
17931
18313
|
}, [navigation, path, tr, match, settingsTabDef]);
|
|
17932
|
-
const parentBack =
|
|
18314
|
+
const parentBack = React65.useMemo(() => {
|
|
17933
18315
|
if (settingsTabDef) {
|
|
17934
18316
|
return { onBack: () => navigateTo("/settings"), label: tr("common.settings", "Settings") };
|
|
17935
18317
|
}
|
|
@@ -18008,11 +18390,15 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
18008
18390
|
onEdit: site?.editRoute ? () => navigateTo(site.editRoute) : void 0
|
|
18009
18391
|
}
|
|
18010
18392
|
),
|
|
18393
|
+
/* @__PURE__ */ jsx(WidgetSlot, { zone: "shell.sidebar.footer" }),
|
|
18011
18394
|
sidebarFooter
|
|
18012
18395
|
] }),
|
|
18013
18396
|
orgSwitcher: layout === "topbar" && showOrgSwitcher ? /* @__PURE__ */ jsx(WorkspaceSwitcher, { variant: "topbar" }) : void 0,
|
|
18014
|
-
topbarStart: /* @__PURE__ */ jsx(WidgetSlot, { zone: "shell.topbar.start" }),
|
|
18015
|
-
topbarEnd: /* @__PURE__ */
|
|
18397
|
+
topbarStart: /* @__PURE__ */ jsx(WidgetSlot, { zone: "shell.topbar.start", surface: "topbar" }),
|
|
18398
|
+
topbarEnd: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
18399
|
+
/* @__PURE__ */ jsx(WidgetSlot, { zone: "shell.topbar.end", surface: "topbar" }),
|
|
18400
|
+
layout !== "sidebar" && /* @__PURE__ */ jsx(WidgetSlot, { zone: "shell.sidebar.footer", surface: "topbar" })
|
|
18401
|
+
] }),
|
|
18016
18402
|
rightRail,
|
|
18017
18403
|
rightRailOpen: railOpen,
|
|
18018
18404
|
defaultRightRailWidth: railWidth,
|
|
@@ -18059,10 +18445,15 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
18059
18445
|
userId: user?.id,
|
|
18060
18446
|
backLabel: parentBack?.label,
|
|
18061
18447
|
onBack: parentBack ? parentBack.onBack : () => navigateTo(homeRoute),
|
|
18062
|
-
children: match?.route.fullBleed ? /* @__PURE__ */ jsx("div", { className: "h-full min-h-0 overflow-hidden", children: activeContent }) :
|
|
18063
|
-
|
|
18064
|
-
|
|
18065
|
-
|
|
18448
|
+
children: match?.route.fullBleed ? /* @__PURE__ */ jsx("div", { className: "h-full min-h-0 overflow-hidden", children: activeContent }) : (
|
|
18449
|
+
// Less air at the top than at the sides: the bar above already
|
|
18450
|
+
// ends in a hairline, so a full 24px under it read as a gap
|
|
18451
|
+
// before the page started rather than as the page's margin.
|
|
18452
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-4 p-3 md:space-y-6 md:px-6 md:pb-6 md:pt-4", children: [
|
|
18453
|
+
softLimitKeys.length > 0 && /* @__PURE__ */ jsx(SoftLimitBanner, { keys: softLimitKeys }),
|
|
18454
|
+
activeContent
|
|
18455
|
+
] })
|
|
18456
|
+
)
|
|
18066
18457
|
},
|
|
18067
18458
|
match?.route.path ?? path
|
|
18068
18459
|
)
|
|
@@ -18081,7 +18472,7 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
18081
18472
|
]
|
|
18082
18473
|
}
|
|
18083
18474
|
),
|
|
18084
|
-
/* @__PURE__ */ jsx(
|
|
18475
|
+
/* @__PURE__ */ jsx(React65.Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
|
|
18085
18476
|
CommandPalette,
|
|
18086
18477
|
{
|
|
18087
18478
|
commands: commandItems,
|
|
@@ -18249,7 +18640,7 @@ function buildI18nConfig(config) {
|
|
|
18249
18640
|
function BillingInitializer({ config }) {
|
|
18250
18641
|
const setPlans = useBillingStore((s) => s.setPlans);
|
|
18251
18642
|
const setCheckout = useBillingStore((s) => s.setCheckout);
|
|
18252
|
-
|
|
18643
|
+
React65.useEffect(() => {
|
|
18253
18644
|
if (config.billing?.plans) setPlans(config.billing.plans.map(normalizeBillingPlan));
|
|
18254
18645
|
setCheckout(config.billing?.onCheckout ?? null);
|
|
18255
18646
|
}, [config.billing, setPlans, setCheckout]);
|
|
@@ -18276,7 +18667,7 @@ function ThemeInitializer({ config }) {
|
|
|
18276
18667
|
const initialize = useThemeStore((s) => s.initialize);
|
|
18277
18668
|
const setOverrides = useThemeStore((s) => s.setOverrides);
|
|
18278
18669
|
const setMode = useThemeStore((s) => s.setMode);
|
|
18279
|
-
|
|
18670
|
+
React65.useEffect(() => {
|
|
18280
18671
|
if (config.theme) {
|
|
18281
18672
|
const resolved = isSaasTheme(config.theme) ? resolveTheme(config.theme) : config.theme;
|
|
18282
18673
|
setOverrides(resolved);
|
|
@@ -18288,14 +18679,21 @@ function ThemeInitializer({ config }) {
|
|
|
18288
18679
|
}, [config.defaultThemeMode, config.theme, initialize, setMode, setOverrides]);
|
|
18289
18680
|
return null;
|
|
18290
18681
|
}
|
|
18682
|
+
function PersistentCacheInitializer() {
|
|
18683
|
+
React65.useEffect(() => {
|
|
18684
|
+
attachPersistentCache();
|
|
18685
|
+
void getPersistentCache()?.hydrate();
|
|
18686
|
+
}, []);
|
|
18687
|
+
return null;
|
|
18688
|
+
}
|
|
18291
18689
|
function FayzEventBridgeInitializer({ config }) {
|
|
18292
|
-
|
|
18690
|
+
React65.useEffect(() => startFayzEventBridge(config.chat?.agent), [config.chat?.agent]);
|
|
18293
18691
|
return null;
|
|
18294
18692
|
}
|
|
18295
18693
|
function TeamInitializer({ config }) {
|
|
18296
18694
|
const setTeamPersonKinds = useOrganizationStore((s) => s.setTeamPersonKinds);
|
|
18297
18695
|
const kinds = config.team?.personKinds;
|
|
18298
|
-
|
|
18696
|
+
React65.useEffect(() => {
|
|
18299
18697
|
setTeamPersonKinds(kinds ?? []);
|
|
18300
18698
|
}, [setTeamPersonKinds, kinds]);
|
|
18301
18699
|
return null;
|
|
@@ -18311,7 +18709,7 @@ function ChatRailPanel({ config }) {
|
|
|
18311
18709
|
const agent = config.chat?.agent;
|
|
18312
18710
|
const voice = config.chat?.voice;
|
|
18313
18711
|
const whatsapp = config.chat?.whatsapp;
|
|
18314
|
-
const Component2 =
|
|
18712
|
+
const Component2 = React65.useMemo(() => {
|
|
18315
18713
|
const Panel = () => /* @__PURE__ */ jsx(
|
|
18316
18714
|
ChatConversation,
|
|
18317
18715
|
{
|
|
@@ -18328,15 +18726,15 @@ function ChatRailPanel({ config }) {
|
|
|
18328
18726
|
const conversations = useChatStore((s) => s.conversations);
|
|
18329
18727
|
const setConversations = useChatStore((s) => s.setConversations);
|
|
18330
18728
|
const user = useAuthStore((s) => s.user);
|
|
18331
|
-
const connection =
|
|
18332
|
-
|
|
18729
|
+
const connection = React65.useMemo(() => resolveFayzAgentConnection(agent), [agent]);
|
|
18730
|
+
React65.useEffect(() => {
|
|
18333
18731
|
if (!connection) return;
|
|
18334
18732
|
getFayzAgentClient(connection).listConversations(user?.id).then(setConversations).catch(() => {
|
|
18335
18733
|
});
|
|
18336
18734
|
}, [connection, user?.id, setConversations]);
|
|
18337
18735
|
const persona = useAssistantInviteStore((s) => s.invite?.persona);
|
|
18338
18736
|
useRightRailPanel(
|
|
18339
|
-
|
|
18737
|
+
React65.useMemo(
|
|
18340
18738
|
() => ({
|
|
18341
18739
|
id: "chat",
|
|
18342
18740
|
label: persona ?? "Chat",
|
|
@@ -18348,17 +18746,17 @@ function ChatRailPanel({ config }) {
|
|
|
18348
18746
|
[Component2, conversations.length, persona]
|
|
18349
18747
|
)
|
|
18350
18748
|
);
|
|
18351
|
-
|
|
18749
|
+
React65.useEffect(() => {
|
|
18352
18750
|
if (chatOpen) openPanel("chat");
|
|
18353
18751
|
}, [chatOpen, openPanel]);
|
|
18354
|
-
|
|
18752
|
+
React65.useEffect(() => {
|
|
18355
18753
|
if (!(railOpen && railActive === "chat")) setChatOpen(false);
|
|
18356
18754
|
}, [railOpen, railActive, setChatOpen]);
|
|
18357
18755
|
return null;
|
|
18358
18756
|
}
|
|
18359
18757
|
function AdminProviders({ config, children }) {
|
|
18360
18758
|
const currentOrg = useOrganizationStore((s) => s.currentOrg);
|
|
18361
|
-
const hasFayzAgent =
|
|
18759
|
+
const hasFayzAgent = React65.useMemo(
|
|
18362
18760
|
() => !!resolveFayzAgentConnection(config.chat?.agent),
|
|
18363
18761
|
[config.chat?.agent]
|
|
18364
18762
|
);
|
|
@@ -18366,7 +18764,7 @@ function AdminProviders({ config, children }) {
|
|
|
18366
18764
|
const surface = config.chat?.surface ?? "dock";
|
|
18367
18765
|
const onConsentScreen = typeof window !== "undefined" && window.location.pathname.replace(/\/+$/, "").endsWith("/connect");
|
|
18368
18766
|
const showFab = assistantEnabled && surface === "dock" && !onConsentScreen;
|
|
18369
|
-
const resolved =
|
|
18767
|
+
const resolved = React65.useMemo(() => {
|
|
18370
18768
|
if (config.supabaseUrl && config.supabaseAnonKey) {
|
|
18371
18769
|
createFayzSupabaseClient(config.supabaseUrl, config.supabaseAnonKey);
|
|
18372
18770
|
}
|
|
@@ -18382,7 +18780,7 @@ function AdminProviders({ config, children }) {
|
|
|
18382
18780
|
};
|
|
18383
18781
|
}, [config]);
|
|
18384
18782
|
const path = useAdminPath();
|
|
18385
|
-
const runtime =
|
|
18783
|
+
const runtime = React65.useMemo(
|
|
18386
18784
|
() => resolvePluginRuntime({
|
|
18387
18785
|
plugins: resolved.plugins,
|
|
18388
18786
|
context: {
|
|
@@ -18408,6 +18806,7 @@ function AdminProviders({ config, children }) {
|
|
|
18408
18806
|
cacheTtlMs: config.org?.cacheTtlMs,
|
|
18409
18807
|
children: /* @__PURE__ */ jsx(PluginRuntimeProvider, { value: runtime, children: /* @__PURE__ */ jsx(PermissionsProvider, { config: config.permissions, children: /* @__PURE__ */ jsx(AccessProvider, { limitDeclarations: config.billing?.limitDeclarations, children: /* @__PURE__ */ jsxs(I18nProvider, { value: resolved.i18n, children: [
|
|
18410
18808
|
/* @__PURE__ */ jsx(ThemeInitializer, { config }),
|
|
18809
|
+
/* @__PURE__ */ jsx(PersistentCacheInitializer, {}),
|
|
18411
18810
|
/* @__PURE__ */ jsx(TeamInitializer, { config }),
|
|
18412
18811
|
/* @__PURE__ */ jsx(BillingInitializer, { config }),
|
|
18413
18812
|
/* @__PURE__ */ jsx(FayzEventBridgeInitializer, { config }),
|
|
@@ -18693,8 +19092,8 @@ function manifestToFayzConfig(manifest, surfaceName) {
|
|
|
18693
19092
|
};
|
|
18694
19093
|
}
|
|
18695
19094
|
function AdminScaffold({ manifest, surface }) {
|
|
18696
|
-
const config =
|
|
18697
|
-
const authShellProps =
|
|
19095
|
+
const config = React65.useMemo(() => manifestToFayzConfig(manifest, surface), [manifest, surface]);
|
|
19096
|
+
const authShellProps = React65.useMemo(() => getAuthShellProps(config.auth), [config.auth]);
|
|
18698
19097
|
return /* @__PURE__ */ jsx(AdminProviders, { config, children: /* @__PURE__ */ jsx(
|
|
18699
19098
|
AdminShell,
|
|
18700
19099
|
{
|
|
@@ -18973,10 +19372,10 @@ function OrderDetailView(props) {
|
|
|
18973
19372
|
// três colunas viravam uma tira de 280px que quebrava todo rótulo.
|
|
18974
19373
|
/* @__PURE__ */ jsxs("div", { className: "fz-container space-y-4", children: [
|
|
18975
19374
|
/* @__PURE__ */ jsx(PageHeader, { title, parentLabel: backLabel, onBack }),
|
|
18976
|
-
|
|
19375
|
+
actions && /* @__PURE__ */ jsx(PageHeaderActions, { children: actions }),
|
|
19376
|
+
(badges.length > 0 || props.badgesNode || subtitle) && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
18977
19377
|
props.badgesNode ?? badges.map((b, i) => /* @__PURE__ */ jsx(Badge15, { badge: b }, i)),
|
|
18978
|
-
subtitle && /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: subtitle })
|
|
18979
|
-
actions && /* @__PURE__ */ jsx("div", { className: "ml-auto flex flex-wrap items-center gap-2", children: actions })
|
|
19378
|
+
subtitle && /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: subtitle })
|
|
18980
19379
|
] }),
|
|
18981
19380
|
stats.length > 0 && /* @__PURE__ */ jsx("div", { className: "fz-fields fz-fields-4 gap-3", children: stats.map((tile, i) => /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-3", children: [
|
|
18982
19381
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
|
|
@@ -19064,7 +19463,9 @@ var ITEM_LABELS = {
|
|
|
19064
19463
|
adjustments: "Desconto / acr\xE9scimo",
|
|
19065
19464
|
removeAdjustments: "Remover ajustes",
|
|
19066
19465
|
remove: "Remover item",
|
|
19067
|
-
done: "Conclu\xEDdo"
|
|
19466
|
+
done: "Conclu\xEDdo",
|
|
19467
|
+
create: "Cadastrar",
|
|
19468
|
+
clear: "Limpar"
|
|
19068
19469
|
};
|
|
19069
19470
|
function OrderFormItemRow({
|
|
19070
19471
|
index,
|
|
@@ -19091,7 +19492,7 @@ function OrderFormItemRow({
|
|
|
19091
19492
|
const total = quantity * unitPrice - (discount ?? 0) + (surcharge ?? 0);
|
|
19092
19493
|
const kindLabel = itemTypes.find((tp) => tp.value === itemKind)?.label ?? itemKind;
|
|
19093
19494
|
const hasAdjustments = (discount ?? 0) > 0 || (surcharge ?? 0) > 0;
|
|
19094
|
-
const [showAdjustments, setShowAdjustments] =
|
|
19495
|
+
const [showAdjustments, setShowAdjustments] = React65.useState(hasAdjustments);
|
|
19095
19496
|
const lookup2 = entityLookups[itemKind];
|
|
19096
19497
|
function handleFieldKeyDown(e) {
|
|
19097
19498
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
@@ -19166,6 +19567,12 @@ function OrderFormItemRow({
|
|
|
19166
19567
|
const results = await lookup2.search(q);
|
|
19167
19568
|
return results.map((r) => ({ id: r.id, label: r.label, subtitle: r.subtitle, group: r.group, data: r }));
|
|
19168
19569
|
},
|
|
19570
|
+
createLabel: l.create,
|
|
19571
|
+
clearLabel: l.clear,
|
|
19572
|
+
onCreate: lookup2.create ? async (name) => {
|
|
19573
|
+
const created = await lookup2.create(name);
|
|
19574
|
+
onChange({ referenceId: created.id, description: created.label });
|
|
19575
|
+
} : void 0,
|
|
19169
19576
|
placeholder: `${l.item}\u2026`,
|
|
19170
19577
|
renderOption: (opt) => /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
19171
19578
|
/* @__PURE__ */ jsx("p", { className: "truncate text-sm", children: opt.label }),
|
|
@@ -19361,7 +19768,7 @@ function OrderFormView({
|
|
|
19361
19768
|
parentLabel,
|
|
19362
19769
|
onBack,
|
|
19363
19770
|
badges,
|
|
19364
|
-
subtitle,
|
|
19771
|
+
subtitle: _subtitle,
|
|
19365
19772
|
actions,
|
|
19366
19773
|
banner,
|
|
19367
19774
|
children,
|
|
@@ -19372,11 +19779,8 @@ function OrderFormView({
|
|
|
19372
19779
|
// se cabem duas colunas é a LARGURA DESTA COLUNA, não a da janela.
|
|
19373
19780
|
/* @__PURE__ */ jsxs("div", { className: "fz-container space-y-4", children: [
|
|
19374
19781
|
/* @__PURE__ */ jsx(PageHeader, { title, parentLabel, onBack }),
|
|
19375
|
-
|
|
19376
|
-
|
|
19377
|
-
subtitle && /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: subtitle }),
|
|
19378
|
-
actions && /* @__PURE__ */ jsx("div", { className: "ml-auto flex flex-wrap items-center gap-2", children: actions })
|
|
19379
|
-
] }),
|
|
19782
|
+
actions && /* @__PURE__ */ jsx(PageHeaderActions, { children: actions }),
|
|
19783
|
+
badges && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2", children: badges }),
|
|
19380
19784
|
banner,
|
|
19381
19785
|
/* @__PURE__ */ jsxs("div", { className: "fz-split", children: [
|
|
19382
19786
|
/* @__PURE__ */ jsx("div", { className: "fz-container space-y-4", children }),
|
|
@@ -19387,13 +19791,12 @@ function OrderFormView({
|
|
|
19387
19791
|
}
|
|
19388
19792
|
OrderFormView.displayName = "OrderFormView";
|
|
19389
19793
|
function OrderFormSkeleton() {
|
|
19390
|
-
return
|
|
19391
|
-
|
|
19392
|
-
|
|
19393
|
-
|
|
19394
|
-
|
|
19395
|
-
|
|
19396
|
-
/* @__PURE__ */ jsxs("div", { className: "fz-split", children: [
|
|
19794
|
+
return (
|
|
19795
|
+
// Sem a linha da migalha nem a fileira de pastilhas: a migalha mora na barra
|
|
19796
|
+
// da shell (que já está desenhada quando isto aparece) e o formulário não
|
|
19797
|
+
// tem badges. Eram duas faixas cinzas prometendo conteúdo que nunca chega —
|
|
19798
|
+
// o "pulo" que um esqueleto existe para evitar, causado pelo esqueleto.
|
|
19799
|
+
/* @__PURE__ */ jsx("div", { className: "fz-container space-y-4", children: /* @__PURE__ */ jsxs("div", { className: "fz-split", children: [
|
|
19397
19800
|
/* @__PURE__ */ jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card", children: [
|
|
19398
19801
|
/* @__PURE__ */ jsx("div", { className: "border-b px-4 py-3", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" }) }),
|
|
19399
19802
|
/* @__PURE__ */ jsx("div", { className: "space-y-3 p-4", children: [1, 2].map((i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
@@ -19406,11 +19809,13 @@ function OrderFormSkeleton() {
|
|
|
19406
19809
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-20" }),
|
|
19407
19810
|
/* @__PURE__ */ jsx("div", { className: "mt-3 space-y-2", children: Array.from({ length: rows }).map((_, j) => /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-full" }, j)) })
|
|
19408
19811
|
] }, i)) })
|
|
19409
|
-
] })
|
|
19410
|
-
|
|
19812
|
+
] }) })
|
|
19813
|
+
);
|
|
19411
19814
|
}
|
|
19412
19815
|
function OrderListView({
|
|
19413
|
-
title,
|
|
19816
|
+
// `title` continua na API (é o que o chamador declara), mas quem escreve o
|
|
19817
|
+
// nome da tela é a barra da shell — ver o corpo.
|
|
19818
|
+
title: _title,
|
|
19414
19819
|
subtitle,
|
|
19415
19820
|
actions,
|
|
19416
19821
|
stats,
|
|
@@ -19428,10 +19833,10 @@ function OrderListView({
|
|
|
19428
19833
|
bulkActions,
|
|
19429
19834
|
rowId
|
|
19430
19835
|
}) {
|
|
19431
|
-
const [search, setSearch] =
|
|
19432
|
-
const [page, setPage] =
|
|
19433
|
-
const [rawSelection, setRawSelection] =
|
|
19434
|
-
const cols =
|
|
19836
|
+
const [search, setSearch] = React65.useState("");
|
|
19837
|
+
const [page, setPage] = React65.useState(1);
|
|
19838
|
+
const [rawSelection, setRawSelection] = React65.useState([]);
|
|
19839
|
+
const cols = React65.useMemo(
|
|
19435
19840
|
() => columns.map((c) => ({
|
|
19436
19841
|
id: c.key,
|
|
19437
19842
|
header: () => /* @__PURE__ */ jsx("div", { className: c.align === "right" ? "text-right" : "", children: c.header }),
|
|
@@ -19439,29 +19844,30 @@ function OrderListView({
|
|
|
19439
19844
|
})),
|
|
19440
19845
|
[columns]
|
|
19441
19846
|
);
|
|
19442
|
-
const filtered =
|
|
19847
|
+
const filtered = React65.useMemo(() => {
|
|
19443
19848
|
const term = search.trim().toLowerCase();
|
|
19444
19849
|
if (!term || !searchText) return rows;
|
|
19445
19850
|
return rows.filter((row) => searchText(row).toLowerCase().includes(term));
|
|
19446
19851
|
}, [rows, search, searchText]);
|
|
19447
|
-
|
|
19852
|
+
React65.useEffect(() => {
|
|
19448
19853
|
setPage(1);
|
|
19449
19854
|
}, [search]);
|
|
19450
19855
|
const paged = pageSize > 0 ? filtered.slice((page - 1) * pageSize, page * pageSize) : filtered;
|
|
19451
|
-
const getId =
|
|
19856
|
+
const getId = React65.useCallback(
|
|
19452
19857
|
(row) => rowId ? rowId(row) : String(row.id ?? ""),
|
|
19453
19858
|
[rowId]
|
|
19454
19859
|
);
|
|
19455
|
-
const pageIds =
|
|
19456
|
-
const selectedIds =
|
|
19860
|
+
const pageIds = React65.useMemo(() => paged.map(getId), [paged, getId]);
|
|
19861
|
+
const selectedIds = React65.useMemo(
|
|
19457
19862
|
() => rawSelection.filter((id) => pageIds.includes(id)),
|
|
19458
19863
|
[rawSelection, pageIds]
|
|
19459
19864
|
);
|
|
19460
|
-
const selectedRows =
|
|
19865
|
+
const selectedRows = React65.useMemo(
|
|
19461
19866
|
() => paged.filter((row) => selectedIds.includes(getId(row))),
|
|
19462
19867
|
[paged, selectedIds, getId]
|
|
19463
19868
|
);
|
|
19464
19869
|
const selectable = (bulkActions?.length ?? 0) > 0;
|
|
19870
|
+
const hasSelection = selectable && selectedIds.length > 0;
|
|
19465
19871
|
const barActions = (bulkActions ?? []).map((action) => ({
|
|
19466
19872
|
id: action.id,
|
|
19467
19873
|
label: action.label,
|
|
@@ -19483,38 +19889,31 @@ function OrderListView({
|
|
|
19483
19889
|
// `p-3 md:p-6` (AdminShell). Reaplicar `p-6 md:p-8` aqui empurrava a lista
|
|
19484
19890
|
// 32px à direita do título na barra de topo e de todas as outras telas.
|
|
19485
19891
|
/* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
19486
|
-
|
|
19487
|
-
|
|
19488
|
-
|
|
19489
|
-
|
|
19490
|
-
|
|
19491
|
-
tabs: navTabs,
|
|
19492
|
-
value: activeNavTab ?? navTabs[0].value,
|
|
19493
|
-
onChange: (v) => onNavTabChange?.(v)
|
|
19494
|
-
}
|
|
19495
|
-
),
|
|
19496
|
-
actions
|
|
19497
|
-
] }),
|
|
19498
|
-
!navTabs?.length && (title || subtitle || actions) && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
|
|
19499
|
-
title || subtitle ? /* @__PURE__ */ jsxs("div", { children: [
|
|
19500
|
-
title && /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold text-foreground", children: title }),
|
|
19501
|
-
subtitle && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: subtitle })
|
|
19502
|
-
] }) : /* @__PURE__ */ jsx("span", {}),
|
|
19503
|
-
actions
|
|
19504
|
-
] }),
|
|
19505
|
-
tiles.length > 0 && /* @__PURE__ */ jsx(StatTiles, { tiles, loading }),
|
|
19506
|
-
selectable && /* @__PURE__ */ jsx(
|
|
19507
|
-
BulkActionBar,
|
|
19892
|
+
actions && /* @__PURE__ */ jsx(PageHeaderActions, { children: actions }),
|
|
19893
|
+
navTabs && navTabs.length > 0 && // Mesma faixa de CrudListView e da sub-nav de módulo: abas à esquerda,
|
|
19894
|
+
// fechada pelo filete que atravessa a página.
|
|
19895
|
+
/* @__PURE__ */ jsx(
|
|
19896
|
+
PageTabs,
|
|
19508
19897
|
{
|
|
19509
|
-
|
|
19510
|
-
|
|
19511
|
-
|
|
19512
|
-
|
|
19513
|
-
actions: barActions
|
|
19898
|
+
className: "mb-0",
|
|
19899
|
+
tabs: navTabs,
|
|
19900
|
+
value: activeNavTab ?? navTabs[0].value,
|
|
19901
|
+
onChange: (v) => onNavTabChange?.(v)
|
|
19514
19902
|
}
|
|
19515
19903
|
),
|
|
19904
|
+
tiles.length > 0 && /* @__PURE__ */ jsx(StatTiles, { tiles, loading }),
|
|
19516
19905
|
/* @__PURE__ */ jsxs(Card, { className: "overflow-hidden", children: [
|
|
19517
|
-
searchText && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2 border-b border-border px-3 py-2", children:
|
|
19906
|
+
(searchText || hasSelection) && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2 border-b border-border px-3 py-2", children: hasSelection ? /* @__PURE__ */ jsx(
|
|
19907
|
+
BulkActionBar,
|
|
19908
|
+
{
|
|
19909
|
+
variant: "inline",
|
|
19910
|
+
count: selectedIds.length,
|
|
19911
|
+
total: paged.length,
|
|
19912
|
+
onSelectAll: () => setRawSelection(pageIds),
|
|
19913
|
+
onClear: () => setRawSelection([]),
|
|
19914
|
+
actions: barActions
|
|
19915
|
+
}
|
|
19916
|
+
) : /* @__PURE__ */ jsx("div", { className: "min-w-[10rem] flex-1", children: /* @__PURE__ */ jsx(
|
|
19518
19917
|
SearchField,
|
|
19519
19918
|
{
|
|
19520
19919
|
value: search,
|
|
@@ -19645,6 +20044,13 @@ function createClientOrdersProvider() {
|
|
|
19645
20044
|
}
|
|
19646
20045
|
};
|
|
19647
20046
|
}
|
|
20047
|
+
var PERSON_LOOKUPS = {};
|
|
20048
|
+
function registerPersonLookup(kind, lookup2) {
|
|
20049
|
+
PERSON_LOOKUPS[kind] = lookup2;
|
|
20050
|
+
}
|
|
20051
|
+
function getPersonLookup(kind) {
|
|
20052
|
+
return PERSON_LOOKUPS[kind] ?? null;
|
|
20053
|
+
}
|
|
19648
20054
|
var ARCHETYPE_DISPLAY = {
|
|
19649
20055
|
person: { table: "people", labelField: "name", subtitleFields: ["phone"], groupField: "kind" },
|
|
19650
20056
|
product: { table: "products", labelField: "name", subtitleFields: ["sku", "description"], priceField: "price" },
|
|
@@ -19705,6 +20111,21 @@ function createArchetypeLookup(config) {
|
|
|
19705
20111
|
(row) => toResult(row, display, config.kindLabels)
|
|
19706
20112
|
);
|
|
19707
20113
|
},
|
|
20114
|
+
// Cadastro na hora: só o nome (e o `kind`, quando a busca já está presa a
|
|
20115
|
+
// um). Um registro nascido aqui é um esboço de propósito — o campo que o
|
|
20116
|
+
// pediu precisa continuar, não abrir um formulário inteiro.
|
|
20117
|
+
async create(name) {
|
|
20118
|
+
const supabase = getSupabaseClientOptional();
|
|
20119
|
+
if (!supabase) throw new Error("No database connection");
|
|
20120
|
+
const row = {
|
|
20121
|
+
[display.labelField]: name,
|
|
20122
|
+
is_active: true
|
|
20123
|
+
};
|
|
20124
|
+
if (kinds && kinds.length === 1) row.kind = kinds[0];
|
|
20125
|
+
const { data, error } = await supabase.from(display.table).insert(row).select("*").single();
|
|
20126
|
+
if (error) throw new Error(error.message);
|
|
20127
|
+
return toResult(data, display, config.kindLabels);
|
|
20128
|
+
},
|
|
19708
20129
|
async getById(id) {
|
|
19709
20130
|
const supabase = getSupabaseClientOptional();
|
|
19710
20131
|
if (!supabase) return null;
|
|
@@ -19888,11 +20309,11 @@ function PersonTimeline({
|
|
|
19888
20309
|
pageSize,
|
|
19889
20310
|
activeSourceIds
|
|
19890
20311
|
});
|
|
19891
|
-
const toneBySource =
|
|
20312
|
+
const toneBySource = React65__default.useMemo(
|
|
19892
20313
|
() => new Map(sources2.map((s) => [s.id, s.tone ?? "neutral"])),
|
|
19893
20314
|
[sources2]
|
|
19894
20315
|
);
|
|
19895
|
-
const hrefFor =
|
|
20316
|
+
const hrefFor = React65__default.useCallback(
|
|
19896
20317
|
(item) => {
|
|
19897
20318
|
if (item.href) return item.href;
|
|
19898
20319
|
if (!recordPath || !item.targetTab) return void 0;
|
|
@@ -19935,19 +20356,19 @@ function PersonTimeline({
|
|
|
19935
20356
|
}
|
|
19936
20357
|
function createPlaceholder(title, description) {
|
|
19937
20358
|
return function PlaceholderPage() {
|
|
19938
|
-
return
|
|
20359
|
+
return React65__default.createElement(
|
|
19939
20360
|
"div",
|
|
19940
20361
|
{ className: "mx-auto max-w-4xl" },
|
|
19941
|
-
|
|
19942
|
-
description ?
|
|
19943
|
-
|
|
20362
|
+
React65__default.createElement("h1", { className: "text-3xl font-bold text-foreground" }, title),
|
|
20363
|
+
description ? React65__default.createElement("p", { className: "mt-1 text-muted-foreground" }, description) : null,
|
|
20364
|
+
React65__default.createElement(
|
|
19944
20365
|
"div",
|
|
19945
20366
|
{ className: "mt-8 flex items-center justify-center rounded-card border border-dashed border-border bg-card p-16" },
|
|
19946
|
-
|
|
20367
|
+
React65__default.createElement(
|
|
19947
20368
|
"div",
|
|
19948
20369
|
{ className: "text-center" },
|
|
19949
|
-
|
|
19950
|
-
|
|
20370
|
+
React65__default.createElement("p", { className: "text-lg font-medium text-muted-foreground" }, "Coming Soon"),
|
|
20371
|
+
React65__default.createElement(
|
|
19951
20372
|
"p",
|
|
19952
20373
|
{ className: "mt-1 text-sm text-muted-foreground/70" },
|
|
19953
20374
|
"This module is being built as a plugin."
|
|
@@ -19957,55 +20378,6 @@ function createPlaceholder(title, description) {
|
|
|
19957
20378
|
);
|
|
19958
20379
|
};
|
|
19959
20380
|
}
|
|
19960
|
-
function QuickActionsButton({ actions, className }) {
|
|
19961
|
-
const [open, setOpen] = useState(false);
|
|
19962
|
-
const ref = useRef(null);
|
|
19963
|
-
const variant = useModuleLayout() === "tabs" ? "default" : "outline";
|
|
19964
|
-
useEffect(() => {
|
|
19965
|
-
function handler(e) {
|
|
19966
|
-
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
19967
|
-
}
|
|
19968
|
-
document.addEventListener("mousedown", handler);
|
|
19969
|
-
return () => document.removeEventListener("mousedown", handler);
|
|
19970
|
-
}, []);
|
|
19971
|
-
if (actions.length === 0) return null;
|
|
19972
|
-
return /* @__PURE__ */ jsxs("div", { ref, className: cn("relative", className), children: [
|
|
19973
|
-
/* @__PURE__ */ jsxs(
|
|
19974
|
-
Button,
|
|
19975
|
-
{
|
|
19976
|
-
variant,
|
|
19977
|
-
size: "sm",
|
|
19978
|
-
onClick: () => setOpen(!open),
|
|
19979
|
-
className: cn(open && variant === "outline" && "bg-muted"),
|
|
19980
|
-
children: [
|
|
19981
|
-
/* @__PURE__ */ jsx(Plus, { className: cn("h-3.5 w-3.5 transition-transform duration-200", open && "rotate-45") }),
|
|
19982
|
-
/* @__PURE__ */ jsx("span", { children: "New" })
|
|
19983
|
-
]
|
|
19984
|
-
}
|
|
19985
|
-
),
|
|
19986
|
-
open && /* @__PURE__ */ jsx("div", { className: "fayz-glass-surface absolute top-full right-0 z-50 mt-2 w-64 rounded-xl border bg-popover shadow-lg overflow-hidden animate-in fade-in-0 zoom-in-95 origin-top-right", children: /* @__PURE__ */ jsx("div", { className: "p-1.5", children: actions.map((action) => {
|
|
19987
|
-
const Icon = action.icon ? ICON_MAP[action.icon] ?? Plus : Plus;
|
|
19988
|
-
return /* @__PURE__ */ jsxs(
|
|
19989
|
-
"button",
|
|
19990
|
-
{
|
|
19991
|
-
onClick: () => {
|
|
19992
|
-
action.action();
|
|
19993
|
-
setOpen(false);
|
|
19994
|
-
},
|
|
19995
|
-
className: "w-full flex items-center gap-3 rounded-lg px-3 py-2.5 text-left hover:bg-muted/50 transition-colors group",
|
|
19996
|
-
children: [
|
|
19997
|
-
/* @__PURE__ */ jsx("div", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-muted group-hover:bg-primary/10 transition-colors shrink-0", children: /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 text-muted-foreground group-hover:text-primary transition-colors" }) }),
|
|
19998
|
-
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
19999
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: action.label }),
|
|
20000
|
-
action.description && /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground leading-tight", children: action.description })
|
|
20001
|
-
] })
|
|
20002
|
-
]
|
|
20003
|
-
},
|
|
20004
|
-
action.id
|
|
20005
|
-
);
|
|
20006
|
-
}) }) })
|
|
20007
|
-
] });
|
|
20008
|
-
}
|
|
20009
20381
|
function ModuleActionBar({
|
|
20010
20382
|
quickActions,
|
|
20011
20383
|
settingsPath,
|
|
@@ -20034,9 +20406,9 @@ function ModuleActionBar({
|
|
|
20034
20406
|
] });
|
|
20035
20407
|
}
|
|
20036
20408
|
function createPluginContext(displayName) {
|
|
20037
|
-
const ConfigContext =
|
|
20038
|
-
const ProviderContext =
|
|
20039
|
-
const StoreContext =
|
|
20409
|
+
const ConfigContext = React65__default.createContext(null);
|
|
20410
|
+
const ProviderContext = React65__default.createContext(null);
|
|
20411
|
+
const StoreContext = React65__default.createContext(null);
|
|
20040
20412
|
const ContextProvider = ({
|
|
20041
20413
|
config,
|
|
20042
20414
|
provider,
|
|
@@ -20045,17 +20417,17 @@ function createPluginContext(displayName) {
|
|
|
20045
20417
|
}) => /* @__PURE__ */ jsx(ConfigContext.Provider, { value: config, children: /* @__PURE__ */ jsx(ProviderContext.Provider, { value: provider, children: /* @__PURE__ */ jsx(StoreContext.Provider, { value: store, children }) }) });
|
|
20046
20418
|
ContextProvider.displayName = `${displayName}ContextProvider`;
|
|
20047
20419
|
function useConfig() {
|
|
20048
|
-
const ctx =
|
|
20420
|
+
const ctx = React65__default.useContext(ConfigContext);
|
|
20049
20421
|
if (!ctx) throw new Error(`useConfig must be used within ${displayName}`);
|
|
20050
20422
|
return ctx;
|
|
20051
20423
|
}
|
|
20052
20424
|
function useProvider() {
|
|
20053
|
-
const ctx =
|
|
20425
|
+
const ctx = React65__default.useContext(ProviderContext);
|
|
20054
20426
|
if (!ctx) throw new Error(`useProvider must be used within ${displayName}`);
|
|
20055
20427
|
return ctx;
|
|
20056
20428
|
}
|
|
20057
20429
|
function useStore$1(selector) {
|
|
20058
|
-
const store =
|
|
20430
|
+
const store = React65__default.useContext(StoreContext);
|
|
20059
20431
|
if (!store) throw new Error(`useStore must be used within ${displayName}`);
|
|
20060
20432
|
return useStore(store, selector);
|
|
20061
20433
|
}
|
|
@@ -20112,7 +20484,7 @@ function PluginRegistryManager({ registries, routeBase, className }) {
|
|
|
20112
20484
|
return registries[0]?.id ?? "";
|
|
20113
20485
|
};
|
|
20114
20486
|
const [activeTab, setActiveTab] = useState(getTabFromHash);
|
|
20115
|
-
|
|
20487
|
+
React65__default.useEffect(() => {
|
|
20116
20488
|
if (!routeBase) return;
|
|
20117
20489
|
const handler = () => setActiveTab(getTabFromHash());
|
|
20118
20490
|
window.addEventListener("hashchange", handler);
|
|
@@ -20170,6 +20542,14 @@ function useModuleNavigation(hashBase, depthMap, homeView = "summary") {
|
|
|
20170
20542
|
const rest = hash.slice(hashBase.length + 1);
|
|
20171
20543
|
const segments = rest.split("/");
|
|
20172
20544
|
if (segments.length === 1 && segments[0] === homeView) return homeView;
|
|
20545
|
+
const UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
20546
|
+
const last = segments[segments.length - 1];
|
|
20547
|
+
if (segments.length >= 3 && !UUID_RE2.test(last) && UUID_RE2.test(segments[segments.length - 2])) {
|
|
20548
|
+
return segments.slice(0, -2).join("-") + "-" + last + ":" + segments[segments.length - 2];
|
|
20549
|
+
}
|
|
20550
|
+
if (segments.length === 2 && UUID_RE2.test(last)) {
|
|
20551
|
+
return segments[0] + "-detail:" + last;
|
|
20552
|
+
}
|
|
20173
20553
|
const ACTION_KEYWORDS = ["edit", "detail", "view", "post"];
|
|
20174
20554
|
if (segments.length >= 3) {
|
|
20175
20555
|
const maybeAction = segments[segments.length - 2];
|
|
@@ -20177,9 +20557,8 @@ function useModuleNavigation(hashBase, depthMap, homeView = "summary") {
|
|
|
20177
20557
|
return segments.slice(0, -2).join("-") + "-" + maybeAction + ":" + segments[segments.length - 1];
|
|
20178
20558
|
}
|
|
20179
20559
|
}
|
|
20180
|
-
|
|
20181
|
-
|
|
20182
|
-
return segments.slice(0, -1).join("-") + ":" + segments[segments.length - 1];
|
|
20560
|
+
if (segments.length >= 2 && UUID_RE2.test(last)) {
|
|
20561
|
+
return segments.slice(0, -1).join("-") + ":" + last;
|
|
20183
20562
|
}
|
|
20184
20563
|
return segments.join("-");
|
|
20185
20564
|
}
|
|
@@ -20234,9 +20613,17 @@ function useModuleNavigation(hashBase, depthMap, homeView = "summary") {
|
|
|
20234
20613
|
} else {
|
|
20235
20614
|
const colonIdx = nextView.indexOf(":");
|
|
20236
20615
|
if (colonIdx !== -1) {
|
|
20237
|
-
const
|
|
20616
|
+
const rawPrefix = nextView.slice(0, colonIdx);
|
|
20238
20617
|
const id = nextView.slice(colonIdx + 1);
|
|
20239
|
-
|
|
20618
|
+
const parts = rawPrefix.split("-");
|
|
20619
|
+
const verb = parts.length > 1 ? parts[parts.length - 1] : void 0;
|
|
20620
|
+
if (verb === "detail") {
|
|
20621
|
+
window.location.hash = `${hashBase}/${parts.slice(0, -1).join("/")}/${id}`;
|
|
20622
|
+
} else if (verb === "edit") {
|
|
20623
|
+
window.location.hash = `${hashBase}/${parts.slice(0, -1).join("/")}/${id}/edit`;
|
|
20624
|
+
} else {
|
|
20625
|
+
window.location.hash = `${hashBase}/${rawPrefix.replace(/-/g, "/")}/${id}`;
|
|
20626
|
+
}
|
|
20240
20627
|
} else {
|
|
20241
20628
|
const path = nextView.replace(/-/g, "/");
|
|
20242
20629
|
window.location.hash = `${hashBase}/${path}`;
|
|
@@ -20265,7 +20652,7 @@ function formatAge(dob) {
|
|
|
20265
20652
|
return null;
|
|
20266
20653
|
}
|
|
20267
20654
|
}
|
|
20268
|
-
function PersonLink2({ personId, name, lookup: lookup2, profileHref, tab, size = "default", className }) {
|
|
20655
|
+
function PersonLink2({ personId, name, lookup: lookup2, kind, profileHref, tab, size = "default", className }) {
|
|
20269
20656
|
const [person, setPerson] = useState(null);
|
|
20270
20657
|
const [loading, setLoading] = useState(false);
|
|
20271
20658
|
const [fetched, setFetched] = useState(false);
|
|
@@ -20274,7 +20661,7 @@ function PersonLink2({ personId, name, lookup: lookup2, profileHref, tab, size =
|
|
|
20274
20661
|
const fetchPerson = useCallback(() => {
|
|
20275
20662
|
if (!fetched && personId) {
|
|
20276
20663
|
setLoading(true);
|
|
20277
|
-
(lookup2 ?? personLookup).getById(personId).then((result) => {
|
|
20664
|
+
(lookup2 ?? (kind ? getPersonLookup(kind) : null) ?? personLookup).getById(personId).then((result) => {
|
|
20278
20665
|
setPerson(result);
|
|
20279
20666
|
setFetched(true);
|
|
20280
20667
|
setLoading(false);
|
|
@@ -20283,7 +20670,7 @@ function PersonLink2({ personId, name, lookup: lookup2, profileHref, tab, size =
|
|
|
20283
20670
|
setLoading(false);
|
|
20284
20671
|
});
|
|
20285
20672
|
}
|
|
20286
|
-
}, [personId, fetched, lookup2]);
|
|
20673
|
+
}, [personId, fetched, lookup2, kind]);
|
|
20287
20674
|
const handleOpenChange = useCallback((v) => {
|
|
20288
20675
|
setOpen(v);
|
|
20289
20676
|
if (v) fetchPerson();
|
|
@@ -20306,13 +20693,14 @@ function PersonLink2({ personId, name, lookup: lookup2, profileHref, tab, size =
|
|
|
20306
20693
|
const data = person?.data;
|
|
20307
20694
|
const email = data?.email;
|
|
20308
20695
|
const phone = data?.phone;
|
|
20309
|
-
const
|
|
20696
|
+
const resolvedKind = kind ?? data?.kind ?? person?.group;
|
|
20310
20697
|
const isActive = data?.is_active;
|
|
20311
20698
|
const dob = data?.date_of_birth;
|
|
20312
20699
|
const createdAt = data?.created_at;
|
|
20313
20700
|
const age = dob ? formatAge(dob) : null;
|
|
20314
20701
|
const initial = name.charAt(0).toUpperCase();
|
|
20315
|
-
const
|
|
20702
|
+
const registeredPath = kind ? getPersonPath(kind) : null;
|
|
20703
|
+
const resolvedHref = profileHref ?? (registeredPath ? `#${registeredPath}/${personId}${tab ? `/${tab}` : ""}` : void 0) ?? resolveEntityAnchor(personId, "person", resolvedKind ?? void 0, tab);
|
|
20316
20704
|
return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
|
|
20317
20705
|
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
20318
20706
|
"button",
|
|
@@ -20347,7 +20735,7 @@ function PersonLink2({ personId, name, lookup: lookup2, profileHref, tab, size =
|
|
|
20347
20735
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
20348
20736
|
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold truncate", children: name }),
|
|
20349
20737
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 mt-0.5", children: [
|
|
20350
|
-
|
|
20738
|
+
resolvedKind && /* @__PURE__ */ jsx("span", { className: "inline-flex items-center rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground capitalize", children: resolvedKind }),
|
|
20351
20739
|
isActive !== void 0 && /* @__PURE__ */ jsxs("span", { className: `inline-flex items-center gap-1 text-[10px] ${isActive ? "text-success" : "text-muted-foreground/50"}`, children: [
|
|
20352
20740
|
/* @__PURE__ */ jsx("span", { className: `h-1.5 w-1.5 rounded-full ${isActive ? "bg-success" : "bg-muted-foreground/30"}` }),
|
|
20353
20741
|
isActive ? "Active" : "Inactive"
|
|
@@ -20414,12 +20802,12 @@ function CrudRecordModal({
|
|
|
20414
20802
|
description,
|
|
20415
20803
|
emptyLabel
|
|
20416
20804
|
}) {
|
|
20417
|
-
const [record, setRecord] =
|
|
20418
|
-
const [loading, setLoading] =
|
|
20419
|
-
const [saving, setSaving] =
|
|
20420
|
-
const [error, setError] =
|
|
20421
|
-
const formId =
|
|
20422
|
-
|
|
20805
|
+
const [record, setRecord] = React65.useState(null);
|
|
20806
|
+
const [loading, setLoading] = React65.useState(false);
|
|
20807
|
+
const [saving, setSaving] = React65.useState(false);
|
|
20808
|
+
const [error, setError] = React65.useState(null);
|
|
20809
|
+
const formId = React65.useId();
|
|
20810
|
+
React65.useEffect(() => {
|
|
20423
20811
|
if (!open) return;
|
|
20424
20812
|
let cancelled = false;
|
|
20425
20813
|
setLoading(true);
|
|
@@ -20491,13 +20879,27 @@ function RecordPickerModal({
|
|
|
20491
20879
|
placeholder = "Buscar\u2026",
|
|
20492
20880
|
confirmLabel = "Adicionar",
|
|
20493
20881
|
emptyLabel = "Nada encontrado.",
|
|
20494
|
-
columns
|
|
20882
|
+
columns,
|
|
20883
|
+
onRefresh,
|
|
20884
|
+
fromCache
|
|
20495
20885
|
}) {
|
|
20886
|
+
const t = useTranslation();
|
|
20496
20887
|
const [term, setTerm] = useState("");
|
|
20497
20888
|
const [items, setItems] = useState([]);
|
|
20498
20889
|
const [loading, setLoading] = useState(false);
|
|
20499
20890
|
const [picked, setPicked] = useState([]);
|
|
20500
20891
|
const input = useRef(null);
|
|
20892
|
+
async function refreshNow() {
|
|
20893
|
+
onRefresh?.();
|
|
20894
|
+
setLoading(true);
|
|
20895
|
+
try {
|
|
20896
|
+
setItems(await search(term.trim()));
|
|
20897
|
+
} catch {
|
|
20898
|
+
setItems([]);
|
|
20899
|
+
} finally {
|
|
20900
|
+
setLoading(false);
|
|
20901
|
+
}
|
|
20902
|
+
}
|
|
20501
20903
|
useEffect(() => {
|
|
20502
20904
|
if (!open) {
|
|
20503
20905
|
setTerm("");
|
|
@@ -20558,6 +20960,17 @@ function RecordPickerModal({
|
|
|
20558
20960
|
"data-testid": "record-picker-search",
|
|
20559
20961
|
className: "w-full bg-transparent py-2 text-sm outline-none"
|
|
20560
20962
|
}
|
|
20963
|
+
),
|
|
20964
|
+
onRefresh && /* @__PURE__ */ jsx(
|
|
20965
|
+
RefreshButton,
|
|
20966
|
+
{
|
|
20967
|
+
onRefresh: refreshNow,
|
|
20968
|
+
fromCache,
|
|
20969
|
+
label: t("crud.list.refresh"),
|
|
20970
|
+
labelCached: t("crud.list.refreshCached"),
|
|
20971
|
+
"data-testid": "record-picker-refresh",
|
|
20972
|
+
className: "shrink-0 rounded p-1 text-muted-foreground hover:text-foreground"
|
|
20973
|
+
}
|
|
20561
20974
|
)
|
|
20562
20975
|
] }) }),
|
|
20563
20976
|
/* @__PURE__ */ jsx(ModalBody, { className: "px-5 py-3", children: /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-md border", children: [
|
|
@@ -21032,10 +21445,10 @@ function useTenantPluginSettings(pluginId, defaults) {
|
|
|
21032
21445
|
);
|
|
21033
21446
|
}
|
|
21034
21447
|
function useAgentSurface(contribution) {
|
|
21035
|
-
const ref =
|
|
21448
|
+
const ref = React65.useRef(contribution);
|
|
21036
21449
|
ref.current = contribution;
|
|
21037
21450
|
const id = contribution.id;
|
|
21038
|
-
|
|
21451
|
+
React65.useEffect(() => {
|
|
21039
21452
|
registerSurface({ id, get: () => ref.current });
|
|
21040
21453
|
const names = (ref.current.tools ?? []).map((t) => t.tool.name);
|
|
21041
21454
|
for (const name of names) {
|
|
@@ -21055,21 +21468,21 @@ function ConnectorsHub({ hostPluginId }) {
|
|
|
21055
21468
|
const { t } = useTranslation$1();
|
|
21056
21469
|
const { connectors, reload } = useConnectors({ includeGrants: false });
|
|
21057
21470
|
const assistantAvailable = useConnectorsPanelAvailable();
|
|
21058
|
-
const [selected, setSelected] =
|
|
21059
|
-
const [adding, setAdding] =
|
|
21060
|
-
const hosted =
|
|
21471
|
+
const [selected, setSelected] = React65__default.useState(null);
|
|
21472
|
+
const [adding, setAdding] = React65__default.useState(false);
|
|
21473
|
+
const hosted = React65__default.useMemo(
|
|
21061
21474
|
() => (connectors ?? []).filter((c) => c.hostPluginId === hostPluginId),
|
|
21062
21475
|
[connectors, hostPluginId]
|
|
21063
21476
|
);
|
|
21064
|
-
const categories =
|
|
21477
|
+
const categories = React65__default.useMemo(
|
|
21065
21478
|
() => [...new Set(hosted.map((c) => c.category).filter((c) => !!c))],
|
|
21066
21479
|
[hosted]
|
|
21067
21480
|
);
|
|
21068
|
-
const scoped =
|
|
21481
|
+
const scoped = React65__default.useMemo(() => {
|
|
21069
21482
|
const siblings = inCategories(connectors ?? [], categories).filter((c) => c.hostPluginId !== hostPluginId);
|
|
21070
21483
|
return [...hosted, ...siblings];
|
|
21071
21484
|
}, [connectors, hosted, categories, hostPluginId]);
|
|
21072
|
-
|
|
21485
|
+
React65__default.useEffect(() => {
|
|
21073
21486
|
if (!selected || !connectors) return;
|
|
21074
21487
|
const fresh = connectors.find((c) => c.id === selected.id);
|
|
21075
21488
|
if (fresh && fresh !== selected) setSelected(fresh);
|
|
@@ -21081,7 +21494,7 @@ function ConnectorsHub({ hostPluginId }) {
|
|
|
21081
21494
|
const only = categories.length === 1 ? categoryLabel(categories[0]) : void 0;
|
|
21082
21495
|
const moreLabel = only ? t("connectors.viewCategory", { category: only }) : t("connectors.viewSimilar");
|
|
21083
21496
|
return /* @__PURE__ */ jsxs("div", { className: "max-w-3xl space-y-3", children: [
|
|
21084
|
-
/* @__PURE__ */ jsx("ul", { className: "divide-y divide-border overflow-hidden rounded-
|
|
21497
|
+
/* @__PURE__ */ jsx("ul", { className: "fayz-glass-surface divide-y divide-border overflow-hidden rounded-card border bg-card text-card-foreground shadow-sm", children: scoped.map((c) => /* @__PURE__ */ jsx(
|
|
21085
21498
|
ConnectorRow,
|
|
21086
21499
|
{
|
|
21087
21500
|
connector: c,
|
|
@@ -21141,7 +21554,7 @@ function ConnectorsHub({ hostPluginId }) {
|
|
|
21141
21554
|
] });
|
|
21142
21555
|
}
|
|
21143
21556
|
function HubSkeleton() {
|
|
21144
|
-
return /* @__PURE__ */ jsx("div", { className: "max-w-3xl", "aria-hidden": true, children: /* @__PURE__ */ jsx("ul", { className: "divide-y divide-border overflow-hidden rounded-
|
|
21557
|
+
return /* @__PURE__ */ jsx("div", { className: "max-w-3xl", "aria-hidden": true, children: /* @__PURE__ */ jsx("ul", { className: "fayz-glass-surface divide-y divide-border overflow-hidden rounded-card border bg-card text-card-foreground shadow-sm", children: [0, 1].map((i) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-4 p-4", children: [
|
|
21145
21558
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-10 shrink-0 rounded-lg" }),
|
|
21146
21559
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-2 py-0.5", children: [
|
|
21147
21560
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-44" }),
|
|
@@ -21150,7 +21563,7 @@ function HubSkeleton() {
|
|
|
21150
21563
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24 shrink-0" })
|
|
21151
21564
|
] }, i)) }) });
|
|
21152
21565
|
}
|
|
21153
|
-
function RegistryCrudView2({ registry: registry3, basePath }) {
|
|
21566
|
+
function RegistryCrudView2({ registry: registry3, basePath, embedded }) {
|
|
21154
21567
|
const useStore = useMemo(() => {
|
|
21155
21568
|
const mockData = registry3.mockData ?? registry3.seedData ?? [];
|
|
21156
21569
|
const provider = registry3.dataProvider ?? resolveDataProvider(registry3.entity, mockData);
|
|
@@ -21163,7 +21576,8 @@ function RegistryCrudView2({ registry: registry3, basePath }) {
|
|
|
21163
21576
|
useStore,
|
|
21164
21577
|
basePath,
|
|
21165
21578
|
display: registry3.display === "cards" ? "cards" : "table",
|
|
21166
|
-
readOnly: registry3.readOnly
|
|
21579
|
+
readOnly: registry3.readOnly,
|
|
21580
|
+
embedded
|
|
21167
21581
|
}
|
|
21168
21582
|
);
|
|
21169
21583
|
}
|
|
@@ -21183,7 +21597,7 @@ function PropertiesTab({ registries, routeBase, regLabel }) {
|
|
|
21183
21597
|
return registries[0]?.id ?? "";
|
|
21184
21598
|
}
|
|
21185
21599
|
const [active2, setActive] = useState(getActive);
|
|
21186
|
-
|
|
21600
|
+
React65__default.useEffect(() => {
|
|
21187
21601
|
const handler = () => setActive(getActive());
|
|
21188
21602
|
window.addEventListener("hashchange", handler);
|
|
21189
21603
|
return () => window.removeEventListener("hashchange", handler);
|
|
@@ -21258,7 +21672,7 @@ function PluginSettingsPanel({ title, subtitle, generalSettings, registries, cus
|
|
|
21258
21672
|
return tabs[0]?.id ?? "";
|
|
21259
21673
|
}
|
|
21260
21674
|
const [activeTab, setActiveTab] = useState(getActiveFromHash);
|
|
21261
|
-
|
|
21675
|
+
React65__default.useEffect(() => {
|
|
21262
21676
|
const handler = () => setActiveTab(getActiveFromHash());
|
|
21263
21677
|
window.addEventListener("hashchange", handler);
|
|
21264
21678
|
return () => window.removeEventListener("hashchange", handler);
|
|
@@ -21306,6 +21720,6 @@ var renderApp = (...args) => {
|
|
|
21306
21720
|
return renderApp$1(...args);
|
|
21307
21721
|
};
|
|
21308
21722
|
|
|
21309
|
-
export { AddConnectorButton, AddConnectorPanel, AdminProviders, AdminScaffold, AdminShell, AssistantInvite, ChatConversation, ClientOrdersTab, ConnectConsentPage, ConnectorDeliveries, ConnectorDetail, ConnectorMark, ConnectorRow, ConnectorSyncActions, ConnectorsHub, ConnectorsTab, ContactPicker, CredentialSinkMissingError, CrudCardGrid, CrudDetailPage, CrudDetailSkeleton, CrudFormPage, CrudFormSkeleton, CrudListView, CrudPage, CrudRecordModal, DeleteConfirmDialog, EntitlementGate, EntityLink, LimitGate, ModuleActionBar, MultiSelectRow, NOTE_LABEL_PREFIX, OrderDetailBlock, OrderDetailRow, OrderDetailSkeleton, OrderDetailView, OrderFormAddItemStep, OrderDetailBlock as OrderFormBlock, OrderFormItemRow, OrderFormItemsCard, OrderFormSkeleton, OrderFormView, OrderListView, PermissionGate, PersonLink2 as PersonLink, PersonTimeline, PluginRegistryManager, PluginSettingsPanel, ProjectsSettings, QuickActionsButton, RecordPickerModal, RegistryCrudView2 as RegistryCrudView, RouteErrorBoundary, RouteErrorScreen, SelectRow, SettingsGroup, SeuSiteWidget, StateChip, TextRow, ToggleRow, UpgradePrompt, WidgetSlot, navigateTo as adminNavigateTo, categoryLabel, connectorRoute, createArchetypeLookup, createClientOrdersProvider, createCrudPage, createFayzApp, createFayzProject, createCrudPage as createNativeCrudPage, createPerson, createPlaceholder, createPluginContext, createViewRouter, dedup, defaultProjectOf, defineSaas, deleteFayzProject, deriveAgentContract, exportToCSV, filterConnectors, formatActivityElapsed, formatCurrency4 as formatCurrency, getDefaultFayzProject, getFayzAgentClient, getPersonPath, getTimelineSources, listFayzProjects, needsCredentialSink, openAssistant, openConnectorsPanel, openEntity, parseViewId, publishAssistantActivity, registerAdminScaffold, registerAssistantLauncher, registerEntityPath, registerNotesTasksAdapter, registerTimelineSource, renderApp, resolveEntityAnchor, resolveEntityHref, resolveFayzAgentConnection, splitConnectorValues, submitConnection, unregisterAssistantLauncher, unregisterTimelineSource, updateFayzProject, useAdminPath, useAgentSurface, useAssistantActivity, useAssistantInviteStore, useAssistantLaunchers, useChatStore, useConnectors, useConnectorsPanelAvailable, useContextualNav, useContextualNavStore, useDelegateToAssistant, useFayzProjectsStore, useFieldRules, useHasRightRail, useModuleNavigation, useNavContribution, useNavContributionsStore, useNotesTasksBridge, usePersonTimeline, usePluginPrefs, usePublishAssistantActivity, useRegisterAssistantLauncher, useRightRailPanel, useRightRailStore, useShellRailAvailable, useTenantPluginSettings, withdrawAssistantActivity };
|
|
21723
|
+
export { AddConnectorButton, AddConnectorPanel, AdminProviders, AdminScaffold, AdminShell, AssistantInvite, ChatConversation, ClientOrdersTab, ConnectConsentPage, ConnectorDeliveries, ConnectorDetail, ConnectorMark, ConnectorRow, ConnectorSyncActions, ConnectorsHub, ConnectorsTab, ContactPicker, CredentialSinkMissingError, CrudCardGrid, CrudDetailPage, CrudDetailSkeleton, CrudFormPage, CrudFormSkeleton, CrudListView, CrudPage, CrudRecordModal, DeleteConfirmDialog, EntitlementGate, EntityLink, LimitGate, ModuleActionBar, MultiSelectRow, NOTE_LABEL_PREFIX, OrderDetailBlock, OrderDetailRow, OrderDetailSkeleton, OrderDetailView, OrderFormAddItemStep, OrderDetailBlock as OrderFormBlock, OrderFormItemRow, OrderFormItemsCard, OrderFormSkeleton, OrderFormView, OrderListView, PermissionGate, PersonLink2 as PersonLink, PersonTimeline, PluginRegistryManager, PluginSettingsPanel, ProjectsSettings, QuickActionsButton, RecordPickerModal, RegistryCrudView2 as RegistryCrudView, RouteErrorBoundary, RouteErrorScreen, SelectRow, SettingsGroup, SeuSiteWidget, StateChip, TextRow, ToggleRow, UpgradePrompt, WidgetSlot, navigateTo as adminNavigateTo, categoryLabel, connectorRoute, createArchetypeLookup, createClientOrdersProvider, createCrudPage, createFayzApp, createFayzProject, createCrudPage as createNativeCrudPage, createPerson, createPlaceholder, createPluginContext, createViewRouter, dedup, defaultProjectOf, defineSaas, deleteFayzProject, deriveAgentContract, exportToCSV, filterConnectors, formatActivityElapsed, formatCurrency4 as formatCurrency, getDefaultFayzProject, getFayzAgentClient, getPersonLookup, getPersonPath, getTimelineSources, listFayzProjects, needsCredentialSink, openAssistant, openConnectorsPanel, openEntity, parseViewId, publishAssistantActivity, registerAdminScaffold, registerAssistantLauncher, registerEntityPath, registerNotesTasksAdapter, registerPersonLookup, registerTimelineSource, renderApp, resolveEntityAnchor, resolveEntityHref, resolveFayzAgentConnection, splitConnectorValues, submitConnection, unregisterAssistantLauncher, unregisterTimelineSource, updateFayzProject, useAdminPath, useAgentSurface, useAssistantActivity, useAssistantInviteStore, useAssistantLaunchers, useChatStore, useConnectors, useConnectorsPanelAvailable, useContextualNav, useContextualNavStore, useDelegateToAssistant, useFayzProjectsStore, useFieldRules, useHasRightRail, useModuleNavigation, useNavContribution, useNavContributionsStore, useNotesTasksBridge, usePersonTimeline, usePluginPrefs, usePublishAssistantActivity, useRegisterAssistantLauncher, useRightRailPanel, useRightRailStore, useShellRailAvailable, useTenantPluginSettings, useWidgetSurface, withdrawAssistantActivity };
|
|
21310
21724
|
//# sourceMappingURL=index.js.map
|
|
21311
21725
|
//# sourceMappingURL=index.js.map
|