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