@fayz-ai/admin 0.12.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/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/{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.map +1 -1
- 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/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/crud/CrudDetailPage.d.ts.map +1 -1
- package/dist/crud/CrudListView.d.ts +10 -2
- 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 +9 -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/useModuleNavigation.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +774 -639
- package/dist/index.js.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/types/entity-lookup.d.ts +9 -0
- package/dist/types/entity-lookup.d.ts.map +1 -1
- package/package.json +8 -8
- 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, cn as cn$1, checkAccess, guardLimit, featureDisplayName, PlanFeatureItem, useAccessOptional, AccessProvider, CORE_LIMIT_DECLARATIONS, entityDerivedLimitDeclarations, getPlanEntitlements, resolvePlanCurrency } from './chunk-
|
|
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,16 +11,16 @@ 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
|
|
14
|
+
import * as React65 from 'react';
|
|
15
|
+
import React65__default, { createContext, useMemo, useState, useRef, useCallback, useEffect, useContext } from 'react';
|
|
16
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, RefreshButton,
|
|
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, Download, ChevronLeft, ChevronRight, AlertTriangle, Pencil, Inbox, Package, X, Sparkles, Plug, Loader2, ArrowDownToLine, ArrowUpFromLine, CheckCircle2, Crown, ArrowRight, ArrowLeft, SquarePen, Settings2, MessageSquare, RotateCcw, Copy, ChevronsUpDown, ExternalLink, PenSquare, RefreshCw,
|
|
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';
|
|
@@ -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]);
|
|
@@ -1046,7 +1046,7 @@ function AssistantInvite({ className, ...def }) {
|
|
|
1046
1046
|
const { id, persona, headline, pitch, description, placeholder, auto } = def;
|
|
1047
1047
|
const suggestions = def.suggestions;
|
|
1048
1048
|
const suggestionKey = JSON.stringify(suggestions ?? []);
|
|
1049
|
-
|
|
1049
|
+
React65.useEffect(() => {
|
|
1050
1050
|
if (!hasAssistant) return;
|
|
1051
1051
|
setInvite({
|
|
1052
1052
|
id,
|
|
@@ -1060,11 +1060,11 @@ function AssistantInvite({ className, ...def }) {
|
|
|
1060
1060
|
});
|
|
1061
1061
|
return () => setInvite(null, id);
|
|
1062
1062
|
}, [hasAssistant, id, persona, headline, pitch, description, placeholder, auto, suggestionKey, setInvite]);
|
|
1063
|
-
const anchorRef =
|
|
1064
|
-
const [box, setBox] =
|
|
1063
|
+
const anchorRef = React65.useRef(null);
|
|
1064
|
+
const [box, setBox] = React65.useState(null);
|
|
1065
1065
|
const docked = stage === "dock" && !railOpen && hasAssistant;
|
|
1066
1066
|
const showing = hasAssistant && (stage === "hero" || docked);
|
|
1067
|
-
|
|
1067
|
+
React65.useEffect(() => {
|
|
1068
1068
|
if (!showing) return;
|
|
1069
1069
|
const el = anchorRef.current;
|
|
1070
1070
|
if (!el) return;
|
|
@@ -1085,7 +1085,7 @@ function AssistantInvite({ className, ...def }) {
|
|
|
1085
1085
|
}, [showing]);
|
|
1086
1086
|
const setDockBox = useAssistantInviteStore((s) => s.setDockBox);
|
|
1087
1087
|
const wide = useWideViewport();
|
|
1088
|
-
|
|
1088
|
+
React65.useEffect(() => {
|
|
1089
1089
|
if (!docked || !wide || !box) {
|
|
1090
1090
|
setDockBox(null);
|
|
1091
1091
|
return;
|
|
@@ -1099,7 +1099,7 @@ function AssistantInvite({ className, ...def }) {
|
|
|
1099
1099
|
function useAsk() {
|
|
1100
1100
|
const queuePrompt = useChatStore((s) => s.queuePrompt);
|
|
1101
1101
|
const dismiss = useAssistantInviteStore((s) => s.dismiss);
|
|
1102
|
-
return
|
|
1102
|
+
return React65.useCallback(
|
|
1103
1103
|
(text) => {
|
|
1104
1104
|
const trimmed = text.trim();
|
|
1105
1105
|
if (!trimmed) return;
|
|
@@ -1117,9 +1117,9 @@ function InviteHero({
|
|
|
1117
1117
|
const { t } = useTranslation$1();
|
|
1118
1118
|
const user = useAuthStore((s) => s.user);
|
|
1119
1119
|
const ask = useAsk();
|
|
1120
|
-
const [draft, setDraft] =
|
|
1120
|
+
const [draft, setDraft] = React65.useState("");
|
|
1121
1121
|
const name = (user?.fullName || user?.email || "").split(/[\s@]/)[0];
|
|
1122
|
-
|
|
1122
|
+
React65.useEffect(() => {
|
|
1123
1123
|
const onKey = (event) => {
|
|
1124
1124
|
if (event.key === "Escape") onDismiss();
|
|
1125
1125
|
};
|
|
@@ -1181,8 +1181,8 @@ function InviteHero({
|
|
|
1181
1181
|
);
|
|
1182
1182
|
}
|
|
1183
1183
|
function useMorphIn(skip = false) {
|
|
1184
|
-
const [entered, setEntered] =
|
|
1185
|
-
|
|
1184
|
+
const [entered, setEntered] = React65.useState(() => skip || prefersReducedMotion());
|
|
1185
|
+
React65.useEffect(() => {
|
|
1186
1186
|
if (entered) return;
|
|
1187
1187
|
let second = 0;
|
|
1188
1188
|
const first = requestAnimationFrame(() => {
|
|
@@ -1201,10 +1201,10 @@ function prefersReducedMotion() {
|
|
|
1201
1201
|
var lastDockExit = null;
|
|
1202
1202
|
var RESUME_WINDOW_MS = 700;
|
|
1203
1203
|
function useWideViewport() {
|
|
1204
|
-
const [wide, setWide] =
|
|
1204
|
+
const [wide, setWide] = React65.useState(
|
|
1205
1205
|
() => typeof window !== "undefined" && !!window.matchMedia?.("(min-width: 768px)").matches
|
|
1206
1206
|
);
|
|
1207
|
-
|
|
1207
|
+
React65.useEffect(() => {
|
|
1208
1208
|
const query = window.matchMedia?.("(min-width: 768px)");
|
|
1209
1209
|
if (!query) return;
|
|
1210
1210
|
const sync = () => setWide(query.matches);
|
|
@@ -1235,16 +1235,22 @@ function InviteDock({ def, left, maxWidth }) {
|
|
|
1235
1235
|
const setOpen = useChatStore((s) => s.setOpen);
|
|
1236
1236
|
const railOpen = useRightRailStore((s) => s.open);
|
|
1237
1237
|
const railWidth = useRightRailStore((s) => s.width);
|
|
1238
|
-
const [draft, setDraft] =
|
|
1239
|
-
const resumed =
|
|
1238
|
+
const [draft, setDraft] = React65.useState("");
|
|
1239
|
+
const resumed = React65.useRef(
|
|
1240
1240
|
!!lastDockExit && lastDockExit.id === def.id && Date.now() - lastDockExit.at < RESUME_WINDOW_MS
|
|
1241
1241
|
).current;
|
|
1242
|
-
|
|
1242
|
+
React65.useEffect(() => () => {
|
|
1243
1243
|
lastDockExit = { id: def.id, at: Date.now() };
|
|
1244
1244
|
}, [def.id]);
|
|
1245
1245
|
const entered = useMorphIn(resumed);
|
|
1246
1246
|
const width = Math.min(maxWidth, DOCK_MAX_WIDTH);
|
|
1247
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]);
|
|
1248
1254
|
return /* @__PURE__ */ jsx(
|
|
1249
1255
|
"div",
|
|
1250
1256
|
{
|
|
@@ -1255,7 +1261,8 @@ function InviteDock({ def, left, maxWidth }) {
|
|
|
1255
1261
|
// Arrives as the FAB and unrolls leftward into a composer. The circle it
|
|
1256
1262
|
// grows out of is the one that just disappeared from that exact spot.
|
|
1257
1263
|
...entered ? morph.open : morph.collapsed,
|
|
1258
|
-
transition: prefersReducedMotion() ? void 0 : morph.transition
|
|
1264
|
+
transition: prefersReducedMotion() ? void 0 : morph.transition,
|
|
1265
|
+
...settled ? { transform: "none", clipPath: "none", marginLeft: -width / 2 } : null
|
|
1259
1266
|
},
|
|
1260
1267
|
children: /* @__PURE__ */ jsx(
|
|
1261
1268
|
InviteComposer,
|
|
@@ -1373,7 +1380,7 @@ function MorphBackPill() {
|
|
|
1373
1380
|
const railWidth = useRightRailStore((s) => s.width);
|
|
1374
1381
|
const { t } = useTranslation$1();
|
|
1375
1382
|
const collapsed = useMorphIn();
|
|
1376
|
-
|
|
1383
|
+
React65.useEffect(() => {
|
|
1377
1384
|
if (prefersReducedMotion()) {
|
|
1378
1385
|
endLeave();
|
|
1379
1386
|
return;
|
|
@@ -1909,12 +1916,12 @@ function detectActivePluginId(runtime) {
|
|
|
1909
1916
|
function useAITools() {
|
|
1910
1917
|
const runtime = usePluginRuntimeOptional();
|
|
1911
1918
|
const access = useAccessOptional();
|
|
1912
|
-
const surfaceVersion =
|
|
1919
|
+
const surfaceVersion = React65.useSyncExternalStore(subscribeSurfaces, getSurfaceVersion, getSurfaceVersion);
|
|
1913
1920
|
const features = usePermissionsStore((s) => s.features);
|
|
1914
1921
|
const profiles = usePermissionsStore((s) => s.profiles);
|
|
1915
1922
|
const hasSystem = useSystemPermission();
|
|
1916
1923
|
const canManagePermissions = hasSystem("manage_permissions");
|
|
1917
|
-
return
|
|
1924
|
+
return React65.useMemo(() => {
|
|
1918
1925
|
const hasPermission = runtime?.context.hasPermission;
|
|
1919
1926
|
const can = access.can;
|
|
1920
1927
|
const verticalId = runtime?.context.tenant?.verticalId;
|
|
@@ -1997,8 +2004,8 @@ function navigateTo(to) {
|
|
|
1997
2004
|
adapter.navigate(normalizeAdminPath(to));
|
|
1998
2005
|
}
|
|
1999
2006
|
function useAdminPath() {
|
|
2000
|
-
const [path, setPath] =
|
|
2001
|
-
|
|
2007
|
+
const [path, setPath] = React65.useState(() => normalizeAdminPath(adapter.getCurrentPath() || "/"));
|
|
2008
|
+
React65.useEffect(() => {
|
|
2002
2009
|
return adapter.onPathChange((p) => {
|
|
2003
2010
|
setPath(normalizeAdminPath(p || "/"));
|
|
2004
2011
|
if (typeof window !== "undefined") window.scrollTo(0, 0);
|
|
@@ -3245,6 +3252,20 @@ async function executeRpcTool(rpcName, args, userId) {
|
|
|
3245
3252
|
|
|
3246
3253
|
// src/components/connect/connector-map.generated.ts
|
|
3247
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
|
+
},
|
|
3248
3269
|
{
|
|
3249
3270
|
slug: "abacatepay",
|
|
3250
3271
|
name: "AbacatePay",
|
|
@@ -3314,6 +3335,20 @@ var SDK_INTEGRATIONS = [
|
|
|
3314
3335
|
status: "soon",
|
|
3315
3336
|
declaredBy: { pluginId: "agenda", package: "@fayz-ai/plugin-agenda" }
|
|
3316
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
|
+
},
|
|
3317
3352
|
{
|
|
3318
3353
|
slug: "google-analytics",
|
|
3319
3354
|
name: "Google Analytics",
|
|
@@ -3382,6 +3417,34 @@ var SDK_INTEGRATIONS = [
|
|
|
3382
3417
|
status: "soon",
|
|
3383
3418
|
declaredBy: { pluginId: "crm", package: "@fayz-ai/plugin-crm" }
|
|
3384
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
|
+
},
|
|
3385
3448
|
{
|
|
3386
3449
|
slug: "kiwify",
|
|
3387
3450
|
name: "Kiwify",
|
|
@@ -3439,11 +3502,16 @@ var SDK_INTEGRATIONS = [
|
|
|
3439
3502
|
},
|
|
3440
3503
|
{
|
|
3441
3504
|
slug: "mercadopago",
|
|
3442
|
-
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",
|
|
3443
3508
|
logoUrl: "https://assets.fayz.ai/connectors/mercadopago.png",
|
|
3444
3509
|
category: "payments",
|
|
3510
|
+
direction: "inbound",
|
|
3511
|
+
planes: ["sync"],
|
|
3445
3512
|
moduleId: "financial",
|
|
3446
|
-
status: "
|
|
3513
|
+
status: "available",
|
|
3514
|
+
connectorId: "mercadopago",
|
|
3447
3515
|
declaredBy: { pluginId: "financial", package: "@fayz-ai/plugin-financial" }
|
|
3448
3516
|
},
|
|
3449
3517
|
{
|
|
@@ -3464,6 +3532,20 @@ var SDK_INTEGRATIONS = [
|
|
|
3464
3532
|
status: "soon",
|
|
3465
3533
|
declaredBy: { pluginId: "financial", package: "@fayz-ai/plugin-financial" }
|
|
3466
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
|
+
},
|
|
3467
3549
|
{
|
|
3468
3550
|
slug: "ranklayer",
|
|
3469
3551
|
name: "RankLayer",
|
|
@@ -3508,10 +3590,15 @@ var SDK_INTEGRATIONS = [
|
|
|
3508
3590
|
{
|
|
3509
3591
|
slug: "stone",
|
|
3510
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",
|
|
3511
3595
|
logoUrl: "https://assets.fayz.ai/connectors/stone.jpeg",
|
|
3512
3596
|
category: "payments",
|
|
3597
|
+
direction: "inbound",
|
|
3598
|
+
planes: ["sync"],
|
|
3513
3599
|
moduleId: "financial",
|
|
3514
|
-
status: "
|
|
3600
|
+
status: "available",
|
|
3601
|
+
connectorId: "stone",
|
|
3515
3602
|
declaredBy: { pluginId: "financial", package: "@fayz-ai/plugin-financial" }
|
|
3516
3603
|
},
|
|
3517
3604
|
{
|
|
@@ -3943,8 +4030,8 @@ function loadCatalog() {
|
|
|
3943
4030
|
return catalogPromise;
|
|
3944
4031
|
}
|
|
3945
4032
|
function useConnectorCatalog() {
|
|
3946
|
-
const [catalog, setCatalog] =
|
|
3947
|
-
|
|
4033
|
+
const [catalog, setCatalog] = React65__default.useState(null);
|
|
4034
|
+
React65__default.useEffect(() => {
|
|
3948
4035
|
let cancelled = false;
|
|
3949
4036
|
void loadCatalog().then((list) => {
|
|
3950
4037
|
if (!cancelled) setCatalog(list);
|
|
@@ -3968,7 +4055,7 @@ function refreshConnectors() {
|
|
|
3968
4055
|
_revisionListeners.forEach((listener) => listener());
|
|
3969
4056
|
}
|
|
3970
4057
|
function useConnectorsRevision() {
|
|
3971
|
-
return
|
|
4058
|
+
return React65__default.useSyncExternalStore(
|
|
3972
4059
|
(listener) => {
|
|
3973
4060
|
_revisionListeners.add(listener);
|
|
3974
4061
|
return () => _revisionListeners.delete(listener);
|
|
@@ -3987,11 +4074,11 @@ function loadGrants(key, fetcher) {
|
|
|
3987
4074
|
}
|
|
3988
4075
|
function useInstalledModuleIds() {
|
|
3989
4076
|
const runtime = usePluginRuntimeOptional();
|
|
3990
|
-
return
|
|
4077
|
+
return React65__default.useMemo(() => (runtime?.plugins ?? []).map((p) => p.id), [runtime]);
|
|
3991
4078
|
}
|
|
3992
4079
|
function useInstalledDefinitions(hostPluginId) {
|
|
3993
4080
|
const runtime = usePluginRuntimeOptional();
|
|
3994
|
-
return
|
|
4081
|
+
return React65__default.useMemo(() => {
|
|
3995
4082
|
const byHost = runtime?.connectorsByHost;
|
|
3996
4083
|
if (!byHost) return [];
|
|
3997
4084
|
if (hostPluginId) return byHost.get(hostPluginId) ?? [];
|
|
@@ -4004,12 +4091,12 @@ function useConnectors(options = {}) {
|
|
|
4004
4091
|
const catalog = useConnectorCatalog();
|
|
4005
4092
|
const tenant = useTenantOptional();
|
|
4006
4093
|
const tenantId2 = tenant?.org?.id;
|
|
4007
|
-
const connection =
|
|
4008
|
-
const [installed, setInstalled] =
|
|
4009
|
-
const [grants, setGrants] =
|
|
4010
|
-
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);
|
|
4011
4098
|
const nonce = useConnectorsRevision();
|
|
4012
|
-
const call =
|
|
4099
|
+
const call = React65__default.useCallback(
|
|
4013
4100
|
async (path, init) => {
|
|
4014
4101
|
if (!connection) throw new Error("Este app n\xE3o est\xE1 ligado a um projeto Fayz.");
|
|
4015
4102
|
const supabase = getFayzSupabaseClientOptional();
|
|
@@ -4029,7 +4116,7 @@ function useConnectors(options = {}) {
|
|
|
4029
4116
|
},
|
|
4030
4117
|
[connection]
|
|
4031
4118
|
);
|
|
4032
|
-
|
|
4119
|
+
React65__default.useEffect(() => {
|
|
4033
4120
|
let cancelled = false;
|
|
4034
4121
|
void loadConnectorStatuses(definitions, tenantId2).then((list) => {
|
|
4035
4122
|
if (!cancelled) setInstalled(list);
|
|
@@ -4038,7 +4125,7 @@ function useConnectors(options = {}) {
|
|
|
4038
4125
|
cancelled = true;
|
|
4039
4126
|
};
|
|
4040
4127
|
}, [definitions, tenantId2, nonce]);
|
|
4041
|
-
|
|
4128
|
+
React65__default.useEffect(() => {
|
|
4042
4129
|
if (!includeGrants || !connection || !tenantId2) {
|
|
4043
4130
|
setGrants(includeGrants ? null : []);
|
|
4044
4131
|
return;
|
|
@@ -4062,7 +4149,7 @@ function useConnectors(options = {}) {
|
|
|
4062
4149
|
cancelled = true;
|
|
4063
4150
|
};
|
|
4064
4151
|
}, [call, tenantId2, includeGrants, connection, nonce]);
|
|
4065
|
-
const revokeGrant =
|
|
4152
|
+
const revokeGrant = React65__default.useCallback(
|
|
4066
4153
|
async (connector) => {
|
|
4067
4154
|
const response = await call(`/${connector.id}`, { method: "DELETE" });
|
|
4068
4155
|
if (!response.ok) {
|
|
@@ -4075,7 +4162,7 @@ function useConnectors(options = {}) {
|
|
|
4075
4162
|
[call]
|
|
4076
4163
|
);
|
|
4077
4164
|
const waitingGrants = includeGrants && !!connection && !!tenantId2 && grants === null;
|
|
4078
|
-
const connectors =
|
|
4165
|
+
const connectors = React65__default.useMemo(() => {
|
|
4079
4166
|
if (installed === null || waitingGrants) return null;
|
|
4080
4167
|
return buildConnectorList({
|
|
4081
4168
|
installed,
|
|
@@ -4744,9 +4831,9 @@ function prefersReducedMotion2() {
|
|
|
4744
4831
|
return typeof window !== "undefined" && !!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
4745
4832
|
}
|
|
4746
4833
|
function TypewriterText({ text, speed = 26, onDone }) {
|
|
4747
|
-
const [displayed, setDisplayed] =
|
|
4748
|
-
const indexRef =
|
|
4749
|
-
|
|
4834
|
+
const [displayed, setDisplayed] = React65.useState("");
|
|
4835
|
+
const indexRef = React65.useRef(0);
|
|
4836
|
+
React65.useEffect(() => {
|
|
4750
4837
|
if (prefersReducedMotion2()) {
|
|
4751
4838
|
setDisplayed(text);
|
|
4752
4839
|
onDone?.();
|
|
@@ -4830,11 +4917,11 @@ function ChatFab({ className, apiEndpoint, systemPrompt, agent, voice, mobile })
|
|
|
4830
4917
|
const { contextualSuggestions } = useAITools();
|
|
4831
4918
|
const { sendMessage } = useChat({ apiEndpoint, systemPrompt, agent });
|
|
4832
4919
|
const { t } = useTranslation$1();
|
|
4833
|
-
const [phase, setPhase] =
|
|
4834
|
-
const [activeSuggestion, setActiveSuggestion] =
|
|
4835
|
-
const timersRef =
|
|
4836
|
-
const prevSuggestionRef =
|
|
4837
|
-
|
|
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, []);
|
|
4838
4925
|
const clearTimers = () => {
|
|
4839
4926
|
timersRef.current.forEach(clearTimeout);
|
|
4840
4927
|
timersRef.current = [];
|
|
@@ -4846,10 +4933,10 @@ function ChatFab({ className, apiEndpoint, systemPrompt, agent, voice, mobile })
|
|
|
4846
4933
|
const topLabel = topSuggestion?.label ?? null;
|
|
4847
4934
|
const invited = useAssistantInviteStore((s) => !!s.invite && s.stage === "dock");
|
|
4848
4935
|
const morphingBack = useAssistantInviteStore((s) => !!s.leaving);
|
|
4849
|
-
const [wide, setWide] =
|
|
4936
|
+
const [wide, setWide] = React65.useState(
|
|
4850
4937
|
() => typeof window !== "undefined" && !!window.matchMedia?.("(min-width: 768px)").matches
|
|
4851
4938
|
);
|
|
4852
|
-
|
|
4939
|
+
React65.useEffect(() => {
|
|
4853
4940
|
const query = window.matchMedia?.("(min-width: 768px)");
|
|
4854
4941
|
if (!query) return;
|
|
4855
4942
|
const sync = () => setWide(query.matches);
|
|
@@ -4858,7 +4945,7 @@ function ChatFab({ className, apiEndpoint, systemPrompt, agent, voice, mobile })
|
|
|
4858
4945
|
return () => query.removeEventListener("change", sync);
|
|
4859
4946
|
}, []);
|
|
4860
4947
|
const teaserAllowed = !hasMessages && !activity && !invited && !teaserDismissed() && teaserShownCount() < TEASER_MAX_PER_SESSION;
|
|
4861
|
-
|
|
4948
|
+
React65.useEffect(() => {
|
|
4862
4949
|
if (expanded || !topSuggestion || !topLabel || !teaserAllowed || teaserSeen().includes(topLabel)) {
|
|
4863
4950
|
if (phase !== "idle") {
|
|
4864
4951
|
clearTimers();
|
|
@@ -4889,14 +4976,14 @@ function ChatFab({ className, apiEndpoint, systemPrompt, agent, voice, mobile })
|
|
|
4889
4976
|
}, 9e3);
|
|
4890
4977
|
return clearTimers;
|
|
4891
4978
|
}, [topLabel, expanded, teaserAllowed]);
|
|
4892
|
-
|
|
4979
|
+
React65.useEffect(() => {
|
|
4893
4980
|
if (expanded && phase !== "idle") {
|
|
4894
4981
|
clearTimers();
|
|
4895
4982
|
setPhase("idle");
|
|
4896
4983
|
}
|
|
4897
4984
|
}, [expanded]);
|
|
4898
|
-
const [entrance, setEntrance] =
|
|
4899
|
-
|
|
4985
|
+
const [entrance, setEntrance] = React65.useState("pending");
|
|
4986
|
+
React65.useEffect(() => {
|
|
4900
4987
|
if (!currentOrg || entrance !== "pending") return;
|
|
4901
4988
|
if (prefersReducedMotion2()) {
|
|
4902
4989
|
setEntrance("done");
|
|
@@ -4906,9 +4993,9 @@ function ChatFab({ className, apiEndpoint, systemPrompt, agent, voice, mobile })
|
|
|
4906
4993
|
const timer = setTimeout(() => setEntrance("done"), 1600);
|
|
4907
4994
|
return () => clearTimeout(timer);
|
|
4908
4995
|
}, [currentOrg, entrance]);
|
|
4909
|
-
const [poppingBack, setPoppingBack] =
|
|
4910
|
-
const wasMorphing =
|
|
4911
|
-
|
|
4996
|
+
const [poppingBack, setPoppingBack] = React65.useState(false);
|
|
4997
|
+
const wasMorphing = React65.useRef(false);
|
|
4998
|
+
React65.useEffect(() => {
|
|
4912
4999
|
const was = wasMorphing.current;
|
|
4913
5000
|
wasMorphing.current = morphingBack;
|
|
4914
5001
|
if (!was || morphingBack || prefersReducedMotion2()) return;
|
|
@@ -5148,7 +5235,7 @@ function ChatFab({ className, apiEndpoint, systemPrompt, agent, voice, mobile })
|
|
|
5148
5235
|
var MAX_SUGGESTIONS = 5;
|
|
5149
5236
|
function ChatSuggestions({ suggestions, onSelect, onDismiss, compact }) {
|
|
5150
5237
|
const { t } = useTranslation$1();
|
|
5151
|
-
const [open, setOpen] =
|
|
5238
|
+
const [open, setOpen] = React65.useState(true);
|
|
5152
5239
|
const visible = suggestions.slice(0, compact ? 3 : MAX_SUGGESTIONS);
|
|
5153
5240
|
if (!visible.length) return null;
|
|
5154
5241
|
return /* @__PURE__ */ jsxs(
|
|
@@ -5227,8 +5314,8 @@ function SuggestionRow({
|
|
|
5227
5314
|
detail,
|
|
5228
5315
|
onSelect
|
|
5229
5316
|
}) {
|
|
5230
|
-
const labelRef =
|
|
5231
|
-
const [showDetail, setShowDetail] =
|
|
5317
|
+
const labelRef = React65.useRef(null);
|
|
5318
|
+
const [showDetail, setShowDetail] = React65.useState(false);
|
|
5232
5319
|
const evaluate = () => {
|
|
5233
5320
|
const el = labelRef.current;
|
|
5234
5321
|
const clipped = !!el && el.scrollWidth > el.clientWidth + 1;
|
|
@@ -5318,8 +5405,8 @@ function ChatToolsPanel({ toolGroups, onClose }) {
|
|
|
5318
5405
|
}
|
|
5319
5406
|
function AutoApprovalsSection() {
|
|
5320
5407
|
const { t } = useTranslation$1();
|
|
5321
|
-
const [rules, setRules] =
|
|
5322
|
-
|
|
5408
|
+
const [rules, setRules] = React65.useState(() => listAutoApprovals());
|
|
5409
|
+
React65.useEffect(() => subscribeAutoApprovals(() => setRules(listAutoApprovals())), []);
|
|
5323
5410
|
if (!rules.length) return null;
|
|
5324
5411
|
return /* @__PURE__ */ jsxs("div", { className: "border-b border-border/40 px-3 py-2.5", children: [
|
|
5325
5412
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-1 pb-1.5", children: [
|
|
@@ -5386,9 +5473,9 @@ function ConnectorMark({
|
|
|
5386
5473
|
connector,
|
|
5387
5474
|
size = "md"
|
|
5388
5475
|
}) {
|
|
5389
|
-
const candidates =
|
|
5390
|
-
const [attempt, setAttempt] =
|
|
5391
|
-
|
|
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]);
|
|
5392
5479
|
const box = size === "sm" ? "h-9 w-9" : "h-10 w-10";
|
|
5393
5480
|
const glyph = size === "sm" ? "h-4 w-4" : "h-5 w-5";
|
|
5394
5481
|
if (connector.builtIn) {
|
|
@@ -5658,15 +5745,15 @@ function ConnectorSyncActions({
|
|
|
5658
5745
|
actions,
|
|
5659
5746
|
onRan
|
|
5660
5747
|
}) {
|
|
5661
|
-
const [running, setRunning] =
|
|
5662
|
-
const [open, setOpen] =
|
|
5663
|
-
const [pending, setPending] =
|
|
5664
|
-
const [hidden, setHidden] =
|
|
5665
|
-
const [queued, setQueued] =
|
|
5666
|
-
const [nonce, setNonce] =
|
|
5667
|
-
const [expanded, setExpanded] =
|
|
5668
|
-
const [resolved, setResolved] =
|
|
5669
|
-
|
|
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(() => {
|
|
5670
5757
|
let cancelled = false;
|
|
5671
5758
|
setResolved(false);
|
|
5672
5759
|
void Promise.all(
|
|
@@ -5851,10 +5938,10 @@ function formatRelative(iso, t) {
|
|
|
5851
5938
|
}
|
|
5852
5939
|
function useConnectorRuns(connector) {
|
|
5853
5940
|
const listRuns = connector.definition?.listRuns;
|
|
5854
|
-
const [runs, setRuns] =
|
|
5855
|
-
const [loading, setLoading] =
|
|
5856
|
-
const [nonce, setNonce] =
|
|
5857
|
-
|
|
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(() => {
|
|
5858
5945
|
if (!listRuns) {
|
|
5859
5946
|
setRuns([]);
|
|
5860
5947
|
setLoading(false);
|
|
@@ -5876,7 +5963,7 @@ function useConnectorRuns(connector) {
|
|
|
5876
5963
|
return {
|
|
5877
5964
|
runs,
|
|
5878
5965
|
loading,
|
|
5879
|
-
reload:
|
|
5966
|
+
reload: React65__default.useCallback(() => setNonce((n) => n + 1), []),
|
|
5880
5967
|
failing: isFailing(runs)
|
|
5881
5968
|
};
|
|
5882
5969
|
}
|
|
@@ -6088,13 +6175,13 @@ function ConnectorSettingsPanel({
|
|
|
6088
6175
|
const { t } = useTranslation$1();
|
|
6089
6176
|
const def = connector.definition;
|
|
6090
6177
|
const settings = def ? connectorSettings(def) : [];
|
|
6091
|
-
const [values, setValues] =
|
|
6178
|
+
const [values, setValues] = React65__default.useState(
|
|
6092
6179
|
() => initialValues(settings, {})
|
|
6093
6180
|
);
|
|
6094
|
-
const [loaded, setLoaded] =
|
|
6095
|
-
const [saving, setSaving] =
|
|
6096
|
-
const [dirty, setDirty] =
|
|
6097
|
-
|
|
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(() => {
|
|
6098
6185
|
if (settings.length === 0 || !def?.getSettings) return;
|
|
6099
6186
|
let cancelled = false;
|
|
6100
6187
|
setLoaded(false);
|
|
@@ -6345,13 +6432,13 @@ function ConnectorInstall({
|
|
|
6345
6432
|
}) {
|
|
6346
6433
|
const { t } = useTranslation$1();
|
|
6347
6434
|
const def = connector.definition;
|
|
6348
|
-
const [plane, setPlane] =
|
|
6435
|
+
const [plane, setPlane] = React65__default.useState(
|
|
6349
6436
|
connector.planes.includes("agentic") ? "agentic" : connector.planes[0]
|
|
6350
6437
|
);
|
|
6351
|
-
const [values, setValues] =
|
|
6352
|
-
const secrets =
|
|
6353
|
-
const [busy, setBusy] =
|
|
6354
|
-
|
|
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(() => {
|
|
6355
6442
|
setValues({});
|
|
6356
6443
|
secrets.current = {};
|
|
6357
6444
|
setBusy(null);
|
|
@@ -6392,13 +6479,13 @@ function ConnectorHome({
|
|
|
6392
6479
|
const needsSetup = connector.state === "needs_setup";
|
|
6393
6480
|
const settingsAvailable = hasOperatingSettings(connector);
|
|
6394
6481
|
const runsAvailable = hasRunHistory(connector);
|
|
6395
|
-
const [tab, setTab] =
|
|
6482
|
+
const [tab, setTab] = React65__default.useState(
|
|
6396
6483
|
needsSetup && settingsAvailable ? "settings" : "overview"
|
|
6397
6484
|
);
|
|
6398
|
-
const [busy, setBusy] =
|
|
6485
|
+
const [busy, setBusy] = React65__default.useState(null);
|
|
6399
6486
|
const run = useRunner(setBusy, onChanged);
|
|
6400
6487
|
const runs = useConnectorRuns(connector);
|
|
6401
|
-
|
|
6488
|
+
React65__default.useEffect(() => {
|
|
6402
6489
|
setTab(needsSetup && settingsAvailable ? "settings" : "overview");
|
|
6403
6490
|
setBusy(null);
|
|
6404
6491
|
}, [connector.id]);
|
|
@@ -6475,7 +6562,7 @@ function ConnectorHome({
|
|
|
6475
6562
|
}
|
|
6476
6563
|
function useRunner(setBusy, onChanged) {
|
|
6477
6564
|
const { t } = useTranslation$1();
|
|
6478
|
-
return
|
|
6565
|
+
return React65__default.useCallback(
|
|
6479
6566
|
async (kind, fn, okMessage) => {
|
|
6480
6567
|
setBusy(kind);
|
|
6481
6568
|
try {
|
|
@@ -6584,7 +6671,7 @@ function ConnectPanel({
|
|
|
6584
6671
|
const tenantId2 = useTenantOptional()?.org?.id;
|
|
6585
6672
|
const needsSink = needsCredentialSink(def);
|
|
6586
6673
|
const sinkMissing = needsSink && !getConnectorCredentialSink();
|
|
6587
|
-
const [formKey, setFormKey] =
|
|
6674
|
+
const [formKey, setFormKey] = React65__default.useState(0);
|
|
6588
6675
|
if (def.authKind === "oauth") {
|
|
6589
6676
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
6590
6677
|
/* @__PURE__ */ jsx(Note, { children: t("connectors.authorize.oauthOnly") }),
|
|
@@ -6716,7 +6803,7 @@ function GrantRevoke({
|
|
|
6716
6803
|
onRevoke
|
|
6717
6804
|
}) {
|
|
6718
6805
|
const { t } = useTranslation$1();
|
|
6719
|
-
const [revoking, setRevoking] =
|
|
6806
|
+
const [revoking, setRevoking] = React65__default.useState(false);
|
|
6720
6807
|
if (connector.revocable === false) {
|
|
6721
6808
|
return /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("connectors.partOfApp") });
|
|
6722
6809
|
}
|
|
@@ -6755,13 +6842,13 @@ function ConnectorsPanel({ onClose }) {
|
|
|
6755
6842
|
const { connectors, reload, revokeGrant, agentAvailable, tenantReady } = useConnectors();
|
|
6756
6843
|
const selectedId = useConnectorsSurface((s) => s.selected);
|
|
6757
6844
|
const select = useConnectorsSurface((s) => s.select);
|
|
6758
|
-
const [query, setQuery] =
|
|
6759
|
-
const [failure, setFailure] =
|
|
6760
|
-
const selected =
|
|
6845
|
+
const [query, setQuery] = React65__default.useState("");
|
|
6846
|
+
const [failure, setFailure] = React65__default.useState(null);
|
|
6847
|
+
const selected = React65__default.useMemo(
|
|
6761
6848
|
() => (connectors ?? []).find((c) => c.id === selectedId) ?? null,
|
|
6762
6849
|
[connectors, selectedId]
|
|
6763
6850
|
);
|
|
6764
|
-
const filtered =
|
|
6851
|
+
const filtered = React65__default.useMemo(
|
|
6765
6852
|
() => filterConnectors(connectors ?? [], "outbound", query),
|
|
6766
6853
|
[connectors, query]
|
|
6767
6854
|
);
|
|
@@ -6863,20 +6950,20 @@ function useDictation({
|
|
|
6863
6950
|
onInterim
|
|
6864
6951
|
}) {
|
|
6865
6952
|
const resolvedLocale = locale ?? (typeof navigator !== "undefined" ? navigator.language || "pt-BR" : "pt-BR");
|
|
6866
|
-
const [state, setState] =
|
|
6867
|
-
const [error, setError] =
|
|
6868
|
-
const sessionRef =
|
|
6869
|
-
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 });
|
|
6870
6957
|
callbacks.current = { onTranscript, onInterim };
|
|
6871
|
-
const supported =
|
|
6958
|
+
const supported = React65.useMemo(
|
|
6872
6959
|
() => isDictationSupported(!!transcribeEndpoint),
|
|
6873
6960
|
[transcribeEndpoint]
|
|
6874
6961
|
);
|
|
6875
|
-
const finish =
|
|
6962
|
+
const finish = React65.useCallback(() => {
|
|
6876
6963
|
sessionRef.current = null;
|
|
6877
6964
|
setState("idle");
|
|
6878
6965
|
}, []);
|
|
6879
|
-
const start =
|
|
6966
|
+
const start = React65.useCallback(() => {
|
|
6880
6967
|
if (sessionRef.current || !supported) return;
|
|
6881
6968
|
stopSpeaking();
|
|
6882
6969
|
setError(null);
|
|
@@ -6897,28 +6984,28 @@ function useDictation({
|
|
|
6897
6984
|
}
|
|
6898
6985
|
);
|
|
6899
6986
|
}, [finish, resolvedLocale, supported, transcribeEndpoint]);
|
|
6900
|
-
const stop =
|
|
6987
|
+
const stop = React65.useCallback(() => {
|
|
6901
6988
|
if (!sessionRef.current) return;
|
|
6902
6989
|
if (transcribeEndpoint) setState("transcribing");
|
|
6903
6990
|
sessionRef.current.stop();
|
|
6904
6991
|
}, [transcribeEndpoint]);
|
|
6905
|
-
const cancel =
|
|
6992
|
+
const cancel = React65.useCallback(() => {
|
|
6906
6993
|
sessionRef.current?.cancel();
|
|
6907
6994
|
sessionRef.current = null;
|
|
6908
6995
|
setState("idle");
|
|
6909
6996
|
setError(null);
|
|
6910
6997
|
}, []);
|
|
6911
|
-
const toggle =
|
|
6998
|
+
const toggle = React65.useCallback(() => {
|
|
6912
6999
|
if (state === "listening" || state === "transcribing") stop();
|
|
6913
7000
|
else start();
|
|
6914
7001
|
}, [state, start, stop]);
|
|
6915
|
-
|
|
7002
|
+
React65.useEffect(() => () => sessionRef.current?.cancel(), []);
|
|
6916
7003
|
return { supported, state, error, start, stop, cancel, toggle, clearError: () => setError(null) };
|
|
6917
7004
|
}
|
|
6918
7005
|
function useMicLevels(active2, bandCount = 28, externalStream) {
|
|
6919
|
-
const levelsRef =
|
|
6920
|
-
const [available, setAvailable] =
|
|
6921
|
-
|
|
7006
|
+
const levelsRef = React65.useRef(new Float32Array(bandCount));
|
|
7007
|
+
const [available, setAvailable] = React65.useState(false);
|
|
7008
|
+
React65.useEffect(() => {
|
|
6922
7009
|
if (!active2) {
|
|
6923
7010
|
levelsRef.current.fill(0);
|
|
6924
7011
|
setAvailable(false);
|
|
@@ -6987,8 +7074,8 @@ var KIND_ICON = {
|
|
|
6987
7074
|
binary: File
|
|
6988
7075
|
};
|
|
6989
7076
|
function useFileDrop(enabled, onFiles) {
|
|
6990
|
-
const [dragging, setDragging] =
|
|
6991
|
-
const depth =
|
|
7077
|
+
const [dragging, setDragging] = React65.useState(false);
|
|
7078
|
+
const depth = React65.useRef(0);
|
|
6992
7079
|
const carriesFiles = (event) => Array.from(event.dataTransfer?.types ?? []).includes("Files");
|
|
6993
7080
|
const reset = () => {
|
|
6994
7081
|
depth.current = 0;
|
|
@@ -7048,7 +7135,7 @@ function AttachmentChips({
|
|
|
7048
7135
|
onRemove
|
|
7049
7136
|
}) {
|
|
7050
7137
|
const { t } = useTranslation$1();
|
|
7051
|
-
const [openId, setOpenId] =
|
|
7138
|
+
const [openId, setOpenId] = React65.useState(null);
|
|
7052
7139
|
if (!attachments.length) return null;
|
|
7053
7140
|
const opened = attachments.find((a) => a.id === openId);
|
|
7054
7141
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -7159,8 +7246,8 @@ function ChatComposer({
|
|
|
7159
7246
|
onToggleSuggestions
|
|
7160
7247
|
}) {
|
|
7161
7248
|
const { t } = useTranslation$1();
|
|
7162
|
-
const [input, setInput] =
|
|
7163
|
-
const textareaRef =
|
|
7249
|
+
const [input, setInput] = React65.useState("");
|
|
7250
|
+
const textareaRef = React65.useRef(null);
|
|
7164
7251
|
const voiceStartRequested = useChatStore((s) => s.voiceStartRequested);
|
|
7165
7252
|
const consumeVoiceStart = useChatStore((s) => s.consumeVoiceStart);
|
|
7166
7253
|
const draft = useChatStore((s) => s.draft);
|
|
@@ -7168,13 +7255,13 @@ function ChatComposer({
|
|
|
7168
7255
|
const attachments = useChatStore((s) => s.attachments);
|
|
7169
7256
|
const addAttachments = useChatStore((s) => s.addAttachments);
|
|
7170
7257
|
const removeAttachment = useChatStore((s) => s.removeAttachment);
|
|
7171
|
-
const fileInputRef =
|
|
7258
|
+
const fileInputRef = React65.useRef(null);
|
|
7172
7259
|
const autoSend = voice?.autoSend === true;
|
|
7173
7260
|
const micEnabled = voice?.input !== false;
|
|
7174
7261
|
const canAttach = isConfigured && !blocked && !isStreaming;
|
|
7175
7262
|
const parsing = attachments.some((a) => a.status === "parsing");
|
|
7176
7263
|
const readyAttachments = attachments.filter((a) => a.status === "ready").length;
|
|
7177
|
-
const submit =
|
|
7264
|
+
const submit = React65.useCallback(
|
|
7178
7265
|
(text) => {
|
|
7179
7266
|
const trimmed = text.trim();
|
|
7180
7267
|
if (!trimmed && !readyAttachments || parsing || isStreaming || !isConfigured || blocked) return;
|
|
@@ -7207,7 +7294,7 @@ function ChatComposer({
|
|
|
7207
7294
|
const WAVEFORM_BANDS = 56;
|
|
7208
7295
|
const activity = useAssistantActivity();
|
|
7209
7296
|
const sessionRecording = activity?.kind === "recording" && activity.state === "running";
|
|
7210
|
-
const sessionStream =
|
|
7297
|
+
const sessionStream = React65.useMemo(
|
|
7211
7298
|
() => sessionRecording ? activity?.stream?.() ?? null : null,
|
|
7212
7299
|
[sessionRecording, activity]
|
|
7213
7300
|
);
|
|
@@ -7219,12 +7306,12 @@ function ChatComposer({
|
|
|
7219
7306
|
);
|
|
7220
7307
|
const sessionPause = activity?.actions?.find((a) => a.intent === "pause" || a.intent === "resume");
|
|
7221
7308
|
const sessionOwnsMic = activity?.kind === "recording" && (activity.state === "running" || activity.state === "paused");
|
|
7222
|
-
|
|
7309
|
+
React65.useEffect(() => {
|
|
7223
7310
|
if (!voiceStartRequested) return;
|
|
7224
7311
|
consumeVoiceStart();
|
|
7225
7312
|
if (showMic) dictation.start();
|
|
7226
7313
|
}, [voiceStartRequested, showMic]);
|
|
7227
|
-
|
|
7314
|
+
React65.useEffect(() => {
|
|
7228
7315
|
if (!draft) return;
|
|
7229
7316
|
setInput(draft);
|
|
7230
7317
|
setDraft("");
|
|
@@ -7234,7 +7321,7 @@ function ChatComposer({
|
|
|
7234
7321
|
el.setSelectionRange(draft.length, draft.length);
|
|
7235
7322
|
}
|
|
7236
7323
|
}, [draft, setDraft]);
|
|
7237
|
-
|
|
7324
|
+
React65.useLayoutEffect(() => {
|
|
7238
7325
|
const el = textareaRef.current;
|
|
7239
7326
|
if (!el) return;
|
|
7240
7327
|
const style = getComputedStyle(el);
|
|
@@ -7431,8 +7518,8 @@ function LiveWaveform({
|
|
|
7431
7518
|
compact,
|
|
7432
7519
|
tone = "primary"
|
|
7433
7520
|
}) {
|
|
7434
|
-
const barsRef =
|
|
7435
|
-
|
|
7521
|
+
const barsRef = React65.useRef([]);
|
|
7522
|
+
React65.useEffect(() => {
|
|
7436
7523
|
if (!live) return;
|
|
7437
7524
|
let frame = 0;
|
|
7438
7525
|
const draw = () => {
|
|
@@ -7713,7 +7800,7 @@ function ConnectorSuggestionCard({ card }) {
|
|
|
7713
7800
|
const setOpen = useChatStore((s) => s.setOpen);
|
|
7714
7801
|
const category = categoryLabel(card.category);
|
|
7715
7802
|
const live = isConnectorState(card.state) ? card.state : null;
|
|
7716
|
-
const go =
|
|
7803
|
+
const go = React65.useCallback(() => {
|
|
7717
7804
|
if (panelAvailable && card.id) {
|
|
7718
7805
|
openConnectorsPanel({ id: card.id });
|
|
7719
7806
|
return;
|
|
@@ -7770,7 +7857,7 @@ function humanizeToolName(name) {
|
|
|
7770
7857
|
}
|
|
7771
7858
|
function ToolCallRow({ call }) {
|
|
7772
7859
|
const { t } = useTranslation$1();
|
|
7773
|
-
const [open, setOpen] =
|
|
7860
|
+
const [open, setOpen] = React65.useState(false);
|
|
7774
7861
|
const failed = call.declined || /"error"\s*:/.test(call.result ?? "");
|
|
7775
7862
|
return /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-xl border border-border/50 bg-muted/30", children: [
|
|
7776
7863
|
/* @__PURE__ */ jsxs(
|
|
@@ -7833,7 +7920,7 @@ function ToolCallRow({ call }) {
|
|
|
7833
7920
|
}
|
|
7834
7921
|
function MessageBubble({ message, isPending }) {
|
|
7835
7922
|
const isUser = message.role === "user";
|
|
7836
|
-
const routedLinks =
|
|
7923
|
+
const routedLinks = React65.useMemo(
|
|
7837
7924
|
() => (message.links ?? []).filter(
|
|
7838
7925
|
(l) => !!l.path || !!resolveEntityRoute(l.archetype, l.kind, l.entityKey)
|
|
7839
7926
|
),
|
|
@@ -7908,9 +7995,9 @@ function ConfirmActionCard({
|
|
|
7908
7995
|
onResolve
|
|
7909
7996
|
}) {
|
|
7910
7997
|
const { t } = useTranslation$1();
|
|
7911
|
-
const schema =
|
|
7998
|
+
const schema = React65.useMemo(() => action.fields ?? [], [action.fields]);
|
|
7912
7999
|
const partial = action.partial === true;
|
|
7913
|
-
const seedValues =
|
|
8000
|
+
const seedValues = React65.useCallback(
|
|
7914
8001
|
(params) => {
|
|
7915
8002
|
if (partial) return { ...params };
|
|
7916
8003
|
const seeded = {};
|
|
@@ -7919,17 +8006,17 @@ function ConfirmActionCard({
|
|
|
7919
8006
|
},
|
|
7920
8007
|
[schema, partial]
|
|
7921
8008
|
);
|
|
7922
|
-
const [values, setValues] =
|
|
7923
|
-
const [showAll, setShowAll] =
|
|
7924
|
-
|
|
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]);
|
|
7925
8012
|
const isSet = (v) => v !== void 0 && v !== null && v !== "";
|
|
7926
|
-
const primaryKeys =
|
|
8013
|
+
const primaryKeys = React65.useMemo(() => {
|
|
7927
8014
|
const keys = Object.keys(action.params).filter((k) => isSet(action.params[k]));
|
|
7928
8015
|
if (partial) return keys;
|
|
7929
8016
|
for (const f of schema) if (f.required && !keys.includes(f.key)) keys.push(f.key);
|
|
7930
8017
|
return keys;
|
|
7931
8018
|
}, [action.params, schema, partial]);
|
|
7932
|
-
const extraKeys =
|
|
8019
|
+
const extraKeys = React65.useMemo(
|
|
7933
8020
|
() => schema.map((f) => f.key).filter((k) => !primaryKeys.includes(k) && k !== "id"),
|
|
7934
8021
|
[schema, primaryKeys]
|
|
7935
8022
|
);
|
|
@@ -7946,20 +8033,20 @@ function ConfirmActionCard({
|
|
|
7946
8033
|
const translatedTool = t(toolKey);
|
|
7947
8034
|
const heading = action.title ?? (translatedTool !== toolKey ? translatedTool : humanizeToolName(action.toolName));
|
|
7948
8035
|
const ruleLabel = action.scopeLabel ?? heading;
|
|
7949
|
-
const missingRequiredKeys =
|
|
8036
|
+
const missingRequiredKeys = React65.useMemo(
|
|
7950
8037
|
() => partial ? [] : schema.filter((f) => f.required && !isSet(values[f.key])).map((f) => f.key),
|
|
7951
8038
|
[schema, values, partial]
|
|
7952
8039
|
);
|
|
7953
8040
|
const canConfirm = missingRequiredKeys.length === 0;
|
|
7954
|
-
const submitted =
|
|
8041
|
+
const submitted = React65.useCallback(
|
|
7955
8042
|
() => partial ? Object.fromEntries(Object.entries(values).filter(([, v]) => isSet(v))) : values,
|
|
7956
8043
|
[partial, values]
|
|
7957
8044
|
);
|
|
7958
|
-
const approve =
|
|
8045
|
+
const approve = React65.useCallback(() => {
|
|
7959
8046
|
if (canConfirm) onResolve(true, submitted());
|
|
7960
8047
|
}, [canConfirm, onResolve, submitted]);
|
|
7961
|
-
const decline =
|
|
7962
|
-
const approveAlways =
|
|
8048
|
+
const decline = React65.useCallback(() => onResolve(false), [onResolve]);
|
|
8049
|
+
const approveAlways = React65.useCallback(() => {
|
|
7963
8050
|
if (!canConfirm) return;
|
|
7964
8051
|
grantAutoApproval({
|
|
7965
8052
|
toolName: action.toolName,
|
|
@@ -7969,7 +8056,7 @@ function ConfirmActionCard({
|
|
|
7969
8056
|
});
|
|
7970
8057
|
onResolve(true, submitted());
|
|
7971
8058
|
}, [canConfirm, action.toolName, action.scope, ruleLabel, destructive, onResolve, submitted]);
|
|
7972
|
-
|
|
8059
|
+
React65.useEffect(() => {
|
|
7973
8060
|
const handler = (event) => {
|
|
7974
8061
|
const target = event.target;
|
|
7975
8062
|
const typing = target?.tagName === "INPUT" || target?.tagName === "TEXTAREA" || target?.tagName === "SELECT";
|
|
@@ -8303,7 +8390,7 @@ function UpgradePrompt({ feature, inline, className }) {
|
|
|
8303
8390
|
const currentPlan = plans.find((p) => p.id === currentPlanId);
|
|
8304
8391
|
const currentPrice = currentPlan?.price ?? 0;
|
|
8305
8392
|
const currentPlanName = currentPlan?.name ?? tr("billing.free", "Free");
|
|
8306
|
-
const featureName =
|
|
8393
|
+
const featureName = React65.useMemo(() => {
|
|
8307
8394
|
if (!feature) return null;
|
|
8308
8395
|
const label = features.find((f) => f.id === feature)?.label;
|
|
8309
8396
|
if (label) return featureDisplayName(label);
|
|
@@ -8311,7 +8398,7 @@ function UpgradePrompt({ feature, inline, className }) {
|
|
|
8311
8398
|
const named = t(key);
|
|
8312
8399
|
return named && named !== key ? named : featureDisplayName(feature);
|
|
8313
8400
|
}, [features, feature, t]);
|
|
8314
|
-
const unlockingPlans =
|
|
8401
|
+
const unlockingPlans = React65.useMemo(
|
|
8315
8402
|
() => plans.filter((p) => p.id !== currentPlanId && p.price > currentPrice && planUnlocks(p, feature)).sort((a, b) => a.price - b.price),
|
|
8316
8403
|
[plans, currentPlanId, currentPrice, feature]
|
|
8317
8404
|
);
|
|
@@ -8489,30 +8576,30 @@ function ChatConversation({
|
|
|
8489
8576
|
usable && !pendingAction && !isStreaming,
|
|
8490
8577
|
addAttachments
|
|
8491
8578
|
);
|
|
8492
|
-
|
|
8579
|
+
React65.useEffect(ensureIntroStyles, []);
|
|
8493
8580
|
const conversationsLoaded = useChatStore((s) => s.conversationsLoaded);
|
|
8494
|
-
const hasHistoryBackend =
|
|
8581
|
+
const hasHistoryBackend = React65.useMemo(
|
|
8495
8582
|
() => !apiEndpoint && !!resolveFayzAgentConnection(agent),
|
|
8496
8583
|
[apiEndpoint, agent]
|
|
8497
8584
|
);
|
|
8498
8585
|
const conversationsPending = hasHistoryBackend && !conversationsLoaded;
|
|
8499
|
-
const [view, setView] =
|
|
8586
|
+
const [view, setView] = React65.useState(
|
|
8500
8587
|
() => useChatStore.getState().messages.length > 0 ? "thread" : "list"
|
|
8501
8588
|
);
|
|
8502
|
-
const [drawer, setDrawer] =
|
|
8503
|
-
const [atBottom, setAtBottom] =
|
|
8504
|
-
const scrollRef =
|
|
8589
|
+
const [drawer, setDrawer] = React65.useState("none");
|
|
8590
|
+
const [atBottom, setAtBottom] = React65.useState(true);
|
|
8591
|
+
const scrollRef = React65.useRef(null);
|
|
8505
8592
|
const hasMessages = messages.length > 0;
|
|
8506
8593
|
const totalTools = toolGroups.reduce((sum, g) => sum + g.tools.length, 0);
|
|
8507
|
-
const scrollToBottom =
|
|
8594
|
+
const scrollToBottom = React65.useCallback((behavior = "smooth") => {
|
|
8508
8595
|
const el = scrollRef.current;
|
|
8509
8596
|
if (!el) return;
|
|
8510
8597
|
el.scrollTo({ top: el.scrollHeight, behavior });
|
|
8511
8598
|
}, []);
|
|
8512
|
-
|
|
8599
|
+
React65.useEffect(() => {
|
|
8513
8600
|
if (atBottom) scrollToBottom();
|
|
8514
8601
|
}, [messages, activeTools, pendingAction, atBottom, scrollToBottom]);
|
|
8515
|
-
|
|
8602
|
+
React65.useEffect(() => {
|
|
8516
8603
|
loadConversations();
|
|
8517
8604
|
setSuggestionsOpen(useChatStore.getState().messages.length === 0);
|
|
8518
8605
|
return () => stopSpeaking();
|
|
@@ -8529,7 +8616,7 @@ function ChatConversation({
|
|
|
8529
8616
|
};
|
|
8530
8617
|
const queuedPrompt = useChatStore((s) => s.queuedPrompt);
|
|
8531
8618
|
const consumeQueuedPrompt = useChatStore((s) => s.consumeQueuedPrompt);
|
|
8532
|
-
|
|
8619
|
+
React65.useEffect(() => {
|
|
8533
8620
|
if (!queuedPrompt) return;
|
|
8534
8621
|
const prompt = consumeQueuedPrompt();
|
|
8535
8622
|
if (prompt && usable) send(prompt);
|
|
@@ -8537,7 +8624,7 @@ function ChatConversation({
|
|
|
8537
8624
|
const toggleDrawer = (next) => setDrawer((current) => current === next ? "none" : next);
|
|
8538
8625
|
const connectorsPending = useConnectorsSurface((s) => s.pending);
|
|
8539
8626
|
const consumeConnectorsRequest = useConnectorsSurface((s) => s.consume);
|
|
8540
|
-
|
|
8627
|
+
React65.useEffect(() => {
|
|
8541
8628
|
if (!connectorsPending) return;
|
|
8542
8629
|
setDrawer("connectors");
|
|
8543
8630
|
consumeConnectorsRequest();
|
|
@@ -8824,7 +8911,7 @@ function HeaderButton({
|
|
|
8824
8911
|
function useDelegateToAssistant() {
|
|
8825
8912
|
const queuePrompt = useChatStore((s) => s.queuePrompt);
|
|
8826
8913
|
const openPanel = useRightRailStore((s) => s.openPanel);
|
|
8827
|
-
return
|
|
8914
|
+
return React65.useCallback(
|
|
8828
8915
|
(prompt) => {
|
|
8829
8916
|
queuePrompt(prompt);
|
|
8830
8917
|
openPanel("chat");
|
|
@@ -8883,12 +8970,12 @@ function NotesPanel() {
|
|
|
8883
8970
|
const user = useAuthStore((s) => s.user);
|
|
8884
8971
|
const currentOrg = useOrganizationStore((s) => s.currentOrg);
|
|
8885
8972
|
const key = storageKey2(currentOrg?.id ?? "local", user?.id ?? "anon");
|
|
8886
|
-
const [notes, setNotes] =
|
|
8887
|
-
const [openId, setOpenId] =
|
|
8888
|
-
const [search, setSearch] =
|
|
8889
|
-
const [preview, setPreview] =
|
|
8890
|
-
const [confirmingDelete, setConfirmingDelete] =
|
|
8891
|
-
|
|
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(() => {
|
|
8892
8979
|
setNotes(loadNotes(key));
|
|
8893
8980
|
setOpenId(null);
|
|
8894
8981
|
}, [key]);
|
|
@@ -9121,10 +9208,10 @@ ${note.content}`
|
|
|
9121
9208
|
function NoteTodosSection({ noteId, noteTitle, tr }) {
|
|
9122
9209
|
const adapter2 = useNotesTasksBridge((s) => s.adapter);
|
|
9123
9210
|
const delegate = useDelegateToAssistant();
|
|
9124
|
-
const [todos, setTodos] =
|
|
9125
|
-
const [draft, setDraft] =
|
|
9126
|
-
const [busy, setBusy] =
|
|
9127
|
-
|
|
9211
|
+
const [todos, setTodos] = React65.useState([]);
|
|
9212
|
+
const [draft, setDraft] = React65.useState("");
|
|
9213
|
+
const [busy, setBusy] = React65.useState(false);
|
|
9214
|
+
React65.useEffect(() => {
|
|
9128
9215
|
if (!adapter2) return;
|
|
9129
9216
|
let alive = true;
|
|
9130
9217
|
adapter2.listTodos(noteId).then((rows) => {
|
|
@@ -9275,11 +9362,11 @@ function NotesRailPanel() {
|
|
|
9275
9362
|
const currentOrg = useOrganizationStore((s) => s.currentOrg);
|
|
9276
9363
|
const key = storageKey2(currentOrg?.id ?? "local", user?.id ?? "anon");
|
|
9277
9364
|
const count = useNotesCount((s) => s.count);
|
|
9278
|
-
|
|
9365
|
+
React65.useEffect(() => {
|
|
9279
9366
|
useNotesCount.getState().setCount(loadNotes(key).length);
|
|
9280
9367
|
}, [key]);
|
|
9281
9368
|
useRightRailPanel(
|
|
9282
|
-
|
|
9369
|
+
React65.useMemo(
|
|
9283
9370
|
() => ({ id: "notes", label, icon: StickyNote, order: 30, badge: { count }, Component: NotesPanel }),
|
|
9284
9371
|
[label, count]
|
|
9285
9372
|
)
|
|
@@ -9933,7 +10020,7 @@ function useGlobalSearch() {
|
|
|
9933
10020
|
);
|
|
9934
10021
|
return { search, select, canOpen, targetCount: targets.length };
|
|
9935
10022
|
}
|
|
9936
|
-
var RouteErrorBoundary = class extends
|
|
10023
|
+
var RouteErrorBoundary = class extends React65.Component {
|
|
9937
10024
|
constructor() {
|
|
9938
10025
|
super(...arguments);
|
|
9939
10026
|
this.state = { crashed: false, report: null };
|
|
@@ -9975,7 +10062,7 @@ var RouteErrorBoundary = class extends React63.Component {
|
|
|
9975
10062
|
}
|
|
9976
10063
|
};
|
|
9977
10064
|
function RouteErrorScreen({ report, tr, onBack, onRetry, backLabel }) {
|
|
9978
|
-
const [copied, setCopied] =
|
|
10065
|
+
const [copied, setCopied] = React65.useState(false);
|
|
9979
10066
|
const copyDetails = () => {
|
|
9980
10067
|
if (!report || typeof navigator === "undefined" || !navigator.clipboard) return;
|
|
9981
10068
|
const details = [
|
|
@@ -10022,16 +10109,21 @@ function RouteErrorScreen({ report, tr, onBack, onRetry, backLabel }) {
|
|
|
10022
10109
|
] })
|
|
10023
10110
|
] });
|
|
10024
10111
|
}
|
|
10112
|
+
var WidgetSurfaceContext = React65.createContext("rail");
|
|
10113
|
+
function useWidgetSurface() {
|
|
10114
|
+
return React65.useContext(WidgetSurfaceContext);
|
|
10115
|
+
}
|
|
10025
10116
|
function WidgetSlot({
|
|
10026
10117
|
zone,
|
|
10027
10118
|
contextOverrides,
|
|
10119
|
+
surface,
|
|
10028
10120
|
...props
|
|
10029
10121
|
}) {
|
|
10030
10122
|
const runtime = usePluginRuntimeOptional();
|
|
10031
10123
|
if (!runtime) return null;
|
|
10032
10124
|
const widgets = getWidgetsForZone(runtime, zone, contextOverrides);
|
|
10033
10125
|
if (!widgets.length) return null;
|
|
10034
|
-
return /* @__PURE__ */ jsx(
|
|
10126
|
+
return /* @__PURE__ */ jsx(WidgetSurfaceContext.Provider, { value: surface ?? "rail", children: widgets.map((widget, i) => {
|
|
10035
10127
|
const Component2 = resolvePluginComponent(widget);
|
|
10036
10128
|
if (!Component2) return null;
|
|
10037
10129
|
const w = widget;
|
|
@@ -10063,7 +10155,7 @@ function useNavContribution(id, entries2) {
|
|
|
10063
10155
|
const setContribution = useNavContributionsStore((s) => s.setContribution);
|
|
10064
10156
|
const clearContribution = useNavContributionsStore((s) => s.clearContribution);
|
|
10065
10157
|
const key = JSON.stringify(entries2);
|
|
10066
|
-
|
|
10158
|
+
React65.useEffect(() => {
|
|
10067
10159
|
setContribution(id, entries2);
|
|
10068
10160
|
return () => clearContribution(id);
|
|
10069
10161
|
}, [id, key]);
|
|
@@ -10093,7 +10185,7 @@ function useContextualNav(nav) {
|
|
|
10093
10185
|
const setNav = useContextualNavStore((s) => s.setNav);
|
|
10094
10186
|
const clearNav = useContextualNavStore((s) => s.clearNav);
|
|
10095
10187
|
const key = nav ? JSON.stringify(nav) : null;
|
|
10096
|
-
|
|
10188
|
+
React65.useEffect(() => {
|
|
10097
10189
|
if (!nav) return;
|
|
10098
10190
|
setNav(nav);
|
|
10099
10191
|
return () => clearNav(nav.base);
|
|
@@ -10244,10 +10336,10 @@ function SeuSiteWidget({ fallback, onEdit }) {
|
|
|
10244
10336
|
const load = useFayzProjectsStore((s) => s.load);
|
|
10245
10337
|
const loadedFor = useFayzProjectsStore((s) => s.loadedFor);
|
|
10246
10338
|
const collapsed = useLayoutStore((s) => s.sidebarCollapsed);
|
|
10247
|
-
const [selectedId, setSelectedId] =
|
|
10248
|
-
const [hovered, setHovered] =
|
|
10249
|
-
const [primed, setPrimed] =
|
|
10250
|
-
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);
|
|
10251
10343
|
const cancelClose = () => {
|
|
10252
10344
|
if (closeTimer.current) {
|
|
10253
10345
|
clearTimeout(closeTimer.current);
|
|
@@ -10263,8 +10355,8 @@ function SeuSiteWidget({ fallback, onEdit }) {
|
|
|
10263
10355
|
cancelClose();
|
|
10264
10356
|
closeTimer.current = setTimeout(() => setHovered(false), 140);
|
|
10265
10357
|
};
|
|
10266
|
-
|
|
10267
|
-
|
|
10358
|
+
React65.useEffect(() => () => cancelClose(), []);
|
|
10359
|
+
React65.useEffect(() => {
|
|
10268
10360
|
if (loadedFor !== (currentOrgId ?? null)) void load(currentOrgId);
|
|
10269
10361
|
}, [currentOrgId, loadedFor, load]);
|
|
10270
10362
|
const active2 = projects.find((p) => p.id === selectedId) ?? defaultProjectOf(projects) ?? synthFromFallback(fallback);
|
|
@@ -10353,10 +10445,10 @@ function SitePreview({
|
|
|
10353
10445
|
onEdit,
|
|
10354
10446
|
tr
|
|
10355
10447
|
}) {
|
|
10356
|
-
const [nonce, setNonce] =
|
|
10357
|
-
const [loading, setLoading] =
|
|
10448
|
+
const [nonce, setNonce] = React65.useState(0);
|
|
10449
|
+
const [loading, setLoading] = React65.useState(true);
|
|
10358
10450
|
const url = project.previewUrl;
|
|
10359
|
-
|
|
10451
|
+
React65.useEffect(() => {
|
|
10360
10452
|
setLoading(true);
|
|
10361
10453
|
}, [nonce, url]);
|
|
10362
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";
|
|
@@ -10453,8 +10545,8 @@ function RightRail({ frame = true }) {
|
|
|
10453
10545
|
const openPanel = useRightRailStore((s) => s.openPanel);
|
|
10454
10546
|
const close = useRightRailStore((s) => s.close);
|
|
10455
10547
|
const setWidth = useRightRailStore((s) => s.setWidth);
|
|
10456
|
-
const rootRef =
|
|
10457
|
-
|
|
10548
|
+
const rootRef = React65.useRef(null);
|
|
10549
|
+
React65.useEffect(() => {
|
|
10458
10550
|
if (!open) return;
|
|
10459
10551
|
const el = rootRef.current;
|
|
10460
10552
|
if (!el) return;
|
|
@@ -10679,9 +10771,9 @@ var TYPE_COLORS = {
|
|
|
10679
10771
|
fix: "text-success"
|
|
10680
10772
|
};
|
|
10681
10773
|
function ChangelogFeed({ changelogUrl, className }) {
|
|
10682
|
-
const [entries2, setEntries] =
|
|
10683
|
-
const [loading, setLoading] =
|
|
10684
|
-
|
|
10774
|
+
const [entries2, setEntries] = React65.useState([]);
|
|
10775
|
+
const [loading, setLoading] = React65.useState(false);
|
|
10776
|
+
React65.useEffect(() => {
|
|
10685
10777
|
if (!changelogUrl) return;
|
|
10686
10778
|
setLoading(true);
|
|
10687
10779
|
fetch(changelogUrl).then((r) => r.json()).then((data) => setEntries(data)).catch(() => setEntries([])).finally(() => setLoading(false));
|
|
@@ -10744,7 +10836,7 @@ function NotificationInbox({
|
|
|
10744
10836
|
changelogUrl,
|
|
10745
10837
|
className
|
|
10746
10838
|
}) {
|
|
10747
|
-
const [activeTab, setActiveTab] =
|
|
10839
|
+
const [activeTab, setActiveTab] = React65.useState("inbox");
|
|
10748
10840
|
const unreadCount = notifications.filter((n) => !n.read).length;
|
|
10749
10841
|
const inboxNotifications = notifications.filter((n) => n.category !== "changelog");
|
|
10750
10842
|
return /* @__PURE__ */ jsxs("div", { className: cn$1("flex w-80 flex-col", className), children: [
|
|
@@ -10840,15 +10932,15 @@ function NotificationInbox({
|
|
|
10840
10932
|
] });
|
|
10841
10933
|
}
|
|
10842
10934
|
function ConnectConsentPage({ appName, logo }) {
|
|
10843
|
-
const [state, setState] =
|
|
10844
|
-
const [tenantId2, setTenantId] =
|
|
10845
|
-
const request =
|
|
10935
|
+
const [state, setState] = React65__default.useState({ status: "loading" });
|
|
10936
|
+
const [tenantId2, setTenantId] = React65__default.useState("");
|
|
10937
|
+
const request = React65__default.useMemo(
|
|
10846
10938
|
() => new URLSearchParams(window.location.search).get("request") ?? "",
|
|
10847
10939
|
[]
|
|
10848
10940
|
);
|
|
10849
|
-
const connection =
|
|
10941
|
+
const connection = React65__default.useMemo(() => resolveFayzAgentConnection(), []);
|
|
10850
10942
|
const product = appName ?? document.title ?? "este app";
|
|
10851
|
-
const authorizedFetch =
|
|
10943
|
+
const authorizedFetch = React65__default.useCallback(
|
|
10852
10944
|
async (path, init) => {
|
|
10853
10945
|
if (!connection) throw new Error("Este app n\xE3o est\xE1 ligado a um projeto Fayz.");
|
|
10854
10946
|
const supabase = getFayzSupabaseClientOptional();
|
|
@@ -10872,7 +10964,7 @@ function ConnectConsentPage({ appName, logo }) {
|
|
|
10872
10964
|
},
|
|
10873
10965
|
[connection]
|
|
10874
10966
|
);
|
|
10875
|
-
|
|
10967
|
+
React65__default.useEffect(() => {
|
|
10876
10968
|
let cancelled = false;
|
|
10877
10969
|
(async () => {
|
|
10878
10970
|
if (!request) {
|
|
@@ -11113,25 +11205,25 @@ function AddConnectorPanel({
|
|
|
11113
11205
|
onSelect
|
|
11114
11206
|
}) {
|
|
11115
11207
|
const { t } = useTranslation$1();
|
|
11116
|
-
const [query, setQuery] =
|
|
11208
|
+
const [query, setQuery] = React65__default.useState("");
|
|
11117
11209
|
const modules = useInstalledModuleIds();
|
|
11118
11210
|
const catalog = useConnectorCatalog();
|
|
11119
11211
|
const scoped = !!categories?.length;
|
|
11120
|
-
const addable =
|
|
11212
|
+
const addable = React65__default.useMemo(
|
|
11121
11213
|
() => inCategories(addableConnectors(connectors ?? []), categories),
|
|
11122
11214
|
[connectors, categories]
|
|
11123
11215
|
);
|
|
11124
|
-
const shelf =
|
|
11216
|
+
const shelf = React65__default.useMemo(() => {
|
|
11125
11217
|
if (connectors === null) return [];
|
|
11126
11218
|
return inCategories(
|
|
11127
11219
|
shelfIntegrations({ present: connectors, installedModules: modules, catalog: catalog ?? [] }),
|
|
11128
11220
|
categories
|
|
11129
11221
|
);
|
|
11130
11222
|
}, [connectors, modules, catalog, categories]);
|
|
11131
|
-
const filtered =
|
|
11132
|
-
const filteredShelf =
|
|
11133
|
-
const soon =
|
|
11134
|
-
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]);
|
|
11135
11227
|
const searchable = addable.length + shelf.length > 6;
|
|
11136
11228
|
return /* @__PURE__ */ jsx(Modal, { open, onOpenChange, children: /* @__PURE__ */ jsxs(ModalContent, { size: "2xl", children: [
|
|
11137
11229
|
/* @__PURE__ */ jsxs(ModalHeader, { children: [
|
|
@@ -11290,20 +11382,20 @@ function AddConnectorButton({ onClick }) {
|
|
|
11290
11382
|
function ConnectorsTab() {
|
|
11291
11383
|
const { t } = useTranslation$1();
|
|
11292
11384
|
const { connectors, error, reload, revokeGrant, agentAvailable, tenantReady } = useConnectors();
|
|
11293
|
-
const [adding, setAdding] =
|
|
11294
|
-
const [selected, setSelected] =
|
|
11295
|
-
const [filter, setFilter] =
|
|
11296
|
-
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);
|
|
11297
11389
|
const assistantAvailable = useConnectorsPanelAvailable();
|
|
11298
|
-
const openJourney =
|
|
11390
|
+
const openJourney = React65__default.useCallback(
|
|
11299
11391
|
(connector) => {
|
|
11300
11392
|
if (assistantAvailable) openConnectorsPanel(connector);
|
|
11301
11393
|
else setSelected(connector);
|
|
11302
11394
|
},
|
|
11303
11395
|
[assistantAvailable]
|
|
11304
11396
|
);
|
|
11305
|
-
const visible =
|
|
11306
|
-
|
|
11397
|
+
const visible = React65__default.useMemo(() => filterConnectors(connectors ?? [], filter), [connectors, filter]);
|
|
11398
|
+
React65__default.useEffect(() => {
|
|
11307
11399
|
if (!selected || !connectors) return;
|
|
11308
11400
|
const fresh = connectors.find((c) => c.id === selected.id);
|
|
11309
11401
|
if (fresh && fresh !== selected) setSelected(fresh);
|
|
@@ -11316,23 +11408,17 @@ function ConnectorsTab() {
|
|
|
11316
11408
|
return /* @__PURE__ */ jsx(Empty, { title: t("connectors.noOrg"), body: t("connectors.noOrgBody") });
|
|
11317
11409
|
}
|
|
11318
11410
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
11319
|
-
/* @__PURE__ */
|
|
11320
|
-
|
|
11321
|
-
|
|
11322
|
-
|
|
11323
|
-
|
|
11324
|
-
|
|
11325
|
-
|
|
11326
|
-
|
|
11327
|
-
|
|
11328
|
-
|
|
11329
|
-
|
|
11330
|
-
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
|
|
11331
|
-
t("connectors.add")
|
|
11332
|
-
]
|
|
11333
|
-
}
|
|
11334
|
-
)
|
|
11335
|
-
] }),
|
|
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
|
+
) }),
|
|
11336
11422
|
/* @__PURE__ */ jsx(
|
|
11337
11423
|
AddConnectorPanel,
|
|
11338
11424
|
{
|
|
@@ -11349,7 +11435,7 @@ function ConnectorsTab() {
|
|
|
11349
11435
|
(connectors?.length ?? 0) > 4 && /* @__PURE__ */ jsx(Filters, { value: filter, onChange: setFilter }),
|
|
11350
11436
|
connectors === null && /* @__PURE__ */ jsx(ConnectionsSkeleton, {}),
|
|
11351
11437
|
connectors !== null && visible.length === 0 && /* @__PURE__ */ jsx(Empty, { title: t("connectors.emptyTitle"), body: t("connectors.emptyBody") }),
|
|
11352
|
-
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)) }),
|
|
11353
11439
|
/* @__PURE__ */ jsx(
|
|
11354
11440
|
ConnectorDetail,
|
|
11355
11441
|
{
|
|
@@ -11384,7 +11470,7 @@ function Filters({ value, onChange }) {
|
|
|
11384
11470
|
)) });
|
|
11385
11471
|
}
|
|
11386
11472
|
function ConnectionsSkeleton() {
|
|
11387
|
-
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: [
|
|
11388
11474
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-10 shrink-0 rounded-lg" }),
|
|
11389
11475
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-2 py-0.5", children: [
|
|
11390
11476
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-40" }),
|
|
@@ -11463,7 +11549,7 @@ function oauthFailureMessage(t, result) {
|
|
|
11463
11549
|
function useConnectorOAuthReturn() {
|
|
11464
11550
|
const { t } = useTranslation$1();
|
|
11465
11551
|
const runtime = usePluginRuntimeOptional();
|
|
11466
|
-
|
|
11552
|
+
React65__default.useEffect(() => {
|
|
11467
11553
|
if (typeof window === "undefined") return;
|
|
11468
11554
|
const result = readConnectorOAuthReturn(window.location.search);
|
|
11469
11555
|
if (!result) return;
|
|
@@ -11498,8 +11584,8 @@ function ConnectorDeliveries({
|
|
|
11498
11584
|
limit = 10
|
|
11499
11585
|
}) {
|
|
11500
11586
|
const { t } = useTranslation$1();
|
|
11501
|
-
const [rows, setRows] =
|
|
11502
|
-
|
|
11587
|
+
const [rows, setRows] = React65__default.useState(null);
|
|
11588
|
+
React65__default.useEffect(() => {
|
|
11503
11589
|
let cancelled = false;
|
|
11504
11590
|
void load({ limit }).then((r) => {
|
|
11505
11591
|
if (!cancelled) setRows(r);
|
|
@@ -11573,11 +11659,11 @@ var CURRENCIES = [
|
|
|
11573
11659
|
function CompanySettings({ tenant, onSave }) {
|
|
11574
11660
|
const { t } = useTranslation$1();
|
|
11575
11661
|
const { locale: uiLocale, setLocale: setUiLocale } = useLocaleStore();
|
|
11576
|
-
const [name, setName] =
|
|
11577
|
-
const [timezone, setTimezone] =
|
|
11578
|
-
const [currency, setCurrency] =
|
|
11579
|
-
const [saving, setSaving] =
|
|
11580
|
-
|
|
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(() => {
|
|
11581
11667
|
if (tenant) {
|
|
11582
11668
|
setName(tenant.name);
|
|
11583
11669
|
setTimezone(tenant.settings?.timezone ?? "UTC");
|
|
@@ -11715,10 +11801,10 @@ function getInitials(name) {
|
|
|
11715
11801
|
}
|
|
11716
11802
|
function UserProfile({ user, onSave, onAvatarChange }) {
|
|
11717
11803
|
const { t } = useTranslation$1();
|
|
11718
|
-
const [fullName, setFullName] =
|
|
11719
|
-
const [saving, setSaving] =
|
|
11720
|
-
const fileInputRef =
|
|
11721
|
-
|
|
11804
|
+
const [fullName, setFullName] = React65.useState(user?.fullName ?? "");
|
|
11805
|
+
const [saving, setSaving] = React65.useState(false);
|
|
11806
|
+
const fileInputRef = React65.useRef(null);
|
|
11807
|
+
React65.useEffect(() => {
|
|
11722
11808
|
if (user) {
|
|
11723
11809
|
setFullName(user.fullName);
|
|
11724
11810
|
}
|
|
@@ -11823,8 +11909,8 @@ function UserProfile({ user, onSave, onAvatarChange }) {
|
|
|
11823
11909
|
function ConnectedUserProfile() {
|
|
11824
11910
|
const user = useAuthStore((s) => s.user);
|
|
11825
11911
|
const setUser = useAuthStore((s) => s.setUser);
|
|
11826
|
-
const [profile, setProfile] =
|
|
11827
|
-
|
|
11912
|
+
const [profile, setProfile] = React65.useState(null);
|
|
11913
|
+
React65.useEffect(() => {
|
|
11828
11914
|
const supabase = getFayzSupabaseClientOptional();
|
|
11829
11915
|
if (!user || !supabase) return;
|
|
11830
11916
|
let cancelled = false;
|
|
@@ -11924,9 +12010,9 @@ function SecuritySettings({
|
|
|
11924
12010
|
onTenantSecurityChange
|
|
11925
12011
|
}) {
|
|
11926
12012
|
const { t } = useTranslation$1();
|
|
11927
|
-
const [resetting, setResetting] =
|
|
11928
|
-
const [resetSent, setResetSent] =
|
|
11929
|
-
const [savingTenant, setSavingTenant] =
|
|
12013
|
+
const [resetting, setResetting] = React65.useState(false);
|
|
12014
|
+
const [resetSent, setResetSent] = React65.useState(false);
|
|
12015
|
+
const [savingTenant, setSavingTenant] = React65.useState(false);
|
|
11930
12016
|
const handleResetPassword = async () => {
|
|
11931
12017
|
if (!onResetPassword) return;
|
|
11932
12018
|
setResetting(true);
|
|
@@ -12102,8 +12188,8 @@ function FileUploadField({
|
|
|
12102
12188
|
hint
|
|
12103
12189
|
}) {
|
|
12104
12190
|
const { t } = useTranslation$1();
|
|
12105
|
-
const inputRef =
|
|
12106
|
-
const [preview, setPreview] =
|
|
12191
|
+
const inputRef = React65.useRef(null);
|
|
12192
|
+
const [preview, setPreview] = React65.useState(null);
|
|
12107
12193
|
const handleChange = (e) => {
|
|
12108
12194
|
const file = e.target.files?.[0];
|
|
12109
12195
|
if (file) {
|
|
@@ -12170,14 +12256,14 @@ function FileUploadField({
|
|
|
12170
12256
|
}
|
|
12171
12257
|
function BrandingSettings({ branding, onSave }) {
|
|
12172
12258
|
const { t } = useTranslation$1();
|
|
12173
|
-
const [primaryColor, setPrimaryColor] =
|
|
12174
|
-
const [accentColor, setAccentColor] =
|
|
12175
|
-
const [logoFile, setLogoFile] =
|
|
12176
|
-
const [faviconFile, setFaviconFile] =
|
|
12177
|
-
const [logoUrl, setLogoUrl] =
|
|
12178
|
-
const [faviconUrl, setFaviconUrl] =
|
|
12179
|
-
const [saving, setSaving] =
|
|
12180
|
-
|
|
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(() => {
|
|
12181
12267
|
if (branding) {
|
|
12182
12268
|
setPrimaryColor(branding.primaryColor ?? "#000000");
|
|
12183
12269
|
setAccentColor(branding.accentColor ?? "#6366f1");
|
|
@@ -12383,9 +12469,9 @@ function ProjectsSettings() {
|
|
|
12383
12469
|
const projects = useFayzProjectsStore((s) => s.projects);
|
|
12384
12470
|
const load = useFayzProjectsStore((s) => s.load);
|
|
12385
12471
|
const refresh = useFayzProjectsStore((s) => s.refresh);
|
|
12386
|
-
const [adding, setAdding] =
|
|
12387
|
-
const [editing, setEditing] =
|
|
12388
|
-
|
|
12472
|
+
const [adding, setAdding] = React65.useState(false);
|
|
12473
|
+
const [editing, setEditing] = React65.useState(null);
|
|
12474
|
+
React65.useEffect(() => {
|
|
12389
12475
|
void load(currentOrgId);
|
|
12390
12476
|
}, [currentOrgId, load]);
|
|
12391
12477
|
const onCreate = async (input) => {
|
|
@@ -12407,16 +12493,10 @@ function ProjectsSettings() {
|
|
|
12407
12493
|
await refresh();
|
|
12408
12494
|
};
|
|
12409
12495
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
12410
|
-
/* @__PURE__ */ jsxs(
|
|
12411
|
-
/* @__PURE__ */
|
|
12412
|
-
|
|
12413
|
-
|
|
12414
|
-
] }),
|
|
12415
|
-
!adding && /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: () => setAdding(true), children: [
|
|
12416
|
-
/* @__PURE__ */ jsx(Plus, { className: "mr-1.5 h-4 w-4" }),
|
|
12417
|
-
" Adicionar"
|
|
12418
|
-
] })
|
|
12419
|
-
] }),
|
|
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
|
+
] }) }),
|
|
12420
12500
|
adding && /* @__PURE__ */ jsx(ProjectForm, { onCancel: () => setAdding(false), onSubmit: onCreate }),
|
|
12421
12501
|
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
12422
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)." }),
|
|
@@ -12457,12 +12537,12 @@ function ProjectRow({ project, onEdit, onDelete, onSetDefault }) {
|
|
|
12457
12537
|
] });
|
|
12458
12538
|
}
|
|
12459
12539
|
function ProjectForm({ initial, onCancel, onSubmit }) {
|
|
12460
|
-
const [name, setName] =
|
|
12461
|
-
const [kind, setKind] =
|
|
12462
|
-
const [fayzProjectId, setFayzProjectId] =
|
|
12463
|
-
const [previewUrl, setPreviewUrl] =
|
|
12464
|
-
const [isDefault, setIsDefault] =
|
|
12465
|
-
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);
|
|
12466
12546
|
const submit = () => onSubmit({
|
|
12467
12547
|
name: name.trim() || "Meu site",
|
|
12468
12548
|
kind,
|
|
@@ -12499,12 +12579,25 @@ function ProjectForm({ initial, onCancel, onSubmit }) {
|
|
|
12499
12579
|
] })
|
|
12500
12580
|
] });
|
|
12501
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
|
+
}
|
|
12502
12595
|
function useCoreSettingsTabs({
|
|
12503
12596
|
showCompany = true,
|
|
12504
12597
|
showBranding = true
|
|
12505
12598
|
} = {}) {
|
|
12506
12599
|
const { t } = useTranslation$1();
|
|
12507
|
-
return
|
|
12600
|
+
return React65.useMemo(() => [
|
|
12508
12601
|
...showCompany ? [{ id: "general", label: t("settings.general"), icon: /* @__PURE__ */ jsx(Building2, { className: "h-4 w-4" }), iconName: "Building2", component: /* @__PURE__ */ jsx(ConnectedCompanySettings, {}) }] : [],
|
|
12509
12602
|
{ id: "profile", label: t("settings.profile"), icon: /* @__PURE__ */ jsx(User, { className: "h-4 w-4" }), iconName: "User", component: /* @__PURE__ */ jsx(ConnectedUserProfile, {}) },
|
|
12510
12603
|
{ id: "security", label: t("settings.security"), icon: /* @__PURE__ */ jsx(Shield, { className: "h-4 w-4" }), iconName: "Shield", component: /* @__PURE__ */ jsx(ConnectedSecuritySettings, {}) },
|
|
@@ -12530,6 +12623,7 @@ function SettingsPage({
|
|
|
12530
12623
|
activeTabId
|
|
12531
12624
|
}) {
|
|
12532
12625
|
const { t } = useTranslation$1();
|
|
12626
|
+
const wide = useIsWide();
|
|
12533
12627
|
const defaultTabs = useCoreSettingsTabs({ showCompany, showBranding });
|
|
12534
12628
|
const baseTabs = tabs ?? defaultTabs;
|
|
12535
12629
|
const resolvedTabs = extraTabs ? [...baseTabs, ...extraTabs] : baseTabs;
|
|
@@ -12542,10 +12636,10 @@ function SettingsPage({
|
|
|
12542
12636
|
}
|
|
12543
12637
|
return null;
|
|
12544
12638
|
}
|
|
12545
|
-
const [activeTab, setActiveTab] =
|
|
12639
|
+
const [activeTab, setActiveTab] = React65.useState(() => {
|
|
12546
12640
|
return getTabFromHash() ?? defaultTab ?? null;
|
|
12547
12641
|
});
|
|
12548
|
-
|
|
12642
|
+
React65.useEffect(() => {
|
|
12549
12643
|
const handler = () => {
|
|
12550
12644
|
const tab = getTabFromHash();
|
|
12551
12645
|
if (tab) setActiveTab(tab);
|
|
@@ -12568,7 +12662,7 @@ function SettingsPage({
|
|
|
12568
12662
|
setActiveTab(null);
|
|
12569
12663
|
window.location.hash = "/settings";
|
|
12570
12664
|
};
|
|
12571
|
-
const sections =
|
|
12665
|
+
const sections = React65.useMemo(() => {
|
|
12572
12666
|
const out = [];
|
|
12573
12667
|
for (const tab of resolvedTabs) {
|
|
12574
12668
|
const heading = tab.isPlugin ? tab.group ?? t("common.plugins") : null;
|
|
@@ -12595,40 +12689,39 @@ function SettingsPage({
|
|
|
12595
12689
|
) }, tab.id)) })
|
|
12596
12690
|
] }, section.key)) });
|
|
12597
12691
|
return /* @__PURE__ */ jsxs("div", { className: cn$1("fz-container space-y-6", className), children: [
|
|
12598
|
-
!controlled && showingContent && /* @__PURE__ */ jsxs(
|
|
12692
|
+
!controlled && showingContent && !wide && /* @__PURE__ */ jsxs(
|
|
12599
12693
|
"button",
|
|
12600
12694
|
{
|
|
12601
12695
|
onClick: handleBack,
|
|
12602
|
-
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",
|
|
12603
12697
|
children: [
|
|
12604
12698
|
/* @__PURE__ */ jsx(ArrowLeft, { className: "h-4 w-4" }),
|
|
12605
12699
|
t("settings.title")
|
|
12606
12700
|
]
|
|
12607
12701
|
}
|
|
12608
12702
|
),
|
|
12609
|
-
!showingContent && /* @__PURE__ */ jsxs("div", {
|
|
12703
|
+
!showingContent && !wide && /* @__PURE__ */ jsxs("div", { children: [
|
|
12610
12704
|
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold tracking-tight", children: t("settings.title") }),
|
|
12611
12705
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("settings.subtitle") })
|
|
12612
12706
|
] }),
|
|
12613
12707
|
beforeContent,
|
|
12614
|
-
/* @__PURE__ */
|
|
12615
|
-
|
|
12616
|
-
|
|
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,
|
|
12617
12712
|
{
|
|
12618
|
-
|
|
12619
|
-
|
|
12620
|
-
|
|
12621
|
-
|
|
12622
|
-
|
|
12623
|
-
|
|
12624
|
-
|
|
12625
|
-
|
|
12626
|
-
|
|
12627
|
-
|
|
12628
|
-
|
|
12629
|
-
|
|
12630
|
-
] }),
|
|
12631
|
-
/* @__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,
|
|
12632
12725
|
afterContent
|
|
12633
12726
|
] });
|
|
12634
12727
|
}
|
|
@@ -12647,10 +12740,10 @@ function InviteMemberDialog({ open, onOpenChange, defaultEmail }) {
|
|
|
12647
12740
|
const profiles = usePermissionsStore((s) => s.profiles);
|
|
12648
12741
|
const setInvites = useInviteStore((s) => s.setInvites);
|
|
12649
12742
|
const { user } = useAuthStore();
|
|
12650
|
-
const [emails, setEmails] =
|
|
12651
|
-
const [profileId, setProfileId] =
|
|
12652
|
-
const [sending, setSending] =
|
|
12653
|
-
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);
|
|
12654
12747
|
const addEmail = () => setEmails((prev) => [...prev, ""]);
|
|
12655
12748
|
const updateEmail = (idx, value) => {
|
|
12656
12749
|
setEmails((prev) => {
|
|
@@ -12747,14 +12840,14 @@ function TeamTab() {
|
|
|
12747
12840
|
const { user } = useAuthStore();
|
|
12748
12841
|
const hasSystemPermission = useSystemPermission();
|
|
12749
12842
|
const personMode = teamPersonKinds.length > 0 && typeof adapter2?.listTeam === "function";
|
|
12750
|
-
const [team, setTeam] =
|
|
12751
|
-
const [inviteOpen, setInviteOpen] =
|
|
12843
|
+
const [team, setTeam] = React65.useState(null);
|
|
12844
|
+
const [inviteOpen, setInviteOpen] = React65.useState(false);
|
|
12752
12845
|
const guardSeats = useLimitGuard("users");
|
|
12753
12846
|
const handleOpenInvite = async () => {
|
|
12754
12847
|
if (await guardSeats(1) === "blocked") return;
|
|
12755
12848
|
setInviteOpen(true);
|
|
12756
12849
|
};
|
|
12757
|
-
const reloadTeam =
|
|
12850
|
+
const reloadTeam = React65.useCallback(async () => {
|
|
12758
12851
|
if (!adapter2 || !currentOrg) return;
|
|
12759
12852
|
if (personMode && adapter2.listTeam) {
|
|
12760
12853
|
setTeam(await adapter2.listTeam(currentOrg.id, teamPersonKinds));
|
|
@@ -12762,12 +12855,12 @@ function TeamTab() {
|
|
|
12762
12855
|
setMembers(await adapter2.listMembers(currentOrg.id));
|
|
12763
12856
|
}
|
|
12764
12857
|
}, [adapter2, currentOrg?.id, personMode, teamPersonKinds, setMembers]);
|
|
12765
|
-
|
|
12858
|
+
React65.useEffect(() => {
|
|
12766
12859
|
if (personMode && adapter2?.listTeam && currentOrg) {
|
|
12767
12860
|
dedup("team:people:" + currentOrg.id, () => adapter2.listTeam(currentOrg.id, teamPersonKinds)).then(setTeam).catch(() => setTeam([]));
|
|
12768
12861
|
}
|
|
12769
12862
|
}, [personMode, adapter2, currentOrg?.id, teamPersonKinds.join(",")]);
|
|
12770
|
-
|
|
12863
|
+
React65.useEffect(() => {
|
|
12771
12864
|
if (adapter2 && currentOrg) {
|
|
12772
12865
|
dedup("team:invites:" + currentOrg.id, () => adapter2.listInvites(currentOrg.id)).then(setInvites).catch(() => {
|
|
12773
12866
|
});
|
|
@@ -12842,18 +12935,13 @@ function TeamTab() {
|
|
|
12842
12935
|
const pendingInvites = invites.filter((i) => i.status === "pending");
|
|
12843
12936
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
12844
12937
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
12845
|
-
/* @__PURE__ */
|
|
12846
|
-
|
|
12847
|
-
|
|
12848
|
-
|
|
12849
|
-
|
|
12850
|
-
|
|
12851
|
-
|
|
12852
|
-
}, children: [
|
|
12853
|
-
/* @__PURE__ */ jsx(UserPlus, { className: "h-4 w-4 mr-1" }),
|
|
12854
|
-
t("organization.team.invite")
|
|
12855
|
-
] })
|
|
12856
|
-
] }),
|
|
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" : "" }) }),
|
|
12857
12945
|
/* @__PURE__ */ jsx(Card, { className: "overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full", children: [
|
|
12858
12946
|
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b bg-muted/50", children: [
|
|
12859
12947
|
/* @__PURE__ */ jsx("th", { className: "text-left p-3 text-sm font-medium text-muted-foreground", children: t("organization.team.member") }),
|
|
@@ -12975,13 +13063,13 @@ var SYSTEM_PERMISSIONS = [
|
|
|
12975
13063
|
];
|
|
12976
13064
|
function PermissionMatrixEditor({ features, profile, onSave, onCancel, saving, isNew, parentLabel }) {
|
|
12977
13065
|
const { t } = useTranslation$1();
|
|
12978
|
-
const [name, setName] =
|
|
12979
|
-
const [description, setDescription] =
|
|
12980
|
-
const [systemPerms, setSystemPerms] =
|
|
12981
|
-
const [grants, setGrants] =
|
|
12982
|
-
const [collapsed, setCollapsed] =
|
|
12983
|
-
const [search, setSearch] =
|
|
12984
|
-
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({
|
|
12985
13073
|
name: profile?.name ?? "",
|
|
12986
13074
|
description: profile?.description ?? "",
|
|
12987
13075
|
systemPerms: JSON.stringify(profile?.systemPermissions ?? []),
|
|
@@ -13019,7 +13107,7 @@ function PermissionMatrixEditor({ features, profile, onSave, onCancel, saving, i
|
|
|
13019
13107
|
saveLabel: isNew ? t("organization.permissions.createProfile") : t("organization.permissions.updateProfile")
|
|
13020
13108
|
});
|
|
13021
13109
|
useBackHandler(onCancel);
|
|
13022
|
-
const groups =
|
|
13110
|
+
const groups = React65.useMemo(() => {
|
|
13023
13111
|
const filtered = search ? features.filter((f) => f.label.toLowerCase().includes(search.toLowerCase())) : features;
|
|
13024
13112
|
const map = /* @__PURE__ */ new Map();
|
|
13025
13113
|
for (const f of filtered) {
|
|
@@ -13088,7 +13176,7 @@ function PermissionMatrixEditor({ features, profile, onSave, onCancel, saving, i
|
|
|
13088
13176
|
}
|
|
13089
13177
|
) }) })
|
|
13090
13178
|
] }, sp.id)),
|
|
13091
|
-
Array.from(groups.entries()).map(([groupName, groupFeatures]) => /* @__PURE__ */ jsxs(
|
|
13179
|
+
Array.from(groups.entries()).map(([groupName, groupFeatures]) => /* @__PURE__ */ jsxs(React65.Fragment, { children: [
|
|
13092
13180
|
/* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: 5, className: "p-2 px-3", children: /* @__PURE__ */ jsxs(
|
|
13093
13181
|
"button",
|
|
13094
13182
|
{
|
|
@@ -13129,11 +13217,11 @@ function PermissionProfilesTab() {
|
|
|
13129
13217
|
const startImpersonation = usePermissionsStore((s) => s.startImpersonation);
|
|
13130
13218
|
const canPreview = (realProfile?.systemPermissions ?? []).includes("manage_permissions") ?? false;
|
|
13131
13219
|
const { t } = useTranslation$1();
|
|
13132
|
-
const [editingProfile, setEditingProfile] =
|
|
13133
|
-
const [creating, setCreating] =
|
|
13134
|
-
const [duplicateSource, setDuplicateSource] =
|
|
13135
|
-
const [saving, setSaving] =
|
|
13136
|
-
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);
|
|
13137
13225
|
const handleDuplicate = (profile) => {
|
|
13138
13226
|
setEditingProfile(null);
|
|
13139
13227
|
setCreating(false);
|
|
@@ -13143,7 +13231,7 @@ function PermissionProfilesTab() {
|
|
|
13143
13231
|
isSystem: false
|
|
13144
13232
|
});
|
|
13145
13233
|
};
|
|
13146
|
-
const memberCountByProfile =
|
|
13234
|
+
const memberCountByProfile = React65.useMemo(() => {
|
|
13147
13235
|
const counts = {};
|
|
13148
13236
|
for (const m of members) {
|
|
13149
13237
|
counts[m.profileId] = (counts[m.profileId] ?? 0) + 1;
|
|
@@ -13200,16 +13288,10 @@ function PermissionProfilesTab() {
|
|
|
13200
13288
|
);
|
|
13201
13289
|
}
|
|
13202
13290
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
13203
|
-
/* @__PURE__ */ jsxs(
|
|
13204
|
-
/* @__PURE__ */
|
|
13205
|
-
|
|
13206
|
-
|
|
13207
|
-
] }),
|
|
13208
|
-
/* @__PURE__ */ jsxs(Button, { onClick: () => setCreating(true), size: "sm", children: [
|
|
13209
|
-
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-1" }),
|
|
13210
|
-
t("organization.permissions.createProfile")
|
|
13211
|
-
] })
|
|
13212
|
-
] }),
|
|
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
|
+
] }) }),
|
|
13213
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 }),
|
|
13214
13296
|
/* @__PURE__ */ jsx("div", { className: "grid gap-3", children: profiles.length === 0 ? (
|
|
13215
13297
|
// Roles load via central org hydration; show skeletons until they arrive.
|
|
@@ -13908,7 +13990,7 @@ function SubjectFormLayout({ fields, allFields, fieldGroups, values, onChange, r
|
|
|
13908
13990
|
const IconComponent = getLucideIcon(entityIcon ?? "Heart") ?? Heart;
|
|
13909
13991
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
13910
13992
|
/* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(CardContent, { className: "pt-5", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-5", children: [
|
|
13911
|
-
/* @__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" }) }),
|
|
13912
13994
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-4", children: [
|
|
13913
13995
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-4", children: [
|
|
13914
13996
|
nameField && /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-1.5", children: [
|
|
@@ -14256,11 +14338,11 @@ function ImageSlot({
|
|
|
14256
14338
|
canEdit
|
|
14257
14339
|
}) {
|
|
14258
14340
|
const t = useTranslation();
|
|
14259
|
-
const inputRef =
|
|
14260
|
-
const [url, setUrl] =
|
|
14261
|
-
const [busy, setBusy] =
|
|
14262
|
-
const [error, setError] =
|
|
14263
|
-
|
|
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(() => {
|
|
14264
14346
|
setUrl(image.get(row));
|
|
14265
14347
|
}, [image.get(row)]);
|
|
14266
14348
|
const pick = () => {
|
|
@@ -14354,7 +14436,7 @@ function CrudFormPage({ entityDef, mode, initialData, onSubmit, onCancel, namePl
|
|
|
14354
14436
|
const computeInit = () => mode === "edit" && initialData ? { ...getDefaultValues(formFields), ...initialData } : getDefaultValues(formFields);
|
|
14355
14437
|
const [values, setValues] = useState(computeInit);
|
|
14356
14438
|
const [saving, setSaving] = useState(false);
|
|
14357
|
-
const initialRef =
|
|
14439
|
+
const initialRef = React65__default.useRef(JSON.stringify(values));
|
|
14358
14440
|
useEffect(() => {
|
|
14359
14441
|
const init = computeInit();
|
|
14360
14442
|
setValues(init);
|
|
@@ -14725,6 +14807,57 @@ function LimitGate({ limitKey, children, className }) {
|
|
|
14725
14807
|
}
|
|
14726
14808
|
);
|
|
14727
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
|
+
}
|
|
14728
14861
|
var ALL_TAB = "__all__";
|
|
14729
14862
|
function getEntityIcon(name) {
|
|
14730
14863
|
const icons = LucideIcons3;
|
|
@@ -14755,6 +14888,7 @@ function CrudListView({
|
|
|
14755
14888
|
onExport,
|
|
14756
14889
|
feature,
|
|
14757
14890
|
readOnly,
|
|
14891
|
+
embedded,
|
|
14758
14892
|
emptyMessage,
|
|
14759
14893
|
navTabs,
|
|
14760
14894
|
activeNavTab,
|
|
@@ -14822,22 +14956,35 @@ function CrudListView({
|
|
|
14822
14956
|
}] : []
|
|
14823
14957
|
];
|
|
14824
14958
|
const selectable = display === "table" && barActions.length > 0;
|
|
14825
|
-
const
|
|
14826
|
-
const headerTabs = navTabs?.length ? navTabs.map((t2) => ({ value: t2.id, label: t2.label, icon: t2.icon })) :
|
|
14827
|
-
|
|
14828
|
-
...facetTab.options.map((o) => ({ value: o.value, label: o.label }))
|
|
14829
|
-
] : null;
|
|
14830
|
-
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;
|
|
14831
14962
|
const onHeaderTabChange = (next) => {
|
|
14832
|
-
|
|
14833
|
-
else if (facetTab) onFacetChange?.(facetTab.field, next === ALL_TAB ? void 0 : next);
|
|
14963
|
+
navTabs?.find((t2) => t2.id === next)?.onSelect();
|
|
14834
14964
|
};
|
|
14835
|
-
const pillFacets = facets
|
|
14836
|
-
const
|
|
14837
|
-
const
|
|
14838
|
-
|
|
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;
|
|
14839
14984
|
return entityDef.limitKey ? /* @__PURE__ */ jsx(LimitGate, { limitKey: entityDef.limitKey, children: roleGated }) : roleGated;
|
|
14840
|
-
}
|
|
14985
|
+
};
|
|
14986
|
+
const gatedNewButton = newButton ? gate(newButton) : null;
|
|
14987
|
+
const gatedCreateButton = onNew && !readOnly ? gate(/* @__PURE__ */ jsx(Button, { onClick: onNew, children: newLabel })) : null;
|
|
14841
14988
|
const isFiltered = Boolean(search?.trim()) || Object.values(activeFilters ?? {}).some((v) => v != null);
|
|
14842
14989
|
const EmptyIcon = getEntityIcon(entityDef.icon);
|
|
14843
14990
|
const emptyState = /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1 py-6", children: [
|
|
@@ -14845,18 +14992,13 @@ function CrudListView({
|
|
|
14845
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() })) }),
|
|
14846
14993
|
!isFiltered && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
14847
14994
|
/* @__PURE__ */ jsx("p", { className: "max-w-sm text-sm text-muted-foreground", children: t("crud.list.emptyHint", { entities: namePlural.toLowerCase() }) }),
|
|
14848
|
-
|
|
14995
|
+
gatedCreateButton && /* @__PURE__ */ jsx("div", { className: "mt-3", children: gatedCreateButton })
|
|
14849
14996
|
] })
|
|
14850
14997
|
] });
|
|
14851
|
-
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: [
|
|
14852
14999
|
headerActions,
|
|
14853
|
-
onImport && /* @__PURE__ */ jsxs(Button, { variant: "outline", onClick: onImport, children: [
|
|
14854
|
-
/* @__PURE__ */ jsx(Upload, { className: "mr-2 h-4 w-4" }),
|
|
14855
|
-
t("crud.import.action")
|
|
14856
|
-
] }),
|
|
14857
|
-
onImport && gatedNewButton && /* @__PURE__ */ jsx("span", { className: "h-6 w-px bg-border", "aria-hidden": true }),
|
|
14858
15000
|
gatedNewButton
|
|
14859
|
-
] });
|
|
15001
|
+
] }) : null;
|
|
14860
15002
|
const sortableColumns = useMemo(() => {
|
|
14861
15003
|
const declared = entityDef.fields.filter((f) => f.sortable !== false).map((f) => ({ key: f.key, label: f.label }));
|
|
14862
15004
|
const has = new Set(declared.map((f) => f.key));
|
|
@@ -14977,18 +15119,21 @@ function CrudListView({
|
|
|
14977
15119
|
] })
|
|
14978
15120
|
] }) : null;
|
|
14979
15121
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
14980
|
-
/* @__PURE__ */
|
|
14981
|
-
|
|
14982
|
-
|
|
14983
|
-
|
|
14984
|
-
|
|
14985
|
-
|
|
14986
|
-
|
|
14987
|
-
|
|
14988
|
-
|
|
14989
|
-
|
|
14990
|
-
|
|
14991
|
-
|
|
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
|
+
),
|
|
14992
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: [
|
|
14993
15138
|
/* @__PURE__ */ jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-destructive" }),
|
|
14994
15139
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
@@ -14998,16 +15143,6 @@ function CrudListView({
|
|
|
14998
15143
|
onRefresh && /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", className: "ml-auto shrink-0", onClick: onRefresh, children: t("crud.list.refresh") })
|
|
14999
15144
|
] }),
|
|
15000
15145
|
stats && stats.length > 0 && /* @__PURE__ */ jsx(StatTiles, { tiles: stats, loading: isInitialLoad }),
|
|
15001
|
-
selectable && /* @__PURE__ */ jsx(
|
|
15002
|
-
BulkActionBar,
|
|
15003
|
-
{
|
|
15004
|
-
count: selectedIds.length,
|
|
15005
|
-
total: items?.length ?? 0,
|
|
15006
|
-
onSelectAll: () => setRawSelection((items ?? []).map((r) => r.id)),
|
|
15007
|
-
onClear: () => setRawSelection([]),
|
|
15008
|
-
actions: barActions
|
|
15009
|
-
}
|
|
15010
|
-
),
|
|
15011
15146
|
display === "cards" ? (
|
|
15012
15147
|
// The card grid keeps the search box floating above it: there is no
|
|
15013
15148
|
// table chrome for a toolbar to sit flush against.
|
|
@@ -15044,11 +15179,21 @@ function CrudListView({
|
|
|
15044
15179
|
same rows, so a search box floating on the page background above a
|
|
15045
15180
|
separate table card read as two unrelated controls. */
|
|
15046
15181
|
/* @__PURE__ */ jsxs(Card, { className: "overflow-hidden", children: [
|
|
15047
|
-
(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: [
|
|
15048
15193
|
/* @__PURE__ */ jsx("div", { className: "min-w-[10rem] flex-1", children: searchBox }),
|
|
15049
15194
|
facetChips,
|
|
15050
15195
|
tableTools
|
|
15051
|
-
] }),
|
|
15196
|
+
] }) }),
|
|
15052
15197
|
/* @__PURE__ */ jsx(
|
|
15053
15198
|
DataTable,
|
|
15054
15199
|
{
|
|
@@ -15444,7 +15589,7 @@ function AddressesTab({ item }) {
|
|
|
15444
15589
|
)
|
|
15445
15590
|
] });
|
|
15446
15591
|
}
|
|
15447
|
-
var ScheduleEditor =
|
|
15592
|
+
var ScheduleEditor = React65__default.lazy(
|
|
15448
15593
|
() => import('./ScheduleEditor-S3QI5MHO.js').then((m) => ({ default: m.ScheduleEditor }))
|
|
15449
15594
|
);
|
|
15450
15595
|
function ComingSoon({ icon: Icon, title, description }) {
|
|
@@ -15525,7 +15670,7 @@ function ScheduleTab({ item }) {
|
|
|
15525
15670
|
}
|
|
15526
15671
|
);
|
|
15527
15672
|
}
|
|
15528
|
-
return /* @__PURE__ */ jsx(
|
|
15673
|
+
return /* @__PURE__ */ jsx(React65__default.Suspense, { fallback: null, children: /* @__PURE__ */ jsx(ScheduleEditor, { assigneeId: item.id }) });
|
|
15529
15674
|
}
|
|
15530
15675
|
var PERSON_DETAIL_TABS = [
|
|
15531
15676
|
{ id: "schedule", label: "Schedule", icon: "CalendarDays", component: ScheduleTab, visibleFor: ["staff"] },
|
|
@@ -15831,6 +15976,10 @@ var SUBJECT_DETAIL_TABS = [
|
|
|
15831
15976
|
{ id: "history", label: "History", component: SubjectHistoryTab },
|
|
15832
15977
|
{ id: "documents", label: "Documents", component: SubjectDocumentsTab }
|
|
15833
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
|
+
}
|
|
15834
15983
|
function formatValue3(field, value, t) {
|
|
15835
15984
|
if (value == null || value === "") return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/50", children: "\u2014" });
|
|
15836
15985
|
if (field.renderCell) return field.renderCell(value, {});
|
|
@@ -15902,7 +16051,7 @@ function InlineEditor({
|
|
|
15902
16051
|
}) {
|
|
15903
16052
|
const [draft, setDraft] = useState(value ?? "");
|
|
15904
16053
|
const [saving, setSaving] = useState(false);
|
|
15905
|
-
const inputRef =
|
|
16054
|
+
const inputRef = React65__default.useRef(null);
|
|
15906
16055
|
useEffect(() => {
|
|
15907
16056
|
inputRef.current?.focus();
|
|
15908
16057
|
if (inputRef.current instanceof HTMLInputElement) inputRef.current.select();
|
|
@@ -16178,7 +16327,7 @@ function CrudDetailPage({
|
|
|
16178
16327
|
const newHash = value === "overview" ? detailPath : `${detailPath}/${value}`;
|
|
16179
16328
|
window.history.replaceState(null, "", `#${newHash}`);
|
|
16180
16329
|
}, [basePath, item.id, embedded]);
|
|
16181
|
-
const headerNode =
|
|
16330
|
+
const headerNode = React65__default.useMemo(
|
|
16182
16331
|
() => embedded ? null : /* @__PURE__ */ jsx(SubpageHeader, { title: displayValue, parentLabel: namePlural, onBack }),
|
|
16183
16332
|
[embedded, displayValue, namePlural, onBack]
|
|
16184
16333
|
);
|
|
@@ -16204,7 +16353,7 @@ function CrudDetailPage({
|
|
|
16204
16353
|
] }),
|
|
16205
16354
|
subtitleValue && /* @__PURE__ */ jsx("p", { className: `text-muted-foreground mt-0.5 ${embedded ? "text-xs" : ""}`, children: subtitleValue })
|
|
16206
16355
|
] }),
|
|
16207
|
-
/* @__PURE__ */ jsxs(
|
|
16356
|
+
/* @__PURE__ */ jsxs(ActionSlot, { embedded, children: [
|
|
16208
16357
|
/* @__PURE__ */ jsx(WidgetSlot, { zone: headerActionsZone, item, entityId, embedded }),
|
|
16209
16358
|
onEdit && /* @__PURE__ */ jsxs(Button, { variant: "outline", size: embedded ? "xs" : "sm", onClick: onEdit, className: embedded ? "h-7 px-2 text-xs gap-1" : "", children: [
|
|
16210
16359
|
/* @__PURE__ */ jsx(Edit, { className: embedded ? "h-3 w-3" : "h-4 w-4 mr-1.5" }),
|
|
@@ -16231,7 +16380,7 @@ function CrudDetailPage({
|
|
|
16231
16380
|
})
|
|
16232
16381
|
] }),
|
|
16233
16382
|
/* @__PURE__ */ jsx(TabsContent, { value: "overview", className: embedded ? "mt-2" : "mt-4", children: /* @__PURE__ */ jsx(OverviewTab, { entityDef, item, compact: embedded, onFieldSave }) }),
|
|
16234
|
-
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))
|
|
16235
16384
|
] }),
|
|
16236
16385
|
/* @__PURE__ */ jsx(WidgetSlot, { zone: widgetZone }),
|
|
16237
16386
|
legacyWidgetZone !== widgetZone && /* @__PURE__ */ jsx(WidgetSlot, { zone: legacyWidgetZone }),
|
|
@@ -16283,7 +16432,7 @@ function useFieldRules(entityKey) {
|
|
|
16283
16432
|
};
|
|
16284
16433
|
}, [entityKey, fieldRules]);
|
|
16285
16434
|
}
|
|
16286
|
-
var ImportWizard2 =
|
|
16435
|
+
var ImportWizard2 = React65__default.lazy(
|
|
16287
16436
|
() => import('./ImportWizard-CISHGNQC.js').then((m) => ({ default: m.ImportWizard }))
|
|
16288
16437
|
);
|
|
16289
16438
|
var PAGE_SIZE = 50;
|
|
@@ -16395,7 +16544,7 @@ function useCrudColumns(entityDef, options) {
|
|
|
16395
16544
|
return tanCols;
|
|
16396
16545
|
}, [cols, displayField, options?.basePath, options?.onDelete, options?.feature, options?.readOnly]);
|
|
16397
16546
|
}
|
|
16398
|
-
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 }) {
|
|
16399
16548
|
const store = useStore();
|
|
16400
16549
|
const t = useTranslation();
|
|
16401
16550
|
const normalizedBasePath = normalizeCrudBasePath(basePath);
|
|
@@ -16672,6 +16821,7 @@ function CrudPage({ entityDef: rawEntityDef, useStore, basePath, display, featur
|
|
|
16672
16821
|
onExport: handleExport,
|
|
16673
16822
|
feature,
|
|
16674
16823
|
readOnly,
|
|
16824
|
+
embedded,
|
|
16675
16825
|
navTabs,
|
|
16676
16826
|
activeNavTab,
|
|
16677
16827
|
stats: stats?.(store.items, store.total),
|
|
@@ -16744,7 +16894,7 @@ function CrudPage({ entityDef: rawEntityDef, useStore, basePath, display, featur
|
|
|
16744
16894
|
displayValue: deleteItem ? deleteItem[displayField] : void 0
|
|
16745
16895
|
}
|
|
16746
16896
|
),
|
|
16747
|
-
/* @__PURE__ */ jsx(
|
|
16897
|
+
/* @__PURE__ */ jsx(React65__default.Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
|
|
16748
16898
|
ImportWizard2,
|
|
16749
16899
|
{
|
|
16750
16900
|
open: importOpen,
|
|
@@ -17236,7 +17386,7 @@ function FieldRulesSettings({ entities, rules: initialRules, onSave }) {
|
|
|
17236
17386
|
const [saving, setSaving] = useState(false);
|
|
17237
17387
|
const [search, setSearch] = useState("");
|
|
17238
17388
|
const [showMore, setShowMore] = useState(false);
|
|
17239
|
-
|
|
17389
|
+
React65.useEffect(() => {
|
|
17240
17390
|
setDraft(initialRules);
|
|
17241
17391
|
}, [initialRules]);
|
|
17242
17392
|
const isDirty = useMemo(
|
|
@@ -17357,16 +17507,10 @@ function FieldRulesSettings({ entities, rules: initialRules, onSave }) {
|
|
|
17357
17507
|
entity.entityKey
|
|
17358
17508
|
));
|
|
17359
17509
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
17360
|
-
/* @__PURE__ */ jsxs(
|
|
17361
|
-
/* @__PURE__ */
|
|
17362
|
-
|
|
17363
|
-
|
|
17364
|
-
] }),
|
|
17365
|
-
/* @__PURE__ */ jsxs(Button, { onClick: handleSave, disabled: !isDirty || saving, className: "shrink-0", children: [
|
|
17366
|
-
saving && /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
17367
|
-
t("common.save")
|
|
17368
|
-
] })
|
|
17369
|
-
] }),
|
|
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
|
+
] }) }),
|
|
17370
17514
|
entities.length > 4 && /* @__PURE__ */ jsxs("div", { className: "relative max-w-sm", children: [
|
|
17371
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" }),
|
|
17372
17516
|
/* @__PURE__ */ jsx(
|
|
@@ -17513,7 +17657,7 @@ function UpgradeModal() {
|
|
|
17513
17657
|
}
|
|
17514
17658
|
function LimitProbe({ limitKey, onReport }) {
|
|
17515
17659
|
const info = useLimit(limitKey);
|
|
17516
|
-
|
|
17660
|
+
React65.useEffect(() => {
|
|
17517
17661
|
onReport(limitKey, info);
|
|
17518
17662
|
}, [limitKey, info, onReport]);
|
|
17519
17663
|
return null;
|
|
@@ -17526,16 +17670,16 @@ function SoftLimitBanner({ keys }) {
|
|
|
17526
17670
|
if (params) for (const [k, val] of Object.entries(params)) v = v.replace(`{${k}}`, String(val)).replace(`{{${k}}}`, String(val));
|
|
17527
17671
|
return v;
|
|
17528
17672
|
};
|
|
17529
|
-
const [over, setOver] =
|
|
17530
|
-
const [dismissed, setDismissed] =
|
|
17531
|
-
const report =
|
|
17673
|
+
const [over, setOver] = React65.useState({});
|
|
17674
|
+
const [dismissed, setDismissed] = React65.useState({});
|
|
17675
|
+
const report = React65.useCallback((key, info) => {
|
|
17532
17676
|
const isOver = !info.unlimited && !info.loading && info.used > info.max;
|
|
17533
17677
|
setOver((prev) => {
|
|
17534
17678
|
if (isOver === Boolean(prev[key])) return prev;
|
|
17535
17679
|
return { ...prev, [key]: isOver };
|
|
17536
17680
|
});
|
|
17537
17681
|
}, []);
|
|
17538
|
-
const monitored =
|
|
17682
|
+
const monitored = React65.useMemo(() => Array.from(new Set(keys)), [keys]);
|
|
17539
17683
|
const activeKey = monitored.find((k) => over[k] && !dismissed[k]);
|
|
17540
17684
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
17541
17685
|
monitored.map((k) => /* @__PURE__ */ jsx(LimitProbe, { limitKey: k, onReport: report }, k)),
|
|
@@ -17558,11 +17702,11 @@ function SoftLimitBanner({ keys }) {
|
|
|
17558
17702
|
] })
|
|
17559
17703
|
] });
|
|
17560
17704
|
}
|
|
17561
|
-
var CommandPalette =
|
|
17705
|
+
var CommandPalette = React65.lazy(
|
|
17562
17706
|
() => import('./CommandPalette-U7MMA2WH.js').then((m) => ({ default: m.CommandPalette }))
|
|
17563
17707
|
);
|
|
17564
|
-
var SubscriptionPage =
|
|
17565
|
-
() => import('./SubscriptionPage-
|
|
17708
|
+
var SubscriptionPage = React65.lazy(
|
|
17709
|
+
() => import('./SubscriptionPage-4KP7DKA2.js').then((m) => ({ default: m.SubscriptionPage }))
|
|
17566
17710
|
);
|
|
17567
17711
|
function orgInitials(name) {
|
|
17568
17712
|
const words = name.trim().split(/\s+/).filter(Boolean);
|
|
@@ -17791,9 +17935,9 @@ function AccessDenied({ tr }) {
|
|
|
17791
17935
|
}
|
|
17792
17936
|
function AdminNotifications() {
|
|
17793
17937
|
const { notifications, unreadCount, fetchNotifications, markAsRead, markAllAsRead } = useNotifications();
|
|
17794
|
-
const [open, setOpen] =
|
|
17795
|
-
const fetchedRef =
|
|
17796
|
-
|
|
17938
|
+
const [open, setOpen] = React65.useState(false);
|
|
17939
|
+
const fetchedRef = React65.useRef(false);
|
|
17940
|
+
React65.useEffect(() => {
|
|
17797
17941
|
if (fetchedRef.current) return;
|
|
17798
17942
|
fetchedRef.current = true;
|
|
17799
17943
|
void fetchNotifications();
|
|
@@ -17910,7 +18054,7 @@ function buildSettingsTabs(pluginTabs, can, hasSystem, t, showOrgSettings, hasBi
|
|
|
17910
18054
|
// sidebar ICON_MAP, which made the settings rail fall back to Home.
|
|
17911
18055
|
icon: /* @__PURE__ */ jsx(CreditCard, { className: "h-4 w-4" }),
|
|
17912
18056
|
iconName: "CreditCard",
|
|
17913
|
-
component: /* @__PURE__ */ jsx(
|
|
18057
|
+
component: /* @__PURE__ */ jsx(React65.Suspense, { fallback: null, children: /* @__PURE__ */ jsx(SubscriptionPage, {}) })
|
|
17914
18058
|
});
|
|
17915
18059
|
}
|
|
17916
18060
|
if (showOrgSettings) {
|
|
@@ -17934,9 +18078,9 @@ function buildSettingsTabs(pluginTabs, can, hasSystem, t, showOrgSettings, hasBi
|
|
|
17934
18078
|
settingsTabs.push({
|
|
17935
18079
|
id: tab.id,
|
|
17936
18080
|
label: translated === labelKey ? tab.label : translated,
|
|
17937
|
-
icon:
|
|
18081
|
+
icon: React65.createElement(IconComp, { className: "h-4 w-4" }),
|
|
17938
18082
|
iconName: tab.icon ?? "Puzzle",
|
|
17939
|
-
component:
|
|
18083
|
+
component: React65.createElement(tab.component),
|
|
17940
18084
|
// Flag plugin-contributed tabs so SettingsPage draws the core/plugins divider.
|
|
17941
18085
|
isPlugin: true,
|
|
17942
18086
|
group: tab.group
|
|
@@ -17950,7 +18094,7 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
17950
18094
|
const can = usePermissionOptional();
|
|
17951
18095
|
const access = useAccessOptional();
|
|
17952
18096
|
const currentProfile = usePermissionsStore((s) => s.currentProfile);
|
|
17953
|
-
const hasSystem =
|
|
18097
|
+
const hasSystem = React65.useCallback(
|
|
17954
18098
|
(perm) => {
|
|
17955
18099
|
if (!currentProfile) return true;
|
|
17956
18100
|
if (currentProfile.id === "owner" || currentProfile.name?.toLowerCase() === "owner") return true;
|
|
@@ -17964,20 +18108,20 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
17964
18108
|
};
|
|
17965
18109
|
const path = useAdminPath();
|
|
17966
18110
|
const { user, signOut } = useAuth();
|
|
17967
|
-
|
|
18111
|
+
React65.useEffect(() => installGlobalErrorHandlers(), []);
|
|
17968
18112
|
const railOpen = useRightRailStore((s) => s.open);
|
|
17969
18113
|
const railHasPanels = useRightRailStore((s) => s.panels.length > 0);
|
|
17970
18114
|
const rightRail = railHasPanels ? /* @__PURE__ */ jsx(RightRail, { frame: contentFrame }) : null;
|
|
17971
18115
|
const setRailMounted = useRightRailStore((s) => s.setMounted);
|
|
17972
|
-
|
|
18116
|
+
React65.useEffect(() => {
|
|
17973
18117
|
setRailMounted(true);
|
|
17974
18118
|
return () => setRailMounted(false);
|
|
17975
18119
|
}, [setRailMounted]);
|
|
17976
18120
|
useConnectorOAuthReturn();
|
|
17977
18121
|
const railWidthLive = useRightRailStore((s) => s.width);
|
|
17978
18122
|
const setSidebarCollapsed = useLayoutStore((s) => s.setSidebarCollapsed);
|
|
17979
|
-
const railAutoCollapsedRef =
|
|
17980
|
-
|
|
18123
|
+
const railAutoCollapsedRef = React65.useRef(false);
|
|
18124
|
+
React65.useEffect(() => {
|
|
17981
18125
|
if (layout !== "sidebar") return;
|
|
17982
18126
|
const SIDEBAR_EXPANDED = 224;
|
|
17983
18127
|
const MIN_CONTENT = 620;
|
|
@@ -17999,20 +18143,20 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
17999
18143
|
window.addEventListener("resize", apply);
|
|
18000
18144
|
return () => window.removeEventListener("resize", apply);
|
|
18001
18145
|
}, [railOpen, railWidthLive, layout, setSidebarCollapsed]);
|
|
18002
|
-
const [railWidth] =
|
|
18146
|
+
const [railWidth] = React65.useState(() => readRightRailWidth());
|
|
18003
18147
|
const billingPlans = useBillingStore((s) => s.plans);
|
|
18004
18148
|
const hasBilling = billingPlans.length > 0;
|
|
18005
18149
|
const orgPlan = useTenantOptional()?.org?.plan;
|
|
18006
|
-
const planBadge =
|
|
18150
|
+
const planBadge = React65.useMemo(
|
|
18007
18151
|
() => hasBilling ? resolvePlanBadge(orgPlan, billingPlans) : null,
|
|
18008
18152
|
[hasBilling, orgPlan, billingPlans]
|
|
18009
18153
|
);
|
|
18010
|
-
const softLimitKeys =
|
|
18154
|
+
const softLimitKeys = React65.useMemo(() => {
|
|
18011
18155
|
const plan = billingPlans.find((p) => p.id === (orgPlan || "free"));
|
|
18012
18156
|
return Object.keys(getPlanEntitlements(plan)?.limits ?? {});
|
|
18013
18157
|
}, [billingPlans, orgPlan]);
|
|
18014
18158
|
const navContributions = useNavContributionsStore((s) => s.contributions);
|
|
18015
|
-
const navigation =
|
|
18159
|
+
const navigation = React65.useMemo(() => {
|
|
18016
18160
|
const contributed = Object.values(navContributions).flat();
|
|
18017
18161
|
const flat = [...runtime.navigation, ...contributed].map((entry) => ({ ...navEntryToItem(entry), position: entry.position, indexChild: entry.indexChild })).sort(compareNavigation);
|
|
18018
18162
|
const items = [];
|
|
@@ -18059,7 +18203,7 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
18059
18203
|
}, [runtime.navigation, navContributions, pages, access]);
|
|
18060
18204
|
const commandPaletteOpen = useLayoutStore((s) => s.commandPaletteOpen);
|
|
18061
18205
|
const setCommandPaletteOpen = useLayoutStore((s) => s.setCommandPaletteOpen);
|
|
18062
|
-
const commandItems =
|
|
18206
|
+
const commandItems = React65.useMemo(() => {
|
|
18063
18207
|
const navGroup = tr("layout.commandPalette.navigation", "Navigation");
|
|
18064
18208
|
const items = [];
|
|
18065
18209
|
for (const nav of navigation) {
|
|
@@ -18071,7 +18215,7 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
18071
18215
|
return items;
|
|
18072
18216
|
}, [navigation]);
|
|
18073
18217
|
const globalSearch = useGlobalSearch();
|
|
18074
|
-
const routes =
|
|
18218
|
+
const routes = React65.useMemo(() => {
|
|
18075
18219
|
const list = [];
|
|
18076
18220
|
const entityRouteMap = /* @__PURE__ */ new Map();
|
|
18077
18221
|
for (const r of runtime.routes) {
|
|
@@ -18093,25 +18237,25 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
18093
18237
|
setEntityRouteMap(entityRouteMap);
|
|
18094
18238
|
return list.sort((a, b) => routeScore(b.path) - routeScore(a.path));
|
|
18095
18239
|
}, [runtime.routes, pages, showSettings]);
|
|
18096
|
-
const match =
|
|
18240
|
+
const match = React65.useMemo(() => {
|
|
18097
18241
|
for (const r of routes) {
|
|
18098
18242
|
const params = matchRoute(r.path, path);
|
|
18099
18243
|
if (params) return { route: r, params };
|
|
18100
18244
|
}
|
|
18101
18245
|
return null;
|
|
18102
18246
|
}, [routes, path]);
|
|
18103
|
-
|
|
18247
|
+
React65.useEffect(() => {
|
|
18104
18248
|
if (!match && (path === "/" || path === "") && navigation.length > 0) {
|
|
18105
18249
|
navigateTo(navigation[0].route);
|
|
18106
18250
|
}
|
|
18107
18251
|
}, [match, path, navigation]);
|
|
18108
18252
|
const ActiveComponent = match?.route.Component;
|
|
18109
18253
|
const activeParams = match?.params ?? {};
|
|
18110
|
-
const settingsTabs =
|
|
18254
|
+
const settingsTabs = React65.useMemo(
|
|
18111
18255
|
() => buildSettingsTabs(runtime.settingsTabs, can, hasSystem, t, showOrgSettings, hasBilling),
|
|
18112
18256
|
[runtime.settingsTabs, can, hasSystem, t, showOrgSettings, hasBilling]
|
|
18113
18257
|
);
|
|
18114
|
-
const profileRoute =
|
|
18258
|
+
const profileRoute = React65.useMemo(() => {
|
|
18115
18259
|
const explicit = routes.find((r) => r.path === "/perfil" || r.path === "/profile");
|
|
18116
18260
|
if (explicit) return explicit.path;
|
|
18117
18261
|
return showSettings ? "/settings/profile" : null;
|
|
@@ -18119,7 +18263,7 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
18119
18263
|
const onProfile = profileRoute ? () => navigateTo(profileRoute) : void 0;
|
|
18120
18264
|
const onBilling = hasBilling && showSettings ? () => navigateTo("/settings/subscription") : void 0;
|
|
18121
18265
|
const coreSettingsTabs = useCoreSettingsTabs({ showCompany: showBranding, showBranding });
|
|
18122
|
-
const allSettingsTabs =
|
|
18266
|
+
const allSettingsTabs = React65.useMemo(
|
|
18123
18267
|
() => {
|
|
18124
18268
|
const hidden = new Set(hiddenSettingsTabs ?? []);
|
|
18125
18269
|
return [...coreSettingsTabs, ...settingsTabs].filter((tab) => !hidden.has(tab.id));
|
|
@@ -18131,12 +18275,12 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
18131
18275
|
const contextualNav = useContextualNavStore((s) => s.nav);
|
|
18132
18276
|
const moduleRail = !inSettings && layout === "sidebar" && contextualNav && (path === contextualNav.base || path.startsWith(contextualNav.base + "/")) ? contextualNav : null;
|
|
18133
18277
|
const activeSettingsTab = inSettings ? path === "/settings" ? null : path.slice("/settings/".length).split("/")[0] : void 0;
|
|
18134
|
-
const settingsTabDef =
|
|
18278
|
+
const settingsTabDef = React65.useMemo(() => {
|
|
18135
18279
|
if (!showSettings || !path.startsWith("/settings/")) return void 0;
|
|
18136
18280
|
const id = path.slice("/settings/".length).split("/")[0];
|
|
18137
18281
|
return allSettingsTabs.find((tab) => tab.id === id);
|
|
18138
18282
|
}, [showSettings, path, allSettingsTabs]);
|
|
18139
|
-
const settingsNavigation =
|
|
18283
|
+
const settingsNavigation = React65.useMemo(
|
|
18140
18284
|
() => allSettingsTabs.map((tab) => ({
|
|
18141
18285
|
id: `settings:${tab.id}`,
|
|
18142
18286
|
label: tab.label,
|
|
@@ -18154,10 +18298,10 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
18154
18298
|
const shellUser = user ? { fullName: user.fullName ?? user.email, email: user.email, avatarUrl: user.avatarUrl } : void 0;
|
|
18155
18299
|
const moduleVariant = moduleNav ?? (layout === "sidebar" ? "tabs" : "rail");
|
|
18156
18300
|
const setRailAvailable = useContextualNavStore((s) => s.setRailAvailable);
|
|
18157
|
-
|
|
18301
|
+
React65.useEffect(() => {
|
|
18158
18302
|
setRailAvailable(layout === "sidebar" && moduleVariant !== "rail");
|
|
18159
18303
|
}, [layout, moduleVariant, setRailAvailable]);
|
|
18160
|
-
const activePageTitle =
|
|
18304
|
+
const activePageTitle = React65.useMemo(() => {
|
|
18161
18305
|
if (settingsTabDef) return settingsTabDef.label;
|
|
18162
18306
|
if (path === "/settings" || path.startsWith("/settings/")) return tr("common.settings", "Settings");
|
|
18163
18307
|
if (match?.route.title) return match.route.title;
|
|
@@ -18167,7 +18311,7 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
18167
18311
|
);
|
|
18168
18312
|
return hit?.label ?? candidates.find((n) => n.route === "/")?.label ?? "";
|
|
18169
18313
|
}, [navigation, path, tr, match, settingsTabDef]);
|
|
18170
|
-
const parentBack =
|
|
18314
|
+
const parentBack = React65.useMemo(() => {
|
|
18171
18315
|
if (settingsTabDef) {
|
|
18172
18316
|
return { onBack: () => navigateTo("/settings"), label: tr("common.settings", "Settings") };
|
|
18173
18317
|
}
|
|
@@ -18246,11 +18390,15 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
18246
18390
|
onEdit: site?.editRoute ? () => navigateTo(site.editRoute) : void 0
|
|
18247
18391
|
}
|
|
18248
18392
|
),
|
|
18393
|
+
/* @__PURE__ */ jsx(WidgetSlot, { zone: "shell.sidebar.footer" }),
|
|
18249
18394
|
sidebarFooter
|
|
18250
18395
|
] }),
|
|
18251
18396
|
orgSwitcher: layout === "topbar" && showOrgSwitcher ? /* @__PURE__ */ jsx(WorkspaceSwitcher, { variant: "topbar" }) : void 0,
|
|
18252
|
-
topbarStart: /* @__PURE__ */ jsx(WidgetSlot, { zone: "shell.topbar.start" }),
|
|
18253
|
-
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
|
+
] }),
|
|
18254
18402
|
rightRail,
|
|
18255
18403
|
rightRailOpen: railOpen,
|
|
18256
18404
|
defaultRightRailWidth: railWidth,
|
|
@@ -18297,10 +18445,15 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
18297
18445
|
userId: user?.id,
|
|
18298
18446
|
backLabel: parentBack?.label,
|
|
18299
18447
|
onBack: parentBack ? parentBack.onBack : () => navigateTo(homeRoute),
|
|
18300
|
-
children: match?.route.fullBleed ? /* @__PURE__ */ jsx("div", { className: "h-full min-h-0 overflow-hidden", children: activeContent }) :
|
|
18301
|
-
|
|
18302
|
-
|
|
18303
|
-
|
|
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
|
+
)
|
|
18304
18457
|
},
|
|
18305
18458
|
match?.route.path ?? path
|
|
18306
18459
|
)
|
|
@@ -18319,7 +18472,7 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
|
|
|
18319
18472
|
]
|
|
18320
18473
|
}
|
|
18321
18474
|
),
|
|
18322
|
-
/* @__PURE__ */ jsx(
|
|
18475
|
+
/* @__PURE__ */ jsx(React65.Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
|
|
18323
18476
|
CommandPalette,
|
|
18324
18477
|
{
|
|
18325
18478
|
commands: commandItems,
|
|
@@ -18487,7 +18640,7 @@ function buildI18nConfig(config) {
|
|
|
18487
18640
|
function BillingInitializer({ config }) {
|
|
18488
18641
|
const setPlans = useBillingStore((s) => s.setPlans);
|
|
18489
18642
|
const setCheckout = useBillingStore((s) => s.setCheckout);
|
|
18490
|
-
|
|
18643
|
+
React65.useEffect(() => {
|
|
18491
18644
|
if (config.billing?.plans) setPlans(config.billing.plans.map(normalizeBillingPlan));
|
|
18492
18645
|
setCheckout(config.billing?.onCheckout ?? null);
|
|
18493
18646
|
}, [config.billing, setPlans, setCheckout]);
|
|
@@ -18514,7 +18667,7 @@ function ThemeInitializer({ config }) {
|
|
|
18514
18667
|
const initialize = useThemeStore((s) => s.initialize);
|
|
18515
18668
|
const setOverrides = useThemeStore((s) => s.setOverrides);
|
|
18516
18669
|
const setMode = useThemeStore((s) => s.setMode);
|
|
18517
|
-
|
|
18670
|
+
React65.useEffect(() => {
|
|
18518
18671
|
if (config.theme) {
|
|
18519
18672
|
const resolved = isSaasTheme(config.theme) ? resolveTheme(config.theme) : config.theme;
|
|
18520
18673
|
setOverrides(resolved);
|
|
@@ -18527,20 +18680,20 @@ function ThemeInitializer({ config }) {
|
|
|
18527
18680
|
return null;
|
|
18528
18681
|
}
|
|
18529
18682
|
function PersistentCacheInitializer() {
|
|
18530
|
-
|
|
18683
|
+
React65.useEffect(() => {
|
|
18531
18684
|
attachPersistentCache();
|
|
18532
18685
|
void getPersistentCache()?.hydrate();
|
|
18533
18686
|
}, []);
|
|
18534
18687
|
return null;
|
|
18535
18688
|
}
|
|
18536
18689
|
function FayzEventBridgeInitializer({ config }) {
|
|
18537
|
-
|
|
18690
|
+
React65.useEffect(() => startFayzEventBridge(config.chat?.agent), [config.chat?.agent]);
|
|
18538
18691
|
return null;
|
|
18539
18692
|
}
|
|
18540
18693
|
function TeamInitializer({ config }) {
|
|
18541
18694
|
const setTeamPersonKinds = useOrganizationStore((s) => s.setTeamPersonKinds);
|
|
18542
18695
|
const kinds = config.team?.personKinds;
|
|
18543
|
-
|
|
18696
|
+
React65.useEffect(() => {
|
|
18544
18697
|
setTeamPersonKinds(kinds ?? []);
|
|
18545
18698
|
}, [setTeamPersonKinds, kinds]);
|
|
18546
18699
|
return null;
|
|
@@ -18556,7 +18709,7 @@ function ChatRailPanel({ config }) {
|
|
|
18556
18709
|
const agent = config.chat?.agent;
|
|
18557
18710
|
const voice = config.chat?.voice;
|
|
18558
18711
|
const whatsapp = config.chat?.whatsapp;
|
|
18559
|
-
const Component2 =
|
|
18712
|
+
const Component2 = React65.useMemo(() => {
|
|
18560
18713
|
const Panel = () => /* @__PURE__ */ jsx(
|
|
18561
18714
|
ChatConversation,
|
|
18562
18715
|
{
|
|
@@ -18573,15 +18726,15 @@ function ChatRailPanel({ config }) {
|
|
|
18573
18726
|
const conversations = useChatStore((s) => s.conversations);
|
|
18574
18727
|
const setConversations = useChatStore((s) => s.setConversations);
|
|
18575
18728
|
const user = useAuthStore((s) => s.user);
|
|
18576
|
-
const connection =
|
|
18577
|
-
|
|
18729
|
+
const connection = React65.useMemo(() => resolveFayzAgentConnection(agent), [agent]);
|
|
18730
|
+
React65.useEffect(() => {
|
|
18578
18731
|
if (!connection) return;
|
|
18579
18732
|
getFayzAgentClient(connection).listConversations(user?.id).then(setConversations).catch(() => {
|
|
18580
18733
|
});
|
|
18581
18734
|
}, [connection, user?.id, setConversations]);
|
|
18582
18735
|
const persona = useAssistantInviteStore((s) => s.invite?.persona);
|
|
18583
18736
|
useRightRailPanel(
|
|
18584
|
-
|
|
18737
|
+
React65.useMemo(
|
|
18585
18738
|
() => ({
|
|
18586
18739
|
id: "chat",
|
|
18587
18740
|
label: persona ?? "Chat",
|
|
@@ -18593,17 +18746,17 @@ function ChatRailPanel({ config }) {
|
|
|
18593
18746
|
[Component2, conversations.length, persona]
|
|
18594
18747
|
)
|
|
18595
18748
|
);
|
|
18596
|
-
|
|
18749
|
+
React65.useEffect(() => {
|
|
18597
18750
|
if (chatOpen) openPanel("chat");
|
|
18598
18751
|
}, [chatOpen, openPanel]);
|
|
18599
|
-
|
|
18752
|
+
React65.useEffect(() => {
|
|
18600
18753
|
if (!(railOpen && railActive === "chat")) setChatOpen(false);
|
|
18601
18754
|
}, [railOpen, railActive, setChatOpen]);
|
|
18602
18755
|
return null;
|
|
18603
18756
|
}
|
|
18604
18757
|
function AdminProviders({ config, children }) {
|
|
18605
18758
|
const currentOrg = useOrganizationStore((s) => s.currentOrg);
|
|
18606
|
-
const hasFayzAgent =
|
|
18759
|
+
const hasFayzAgent = React65.useMemo(
|
|
18607
18760
|
() => !!resolveFayzAgentConnection(config.chat?.agent),
|
|
18608
18761
|
[config.chat?.agent]
|
|
18609
18762
|
);
|
|
@@ -18611,7 +18764,7 @@ function AdminProviders({ config, children }) {
|
|
|
18611
18764
|
const surface = config.chat?.surface ?? "dock";
|
|
18612
18765
|
const onConsentScreen = typeof window !== "undefined" && window.location.pathname.replace(/\/+$/, "").endsWith("/connect");
|
|
18613
18766
|
const showFab = assistantEnabled && surface === "dock" && !onConsentScreen;
|
|
18614
|
-
const resolved =
|
|
18767
|
+
const resolved = React65.useMemo(() => {
|
|
18615
18768
|
if (config.supabaseUrl && config.supabaseAnonKey) {
|
|
18616
18769
|
createFayzSupabaseClient(config.supabaseUrl, config.supabaseAnonKey);
|
|
18617
18770
|
}
|
|
@@ -18627,7 +18780,7 @@ function AdminProviders({ config, children }) {
|
|
|
18627
18780
|
};
|
|
18628
18781
|
}, [config]);
|
|
18629
18782
|
const path = useAdminPath();
|
|
18630
|
-
const runtime =
|
|
18783
|
+
const runtime = React65.useMemo(
|
|
18631
18784
|
() => resolvePluginRuntime({
|
|
18632
18785
|
plugins: resolved.plugins,
|
|
18633
18786
|
context: {
|
|
@@ -18939,8 +19092,8 @@ function manifestToFayzConfig(manifest, surfaceName) {
|
|
|
18939
19092
|
};
|
|
18940
19093
|
}
|
|
18941
19094
|
function AdminScaffold({ manifest, surface }) {
|
|
18942
|
-
const config =
|
|
18943
|
-
const authShellProps =
|
|
19095
|
+
const config = React65.useMemo(() => manifestToFayzConfig(manifest, surface), [manifest, surface]);
|
|
19096
|
+
const authShellProps = React65.useMemo(() => getAuthShellProps(config.auth), [config.auth]);
|
|
18944
19097
|
return /* @__PURE__ */ jsx(AdminProviders, { config, children: /* @__PURE__ */ jsx(
|
|
18945
19098
|
AdminShell,
|
|
18946
19099
|
{
|
|
@@ -19219,10 +19372,10 @@ function OrderDetailView(props) {
|
|
|
19219
19372
|
// três colunas viravam uma tira de 280px que quebrava todo rótulo.
|
|
19220
19373
|
/* @__PURE__ */ jsxs("div", { className: "fz-container space-y-4", children: [
|
|
19221
19374
|
/* @__PURE__ */ jsx(PageHeader, { title, parentLabel: backLabel, onBack }),
|
|
19222
|
-
|
|
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: [
|
|
19223
19377
|
props.badgesNode ?? badges.map((b, i) => /* @__PURE__ */ jsx(Badge15, { badge: b }, i)),
|
|
19224
|
-
subtitle && /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: subtitle })
|
|
19225
|
-
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 })
|
|
19226
19379
|
] }),
|
|
19227
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: [
|
|
19228
19381
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
|
|
@@ -19310,7 +19463,9 @@ var ITEM_LABELS = {
|
|
|
19310
19463
|
adjustments: "Desconto / acr\xE9scimo",
|
|
19311
19464
|
removeAdjustments: "Remover ajustes",
|
|
19312
19465
|
remove: "Remover item",
|
|
19313
|
-
done: "Conclu\xEDdo"
|
|
19466
|
+
done: "Conclu\xEDdo",
|
|
19467
|
+
create: "Cadastrar",
|
|
19468
|
+
clear: "Limpar"
|
|
19314
19469
|
};
|
|
19315
19470
|
function OrderFormItemRow({
|
|
19316
19471
|
index,
|
|
@@ -19337,7 +19492,7 @@ function OrderFormItemRow({
|
|
|
19337
19492
|
const total = quantity * unitPrice - (discount ?? 0) + (surcharge ?? 0);
|
|
19338
19493
|
const kindLabel = itemTypes.find((tp) => tp.value === itemKind)?.label ?? itemKind;
|
|
19339
19494
|
const hasAdjustments = (discount ?? 0) > 0 || (surcharge ?? 0) > 0;
|
|
19340
|
-
const [showAdjustments, setShowAdjustments] =
|
|
19495
|
+
const [showAdjustments, setShowAdjustments] = React65.useState(hasAdjustments);
|
|
19341
19496
|
const lookup2 = entityLookups[itemKind];
|
|
19342
19497
|
function handleFieldKeyDown(e) {
|
|
19343
19498
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
@@ -19412,6 +19567,12 @@ function OrderFormItemRow({
|
|
|
19412
19567
|
const results = await lookup2.search(q);
|
|
19413
19568
|
return results.map((r) => ({ id: r.id, label: r.label, subtitle: r.subtitle, group: r.group, data: r }));
|
|
19414
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,
|
|
19415
19576
|
placeholder: `${l.item}\u2026`,
|
|
19416
19577
|
renderOption: (opt) => /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
19417
19578
|
/* @__PURE__ */ jsx("p", { className: "truncate text-sm", children: opt.label }),
|
|
@@ -19607,7 +19768,7 @@ function OrderFormView({
|
|
|
19607
19768
|
parentLabel,
|
|
19608
19769
|
onBack,
|
|
19609
19770
|
badges,
|
|
19610
|
-
subtitle,
|
|
19771
|
+
subtitle: _subtitle,
|
|
19611
19772
|
actions,
|
|
19612
19773
|
banner,
|
|
19613
19774
|
children,
|
|
@@ -19618,11 +19779,8 @@ function OrderFormView({
|
|
|
19618
19779
|
// se cabem duas colunas é a LARGURA DESTA COLUNA, não a da janela.
|
|
19619
19780
|
/* @__PURE__ */ jsxs("div", { className: "fz-container space-y-4", children: [
|
|
19620
19781
|
/* @__PURE__ */ jsx(PageHeader, { title, parentLabel, onBack }),
|
|
19621
|
-
|
|
19622
|
-
|
|
19623
|
-
subtitle && /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: subtitle }),
|
|
19624
|
-
actions && /* @__PURE__ */ jsx("div", { className: "ml-auto flex flex-wrap items-center gap-2", children: actions })
|
|
19625
|
-
] }),
|
|
19782
|
+
actions && /* @__PURE__ */ jsx(PageHeaderActions, { children: actions }),
|
|
19783
|
+
badges && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2", children: badges }),
|
|
19626
19784
|
banner,
|
|
19627
19785
|
/* @__PURE__ */ jsxs("div", { className: "fz-split", children: [
|
|
19628
19786
|
/* @__PURE__ */ jsx("div", { className: "fz-container space-y-4", children }),
|
|
@@ -19633,13 +19791,12 @@ function OrderFormView({
|
|
|
19633
19791
|
}
|
|
19634
19792
|
OrderFormView.displayName = "OrderFormView";
|
|
19635
19793
|
function OrderFormSkeleton() {
|
|
19636
|
-
return
|
|
19637
|
-
|
|
19638
|
-
|
|
19639
|
-
|
|
19640
|
-
|
|
19641
|
-
|
|
19642
|
-
/* @__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: [
|
|
19643
19800
|
/* @__PURE__ */ jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card", children: [
|
|
19644
19801
|
/* @__PURE__ */ jsx("div", { className: "border-b px-4 py-3", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" }) }),
|
|
19645
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: [
|
|
@@ -19652,11 +19809,13 @@ function OrderFormSkeleton() {
|
|
|
19652
19809
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-20" }),
|
|
19653
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)) })
|
|
19654
19811
|
] }, i)) })
|
|
19655
|
-
] })
|
|
19656
|
-
|
|
19812
|
+
] }) })
|
|
19813
|
+
);
|
|
19657
19814
|
}
|
|
19658
19815
|
function OrderListView({
|
|
19659
|
-
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,
|
|
19660
19819
|
subtitle,
|
|
19661
19820
|
actions,
|
|
19662
19821
|
stats,
|
|
@@ -19674,10 +19833,10 @@ function OrderListView({
|
|
|
19674
19833
|
bulkActions,
|
|
19675
19834
|
rowId
|
|
19676
19835
|
}) {
|
|
19677
|
-
const [search, setSearch] =
|
|
19678
|
-
const [page, setPage] =
|
|
19679
|
-
const [rawSelection, setRawSelection] =
|
|
19680
|
-
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(
|
|
19681
19840
|
() => columns.map((c) => ({
|
|
19682
19841
|
id: c.key,
|
|
19683
19842
|
header: () => /* @__PURE__ */ jsx("div", { className: c.align === "right" ? "text-right" : "", children: c.header }),
|
|
@@ -19685,29 +19844,30 @@ function OrderListView({
|
|
|
19685
19844
|
})),
|
|
19686
19845
|
[columns]
|
|
19687
19846
|
);
|
|
19688
|
-
const filtered =
|
|
19847
|
+
const filtered = React65.useMemo(() => {
|
|
19689
19848
|
const term = search.trim().toLowerCase();
|
|
19690
19849
|
if (!term || !searchText) return rows;
|
|
19691
19850
|
return rows.filter((row) => searchText(row).toLowerCase().includes(term));
|
|
19692
19851
|
}, [rows, search, searchText]);
|
|
19693
|
-
|
|
19852
|
+
React65.useEffect(() => {
|
|
19694
19853
|
setPage(1);
|
|
19695
19854
|
}, [search]);
|
|
19696
19855
|
const paged = pageSize > 0 ? filtered.slice((page - 1) * pageSize, page * pageSize) : filtered;
|
|
19697
|
-
const getId =
|
|
19856
|
+
const getId = React65.useCallback(
|
|
19698
19857
|
(row) => rowId ? rowId(row) : String(row.id ?? ""),
|
|
19699
19858
|
[rowId]
|
|
19700
19859
|
);
|
|
19701
|
-
const pageIds =
|
|
19702
|
-
const selectedIds =
|
|
19860
|
+
const pageIds = React65.useMemo(() => paged.map(getId), [paged, getId]);
|
|
19861
|
+
const selectedIds = React65.useMemo(
|
|
19703
19862
|
() => rawSelection.filter((id) => pageIds.includes(id)),
|
|
19704
19863
|
[rawSelection, pageIds]
|
|
19705
19864
|
);
|
|
19706
|
-
const selectedRows =
|
|
19865
|
+
const selectedRows = React65.useMemo(
|
|
19707
19866
|
() => paged.filter((row) => selectedIds.includes(getId(row))),
|
|
19708
19867
|
[paged, selectedIds, getId]
|
|
19709
19868
|
);
|
|
19710
19869
|
const selectable = (bulkActions?.length ?? 0) > 0;
|
|
19870
|
+
const hasSelection = selectable && selectedIds.length > 0;
|
|
19711
19871
|
const barActions = (bulkActions ?? []).map((action) => ({
|
|
19712
19872
|
id: action.id,
|
|
19713
19873
|
label: action.label,
|
|
@@ -19729,38 +19889,31 @@ function OrderListView({
|
|
|
19729
19889
|
// `p-3 md:p-6` (AdminShell). Reaplicar `p-6 md:p-8` aqui empurrava a lista
|
|
19730
19890
|
// 32px à direita do título na barra de topo e de todas as outras telas.
|
|
19731
19891
|
/* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
19732
|
-
|
|
19733
|
-
|
|
19734
|
-
|
|
19735
|
-
|
|
19736
|
-
|
|
19737
|
-
tabs: navTabs,
|
|
19738
|
-
value: activeNavTab ?? navTabs[0].value,
|
|
19739
|
-
onChange: (v) => onNavTabChange?.(v)
|
|
19740
|
-
}
|
|
19741
|
-
),
|
|
19742
|
-
actions
|
|
19743
|
-
] }),
|
|
19744
|
-
!navTabs?.length && (title || subtitle || actions) && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
|
|
19745
|
-
title || subtitle ? /* @__PURE__ */ jsxs("div", { children: [
|
|
19746
|
-
title && /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold text-foreground", children: title }),
|
|
19747
|
-
subtitle && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: subtitle })
|
|
19748
|
-
] }) : /* @__PURE__ */ jsx("span", {}),
|
|
19749
|
-
actions
|
|
19750
|
-
] }),
|
|
19751
|
-
tiles.length > 0 && /* @__PURE__ */ jsx(StatTiles, { tiles, loading }),
|
|
19752
|
-
selectable && /* @__PURE__ */ jsx(
|
|
19753
|
-
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,
|
|
19754
19897
|
{
|
|
19755
|
-
|
|
19756
|
-
|
|
19757
|
-
|
|
19758
|
-
|
|
19759
|
-
actions: barActions
|
|
19898
|
+
className: "mb-0",
|
|
19899
|
+
tabs: navTabs,
|
|
19900
|
+
value: activeNavTab ?? navTabs[0].value,
|
|
19901
|
+
onChange: (v) => onNavTabChange?.(v)
|
|
19760
19902
|
}
|
|
19761
19903
|
),
|
|
19904
|
+
tiles.length > 0 && /* @__PURE__ */ jsx(StatTiles, { tiles, loading }),
|
|
19762
19905
|
/* @__PURE__ */ jsxs(Card, { className: "overflow-hidden", children: [
|
|
19763
|
-
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(
|
|
19764
19917
|
SearchField,
|
|
19765
19918
|
{
|
|
19766
19919
|
value: search,
|
|
@@ -19958,6 +20111,21 @@ function createArchetypeLookup(config) {
|
|
|
19958
20111
|
(row) => toResult(row, display, config.kindLabels)
|
|
19959
20112
|
);
|
|
19960
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
|
+
},
|
|
19961
20129
|
async getById(id) {
|
|
19962
20130
|
const supabase = getSupabaseClientOptional();
|
|
19963
20131
|
if (!supabase) return null;
|
|
@@ -20141,11 +20309,11 @@ function PersonTimeline({
|
|
|
20141
20309
|
pageSize,
|
|
20142
20310
|
activeSourceIds
|
|
20143
20311
|
});
|
|
20144
|
-
const toneBySource =
|
|
20312
|
+
const toneBySource = React65__default.useMemo(
|
|
20145
20313
|
() => new Map(sources2.map((s) => [s.id, s.tone ?? "neutral"])),
|
|
20146
20314
|
[sources2]
|
|
20147
20315
|
);
|
|
20148
|
-
const hrefFor =
|
|
20316
|
+
const hrefFor = React65__default.useCallback(
|
|
20149
20317
|
(item) => {
|
|
20150
20318
|
if (item.href) return item.href;
|
|
20151
20319
|
if (!recordPath || !item.targetTab) return void 0;
|
|
@@ -20188,19 +20356,19 @@ function PersonTimeline({
|
|
|
20188
20356
|
}
|
|
20189
20357
|
function createPlaceholder(title, description) {
|
|
20190
20358
|
return function PlaceholderPage() {
|
|
20191
|
-
return
|
|
20359
|
+
return React65__default.createElement(
|
|
20192
20360
|
"div",
|
|
20193
20361
|
{ className: "mx-auto max-w-4xl" },
|
|
20194
|
-
|
|
20195
|
-
description ?
|
|
20196
|
-
|
|
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(
|
|
20197
20365
|
"div",
|
|
20198
20366
|
{ className: "mt-8 flex items-center justify-center rounded-card border border-dashed border-border bg-card p-16" },
|
|
20199
|
-
|
|
20367
|
+
React65__default.createElement(
|
|
20200
20368
|
"div",
|
|
20201
20369
|
{ className: "text-center" },
|
|
20202
|
-
|
|
20203
|
-
|
|
20370
|
+
React65__default.createElement("p", { className: "text-lg font-medium text-muted-foreground" }, "Coming Soon"),
|
|
20371
|
+
React65__default.createElement(
|
|
20204
20372
|
"p",
|
|
20205
20373
|
{ className: "mt-1 text-sm text-muted-foreground/70" },
|
|
20206
20374
|
"This module is being built as a plugin."
|
|
@@ -20210,55 +20378,6 @@ function createPlaceholder(title, description) {
|
|
|
20210
20378
|
);
|
|
20211
20379
|
};
|
|
20212
20380
|
}
|
|
20213
|
-
function QuickActionsButton({ actions, className }) {
|
|
20214
|
-
const [open, setOpen] = useState(false);
|
|
20215
|
-
const ref = useRef(null);
|
|
20216
|
-
const variant = useModuleLayout() === "tabs" ? "default" : "outline";
|
|
20217
|
-
useEffect(() => {
|
|
20218
|
-
function handler(e) {
|
|
20219
|
-
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
20220
|
-
}
|
|
20221
|
-
document.addEventListener("mousedown", handler);
|
|
20222
|
-
return () => document.removeEventListener("mousedown", handler);
|
|
20223
|
-
}, []);
|
|
20224
|
-
if (actions.length === 0) return null;
|
|
20225
|
-
return /* @__PURE__ */ jsxs("div", { ref, className: cn("relative", className), children: [
|
|
20226
|
-
/* @__PURE__ */ jsxs(
|
|
20227
|
-
Button,
|
|
20228
|
-
{
|
|
20229
|
-
variant,
|
|
20230
|
-
size: "sm",
|
|
20231
|
-
onClick: () => setOpen(!open),
|
|
20232
|
-
className: cn(open && variant === "outline" && "bg-muted"),
|
|
20233
|
-
children: [
|
|
20234
|
-
/* @__PURE__ */ jsx(Plus, { className: cn("h-3.5 w-3.5 transition-transform duration-200", open && "rotate-45") }),
|
|
20235
|
-
/* @__PURE__ */ jsx("span", { children: "New" })
|
|
20236
|
-
]
|
|
20237
|
-
}
|
|
20238
|
-
),
|
|
20239
|
-
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) => {
|
|
20240
|
-
const Icon = action.icon ? ICON_MAP[action.icon] ?? Plus : Plus;
|
|
20241
|
-
return /* @__PURE__ */ jsxs(
|
|
20242
|
-
"button",
|
|
20243
|
-
{
|
|
20244
|
-
onClick: () => {
|
|
20245
|
-
action.action();
|
|
20246
|
-
setOpen(false);
|
|
20247
|
-
},
|
|
20248
|
-
className: "w-full flex items-center gap-3 rounded-lg px-3 py-2.5 text-left hover:bg-muted/50 transition-colors group",
|
|
20249
|
-
children: [
|
|
20250
|
-
/* @__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" }) }),
|
|
20251
|
-
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
20252
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: action.label }),
|
|
20253
|
-
action.description && /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground leading-tight", children: action.description })
|
|
20254
|
-
] })
|
|
20255
|
-
]
|
|
20256
|
-
},
|
|
20257
|
-
action.id
|
|
20258
|
-
);
|
|
20259
|
-
}) }) })
|
|
20260
|
-
] });
|
|
20261
|
-
}
|
|
20262
20381
|
function ModuleActionBar({
|
|
20263
20382
|
quickActions,
|
|
20264
20383
|
settingsPath,
|
|
@@ -20287,9 +20406,9 @@ function ModuleActionBar({
|
|
|
20287
20406
|
] });
|
|
20288
20407
|
}
|
|
20289
20408
|
function createPluginContext(displayName) {
|
|
20290
|
-
const ConfigContext =
|
|
20291
|
-
const ProviderContext =
|
|
20292
|
-
const StoreContext =
|
|
20409
|
+
const ConfigContext = React65__default.createContext(null);
|
|
20410
|
+
const ProviderContext = React65__default.createContext(null);
|
|
20411
|
+
const StoreContext = React65__default.createContext(null);
|
|
20293
20412
|
const ContextProvider = ({
|
|
20294
20413
|
config,
|
|
20295
20414
|
provider,
|
|
@@ -20298,17 +20417,17 @@ function createPluginContext(displayName) {
|
|
|
20298
20417
|
}) => /* @__PURE__ */ jsx(ConfigContext.Provider, { value: config, children: /* @__PURE__ */ jsx(ProviderContext.Provider, { value: provider, children: /* @__PURE__ */ jsx(StoreContext.Provider, { value: store, children }) }) });
|
|
20299
20418
|
ContextProvider.displayName = `${displayName}ContextProvider`;
|
|
20300
20419
|
function useConfig() {
|
|
20301
|
-
const ctx =
|
|
20420
|
+
const ctx = React65__default.useContext(ConfigContext);
|
|
20302
20421
|
if (!ctx) throw new Error(`useConfig must be used within ${displayName}`);
|
|
20303
20422
|
return ctx;
|
|
20304
20423
|
}
|
|
20305
20424
|
function useProvider() {
|
|
20306
|
-
const ctx =
|
|
20425
|
+
const ctx = React65__default.useContext(ProviderContext);
|
|
20307
20426
|
if (!ctx) throw new Error(`useProvider must be used within ${displayName}`);
|
|
20308
20427
|
return ctx;
|
|
20309
20428
|
}
|
|
20310
20429
|
function useStore$1(selector) {
|
|
20311
|
-
const store =
|
|
20430
|
+
const store = React65__default.useContext(StoreContext);
|
|
20312
20431
|
if (!store) throw new Error(`useStore must be used within ${displayName}`);
|
|
20313
20432
|
return useStore(store, selector);
|
|
20314
20433
|
}
|
|
@@ -20365,7 +20484,7 @@ function PluginRegistryManager({ registries, routeBase, className }) {
|
|
|
20365
20484
|
return registries[0]?.id ?? "";
|
|
20366
20485
|
};
|
|
20367
20486
|
const [activeTab, setActiveTab] = useState(getTabFromHash);
|
|
20368
|
-
|
|
20487
|
+
React65__default.useEffect(() => {
|
|
20369
20488
|
if (!routeBase) return;
|
|
20370
20489
|
const handler = () => setActiveTab(getTabFromHash());
|
|
20371
20490
|
window.addEventListener("hashchange", handler);
|
|
@@ -20423,6 +20542,14 @@ function useModuleNavigation(hashBase, depthMap, homeView = "summary") {
|
|
|
20423
20542
|
const rest = hash.slice(hashBase.length + 1);
|
|
20424
20543
|
const segments = rest.split("/");
|
|
20425
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
|
+
}
|
|
20426
20553
|
const ACTION_KEYWORDS = ["edit", "detail", "view", "post"];
|
|
20427
20554
|
if (segments.length >= 3) {
|
|
20428
20555
|
const maybeAction = segments[segments.length - 2];
|
|
@@ -20430,9 +20557,8 @@ function useModuleNavigation(hashBase, depthMap, homeView = "summary") {
|
|
|
20430
20557
|
return segments.slice(0, -2).join("-") + "-" + maybeAction + ":" + segments[segments.length - 1];
|
|
20431
20558
|
}
|
|
20432
20559
|
}
|
|
20433
|
-
|
|
20434
|
-
|
|
20435
|
-
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;
|
|
20436
20562
|
}
|
|
20437
20563
|
return segments.join("-");
|
|
20438
20564
|
}
|
|
@@ -20487,9 +20613,17 @@ function useModuleNavigation(hashBase, depthMap, homeView = "summary") {
|
|
|
20487
20613
|
} else {
|
|
20488
20614
|
const colonIdx = nextView.indexOf(":");
|
|
20489
20615
|
if (colonIdx !== -1) {
|
|
20490
|
-
const
|
|
20616
|
+
const rawPrefix = nextView.slice(0, colonIdx);
|
|
20491
20617
|
const id = nextView.slice(colonIdx + 1);
|
|
20492
|
-
|
|
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
|
+
}
|
|
20493
20627
|
} else {
|
|
20494
20628
|
const path = nextView.replace(/-/g, "/");
|
|
20495
20629
|
window.location.hash = `${hashBase}/${path}`;
|
|
@@ -20668,12 +20802,12 @@ function CrudRecordModal({
|
|
|
20668
20802
|
description,
|
|
20669
20803
|
emptyLabel
|
|
20670
20804
|
}) {
|
|
20671
|
-
const [record, setRecord] =
|
|
20672
|
-
const [loading, setLoading] =
|
|
20673
|
-
const [saving, setSaving] =
|
|
20674
|
-
const [error, setError] =
|
|
20675
|
-
const formId =
|
|
20676
|
-
|
|
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(() => {
|
|
20677
20811
|
if (!open) return;
|
|
20678
20812
|
let cancelled = false;
|
|
20679
20813
|
setLoading(true);
|
|
@@ -21311,10 +21445,10 @@ function useTenantPluginSettings(pluginId, defaults) {
|
|
|
21311
21445
|
);
|
|
21312
21446
|
}
|
|
21313
21447
|
function useAgentSurface(contribution) {
|
|
21314
|
-
const ref =
|
|
21448
|
+
const ref = React65.useRef(contribution);
|
|
21315
21449
|
ref.current = contribution;
|
|
21316
21450
|
const id = contribution.id;
|
|
21317
|
-
|
|
21451
|
+
React65.useEffect(() => {
|
|
21318
21452
|
registerSurface({ id, get: () => ref.current });
|
|
21319
21453
|
const names = (ref.current.tools ?? []).map((t) => t.tool.name);
|
|
21320
21454
|
for (const name of names) {
|
|
@@ -21334,21 +21468,21 @@ function ConnectorsHub({ hostPluginId }) {
|
|
|
21334
21468
|
const { t } = useTranslation$1();
|
|
21335
21469
|
const { connectors, reload } = useConnectors({ includeGrants: false });
|
|
21336
21470
|
const assistantAvailable = useConnectorsPanelAvailable();
|
|
21337
|
-
const [selected, setSelected] =
|
|
21338
|
-
const [adding, setAdding] =
|
|
21339
|
-
const hosted =
|
|
21471
|
+
const [selected, setSelected] = React65__default.useState(null);
|
|
21472
|
+
const [adding, setAdding] = React65__default.useState(false);
|
|
21473
|
+
const hosted = React65__default.useMemo(
|
|
21340
21474
|
() => (connectors ?? []).filter((c) => c.hostPluginId === hostPluginId),
|
|
21341
21475
|
[connectors, hostPluginId]
|
|
21342
21476
|
);
|
|
21343
|
-
const categories =
|
|
21477
|
+
const categories = React65__default.useMemo(
|
|
21344
21478
|
() => [...new Set(hosted.map((c) => c.category).filter((c) => !!c))],
|
|
21345
21479
|
[hosted]
|
|
21346
21480
|
);
|
|
21347
|
-
const scoped =
|
|
21481
|
+
const scoped = React65__default.useMemo(() => {
|
|
21348
21482
|
const siblings = inCategories(connectors ?? [], categories).filter((c) => c.hostPluginId !== hostPluginId);
|
|
21349
21483
|
return [...hosted, ...siblings];
|
|
21350
21484
|
}, [connectors, hosted, categories, hostPluginId]);
|
|
21351
|
-
|
|
21485
|
+
React65__default.useEffect(() => {
|
|
21352
21486
|
if (!selected || !connectors) return;
|
|
21353
21487
|
const fresh = connectors.find((c) => c.id === selected.id);
|
|
21354
21488
|
if (fresh && fresh !== selected) setSelected(fresh);
|
|
@@ -21360,7 +21494,7 @@ function ConnectorsHub({ hostPluginId }) {
|
|
|
21360
21494
|
const only = categories.length === 1 ? categoryLabel(categories[0]) : void 0;
|
|
21361
21495
|
const moreLabel = only ? t("connectors.viewCategory", { category: only }) : t("connectors.viewSimilar");
|
|
21362
21496
|
return /* @__PURE__ */ jsxs("div", { className: "max-w-3xl space-y-3", children: [
|
|
21363
|
-
/* @__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(
|
|
21364
21498
|
ConnectorRow,
|
|
21365
21499
|
{
|
|
21366
21500
|
connector: c,
|
|
@@ -21420,7 +21554,7 @@ function ConnectorsHub({ hostPluginId }) {
|
|
|
21420
21554
|
] });
|
|
21421
21555
|
}
|
|
21422
21556
|
function HubSkeleton() {
|
|
21423
|
-
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: [
|
|
21424
21558
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-10 shrink-0 rounded-lg" }),
|
|
21425
21559
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-2 py-0.5", children: [
|
|
21426
21560
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-44" }),
|
|
@@ -21429,7 +21563,7 @@ function HubSkeleton() {
|
|
|
21429
21563
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24 shrink-0" })
|
|
21430
21564
|
] }, i)) }) });
|
|
21431
21565
|
}
|
|
21432
|
-
function RegistryCrudView2({ registry: registry3, basePath }) {
|
|
21566
|
+
function RegistryCrudView2({ registry: registry3, basePath, embedded }) {
|
|
21433
21567
|
const useStore = useMemo(() => {
|
|
21434
21568
|
const mockData = registry3.mockData ?? registry3.seedData ?? [];
|
|
21435
21569
|
const provider = registry3.dataProvider ?? resolveDataProvider(registry3.entity, mockData);
|
|
@@ -21442,7 +21576,8 @@ function RegistryCrudView2({ registry: registry3, basePath }) {
|
|
|
21442
21576
|
useStore,
|
|
21443
21577
|
basePath,
|
|
21444
21578
|
display: registry3.display === "cards" ? "cards" : "table",
|
|
21445
|
-
readOnly: registry3.readOnly
|
|
21579
|
+
readOnly: registry3.readOnly,
|
|
21580
|
+
embedded
|
|
21446
21581
|
}
|
|
21447
21582
|
);
|
|
21448
21583
|
}
|
|
@@ -21462,7 +21597,7 @@ function PropertiesTab({ registries, routeBase, regLabel }) {
|
|
|
21462
21597
|
return registries[0]?.id ?? "";
|
|
21463
21598
|
}
|
|
21464
21599
|
const [active2, setActive] = useState(getActive);
|
|
21465
|
-
|
|
21600
|
+
React65__default.useEffect(() => {
|
|
21466
21601
|
const handler = () => setActive(getActive());
|
|
21467
21602
|
window.addEventListener("hashchange", handler);
|
|
21468
21603
|
return () => window.removeEventListener("hashchange", handler);
|
|
@@ -21537,7 +21672,7 @@ function PluginSettingsPanel({ title, subtitle, generalSettings, registries, cus
|
|
|
21537
21672
|
return tabs[0]?.id ?? "";
|
|
21538
21673
|
}
|
|
21539
21674
|
const [activeTab, setActiveTab] = useState(getActiveFromHash);
|
|
21540
|
-
|
|
21675
|
+
React65__default.useEffect(() => {
|
|
21541
21676
|
const handler = () => setActiveTab(getActiveFromHash());
|
|
21542
21677
|
window.addEventListener("hashchange", handler);
|
|
21543
21678
|
return () => window.removeEventListener("hashchange", handler);
|
|
@@ -21585,6 +21720,6 @@ var renderApp = (...args) => {
|
|
|
21585
21720
|
return renderApp$1(...args);
|
|
21586
21721
|
};
|
|
21587
21722
|
|
|
21588
|
-
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, 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 };
|
|
21589
21724
|
//# sourceMappingURL=index.js.map
|
|
21590
21725
|
//# sourceMappingURL=index.js.map
|