@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.
- package/LICENSE +21 -0
- package/dist/crud/CrudDetailPage.d.ts.map +1 -1
- package/dist/crud/CrudFormPage.d.ts.map +1 -1
- package/dist/crud/archetypes/PersonDetailTabs.d.ts +12 -0
- package/dist/crud/archetypes/PersonDetailTabs.d.ts.map +1 -1
- package/dist/crud/fieldToColumn.d.ts.map +1 -1
- package/dist/crud/index.d.ts +1 -0
- package/dist/crud/index.d.ts.map +1 -1
- package/dist/crud/relation-field.d.ts +28 -0
- package/dist/crud/relation-field.d.ts.map +1 -0
- package/dist/db.cjs +14 -0
- package/dist/db.cjs.map +1 -0
- package/dist/db.d.ts +2 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +3 -0
- package/dist/db.js.map +1 -0
- package/dist/hooks/useModuleNavigation.d.ts +2 -0
- package/dist/hooks/useModuleNavigation.d.ts.map +1 -1
- package/dist/index.cjs +747 -379
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +552 -204
- package/dist/index.js.map +1 -1
- package/dist/shell/components/plugins/ConnectorsHub.d.ts +6 -0
- package/dist/shell/components/plugins/ConnectorsHub.d.ts.map +1 -0
- package/dist/shell/components/plugins/PluginSettingsPanel.d.ts +4 -2
- package/dist/shell/components/plugins/PluginSettingsPanel.d.ts.map +1 -1
- package/dist/shell/createSaasApp.d.ts.map +1 -1
- package/dist/shell/hooks/useModuleNavigation.d.ts +2 -0
- package/dist/shell/hooks/useModuleNavigation.d.ts.map +1 -1
- package/dist/shell/types/crud.d.ts +12 -1
- package/dist/shell/types/crud.d.ts.map +1 -1
- package/dist/ui.cjs +14 -0
- package/dist/ui.cjs.map +1 -0
- package/dist/ui.d.ts +2 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +3 -0
- package/dist/ui.js.map +1 -0
- package/package.json +18 -4
- package/src/crud/CrudDetailPage.tsx +5 -0
- package/src/crud/CrudFormPage.tsx +12 -0
- package/src/crud/archetypes/PersonDetailTabs.tsx +22 -0
- package/src/crud/fieldToColumn.tsx +3 -0
- package/src/crud/index.ts +1 -0
- package/src/crud/relation-field.tsx +115 -0
- package/src/db.ts +12 -0
- package/src/hooks/useModuleNavigation.ts +27 -1
- package/src/index.ts +17 -0
- package/src/shell/components/plugins/ConnectorsHub.tsx +163 -0
- package/src/shell/components/plugins/PluginSettingsPanel.tsx +106 -27
- package/src/shell/createSaasApp.tsx +22 -1
- package/src/shell/hooks/useModuleNavigation.ts +27 -1
- package/src/shell/types/crud.ts +13 -0
- 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
|
|
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
|
|
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
|
|
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 =
|
|
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] =
|
|
286
|
-
const indexRef =
|
|
287
|
-
|
|
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] =
|
|
333
|
-
const [activeSuggestion, setActiveSuggestion] =
|
|
334
|
-
const timersRef =
|
|
335
|
-
const prevSuggestionRef =
|
|
336
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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] =
|
|
520
|
-
const [showTools, setShowTools] =
|
|
521
|
-
const scrollRef =
|
|
522
|
-
const inputRef =
|
|
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
|
-
|
|
526
|
+
React41__namespace.useEffect(() => {
|
|
526
527
|
scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight, behavior: "smooth" });
|
|
527
528
|
}, [messages]);
|
|
528
|
-
|
|
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] =
|
|
1086
|
-
|
|
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] =
|
|
1142
|
-
const [email, setEmail] =
|
|
1143
|
-
const [password, setPassword] =
|
|
1144
|
-
const [fullName, setFullName] =
|
|
1145
|
-
const [notice, setNotice] =
|
|
1146
|
-
const [submitting, setSubmitting] =
|
|
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] =
|
|
1388
|
-
const [timezone, setTimezone] =
|
|
1389
|
-
const [currency, setCurrency] =
|
|
1390
|
-
const [saving, setSaving] =
|
|
1391
|
-
|
|
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 =
|
|
1476
|
+
var OrgAdapterContext = React41.createContext(null);
|
|
1476
1477
|
var OrgAdapterProvider = OrgAdapterContext.Provider;
|
|
1477
1478
|
function useOrgAdapter2() {
|
|
1478
|
-
const adapter2 =
|
|
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
|
|
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] =
|
|
1542
|
-
const [saving, setSaving] =
|
|
1543
|
-
const fileInputRef =
|
|
1544
|
-
|
|
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] =
|
|
1754
|
-
const [resetSent, setResetSent] =
|
|
1755
|
-
const [savingTenant, setSavingTenant] =
|
|
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 =
|
|
1857
|
+
var AuthAdapterContext = React41.createContext(null);
|
|
1857
1858
|
var AuthAdapterProvider = AuthAdapterContext.Provider;
|
|
1858
1859
|
function useAuthAdapterOptional() {
|
|
1859
|
-
return
|
|
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 =
|
|
1916
|
-
const [preview, setPreview] =
|
|
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] =
|
|
1984
|
-
const [accentColor, setAccentColor] =
|
|
1985
|
-
const [logoFile, setLogoFile] =
|
|
1986
|
-
const [faviconFile, setFaviconFile] =
|
|
1987
|
-
const [logoUrl, setLogoUrl] =
|
|
1988
|
-
const [faviconUrl, setFaviconUrl] =
|
|
1989
|
-
const [saving, setSaving] =
|
|
1990
|
-
|
|
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 =
|
|
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] =
|
|
2210
|
+
const [activeTab, setActiveTab] = React41__namespace.useState(() => {
|
|
2210
2211
|
return getTabFromHash() ?? defaultTab ?? null;
|
|
2211
2212
|
});
|
|
2212
|
-
|
|
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(
|
|
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] =
|
|
2293
|
-
const [profileId, setProfileId] =
|
|
2294
|
-
const [sending, setSending] =
|
|
2295
|
-
const [sent, setSent] =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
2435
|
+
const permissions = React41.useMemo(() => {
|
|
2435
2436
|
if (!currentRole) return [];
|
|
2436
2437
|
return ROLE_PERMISSIONS[currentRole];
|
|
2437
2438
|
}, [currentRole]);
|
|
2438
|
-
const hasPermission =
|
|
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 =
|
|
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 =
|
|
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] =
|
|
2494
|
-
|
|
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] =
|
|
2642
|
-
const [description, setDescription] =
|
|
2643
|
-
const [systemPerms, setSystemPerms] =
|
|
2644
|
-
const [grants, setGrants] =
|
|
2645
|
-
const [collapsed, setCollapsed] =
|
|
2646
|
-
const [search, setSearch] =
|
|
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 =
|
|
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(
|
|
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] =
|
|
2777
|
-
const [creating, setCreating] =
|
|
2778
|
-
const [saving, setSaving] =
|
|
2779
|
-
const memberCountByProfile =
|
|
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] =
|
|
3243
|
-
const [query, setQuery] =
|
|
3244
|
-
const [results, setResults] =
|
|
3245
|
-
const [searching, setSearching] =
|
|
3246
|
-
const [selected, setSelected] =
|
|
3247
|
-
const [showCreate, setShowCreate] =
|
|
3248
|
-
const [creating, setCreating] =
|
|
3249
|
-
const searchTimer =
|
|
3250
|
-
const inputRef =
|
|
3251
|
-
const containerRef =
|
|
3252
|
-
const [newPhone, setNewPhone] =
|
|
3253
|
-
const [newEmail, setNewEmail] =
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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:
|
|
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] =
|
|
3774
|
-
const [saving, setSaving] =
|
|
3775
|
-
const initialRef =
|
|
3776
|
-
|
|
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 =
|
|
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 =
|
|
4372
|
-
const [pos, setPos] =
|
|
4373
|
-
|
|
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
|
-
|
|
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] =
|
|
4514
|
-
const ref =
|
|
4515
|
-
|
|
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] =
|
|
4575
|
-
const ref =
|
|
4576
|
-
|
|
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 =
|
|
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] =
|
|
4798
|
-
const [exceptions, setExceptions] =
|
|
4799
|
-
const [loading, setLoading] =
|
|
4800
|
-
const [saving, setSaving] =
|
|
4801
|
-
const [showAddException, setShowAddException] =
|
|
4802
|
-
const blockConfig =
|
|
4803
|
-
const [settingsPopover, setSettingsPopover] =
|
|
4804
|
-
const [weekDirty, setWeekDirty] =
|
|
4805
|
-
|
|
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] =
|
|
4812
|
-
const [newExEndDate, setNewExEndDate] =
|
|
4813
|
-
const [newExType, setNewExType] =
|
|
4814
|
-
const [newExPeriods, setNewExPeriods] =
|
|
4815
|
-
const [newExNotes, setNewExNotes] =
|
|
4816
|
-
const [savingException, setSavingException] =
|
|
4817
|
-
const loadData =
|
|
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
|
-
|
|
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] =
|
|
5523
|
-
const [loading, setLoading] =
|
|
5524
|
-
|
|
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 =
|
|
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 ?
|
|
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(
|
|
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 =
|
|
6001
|
-
const [dragOver, setDragOver] =
|
|
6002
|
-
const [error, setError] =
|
|
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 =
|
|
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] =
|
|
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] =
|
|
6253
|
-
const [csv, setCsv] =
|
|
6254
|
-
const [fileName, setFileName] =
|
|
6255
|
-
const [result, setResult] =
|
|
6256
|
-
const [progress, setProgress] =
|
|
6257
|
-
const fields =
|
|
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 =
|
|
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] =
|
|
6376
|
-
const [direction, setDirection] =
|
|
6377
|
-
const prevDepthRef =
|
|
6378
|
-
|
|
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
|
|
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 =
|
|
6589
|
+
const entityDef = React41.useMemo(() => ({
|
|
6459
6590
|
...rawEntityDef,
|
|
6460
6591
|
fields: applyRules(rawEntityDef.fields)
|
|
6461
6592
|
}), [rawEntityDef, applyRules]);
|
|
6462
|
-
const [deleteItem, setDeleteItem] =
|
|
6463
|
-
const [searchInput, setSearchInput] =
|
|
6464
|
-
const [importOpen, setImportOpen] =
|
|
6465
|
-
const [activeFilters, setActiveFilters] =
|
|
6466
|
-
const activeFiltersRef =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
6487
|
-
const handleInlineUpdate =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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] =
|
|
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] =
|
|
7069
|
-
const [saving, setSaving] =
|
|
7070
|
-
const [search, setSearch] =
|
|
7071
|
-
const [showMore, setShowMore] =
|
|
7072
|
-
|
|
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 =
|
|
7206
|
+
const isDirty = React41.useMemo(
|
|
7076
7207
|
() => JSON.stringify(draft) !== JSON.stringify(initialRules),
|
|
7077
7208
|
[draft, initialRules]
|
|
7078
7209
|
);
|
|
7079
|
-
const { coreEntities, standaloneEntities, pluginGroups } =
|
|
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 =
|
|
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 =
|
|
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:
|
|
7429
|
-
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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] =
|
|
7888
|
+
const [pathname, setPathname] = React41__namespace.useState(
|
|
7758
7889
|
typeof window !== "undefined" ? window.location.hash.slice(1) || "/" : "/"
|
|
7759
7890
|
);
|
|
7760
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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] =
|
|
8053
|
-
|
|
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] =
|
|
8132
|
-
const [loading, setLoading] =
|
|
8133
|
-
const abortRef =
|
|
8134
|
-
|
|
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] =
|
|
8299
|
+
const [search, setSearch] = React41.useState("");
|
|
8169
8300
|
const { results: entityResults, loading: entityLoading } = useEntitySearch(onEntitySearch, search, open);
|
|
8170
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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] =
|
|
8436
|
-
const [password, setPassword] =
|
|
8437
|
-
const [error, setError] =
|
|
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] =
|
|
8539
|
-
const [email, setEmail] =
|
|
8540
|
-
const [password, setPassword] =
|
|
8541
|
-
const [confirmPassword, setConfirmPassword] =
|
|
8542
|
-
const [error, setError] =
|
|
8543
|
-
const [success, setSuccess] =
|
|
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] =
|
|
8673
|
-
const [error, setError] =
|
|
8674
|
-
const [submitted, setSubmitted] =
|
|
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] =
|
|
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] =
|
|
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
|
-
|
|
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] =
|
|
9684
|
-
const [newOrgName, setNewOrgName] =
|
|
9685
|
-
const [creating, setCreating] =
|
|
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] =
|
|
9872
|
-
const [error, setError] =
|
|
9873
|
-
const [companyName, setCompanyName] =
|
|
9874
|
-
const [timezone, setTimezone] =
|
|
9875
|
-
const [currency, setCurrency] =
|
|
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] =
|
|
9984
|
-
const [initialized, setInitialized] =
|
|
9985
|
-
const [connectionError, setConnectionError] =
|
|
9986
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
12210
|
-
const commands =
|
|
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 =
|
|
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
|
|
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
|
|
12386
|
+
return React41__namespace.default.createElement(
|
|
12256
12387
|
"div",
|
|
12257
12388
|
{ className: "flex items-center gap-3" },
|
|
12258
|
-
|
|
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
|
-
|
|
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:
|
|
12291
|
-
{ id: "permissions", label: t("settings.permissions"), icon:
|
|
12292
|
-
{ id: "locations", label: t("settings.locations"), icon:
|
|
12293
|
-
{ id: "field-rules", label: t("settings.fieldRules"), icon:
|
|
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:
|
|
12310
|
-
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
|
|
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
|
-
|
|
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
|
|
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 = () =>
|
|
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
|
-
|
|
12438
|
-
|
|
12439
|
-
|
|
12440
|
-
|
|
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 ?
|
|
12603
|
+
const renderedPage = matchedPath === "/settings" && config.showSettings !== false ? React41__namespace.default.createElement(SettingsPage, {
|
|
12461
12604
|
extraTabs: settingsTabs,
|
|
12462
|
-
beforeContent:
|
|
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:
|
|
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
|
-
}) :
|
|
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 ?
|
|
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
|
-
|
|
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
|
-
|
|
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 ?
|
|
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:
|
|
12641
|
+
fallback: React41__namespace.default.createElement(
|
|
12499
12642
|
"div",
|
|
12500
12643
|
{ className: "flex items-center justify-center py-24" },
|
|
12501
|
-
|
|
12644
|
+
React41__namespace.default.createElement(
|
|
12502
12645
|
"div",
|
|
12503
12646
|
{ className: "text-center" },
|
|
12504
|
-
|
|
12505
|
-
|
|
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 ?
|
|
12512
|
-
const content =
|
|
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
|
-
|
|
12516
|
-
|
|
12658
|
+
React41__namespace.default.createElement(
|
|
12659
|
+
React41__namespace.default.Fragment,
|
|
12517
12660
|
null,
|
|
12518
|
-
|
|
12519
|
-
|
|
12520
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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 ?
|
|
12709
|
+
orgAdapter ? React41__namespace.default.createElement(OrgInitializer, { verticalId: config.verticalId }) : null,
|
|
12567
12710
|
// Location switch overlay
|
|
12568
|
-
|
|
12711
|
+
React41__namespace.default.createElement(LocationSwitchOverlay),
|
|
12569
12712
|
// Chat
|
|
12570
|
-
config.chat?.enabled !== false && config.chat ?
|
|
12571
|
-
|
|
12713
|
+
config.chat?.enabled !== false && config.chat ? React41__namespace.default.createElement(
|
|
12714
|
+
React41__namespace.default.Fragment,
|
|
12572
12715
|
null,
|
|
12573
|
-
|
|
12574
|
-
|
|
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
|
-
|
|
12719
|
+
React41__namespace.default.createElement(WidgetSlot, {
|
|
12577
12720
|
zone: "shell.floating",
|
|
12578
12721
|
contextOverrides: { matchedPath }
|
|
12579
12722
|
}),
|
|
12580
12723
|
// Command palette
|
|
12581
|
-
|
|
12724
|
+
React41__namespace.default.createElement(CommandPaletteWrapper, { navigation, routerAdapter })
|
|
12582
12725
|
)
|
|
12583
12726
|
);
|
|
12584
12727
|
if (requireAuth && authAdapter) {
|
|
12585
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
12760
|
+
React41__namespace.default.useEffect(() => {
|
|
12618
12761
|
if (config.permissions?.features) {
|
|
12619
12762
|
setFeatures(config.permissions.features);
|
|
12620
12763
|
}
|
|
12621
12764
|
}, [setFeatures]);
|
|
12622
|
-
|
|
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 =
|
|
12769
|
+
let inner = React41__namespace.default.createElement(
|
|
12627
12770
|
RouterProvider,
|
|
12628
12771
|
{ value: routerAdapter },
|
|
12629
|
-
|
|
12630
|
-
|
|
12772
|
+
React41__namespace.default.createElement(ui.ToastProvider, null),
|
|
12773
|
+
React41__namespace.default.createElement(AppContent)
|
|
12631
12774
|
);
|
|
12632
12775
|
if (orgAdapter) {
|
|
12633
|
-
inner =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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] =
|
|
12904
|
-
const [total, setTotal] =
|
|
12905
|
-
const [loading, setLoading] =
|
|
12906
|
-
const [stageFilter, setStageFilter] =
|
|
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 =
|
|
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
|
-
|
|
13067
|
+
React41.useEffect(() => {
|
|
12925
13068
|
fetchDocs();
|
|
12926
13069
|
}, [fetchDocs]);
|
|
12927
13070
|
const columns = useColumns(currency, t, onBookingClick, onInvoiceClick);
|
|
12928
|
-
const tags =
|
|
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
|
|
13240
|
+
return React41__namespace.default.createElement(
|
|
13098
13241
|
"div",
|
|
13099
13242
|
{ className: "mx-auto max-w-4xl" },
|
|
13100
|
-
|
|
13101
|
-
description ?
|
|
13102
|
-
|
|
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
|
-
|
|
13248
|
+
React41__namespace.default.createElement(
|
|
13106
13249
|
"div",
|
|
13107
13250
|
{ className: "text-center" },
|
|
13108
|
-
|
|
13109
|
-
|
|
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] =
|
|
13181
|
-
const ref =
|
|
13323
|
+
const [open, setOpen] = React41.useState(false);
|
|
13324
|
+
const ref = React41.useRef(null);
|
|
13182
13325
|
const variant = ui.useModuleLayout() === "tabs" ? "default" : "outline";
|
|
13183
|
-
|
|
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 =
|
|
13257
|
-
const ProviderContext =
|
|
13258
|
-
const StoreContext =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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] =
|
|
13335
|
-
|
|
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] =
|
|
13405
|
-
const [direction, setDirection] =
|
|
13406
|
-
const prevDepthRef =
|
|
13407
|
-
|
|
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 =
|
|
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] =
|
|
13469
|
-
const [loading, setLoading] =
|
|
13470
|
-
const [fetched, setFetched] =
|
|
13471
|
-
const [open, setOpen] =
|
|
13472
|
-
const hoverTimer =
|
|
13473
|
-
const fetchPerson =
|
|
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 =
|
|
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] =
|
|
13616
|
-
const get =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
13634
|
-
const reset =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
14016
|
+
const tabs = React41.useMemo(() => {
|
|
13665
14017
|
const list = [];
|
|
13666
14018
|
if (generalSettings) {
|
|
13667
|
-
list.push({ id: "_general", label: t("settings.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 (
|
|
13675
|
-
|
|
13676
|
-
|
|
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] =
|
|
13692
|
-
|
|
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 === "
|
|
13736
|
-
|
|
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;
|