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