@fayz-ai/saas 0.1.7 → 0.2.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.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/dist/crud/CrudDetailPage.d.ts.map +1 -1
  3. package/dist/crud/CrudFormPage.d.ts.map +1 -1
  4. package/dist/crud/archetypes/PersonDetailTabs.d.ts +12 -0
  5. package/dist/crud/archetypes/PersonDetailTabs.d.ts.map +1 -1
  6. package/dist/crud/fieldToColumn.d.ts.map +1 -1
  7. package/dist/crud/index.d.ts +1 -0
  8. package/dist/crud/index.d.ts.map +1 -1
  9. package/dist/crud/relation-field.d.ts +28 -0
  10. package/dist/crud/relation-field.d.ts.map +1 -0
  11. package/dist/hooks/useModuleNavigation.d.ts +2 -0
  12. package/dist/hooks/useModuleNavigation.d.ts.map +1 -1
  13. package/dist/index.cjs +726 -379
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +550 -204
  18. package/dist/index.js.map +1 -1
  19. package/dist/shell/components/plugins/ConnectorsHub.d.ts +6 -0
  20. package/dist/shell/components/plugins/ConnectorsHub.d.ts.map +1 -0
  21. package/dist/shell/components/plugins/PluginSettingsPanel.d.ts +4 -2
  22. package/dist/shell/components/plugins/PluginSettingsPanel.d.ts.map +1 -1
  23. package/dist/shell/createSaasApp.d.ts.map +1 -1
  24. package/dist/shell/hooks/useModuleNavigation.d.ts +2 -0
  25. package/dist/shell/hooks/useModuleNavigation.d.ts.map +1 -1
  26. package/dist/shell/types/crud.d.ts +12 -1
  27. package/dist/shell/types/crud.d.ts.map +1 -1
  28. package/package.json +4 -4
  29. package/src/crud/CrudDetailPage.tsx +5 -0
  30. package/src/crud/CrudFormPage.tsx +12 -0
  31. package/src/crud/archetypes/PersonDetailTabs.tsx +22 -0
  32. package/src/crud/fieldToColumn.tsx +3 -0
  33. package/src/crud/index.ts +1 -0
  34. package/src/crud/relation-field.tsx +115 -0
  35. package/src/hooks/useModuleNavigation.ts +27 -1
  36. package/src/index.ts +1 -0
  37. package/src/shell/components/plugins/ConnectorsHub.tsx +163 -0
  38. package/src/shell/components/plugins/PluginSettingsPanel.tsx +106 -27
  39. package/src/shell/createSaasApp.tsx +22 -1
  40. package/src/shell/hooks/useModuleNavigation.ts +27 -1
  41. package/src/shell/types/crud.ts +13 -0
package/dist/index.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
  var chunkQGMDVLLW_cjs = require('./chunk-QGMDVLLW.cjs');
4
4
  var chunk4XTQ4V5L_cjs = require('./chunk-4XTQ4V5L.cjs');
5
5
  var chunkKYID2MR6_cjs = require('./chunk-KYID2MR6.cjs');
6
- var React40 = require('react');
6
+ var React41 = require('react');
7
7
  var core = require('@fayz-ai/core');
8
8
  var auth = require('@fayz-ai/auth');
9
9
  var ui = require('@fayz-ai/ui');
@@ -32,7 +32,7 @@ function _interopNamespace(e) {
32
32
  return Object.freeze(n);
33
33
  }
34
34
 
35
- var React40__namespace = /*#__PURE__*/_interopNamespace(React40);
35
+ var React41__namespace = /*#__PURE__*/_interopNamespace(React41);
36
36
  var LucideIcons4__namespace = /*#__PURE__*/_interopNamespace(LucideIcons4);
37
37
  var Dialog__namespace = /*#__PURE__*/_interopNamespace(Dialog);
38
38
 
@@ -149,7 +149,7 @@ function detectActivePluginId(runtime) {
149
149
  }
150
150
  function useAITools() {
151
151
  const runtime = core.usePluginRuntimeOptional();
152
- return React40__namespace.useMemo(() => {
152
+ return React41__namespace.useMemo(() => {
153
153
  const hasPermission = runtime?.context.hasPermission;
154
154
  const verticalId = runtime?.context.tenant?.verticalId;
155
155
  const activePluginId = detectActivePluginId(runtime);
@@ -213,7 +213,7 @@ function useAITools() {
213
213
  }
214
214
  function useChat(options) {
215
215
  const store = useChatStore();
216
- const sendMessage = React40.useCallback(
216
+ const sendMessage = React41.useCallback(
217
217
  async (content) => {
218
218
  const userMsg = {
219
219
  id: `msg-${Date.now()}`,
@@ -282,9 +282,9 @@ function useTranslation() {
282
282
  return { t, locale: core.getCurrentLocale() };
283
283
  }
284
284
  function TypewriterText({ text, speed = 28, onDone }) {
285
- const [displayed, setDisplayed] = React40__namespace.useState("");
286
- const indexRef = React40__namespace.useRef(0);
287
- React40__namespace.useEffect(() => {
285
+ const [displayed, setDisplayed] = React41__namespace.useState("");
286
+ const indexRef = React41__namespace.useRef(0);
287
+ React41__namespace.useEffect(() => {
288
288
  setDisplayed("");
289
289
  indexRef.current = 0;
290
290
  const interval = setInterval(() => {
@@ -329,11 +329,11 @@ function ChatFab({ className, apiEndpoint, systemPrompt }) {
329
329
  const { contextualSuggestions } = useAITools();
330
330
  const { sendMessage } = useChat({ apiEndpoint, systemPrompt });
331
331
  const { t } = useTranslation();
332
- const [phase, setPhase] = React40__namespace.useState("idle");
333
- const [activeSuggestion, setActiveSuggestion] = React40__namespace.useState(null);
334
- const timersRef = React40__namespace.useRef([]);
335
- const prevSuggestionRef = React40__namespace.useRef(null);
336
- React40__namespace.useEffect(ensureStyles, []);
332
+ const [phase, setPhase] = React41__namespace.useState("idle");
333
+ const [activeSuggestion, setActiveSuggestion] = React41__namespace.useState(null);
334
+ const timersRef = React41__namespace.useRef([]);
335
+ const prevSuggestionRef = React41__namespace.useRef(null);
336
+ React41__namespace.useEffect(ensureStyles, []);
337
337
  const clearTimers = () => {
338
338
  timersRef.current.forEach(clearTimeout);
339
339
  timersRef.current = [];
@@ -343,7 +343,7 @@ function ChatFab({ className, apiEndpoint, systemPrompt }) {
343
343
  };
344
344
  const topSuggestion = contextualSuggestions[0] ?? null;
345
345
  const topLabel = topSuggestion?.label ?? null;
346
- React40__namespace.useEffect(() => {
346
+ React41__namespace.useEffect(() => {
347
347
  if (isOpen || !topSuggestion || !topLabel) {
348
348
  if (phase !== "idle") {
349
349
  clearTimers();
@@ -373,7 +373,7 @@ function ChatFab({ className, apiEndpoint, systemPrompt }) {
373
373
  }, 9e3);
374
374
  return clearTimers;
375
375
  }, [topLabel, isOpen]);
376
- React40__namespace.useEffect(() => {
376
+ React41__namespace.useEffect(() => {
377
377
  if (isOpen && phase !== "idle") {
378
378
  clearTimers();
379
379
  setPhase("idle");
@@ -516,16 +516,16 @@ function ChatPanel({
516
516
  const { sendMessage } = useChat({ apiEndpoint, systemPrompt });
517
517
  const { t } = useTranslation();
518
518
  const { suggestions, toolGroups } = useAITools();
519
- const [input, setInput] = React40__namespace.useState("");
520
- const [showTools, setShowTools] = React40__namespace.useState(false);
521
- const scrollRef = React40__namespace.useRef(null);
522
- const inputRef = React40__namespace.useRef(null);
519
+ const [input, setInput] = React41__namespace.useState("");
520
+ const [showTools, setShowTools] = React41__namespace.useState(false);
521
+ const scrollRef = React41__namespace.useRef(null);
522
+ const inputRef = React41__namespace.useRef(null);
523
523
  const hasMessages = messages.length > 0;
524
524
  const totalTools = toolGroups.reduce((sum, g) => sum + g.tools.length, 0);
525
- React40__namespace.useEffect(() => {
525
+ React41__namespace.useEffect(() => {
526
526
  scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight, behavior: "smooth" });
527
527
  }, [messages]);
528
- React40__namespace.useEffect(() => {
528
+ React41__namespace.useEffect(() => {
529
529
  if (isOpen) {
530
530
  const timer = setTimeout(() => inputRef.current?.focus(), 100);
531
531
  return () => clearTimeout(timer);
@@ -1082,8 +1082,8 @@ function navigateTo(to) {
1082
1082
  adapter.navigate(normalizeAdminPath(to));
1083
1083
  }
1084
1084
  function useAdminPath() {
1085
- const [path, setPath] = React40__namespace.useState(() => normalizeAdminPath(adapter.getCurrentPath() || "/"));
1086
- React40__namespace.useEffect(() => {
1085
+ const [path, setPath] = React41__namespace.useState(() => normalizeAdminPath(adapter.getCurrentPath() || "/"));
1086
+ React41__namespace.useEffect(() => {
1087
1087
  return adapter.onPathChange((p) => {
1088
1088
  setPath(normalizeAdminPath(p || "/"));
1089
1089
  if (typeof window !== "undefined") window.scrollTo(0, 0);
@@ -1138,12 +1138,12 @@ function LoginPage({
1138
1138
  return !v || v === key || v.includes("{{") ? fallback : v;
1139
1139
  };
1140
1140
  const { signIn, signUp, signInWithOAuth, resetPassword, isLoading, error } = auth.useAuth();
1141
- const [view, setView] = React40__namespace.useState("login");
1142
- const [email, setEmail] = React40__namespace.useState("");
1143
- const [password, setPassword] = React40__namespace.useState("");
1144
- const [fullName, setFullName] = React40__namespace.useState("");
1145
- const [notice, setNotice] = React40__namespace.useState(null);
1146
- const [submitting, setSubmitting] = React40__namespace.useState(false);
1141
+ const [view, setView] = React41__namespace.useState("login");
1142
+ const [email, setEmail] = React41__namespace.useState("");
1143
+ const [password, setPassword] = React41__namespace.useState("");
1144
+ const [fullName, setFullName] = React41__namespace.useState("");
1145
+ const [notice, setNotice] = React41__namespace.useState(null);
1146
+ const [submitting, setSubmitting] = React41__namespace.useState(false);
1147
1147
  const busy = submitting || isLoading;
1148
1148
  const brandLogo = loginLogo ?? logo;
1149
1149
  const heading = view === "login" ? tr("auth.login.title", "Welcome back") : view === "signup" ? tr("auth.signup.title", "Create account") : tr("auth.recovery.title", "Reset password");
@@ -1384,11 +1384,11 @@ var CURRENCIES = [
1384
1384
  function CompanySettings({ tenant, onSave }) {
1385
1385
  const { t } = useTranslation();
1386
1386
  const { locale: uiLocale, setLocale: setUiLocale } = useLocaleStore();
1387
- const [name, setName] = React40__namespace.useState(tenant?.name ?? "");
1388
- const [timezone, setTimezone] = React40__namespace.useState(tenant?.settings?.timezone ?? "UTC");
1389
- const [currency, setCurrency] = React40__namespace.useState(tenant?.settings?.currency ?? "USD");
1390
- const [saving, setSaving] = React40__namespace.useState(false);
1391
- React40__namespace.useEffect(() => {
1387
+ const [name, setName] = React41__namespace.useState(tenant?.name ?? "");
1388
+ const [timezone, setTimezone] = React41__namespace.useState(tenant?.settings?.timezone ?? "UTC");
1389
+ const [currency, setCurrency] = React41__namespace.useState(tenant?.settings?.currency ?? "USD");
1390
+ const [saving, setSaving] = React41__namespace.useState(false);
1391
+ React41__namespace.useEffect(() => {
1392
1392
  if (tenant) {
1393
1393
  setName(tenant.name);
1394
1394
  setTimezone(tenant.settings?.timezone ?? "UTC");
@@ -1472,17 +1472,17 @@ function CompanySettings({ tenant, onSave }) {
1472
1472
  ] })
1473
1473
  ] });
1474
1474
  }
1475
- var OrgAdapterContext = React40.createContext(null);
1475
+ var OrgAdapterContext = React41.createContext(null);
1476
1476
  var OrgAdapterProvider = OrgAdapterContext.Provider;
1477
1477
  function useOrgAdapter2() {
1478
- const adapter2 = React40.useContext(OrgAdapterContext);
1478
+ const adapter2 = React41.useContext(OrgAdapterContext);
1479
1479
  if (!adapter2) {
1480
1480
  throw new Error("useOrgAdapter must be used within an OrgAdapterProvider");
1481
1481
  }
1482
1482
  return adapter2;
1483
1483
  }
1484
1484
  function useOrgAdapterOptional2() {
1485
- return React40.useContext(OrgAdapterContext);
1485
+ return React41.useContext(OrgAdapterContext);
1486
1486
  }
1487
1487
  function toTenantSettings(settings) {
1488
1488
  const source = settings && typeof settings === "object" ? settings : {};
@@ -1538,10 +1538,10 @@ function getInitials(name) {
1538
1538
  }
1539
1539
  function UserProfile({ user, onSave, onAvatarChange }) {
1540
1540
  const { t } = useTranslation();
1541
- const [fullName, setFullName] = React40__namespace.useState(user?.fullName ?? "");
1542
- const [saving, setSaving] = React40__namespace.useState(false);
1543
- const fileInputRef = React40__namespace.useRef(null);
1544
- React40__namespace.useEffect(() => {
1541
+ const [fullName, setFullName] = React41__namespace.useState(user?.fullName ?? "");
1542
+ const [saving, setSaving] = React41__namespace.useState(false);
1543
+ const fileInputRef = React41__namespace.useRef(null);
1544
+ React41__namespace.useEffect(() => {
1545
1545
  if (user) {
1546
1546
  setFullName(user.fullName);
1547
1547
  }
@@ -1750,9 +1750,9 @@ function SecuritySettings({
1750
1750
  onTenantSecurityChange
1751
1751
  }) {
1752
1752
  const { t } = useTranslation();
1753
- const [resetting, setResetting] = React40__namespace.useState(false);
1754
- const [resetSent, setResetSent] = React40__namespace.useState(false);
1755
- const [savingTenant, setSavingTenant] = React40__namespace.useState(false);
1753
+ const [resetting, setResetting] = React41__namespace.useState(false);
1754
+ const [resetSent, setResetSent] = React41__namespace.useState(false);
1755
+ const [savingTenant, setSavingTenant] = React41__namespace.useState(false);
1756
1756
  const handleResetPassword = async () => {
1757
1757
  if (!onResetPassword) return;
1758
1758
  setResetting(true);
@@ -1853,10 +1853,10 @@ function SecuritySettings({
1853
1853
  ] })
1854
1854
  ] });
1855
1855
  }
1856
- var AuthAdapterContext = React40.createContext(null);
1856
+ var AuthAdapterContext = React41.createContext(null);
1857
1857
  var AuthAdapterProvider = AuthAdapterContext.Provider;
1858
1858
  function useAuthAdapterOptional() {
1859
- return React40.useContext(AuthAdapterContext);
1859
+ return React41.useContext(AuthAdapterContext);
1860
1860
  }
1861
1861
  function ConnectedSecuritySettings() {
1862
1862
  const user = useAuthStore((s) => s.user);
@@ -1912,8 +1912,8 @@ function FileUploadField({
1912
1912
  hint
1913
1913
  }) {
1914
1914
  const { t } = useTranslation();
1915
- const inputRef = React40__namespace.useRef(null);
1916
- const [preview, setPreview] = React40__namespace.useState(null);
1915
+ const inputRef = React41__namespace.useRef(null);
1916
+ const [preview, setPreview] = React41__namespace.useState(null);
1917
1917
  const handleChange = (e) => {
1918
1918
  const file = e.target.files?.[0];
1919
1919
  if (file) {
@@ -1980,14 +1980,14 @@ function FileUploadField({
1980
1980
  }
1981
1981
  function BrandingSettings({ branding, onSave }) {
1982
1982
  const { t } = useTranslation();
1983
- const [primaryColor, setPrimaryColor] = React40__namespace.useState(branding?.primaryColor ?? "#000000");
1984
- const [accentColor, setAccentColor] = React40__namespace.useState(branding?.accentColor ?? "#6366f1");
1985
- const [logoFile, setLogoFile] = React40__namespace.useState(null);
1986
- const [faviconFile, setFaviconFile] = React40__namespace.useState(null);
1987
- const [logoUrl, setLogoUrl] = React40__namespace.useState(branding?.logoUrl ?? "");
1988
- const [faviconUrl, setFaviconUrl] = React40__namespace.useState(branding?.faviconUrl ?? "");
1989
- const [saving, setSaving] = React40__namespace.useState(false);
1990
- React40__namespace.useEffect(() => {
1983
+ const [primaryColor, setPrimaryColor] = React41__namespace.useState(branding?.primaryColor ?? "#000000");
1984
+ const [accentColor, setAccentColor] = React41__namespace.useState(branding?.accentColor ?? "#6366f1");
1985
+ const [logoFile, setLogoFile] = React41__namespace.useState(null);
1986
+ const [faviconFile, setFaviconFile] = React41__namespace.useState(null);
1987
+ const [logoUrl, setLogoUrl] = React41__namespace.useState(branding?.logoUrl ?? "");
1988
+ const [faviconUrl, setFaviconUrl] = React41__namespace.useState(branding?.faviconUrl ?? "");
1989
+ const [saving, setSaving] = React41__namespace.useState(false);
1990
+ React41__namespace.useEffect(() => {
1991
1991
  if (branding) {
1992
1992
  setPrimaryColor(branding.primaryColor ?? "#000000");
1993
1993
  setAccentColor(branding.accentColor ?? "#6366f1");
@@ -2190,7 +2190,7 @@ function SettingsPage({
2190
2190
  afterContent
2191
2191
  }) {
2192
2192
  const { t } = useTranslation();
2193
- const defaultTabs = React40__namespace.useMemo(() => [
2193
+ const defaultTabs = React41__namespace.useMemo(() => [
2194
2194
  { id: "general", label: t("settings.general"), icon: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons4.Building2, { className: "h-4 w-4" }), component: /* @__PURE__ */ jsxRuntime.jsx(ConnectedCompanySettings, {}) },
2195
2195
  { id: "profile", label: t("settings.profile"), icon: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons4.User, { className: "h-4 w-4" }), component: /* @__PURE__ */ jsxRuntime.jsx(ConnectedUserProfile, {}) },
2196
2196
  { id: "security", label: t("settings.security"), icon: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons4.Shield, { className: "h-4 w-4" }), component: /* @__PURE__ */ jsxRuntime.jsx(ConnectedSecuritySettings, {}) },
@@ -2206,10 +2206,10 @@ function SettingsPage({
2206
2206
  }
2207
2207
  return null;
2208
2208
  }
2209
- const [activeTab, setActiveTab] = React40__namespace.useState(() => {
2209
+ const [activeTab, setActiveTab] = React41__namespace.useState(() => {
2210
2210
  return getTabFromHash() ?? defaultTab ?? null;
2211
2211
  });
2212
- React40__namespace.useEffect(() => {
2212
+ React41__namespace.useEffect(() => {
2213
2213
  const handler = () => {
2214
2214
  const tab = getTabFromHash();
2215
2215
  if (tab) setActiveTab(tab);
@@ -2229,7 +2229,7 @@ function SettingsPage({
2229
2229
  setActiveTab(null);
2230
2230
  window.location.hash = "/settings";
2231
2231
  };
2232
- const renderNav = (activeId) => /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-0.5", children: resolvedTabs.map((tab, i) => /* @__PURE__ */ jsxRuntime.jsxs(React40__namespace.Fragment, { children: [
2232
+ const renderNav = (activeId) => /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-0.5", children: resolvedTabs.map((tab, i) => /* @__PURE__ */ jsxRuntime.jsxs(React41__namespace.Fragment, { children: [
2233
2233
  tab.isPlugin && (i === 0 || !resolvedTabs[i - 1]?.isPlugin) && /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "py-2", children: [
2234
2234
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t" }),
2235
2235
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pt-2 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: t("common.plugins") })
@@ -2289,10 +2289,10 @@ function InviteMemberDialog({ open, onOpenChange, defaultEmail }) {
2289
2289
  const profiles = chunk4XTQ4V5L_cjs.usePermissionsStore((s) => s.profiles);
2290
2290
  const setInvites = useInviteStore((s) => s.setInvites);
2291
2291
  const user = useAuthStore((s) => s.user);
2292
- const [emails, setEmails] = React40__namespace.useState([defaultEmail ?? ""]);
2293
- const [profileId, setProfileId] = React40__namespace.useState(profiles[1]?.id ?? profiles[0]?.id ?? "");
2294
- const [sending, setSending] = React40__namespace.useState(false);
2295
- const [sent, setSent] = React40__namespace.useState(false);
2292
+ const [emails, setEmails] = React41__namespace.useState([defaultEmail ?? ""]);
2293
+ const [profileId, setProfileId] = React41__namespace.useState(profiles[1]?.id ?? profiles[0]?.id ?? "");
2294
+ const [sending, setSending] = React41__namespace.useState(false);
2295
+ const [sent, setSent] = React41__namespace.useState(false);
2296
2296
  const addEmail = () => setEmails((prev) => [...prev, ""]);
2297
2297
  const updateEmail = (idx, value) => {
2298
2298
  setEmails((prev) => {
@@ -2416,7 +2416,7 @@ var ROLE_HIERARCHY = {
2416
2416
  function usePermission2() {
2417
2417
  const currentRole = useTenantStore((s) => s.currentRole);
2418
2418
  const currentProfile = chunk4XTQ4V5L_cjs.usePermissionsStore((s) => s.currentProfile);
2419
- const can = React40.useCallback(
2419
+ const can = React41.useCallback(
2420
2420
  (featureId, action) => {
2421
2421
  if (!currentProfile) return true;
2422
2422
  if (currentProfile.id === "owner") return true;
@@ -2424,18 +2424,18 @@ function usePermission2() {
2424
2424
  },
2425
2425
  [currentProfile]
2426
2426
  );
2427
- const hasSystemPermission = React40.useCallback(
2427
+ const hasSystemPermission = React41.useCallback(
2428
2428
  (perm) => {
2429
2429
  if (!currentProfile) return true;
2430
2430
  return (currentProfile.systemPermissions ?? []).includes(perm);
2431
2431
  },
2432
2432
  [currentProfile]
2433
2433
  );
2434
- const permissions = React40.useMemo(() => {
2434
+ const permissions = React41.useMemo(() => {
2435
2435
  if (!currentRole) return [];
2436
2436
  return ROLE_PERMISSIONS[currentRole];
2437
2437
  }, [currentRole]);
2438
- const hasPermission = React40.useCallback(
2438
+ const hasPermission = React41.useCallback(
2439
2439
  (permission) => {
2440
2440
  if (currentProfile) {
2441
2441
  return (currentProfile.systemPermissions ?? []).includes(permission);
@@ -2444,14 +2444,14 @@ function usePermission2() {
2444
2444
  },
2445
2445
  [currentProfile, permissions]
2446
2446
  );
2447
- const requireRole = React40.useCallback(
2447
+ const requireRole = React41.useCallback(
2448
2448
  (role) => {
2449
2449
  if (!currentRole) return false;
2450
2450
  return ROLE_HIERARCHY[currentRole] >= ROLE_HIERARCHY[role];
2451
2451
  },
2452
2452
  [currentRole]
2453
2453
  );
2454
- const canAccess = React40.useCallback(
2454
+ const canAccess = React41.useCallback(
2455
2455
  (requiredPermissions) => {
2456
2456
  return requiredPermissions.every((p) => permissions.includes(p));
2457
2457
  },
@@ -2490,8 +2490,8 @@ function TeamTab() {
2490
2490
  const setInvites = useInviteStore((s) => s.setInvites);
2491
2491
  const user = useAuthStore((s) => s.user);
2492
2492
  const { hasSystemPermission } = usePermission2();
2493
- const [inviteOpen, setInviteOpen] = React40__namespace.useState(false);
2494
- React40__namespace.useEffect(() => {
2493
+ const [inviteOpen, setInviteOpen] = React41__namespace.useState(false);
2494
+ React41__namespace.useEffect(() => {
2495
2495
  if (adapter2 && currentOrg) {
2496
2496
  dedup("team:invites:" + currentOrg.id, () => adapter2.listInvites(currentOrg.id)).then(setInvites).catch(() => {
2497
2497
  });
@@ -2638,12 +2638,12 @@ var SYSTEM_PERMISSIONS = [
2638
2638
  ];
2639
2639
  function PermissionMatrixEditor({ features, profile, onSave, onCancel, saving }) {
2640
2640
  const { t } = useTranslation();
2641
- const [name, setName] = React40__namespace.useState(profile?.name ?? "");
2642
- const [description, setDescription] = React40__namespace.useState(profile?.description ?? "");
2643
- const [systemPerms, setSystemPerms] = React40__namespace.useState(profile?.systemPermissions ?? []);
2644
- const [grants, setGrants] = React40__namespace.useState(profile?.grants ?? {});
2645
- const [collapsed, setCollapsed] = React40__namespace.useState(/* @__PURE__ */ new Set());
2646
- const [search, setSearch] = React40__namespace.useState("");
2641
+ const [name, setName] = React41__namespace.useState(profile?.name ?? "");
2642
+ const [description, setDescription] = React41__namespace.useState(profile?.description ?? "");
2643
+ const [systemPerms, setSystemPerms] = React41__namespace.useState(profile?.systemPermissions ?? []);
2644
+ const [grants, setGrants] = React41__namespace.useState(profile?.grants ?? {});
2645
+ const [collapsed, setCollapsed] = React41__namespace.useState(/* @__PURE__ */ new Set());
2646
+ const [search, setSearch] = React41__namespace.useState("");
2647
2647
  const toggleSystemPerm = (perm) => {
2648
2648
  setSystemPerms(
2649
2649
  (prev) => prev.includes(perm) ? prev.filter((p) => p !== perm) : [...prev, perm]
@@ -2667,7 +2667,7 @@ function PermissionMatrixEditor({ features, profile, onSave, onCancel, saving })
2667
2667
  if (!name.trim()) return;
2668
2668
  onSave({ name: name.trim(), description: description.trim() || void 0, systemPermissions: systemPerms, grants });
2669
2669
  };
2670
- const groups = React40__namespace.useMemo(() => {
2670
+ const groups = React41__namespace.useMemo(() => {
2671
2671
  const filtered = search ? features.filter((f) => f.label.toLowerCase().includes(search.toLowerCase())) : features;
2672
2672
  const map = /* @__PURE__ */ new Map();
2673
2673
  for (const f of filtered) {
@@ -2728,7 +2728,7 @@ function PermissionMatrixEditor({ features, profile, onSave, onCancel, saving })
2728
2728
  }
2729
2729
  ) }) })
2730
2730
  ] }, sp.id)),
2731
- Array.from(groups.entries()).map(([groupName, groupFeatures]) => /* @__PURE__ */ jsxRuntime.jsxs(React40__namespace.Fragment, { children: [
2731
+ Array.from(groups.entries()).map(([groupName, groupFeatures]) => /* @__PURE__ */ jsxRuntime.jsxs(React41__namespace.Fragment, { children: [
2732
2732
  /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: 5, className: "p-2 px-3", children: /* @__PURE__ */ jsxRuntime.jsxs(
2733
2733
  "button",
2734
2734
  {
@@ -2773,10 +2773,10 @@ function PermissionProfilesTab() {
2773
2773
  const startImpersonation = chunk4XTQ4V5L_cjs.usePermissionsStore((s) => s.startImpersonation);
2774
2774
  const canPreview = (realProfile?.systemPermissions ?? []).includes("manage_permissions") ?? false;
2775
2775
  const { t } = useTranslation();
2776
- const [editingProfile, setEditingProfile] = React40__namespace.useState(null);
2777
- const [creating, setCreating] = React40__namespace.useState(false);
2778
- const [saving, setSaving] = React40__namespace.useState(false);
2779
- const memberCountByProfile = React40__namespace.useMemo(() => {
2776
+ const [editingProfile, setEditingProfile] = React41__namespace.useState(null);
2777
+ const [creating, setCreating] = React41__namespace.useState(false);
2778
+ const [saving, setSaving] = React41__namespace.useState(false);
2779
+ const memberCountByProfile = React41__namespace.useMemo(() => {
2780
2780
  const counts = {};
2781
2781
  for (const m of members) {
2782
2782
  counts[m.profileId] = (counts[m.profileId] ?? 0) + 1;
@@ -3239,20 +3239,20 @@ function PersonPicker({
3239
3239
  placeholder = "Search or type a name to add...",
3240
3240
  onPersonData
3241
3241
  }) {
3242
- const [open, setOpen] = React40.useState(false);
3243
- const [query, setQuery] = React40.useState("");
3244
- const [results, setResults] = React40.useState([]);
3245
- const [searching, setSearching] = React40.useState(false);
3246
- const [selected, setSelected] = React40.useState(null);
3247
- const [showCreate, setShowCreate] = React40.useState(false);
3248
- const [creating, setCreating] = React40.useState(false);
3249
- const searchTimer = React40.useRef(null);
3250
- const inputRef = React40.useRef(null);
3251
- const containerRef = React40.useRef(null);
3252
- const [newPhone, setNewPhone] = React40.useState("");
3253
- const [newEmail, setNewEmail] = React40.useState("");
3242
+ const [open, setOpen] = React41.useState(false);
3243
+ const [query, setQuery] = React41.useState("");
3244
+ const [results, setResults] = React41.useState([]);
3245
+ const [searching, setSearching] = React41.useState(false);
3246
+ const [selected, setSelected] = React41.useState(null);
3247
+ const [showCreate, setShowCreate] = React41.useState(false);
3248
+ const [creating, setCreating] = React41.useState(false);
3249
+ const searchTimer = React41.useRef(null);
3250
+ const inputRef = React41.useRef(null);
3251
+ const containerRef = React41.useRef(null);
3252
+ const [newPhone, setNewPhone] = React41.useState("");
3253
+ const [newEmail, setNewEmail] = React41.useState("");
3254
3254
  const tenantId = chunkQGMDVLLW_cjs.useOrganizationStore((s) => s.currentOrg?.id);
3255
- React40.useEffect(() => {
3255
+ React41.useEffect(() => {
3256
3256
  if (value && !selected) {
3257
3257
  const supabase = core.getSupabaseClientOptional();
3258
3258
  if (!supabase) return;
@@ -3261,7 +3261,7 @@ function PersonPicker({
3261
3261
  });
3262
3262
  }
3263
3263
  }, [value]);
3264
- React40.useEffect(() => {
3264
+ React41.useEffect(() => {
3265
3265
  const handler = (e) => {
3266
3266
  if (containerRef.current && !containerRef.current.contains(e.target)) {
3267
3267
  setOpen(false);
@@ -3271,7 +3271,7 @@ function PersonPicker({
3271
3271
  document.addEventListener("mousedown", handler);
3272
3272
  return () => document.removeEventListener("mousedown", handler);
3273
3273
  }, []);
3274
- const doSearch = React40.useCallback(async (term) => {
3274
+ const doSearch = React41.useCallback(async (term) => {
3275
3275
  if (!term.trim() || !tenantId) {
3276
3276
  setResults([]);
3277
3277
  return;
@@ -3516,7 +3516,7 @@ function SubjectFormLayout({ fields, allFields, fieldGroups, values, onChange, r
3516
3516
  const IconComponent = LucideIcons4__namespace[entityIcon ?? "Heart"] ?? LucideIcons4__namespace.Heart;
3517
3517
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
3518
3518
  /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.CardContent, { className: "pt-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-5", children: [
3519
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-20 w-20 shrink-0 items-center justify-center rounded-2xl bg-primary/10 text-primary", children: React40__namespace.default.createElement(IconComponent, { className: "h-8 w-8" }) }),
3519
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-20 w-20 shrink-0 items-center justify-center rounded-2xl bg-primary/10 text-primary", children: React41__namespace.default.createElement(IconComponent, { className: "h-8 w-8" }) }),
3520
3520
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-4", children: [
3521
3521
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-4", children: [
3522
3522
  nameField && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-1.5", children: [
@@ -3560,6 +3560,99 @@ function SubjectFormLayout({ fields, allFields, fieldGroups, values, onChange, r
3560
3560
  notesField && /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.CardContent, { className: "pt-5", children: /* @__PURE__ */ jsxRuntime.jsx(FieldItem5, { field: notesField, value: values[notesField.key], onChange: (val) => onChange(notesField.key, val), renderField: renderField2 }) }) })
3561
3561
  ] });
3562
3562
  }
3563
+ var cache = /* @__PURE__ */ new Map();
3564
+ function keyOf(r) {
3565
+ const tenant = r.tenantScoped !== false ? core.getActiveTenantId() ?? "" : "";
3566
+ return JSON.stringify([
3567
+ r.schema ?? "public",
3568
+ r.table,
3569
+ r.valueField ?? "id",
3570
+ r.labelField ?? "name",
3571
+ tenant,
3572
+ r.filter ?? null
3573
+ ]);
3574
+ }
3575
+ async function fetchOptions(r) {
3576
+ const supabase = core.getSupabaseClientOptional();
3577
+ if (!supabase) return [];
3578
+ const valueField = r.valueField ?? "id";
3579
+ const labelField = r.labelField ?? "name";
3580
+ let q = (r.schema ? supabase.schema(r.schema) : supabase).from(r.table).select(`${valueField}, ${labelField}`);
3581
+ if (r.tenantScoped !== false) {
3582
+ const tid = core.getActiveTenantId();
3583
+ if (tid) q = q.eq("tenant_id", tid);
3584
+ }
3585
+ if (r.filter) for (const [k, v] of Object.entries(r.filter)) q = q.eq(k, v);
3586
+ q = q.order(labelField, { ascending: true });
3587
+ const { data } = await q;
3588
+ return (data ?? []).map((row) => ({
3589
+ value: String(row[valueField]),
3590
+ label: String(row[labelField] ?? row[valueField])
3591
+ }));
3592
+ }
3593
+ function loadRelationOptions(r) {
3594
+ const k = keyOf(r);
3595
+ if (!cache.has(k)) {
3596
+ cache.set(k, fetchOptions(r).catch(() => {
3597
+ cache.delete(k);
3598
+ return [];
3599
+ }));
3600
+ }
3601
+ return cache.get(k);
3602
+ }
3603
+ function useRelationOptions(r) {
3604
+ const [options, setOptions] = React41.useState([]);
3605
+ const [loading, setLoading] = React41.useState(true);
3606
+ const dep = r ? keyOf(r) : "none";
3607
+ React41.useEffect(() => {
3608
+ let alive = true;
3609
+ if (!r) {
3610
+ setLoading(false);
3611
+ return;
3612
+ }
3613
+ setLoading(true);
3614
+ loadRelationOptions(r).then((opts) => {
3615
+ if (alive) {
3616
+ setOptions(opts);
3617
+ setLoading(false);
3618
+ }
3619
+ });
3620
+ return () => {
3621
+ alive = false;
3622
+ };
3623
+ }, [dep]);
3624
+ const labelFor = (value) => options.find((o) => o.value === String(value))?.label ?? "";
3625
+ return { options, loading, labelFor };
3626
+ }
3627
+ function RelationSelect({
3628
+ relation,
3629
+ value,
3630
+ onChange,
3631
+ className,
3632
+ required,
3633
+ placeholder
3634
+ }) {
3635
+ const { options, loading } = useRelationOptions(relation);
3636
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3637
+ "select",
3638
+ {
3639
+ value: value ?? "",
3640
+ onChange: (e) => onChange(e.target.value || null),
3641
+ required,
3642
+ className,
3643
+ children: [
3644
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: loading ? "Loading\u2026" : placeholder ?? "Select..." }),
3645
+ options.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
3646
+ ]
3647
+ }
3648
+ );
3649
+ }
3650
+ function RelationCell({ relation, value }) {
3651
+ const { labelFor, loading } = useRelationOptions(relation);
3652
+ if (value == null || value === "") return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "\u2014" });
3653
+ const label = labelFor(value);
3654
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { variant: "secondary", children: label || (loading ? "\u2026" : String(value)) });
3655
+ }
3563
3656
  function currencySymbolFor(code, locale) {
3564
3657
  if (!code) return "R$";
3565
3658
  try {
@@ -3646,6 +3739,18 @@ function renderField(field, value, onChange, allValues = {}) {
3646
3739
  className: `${baseClass} min-h-[60px] py-1.5`
3647
3740
  }
3648
3741
  );
3742
+ case "relation":
3743
+ return /* @__PURE__ */ jsxRuntime.jsx(
3744
+ RelationSelect,
3745
+ {
3746
+ relation: field.relation,
3747
+ value,
3748
+ onChange,
3749
+ className: baseClass,
3750
+ required: field.required,
3751
+ placeholder: field.placeholder ?? `Select ${field.label.toLowerCase()}...`
3752
+ }
3753
+ );
3649
3754
  case "select": {
3650
3755
  const options = (field.options ?? []).map(
3651
3756
  (o) => typeof o === "string" ? { label: o, value: o } : o
@@ -3770,10 +3875,10 @@ function CrudFormPage({ entityDef, mode, initialData, onSubmit, onCancel, namePl
3770
3875
  const formFields = entityDef.fields.filter((f) => f.showInForm !== false);
3771
3876
  const displayField = entityDef.displayField ?? entityDef.fields[0]?.key ?? "id";
3772
3877
  const computeInit = () => mode === "edit" && initialData ? { ...getDefaultValues(formFields), ...initialData } : getDefaultValues(formFields);
3773
- const [values, setValues] = React40.useState(computeInit);
3774
- const [saving, setSaving] = React40.useState(false);
3775
- const initialRef = React40__namespace.default.useRef(JSON.stringify(values));
3776
- React40.useEffect(() => {
3878
+ const [values, setValues] = React41.useState(computeInit);
3879
+ const [saving, setSaving] = React41.useState(false);
3880
+ const initialRef = React41__namespace.default.useRef(JSON.stringify(values));
3881
+ React41.useEffect(() => {
3777
3882
  const init = computeInit();
3778
3883
  setValues(init);
3779
3884
  initialRef.current = JSON.stringify(init);
@@ -3966,6 +4071,8 @@ function fieldToColumns(fields, options) {
3966
4071
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-4 w-4 rounded-full border shrink-0", style: { backgroundColor: String(value) } }),
3967
4072
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: String(value) })
3968
4073
  ] });
4074
+ case "relation":
4075
+ return /* @__PURE__ */ jsxRuntime.jsx(RelationCell, { relation: field.relation, value });
3969
4076
  case "select":
3970
4077
  return /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { variant: "secondary", children: String(value) });
3971
4078
  case "number":
@@ -4076,7 +4183,7 @@ function CrudListView({
4076
4183
  const t = core.useTranslation();
4077
4184
  const namePlural = entityDef.namePlural ?? entityDef.name + "s";
4078
4185
  const displayField = entityDef.displayField ?? entityDef.fields[0]?.key ?? "id";
4079
- const derivedColumns = React40.useMemo(() => {
4186
+ const derivedColumns = React41.useMemo(() => {
4080
4187
  return fieldToColumns(entityDef.fields).map((col) => ({
4081
4188
  accessorKey: col.key,
4082
4189
  header: col.label,
@@ -4368,9 +4475,9 @@ function BlockSettingsPopover({
4368
4475
  onClose
4369
4476
  }) {
4370
4477
  const t = core.useTranslation();
4371
- const popoverRef = React40.useRef(null);
4372
- const [pos, setPos] = React40.useState({ top: 0, left: 0 });
4373
- React40.useEffect(() => {
4478
+ const popoverRef = React41.useRef(null);
4479
+ const [pos, setPos] = React41.useState({ top: 0, left: 0 });
4480
+ React41.useEffect(() => {
4374
4481
  if (!open || !triggerRef.current) return;
4375
4482
  const rect = triggerRef.current.getBoundingClientRect();
4376
4483
  const popW = 280;
@@ -4379,7 +4486,7 @@ function BlockSettingsPopover({
4379
4486
  if (left < 8) left = 8;
4380
4487
  setPos({ top: rect.bottom + 6, left });
4381
4488
  }, [open, triggerRef]);
4382
- React40.useEffect(() => {
4489
+ React41.useEffect(() => {
4383
4490
  if (!open) return;
4384
4491
  const handler = (e) => {
4385
4492
  if (popoverRef.current?.contains(e.target)) return;
@@ -4510,9 +4617,9 @@ function LocationSelect({
4510
4617
  onChange
4511
4618
  }) {
4512
4619
  const t = core.useTranslation();
4513
- const [open, setOpen] = React40.useState(false);
4514
- const ref = React40.useRef(null);
4515
- React40.useEffect(() => {
4620
+ const [open, setOpen] = React41.useState(false);
4621
+ const ref = React41.useRef(null);
4622
+ React41.useEffect(() => {
4516
4623
  if (!open) return;
4517
4624
  const handler = (e) => {
4518
4625
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -4571,9 +4678,9 @@ function ServiceSelect({
4571
4678
  onChange
4572
4679
  }) {
4573
4680
  const t = core.useTranslation();
4574
- const [open, setOpen] = React40.useState(false);
4575
- const ref = React40.useRef(null);
4576
- React40.useEffect(() => {
4681
+ const [open, setOpen] = React41.useState(false);
4682
+ const ref = React41.useRef(null);
4683
+ React41.useEffect(() => {
4577
4684
  if (!open) return;
4578
4685
  const handler = (e) => {
4579
4686
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -4700,7 +4807,7 @@ function PeriodRow({
4700
4807
  onAddBlock
4701
4808
  }) {
4702
4809
  const t = core.useTranslation();
4703
- const gearRef = React40.useRef(null);
4810
+ const gearRef = React41.useRef(null);
4704
4811
  const bufferValue = period.settings?.bufferMinutes ?? blockConfig?.defaults.bufferMinutes ?? 0;
4705
4812
  const hasCustomSettings = period.settings && Object.entries(period.settings).some(
4706
4813
  ([k, v]) => k !== "bufferMinutes" && v !== void 0
@@ -4794,27 +4901,27 @@ function PeriodRow({
4794
4901
  }
4795
4902
  function ScheduleEditor({ assigneeId }) {
4796
4903
  const t = core.useTranslation();
4797
- const [week, setWeek] = React40.useState({});
4798
- const [exceptions, setExceptions] = React40.useState([]);
4799
- const [loading, setLoading] = React40.useState(true);
4800
- const [saving, setSaving] = React40.useState(false);
4801
- const [showAddException, setShowAddException] = React40.useState(false);
4802
- const blockConfig = React40.useSyncExternalStore(subscribeScheduleBlockConfig, getScheduleBlockConfig);
4803
- const [settingsPopover, setSettingsPopover] = React40.useState(null);
4804
- const [weekDirty, setWeekDirty] = React40.useState(false);
4805
- React40.useEffect(() => {
4904
+ const [week, setWeek] = React41.useState({});
4905
+ const [exceptions, setExceptions] = React41.useState([]);
4906
+ const [loading, setLoading] = React41.useState(true);
4907
+ const [saving, setSaving] = React41.useState(false);
4908
+ const [showAddException, setShowAddException] = React41.useState(false);
4909
+ const blockConfig = React41.useSyncExternalStore(subscribeScheduleBlockConfig, getScheduleBlockConfig);
4910
+ const [settingsPopover, setSettingsPopover] = React41.useState(null);
4911
+ const [weekDirty, setWeekDirty] = React41.useState(false);
4912
+ React41.useEffect(() => {
4806
4913
  if (blockConfig?.showLocations && (!blockConfig.locations || blockConfig.locations.length === 0) && blockConfig.fetchLocations) {
4807
4914
  blockConfig.fetchLocations().catch(() => {
4808
4915
  });
4809
4916
  }
4810
4917
  }, [blockConfig?.showLocations, blockConfig?.locations?.length]);
4811
- const [newExStartDate, setNewExStartDate] = React40.useState("");
4812
- const [newExEndDate, setNewExEndDate] = React40.useState("");
4813
- const [newExType, setNewExType] = React40.useState("unavailable");
4814
- const [newExPeriods, setNewExPeriods] = React40.useState([{ startsAt: "09:00", endsAt: "17:00" }]);
4815
- const [newExNotes, setNewExNotes] = React40.useState("");
4816
- const [savingException, setSavingException] = React40.useState(false);
4817
- const loadData = React40.useCallback(async () => {
4918
+ const [newExStartDate, setNewExStartDate] = React41.useState("");
4919
+ const [newExEndDate, setNewExEndDate] = React41.useState("");
4920
+ const [newExType, setNewExType] = React41.useState("unavailable");
4921
+ const [newExPeriods, setNewExPeriods] = React41.useState([{ startsAt: "09:00", endsAt: "17:00" }]);
4922
+ const [newExNotes, setNewExNotes] = React41.useState("");
4923
+ const [savingException, setSavingException] = React41.useState(false);
4924
+ const loadData = React41.useCallback(async () => {
4818
4925
  setLoading(true);
4819
4926
  try {
4820
4927
  const data = await getSchedules(assigneeId);
@@ -4826,7 +4933,7 @@ function ScheduleEditor({ assigneeId }) {
4826
4933
  }
4827
4934
  setLoading(false);
4828
4935
  }, [assigneeId]);
4829
- React40.useEffect(() => {
4936
+ React41.useEffect(() => {
4830
4937
  loadData();
4831
4938
  }, [loadData]);
4832
4939
  function markDirty() {
@@ -5293,6 +5400,25 @@ function DocumentsTab({ item }) {
5293
5400
  }
5294
5401
  );
5295
5402
  }
5403
+ function FinancialTab({ item }) {
5404
+ const runtime = core.usePluginRuntimeOptional();
5405
+ const widgets = runtime ? core.getWidgetsForZone(runtime, "person.detail.financial") : [];
5406
+ if (widgets.length > 0 && item) {
5407
+ const w = widgets[0];
5408
+ const Widget = w.component;
5409
+ return /* @__PURE__ */ jsxRuntime.jsx(
5410
+ Widget,
5411
+ {
5412
+ item,
5413
+ config: w.config,
5414
+ runtime: runtime?.context,
5415
+ plugin: w.plugin,
5416
+ widget: w
5417
+ }
5418
+ );
5419
+ }
5420
+ return null;
5421
+ }
5296
5422
  function ScheduleTab({ item }) {
5297
5423
  const t = core.useTranslation();
5298
5424
  if (!item?.id) {
@@ -5310,6 +5436,9 @@ function ScheduleTab({ item }) {
5310
5436
  var PERSON_DETAIL_TABS = [
5311
5437
  { id: "schedule", label: "Schedule", icon: "CalendarDays", component: ScheduleTab, visibleFor: ["staff"] },
5312
5438
  { id: "documents", label: "Documents", icon: "FileText", component: DocumentsTab },
5439
+ // Per-person financial statement — only shown when the financial plugin contributes
5440
+ // its widget (see requiresWidgetZone). Clients = paid invoices; staff = commissions.
5441
+ { id: "financial", label: "Statement", icon: "DollarSign", component: FinancialTab, requiresWidgetZone: "person.detail.financial" },
5313
5442
  { id: "activity", label: "Activity", icon: "Clock", component: ActivityTab }
5314
5443
  ];
5315
5444
  function ComingSoon2({ icon: Icon, title, description }) {
@@ -5519,9 +5648,9 @@ function ComingSoon5({ icon: Icon, title, description }) {
5519
5648
  }
5520
5649
  function OwnerTab({ item }) {
5521
5650
  const t = core.useTranslation();
5522
- const [person, setPerson] = React40.useState(null);
5523
- const [loading, setLoading] = React40.useState(true);
5524
- React40.useEffect(() => {
5651
+ const [person, setPerson] = React41.useState(null);
5652
+ const [loading, setLoading] = React41.useState(true);
5653
+ React41.useEffect(() => {
5525
5654
  const tutorId = item?.tutorId;
5526
5655
  if (!tutorId) {
5527
5656
  setLoading(false);
@@ -5762,13 +5891,14 @@ function CrudDetailPage({
5762
5891
  const subtitleValue = entityDef.subtitleField ? item[entityDef.subtitleField] : null;
5763
5892
  const imageValue = entityDef.imageField ? item[entityDef.imageField] : null;
5764
5893
  const initial = typeof displayValue === "string" ? displayValue.charAt(0).toUpperCase() : "?";
5894
+ const runtime = core.usePluginRuntimeOptional();
5765
5895
  const archetypeTabs = getArchetypeTabs(entityDef.layout, entityDef.data?.archetypeKind);
5766
- const customTabs = [...archetypeTabs, ...entityDef.detailTabs ?? []];
5896
+ const customTabs = [...archetypeTabs, ...entityDef.detailTabs ?? []].filter((tab) => !tab.requiresWidgetZone || (runtime ? core.getWidgetsForZone(runtime, tab.requiresWidgetZone).length > 0 : false));
5767
5897
  const entityId = entityDef.name.toLowerCase().replace(/\s+/g, "-");
5768
5898
  const widgetZone = `${entityId}.detail.tabs`;
5769
5899
  const validTabs = ["overview", ...customTabs.map((t2) => t2.id)];
5770
5900
  const activeTab = initialTab && validTabs.includes(initialTab) ? initialTab : "overview";
5771
- const handleTabChange = React40.useCallback((value) => {
5901
+ const handleTabChange = React41.useCallback((value) => {
5772
5902
  if (embedded) return;
5773
5903
  const detailPath = `${basePath}/${item.id}`;
5774
5904
  const newHash = value === "overview" ? detailPath : `${detailPath}/${value}`;
@@ -5819,7 +5949,7 @@ function CrudDetailPage({
5819
5949
  })
5820
5950
  ] }),
5821
5951
  /* @__PURE__ */ jsxRuntime.jsx(ui.TabsContent, { value: "overview", className: embedded ? "mt-2" : "mt-4", children: /* @__PURE__ */ jsxRuntime.jsx(OverviewTab, { entityDef, item, compact: embedded }) }),
5822
- customTabs.map((tab) => /* @__PURE__ */ jsxRuntime.jsx(ui.TabsContent, { value: tab.id, className: "mt-4", children: tab.component ? React40__namespace.default.createElement(tab.component, { item, entityDef, ...tab.props ?? {} }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.CardContent, { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: t("common.noContent") }) }) }) }, tab.id))
5952
+ customTabs.map((tab) => /* @__PURE__ */ jsxRuntime.jsx(ui.TabsContent, { value: tab.id, className: "mt-4", children: tab.component ? React41__namespace.default.createElement(tab.component, { item, entityDef, ...tab.props ?? {} }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.CardContent, { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: t("common.noContent") }) }) }) }, tab.id))
5823
5953
  ] }),
5824
5954
  /* @__PURE__ */ jsxRuntime.jsx(WidgetSlot, { zone: widgetZone })
5825
5955
  ] });
@@ -5944,7 +6074,7 @@ function StepIndicator({ current }) {
5944
6074
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1.5", children: STEPS.map((step, i) => {
5945
6075
  const isDone = i < currentIdx || current === "done";
5946
6076
  const isActive = step === current;
5947
- return /* @__PURE__ */ jsxRuntime.jsxs(React40__namespace.default.Fragment, { children: [
6077
+ return /* @__PURE__ */ jsxRuntime.jsxs(React41__namespace.default.Fragment, { children: [
5948
6078
  i > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: ui.cn("h-px w-6", isDone ? "bg-primary" : "bg-border") }),
5949
6079
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
5950
6080
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -5997,9 +6127,9 @@ function UploadStep({
5997
6127
  onBack
5998
6128
  }) {
5999
6129
  const t = core.useTranslation();
6000
- const inputRef = React40.useRef(null);
6001
- const [dragOver, setDragOver] = React40.useState(false);
6002
- const [error, setError] = React40.useState(null);
6130
+ const inputRef = React41.useRef(null);
6131
+ const [dragOver, setDragOver] = React41.useState(false);
6132
+ const [error, setError] = React41.useState(null);
6003
6133
  const processFile = (file) => {
6004
6134
  setError(null);
6005
6135
  if (!file.name.endsWith(".csv")) {
@@ -6083,7 +6213,7 @@ function MappingStep({
6083
6213
  onBack
6084
6214
  }) {
6085
6215
  const t = core.useTranslation();
6086
- const initialMapping = React40.useMemo(() => {
6216
+ const initialMapping = React41.useMemo(() => {
6087
6217
  const map = /* @__PURE__ */ new Map();
6088
6218
  for (let i = 0; i < csv.headers.length; i++) {
6089
6219
  const header = csv.headers[i].toLowerCase().trim();
@@ -6094,7 +6224,7 @@ function MappingStep({
6094
6224
  }
6095
6225
  return map;
6096
6226
  }, [csv.headers, fields]);
6097
- const [mapping, setMapping] = React40.useState(initialMapping);
6227
+ const [mapping, setMapping] = React41.useState(initialMapping);
6098
6228
  const mappedCount = Array.from(mapping.values()).filter(Boolean).length;
6099
6229
  const previewRows = csv.rows.slice(0, 3);
6100
6230
  const handleSelect = (colIdx, fieldKey) => {
@@ -6249,12 +6379,12 @@ function ImportingStep({
6249
6379
  }
6250
6380
  function ImportWizard({ open, onClose, entityDef, onImport }) {
6251
6381
  const t = core.useTranslation();
6252
- const [step, setStep] = React40.useState("download");
6253
- const [csv, setCsv] = React40.useState(null);
6254
- const [fileName, setFileName] = React40.useState("");
6255
- const [result, setResult] = React40.useState(null);
6256
- const [progress, setProgress] = React40.useState(null);
6257
- const fields = React40.useMemo(() => getImportableFields(entityDef), [entityDef]);
6382
+ const [step, setStep] = React41.useState("download");
6383
+ const [csv, setCsv] = React41.useState(null);
6384
+ const [fileName, setFileName] = React41.useState("");
6385
+ const [result, setResult] = React41.useState(null);
6386
+ const [progress, setProgress] = React41.useState(null);
6387
+ const fields = React41.useMemo(() => getImportableFields(entityDef), [entityDef]);
6258
6388
  const handleClose = () => {
6259
6389
  setStep("download");
6260
6390
  setCsv(null);
@@ -6268,7 +6398,7 @@ function ImportWizard({ open, onClose, entityDef, onImport }) {
6268
6398
  setFileName(name);
6269
6399
  setStep("mapping");
6270
6400
  };
6271
- const handleConfirmMapping = React40.useCallback(async (mapping) => {
6401
+ const handleConfirmMapping = React41.useCallback(async (mapping) => {
6272
6402
  if (!csv) return;
6273
6403
  setStep("importing");
6274
6404
  setResult(null);
@@ -6372,10 +6502,10 @@ function useSubRoute(basePath) {
6372
6502
  if (hash === normalizedBasePath) return "";
6373
6503
  return hash.startsWith(`${normalizedBasePath}/`) ? hash.slice(normalizedBasePath.length) : "";
6374
6504
  };
6375
- const [sub, setSub] = React40.useState(getSub);
6376
- const [direction, setDirection] = React40.useState("forward");
6377
- const prevDepthRef = React40.useRef(getRouteDepth(getSub()));
6378
- React40.useEffect(() => {
6505
+ const [sub, setSub] = React41.useState(getSub);
6506
+ const [direction, setDirection] = React41.useState("forward");
6507
+ const prevDepthRef = React41.useRef(getRouteDepth(getSub()));
6508
+ React41.useEffect(() => {
6379
6509
  const handler = () => {
6380
6510
  const next = getSub();
6381
6511
  const nextDepth = getRouteDepth(next);
@@ -6391,7 +6521,7 @@ function useSubRoute(basePath) {
6391
6521
  function useCrudColumns(entityDef, options) {
6392
6522
  const displayField = entityDef.displayField ?? entityDef.fields[0]?.key ?? "id";
6393
6523
  const cols = fieldToColumns(entityDef.fields, { onInlineUpdate: options?.onInlineUpdate });
6394
- return React40.useMemo(() => {
6524
+ return React41.useMemo(() => {
6395
6525
  const tanCols = cols.map((col) => ({
6396
6526
  accessorKey: col.key,
6397
6527
  header: col.label,
@@ -6455,18 +6585,18 @@ function CrudPage({ entityDef: rawEntityDef, useStore, basePath, display, featur
6455
6585
  const { sub, direction } = useSubRoute(normalizedBasePath);
6456
6586
  core.deriveEntityKey(rawEntityDef);
6457
6587
  const { applyRules } = useFieldRules();
6458
- const entityDef = React40.useMemo(() => ({
6588
+ const entityDef = React41.useMemo(() => ({
6459
6589
  ...rawEntityDef,
6460
6590
  fields: applyRules(rawEntityDef.fields)
6461
6591
  }), [rawEntityDef, applyRules]);
6462
- const [deleteItem, setDeleteItem] = React40.useState(null);
6463
- const [searchInput, setSearchInput] = React40.useState("");
6464
- const [importOpen, setImportOpen] = React40.useState(false);
6465
- const [activeFilters, setActiveFilters] = React40.useState({});
6466
- const activeFiltersRef = React40.useRef({});
6592
+ const [deleteItem, setDeleteItem] = React41.useState(null);
6593
+ const [searchInput, setSearchInput] = React41.useState("");
6594
+ const [importOpen, setImportOpen] = React41.useState(false);
6595
+ const [activeFilters, setActiveFilters] = React41.useState({});
6596
+ const activeFiltersRef = React41.useRef({});
6467
6597
  const namePlural = entityDef.namePlural ?? entityDef.name + "s";
6468
6598
  const displayField = entityDef.displayField ?? entityDef.fields[0]?.key ?? "id";
6469
- const resolvedFacets = React40.useMemo(() => {
6599
+ const resolvedFacets = React41.useMemo(() => {
6470
6600
  return (entityDef.facets ?? []).map((f) => {
6471
6601
  const field = entityDef.fields.find((x) => x.key === f.field);
6472
6602
  const options = (field?.options ?? []).map(
@@ -6475,7 +6605,7 @@ function CrudPage({ entityDef: rawEntityDef, useStore, basePath, display, featur
6475
6605
  return { field: f.field, options, allLabel: f.allLabel };
6476
6606
  });
6477
6607
  }, [entityDef]);
6478
- const handleFacetChange = React40.useCallback((field, value) => {
6608
+ const handleFacetChange = React41.useCallback((field, value) => {
6479
6609
  const next = { ...activeFiltersRef.current };
6480
6610
  if (value == null) delete next[field];
6481
6611
  else next[field] = value;
@@ -6483,20 +6613,20 @@ function CrudPage({ entityDef: rawEntityDef, useStore, basePath, display, featur
6483
6613
  setActiveFilters(next);
6484
6614
  store.setQuery({ filters: next });
6485
6615
  }, [store]);
6486
- const searchTimer = React40.useRef(null);
6487
- const handleInlineUpdate = React40.useCallback(async (id, field, value) => {
6616
+ const searchTimer = React41.useRef(null);
6617
+ const handleInlineUpdate = React41.useCallback(async (id, field, value) => {
6488
6618
  await store.update(id, { [field]: value });
6489
6619
  }, [store]);
6490
6620
  const tanColumns = useCrudColumns(entityDef, { basePath: normalizedBasePath, onDelete: readOnly ? void 0 : (item) => setDeleteItem(item), onInlineUpdate: handleInlineUpdate, feature, readOnly });
6491
6621
  const currentOrgId = chunkQGMDVLLW_cjs.useOrganizationStore((s) => s.currentOrg?.id);
6492
- React40.useEffect(() => {
6622
+ React41.useEffect(() => {
6493
6623
  if (currentOrgId) store.fetch();
6494
6624
  }, [currentOrgId]);
6495
6625
  const navigateToList = () => {
6496
6626
  setCrudHash(normalizedBasePath);
6497
6627
  };
6498
6628
  const animClass = direction === "forward" ? "saas-nav-forward" : "saas-nav-back";
6499
- const handleImport = React40.useCallback(async (rows, onProgress) => {
6629
+ const handleImport = React41.useCallback(async (rows, onProgress) => {
6500
6630
  if (!core.getSupabaseClientOptional()) {
6501
6631
  return {
6502
6632
  success: 0,
@@ -6518,7 +6648,7 @@ function CrudPage({ entityDef: rawEntityDef, useStore, basePath, display, featur
6518
6648
  }
6519
6649
  return { success, errors };
6520
6650
  }, [store, t]);
6521
- const handleExport = React40.useCallback(() => {
6651
+ const handleExport = React41.useCallback(() => {
6522
6652
  const items = store.items;
6523
6653
  if (!items || items.length === 0) {
6524
6654
  ui.toast.error(t("crud.export.noData"));
@@ -6832,7 +6962,7 @@ function createCrudPage(entityDef, options) {
6832
6962
  eagerStore = createCrudStore(options.dataProvider);
6833
6963
  }
6834
6964
  const GeneratedCrudPage = () => {
6835
- const useStore = React40.useMemo(() => {
6965
+ const useStore = React41.useMemo(() => {
6836
6966
  if (eagerStore) return eagerStore;
6837
6967
  const provider = core.resolveDataProvider(entityDef, options?.mockData);
6838
6968
  return createCrudStore(provider);
@@ -6968,7 +7098,7 @@ function EntityAccordion({
6968
7098
  onReset
6969
7099
  }) {
6970
7100
  const { t } = useTranslation();
6971
- const [open, setOpen] = React40.useState(false);
7101
+ const [open, setOpen] = React41.useState(false);
6972
7102
  const modified = countModified(entity.fields, rules);
6973
7103
  const Icon = resolveIcon(entity.icon);
6974
7104
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { children: [
@@ -7065,18 +7195,18 @@ function PluginSectionHeader({ name, iconName }) {
7065
7195
  }
7066
7196
  function FieldRulesSettings({ entities, rules: initialRules, onSave }) {
7067
7197
  const { t } = useTranslation();
7068
- const [draft, setDraft] = React40.useState(initialRules);
7069
- const [saving, setSaving] = React40.useState(false);
7070
- const [search, setSearch] = React40.useState("");
7071
- const [showMore, setShowMore] = React40.useState(false);
7072
- React40__namespace.useEffect(() => {
7198
+ const [draft, setDraft] = React41.useState(initialRules);
7199
+ const [saving, setSaving] = React41.useState(false);
7200
+ const [search, setSearch] = React41.useState("");
7201
+ const [showMore, setShowMore] = React41.useState(false);
7202
+ React41__namespace.useEffect(() => {
7073
7203
  setDraft(initialRules);
7074
7204
  }, [initialRules]);
7075
- const isDirty = React40.useMemo(
7205
+ const isDirty = React41.useMemo(
7076
7206
  () => JSON.stringify(draft) !== JSON.stringify(initialRules),
7077
7207
  [draft, initialRules]
7078
7208
  );
7079
- const { coreEntities, standaloneEntities, pluginGroups } = React40.useMemo(() => {
7209
+ const { coreEntities, standaloneEntities, pluginGroups } = React41.useMemo(() => {
7080
7210
  const q = search.trim().toLowerCase();
7081
7211
  const core = [];
7082
7212
  const standalone = [];
@@ -7127,7 +7257,7 @@ function FieldRulesSettings({ entities, rules: initialRules, onSave }) {
7127
7257
  const showExtras = hasExtras && (showMore || isSearching);
7128
7258
  const extraCount = standaloneEntities.length + pluginGroups.reduce((sum, g) => sum + g.entities.length, 0);
7129
7259
  const hasNoResults = coreEntities.length === 0 && !hasExtras;
7130
- const handleToggle = React40.useCallback(
7260
+ const handleToggle = React41.useCallback(
7131
7261
  (entityKey, fieldKey, ruleKey, value) => {
7132
7262
  setDraft((prev) => {
7133
7263
  const entityRules = { ...prev[entityKey] };
@@ -7139,7 +7269,7 @@ function FieldRulesSettings({ entities, rules: initialRules, onSave }) {
7139
7269
  },
7140
7270
  []
7141
7271
  );
7142
- const handleReset = React40.useCallback((entityKey) => {
7272
+ const handleReset = React41.useCallback((entityKey) => {
7143
7273
  setDraft((prev) => {
7144
7274
  const next = { ...prev };
7145
7275
  delete next[entityKey];
@@ -7425,8 +7555,8 @@ function buildSettingsTabs(pluginTabs, can, t, showOrgSettings) {
7425
7555
  settingsTabs.push({
7426
7556
  id: tab.id,
7427
7557
  label: translated === labelKey ? tab.label : translated,
7428
- icon: React40__namespace.createElement(IconComp, { className: "h-4 w-4" }),
7429
- component: React40__namespace.createElement(tab.component),
7558
+ icon: React41__namespace.createElement(IconComp, { className: "h-4 w-4" }),
7559
+ component: React41__namespace.createElement(tab.component),
7430
7560
  // Flag plugin-contributed tabs so SettingsPage draws the core/plugins divider.
7431
7561
  isPlugin: true
7432
7562
  });
@@ -7443,7 +7573,7 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
7443
7573
  };
7444
7574
  const path = useAdminPath();
7445
7575
  const { user, signOut } = auth.useAuth();
7446
- const navigation = React40__namespace.useMemo(() => {
7576
+ const navigation = React41__namespace.useMemo(() => {
7447
7577
  const items = runtime.navigation.map((entry) => ({
7448
7578
  ...navEntryToItem(entry),
7449
7579
  position: entry.position
@@ -7454,7 +7584,7 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
7454
7584
  }
7455
7585
  return items.sort(compareNavigation);
7456
7586
  }, [runtime.navigation, pages]);
7457
- const routes = React40__namespace.useMemo(() => {
7587
+ const routes = React41__namespace.useMemo(() => {
7458
7588
  const list = [];
7459
7589
  const entityRouteMap = /* @__PURE__ */ new Map();
7460
7590
  for (const r of runtime.routes) {
@@ -7470,27 +7600,27 @@ function AdminShellInner({ appName, layout = "sidebar", logo, pages = [], showSe
7470
7600
  setEntityRouteMap(entityRouteMap);
7471
7601
  return list.sort((a, b) => routeScore(b.path) - routeScore(a.path));
7472
7602
  }, [runtime.routes, pages, showSettings]);
7473
- const match = React40__namespace.useMemo(() => {
7603
+ const match = React41__namespace.useMemo(() => {
7474
7604
  for (const r of routes) {
7475
7605
  const params = matchRoute(r.path, path);
7476
7606
  if (params) return { route: r, params };
7477
7607
  }
7478
7608
  return null;
7479
7609
  }, [routes, path]);
7480
- React40__namespace.useEffect(() => {
7610
+ React41__namespace.useEffect(() => {
7481
7611
  if (!match && (path === "/" || path === "") && navigation.length > 0) {
7482
7612
  navigateTo(navigation[0].route);
7483
7613
  }
7484
7614
  }, [match, path, navigation]);
7485
7615
  const ActiveComponent = match?.route.Component;
7486
7616
  const activeParams = match?.params ?? {};
7487
- const settingsTabs = React40__namespace.useMemo(
7617
+ const settingsTabs = React41__namespace.useMemo(
7488
7618
  () => buildSettingsTabs(runtime.settingsTabs, can, t, showOrgSettings),
7489
7619
  [runtime.settingsTabs, can, t, showOrgSettings]
7490
7620
  );
7491
7621
  const shellUser = user ? { fullName: user.fullName ?? user.email, email: user.email, avatarUrl: user.avatarUrl } : void 0;
7492
7622
  const moduleVariant = moduleNav ?? (layout === "sidebar" ? "tabs" : "rail");
7493
- const activePageTitle = React40__namespace.useMemo(() => {
7623
+ const activePageTitle = React41__namespace.useMemo(() => {
7494
7624
  if (path === "/settings" || path.startsWith("/settings/")) return tr("common.settings", "Settings");
7495
7625
  const candidates = navigation.filter((n) => n.route).sort((a, b) => b.route.length - a.route.length);
7496
7626
  const hit = candidates.find(
@@ -7611,7 +7741,7 @@ function buildI18nConfig(config) {
7611
7741
  }
7612
7742
  function BillingInitializer({ config }) {
7613
7743
  const setPlans = chunkKYID2MR6_cjs.useBillingStore((s) => s.setPlans);
7614
- React40__namespace.useEffect(() => {
7744
+ React41__namespace.useEffect(() => {
7615
7745
  if (config.billing?.plans) setPlans(config.billing.plans.map(normalizeBillingPlan));
7616
7746
  }, [config.billing, setPlans]);
7617
7747
  return null;
@@ -7633,7 +7763,7 @@ function ThemeInitializer({ config }) {
7633
7763
  const initialize = useThemeStore((s) => s.initialize);
7634
7764
  const setOverrides = useThemeStore((s) => s.setOverrides);
7635
7765
  const setMode = useThemeStore((s) => s.setMode);
7636
- React40__namespace.useEffect(() => {
7766
+ React41__namespace.useEffect(() => {
7637
7767
  if (config.theme) {
7638
7768
  const isSaasTheme = "brand" in config.theme && ("radius" in config.theme || "sidebar" in config.theme || "font" in config.theme);
7639
7769
  const resolved = isSaasTheme ? resolveTheme(config.theme) : config.theme;
@@ -7648,7 +7778,7 @@ function ThemeInitializer({ config }) {
7648
7778
  }
7649
7779
  function AdminProviders({ config, children }) {
7650
7780
  const currentOrg = chunkQGMDVLLW_cjs.useOrganizationStore((s) => s.currentOrg);
7651
- const resolved = React40__namespace.useMemo(() => {
7781
+ const resolved = React41__namespace.useMemo(() => {
7652
7782
  if (config.supabaseUrl && config.supabaseAnonKey) {
7653
7783
  chunkQGMDVLLW_cjs.createFayzSupabaseClient(config.supabaseUrl, config.supabaseAnonKey);
7654
7784
  }
@@ -7662,7 +7792,7 @@ function AdminProviders({ config, children }) {
7662
7792
  };
7663
7793
  }, [config]);
7664
7794
  const path = useAdminPath();
7665
- const runtime = React40__namespace.useMemo(
7795
+ const runtime = React41__namespace.useMemo(
7666
7796
  () => core.resolvePluginRuntime({
7667
7797
  plugins: resolved.plugins,
7668
7798
  context: {
@@ -7754,10 +7884,10 @@ function hashRouterAdapter2() {
7754
7884
  window.location.hash = path;
7755
7885
  },
7756
7886
  usePathname: () => {
7757
- const [pathname, setPathname] = React40__namespace.useState(
7887
+ const [pathname, setPathname] = React41__namespace.useState(
7758
7888
  typeof window !== "undefined" ? window.location.hash.slice(1) || "/" : "/"
7759
7889
  );
7760
- React40__namespace.useEffect(() => {
7890
+ React41__namespace.useEffect(() => {
7761
7891
  const handler = () => setPathname(window.location.hash.slice(1) || "/");
7762
7892
  window.addEventListener("hashchange", handler);
7763
7893
  return () => window.removeEventListener("hashchange", handler);
@@ -7766,7 +7896,7 @@ function hashRouterAdapter2() {
7766
7896
  }
7767
7897
  };
7768
7898
  }
7769
- var RouterContext = React40__namespace.createContext(null);
7899
+ var RouterContext = React41__namespace.createContext(null);
7770
7900
  var RouterProvider = RouterContext.Provider;
7771
7901
  function MockModeBanner() {
7772
7902
  const { t } = useTranslation();
@@ -7923,7 +8053,7 @@ function SubscriptionCard({
7923
8053
  }
7924
8054
  function useBilling() {
7925
8055
  const store = chunkKYID2MR6_cjs.useBillingStore();
7926
- const fetchPlans = React40.useCallback(async () => {
8056
+ const fetchPlans = React41.useCallback(async () => {
7927
8057
  store.setLoading(true);
7928
8058
  try {
7929
8059
  const supabase = chunkQGMDVLLW_cjs.getFayzSupabaseClient();
@@ -7936,7 +8066,7 @@ function useBilling() {
7936
8066
  store.setLoading(false);
7937
8067
  }
7938
8068
  }, [store]);
7939
- const fetchSubscription = React40.useCallback(async () => {
8069
+ const fetchSubscription = React41.useCallback(async () => {
7940
8070
  store.setLoading(true);
7941
8071
  try {
7942
8072
  const supabase = chunkQGMDVLLW_cjs.getFayzSupabaseClient();
@@ -7949,7 +8079,7 @@ function useBilling() {
7949
8079
  store.setLoading(false);
7950
8080
  }
7951
8081
  }, [store]);
7952
- const fetchInvoices = React40.useCallback(async () => {
8082
+ const fetchInvoices = React41.useCallback(async () => {
7953
8083
  store.setLoading(true);
7954
8084
  try {
7955
8085
  const supabase = chunkQGMDVLLW_cjs.getFayzSupabaseClient();
@@ -7962,7 +8092,7 @@ function useBilling() {
7962
8092
  store.setLoading(false);
7963
8093
  }
7964
8094
  }, [store]);
7965
- const subscribe = React40.useCallback(
8095
+ const subscribe = React41.useCallback(
7966
8096
  async (planId, interval) => {
7967
8097
  store.setLoading(true);
7968
8098
  try {
@@ -7984,7 +8114,7 @@ function useBilling() {
7984
8114
  },
7985
8115
  [store]
7986
8116
  );
7987
- const cancelSubscription = React40.useCallback(async () => {
8117
+ const cancelSubscription = React41.useCallback(async () => {
7988
8118
  store.setLoading(true);
7989
8119
  try {
7990
8120
  const supabase = chunkQGMDVLLW_cjs.getFayzSupabaseClient();
@@ -8001,7 +8131,7 @@ function useBilling() {
8001
8131
  store.setLoading(false);
8002
8132
  }
8003
8133
  }, [store, fetchSubscription]);
8004
- const resumeSubscription = React40.useCallback(async () => {
8134
+ const resumeSubscription = React41.useCallback(async () => {
8005
8135
  store.setLoading(true);
8006
8136
  try {
8007
8137
  const supabase = chunkQGMDVLLW_cjs.getFayzSupabaseClient();
@@ -8018,7 +8148,7 @@ function useBilling() {
8018
8148
  store.setLoading(false);
8019
8149
  }
8020
8150
  }, [store, fetchSubscription]);
8021
- return React40.useMemo(
8151
+ return React41.useMemo(
8022
8152
  () => ({
8023
8153
  subscription: store.subscription,
8024
8154
  invoices: store.invoices,
@@ -8049,8 +8179,8 @@ function BillingPage({ className }) {
8049
8179
  const { plans, subscription, loading } = chunkKYID2MR6_cjs.useBillingStore();
8050
8180
  const billing = useBilling();
8051
8181
  const { t } = useTranslation();
8052
- const [interval, setInterval2] = React40__namespace.useState("monthly");
8053
- React40__namespace.useEffect(() => {
8182
+ const [interval, setInterval2] = React41__namespace.useState("monthly");
8183
+ React41__namespace.useEffect(() => {
8054
8184
  billing.fetchSubscription();
8055
8185
  }, []);
8056
8186
  const currentPlan = plans.find((p) => p.id === subscription?.planId);
@@ -8128,10 +8258,10 @@ var ENTITY_ICON = {
8128
8258
  services: LucideIcons4.Sparkles
8129
8259
  };
8130
8260
  function useEntitySearch(searchFn, query, open) {
8131
- const [results, setResults] = React40.useState([]);
8132
- const [loading, setLoading] = React40.useState(false);
8133
- const abortRef = React40.useRef(0);
8134
- React40.useEffect(() => {
8261
+ const [results, setResults] = React41.useState([]);
8262
+ const [loading, setLoading] = React41.useState(false);
8263
+ const abortRef = React41.useRef(0);
8264
+ React41.useEffect(() => {
8135
8265
  if (!open) {
8136
8266
  setResults([]);
8137
8267
  setLoading(false);
@@ -8165,9 +8295,9 @@ function useEntitySearch(searchFn, query, open) {
8165
8295
  }
8166
8296
  function CommandPalette({ commands = [], open, onOpenChange, onEntitySearch, onEntitySelect }) {
8167
8297
  const { t } = useTranslation();
8168
- const [search, setSearch] = React40.useState("");
8298
+ const [search, setSearch] = React41.useState("");
8169
8299
  const { results: entityResults, loading: entityLoading } = useEntitySearch(onEntitySearch, search, open);
8170
- React40.useEffect(() => {
8300
+ React41.useEffect(() => {
8171
8301
  const handleKeyDown = (e) => {
8172
8302
  if ((e.metaKey || e.ctrlKey) && e.key === "k") {
8173
8303
  e.preventDefault();
@@ -8177,7 +8307,7 @@ function CommandPalette({ commands = [], open, onOpenChange, onEntitySearch, onE
8177
8307
  document.addEventListener("keydown", handleKeyDown);
8178
8308
  return () => document.removeEventListener("keydown", handleKeyDown);
8179
8309
  }, [open, onOpenChange]);
8180
- React40.useEffect(() => {
8310
+ React41.useEffect(() => {
8181
8311
  if (!open) setSearch("");
8182
8312
  }, [open]);
8183
8313
  const grouped = commands.reduce((acc, cmd) => {
@@ -8296,7 +8426,7 @@ function CommandPalette({ commands = [], open, onOpenChange, onEntitySearch, onE
8296
8426
  function useAuth3() {
8297
8427
  const store = useAuthStore();
8298
8428
  const adapter2 = useAuthAdapterOptional();
8299
- React40.useEffect(() => {
8429
+ React41.useEffect(() => {
8300
8430
  if (!adapter2) {
8301
8431
  store.setInitialized(true);
8302
8432
  store.setLoading(false);
@@ -8323,7 +8453,7 @@ function useAuth3() {
8323
8453
  });
8324
8454
  return unsubscribe;
8325
8455
  }, []);
8326
- const signIn = React40.useCallback(async (email, password) => {
8456
+ const signIn = React41.useCallback(async (email, password) => {
8327
8457
  if (!adapter2) throw new Error("No auth adapter configured");
8328
8458
  store.setLoading(true);
8329
8459
  try {
@@ -8334,7 +8464,7 @@ function useAuth3() {
8334
8464
  store.setLoading(false);
8335
8465
  }
8336
8466
  }, [adapter2, store]);
8337
- const signUp = React40.useCallback(async (email, password, fullName) => {
8467
+ const signUp = React41.useCallback(async (email, password, fullName) => {
8338
8468
  if (!adapter2) throw new Error("No auth adapter configured");
8339
8469
  store.setLoading(true);
8340
8470
  try {
@@ -8352,7 +8482,7 @@ function useAuth3() {
8352
8482
  store.setLoading(false);
8353
8483
  }
8354
8484
  }, [adapter2, store]);
8355
- const signOut = React40.useCallback(async () => {
8485
+ const signOut = React41.useCallback(async () => {
8356
8486
  if (!adapter2) throw new Error("No auth adapter configured");
8357
8487
  store.setLoading(true);
8358
8488
  try {
@@ -8363,11 +8493,11 @@ function useAuth3() {
8363
8493
  store.setLoading(false);
8364
8494
  }
8365
8495
  }, [adapter2, store]);
8366
- const signInWithOAuth = React40.useCallback(async (provider) => {
8496
+ const signInWithOAuth = React41.useCallback(async (provider) => {
8367
8497
  if (!adapter2) throw new Error("No auth adapter configured");
8368
8498
  await adapter2.signInWithOAuth(provider);
8369
8499
  }, [adapter2]);
8370
- const resetPassword = React40.useCallback(async (email) => {
8500
+ const resetPassword = React41.useCallback(async (email) => {
8371
8501
  if (!adapter2) throw new Error("No auth adapter configured");
8372
8502
  await adapter2.resetPassword(email);
8373
8503
  }, [adapter2]);
@@ -8432,9 +8562,9 @@ function LoginForm({
8432
8562
  }) {
8433
8563
  const { signIn, signInWithOAuth, loading } = useAuth3();
8434
8564
  const { t } = useTranslation();
8435
- const [email, setEmail] = React40.useState("");
8436
- const [password, setPassword] = React40.useState("");
8437
- const [error, setError] = React40.useState(null);
8565
+ const [email, setEmail] = React41.useState("");
8566
+ const [password, setPassword] = React41.useState("");
8567
+ const [error, setError] = React41.useState(null);
8438
8568
  const handleSubmit = async (e) => {
8439
8569
  e.preventDefault();
8440
8570
  setError(null);
@@ -8535,12 +8665,12 @@ function SignupForm({
8535
8665
  }) {
8536
8666
  const { signUp, loading } = useAuth3();
8537
8667
  const { t } = useTranslation();
8538
- const [fullName, setFullName] = React40.useState("");
8539
- const [email, setEmail] = React40.useState("");
8540
- const [password, setPassword] = React40.useState("");
8541
- const [confirmPassword, setConfirmPassword] = React40.useState("");
8542
- const [error, setError] = React40.useState(null);
8543
- const [success, setSuccess] = React40.useState(null);
8668
+ const [fullName, setFullName] = React41.useState("");
8669
+ const [email, setEmail] = React41.useState("");
8670
+ const [password, setPassword] = React41.useState("");
8671
+ const [confirmPassword, setConfirmPassword] = React41.useState("");
8672
+ const [error, setError] = React41.useState(null);
8673
+ const [success, setSuccess] = React41.useState(null);
8544
8674
  const handleSubmit = async (e) => {
8545
8675
  e.preventDefault();
8546
8676
  setError(null);
@@ -8669,9 +8799,9 @@ function RecoveryForm({
8669
8799
  }) {
8670
8800
  const { resetPassword, loading } = useAuth3();
8671
8801
  const { t } = useTranslation();
8672
- const [email, setEmail] = React40.useState("");
8673
- const [error, setError] = React40.useState(null);
8674
- const [submitted, setSubmitted] = React40.useState(false);
8802
+ const [email, setEmail] = React41.useState("");
8803
+ const [error, setError] = React41.useState(null);
8804
+ const [submitted, setSubmitted] = React41.useState(false);
8675
8805
  const handleSubmit = async (e) => {
8676
8806
  e.preventDefault();
8677
8807
  setError(null);
@@ -8747,7 +8877,7 @@ function RecoveryForm({
8747
8877
  );
8748
8878
  }
8749
8879
  function SplitLogin({ appName, logo, tagline, description, showOAuth, oauthProviders, onSuccess }) {
8750
- const [view, setView] = React40.useState("login");
8880
+ const [view, setView] = React41.useState("login");
8751
8881
  const { t } = useTranslation();
8752
8882
  const heading = view === "login" ? t("auth.login.title") : view === "signup" ? t("auth.signup.title") : t("auth.recovery.title");
8753
8883
  const subtitle = view === "login" ? t("auth.login.enterCredentials") : view === "signup" ? t("auth.signup.getStarted") : t("auth.recovery.resetSubtitle");
@@ -8802,7 +8932,7 @@ function SplitLogin({ appName, logo, tagline, description, showOAuth, oauthProvi
8802
8932
  ] });
8803
8933
  }
8804
8934
  function CenteredLogin({ appName, logo, tagline, showOAuth, oauthProviders, onSuccess }) {
8805
- const [view, setView] = React40.useState("login");
8935
+ const [view, setView] = React41.useState("login");
8806
8936
  const { t } = useTranslation();
8807
8937
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-screen items-center justify-center bg-sidebar p-4", children: [
8808
8938
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pointer-events-none absolute inset-0 overflow-hidden", children: [
@@ -8853,7 +8983,7 @@ function LoadingSkeleton() {
8853
8983
  function ProtectedRoute({ children, requiredRole, fallback, onUnauthenticated }) {
8854
8984
  const { user, loading, initialized } = useAuth3();
8855
8985
  const { requireRole } = usePermission2();
8856
- React40__namespace.default.useEffect(() => {
8986
+ React41__namespace.default.useEffect(() => {
8857
8987
  if (initialized && !loading && !user && onUnauthenticated) {
8858
8988
  onUnauthenticated();
8859
8989
  }
@@ -9680,9 +9810,9 @@ function OrgSwitcher({ collapsed }) {
9680
9810
  const setCurrentProfile = chunk4XTQ4V5L_cjs.usePermissionsStore((s) => s.setCurrentProfile);
9681
9811
  const setProfiles = chunk4XTQ4V5L_cjs.usePermissionsStore((s) => s.setProfiles);
9682
9812
  const user = useAuthStore((s) => s.user);
9683
- const [createOpen, setCreateOpen] = React40__namespace.useState(false);
9684
- const [newOrgName, setNewOrgName] = React40__namespace.useState("");
9685
- const [creating, setCreating] = React40__namespace.useState(false);
9813
+ const [createOpen, setCreateOpen] = React41__namespace.useState(false);
9814
+ const [newOrgName, setNewOrgName] = React41__namespace.useState("");
9815
+ const [creating, setCreating] = React41__namespace.useState(false);
9686
9816
  const { t } = useTranslation();
9687
9817
  if (!adapter2 || !currentOrg) return null;
9688
9818
  const initial = currentOrg.name.charAt(0).toUpperCase();
@@ -9868,11 +9998,11 @@ function TenantOnboarding({ verticalId, appName, logo }) {
9868
9998
  const setMembers = chunkQGMDVLLW_cjs.useOrganizationStore((s) => s.setMembers);
9869
9999
  const setProfiles = chunk4XTQ4V5L_cjs.usePermissionsStore((s) => s.setProfiles);
9870
10000
  const setCurrentProfile = chunk4XTQ4V5L_cjs.usePermissionsStore((s) => s.setCurrentProfile);
9871
- const [step, setStep] = React40__namespace.useState(0);
9872
- const [error, setError] = React40__namespace.useState("");
9873
- const [companyName, setCompanyName] = React40__namespace.useState("");
9874
- const [timezone, setTimezone] = React40__namespace.useState("America/Sao_Paulo");
9875
- const [currency, setCurrency] = React40__namespace.useState("BRL");
10001
+ const [step, setStep] = React41__namespace.useState(0);
10002
+ const [error, setError] = React41__namespace.useState("");
10003
+ const [companyName, setCompanyName] = React41__namespace.useState("");
10004
+ const [timezone, setTimezone] = React41__namespace.useState("America/Sao_Paulo");
10005
+ const [currency, setCurrency] = React41__namespace.useState("BRL");
9876
10006
  const handleCreate = async () => {
9877
10007
  if (!user || !companyName.trim()) return;
9878
10008
  setStep(2);
@@ -9980,10 +10110,10 @@ function OrgInitializer({ verticalId }) {
9980
10110
  const setLoading = chunkQGMDVLLW_cjs.useOrganizationStore((s) => s.setLoading);
9981
10111
  const setProfiles = chunk4XTQ4V5L_cjs.usePermissionsStore((s) => s.setProfiles);
9982
10112
  const setCurrentProfile = chunk4XTQ4V5L_cjs.usePermissionsStore((s) => s.setCurrentProfile);
9983
- const [needsOnboarding, setNeedsOnboarding] = React40.useState(false);
9984
- const [initialized, setInitialized] = React40.useState(false);
9985
- const [connectionError, setConnectionError] = React40.useState(false);
9986
- React40.useEffect(() => {
10113
+ const [needsOnboarding, setNeedsOnboarding] = React41.useState(false);
10114
+ const [initialized, setInitialized] = React41.useState(false);
10115
+ const [connectionError, setConnectionError] = React41.useState(false);
10116
+ React41.useEffect(() => {
9987
10117
  if (!adapter2 || !user) return;
9988
10118
  let cancelled = false;
9989
10119
  async function init() {
@@ -10036,7 +10166,7 @@ function OrgInitializer({ verticalId }) {
10036
10166
  cancelled = true;
10037
10167
  };
10038
10168
  }, [adapter2, user?.id]);
10039
- React40.useEffect(() => {
10169
+ React41.useEffect(() => {
10040
10170
  if (currentOrg && needsOnboarding) setNeedsOnboarding(false);
10041
10171
  }, [currentOrg]);
10042
10172
  const { t } = useTranslation();
@@ -10257,7 +10387,7 @@ function useTenantPlugins(options) {
10257
10387
  const setLoading = usePluginStore((state) => state.setLoading);
10258
10388
  const setError = usePluginStore((state) => state.setError);
10259
10389
  const reset = usePluginStore((state) => state.reset);
10260
- React40.useEffect(() => {
10390
+ React41.useEffect(() => {
10261
10391
  if (!enabled) {
10262
10392
  reset();
10263
10393
  return;
@@ -12206,8 +12336,8 @@ function createGlobalEntitySearch() {
12206
12336
  }
12207
12337
  function CommandPaletteWrapper({ navigation, routerAdapter }) {
12208
12338
  const { commandPaletteOpen, setCommandPaletteOpen } = ui.useLayoutStore();
12209
- const entitySearch = React40__namespace.default.useMemo(() => createGlobalEntitySearch(), []);
12210
- const commands = React40__namespace.default.useMemo(() => {
12339
+ const entitySearch = React41__namespace.default.useMemo(() => createGlobalEntitySearch(), []);
12340
+ const commands = React41__namespace.default.useMemo(() => {
12211
12341
  const items = [];
12212
12342
  for (const nav of navigation) {
12213
12343
  items.push({
@@ -12235,13 +12365,13 @@ function CommandPaletteWrapper({ navigation, routerAdapter }) {
12235
12365
  );
12236
12366
  return items;
12237
12367
  }, [navigation, routerAdapter]);
12238
- const handleEntitySelect = React40__namespace.default.useCallback((result) => {
12368
+ const handleEntitySelect = React41__namespace.default.useCallback((result) => {
12239
12369
  const archetype = result.data?.archetype ? String(result.data.archetype) : void 0;
12240
12370
  const kind = result.data?.kind ? String(result.data.kind) : void 0;
12241
12371
  const href = resolveEntityHref2(result.id, archetype, kind);
12242
12372
  routerAdapter.navigate(href);
12243
12373
  }, [routerAdapter]);
12244
- return React40__namespace.default.createElement(CommandPalette, {
12374
+ return React41__namespace.default.createElement(CommandPalette, {
12245
12375
  commands,
12246
12376
  open: commandPaletteOpen,
12247
12377
  onOpenChange: setCommandPaletteOpen,
@@ -12252,13 +12382,13 @@ function CommandPaletteWrapper({ navigation, routerAdapter }) {
12252
12382
  function renderLogo(name, logo) {
12253
12383
  if (logo && typeof logo !== "string") return logo;
12254
12384
  const initial = typeof logo === "string" ? logo : name.charAt(0).toUpperCase();
12255
- return React40__namespace.default.createElement(
12385
+ return React41__namespace.default.createElement(
12256
12386
  "div",
12257
12387
  { className: "flex items-center gap-3" },
12258
- React40__namespace.default.createElement("div", {
12388
+ React41__namespace.default.createElement("div", {
12259
12389
  className: "w-8 h-8 rounded-lg bg-primary flex items-center justify-center text-primary-foreground font-bold text-sm"
12260
12390
  }, initial),
12261
- React40__namespace.default.createElement("span", { className: "font-bold text-lg" }, name)
12391
+ React41__namespace.default.createElement("span", { className: "font-bold text-lg" }, name)
12262
12392
  );
12263
12393
  }
12264
12394
  function resolveAuthAdapter2(config) {
@@ -12287,10 +12417,10 @@ function buildSettingsTabs2(config, pluginTabs, can, t) {
12287
12417
  const settingsTabs = [];
12288
12418
  if (config.organization) {
12289
12419
  settingsTabs.push(
12290
- { id: "team", label: t("settings.team"), icon: React40__namespace.default.createElement(LucideIcons4.Users, { className: "h-4 w-4" }), component: React40__namespace.default.createElement(TeamTab) },
12291
- { id: "permissions", label: t("settings.permissions"), icon: React40__namespace.default.createElement(LucideIcons4.ShieldCheck, { className: "h-4 w-4" }), component: React40__namespace.default.createElement(PermissionProfilesTab) },
12292
- { id: "locations", label: t("settings.locations"), icon: React40__namespace.default.createElement(LucideIcons4.MapPin, { className: "h-4 w-4" }), component: React40__namespace.default.createElement(LocationsCrudPage) },
12293
- { id: "field-rules", label: t("settings.fieldRules"), icon: React40__namespace.default.createElement(LucideIcons4.SlidersHorizontal, { className: "h-4 w-4" }), component: React40__namespace.default.createElement(ConnectedFieldRulesSettings) }
12420
+ { id: "team", label: t("settings.team"), icon: React41__namespace.default.createElement(LucideIcons4.Users, { className: "h-4 w-4" }), component: React41__namespace.default.createElement(TeamTab) },
12421
+ { id: "permissions", label: t("settings.permissions"), icon: React41__namespace.default.createElement(LucideIcons4.ShieldCheck, { className: "h-4 w-4" }), component: React41__namespace.default.createElement(PermissionProfilesTab) },
12422
+ { id: "locations", label: t("settings.locations"), icon: React41__namespace.default.createElement(LucideIcons4.MapPin, { className: "h-4 w-4" }), component: React41__namespace.default.createElement(LocationsCrudPage) },
12423
+ { id: "field-rules", label: t("settings.fieldRules"), icon: React41__namespace.default.createElement(LucideIcons4.SlidersHorizontal, { className: "h-4 w-4" }), component: React41__namespace.default.createElement(ConnectedFieldRulesSettings) }
12294
12424
  );
12295
12425
  }
12296
12426
  if (config.settingsTabs) {
@@ -12306,8 +12436,8 @@ function buildSettingsTabs2(config, pluginTabs, can, t) {
12306
12436
  settingsTabs.push({
12307
12437
  id: tab.id,
12308
12438
  label: pluginLabel === pluginLabelKey ? tab.label : pluginLabel,
12309
- icon: React40__namespace.default.createElement(IconComp, { className: "h-4 w-4" }),
12310
- component: React40__namespace.default.createElement(tab.component),
12439
+ icon: React41__namespace.default.createElement(IconComp, { className: "h-4 w-4" }),
12440
+ component: React41__namespace.default.createElement(tab.component),
12311
12441
  isPlugin: true
12312
12442
  });
12313
12443
  }
@@ -12326,7 +12456,7 @@ function createSaasApp(config) {
12326
12456
  const orgAdapter = resolveOrgAdapter2(config);
12327
12457
  const requireAuth = config.auth?.requireAuth ?? !!authAdapter;
12328
12458
  const LoginPageWrapper = () => {
12329
- return React40__namespace.default.createElement(LoginPage2, {
12459
+ return React41__namespace.default.createElement(LoginPage2, {
12330
12460
  appName: config.name,
12331
12461
  logo: config.auth?.loginLogo ?? logoNode,
12332
12462
  layout: config.auth?.loginLayout ?? "split",
@@ -12349,7 +12479,7 @@ function createSaasApp(config) {
12349
12479
  const { tenantPlugins: hydratedTenantPlugins } = useTenantPlugins({ enabled: shouldHydrateTenantPlugins });
12350
12480
  const { t } = useTranslation();
12351
12481
  const user = authUser ? { fullName: authUser.fullName, email: authUser.email, avatarUrl: authUser.avatarUrl } : config.user;
12352
- React40__namespace.default.useEffect(() => {
12482
+ React41__namespace.default.useEffect(() => {
12353
12483
  const pf = config.plugins?.flatMap((p) => p.declaredFeatures ?? []) ?? [];
12354
12484
  if (pf.length === 0) return;
12355
12485
  const store = chunk4XTQ4V5L_cjs.usePermissionsStore.getState();
@@ -12357,8 +12487,12 @@ function createSaasApp(config) {
12357
12487
  const toAdd = pf.filter((f) => !existing.has(f.id));
12358
12488
  if (toAdd.length > 0) store.setFeatures([...store.features, ...toAdd]);
12359
12489
  }, []);
12490
+ const navLabelRef = React41__namespace.default.useRef(() => "");
12491
+ React41__namespace.default.useEffect(() => {
12492
+ core.recordNavigation(route, navLabelRef.current(route));
12493
+ }, [route]);
12360
12494
  if (route === "/login") {
12361
- return React40__namespace.default.createElement(LoginPageWrapper);
12495
+ return React41__namespace.default.createElement(LoginPageWrapper);
12362
12496
  }
12363
12497
  const tenantPluginBindings = config.pluginRuntime?.resolveTenantPlugins?.({
12364
12498
  tenant: currentOrg ? {
@@ -12413,6 +12547,14 @@ function createSaasApp(config) {
12413
12547
  fullBleed: pluginRoute.fullBleed
12414
12548
  });
12415
12549
  }
12550
+ navLabelRef.current = (path) => {
12551
+ const exact = navigation.find((n) => n.route === path)?.label;
12552
+ if (exact) return exact;
12553
+ for (const n of navigation) {
12554
+ if (n.route !== "/" && path.startsWith(n.route + "/")) return n.label;
12555
+ }
12556
+ return "";
12557
+ };
12416
12558
  let matchedPath = route;
12417
12559
  let routeEntry = routes.get(route);
12418
12560
  if (!routeEntry) {
@@ -12431,13 +12573,13 @@ function createSaasApp(config) {
12431
12573
  matchedPath
12432
12574
  }
12433
12575
  };
12434
- const NotFoundPage = () => React40__namespace.default.createElement(
12576
+ const NotFoundPage = () => React41__namespace.default.createElement(
12435
12577
  "div",
12436
12578
  { className: "flex flex-col items-center justify-center py-24 text-center" },
12437
- React40__namespace.default.createElement("h1", { className: "text-6xl font-bold text-muted-foreground/20 mb-4" }, t("app.notFound.title")),
12438
- React40__namespace.default.createElement("h2", { className: "text-xl font-semibold mb-2" }, t("app.notFound.heading")),
12439
- React40__namespace.default.createElement("p", { className: "text-sm text-muted-foreground mb-6" }, t("app.notFound.message")),
12440
- React40__namespace.default.createElement("button", {
12579
+ React41__namespace.default.createElement("h1", { className: "text-6xl font-bold text-muted-foreground/20 mb-4" }, t("app.notFound.title")),
12580
+ React41__namespace.default.createElement("h2", { className: "text-xl font-semibold mb-2" }, t("app.notFound.heading")),
12581
+ React41__namespace.default.createElement("p", { className: "text-sm text-muted-foreground mb-6" }, t("app.notFound.message")),
12582
+ React41__namespace.default.createElement("button", {
12441
12583
  className: "rounded-lg bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors",
12442
12584
  onClick: () => routerAdapter.navigate("/")
12443
12585
  }, t("app.notFound.goToDashboard"))
@@ -12457,67 +12599,67 @@ function createSaasApp(config) {
12457
12599
  routerAdapter.navigate("/login");
12458
12600
  }
12459
12601
  };
12460
- const renderedPage = matchedPath === "/settings" && config.showSettings !== false ? React40__namespace.default.createElement(SettingsPage, {
12602
+ const renderedPage = matchedPath === "/settings" && config.showSettings !== false ? React41__namespace.default.createElement(SettingsPage, {
12461
12603
  extraTabs: settingsTabs,
12462
- beforeContent: React40__namespace.default.createElement(WidgetSlot, {
12604
+ beforeContent: React41__namespace.default.createElement(WidgetSlot, {
12463
12605
  zone: "settings.before",
12464
12606
  className: "space-y-4",
12465
12607
  contextOverrides: { matchedPath }
12466
12608
  }),
12467
- afterContent: React40__namespace.default.createElement(WidgetSlot, {
12609
+ afterContent: React41__namespace.default.createElement(WidgetSlot, {
12468
12610
  zone: "settings.after",
12469
12611
  className: "space-y-4",
12470
12612
  contextOverrides: { matchedPath }
12471
12613
  })
12472
- }) : React40__namespace.default.createElement(PageComponent, routeEntry?.plugin ? {
12614
+ }) : React41__namespace.default.createElement(PageComponent, routeEntry?.plugin ? {
12473
12615
  plugin: routeEntry.plugin,
12474
12616
  runtime: pluginRuntime.context,
12475
12617
  config: routeEntry.plugin.config
12476
12618
  } : void 0);
12477
12619
  const fullBleed = Boolean(routeEntry?.fullBleed);
12478
- const pageContent = fullBleed ? React40__namespace.default.createElement("div", { key: matchedPath, className: "h-full min-h-0 overflow-hidden" }, renderedPage) : React40__namespace.default.createElement(
12620
+ const pageContent = fullBleed ? React41__namespace.default.createElement("div", { key: matchedPath, className: "h-full min-h-0 overflow-hidden" }, renderedPage) : React41__namespace.default.createElement(
12479
12621
  "div",
12480
12622
  { key: matchedPath, className: "saas-page-enter space-y-6 p-6" },
12481
- React40__namespace.default.createElement(WidgetSlot, {
12623
+ React41__namespace.default.createElement(WidgetSlot, {
12482
12624
  zone: "page.before",
12483
12625
  className: "space-y-4",
12484
12626
  contextOverrides: { matchedPath }
12485
12627
  }),
12486
12628
  renderedPage,
12487
- React40__namespace.default.createElement(WidgetSlot, {
12629
+ React41__namespace.default.createElement(WidgetSlot, {
12488
12630
  zone: "page.after",
12489
12631
  className: "space-y-4",
12490
12632
  contextOverrides: { matchedPath }
12491
12633
  })
12492
12634
  );
12493
- const pageElement = pagePermission ? React40__namespace.default.createElement(
12635
+ const pageElement = pagePermission ? React41__namespace.default.createElement(
12494
12636
  PermissionGate,
12495
12637
  {
12496
12638
  feature: pagePermission.feature,
12497
12639
  action: pagePermission.action,
12498
- fallback: React40__namespace.default.createElement(
12640
+ fallback: React41__namespace.default.createElement(
12499
12641
  "div",
12500
12642
  { className: "flex items-center justify-center py-24" },
12501
- React40__namespace.default.createElement(
12643
+ React41__namespace.default.createElement(
12502
12644
  "div",
12503
12645
  { className: "text-center" },
12504
- React40__namespace.default.createElement("h2", { className: "text-xl font-semibold mb-2" }, t("app.accessDenied.heading")),
12505
- React40__namespace.default.createElement("p", { className: "text-muted-foreground" }, t("app.accessDenied.message"))
12646
+ React41__namespace.default.createElement("h2", { className: "text-xl font-semibold mb-2" }, t("app.accessDenied.heading")),
12647
+ React41__namespace.default.createElement("p", { className: "text-muted-foreground" }, t("app.accessDenied.message"))
12506
12648
  )
12507
12649
  ),
12508
12650
  children: pageContent
12509
12651
  }
12510
12652
  ) : pageContent;
12511
- const orgSwitcherElement = orgAdapter ? React40__namespace.default.createElement(OrgSwitcher) : void 0;
12512
- const content = React40__namespace.default.createElement(
12653
+ const orgSwitcherElement = orgAdapter ? React41__namespace.default.createElement(OrgSwitcher) : void 0;
12654
+ const content = React41__namespace.default.createElement(
12513
12655
  core.PluginRuntimeProvider,
12514
12656
  { value: pluginRuntime },
12515
- React40__namespace.default.createElement(
12516
- React40__namespace.default.Fragment,
12657
+ React41__namespace.default.createElement(
12658
+ React41__namespace.default.Fragment,
12517
12659
  null,
12518
- React40__namespace.default.createElement(MockModeBanner),
12519
- React40__namespace.default.createElement(ImpersonationBanner),
12520
- React40__namespace.default.createElement(
12660
+ React41__namespace.default.createElement(MockModeBanner),
12661
+ React41__namespace.default.createElement(ImpersonationBanner),
12662
+ React41__namespace.default.createElement(
12521
12663
  ui.AppShell,
12522
12664
  {
12523
12665
  variant: layout,
@@ -12538,22 +12680,22 @@ function createSaasApp(config) {
12538
12680
  } : void 0,
12539
12681
  logo: logoNode,
12540
12682
  orgSwitcher: orgSwitcherElement,
12541
- topbarStart: React40__namespace.default.createElement(WidgetSlot, {
12683
+ topbarStart: React41__namespace.default.createElement(WidgetSlot, {
12542
12684
  zone: "shell.topbar.start",
12543
12685
  className: "flex items-center gap-2",
12544
12686
  contextOverrides: { matchedPath }
12545
12687
  }),
12546
- topbarEnd: React40__namespace.default.createElement(WidgetSlot, {
12688
+ topbarEnd: React41__namespace.default.createElement(WidgetSlot, {
12547
12689
  zone: "shell.topbar.end",
12548
12690
  className: "flex items-center gap-2",
12549
12691
  contextOverrides: { matchedPath }
12550
12692
  }),
12551
- sidebarTopContent: React40__namespace.default.createElement(WidgetSlot, {
12693
+ sidebarTopContent: React41__namespace.default.createElement(WidgetSlot, {
12552
12694
  zone: "shell.sidebar.before-nav",
12553
12695
  className: "space-y-2",
12554
12696
  contextOverrides: { matchedPath }
12555
12697
  }),
12556
- sidebarFooterContent: React40__namespace.default.createElement(WidgetSlot, {
12698
+ sidebarFooterContent: React41__namespace.default.createElement(WidgetSlot, {
12557
12699
  zone: "shell.sidebar.footer",
12558
12700
  className: "space-y-2",
12559
12701
  contextOverrides: { matchedPath }
@@ -12563,26 +12705,26 @@ function createSaasApp(config) {
12563
12705
  pageElement
12564
12706
  ),
12565
12707
  // Org initializer
12566
- orgAdapter ? React40__namespace.default.createElement(OrgInitializer, { verticalId: config.verticalId }) : null,
12708
+ orgAdapter ? React41__namespace.default.createElement(OrgInitializer, { verticalId: config.verticalId }) : null,
12567
12709
  // Location switch overlay
12568
- React40__namespace.default.createElement(LocationSwitchOverlay),
12710
+ React41__namespace.default.createElement(LocationSwitchOverlay),
12569
12711
  // Chat
12570
- config.chat?.enabled !== false && config.chat ? React40__namespace.default.createElement(
12571
- React40__namespace.default.Fragment,
12712
+ config.chat?.enabled !== false && config.chat ? React41__namespace.default.createElement(
12713
+ React41__namespace.default.Fragment,
12572
12714
  null,
12573
- React40__namespace.default.createElement(ChatFab, { apiEndpoint: config.chat.apiEndpoint, systemPrompt: config.chat.systemPrompt }),
12574
- React40__namespace.default.createElement(ChatPanel, { title: config.chat.title, apiEndpoint: config.chat.apiEndpoint, systemPrompt: config.chat.systemPrompt })
12715
+ React41__namespace.default.createElement(ChatFab, { apiEndpoint: config.chat.apiEndpoint, systemPrompt: config.chat.systemPrompt }),
12716
+ React41__namespace.default.createElement(ChatPanel, { title: config.chat.title, apiEndpoint: config.chat.apiEndpoint, systemPrompt: config.chat.systemPrompt })
12575
12717
  ) : null,
12576
- React40__namespace.default.createElement(WidgetSlot, {
12718
+ React41__namespace.default.createElement(WidgetSlot, {
12577
12719
  zone: "shell.floating",
12578
12720
  contextOverrides: { matchedPath }
12579
12721
  }),
12580
12722
  // Command palette
12581
- React40__namespace.default.createElement(CommandPaletteWrapper, { navigation, routerAdapter })
12723
+ React41__namespace.default.createElement(CommandPaletteWrapper, { navigation, routerAdapter })
12582
12724
  )
12583
12725
  );
12584
12726
  if (requireAuth && authAdapter) {
12585
- return React40__namespace.default.createElement(
12727
+ return React41__namespace.default.createElement(
12586
12728
  ProtectedRoute,
12587
12729
  { onUnauthenticated: () => {
12588
12730
  routerAdapter.navigate("/login");
@@ -12598,7 +12740,7 @@ function createSaasApp(config) {
12598
12740
  const setPlans = chunkKYID2MR6_cjs.useBillingStore((s) => s.setPlans);
12599
12741
  const setFeatures = chunk4XTQ4V5L_cjs.usePermissionsStore((s) => s.setFeatures);
12600
12742
  const setMode = useThemeStore((s) => s.setMode);
12601
- React40__namespace.default.useEffect(() => {
12743
+ React41__namespace.default.useEffect(() => {
12602
12744
  if (config.theme) {
12603
12745
  const isSaasTheme = "brand" in config.theme && ("radius" in config.theme || "sidebar" in config.theme || "font" in config.theme);
12604
12746
  const resolved = isSaasTheme ? resolveTheme(config.theme) : config.theme;
@@ -12609,34 +12751,34 @@ function createSaasApp(config) {
12609
12751
  }
12610
12752
  initialize();
12611
12753
  }, [initialize, setOverrides, setMode]);
12612
- React40__namespace.default.useEffect(() => {
12754
+ React41__namespace.default.useEffect(() => {
12613
12755
  if (config.billing?.plans) {
12614
12756
  setPlans(config.billing.plans.map(normalizePlanConfig));
12615
12757
  }
12616
12758
  }, [setPlans]);
12617
- React40__namespace.default.useEffect(() => {
12759
+ React41__namespace.default.useEffect(() => {
12618
12760
  if (config.permissions?.features) {
12619
12761
  setFeatures(config.permissions.features);
12620
12762
  }
12621
12763
  }, [setFeatures]);
12622
- React40__namespace.default.useEffect(() => {
12764
+ React41__namespace.default.useEffect(() => {
12623
12765
  core.setCurrentLocale(config.locale?.default ?? "en");
12624
12766
  core.setDefaultCurrency(config.locale?.currency);
12625
12767
  }, []);
12626
- let inner = React40__namespace.default.createElement(
12768
+ let inner = React41__namespace.default.createElement(
12627
12769
  RouterProvider,
12628
12770
  { value: routerAdapter },
12629
- React40__namespace.default.createElement(ui.ToastProvider, null),
12630
- React40__namespace.default.createElement(AppContent)
12771
+ React41__namespace.default.createElement(ui.ToastProvider, null),
12772
+ React41__namespace.default.createElement(AppContent)
12631
12773
  );
12632
12774
  if (orgAdapter) {
12633
- inner = React40__namespace.default.createElement(
12775
+ inner = React41__namespace.default.createElement(
12634
12776
  OrgAdapterProvider,
12635
12777
  { value: orgAdapter, children: inner }
12636
12778
  );
12637
12779
  }
12638
12780
  if (authAdapter) {
12639
- inner = React40__namespace.default.createElement(
12781
+ inner = React41__namespace.default.createElement(
12640
12782
  AuthAdapterProvider,
12641
12783
  { value: authAdapter, children: inner }
12642
12784
  );
@@ -12656,7 +12798,7 @@ function createSaasApp(config) {
12656
12798
  mergedTranslations[loc] = layer;
12657
12799
  }
12658
12800
  core.registerTranslations(mergedTranslations);
12659
- inner = React40__namespace.default.createElement(core.I18nProvider, {
12801
+ inner = React41__namespace.default.createElement(core.I18nProvider, {
12660
12802
  value: {
12661
12803
  defaultLocale: config.locale?.default ?? "en",
12662
12804
  supported: supportedLocales,
@@ -12755,11 +12897,11 @@ function manifestToFayzConfig(manifest, surfaceName) {
12755
12897
  function AdminScaffold({ manifest, surface }) {
12756
12898
  const liveConfigRef = manifest.surfaces[surface]?.options?.[liveConfigOption];
12757
12899
  const liveConfig = typeof liveConfigRef === "string" ? liveSaasConfigs.get(liveConfigRef) : void 0;
12758
- const LegacyApp = React40__namespace.useMemo(() => {
12900
+ const LegacyApp = React41__namespace.useMemo(() => {
12759
12901
  if (!liveConfig || !hasLegacyShellConfig(liveConfig)) return null;
12760
12902
  return createSaasApp(liveConfig);
12761
12903
  }, [liveConfig]);
12762
- const config = React40__namespace.useMemo(() => manifestToFayzConfig(manifest, surface), [manifest, surface]);
12904
+ const config = React41__namespace.useMemo(() => manifestToFayzConfig(manifest, surface), [manifest, surface]);
12763
12905
  if (LegacyApp) return /* @__PURE__ */ jsxRuntime.jsx(LegacyApp, {});
12764
12906
  return /* @__PURE__ */ jsxRuntime.jsx(AdminProviders, { config, children: /* @__PURE__ */ jsxRuntime.jsx(
12765
12907
  AdminShell,
@@ -12795,7 +12937,7 @@ var STAGE_CONFIG = {
12795
12937
  completed: { icon: LucideIcons4.CircleCheckBig, color: "bg-success-soft text-success-soft-foreground", labelKey: "crud.orders.stage.completed" }
12796
12938
  };
12797
12939
  function useColumns(currency, t, onBookingClick, onInvoiceClick) {
12798
- return React40.useMemo(() => [
12940
+ return React41.useMemo(() => [
12799
12941
  {
12800
12942
  accessorKey: "date",
12801
12943
  header: t("crud.orders.columnDate"),
@@ -12900,12 +13042,12 @@ function ClientOrdersTab({
12900
13042
  currency = { code: "BRL", locale: "pt-BR" }
12901
13043
  }) {
12902
13044
  const { t } = useTranslation();
12903
- const [docs, setDocs] = React40.useState([]);
12904
- const [total, setTotal] = React40.useState(0);
12905
- const [loading, setLoading] = React40.useState(true);
12906
- const [stageFilter, setStageFilter] = React40.useState();
13045
+ const [docs, setDocs] = React41.useState([]);
13046
+ const [total, setTotal] = React41.useState(0);
13047
+ const [loading, setLoading] = React41.useState(true);
13048
+ const [stageFilter, setStageFilter] = React41.useState();
12907
13049
  const clientId = item.id;
12908
- const fetchDocs = React40.useCallback(async () => {
13050
+ const fetchDocs = React41.useCallback(async () => {
12909
13051
  setLoading(true);
12910
13052
  try {
12911
13053
  const result = await provider.getDocuments({
@@ -12921,11 +13063,11 @@ function ClientOrdersTab({
12921
13063
  setLoading(false);
12922
13064
  }
12923
13065
  }, [clientId, stageFilter, provider]);
12924
- React40.useEffect(() => {
13066
+ React41.useEffect(() => {
12925
13067
  fetchDocs();
12926
13068
  }, [fetchDocs]);
12927
13069
  const columns = useColumns(currency, t, onBookingClick, onInvoiceClick);
12928
- const tags = React40.useMemo(() => [
13070
+ const tags = React41.useMemo(() => [
12929
13071
  { value: "booked", label: t("crud.orders.stage.booked") },
12930
13072
  { value: "invoiced", label: t("crud.orders.stage.invoiced") },
12931
13073
  { value: "paid", label: t("crud.orders.stage.paid") },
@@ -13094,19 +13236,19 @@ function createArchetypeLookup(config) {
13094
13236
  }
13095
13237
  function createPlaceholder(title, description) {
13096
13238
  return function PlaceholderPage() {
13097
- return React40__namespace.default.createElement(
13239
+ return React41__namespace.default.createElement(
13098
13240
  "div",
13099
13241
  { className: "mx-auto max-w-4xl" },
13100
- React40__namespace.default.createElement("h1", { className: "text-3xl font-bold text-foreground" }, title),
13101
- description ? React40__namespace.default.createElement("p", { className: "mt-1 text-muted-foreground" }, description) : null,
13102
- React40__namespace.default.createElement(
13242
+ React41__namespace.default.createElement("h1", { className: "text-3xl font-bold text-foreground" }, title),
13243
+ description ? React41__namespace.default.createElement("p", { className: "mt-1 text-muted-foreground" }, description) : null,
13244
+ React41__namespace.default.createElement(
13103
13245
  "div",
13104
13246
  { className: "mt-8 flex items-center justify-center rounded-card border border-dashed border-border bg-card p-16" },
13105
- React40__namespace.default.createElement(
13247
+ React41__namespace.default.createElement(
13106
13248
  "div",
13107
13249
  { className: "text-center" },
13108
- React40__namespace.default.createElement("p", { className: "text-lg font-medium text-muted-foreground" }, "Coming Soon"),
13109
- React40__namespace.default.createElement(
13250
+ React41__namespace.default.createElement("p", { className: "text-lg font-medium text-muted-foreground" }, "Coming Soon"),
13251
+ React41__namespace.default.createElement(
13110
13252
  "p",
13111
13253
  { className: "mt-1 text-sm text-muted-foreground/70" },
13112
13254
  "This module is being built as a plugin."
@@ -13177,10 +13319,10 @@ function SettingsGroup({ title, description, children }) {
13177
13319
  ] });
13178
13320
  }
13179
13321
  function QuickActionsButton({ actions, className }) {
13180
- const [open, setOpen] = React40.useState(false);
13181
- const ref = React40.useRef(null);
13322
+ const [open, setOpen] = React41.useState(false);
13323
+ const ref = React41.useRef(null);
13182
13324
  const variant = ui.useModuleLayout() === "tabs" ? "default" : "outline";
13183
- React40.useEffect(() => {
13325
+ React41.useEffect(() => {
13184
13326
  function handler(e) {
13185
13327
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
13186
13328
  }
@@ -13253,9 +13395,9 @@ function ModuleActionBar({
13253
13395
  ] });
13254
13396
  }
13255
13397
  function createPluginContext(displayName) {
13256
- const ConfigContext = React40__namespace.default.createContext(null);
13257
- const ProviderContext = React40__namespace.default.createContext(null);
13258
- const StoreContext = React40__namespace.default.createContext(null);
13398
+ const ConfigContext = React41__namespace.default.createContext(null);
13399
+ const ProviderContext = React41__namespace.default.createContext(null);
13400
+ const StoreContext = React41__namespace.default.createContext(null);
13259
13401
  const ContextProvider = ({
13260
13402
  config,
13261
13403
  provider,
@@ -13264,17 +13406,17 @@ function createPluginContext(displayName) {
13264
13406
  }) => /* @__PURE__ */ jsxRuntime.jsx(ConfigContext.Provider, { value: config, children: /* @__PURE__ */ jsxRuntime.jsx(ProviderContext.Provider, { value: provider, children: /* @__PURE__ */ jsxRuntime.jsx(StoreContext.Provider, { value: store, children }) }) });
13265
13407
  ContextProvider.displayName = `${displayName}ContextProvider`;
13266
13408
  function useConfig() {
13267
- const ctx = React40__namespace.default.useContext(ConfigContext);
13409
+ const ctx = React41__namespace.default.useContext(ConfigContext);
13268
13410
  if (!ctx) throw new Error(`useConfig must be used within ${displayName}`);
13269
13411
  return ctx;
13270
13412
  }
13271
13413
  function useProvider() {
13272
- const ctx = React40__namespace.default.useContext(ProviderContext);
13414
+ const ctx = React41__namespace.default.useContext(ProviderContext);
13273
13415
  if (!ctx) throw new Error(`useProvider must be used within ${displayName}`);
13274
13416
  return ctx;
13275
13417
  }
13276
13418
  function useStore(selector) {
13277
- const store = React40__namespace.default.useContext(StoreContext);
13419
+ const store = React41__namespace.default.useContext(StoreContext);
13278
13420
  if (!store) throw new Error(`useStore must be used within ${displayName}`);
13279
13421
  return zustand.useStore(store, selector);
13280
13422
  }
@@ -13304,7 +13446,7 @@ function formatCurrency4(value, currency) {
13304
13446
  }).format(value);
13305
13447
  }
13306
13448
  function RegistryCrudView({ registry: registry2, basePath }) {
13307
- const useStore = React40.useMemo(() => {
13449
+ const useStore = React41.useMemo(() => {
13308
13450
  const data = registry2.mockData ?? registry2.seedData ?? [];
13309
13451
  const provider = core.createMockProvider(registry2.entity, data);
13310
13452
  return createCrudStore(provider);
@@ -13331,8 +13473,8 @@ function PluginRegistryManager({ registries, routeBase, className }) {
13331
13473
  }
13332
13474
  return registries[0]?.id ?? "";
13333
13475
  };
13334
- const [activeTab, setActiveTab] = React40.useState(getTabFromHash);
13335
- React40__namespace.default.useEffect(() => {
13476
+ const [activeTab, setActiveTab] = React41.useState(getTabFromHash);
13477
+ React41__namespace.default.useEffect(() => {
13336
13478
  if (!routeBase) return;
13337
13479
  const handler = () => setActiveTab(getTabFromHash());
13338
13480
  window.addEventListener("hashchange", handler);
@@ -13401,10 +13543,20 @@ function useModuleNavigation(hashBase, depthMap, homeView = "summary") {
13401
13543
  }
13402
13544
  return homeView;
13403
13545
  }
13404
- const [view, setView] = React40.useState(getInitialView);
13405
- const [direction, setDirection] = React40.useState("forward");
13406
- const prevDepthRef = React40.useRef(getDepth(getInitialView()));
13407
- React40.useEffect(() => {
13546
+ const [view, setView] = React41.useState(getInitialView);
13547
+ const [direction, setDirection] = React41.useState("forward");
13548
+ const prevDepthRef = React41.useRef(getDepth(getInitialView()));
13549
+ const historyRef = React41.useRef([getInitialView()]);
13550
+ const [previousView, setPreviousView] = React41.useState(null);
13551
+ React41.useEffect(() => {
13552
+ const stack = historyRef.current;
13553
+ if (stack[stack.length - 1] !== view) {
13554
+ stack.push(view);
13555
+ if (stack.length > 30) stack.shift();
13556
+ }
13557
+ setPreviousView(stack.length >= 2 ? stack[stack.length - 2] : null);
13558
+ }, [view]);
13559
+ React41.useEffect(() => {
13408
13560
  function handler() {
13409
13561
  const hash = (window.location.hash.slice(1) || "/").split("?")[0];
13410
13562
  if (hash === hashBase || hash === hashBase + "/" || hash.startsWith(hashBase + "/")) {
@@ -13428,7 +13580,7 @@ function useModuleNavigation(hashBase, depthMap, homeView = "summary") {
13428
13580
  if (v.includes("edit")) return depths.edit ?? 2;
13429
13581
  return 0;
13430
13582
  }
13431
- const navigate = React40.useCallback((nextView, hash) => {
13583
+ const navigate = React41.useCallback((nextView, hash) => {
13432
13584
  const nextDepth = getDepth(nextView);
13433
13585
  setDirection(nextDepth > prevDepthRef.current ? "forward" : "back");
13434
13586
  prevDepthRef.current = nextDepth;
@@ -13449,8 +13601,15 @@ function useModuleNavigation(hashBase, depthMap, homeView = "summary") {
13449
13601
  }
13450
13602
  }
13451
13603
  }, [hashBase]);
13604
+ const back = React41.useCallback((fallbackView) => {
13605
+ if (historyRef.current.length >= 2) {
13606
+ window.history.back();
13607
+ } else {
13608
+ navigate(fallbackView ?? homeView);
13609
+ }
13610
+ }, [navigate, homeView]);
13452
13611
  const animationClass = direction === "forward" ? "saas-nav-forward" : "saas-nav-back";
13453
- return { view, direction, animationClass, navigate };
13612
+ return { view, direction, animationClass, navigate, previousView, back };
13454
13613
  }
13455
13614
  var personLookup = createArchetypeLookup({ archetype: "person" });
13456
13615
  function formatAge(dob) {
@@ -13465,12 +13624,12 @@ function formatAge(dob) {
13465
13624
  }
13466
13625
  }
13467
13626
  function PersonLink2({ personId, name, profileHref, tab, size = "default", className }) {
13468
- const [person, setPerson] = React40.useState(null);
13469
- const [loading, setLoading] = React40.useState(false);
13470
- const [fetched, setFetched] = React40.useState(false);
13471
- const [open, setOpen] = React40.useState(false);
13472
- const hoverTimer = React40.useRef(null);
13473
- const fetchPerson = React40.useCallback(() => {
13627
+ const [person, setPerson] = React41.useState(null);
13628
+ const [loading, setLoading] = React41.useState(false);
13629
+ const [fetched, setFetched] = React41.useState(false);
13630
+ const [open, setOpen] = React41.useState(false);
13631
+ const hoverTimer = React41.useRef(null);
13632
+ const fetchPerson = React41.useCallback(() => {
13474
13633
  if (!fetched && personId) {
13475
13634
  setLoading(true);
13476
13635
  personLookup.getById(personId).then((result) => {
@@ -13483,7 +13642,7 @@ function PersonLink2({ personId, name, profileHref, tab, size = "default", class
13483
13642
  });
13484
13643
  }
13485
13644
  }, [personId, fetched]);
13486
- const handleOpenChange = React40.useCallback((v) => {
13645
+ const handleOpenChange = React41.useCallback((v) => {
13487
13646
  setOpen(v);
13488
13647
  if (v) fetchPerson();
13489
13648
  }, [fetchPerson]);
@@ -13612,33 +13771,174 @@ function writeStore(pluginId, data) {
13612
13771
  }
13613
13772
  }
13614
13773
  function usePluginPrefs(pluginId, defaults) {
13615
- const [state, setState] = React40.useState(() => readStore(pluginId, defaults));
13616
- const get = React40.useCallback((key) => {
13774
+ const [state, setState] = React41.useState(() => readStore(pluginId, defaults));
13775
+ const get = React41.useCallback((key) => {
13617
13776
  return state[key];
13618
13777
  }, [state]);
13619
- const set = React40.useCallback((key, value) => {
13778
+ const set = React41.useCallback((key, value) => {
13620
13779
  setState((prev) => {
13621
13780
  const next = { ...prev, [key]: value };
13622
13781
  writeStore(pluginId, next);
13623
13782
  return next;
13624
13783
  });
13625
13784
  }, [pluginId]);
13626
- const update = React40.useCallback((partial) => {
13785
+ const update = React41.useCallback((partial) => {
13627
13786
  setState((prev) => {
13628
13787
  const next = { ...prev, ...partial };
13629
13788
  writeStore(pluginId, next);
13630
13789
  return next;
13631
13790
  });
13632
13791
  }, [pluginId]);
13633
- const getAll = React40.useCallback(() => state, [state]);
13634
- const reset = React40.useCallback(() => {
13792
+ const getAll = React41.useCallback(() => state, [state]);
13793
+ const reset = React41.useCallback(() => {
13635
13794
  setState({ ...defaults });
13636
13795
  writeStore(pluginId, defaults);
13637
13796
  }, [pluginId, defaults]);
13638
- return React40.useMemo(() => ({ get, set, update, getAll, reset }), [get, set, update, getAll, reset]);
13797
+ return React41.useMemo(() => ({ get, set, update, getAll, reset }), [get, set, update, getAll, reset]);
13798
+ }
13799
+ function ConnectorCard({ connector }) {
13800
+ const { t } = useTranslation();
13801
+ const [status, setStatus] = React41.useState(null);
13802
+ const [open, setOpen] = React41.useState(false);
13803
+ const [values, setValues] = React41.useState({});
13804
+ const [testing, setTesting] = React41.useState(false);
13805
+ const [saving, setSaving] = React41.useState(false);
13806
+ const [oauthing, setOauthing] = React41.useState(false);
13807
+ const loadStatus = React41.useCallback(async () => {
13808
+ try {
13809
+ setStatus(await connector.getStatus());
13810
+ } catch {
13811
+ setStatus({ connected: false });
13812
+ }
13813
+ }, [connector]);
13814
+ React41.useEffect(() => {
13815
+ void loadStatus();
13816
+ }, [loadStatus]);
13817
+ const connected = !!status?.connected;
13818
+ const Icon = connector.icon ? ui.ICON_MAP[connector.icon] ?? LucideIcons4.Plug : LucideIcons4.Plug;
13819
+ async function handleTest() {
13820
+ if (!connector.testConnection) return;
13821
+ setTesting(true);
13822
+ try {
13823
+ const res = await connector.testConnection(values);
13824
+ res.ok ? ui.toast.success(res.message ?? t("connectors.connected")) : ui.toast.error(res.message ?? t("common.error"));
13825
+ } catch (e) {
13826
+ ui.toast.error(e?.message ?? t("common.error"));
13827
+ } finally {
13828
+ setTesting(false);
13829
+ }
13830
+ }
13831
+ async function handleSave() {
13832
+ if (!connector.saveConnection) return;
13833
+ setSaving(true);
13834
+ try {
13835
+ await connector.saveConnection(values);
13836
+ ui.toast.success(t("connectors.save"));
13837
+ await loadStatus();
13838
+ } catch (e) {
13839
+ ui.toast.error(e?.message ?? t("common.error"));
13840
+ } finally {
13841
+ setSaving(false);
13842
+ }
13843
+ }
13844
+ async function handleConnectOAuth() {
13845
+ if (!connector.startOAuth) return;
13846
+ setOauthing(true);
13847
+ try {
13848
+ window.location.href = await connector.startOAuth(window.location.href);
13849
+ } catch (e) {
13850
+ ui.toast.error(e?.message ?? t("common.error"));
13851
+ setOauthing(false);
13852
+ }
13853
+ }
13854
+ async function handleDisconnect() {
13855
+ if (!connector.disconnect) return;
13856
+ try {
13857
+ await connector.disconnect();
13858
+ ui.toast.success(t("connectors.disconnect"));
13859
+ await loadStatus();
13860
+ } catch (e) {
13861
+ ui.toast.error(e?.message ?? t("common.error"));
13862
+ }
13863
+ }
13864
+ const ExtraPanel = connector.ExtraPanel;
13865
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border bg-card shadow-sm overflow-hidden", children: [
13866
+ /* @__PURE__ */ jsxRuntime.jsxs(
13867
+ "button",
13868
+ {
13869
+ onClick: () => setOpen((o) => !o),
13870
+ className: "w-full flex items-center gap-3 px-4 py-3 text-left hover:bg-muted/30 transition-colors",
13871
+ children: [
13872
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-9 w-9 items-center justify-center rounded-lg bg-muted shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-4 w-4 text-muted-foreground" }) }),
13873
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
13874
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold truncate", children: connector.name }),
13875
+ connector.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-muted-foreground truncate", children: connector.description })
13876
+ ] }),
13877
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: `inline-flex items-center gap-1 text-[11px] shrink-0 ${connected ? "text-success" : "text-muted-foreground"}`, children: connected ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
13878
+ /* @__PURE__ */ jsxRuntime.jsx(LucideIcons4.CheckCircle2, { className: "h-3.5 w-3.5" }),
13879
+ " ",
13880
+ t("connectors.connected")
13881
+ ] }) : t("connectors.notConnected") }),
13882
+ /* @__PURE__ */ jsxRuntime.jsx(LucideIcons4.ChevronDown, { className: `h-4 w-4 text-muted-foreground shrink-0 transition-transform ${open ? "rotate-180" : ""}` })
13883
+ ]
13884
+ }
13885
+ ),
13886
+ open && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t px-4 py-4 space-y-4", children: [
13887
+ connector.authKind === "oauth" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
13888
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { onClick: handleConnectOAuth, disabled: oauthing, children: [
13889
+ oauthing ? /* @__PURE__ */ jsxRuntime.jsx(LucideIcons4.Loader2, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(LucideIcons4.Plug, { className: "h-4 w-4" }),
13890
+ connected ? t("connectors.connected") : `${t("connectors.connect")} ${connector.name}`
13891
+ ] }),
13892
+ connected && connector.disconnect && /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { variant: "outline", size: "sm", onClick: handleDisconnect, children: [
13893
+ /* @__PURE__ */ jsxRuntime.jsx(LucideIcons4.Power, { className: "h-3.5 w-3.5" }),
13894
+ " ",
13895
+ t("connectors.disconnect")
13896
+ ] })
13897
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
13898
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-3 sm:grid-cols-2", children: (connector.fields ?? []).map((f) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block", children: [
13899
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-muted-foreground", children: f.label }),
13900
+ /* @__PURE__ */ jsxRuntime.jsx(
13901
+ "input",
13902
+ {
13903
+ type: f.type,
13904
+ value: values[f.key] ?? "",
13905
+ onChange: (e) => setValues((v) => ({ ...v, [f.key]: e.target.value })),
13906
+ placeholder: f.placeholder,
13907
+ className: "w-full mt-1 rounded-input border border-input bg-card px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
13908
+ }
13909
+ )
13910
+ ] }, f.key)) }),
13911
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
13912
+ connector.testConnection && /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { variant: "outline", size: "sm", onClick: handleTest, disabled: testing, children: [
13913
+ testing ? /* @__PURE__ */ jsxRuntime.jsx(LucideIcons4.Loader2, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(LucideIcons4.Plug, { className: "h-3.5 w-3.5" }),
13914
+ " ",
13915
+ t("connectors.test")
13916
+ ] }),
13917
+ connector.saveConnection && /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "sm", onClick: handleSave, disabled: saving, children: [
13918
+ saving ? /* @__PURE__ */ jsxRuntime.jsx(LucideIcons4.Loader2, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(LucideIcons4.CheckCircle2, { className: "h-3.5 w-3.5" }),
13919
+ " ",
13920
+ t("connectors.save")
13921
+ ] }),
13922
+ connected && connector.disconnect && /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { variant: "outline", size: "sm", onClick: handleDisconnect, children: [
13923
+ /* @__PURE__ */ jsxRuntime.jsx(LucideIcons4.Power, { className: "h-3.5 w-3.5" }),
13924
+ " ",
13925
+ t("connectors.disconnect")
13926
+ ] })
13927
+ ] })
13928
+ ] }),
13929
+ ExtraPanel && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-1", children: /* @__PURE__ */ jsxRuntime.jsx(ExtraPanel, {}) })
13930
+ ] })
13931
+ ] });
13932
+ }
13933
+ function ConnectorsHub({ connectors }) {
13934
+ const { t } = useTranslation();
13935
+ if (!connectors || connectors.length === 0) {
13936
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground py-8 text-center", children: t("connectors.empty") });
13937
+ }
13938
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3 max-w-3xl", children: connectors.map((c) => /* @__PURE__ */ jsxRuntime.jsx(ConnectorCard, { connector: c }, c.id)) });
13639
13939
  }
13640
13940
  function RegistryCrudView2({ registry: registry2, basePath }) {
13641
- const useStore = React40.useMemo(() => {
13941
+ const useStore = React41.useMemo(() => {
13642
13942
  const mockData = registry2.mockData ?? registry2.seedData ?? [];
13643
13943
  const provider = core.resolveDataProvider(registry2.entity, mockData);
13644
13944
  return createCrudStore(provider);
@@ -13654,30 +13954,82 @@ function RegistryCrudView2({ registry: registry2, basePath }) {
13654
13954
  }
13655
13955
  );
13656
13956
  }
13657
- function PluginSettingsPanel({ title, subtitle, generalSettings, registries, customTabs, routeBase, onClose }) {
13957
+ function PropertiesTab({ registries, routeBase, regLabel }) {
13958
+ function getActive() {
13959
+ const hash = window.location.hash.slice(1);
13960
+ const nested = `${routeBase}/_properties/`;
13961
+ if (hash.startsWith(nested)) {
13962
+ const id = hash.slice(nested.length).split("/")[0];
13963
+ if (registries.find((r) => r.id === id)) return id;
13964
+ }
13965
+ const flat = `${routeBase}/`;
13966
+ if (hash.startsWith(flat)) {
13967
+ const id = hash.slice(flat.length).split("/")[0];
13968
+ if (registries.find((r) => r.id === id)) return id;
13969
+ }
13970
+ return registries[0]?.id ?? "";
13971
+ }
13972
+ const [active, setActive] = React41.useState(getActive);
13973
+ React41__namespace.default.useEffect(() => {
13974
+ const handler = () => setActive(getActive());
13975
+ window.addEventListener("hashchange", handler);
13976
+ return () => window.removeEventListener("hashchange", handler);
13977
+ }, [routeBase, registries]);
13978
+ function select(id) {
13979
+ setActive(id);
13980
+ window.location.hash = `${routeBase}/_properties/${id}`;
13981
+ }
13982
+ const activeReg = registries.find((r) => r.id === active) ?? registries[0];
13983
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
13984
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-1.5 flex-wrap", children: registries.map((r) => {
13985
+ const Icon = r.icon ? ui.ICON_MAP[r.icon] ?? null : null;
13986
+ const on = r.id === activeReg?.id;
13987
+ return /* @__PURE__ */ jsxRuntime.jsxs(
13988
+ "button",
13989
+ {
13990
+ onClick: () => select(r.id),
13991
+ className: ui.cn(
13992
+ "inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-xs font-medium transition-colors",
13993
+ on ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground hover:bg-muted/70"
13994
+ ),
13995
+ children: [
13996
+ Icon && /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-3.5 w-3.5" }),
13997
+ regLabel(r.id, r.entity.name)
13998
+ ]
13999
+ },
14000
+ r.id
14001
+ );
14002
+ }) }),
14003
+ activeReg?.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: regLabel(activeReg.id + ".description", activeReg.description) }),
14004
+ activeReg && /* @__PURE__ */ jsxRuntime.jsx(RegistryCrudView2, { registry: activeReg, basePath: `${routeBase}/_properties/${activeReg.id}` }, activeReg.id)
14005
+ ] });
14006
+ }
14007
+ function PluginSettingsPanel({ title, subtitle, generalSettings, registries, customTabs, routeBase, hostPluginId, onClose }) {
13658
14008
  const { t } = useTranslation();
14009
+ const connectors = core.useConnectorsForPlugin(hostPluginId ?? "");
13659
14010
  const regLabel = (id, fallback) => {
13660
14011
  const key = `registry.${id}`;
13661
14012
  const translated = t(key);
13662
14013
  return translated === key ? fallback : translated;
13663
14014
  };
13664
- const tabs = React40.useMemo(() => {
14015
+ const tabs = React41.useMemo(() => {
13665
14016
  const list = [];
13666
14017
  if (generalSettings) {
13667
- list.push({ id: "_general", label: t("settings.general"), icon: "Settings", type: "general" });
14018
+ list.push({ id: "_general", label: t("settings.general"), IconComp: LucideIcons4.Settings, type: "general" });
13668
14019
  }
13669
14020
  if (customTabs) {
13670
14021
  for (const tab of customTabs) {
13671
14022
  list.push({ id: `_custom_${tab.id}`, label: tab.label, icon: tab.icon, type: "custom" });
13672
14023
  }
13673
14024
  }
13674
- if (registries) {
13675
- for (const reg of registries) {
13676
- list.push({ id: reg.id, label: regLabel(reg.id, reg.entity.name), icon: reg.icon, type: "registry", registryDef: reg });
13677
- }
14025
+ if (connectors.length > 0) {
14026
+ list.push({ id: "_integrations", label: t("connectors.title"), IconComp: LucideIcons4.Plug, type: "integrations" });
14027
+ }
14028
+ if (registries && registries.length > 0) {
14029
+ list.push({ id: "_properties", label: t("settings.properties"), IconComp: LucideIcons4.TableProperties, type: "properties" });
13678
14030
  }
13679
14031
  return list;
13680
- }, [generalSettings, customTabs, registries, t]);
14032
+ }, [generalSettings, customTabs, connectors.length, registries, t]);
13681
14033
  const useHashRouting = true;
13682
14034
  function getActiveFromHash() {
13683
14035
  const hash = window.location.hash.slice(1) || "/";
@@ -13685,11 +14037,12 @@ function PluginSettingsPanel({ title, subtitle, generalSettings, registries, cus
13685
14037
  const rest = hash.slice(routeBase.length + 1).split("/")[0];
13686
14038
  const match = tabs.find((t2) => t2.id === rest);
13687
14039
  if (match) return match.id;
14040
+ if (registries?.some((r) => r.id === rest) && tabs.some((t2) => t2.id === "_properties")) return "_properties";
13688
14041
  }
13689
14042
  return tabs[0]?.id ?? "";
13690
14043
  }
13691
- const [activeTab, setActiveTab] = React40.useState(getActiveFromHash);
13692
- React40__namespace.default.useEffect(() => {
14044
+ const [activeTab, setActiveTab] = React41.useState(getActiveFromHash);
14045
+ React41__namespace.default.useEffect(() => {
13693
14046
  const handler = () => setActiveTab(getActiveFromHash());
13694
14047
  window.addEventListener("hashchange", handler);
13695
14048
  return () => window.removeEventListener("hashchange", handler);
@@ -13711,7 +14064,7 @@ function PluginSettingsPanel({ title, subtitle, generalSettings, registries, cus
13711
14064
  ] })
13712
14065
  ] }),
13713
14066
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-0.5 overflow-x-auto border-b scrollbar-none", style: { scrollbarWidth: "none" }, children: tabs.map((tab) => {
13714
- const Icon = tab.icon ? ui.ICON_MAP[tab.icon] ?? null : null;
14067
+ const Icon = tab.IconComp ?? (tab.icon ? ui.ICON_MAP[tab.icon] ?? null : null);
13715
14068
  const active = tab.id === activeTab;
13716
14069
  return /* @__PURE__ */ jsxRuntime.jsxs(
13717
14070
  "button",
@@ -13729,17 +14082,10 @@ function PluginSettingsPanel({ title, subtitle, generalSettings, registries, cus
13729
14082
  tab.id
13730
14083
  );
13731
14084
  }) }),
13732
- activeTabDef?.type === "registry" && activeTabDef.registryDef?.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: regLabel(activeTabDef.id + ".description", activeTabDef.registryDef.description) }),
13733
14085
  activeTabDef?.type === "general" && generalSettings && /* @__PURE__ */ jsxRuntime.jsx("div", { children: generalSettings }),
13734
14086
  activeTabDef?.type === "custom" && customTabContent && /* @__PURE__ */ jsxRuntime.jsx("div", { children: customTabContent.content }),
13735
- activeTabDef?.type === "registry" && activeTabDef.registryDef && /* @__PURE__ */ jsxRuntime.jsx(
13736
- RegistryCrudView2,
13737
- {
13738
- registry: activeTabDef.registryDef,
13739
- basePath: `${routeBase}/${activeTabDef.id}`
13740
- },
13741
- activeTabDef.id
13742
- )
14087
+ activeTabDef?.type === "integrations" && /* @__PURE__ */ jsxRuntime.jsx(ConnectorsHub, { connectors }),
14088
+ activeTabDef?.type === "properties" && registries && registries.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(PropertiesTab, { registries, routeBase, regLabel })
13743
14089
  ] });
13744
14090
  }
13745
14091
 
@@ -13835,6 +14181,7 @@ exports.AdminProviders = AdminProviders;
13835
14181
  exports.AdminScaffold = AdminScaffold;
13836
14182
  exports.AdminShell = AdminShell;
13837
14183
  exports.ClientOrdersTab = ClientOrdersTab;
14184
+ exports.ConnectorsHub = ConnectorsHub;
13838
14185
  exports.CrudCardGrid = CrudCardGrid;
13839
14186
  exports.CrudDetailPage = CrudDetailPage;
13840
14187
  exports.CrudFormPage = CrudFormPage;