@infuro/cms-core 1.0.31 → 1.0.33
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/README.md +3 -2
- package/dist/admin.cjs +929 -345
- package/dist/admin.cjs.map +1 -1
- package/dist/admin.js +947 -362
- package/dist/admin.js.map +1 -1
- package/dist/api.cjs +839 -59
- package/dist/api.cjs.map +1 -1
- package/dist/api.d.cts +1 -1
- package/dist/api.d.ts +1 -1
- package/dist/api.js +833 -53
- package/dist/api.js.map +1 -1
- package/dist/auth.cjs +159 -14
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +37 -22
- package/dist/auth.d.ts +37 -22
- package/dist/auth.js +153 -14
- package/dist/auth.js.map +1 -1
- package/dist/cli.cjs +3 -2
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +3 -2
- package/dist/cli.js.map +1 -1
- package/dist/{index-Bda8D1Rm.d.ts → index-DWd5Gjc4.d.ts} +2 -2
- package/dist/{index-BcMRGNjS.d.cts → index-rZTnpK7y.d.cts} +2 -2
- package/dist/index.cjs +1141 -254
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -30
- package/dist/index.d.ts +41 -30
- package/dist/index.js +1135 -254
- package/dist/index.js.map +1 -1
- package/dist/migrations/1778660000003-AddQrTokenToOrders.ts +32 -0
- package/dist/migrations/1779100000000-ChatConversationLeadEmailSent.ts +16 -0
- package/dist/migrations/1779200000000-LlmAgentScope.ts +72 -0
- package/package.json +2 -1
package/dist/admin.cjs
CHANGED
|
@@ -1594,7 +1594,7 @@ var defaultValue = {
|
|
|
1594
1594
|
var AdminConfigContext = (0, import_react4.createContext)(defaultValue);
|
|
1595
1595
|
|
|
1596
1596
|
// src/lib/cms-version.ts
|
|
1597
|
-
var CMS_VERSION = true ? "1.0.
|
|
1597
|
+
var CMS_VERSION = true ? "1.0.33" : "0.0.0";
|
|
1598
1598
|
|
|
1599
1599
|
// src/components/Admin/Sidebar.tsx
|
|
1600
1600
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
@@ -2078,6 +2078,34 @@ var BUILTIN_PLUGIN_DESCRIPTORS = [
|
|
|
2078
2078
|
}
|
|
2079
2079
|
];
|
|
2080
2080
|
|
|
2081
|
+
// src/auth/auth-debug.ts
|
|
2082
|
+
var LOG_PREFIX = "[cms-auth]";
|
|
2083
|
+
function isAuthDebugClientEnabled() {
|
|
2084
|
+
if (typeof window === "undefined") return false;
|
|
2085
|
+
const v = process.env.NEXT_PUBLIC_CMS_AUTH_DEBUG?.trim().toLowerCase();
|
|
2086
|
+
if (v === "1" || v === "true" || v === "yes") return true;
|
|
2087
|
+
if (v === "0" || v === "false" || v === "no") return false;
|
|
2088
|
+
return process.env.NODE_ENV === "development";
|
|
2089
|
+
}
|
|
2090
|
+
function logAuthClient(message, data) {
|
|
2091
|
+
if (!isAuthDebugClientEnabled()) return;
|
|
2092
|
+
if (data) console.info(LOG_PREFIX, message, data);
|
|
2093
|
+
else console.info(LOG_PREFIX, message);
|
|
2094
|
+
}
|
|
2095
|
+
function summarizeSessionUserForLog(user) {
|
|
2096
|
+
if (!user || typeof user !== "object") return { present: false };
|
|
2097
|
+
const u = user;
|
|
2098
|
+
return {
|
|
2099
|
+
present: true,
|
|
2100
|
+
email: u.email ?? null,
|
|
2101
|
+
id: u.id ?? null,
|
|
2102
|
+
adminAccess: u.adminAccess ?? null,
|
|
2103
|
+
isRBACAdmin: u.isRBACAdmin ?? null,
|
|
2104
|
+
isVendorPortal: u.isVendorPortal ?? null,
|
|
2105
|
+
groupName: u.groupName ?? null
|
|
2106
|
+
};
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2081
2109
|
// src/admin/pages/AdminLayout.tsx
|
|
2082
2110
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2083
2111
|
var PUBLIC_ADMIN_PATHS = [
|
|
@@ -2111,6 +2139,14 @@ function AdminLayoutInner({ children }) {
|
|
|
2111
2139
|
(0, import_react9.useEffect)(() => {
|
|
2112
2140
|
if (isMobile) setMoreSheetOpen(false);
|
|
2113
2141
|
}, [isMobile, pathname]);
|
|
2142
|
+
(0, import_react9.useEffect)(() => {
|
|
2143
|
+
logAuthClient("AdminLayout session state", {
|
|
2144
|
+
pathname,
|
|
2145
|
+
isPublicPath,
|
|
2146
|
+
status,
|
|
2147
|
+
sessionUser: summarizeSessionUserForLog(session?.user)
|
|
2148
|
+
});
|
|
2149
|
+
}, [pathname, isPublicPath, status, session?.user]);
|
|
2114
2150
|
(0, import_react9.useEffect)(() => {
|
|
2115
2151
|
if (isPublicPath) return;
|
|
2116
2152
|
if (status === "loading") {
|
|
@@ -2118,6 +2154,7 @@ function AdminLayoutInner({ children }) {
|
|
|
2118
2154
|
return () => clearTimeout(timeout);
|
|
2119
2155
|
}
|
|
2120
2156
|
if (status === "unauthenticated") {
|
|
2157
|
+
logAuthClient("AdminLayout redirect \u2192 /admin/signin (unauthenticated)", { pathname });
|
|
2121
2158
|
router.replace("/admin/signin");
|
|
2122
2159
|
} else {
|
|
2123
2160
|
setLoadingTimeout(false);
|
|
@@ -9075,7 +9112,9 @@ var SigninPage = () => {
|
|
|
9075
9112
|
const router = (0, import_navigation8.useRouter)();
|
|
9076
9113
|
const { status } = (0, import_react31.useSession)();
|
|
9077
9114
|
(0, import_react30.useEffect)(() => {
|
|
9115
|
+
logAuthClient("SignInPage session status", { status });
|
|
9078
9116
|
if (status === "authenticated") {
|
|
9117
|
+
logAuthClient("SignInPage redirect \u2192 /admin/dashboard (already authenticated)");
|
|
9079
9118
|
router.replace("/admin/dashboard");
|
|
9080
9119
|
}
|
|
9081
9120
|
}, [status, router]);
|
|
@@ -9084,14 +9123,22 @@ var SigninPage = () => {
|
|
|
9084
9123
|
setLoading(true);
|
|
9085
9124
|
setError("");
|
|
9086
9125
|
try {
|
|
9126
|
+
logAuthClient("SignInPage signIn start", { email });
|
|
9087
9127
|
const result = await (0, import_react31.signIn)("credentials", {
|
|
9088
9128
|
email,
|
|
9089
9129
|
password,
|
|
9090
9130
|
redirect: false
|
|
9091
9131
|
});
|
|
9132
|
+
logAuthClient("SignInPage signIn result", {
|
|
9133
|
+
ok: result?.ok ?? null,
|
|
9134
|
+
error: result?.error ?? null,
|
|
9135
|
+
status: result?.status ?? null,
|
|
9136
|
+
url: result?.url ?? null
|
|
9137
|
+
});
|
|
9092
9138
|
if (result?.error) {
|
|
9093
9139
|
setError("Invalid email or password");
|
|
9094
9140
|
} else {
|
|
9141
|
+
logAuthClient("SignInPage navigate \u2192 /admin/dashboard");
|
|
9095
9142
|
window.location.assign("/admin/dashboard");
|
|
9096
9143
|
}
|
|
9097
9144
|
} catch (error2) {
|
|
@@ -10210,6 +10257,7 @@ init_utils();
|
|
|
10210
10257
|
init_table();
|
|
10211
10258
|
init_DetailPageLayout();
|
|
10212
10259
|
init_DetailPageHeader();
|
|
10260
|
+
var import_react_qr_code = require("react-qr-code");
|
|
10213
10261
|
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
10214
10262
|
function formatMoney(amount, currency = "INR") {
|
|
10215
10263
|
return new Intl.NumberFormat("en-IN", {
|
|
@@ -10567,6 +10615,19 @@ function OrderDetailPage({ orderId }) {
|
|
|
10567
10615
|
},
|
|
10568
10616
|
p.id
|
|
10569
10617
|
)) })
|
|
10618
|
+
] }),
|
|
10619
|
+
order.qrToken && /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("section", { children: [
|
|
10620
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Order QR Code" }),
|
|
10621
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "min-w-0 border border-gray-200 rounded-lg p-4 bg-gray-50/50 flex flex-col items-center gap-2", children: [
|
|
10622
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
10623
|
+
import_react_qr_code.QRCode,
|
|
10624
|
+
{
|
|
10625
|
+
value: `${window.location.origin}/track/${order.qrToken}`,
|
|
10626
|
+
size: 180
|
|
10627
|
+
}
|
|
10628
|
+
),
|
|
10629
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("p", { className: "text-xs text-gray-400 break-all text-center", children: order.qrToken })
|
|
10630
|
+
] })
|
|
10570
10631
|
] })
|
|
10571
10632
|
] })
|
|
10572
10633
|
}
|
|
@@ -16115,6 +16176,155 @@ function serializeEmailRecipients(emails) {
|
|
|
16115
16176
|
init_button();
|
|
16116
16177
|
init_input();
|
|
16117
16178
|
var import_sonner12 = require("sonner");
|
|
16179
|
+
|
|
16180
|
+
// src/plugins/llm/chat-email-intent.ts
|
|
16181
|
+
function normalizeIntentKey(raw) {
|
|
16182
|
+
return raw.trim().toUpperCase().replace(/[^A-Z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
16183
|
+
}
|
|
16184
|
+
function parseIntentsJson(raw) {
|
|
16185
|
+
if (!raw?.trim()) return null;
|
|
16186
|
+
try {
|
|
16187
|
+
const parsed = JSON.parse(raw);
|
|
16188
|
+
if (!Array.isArray(parsed)) return null;
|
|
16189
|
+
const out = [];
|
|
16190
|
+
for (const row of parsed) {
|
|
16191
|
+
if (!row || typeof row !== "object") continue;
|
|
16192
|
+
const o = row;
|
|
16193
|
+
const intent = normalizeIntentKey(String(o.intent ?? o.id ?? ""));
|
|
16194
|
+
const description = String(o.description ?? "").trim();
|
|
16195
|
+
const emailTo = String(o.emailTo ?? o.email ?? "").trim();
|
|
16196
|
+
if (!intent || !description || !emailTo) continue;
|
|
16197
|
+
out.push({ intent, description, emailTo });
|
|
16198
|
+
}
|
|
16199
|
+
return out.length > 0 ? out : null;
|
|
16200
|
+
} catch {
|
|
16201
|
+
return null;
|
|
16202
|
+
}
|
|
16203
|
+
}
|
|
16204
|
+
function dedupeIntents(intents) {
|
|
16205
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16206
|
+
const out = [];
|
|
16207
|
+
for (const row of intents) {
|
|
16208
|
+
const key = normalizeIntentKey(row.intent);
|
|
16209
|
+
if (!key || seen.has(key)) continue;
|
|
16210
|
+
seen.add(key);
|
|
16211
|
+
out.push({
|
|
16212
|
+
intent: key,
|
|
16213
|
+
description: row.description.trim(),
|
|
16214
|
+
emailTo: row.emailTo.trim()
|
|
16215
|
+
});
|
|
16216
|
+
}
|
|
16217
|
+
return out;
|
|
16218
|
+
}
|
|
16219
|
+
function parseEmailIntentsFromSettings(raw) {
|
|
16220
|
+
return dedupeIntents(parseIntentsJson(raw) ?? []);
|
|
16221
|
+
}
|
|
16222
|
+
function serializeChatLeadIntents(intents) {
|
|
16223
|
+
return JSON.stringify(
|
|
16224
|
+
dedupeIntents(intents).map((r) => ({
|
|
16225
|
+
intent: r.intent,
|
|
16226
|
+
description: r.description,
|
|
16227
|
+
emailTo: r.emailTo
|
|
16228
|
+
}))
|
|
16229
|
+
);
|
|
16230
|
+
}
|
|
16231
|
+
var EMAIL_TOOL_VALIDATION_KEY = "emailTool";
|
|
16232
|
+
function parseEmailToolObject(raw) {
|
|
16233
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
16234
|
+
const o = raw;
|
|
16235
|
+
const intentsRaw = o.intents;
|
|
16236
|
+
let intents;
|
|
16237
|
+
if (Array.isArray(intentsRaw)) {
|
|
16238
|
+
const parsed = parseIntentsJson(JSON.stringify(intentsRaw));
|
|
16239
|
+
if (parsed?.length) intents = parsed;
|
|
16240
|
+
}
|
|
16241
|
+
return {
|
|
16242
|
+
enabled: o.enabled === true,
|
|
16243
|
+
classifierInstructions: typeof o.classifierInstructions === "string" ? o.classifierInstructions.trim() : void 0,
|
|
16244
|
+
toolPrompt: typeof o.toolPrompt === "string" ? o.toolPrompt.trim() : void 0,
|
|
16245
|
+
intents
|
|
16246
|
+
};
|
|
16247
|
+
}
|
|
16248
|
+
function splitValidationRulesForAdmin(validationRulesText) {
|
|
16249
|
+
const raw = validationRulesText?.trim() ?? "";
|
|
16250
|
+
if (!raw) return { guardrailsJson: "", emailTool: null };
|
|
16251
|
+
try {
|
|
16252
|
+
const parsed = JSON.parse(raw);
|
|
16253
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
16254
|
+
return { guardrailsJson: raw, emailTool: null };
|
|
16255
|
+
}
|
|
16256
|
+
const emailTool = parseEmailToolObject(parsed[EMAIL_TOOL_VALIDATION_KEY]);
|
|
16257
|
+
const rest = { ...parsed };
|
|
16258
|
+
delete rest[EMAIL_TOOL_VALIDATION_KEY];
|
|
16259
|
+
const guardrailsJson = Object.keys(rest).length > 0 ? JSON.stringify(rest, null, 2) : "";
|
|
16260
|
+
return { guardrailsJson, emailTool };
|
|
16261
|
+
} catch {
|
|
16262
|
+
return { guardrailsJson: raw, emailTool: null };
|
|
16263
|
+
}
|
|
16264
|
+
}
|
|
16265
|
+
function mergeEmailToolIntoValidationRules(guardrailsJson, emailTool) {
|
|
16266
|
+
const intents = dedupeIntents(emailTool.intents);
|
|
16267
|
+
const hasEmail = intents.length > 0 || emailTool.classifierInstructions.trim() !== "" || emailTool.toolPrompt.trim() !== "";
|
|
16268
|
+
let base = {};
|
|
16269
|
+
const raw = guardrailsJson?.trim();
|
|
16270
|
+
if (raw) {
|
|
16271
|
+
try {
|
|
16272
|
+
const parsed = JSON.parse(raw);
|
|
16273
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
16274
|
+
base = { ...parsed };
|
|
16275
|
+
delete base[EMAIL_TOOL_VALIDATION_KEY];
|
|
16276
|
+
} else {
|
|
16277
|
+
return raw;
|
|
16278
|
+
}
|
|
16279
|
+
} catch {
|
|
16280
|
+
return raw;
|
|
16281
|
+
}
|
|
16282
|
+
}
|
|
16283
|
+
if (!hasEmail) {
|
|
16284
|
+
return Object.keys(base).length > 0 ? JSON.stringify(base, null, 2) : null;
|
|
16285
|
+
}
|
|
16286
|
+
base[EMAIL_TOOL_VALIDATION_KEY] = {
|
|
16287
|
+
enabled: true,
|
|
16288
|
+
classifierInstructions: emailTool.classifierInstructions.trim(),
|
|
16289
|
+
toolPrompt: emailTool.toolPrompt.trim(),
|
|
16290
|
+
intents: intents.map((r) => ({
|
|
16291
|
+
intent: r.intent,
|
|
16292
|
+
description: r.description,
|
|
16293
|
+
emailTo: r.emailTo
|
|
16294
|
+
}))
|
|
16295
|
+
};
|
|
16296
|
+
return JSON.stringify(base, null, 2);
|
|
16297
|
+
}
|
|
16298
|
+
|
|
16299
|
+
// src/plugins/llm/llm-agent-scope.ts
|
|
16300
|
+
var LLM_AGENT_SCOPE_CHATBOT = "chatbot";
|
|
16301
|
+
var LLM_AGENT_SCOPE_BLOG_CREATION = "blog_creation";
|
|
16302
|
+
var LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST = "social_media_post";
|
|
16303
|
+
var LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT = "email_intent_chatbot";
|
|
16304
|
+
var LLM_AGENT_SCOPE_BLOG_METADATA = "blog_metadata";
|
|
16305
|
+
var LLM_AGENT_DEFAULT_SLUG_BY_SCOPE = {
|
|
16306
|
+
[LLM_AGENT_SCOPE_CHATBOT]: "site-chat-assistant",
|
|
16307
|
+
[LLM_AGENT_SCOPE_BLOG_CREATION]: "blog-generator",
|
|
16308
|
+
[LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST]: "blog-generator-social",
|
|
16309
|
+
[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT]: "email-intent-chatbot",
|
|
16310
|
+
[LLM_AGENT_SCOPE_BLOG_METADATA]: "blog-generator-metadata"
|
|
16311
|
+
};
|
|
16312
|
+
var LLM_AGENT_DEFAULT_NAME_BY_SCOPE = {
|
|
16313
|
+
[LLM_AGENT_SCOPE_CHATBOT]: "Site Chat Assistant",
|
|
16314
|
+
[LLM_AGENT_SCOPE_BLOG_CREATION]: "Blog Generator",
|
|
16315
|
+
[LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST]: "Blog Generator (Social)",
|
|
16316
|
+
[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT]: "Chat Lead Intent Classifier",
|
|
16317
|
+
[LLM_AGENT_SCOPE_BLOG_METADATA]: "Blog Generator (Metadata)"
|
|
16318
|
+
};
|
|
16319
|
+
var SITE_CHAT_ASSISTANT_SLUG = LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
16320
|
+
var SITE_CHAT_ASSISTANT_NAME = LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
16321
|
+
var BLOG_LLM_AGENT_SLUGS = [
|
|
16322
|
+
LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_BLOG_CREATION],
|
|
16323
|
+
LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_BLOG_METADATA],
|
|
16324
|
+
LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST]
|
|
16325
|
+
];
|
|
16326
|
+
|
|
16327
|
+
// src/admin/pages/PluginsPage.tsx
|
|
16118
16328
|
var import_jsx_runtime66 = require("react/jsx-runtime");
|
|
16119
16329
|
function normalizeLinkedInOrganizations(payload) {
|
|
16120
16330
|
if (!payload || typeof payload !== "object") return [];
|
|
@@ -16154,10 +16364,6 @@ function normalizeFacebookGraphPages(graph) {
|
|
|
16154
16364
|
}
|
|
16155
16365
|
return out;
|
|
16156
16366
|
}
|
|
16157
|
-
function slugifyAgentKey(name) {
|
|
16158
|
-
const s = name.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
|
|
16159
|
-
return s || "agent";
|
|
16160
|
-
}
|
|
16161
16367
|
function normalizeChatMode(raw) {
|
|
16162
16368
|
if (raw === "external" || raw === "llm") return raw;
|
|
16163
16369
|
return "whatsapp";
|
|
@@ -16296,6 +16502,8 @@ function PluginSettingsPanel({
|
|
|
16296
16502
|
descriptor,
|
|
16297
16503
|
onSaved
|
|
16298
16504
|
}) {
|
|
16505
|
+
const { pluginDescriptors = [] } = (0, import_react51.useContext)(AdminConfigContext);
|
|
16506
|
+
const emailPluginAvailable = pluginDescriptors.some((p) => p.name === "email" && p.enabled !== false);
|
|
16299
16507
|
const settingsGroup = descriptor.settingsGroup;
|
|
16300
16508
|
const isLlm = settingsGroup === "llm";
|
|
16301
16509
|
const isEmail = settingsGroup === "email";
|
|
@@ -16331,9 +16539,19 @@ function PluginSettingsPanel({
|
|
|
16331
16539
|
const [agentTemp, setAgentTemp] = (0, import_react51.useState)("");
|
|
16332
16540
|
const [agentMaxTokens, setAgentMaxTokens] = (0, import_react51.useState)("");
|
|
16333
16541
|
const [agentValidationJson, setAgentValidationJson] = (0, import_react51.useState)("");
|
|
16542
|
+
const [emailToolEnabled, setEmailToolEnabled] = (0, import_react51.useState)(false);
|
|
16543
|
+
const [emailIntents, setEmailIntents] = (0, import_react51.useState)([]);
|
|
16544
|
+
const [emailToolPrompt, setEmailToolPrompt] = (0, import_react51.useState)("");
|
|
16334
16545
|
const [agentLoading, setAgentLoading] = (0, import_react51.useState)(false);
|
|
16335
16546
|
const [agentSaving, setAgentSaving] = (0, import_react51.useState)(false);
|
|
16336
16547
|
const [agentProvisionError, setAgentProvisionError] = (0, import_react51.useState)(null);
|
|
16548
|
+
const [llmConfigTab, setLlmConfigTab] = (0, import_react51.useState)("chat");
|
|
16549
|
+
const [notifyEmailAgentId, setNotifyEmailAgentId] = (0, import_react51.useState)(null);
|
|
16550
|
+
const [notifyEmailName, setNotifyEmailName] = (0, import_react51.useState)("");
|
|
16551
|
+
const [notifyEmailSystem, setNotifyEmailSystem] = (0, import_react51.useState)("");
|
|
16552
|
+
const [notifyEmailLoading, setNotifyEmailLoading] = (0, import_react51.useState)(false);
|
|
16553
|
+
const [notifyEmailSaving, setNotifyEmailSaving] = (0, import_react51.useState)(false);
|
|
16554
|
+
const [notifyEmailProvisionError, setNotifyEmailProvisionError] = (0, import_react51.useState)(null);
|
|
16337
16555
|
const [kbCatalog, setKbCatalog] = (0, import_react51.useState)([]);
|
|
16338
16556
|
const [attachedAgentKnowledge, setAttachedAgentKnowledge] = (0, import_react51.useState)([]);
|
|
16339
16557
|
const [attachedKbLoading, setAttachedKbLoading] = (0, import_react51.useState)(false);
|
|
@@ -16555,7 +16773,12 @@ function PluginSettingsPanel({
|
|
|
16555
16773
|
setIconImageUrl(data.iconImageUrl ?? "");
|
|
16556
16774
|
setIconBackgroundColor(data.iconBackgroundColor ?? "#6366f1");
|
|
16557
16775
|
setHeaderColor(data.headerColor ?? "#6366f1");
|
|
16558
|
-
setAttachedAgentSlug(data.attachedAgentSlug ?? "");
|
|
16776
|
+
setAttachedAgentSlug((data.attachedAgentSlug ?? "").trim());
|
|
16777
|
+
setEmailToolEnabled(data.emailToolEnabled === "true");
|
|
16778
|
+
setEmailIntents(parseEmailIntentsFromSettings(data.emailIntents));
|
|
16779
|
+
const legacyClassifier = data.emailClassifierInstructions ?? [data.emailIntentPrompt, data.emailNegativeIntentPrompt].filter(Boolean).join("\n\n") ?? "";
|
|
16780
|
+
if (legacyClassifier) setNotifyEmailSystem(legacyClassifier);
|
|
16781
|
+
setEmailToolPrompt(data.emailToolPrompt ?? "");
|
|
16559
16782
|
}
|
|
16560
16783
|
if (isErp) {
|
|
16561
16784
|
setErpPipelineName(data.pipelineName ?? data.pipelineId ?? "");
|
|
@@ -16641,33 +16864,116 @@ function PluginSettingsPanel({
|
|
|
16641
16864
|
}).catch(() => setErpFormsCatalog([]));
|
|
16642
16865
|
}, [isErp, loading]);
|
|
16643
16866
|
const fetchLlmAgents = (0, import_react51.useCallback)(async () => {
|
|
16644
|
-
const res = await fetch(
|
|
16867
|
+
const res = await fetch(
|
|
16868
|
+
`/api/llm_agents?scope=${LLM_AGENT_SCOPE_CHATBOT}&limit=5&sortField=name&sortOrder=asc`
|
|
16869
|
+
);
|
|
16645
16870
|
if (!res.ok) {
|
|
16646
16871
|
setLlmAgents([]);
|
|
16872
|
+
setAgentId(null);
|
|
16647
16873
|
return;
|
|
16648
16874
|
}
|
|
16649
16875
|
const j = await res.json();
|
|
16650
|
-
const
|
|
16876
|
+
const chatRows = (j.data ?? []).filter(
|
|
16877
|
+
(r) => String(r.scope ?? "").trim() === LLM_AGENT_SCOPE_CHATBOT || String(r.slug ?? "").trim() === LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT]
|
|
16878
|
+
);
|
|
16879
|
+
const list = chatRows.map((r) => ({
|
|
16651
16880
|
id: r.id,
|
|
16652
16881
|
name: String(r.name ?? ""),
|
|
16653
16882
|
slug: String(r.slug ?? ""),
|
|
16883
|
+
scope: LLM_AGENT_SCOPE_CHATBOT,
|
|
16654
16884
|
enabled: r.enabled !== false
|
|
16655
16885
|
}));
|
|
16656
16886
|
setLlmAgents(list);
|
|
16657
16887
|
const pick = list.find((a) => a.enabled) ?? list[0];
|
|
16658
|
-
const fullRow =
|
|
16888
|
+
const fullRow = pick ? chatRows.find((r) => r.id === pick.id) : void 0;
|
|
16659
16889
|
if (pick && fullRow) {
|
|
16660
16890
|
setAgentId(pick.id);
|
|
16661
16891
|
setAgentName(pick.name);
|
|
16662
16892
|
setAgentSlug(pick.slug);
|
|
16893
|
+
setAttachedAgentSlug(pick.slug);
|
|
16663
16894
|
setAgentSystem(String(fullRow.systemInstruction ?? ""));
|
|
16664
16895
|
setAgentModel(String(fullRow.model ?? ""));
|
|
16665
16896
|
setAgentTemp(fullRow.temperature != null ? String(fullRow.temperature) : "");
|
|
16666
16897
|
setAgentMaxTokens(fullRow.maxTokens != null ? String(fullRow.maxTokens) : "");
|
|
16667
|
-
|
|
16668
|
-
|
|
16898
|
+
const { guardrailsJson } = splitValidationRulesForAdmin(fullRow.validationRules ?? null);
|
|
16899
|
+
setAgentValidationJson(guardrailsJson);
|
|
16900
|
+
} else {
|
|
16901
|
+
setAgentId(null);
|
|
16902
|
+
setAgentName(botName.trim() || LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT]);
|
|
16903
|
+
setAgentSlug(LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT]);
|
|
16904
|
+
setAgentSystem("");
|
|
16905
|
+
setAgentModel("");
|
|
16906
|
+
setAgentTemp("");
|
|
16907
|
+
setAgentMaxTokens("");
|
|
16908
|
+
setAgentValidationJson("");
|
|
16909
|
+
}
|
|
16910
|
+
}, [botName]);
|
|
16911
|
+
const fetchNotifyEmailAgent = (0, import_react51.useCallback)(async () => {
|
|
16912
|
+
const res = await fetch(
|
|
16913
|
+
`/api/llm_agents?scope=${LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT}&limit=1&sortField=name&sortOrder=asc`
|
|
16914
|
+
);
|
|
16915
|
+
if (!res.ok) {
|
|
16916
|
+
setNotifyEmailAgentId(null);
|
|
16917
|
+
return;
|
|
16918
|
+
}
|
|
16919
|
+
const j = await res.json();
|
|
16920
|
+
const row = j.data?.find((r) => String(r.scope ?? "").trim() === LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT) ?? j.data?.find(
|
|
16921
|
+
(r) => String(r.slug ?? "").trim() === LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT]
|
|
16922
|
+
) ?? j.data?.[0];
|
|
16923
|
+
if (!row || String(row.scope ?? "").trim() !== LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT) {
|
|
16924
|
+
setNotifyEmailAgentId(null);
|
|
16925
|
+
setNotifyEmailName(LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT]);
|
|
16926
|
+
setNotifyEmailSystem("");
|
|
16927
|
+
return;
|
|
16928
|
+
}
|
|
16929
|
+
setNotifyEmailAgentId(row.id);
|
|
16930
|
+
setNotifyEmailName(String(row.name ?? ""));
|
|
16931
|
+
setNotifyEmailSystem(String(row.systemInstruction ?? ""));
|
|
16932
|
+
const { emailTool } = splitValidationRulesForAdmin(row.validationRules ?? null);
|
|
16933
|
+
if (emailTool?.intents?.length) setEmailIntents(emailTool.intents);
|
|
16934
|
+
if (emailTool?.toolPrompt) setEmailToolPrompt(emailTool.toolPrompt);
|
|
16935
|
+
if (!row.systemInstruction?.trim() && emailTool?.classifierInstructions) {
|
|
16936
|
+
setNotifyEmailSystem(emailTool.classifierInstructions);
|
|
16669
16937
|
}
|
|
16670
16938
|
}, []);
|
|
16939
|
+
const bootstrapNotifyEmailAgent = (0, import_react51.useCallback)(async () => {
|
|
16940
|
+
setNotifyEmailProvisionError(null);
|
|
16941
|
+
const listRes = await fetch(
|
|
16942
|
+
`/api/llm_agents?scope=${LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT}&limit=1`
|
|
16943
|
+
);
|
|
16944
|
+
if (!listRes.ok) {
|
|
16945
|
+
const message = `Could not load notify email agent (HTTP ${listRes.status}).`;
|
|
16946
|
+
setNotifyEmailProvisionError(message);
|
|
16947
|
+
await fetchNotifyEmailAgent();
|
|
16948
|
+
return { ok: false, message };
|
|
16949
|
+
}
|
|
16950
|
+
const listJ = await listRes.json();
|
|
16951
|
+
const notifyRow = listJ.data?.find((a) => a.scope === LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT);
|
|
16952
|
+
if (notifyRow) {
|
|
16953
|
+
await fetchNotifyEmailAgent();
|
|
16954
|
+
return { ok: true };
|
|
16955
|
+
}
|
|
16956
|
+
const createRes = await fetch("/api/llm_agents", {
|
|
16957
|
+
method: "POST",
|
|
16958
|
+
headers: { "Content-Type": "application/json" },
|
|
16959
|
+
body: JSON.stringify({
|
|
16960
|
+
name: LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT],
|
|
16961
|
+
slug: LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT],
|
|
16962
|
+
scope: LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT,
|
|
16963
|
+
systemInstruction: "",
|
|
16964
|
+
enabled: true
|
|
16965
|
+
})
|
|
16966
|
+
});
|
|
16967
|
+
if (!createRes.ok) {
|
|
16968
|
+
const errBody = await createRes.json().catch(() => ({}));
|
|
16969
|
+
const message = errBody.error ?? `Could not create notify email agent (HTTP ${createRes.status}).`;
|
|
16970
|
+
setNotifyEmailProvisionError(message);
|
|
16971
|
+
await fetchNotifyEmailAgent();
|
|
16972
|
+
return { ok: false, message };
|
|
16973
|
+
}
|
|
16974
|
+
await fetchNotifyEmailAgent();
|
|
16975
|
+
return { ok: true };
|
|
16976
|
+
}, [fetchNotifyEmailAgent]);
|
|
16671
16977
|
const fetchKbCatalog = (0, import_react51.useCallback)(async () => {
|
|
16672
16978
|
try {
|
|
16673
16979
|
const res = await fetch("/api/knowledge_base_documents?limit=300&sortField=name&sortOrder=asc");
|
|
@@ -16713,7 +17019,9 @@ function PluginSettingsPanel({
|
|
|
16713
17019
|
}, []);
|
|
16714
17020
|
const bootstrapLlmAgentForPlugins = (0, import_react51.useCallback)(async () => {
|
|
16715
17021
|
setAgentProvisionError(null);
|
|
16716
|
-
const listRes = await fetch(
|
|
17022
|
+
const listRes = await fetch(
|
|
17023
|
+
`/api/llm_agents?scope=${LLM_AGENT_SCOPE_CHATBOT}&limit=5&sortField=name&sortOrder=asc`
|
|
17024
|
+
);
|
|
16717
17025
|
if (!listRes.ok) {
|
|
16718
17026
|
const errBody = await listRes.json().catch(() => ({}));
|
|
16719
17027
|
const message = errBody.error ?? `Could not load agents (HTTP ${listRes.status}). Ensure your app uses the latest @infuro/cms-core and your admin user can read entity "llm_agents".`;
|
|
@@ -16722,16 +17030,25 @@ function PluginSettingsPanel({
|
|
|
16722
17030
|
return { ok: false, message };
|
|
16723
17031
|
}
|
|
16724
17032
|
const listJ = await listRes.json();
|
|
16725
|
-
|
|
17033
|
+
const chatRow = listJ.data?.find(
|
|
17034
|
+
(a) => String(a.scope ?? "").trim() === LLM_AGENT_SCOPE_CHATBOT || String(a.slug ?? "").trim() === LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT]
|
|
17035
|
+
);
|
|
17036
|
+
if (chatRow) {
|
|
16726
17037
|
await fetchLlmAgents();
|
|
16727
17038
|
return { ok: true };
|
|
16728
17039
|
}
|
|
16729
|
-
const defaultName = botName.trim() ||
|
|
16730
|
-
const defaultSlug =
|
|
17040
|
+
const defaultName = botName.trim() || LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
17041
|
+
const defaultSlug = LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
16731
17042
|
const createRes = await fetch("/api/llm_agents", {
|
|
16732
17043
|
method: "POST",
|
|
16733
17044
|
headers: { "Content-Type": "application/json" },
|
|
16734
|
-
body: JSON.stringify({
|
|
17045
|
+
body: JSON.stringify({
|
|
17046
|
+
name: defaultName,
|
|
17047
|
+
slug: defaultSlug,
|
|
17048
|
+
scope: LLM_AGENT_SCOPE_CHATBOT,
|
|
17049
|
+
systemInstruction: "",
|
|
17050
|
+
enabled: true
|
|
17051
|
+
})
|
|
16735
17052
|
});
|
|
16736
17053
|
if (!createRes.ok) {
|
|
16737
17054
|
const errBody = await createRes.json().catch(() => ({}));
|
|
@@ -16757,11 +17074,7 @@ function PluginSettingsPanel({
|
|
|
16757
17074
|
}
|
|
16758
17075
|
};
|
|
16759
17076
|
const handleCreateAssistantFromForm = async () => {
|
|
16760
|
-
const name = agentName.trim() || botName.trim();
|
|
16761
|
-
if (!name) {
|
|
16762
|
-
import_sonner12.toast.error("Enter an assistant name");
|
|
16763
|
-
return;
|
|
16764
|
-
}
|
|
17077
|
+
const name = agentName.trim() || botName.trim() || LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
16765
17078
|
const tempRaw = agentTemp.trim();
|
|
16766
17079
|
const maxRaw = agentMaxTokens.trim();
|
|
16767
17080
|
const temperature = tempRaw === "" ? null : Number(tempRaw);
|
|
@@ -16774,7 +17087,7 @@ function PluginSettingsPanel({
|
|
|
16774
17087
|
import_sonner12.toast.error("Max tokens must be a positive integer");
|
|
16775
17088
|
return;
|
|
16776
17089
|
}
|
|
16777
|
-
const slug =
|
|
17090
|
+
const slug = LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
16778
17091
|
setAgentSaving(true);
|
|
16779
17092
|
try {
|
|
16780
17093
|
const res = await fetch("/api/llm_agents", {
|
|
@@ -16783,6 +17096,7 @@ function PluginSettingsPanel({
|
|
|
16783
17096
|
body: JSON.stringify({
|
|
16784
17097
|
name,
|
|
16785
17098
|
slug,
|
|
17099
|
+
scope: LLM_AGENT_SCOPE_CHATBOT,
|
|
16786
17100
|
systemInstruction: agentSystem.trim(),
|
|
16787
17101
|
model: agentModel.trim() || null,
|
|
16788
17102
|
temperature,
|
|
@@ -16809,18 +17123,19 @@ function PluginSettingsPanel({
|
|
|
16809
17123
|
(0, import_react51.useEffect)(() => {
|
|
16810
17124
|
if (!isLlm || loading || chatMode !== "llm") return;
|
|
16811
17125
|
setAgentLoading(true);
|
|
17126
|
+
setNotifyEmailLoading(true);
|
|
16812
17127
|
void (async () => {
|
|
16813
17128
|
try {
|
|
16814
17129
|
await bootstrapLlmAgentForPlugins();
|
|
17130
|
+
await bootstrapNotifyEmailAgent();
|
|
17131
|
+
await fetchNotifyEmailAgent();
|
|
17132
|
+
await fetchKbCatalog();
|
|
16815
17133
|
} finally {
|
|
16816
17134
|
setAgentLoading(false);
|
|
17135
|
+
setNotifyEmailLoading(false);
|
|
16817
17136
|
}
|
|
16818
17137
|
})();
|
|
16819
|
-
}, [isLlm, loading, chatMode, bootstrapLlmAgentForPlugins]);
|
|
16820
|
-
(0, import_react51.useEffect)(() => {
|
|
16821
|
-
if (!isLlm || loading || chatMode !== "llm") return;
|
|
16822
|
-
void fetchKbCatalog();
|
|
16823
|
-
}, [isLlm, loading, chatMode, fetchKbCatalog]);
|
|
17138
|
+
}, [isLlm, loading, chatMode, bootstrapLlmAgentForPlugins, bootstrapNotifyEmailAgent, fetchNotifyEmailAgent, fetchKbCatalog]);
|
|
16824
17139
|
(0, import_react51.useEffect)(() => {
|
|
16825
17140
|
if (!isLlm || loading || chatMode !== "llm" || !attachedAgentSlug.trim()) {
|
|
16826
17141
|
setAttachedAgentKnowledge([]);
|
|
@@ -16911,7 +17226,13 @@ function PluginSettingsPanel({
|
|
|
16911
17226
|
payload.iconImageUrl = { value: iconImageUrl, type: "public" };
|
|
16912
17227
|
payload.iconBackgroundColor = { value: iconBackgroundColor, type: "public" };
|
|
16913
17228
|
payload.headerColor = { value: headerColor, type: "public" };
|
|
16914
|
-
payload.attachedAgentSlug = {
|
|
17229
|
+
payload.attachedAgentSlug = {
|
|
17230
|
+
value: agentSlug.trim() || attachedAgentSlug.trim() || LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT],
|
|
17231
|
+
type: "public"
|
|
17232
|
+
};
|
|
17233
|
+
payload.emailToolEnabled = { value: emailToolEnabled ? "true" : "false", type: "public" };
|
|
17234
|
+
payload.emailIntents = { value: serializeChatLeadIntents(emailIntents), type: "public" };
|
|
17235
|
+
payload.emailToolPrompt = { value: emailToolPrompt, type: "public" };
|
|
16915
17236
|
}
|
|
16916
17237
|
if (isEmail) {
|
|
16917
17238
|
payload.salesTeamEmails = { value: serializeEmailRecipients(salesTeamEmails), type: "public" };
|
|
@@ -16927,65 +17248,169 @@ function PluginSettingsPanel({
|
|
|
16927
17248
|
}
|
|
16928
17249
|
return payload;
|
|
16929
17250
|
};
|
|
16930
|
-
const
|
|
16931
|
-
|
|
16932
|
-
|
|
16933
|
-
|
|
16934
|
-
|
|
16935
|
-
|
|
16936
|
-
|
|
16937
|
-
|
|
16938
|
-
|
|
16939
|
-
}
|
|
17251
|
+
const savePluginSettings = async () => {
|
|
17252
|
+
const res = await fetch(`/api/settings/${settingsGroup}`, {
|
|
17253
|
+
method: "PUT",
|
|
17254
|
+
headers: { "Content-Type": "application/json" },
|
|
17255
|
+
body: JSON.stringify(buildPayload())
|
|
17256
|
+
});
|
|
17257
|
+
return res.ok;
|
|
17258
|
+
};
|
|
17259
|
+
const validateChatAgentNumbers = () => {
|
|
16940
17260
|
const tempRaw = agentTemp.trim();
|
|
16941
17261
|
const maxRaw = agentMaxTokens.trim();
|
|
16942
17262
|
const temperature = tempRaw === "" ? null : Number(tempRaw);
|
|
16943
17263
|
const maxTokens = maxRaw === "" ? null : parseInt(maxRaw, 10);
|
|
16944
17264
|
if (tempRaw !== "" && !Number.isFinite(temperature)) {
|
|
16945
17265
|
import_sonner12.toast.error("Temperature must be a number");
|
|
16946
|
-
return;
|
|
17266
|
+
return null;
|
|
16947
17267
|
}
|
|
16948
17268
|
if (maxRaw !== "" && (!Number.isFinite(maxTokens) || maxTokens < 1)) {
|
|
16949
17269
|
import_sonner12.toast.error("Max tokens must be a positive integer");
|
|
17270
|
+
return null;
|
|
17271
|
+
}
|
|
17272
|
+
return { temperature, maxTokens };
|
|
17273
|
+
};
|
|
17274
|
+
const persistChatAgent = async () => {
|
|
17275
|
+
if (!agentId) return false;
|
|
17276
|
+
const nums = validateChatAgentNumbers();
|
|
17277
|
+
if (!nums) return false;
|
|
17278
|
+
const name = agentName.trim() || botName.trim() || LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
17279
|
+
const res = await fetch(`/api/llm_agents/${agentId}`, {
|
|
17280
|
+
method: "PUT",
|
|
17281
|
+
headers: { "Content-Type": "application/json" },
|
|
17282
|
+
body: JSON.stringify({
|
|
17283
|
+
name,
|
|
17284
|
+
systemInstruction: agentSystem.trim(),
|
|
17285
|
+
model: agentModel.trim() || null,
|
|
17286
|
+
temperature: nums.temperature,
|
|
17287
|
+
maxTokens: nums.maxTokens,
|
|
17288
|
+
validationRules: agentValidationJson.trim() || null,
|
|
17289
|
+
enabled: true
|
|
17290
|
+
})
|
|
17291
|
+
});
|
|
17292
|
+
if (!res.ok) return false;
|
|
17293
|
+
setAttachedAgentSlug(agentSlug);
|
|
17294
|
+
return true;
|
|
17295
|
+
};
|
|
17296
|
+
const persistNotifyEmailAgent = async (agentIdOverride) => {
|
|
17297
|
+
const id = agentIdOverride ?? notifyEmailAgentId;
|
|
17298
|
+
if (!id) return false;
|
|
17299
|
+
const validationRules = mergeEmailToolIntoValidationRules(null, {
|
|
17300
|
+
classifierInstructions: "",
|
|
17301
|
+
toolPrompt: emailToolPrompt,
|
|
17302
|
+
intents: emailIntents
|
|
17303
|
+
});
|
|
17304
|
+
const res = await fetch(`/api/llm_agents/${id}`, {
|
|
17305
|
+
method: "PUT",
|
|
17306
|
+
headers: { "Content-Type": "application/json" },
|
|
17307
|
+
body: JSON.stringify({
|
|
17308
|
+
name: notifyEmailName.trim() || LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT],
|
|
17309
|
+
systemInstruction: notifyEmailSystem.trim(),
|
|
17310
|
+
validationRules,
|
|
17311
|
+
enabled: true
|
|
17312
|
+
})
|
|
17313
|
+
});
|
|
17314
|
+
return res.ok;
|
|
17315
|
+
};
|
|
17316
|
+
const saveLlmPluginSettingsOnly = async () => {
|
|
17317
|
+
const res = await fetch(`/api/settings/${settingsGroup}`, {
|
|
17318
|
+
method: "PUT",
|
|
17319
|
+
headers: { "Content-Type": "application/json" },
|
|
17320
|
+
body: JSON.stringify(buildPayload())
|
|
17321
|
+
});
|
|
17322
|
+
return res.ok;
|
|
17323
|
+
};
|
|
17324
|
+
const handleSaveLlmChatTab = async () => {
|
|
17325
|
+
if (!agentId) {
|
|
17326
|
+
import_sonner12.toast.error("Wait for the assistant to load, or click Create assistant");
|
|
16950
17327
|
return;
|
|
16951
17328
|
}
|
|
16952
|
-
|
|
17329
|
+
if (!validateChatAgentNumbers()) return;
|
|
17330
|
+
setSaving(true);
|
|
16953
17331
|
try {
|
|
16954
|
-
const
|
|
16955
|
-
|
|
16956
|
-
|
|
16957
|
-
|
|
16958
|
-
|
|
16959
|
-
|
|
16960
|
-
|
|
16961
|
-
|
|
16962
|
-
maxTokens,
|
|
16963
|
-
validationRules: agentValidationJson.trim() || null,
|
|
16964
|
-
enabled: true
|
|
16965
|
-
})
|
|
16966
|
-
});
|
|
16967
|
-
if (!res.ok) {
|
|
16968
|
-
const err = await res.json().catch(() => ({}));
|
|
16969
|
-
import_sonner12.toast.error(err.error || "Failed to update agent");
|
|
17332
|
+
const chatOk = await persistChatAgent();
|
|
17333
|
+
if (!chatOk) {
|
|
17334
|
+
import_sonner12.toast.error("Failed to save assistant");
|
|
17335
|
+
return;
|
|
17336
|
+
}
|
|
17337
|
+
const settingsOk = await saveLlmPluginSettingsOnly();
|
|
17338
|
+
if (!settingsOk) {
|
|
17339
|
+
import_sonner12.toast.error("Failed to save widget settings");
|
|
16970
17340
|
return;
|
|
16971
17341
|
}
|
|
16972
|
-
|
|
16973
|
-
import_sonner12.toast.success("Agent saved");
|
|
17342
|
+
import_sonner12.toast.success("Chat settings saved");
|
|
16974
17343
|
} catch {
|
|
16975
|
-
import_sonner12.toast.error("Failed to
|
|
17344
|
+
import_sonner12.toast.error("Failed to save");
|
|
16976
17345
|
} finally {
|
|
16977
|
-
|
|
17346
|
+
setSaving(false);
|
|
17347
|
+
}
|
|
17348
|
+
};
|
|
17349
|
+
const handleSaveLlmNotifyTab = async () => {
|
|
17350
|
+
if (!emailPluginAvailable) {
|
|
17351
|
+
import_sonner12.toast.error("Enable the Email plugin (SMTP) first");
|
|
17352
|
+
return;
|
|
17353
|
+
}
|
|
17354
|
+
const filledIntents = emailIntents.filter(
|
|
17355
|
+
(r) => r.intent.trim() && r.description.trim() && r.emailTo.trim()
|
|
17356
|
+
);
|
|
17357
|
+
if (filledIntents.length === 0) {
|
|
17358
|
+
import_sonner12.toast.error("Add at least one intent with Intent, Description, and Email To");
|
|
17359
|
+
return;
|
|
17360
|
+
}
|
|
17361
|
+
setEmailIntents(filledIntents);
|
|
17362
|
+
setNotifyEmailSaving(true);
|
|
17363
|
+
try {
|
|
17364
|
+
let notifyId = notifyEmailAgentId;
|
|
17365
|
+
if (!notifyId) {
|
|
17366
|
+
await bootstrapNotifyEmailAgent();
|
|
17367
|
+
const nr = await fetch(
|
|
17368
|
+
`/api/llm_agents?scope=${LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT}&limit=1`
|
|
17369
|
+
);
|
|
17370
|
+
if (nr.ok) {
|
|
17371
|
+
const nj = await nr.json();
|
|
17372
|
+
const row = nj.data?.find(
|
|
17373
|
+
(r) => String(r.scope ?? "").trim() === LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT
|
|
17374
|
+
);
|
|
17375
|
+
if (row) {
|
|
17376
|
+
notifyId = row.id;
|
|
17377
|
+
setNotifyEmailAgentId(row.id);
|
|
17378
|
+
}
|
|
17379
|
+
}
|
|
17380
|
+
}
|
|
17381
|
+
if (!notifyId) {
|
|
17382
|
+
import_sonner12.toast.error("Could not set up lead email \u2014 try again");
|
|
17383
|
+
return;
|
|
17384
|
+
}
|
|
17385
|
+
setEmailToolEnabled(true);
|
|
17386
|
+
const notifyOk = await persistNotifyEmailAgent(notifyId);
|
|
17387
|
+
if (!notifyOk) {
|
|
17388
|
+
import_sonner12.toast.error("Failed to save lead email settings");
|
|
17389
|
+
return;
|
|
17390
|
+
}
|
|
17391
|
+
const settingsOk = await saveLlmPluginSettingsOnly();
|
|
17392
|
+
if (!settingsOk) {
|
|
17393
|
+
import_sonner12.toast.warning("Routing saved, but enable flag failed to save in settings");
|
|
17394
|
+
return;
|
|
17395
|
+
}
|
|
17396
|
+
import_sonner12.toast.success("Lead email routing saved");
|
|
17397
|
+
await fetchNotifyEmailAgent();
|
|
17398
|
+
} catch {
|
|
17399
|
+
import_sonner12.toast.error("Failed to save");
|
|
17400
|
+
} finally {
|
|
17401
|
+
setNotifyEmailSaving(false);
|
|
16978
17402
|
}
|
|
16979
17403
|
};
|
|
16980
17404
|
const handleSave = async () => {
|
|
17405
|
+
if (isLlm && chatMode === "llm") {
|
|
17406
|
+
if (llmConfigTab === "notify") await handleSaveLlmNotifyTab();
|
|
17407
|
+
else await handleSaveLlmChatTab();
|
|
17408
|
+
return;
|
|
17409
|
+
}
|
|
16981
17410
|
setSaving(true);
|
|
16982
17411
|
try {
|
|
16983
|
-
const
|
|
16984
|
-
|
|
16985
|
-
headers: { "Content-Type": "application/json" },
|
|
16986
|
-
body: JSON.stringify(buildPayload())
|
|
16987
|
-
});
|
|
16988
|
-
if (!res.ok) throw new Error();
|
|
17412
|
+
const ok = await savePluginSettings();
|
|
17413
|
+
if (!ok) throw new Error();
|
|
16989
17414
|
if (isSocialMedia && (linkedinAccessToken.trim() || linkedinHasSavedToken)) {
|
|
16990
17415
|
if (linkedinAccessToken.trim()) {
|
|
16991
17416
|
setLinkedinHasSavedToken(true);
|
|
@@ -17907,328 +18332,458 @@ function PluginSettingsPanel({
|
|
|
17907
18332
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Only paste code from sources you trust." })
|
|
17908
18333
|
] }),
|
|
17909
18334
|
chatMode === "llm" && /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(import_jsx_runtime66.Fragment, { children: [
|
|
17910
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "rounded-lg border border-gray-200 dark:border-gray-600
|
|
17911
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
|
|
17912
|
-
|
|
17913
|
-
|
|
17914
|
-
|
|
17915
|
-
|
|
17916
|
-
|
|
17917
|
-
|
|
17918
|
-
|
|
17919
|
-
|
|
17920
|
-
|
|
17921
|
-
|
|
17922
|
-
|
|
18335
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "inline-flex rounded-lg border border-gray-200 bg-gray-50 p-0.5 dark:border-gray-600 dark:bg-gray-800/80", children: [
|
|
18336
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
|
|
18337
|
+
"button",
|
|
18338
|
+
{
|
|
18339
|
+
type: "button",
|
|
18340
|
+
className: `flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-colors ${llmConfigTab === "chat" ? "bg-white text-gray-900 shadow-sm dark:bg-gray-900 dark:text-white" : "text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"}`,
|
|
18341
|
+
onClick: () => setLlmConfigTab("chat"),
|
|
18342
|
+
children: [
|
|
18343
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.MessageCircle, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
18344
|
+
"Chat"
|
|
18345
|
+
]
|
|
18346
|
+
}
|
|
18347
|
+
),
|
|
18348
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
|
|
18349
|
+
"button",
|
|
18350
|
+
{
|
|
18351
|
+
type: "button",
|
|
18352
|
+
className: `flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-colors ${llmConfigTab === "notify" ? "bg-white text-gray-900 shadow-sm dark:bg-gray-900 dark:text-white" : "text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"}`,
|
|
18353
|
+
onClick: () => setLlmConfigTab("notify"),
|
|
18354
|
+
children: [
|
|
18355
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Mail, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
18356
|
+
"Notify"
|
|
18357
|
+
]
|
|
18358
|
+
}
|
|
18359
|
+
)
|
|
18360
|
+
] }),
|
|
18361
|
+
llmConfigTab === "chat" ? /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(import_jsx_runtime66.Fragment, { children: [
|
|
18362
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "rounded-lg border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-900/40 p-3 space-y-3", children: [
|
|
18363
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Widget on your site" }),
|
|
18364
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "text-[11px] text-gray-500 dark:text-gray-400", children: "Title, icon, and colors visitors see on the chat bubble." }),
|
|
17923
18365
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-1", children: [
|
|
17924
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor:
|
|
18366
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: `${settingsGroup}-botName`, className: "text-sm", children: "Widget title" }),
|
|
17925
18367
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
17926
18368
|
Input,
|
|
17927
18369
|
{
|
|
17928
|
-
id:
|
|
17929
|
-
value:
|
|
17930
|
-
onChange: (e) =>
|
|
18370
|
+
id: `${settingsGroup}-botName`,
|
|
18371
|
+
value: botName,
|
|
18372
|
+
onChange: (e) => setBotName(e.target.value),
|
|
17931
18373
|
placeholder: "e.g. JM Buddy",
|
|
17932
18374
|
className: "h-8 text-sm"
|
|
17933
18375
|
}
|
|
17934
18376
|
)
|
|
17935
18377
|
] }),
|
|
17936
18378
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-1", children: [
|
|
17937
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor:
|
|
18379
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: `${settingsGroup}-iconImageUrl`, className: "text-sm", children: "Icon image URL" }),
|
|
17938
18380
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
17939
18381
|
Input,
|
|
17940
18382
|
{
|
|
17941
|
-
id:
|
|
17942
|
-
value:
|
|
17943
|
-
|
|
17944
|
-
|
|
18383
|
+
id: `${settingsGroup}-iconImageUrl`,
|
|
18384
|
+
value: iconImageUrl,
|
|
18385
|
+
onChange: (e) => setIconImageUrl(e.target.value),
|
|
18386
|
+
placeholder: "https://\u2026 or /images/chat-icon.png",
|
|
18387
|
+
className: "h-8 text-sm"
|
|
17945
18388
|
}
|
|
17946
18389
|
),
|
|
17947
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "text-
|
|
18390
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "PNG or image URL. Leave empty to use emoji below." })
|
|
17948
18391
|
] }),
|
|
17949
18392
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-1", children: [
|
|
17950
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor:
|
|
18393
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: `${settingsGroup}-icon`, className: "text-sm", children: "Icon fallback (emoji)" }),
|
|
17951
18394
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
17952
|
-
|
|
18395
|
+
Input,
|
|
17953
18396
|
{
|
|
17954
|
-
id:
|
|
17955
|
-
value:
|
|
17956
|
-
onChange: (e) =>
|
|
17957
|
-
|
|
17958
|
-
|
|
17959
|
-
className: "text-sm"
|
|
18397
|
+
id: `${settingsGroup}-icon`,
|
|
18398
|
+
value: icon,
|
|
18399
|
+
onChange: (e) => setIcon(e.target.value),
|
|
18400
|
+
placeholder: "e.g. \u{1F4AC}",
|
|
18401
|
+
className: "h-8 text-sm w-20"
|
|
17960
18402
|
}
|
|
17961
18403
|
)
|
|
17962
18404
|
] }),
|
|
17963
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "
|
|
18405
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex gap-4", children: [
|
|
18406
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-1", children: [
|
|
18407
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: `${settingsGroup}-iconBg`, className: "text-sm", children: "Icon background" }),
|
|
18408
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
18409
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18410
|
+
"input",
|
|
18411
|
+
{
|
|
18412
|
+
type: "color",
|
|
18413
|
+
id: `${settingsGroup}-iconBg`,
|
|
18414
|
+
value: iconBackgroundColor,
|
|
18415
|
+
onChange: (e) => setIconBackgroundColor(e.target.value),
|
|
18416
|
+
className: "h-8 w-10 cursor-pointer rounded border border-gray-300 dark:border-gray-600"
|
|
18417
|
+
}
|
|
18418
|
+
),
|
|
18419
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18420
|
+
Input,
|
|
18421
|
+
{
|
|
18422
|
+
value: iconBackgroundColor,
|
|
18423
|
+
onChange: (e) => setIconBackgroundColor(e.target.value),
|
|
18424
|
+
className: "h-8 w-24 text-sm font-mono"
|
|
18425
|
+
}
|
|
18426
|
+
)
|
|
18427
|
+
] })
|
|
18428
|
+
] }),
|
|
18429
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-1", children: [
|
|
18430
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: `${settingsGroup}-headerColor`, className: "text-sm", children: "Header color" }),
|
|
18431
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
18432
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18433
|
+
"input",
|
|
18434
|
+
{
|
|
18435
|
+
type: "color",
|
|
18436
|
+
id: `${settingsGroup}-headerColor`,
|
|
18437
|
+
value: headerColor,
|
|
18438
|
+
onChange: (e) => setHeaderColor(e.target.value),
|
|
18439
|
+
className: "h-8 w-10 cursor-pointer rounded border border-gray-300 dark:border-gray-600"
|
|
18440
|
+
}
|
|
18441
|
+
),
|
|
18442
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18443
|
+
Input,
|
|
18444
|
+
{
|
|
18445
|
+
value: headerColor,
|
|
18446
|
+
onChange: (e) => setHeaderColor(e.target.value),
|
|
18447
|
+
className: "h-8 w-24 text-sm font-mono"
|
|
18448
|
+
}
|
|
18449
|
+
)
|
|
18450
|
+
] })
|
|
18451
|
+
] })
|
|
18452
|
+
] })
|
|
18453
|
+
] }),
|
|
18454
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "rounded-lg border border-gray-200 dark:border-gray-600 bg-gray-50/80 dark:bg-gray-800/40 p-3 space-y-4", children: [
|
|
18455
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-1", children: [
|
|
18456
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex items-center gap-2 text-sm font-medium text-gray-900 dark:text-white", children: [
|
|
18457
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Bot, { className: "h-4 w-4" }),
|
|
18458
|
+
"Assistant"
|
|
18459
|
+
] }),
|
|
18460
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "text-[11px] text-gray-500 dark:text-gray-400", children: "Storefront assistant \u2014 model, instructions, and guardrails." })
|
|
18461
|
+
] }),
|
|
18462
|
+
agentLoading ? /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex items-center gap-2 text-sm text-gray-500", children: [
|
|
18463
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
18464
|
+
"Loading\u2026"
|
|
18465
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(import_jsx_runtime66.Fragment, { children: [
|
|
18466
|
+
agentProvisionError ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "rounded border border-amber-200 bg-amber-50 p-2 text-xs text-amber-900 dark:border-amber-800 dark:bg-amber-950/40 dark:text-amber-100", children: agentProvisionError }) : null,
|
|
17964
18467
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-1", children: [
|
|
17965
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: "agent-
|
|
18468
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: "agent-system", className: "text-sm", children: "System instruction" }),
|
|
17966
18469
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
17967
|
-
|
|
18470
|
+
Textarea,
|
|
17968
18471
|
{
|
|
17969
|
-
id: "agent-
|
|
17970
|
-
value:
|
|
17971
|
-
onChange: (e) =>
|
|
17972
|
-
|
|
17973
|
-
|
|
18472
|
+
id: "agent-system",
|
|
18473
|
+
value: agentSystem,
|
|
18474
|
+
onChange: (e) => setAgentSystem(e.target.value),
|
|
18475
|
+
rows: 5,
|
|
18476
|
+
placeholder: "How the model should behave\u2026",
|
|
18477
|
+
className: "text-sm"
|
|
17974
18478
|
}
|
|
17975
18479
|
)
|
|
17976
18480
|
] }),
|
|
18481
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
18482
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-1", children: [
|
|
18483
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: "agent-model", className: "text-sm", children: "Model (optional)" }),
|
|
18484
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18485
|
+
Input,
|
|
18486
|
+
{
|
|
18487
|
+
id: "agent-model",
|
|
18488
|
+
value: agentModel,
|
|
18489
|
+
onChange: (e) => setAgentModel(e.target.value),
|
|
18490
|
+
placeholder: "Gateway model id",
|
|
18491
|
+
className: "h-8 text-sm font-mono"
|
|
18492
|
+
}
|
|
18493
|
+
)
|
|
18494
|
+
] }),
|
|
18495
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-1", children: [
|
|
18496
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: "agent-temp", className: "text-sm", children: "Temperature" }),
|
|
18497
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18498
|
+
Input,
|
|
18499
|
+
{
|
|
18500
|
+
id: "agent-temp",
|
|
18501
|
+
value: agentTemp,
|
|
18502
|
+
onChange: (e) => setAgentTemp(e.target.value),
|
|
18503
|
+
placeholder: "e.g. 0.7",
|
|
18504
|
+
className: "h-8 text-sm"
|
|
18505
|
+
}
|
|
18506
|
+
)
|
|
18507
|
+
] })
|
|
18508
|
+
] }),
|
|
17977
18509
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-1", children: [
|
|
17978
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: "agent-
|
|
18510
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: "agent-max", className: "text-sm", children: "Max tokens" }),
|
|
17979
18511
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
17980
18512
|
Input,
|
|
17981
18513
|
{
|
|
17982
|
-
id: "agent-
|
|
17983
|
-
value:
|
|
17984
|
-
onChange: (e) =>
|
|
17985
|
-
placeholder: "e.g.
|
|
18514
|
+
id: "agent-max",
|
|
18515
|
+
value: agentMaxTokens,
|
|
18516
|
+
onChange: (e) => setAgentMaxTokens(e.target.value.replace(/\D/g, "")),
|
|
18517
|
+
placeholder: "e.g. 1024",
|
|
17986
18518
|
className: "h-8 text-sm"
|
|
17987
18519
|
}
|
|
17988
18520
|
)
|
|
17989
|
-
] })
|
|
17990
|
-
|
|
17991
|
-
|
|
17992
|
-
|
|
17993
|
-
|
|
17994
|
-
|
|
17995
|
-
|
|
17996
|
-
|
|
17997
|
-
|
|
17998
|
-
|
|
17999
|
-
|
|
18000
|
-
|
|
18001
|
-
|
|
18002
|
-
|
|
18521
|
+
] }),
|
|
18522
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-1", children: [
|
|
18523
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: "agent-validation", className: "text-sm", children: "Validation & output guardrails" }),
|
|
18524
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18525
|
+
Textarea,
|
|
18526
|
+
{
|
|
18527
|
+
id: "agent-validation",
|
|
18528
|
+
value: agentValidationJson,
|
|
18529
|
+
onChange: (e) => setAgentValidationJson(e.target.value),
|
|
18530
|
+
rows: 4,
|
|
18531
|
+
placeholder: 'Plain text or JSON: {"guardrails":"Never promise refunds.","maxUserChars":2000}',
|
|
18532
|
+
className: "text-xs font-mono"
|
|
18533
|
+
}
|
|
18534
|
+
)
|
|
18535
|
+
] }),
|
|
18536
|
+
!agentId ? /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
18537
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18538
|
+
Button,
|
|
18539
|
+
{
|
|
18540
|
+
type: "button",
|
|
18541
|
+
size: "sm",
|
|
18542
|
+
className: "gap-1",
|
|
18543
|
+
disabled: agentSaving,
|
|
18544
|
+
onClick: () => void handleCreateAssistantFromForm(),
|
|
18545
|
+
children: agentSaving ? /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
18546
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Loader2, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
18547
|
+
"Creating\u2026"
|
|
18548
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(import_jsx_runtime66.Fragment, { children: [
|
|
18549
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Bot, { className: "h-3.5 w-3.5" }),
|
|
18550
|
+
"Create assistant"
|
|
18551
|
+
] })
|
|
18552
|
+
}
|
|
18553
|
+
),
|
|
18554
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18555
|
+
Button,
|
|
18556
|
+
{
|
|
18557
|
+
type: "button",
|
|
18558
|
+
size: "sm",
|
|
18559
|
+
variant: "secondary",
|
|
18560
|
+
className: "gap-1",
|
|
18561
|
+
disabled: agentSaving || agentLoading,
|
|
18562
|
+
onClick: () => void handleRetryBootstrapAgent(),
|
|
18563
|
+
children: "Retry auto-setup"
|
|
18564
|
+
}
|
|
18565
|
+
)
|
|
18566
|
+
] }) : null
|
|
18003
18567
|
] }),
|
|
18568
|
+
agentId && agentSlug.trim() ? /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "rounded-md border border-dashed border-gray-300 dark:border-gray-600 bg-white/60 dark:bg-gray-900/30 p-3 space-y-3", children: [
|
|
18569
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex items-center gap-2 text-xs font-medium text-gray-800 dark:text-gray-200", children: [
|
|
18570
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.FileUp, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
18571
|
+
"Knowledge for this agent"
|
|
18572
|
+
] }),
|
|
18573
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Upload text (.txt, .md, .json) or PDF (.pdf), or link documents already in the knowledge base." }),
|
|
18574
|
+
attachedKbLoading ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Loading linked documents\u2026" }) : attachedAgentKnowledge.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "No documents linked yet." }) : /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("ul", { className: "max-h-32 space-y-1.5 overflow-y-auto", children: attachedAgentKnowledge.map((d) => /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("li", { className: "flex items-center justify-between gap-2 text-sm", children: [
|
|
18575
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "min-w-0 truncate", title: d.name, children: d.name }),
|
|
18576
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18577
|
+
Button,
|
|
18578
|
+
{
|
|
18579
|
+
type: "button",
|
|
18580
|
+
variant: "ghost",
|
|
18581
|
+
size: "sm",
|
|
18582
|
+
className: "h-7 shrink-0 text-xs text-red-600 hover:text-red-700 dark:text-red-400",
|
|
18583
|
+
onClick: () => void handleUnlinkKbDoc(d.id),
|
|
18584
|
+
children: "Remove"
|
|
18585
|
+
}
|
|
18586
|
+
)
|
|
18587
|
+
] }, d.id)) }),
|
|
18588
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "min-w-[180px] space-y-1", children: [
|
|
18589
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { className: "text-xs", children: "Upload file" }),
|
|
18590
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "relative", children: [
|
|
18591
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18592
|
+
Input,
|
|
18593
|
+
{
|
|
18594
|
+
type: "file",
|
|
18595
|
+
accept: ".txt,.md,.json,.pdf,text/plain,text/markdown,application/json,application/pdf",
|
|
18596
|
+
disabled: uploadingAttachedKbFile || uploadingAttachedKbLink,
|
|
18597
|
+
className: "h-8 cursor-pointer text-xs disabled:opacity-60",
|
|
18598
|
+
onChange: onAttachedKbFileChange
|
|
18599
|
+
},
|
|
18600
|
+
attachedKbInputKey
|
|
18601
|
+
),
|
|
18602
|
+
uploadingAttachedKbFile ? /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
|
|
18603
|
+
"div",
|
|
18604
|
+
{
|
|
18605
|
+
className: "pointer-events-none absolute inset-0 flex items-center justify-center gap-2 rounded-md bg-background/85 text-xs font-medium text-gray-700 dark:text-gray-200",
|
|
18606
|
+
"aria-live": "polite",
|
|
18607
|
+
children: [
|
|
18608
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Loader2, { className: "h-4 w-4 shrink-0 animate-spin" }),
|
|
18609
|
+
"Saving & linking\u2026"
|
|
18610
|
+
]
|
|
18611
|
+
}
|
|
18612
|
+
) : null
|
|
18613
|
+
] }),
|
|
18614
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "text-[11px] text-gray-500 dark:text-gray-400", children: "Pick a file to upload immediately (chunking, embeddings if configured, then link to this agent)." })
|
|
18615
|
+
] }),
|
|
18616
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex flex-wrap items-end gap-2", children: [
|
|
18617
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "min-w-[200px] flex-1 space-y-1", children: [
|
|
18618
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { className: "text-xs", children: "Attach existing document" }),
|
|
18619
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(Select, { value: attachExistingDocId, onValueChange: setAttachExistingDocId, children: [
|
|
18620
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(SelectValue, { placeholder: "Choose a document" }) }),
|
|
18621
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(SelectContent, { children: [
|
|
18622
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(SelectItem, { value: "__none__", children: "\u2014 Select \u2014" }),
|
|
18623
|
+
kbCatalog.filter((d) => !attachedAgentKnowledge.some((a) => a.id === d.id)).map((d) => /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(SelectItem, { value: String(d.id), children: d.name }, d.id))
|
|
18624
|
+
] })
|
|
18625
|
+
] })
|
|
18626
|
+
] }),
|
|
18627
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18628
|
+
Button,
|
|
18629
|
+
{
|
|
18630
|
+
type: "button",
|
|
18631
|
+
size: "sm",
|
|
18632
|
+
className: "h-8",
|
|
18633
|
+
disabled: uploadingAttachedKbFile || uploadingAttachedKbLink || attachExistingDocId === "__none__",
|
|
18634
|
+
onClick: () => void handleAttachExistingToAttached(),
|
|
18635
|
+
children: uploadingAttachedKbLink ? /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
18636
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Loader2, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
18637
|
+
"Linking\u2026"
|
|
18638
|
+
] }) : "Attach"
|
|
18639
|
+
}
|
|
18640
|
+
)
|
|
18641
|
+
] })
|
|
18642
|
+
] }) : null
|
|
18643
|
+
] }),
|
|
18644
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
|
|
18645
|
+
Button,
|
|
18646
|
+
{
|
|
18647
|
+
type: "button",
|
|
18648
|
+
size: "sm",
|
|
18649
|
+
onClick: () => void handleSaveLlmChatTab(),
|
|
18650
|
+
disabled: saving,
|
|
18651
|
+
className: "gap-1",
|
|
18652
|
+
children: [
|
|
18653
|
+
saving ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Loader2, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Save, { className: "h-3.5 w-3.5" }),
|
|
18654
|
+
"Save"
|
|
18655
|
+
]
|
|
18656
|
+
}
|
|
18657
|
+
)
|
|
18658
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "rounded-lg border border-gray-200 dark:border-gray-600 bg-gray-50/80 dark:bg-gray-800/40 p-3 space-y-4", children: [
|
|
18659
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { children: [
|
|
18660
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Lead email routing" }),
|
|
18661
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "mt-0.5 text-[11px] text-gray-500 dark:text-gray-400", children: "Routing instructions and intents. When a message matches, your team gets one email per conversation." })
|
|
18662
|
+
] }),
|
|
18663
|
+
!emailPluginAvailable ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "rounded border border-amber-200 bg-amber-50/80 p-2 text-[11px] text-amber-700 dark:border-amber-800 dark:bg-amber-950/40 dark:text-amber-300", children: "Enable the Email plugin (SMTP) to send lead alert emails." }) : notifyEmailLoading ? /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex items-center gap-2 text-sm text-gray-500", children: [
|
|
18664
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
18665
|
+
"Loading\u2026"
|
|
18666
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(import_jsx_runtime66.Fragment, { children: [
|
|
18667
|
+
notifyEmailProvisionError ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "rounded border border-amber-200 bg-amber-50 p-2 text-xs text-amber-900 dark:border-amber-800 dark:bg-amber-950/40 dark:text-amber-100", children: notifyEmailProvisionError }) : null,
|
|
18004
18668
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-1", children: [
|
|
18005
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: "
|
|
18669
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: "notify-email-system", className: "text-sm", children: "Routing instructions" }),
|
|
18006
18670
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18007
18671
|
Textarea,
|
|
18008
18672
|
{
|
|
18009
|
-
id: "
|
|
18010
|
-
value:
|
|
18011
|
-
onChange: (e) =>
|
|
18673
|
+
id: "notify-email-system",
|
|
18674
|
+
value: notifyEmailSystem,
|
|
18675
|
+
onChange: (e) => setNotifyEmailSystem(e.target.value),
|
|
18012
18676
|
rows: 4,
|
|
18013
|
-
placeholder:
|
|
18014
|
-
className: "text-
|
|
18015
|
-
}
|
|
18016
|
-
)
|
|
18017
|
-
] }),
|
|
18018
|
-
!agentId ? /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
18019
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18020
|
-
Button,
|
|
18021
|
-
{
|
|
18022
|
-
type: "button",
|
|
18023
|
-
size: "sm",
|
|
18024
|
-
className: "gap-1",
|
|
18025
|
-
disabled: agentSaving,
|
|
18026
|
-
onClick: () => void handleCreateAssistantFromForm(),
|
|
18027
|
-
children: agentSaving ? /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
18028
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Loader2, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
18029
|
-
"Creating\u2026"
|
|
18030
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(import_jsx_runtime66.Fragment, { children: [
|
|
18031
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Bot, { className: "h-3.5 w-3.5" }),
|
|
18032
|
-
"Create assistant"
|
|
18033
|
-
] })
|
|
18034
|
-
}
|
|
18035
|
-
),
|
|
18036
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18037
|
-
Button,
|
|
18038
|
-
{
|
|
18039
|
-
type: "button",
|
|
18040
|
-
size: "sm",
|
|
18041
|
-
variant: "secondary",
|
|
18042
|
-
className: "gap-1",
|
|
18043
|
-
disabled: agentSaving || agentLoading,
|
|
18044
|
-
onClick: () => void handleRetryBootstrapAgent(),
|
|
18045
|
-
children: "Retry auto-setup"
|
|
18677
|
+
placeholder: "When to treat a message as a lead, priority, when not to email\u2026",
|
|
18678
|
+
className: "text-sm"
|
|
18046
18679
|
}
|
|
18047
18680
|
)
|
|
18048
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18049
|
-
Button,
|
|
18050
|
-
{
|
|
18051
|
-
type: "button",
|
|
18052
|
-
size: "sm",
|
|
18053
|
-
className: "gap-1",
|
|
18054
|
-
disabled: agentSaving,
|
|
18055
|
-
onClick: () => void handleSaveAgent(),
|
|
18056
|
-
children: agentSaving ? /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
18057
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Loader2, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
18058
|
-
"Saving\u2026"
|
|
18059
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(import_jsx_runtime66.Fragment, { children: [
|
|
18060
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Save, { className: "h-3.5 w-3.5" }),
|
|
18061
|
-
"Save assistant"
|
|
18062
|
-
] })
|
|
18063
|
-
}
|
|
18064
|
-
)
|
|
18065
|
-
] }),
|
|
18066
|
-
agentId && agentSlug.trim() ? /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "rounded-md border border-dashed border-gray-300 dark:border-gray-600 bg-white/60 dark:bg-gray-900/30 p-3 space-y-3", children: [
|
|
18067
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex items-center gap-2 text-xs font-medium text-gray-800 dark:text-gray-200", children: [
|
|
18068
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.FileUp, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
18069
|
-
"Knowledge for this agent"
|
|
18070
18681
|
] }),
|
|
18071
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.
|
|
18072
|
-
|
|
18073
|
-
|
|
18074
|
-
|
|
18075
|
-
|
|
18076
|
-
{
|
|
18077
|
-
type: "button",
|
|
18078
|
-
variant: "ghost",
|
|
18079
|
-
size: "sm",
|
|
18080
|
-
className: "h-7 shrink-0 text-xs text-red-600 hover:text-red-700 dark:text-red-400",
|
|
18081
|
-
onClick: () => void handleUnlinkKbDoc(d.id),
|
|
18082
|
-
children: "Remove"
|
|
18083
|
-
}
|
|
18084
|
-
)
|
|
18085
|
-
] }, d.id)) }),
|
|
18086
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "min-w-[180px] space-y-1", children: [
|
|
18087
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { className: "text-xs", children: "Upload file" }),
|
|
18088
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "relative", children: [
|
|
18089
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18090
|
-
Input,
|
|
18091
|
-
{
|
|
18092
|
-
type: "file",
|
|
18093
|
-
accept: ".txt,.md,.json,.pdf,text/plain,text/markdown,application/json,application/pdf",
|
|
18094
|
-
disabled: uploadingAttachedKbFile || uploadingAttachedKbLink,
|
|
18095
|
-
className: "h-8 cursor-pointer text-xs disabled:opacity-60",
|
|
18096
|
-
onChange: onAttachedKbFileChange
|
|
18097
|
-
},
|
|
18098
|
-
attachedKbInputKey
|
|
18099
|
-
),
|
|
18100
|
-
uploadingAttachedKbFile ? /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
|
|
18101
|
-
"div",
|
|
18682
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-2", children: [
|
|
18683
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
|
|
18684
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { className: "text-sm", children: "Intents" }),
|
|
18685
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
|
|
18686
|
+
Button,
|
|
18102
18687
|
{
|
|
18103
|
-
|
|
18104
|
-
|
|
18688
|
+
type: "button",
|
|
18689
|
+
size: "sm",
|
|
18690
|
+
variant: "outline",
|
|
18691
|
+
className: "h-7 gap-1 text-xs",
|
|
18692
|
+
onClick: () => setEmailIntents((rows) => [
|
|
18693
|
+
...rows,
|
|
18694
|
+
{ intent: "", description: "", emailTo: "" }
|
|
18695
|
+
]),
|
|
18105
18696
|
children: [
|
|
18106
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.
|
|
18107
|
-
"
|
|
18697
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Plus, { className: "h-3 w-3" }),
|
|
18698
|
+
"Add intent"
|
|
18108
18699
|
]
|
|
18109
18700
|
}
|
|
18110
|
-
)
|
|
18701
|
+
)
|
|
18111
18702
|
] }),
|
|
18112
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("
|
|
18113
|
-
|
|
18114
|
-
|
|
18115
|
-
|
|
18116
|
-
|
|
18117
|
-
|
|
18118
|
-
|
|
18119
|
-
|
|
18120
|
-
|
|
18121
|
-
|
|
18122
|
-
|
|
18703
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("div", { className: "overflow-x-auto rounded border border-gray-200 dark:border-gray-600", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("table", { className: "w-full text-xs", children: [
|
|
18704
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("tr", { className: "bg-gray-100/80 text-left dark:bg-gray-900/60", children: [
|
|
18705
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("th", { className: "w-[28%] p-2 font-medium", children: "Intent" }),
|
|
18706
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("th", { className: "w-[42%] p-2 font-medium", children: "Description" }),
|
|
18707
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("th", { className: "w-[26%] p-2 font-medium", children: "Email To" }),
|
|
18708
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("th", { className: "w-8 p-2" })
|
|
18709
|
+
] }) }),
|
|
18710
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("tbody", { children: [
|
|
18711
|
+
emailIntents.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("td", { colSpan: 4, className: "p-4 text-center text-gray-500 dark:text-gray-400", children: "Add at least one intent, then Save." }) }) : null,
|
|
18712
|
+
emailIntents.map((row, idx) => /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("tr", { className: "border-t border-gray-200 dark:border-gray-700", children: [
|
|
18713
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("td", { className: "p-1.5 align-top", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18714
|
+
Input,
|
|
18715
|
+
{
|
|
18716
|
+
value: row.intent,
|
|
18717
|
+
onChange: (e) => {
|
|
18718
|
+
const v = e.target.value.toUpperCase().replace(/[^A-Z0-9_]/g, "");
|
|
18719
|
+
setEmailIntents(
|
|
18720
|
+
(rows) => rows.map((r, i) => i === idx ? { ...r, intent: v } : r)
|
|
18721
|
+
);
|
|
18722
|
+
},
|
|
18723
|
+
placeholder: "SALES_LEAD",
|
|
18724
|
+
className: "h-8 font-mono text-xs"
|
|
18725
|
+
}
|
|
18726
|
+
) }),
|
|
18727
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("td", { className: "p-1.5 align-top", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18728
|
+
Input,
|
|
18729
|
+
{
|
|
18730
|
+
value: row.description,
|
|
18731
|
+
onChange: (e) => setEmailIntents(
|
|
18732
|
+
(rows) => rows.map(
|
|
18733
|
+
(r, i) => i === idx ? { ...r, description: e.target.value } : r
|
|
18734
|
+
)
|
|
18735
|
+
),
|
|
18736
|
+
placeholder: "What this intent means",
|
|
18737
|
+
className: "h-8 text-xs"
|
|
18738
|
+
}
|
|
18739
|
+
) }),
|
|
18740
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("td", { className: "p-1.5 align-top", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18741
|
+
Input,
|
|
18742
|
+
{
|
|
18743
|
+
value: row.emailTo,
|
|
18744
|
+
onChange: (e) => setEmailIntents(
|
|
18745
|
+
(rows) => rows.map(
|
|
18746
|
+
(r, i) => i === idx ? { ...r, emailTo: e.target.value } : r
|
|
18747
|
+
)
|
|
18748
|
+
),
|
|
18749
|
+
placeholder: "team@company.com",
|
|
18750
|
+
className: "h-8 text-xs"
|
|
18751
|
+
}
|
|
18752
|
+
) }),
|
|
18753
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("td", { className: "p-1.5 align-top", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18754
|
+
Button,
|
|
18755
|
+
{
|
|
18756
|
+
type: "button",
|
|
18757
|
+
size: "icon",
|
|
18758
|
+
variant: "ghost",
|
|
18759
|
+
className: "h-8 w-8 text-red-600",
|
|
18760
|
+
onClick: () => setEmailIntents((rows) => rows.filter((_, i) => i !== idx)),
|
|
18761
|
+
"aria-label": "Remove intent",
|
|
18762
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Trash2, { className: "h-3.5 w-3.5" })
|
|
18763
|
+
}
|
|
18764
|
+
) })
|
|
18765
|
+
] }, idx))
|
|
18123
18766
|
] })
|
|
18124
|
-
] })
|
|
18125
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18126
|
-
Button,
|
|
18127
|
-
{
|
|
18128
|
-
type: "button",
|
|
18129
|
-
size: "sm",
|
|
18130
|
-
className: "h-8",
|
|
18131
|
-
disabled: uploadingAttachedKbFile || uploadingAttachedKbLink || attachExistingDocId === "__none__",
|
|
18132
|
-
onClick: () => void handleAttachExistingToAttached(),
|
|
18133
|
-
children: uploadingAttachedKbLink ? /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
18134
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Loader2, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
18135
|
-
"Linking\u2026"
|
|
18136
|
-
] }) : "Attach"
|
|
18137
|
-
}
|
|
18138
|
-
)
|
|
18767
|
+
] }) })
|
|
18139
18768
|
] })
|
|
18140
|
-
] })
|
|
18141
|
-
|
|
18142
|
-
|
|
18143
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: `${settingsGroup}-botName`, className: "text-sm", children: "Widget title" }),
|
|
18144
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18145
|
-
Input,
|
|
18146
|
-
{
|
|
18147
|
-
id: `${settingsGroup}-botName`,
|
|
18148
|
-
value: botName,
|
|
18149
|
-
onChange: (e) => setBotName(e.target.value),
|
|
18150
|
-
placeholder: "e.g. Support Bot",
|
|
18151
|
-
className: "h-8 text-sm"
|
|
18152
|
-
}
|
|
18153
|
-
)
|
|
18154
|
-
] }),
|
|
18155
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-1", children: [
|
|
18156
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: `${settingsGroup}-iconImageUrl`, className: "text-sm", children: "Icon image URL" }),
|
|
18157
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18158
|
-
Input,
|
|
18159
|
-
{
|
|
18160
|
-
id: `${settingsGroup}-iconImageUrl`,
|
|
18161
|
-
value: iconImageUrl,
|
|
18162
|
-
onChange: (e) => setIconImageUrl(e.target.value),
|
|
18163
|
-
placeholder: "https://\u2026 or /images/chat-icon.png",
|
|
18164
|
-
className: "h-8 text-sm"
|
|
18165
|
-
}
|
|
18166
|
-
),
|
|
18167
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "PNG or image URL. Leave empty to use emoji below." })
|
|
18168
|
-
] }),
|
|
18169
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-1", children: [
|
|
18170
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: `${settingsGroup}-icon`, className: "text-sm", children: "Icon fallback (emoji)" }),
|
|
18171
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18172
|
-
Input,
|
|
18769
|
+
] }),
|
|
18770
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
|
|
18771
|
+
Button,
|
|
18173
18772
|
{
|
|
18174
|
-
|
|
18175
|
-
|
|
18176
|
-
|
|
18177
|
-
|
|
18178
|
-
className: "
|
|
18773
|
+
type: "button",
|
|
18774
|
+
size: "sm",
|
|
18775
|
+
onClick: () => void handleSaveLlmNotifyTab(),
|
|
18776
|
+
disabled: notifyEmailSaving || !emailPluginAvailable,
|
|
18777
|
+
className: "gap-1",
|
|
18778
|
+
children: [
|
|
18779
|
+
notifyEmailSaving ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Loader2, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Save, { className: "h-3.5 w-3.5" }),
|
|
18780
|
+
"Save"
|
|
18781
|
+
]
|
|
18179
18782
|
}
|
|
18180
18783
|
)
|
|
18181
|
-
] }),
|
|
18182
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex gap-4", children: [
|
|
18183
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-1", children: [
|
|
18184
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: `${settingsGroup}-iconBg`, className: "text-sm", children: "Icon background" }),
|
|
18185
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
18186
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18187
|
-
"input",
|
|
18188
|
-
{
|
|
18189
|
-
type: "color",
|
|
18190
|
-
id: `${settingsGroup}-iconBg`,
|
|
18191
|
-
value: iconBackgroundColor,
|
|
18192
|
-
onChange: (e) => setIconBackgroundColor(e.target.value),
|
|
18193
|
-
className: "h-8 w-10 cursor-pointer rounded border border-gray-300 dark:border-gray-600"
|
|
18194
|
-
}
|
|
18195
|
-
),
|
|
18196
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18197
|
-
Input,
|
|
18198
|
-
{
|
|
18199
|
-
value: iconBackgroundColor,
|
|
18200
|
-
onChange: (e) => setIconBackgroundColor(e.target.value),
|
|
18201
|
-
className: "h-8 w-24 text-sm font-mono"
|
|
18202
|
-
}
|
|
18203
|
-
)
|
|
18204
|
-
] })
|
|
18205
|
-
] }),
|
|
18206
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-1", children: [
|
|
18207
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Label3, { htmlFor: `${settingsGroup}-headerColor`, className: "text-sm", children: "Header color" }),
|
|
18208
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
18209
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18210
|
-
"input",
|
|
18211
|
-
{
|
|
18212
|
-
type: "color",
|
|
18213
|
-
id: `${settingsGroup}-headerColor`,
|
|
18214
|
-
value: headerColor,
|
|
18215
|
-
onChange: (e) => setHeaderColor(e.target.value),
|
|
18216
|
-
className: "h-8 w-10 cursor-pointer rounded border border-gray-300 dark:border-gray-600"
|
|
18217
|
-
}
|
|
18218
|
-
),
|
|
18219
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
18220
|
-
Input,
|
|
18221
|
-
{
|
|
18222
|
-
value: headerColor,
|
|
18223
|
-
onChange: (e) => setHeaderColor(e.target.value),
|
|
18224
|
-
className: "h-8 w-24 text-sm font-mono"
|
|
18225
|
-
}
|
|
18226
|
-
)
|
|
18227
|
-
] })
|
|
18228
|
-
] })
|
|
18229
18784
|
] })
|
|
18230
18785
|
] }),
|
|
18231
|
-
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(Button, { size: "sm", onClick: handleSave, disabled: saving, className: "gap-1", children: [
|
|
18786
|
+
chatMode !== "llm" && /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(Button, { size: "sm", onClick: handleSave, disabled: saving, className: "gap-1", children: [
|
|
18232
18787
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react39.Save, { className: "h-3.5 w-3.5" }),
|
|
18233
18788
|
"Save"
|
|
18234
18789
|
] })
|
|
@@ -19195,12 +19750,10 @@ function ProductEditPage({ productId }) {
|
|
|
19195
19750
|
setSaving(true);
|
|
19196
19751
|
try {
|
|
19197
19752
|
const activeCurrency = String(currency || "INR");
|
|
19198
|
-
console.log("DEBUG save:", { activeCurrency, price, compareAtPrice });
|
|
19199
19753
|
let saveRate = 1;
|
|
19200
19754
|
if (activeCurrency !== "INR") {
|
|
19201
19755
|
const displayRate = await fetchDisplayRate(activeCurrency);
|
|
19202
19756
|
saveRate = displayRate !== 0 && displayRate !== 1 ? 1 / displayRate : 1;
|
|
19203
|
-
console.log("DEBUG rate:", { displayRate, saveRate, priceInBase: Math.round(Number(price) * saveRate * 100) / 100 });
|
|
19204
19757
|
}
|
|
19205
19758
|
const priceInBase = Math.round(Number(price) * saveRate * 100) / 100;
|
|
19206
19759
|
const compareAtPriceInBase = compareAtPrice ? Math.round(Number(compareAtPrice) * saveRate * 100) / 100 : null;
|
|
@@ -21359,7 +21912,7 @@ function RuleTreeNode({ node, depth = 0 }) {
|
|
|
21359
21912
|
node.type && /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "rounded bg-white border border-gray-200 px-2 py-0.5 text-xs text-gray-700", children: RULE_TYPE_LABEL[node.type] ?? node.type }),
|
|
21360
21913
|
node.subType && /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "text-gray-400 text-xs", children: node.subType }),
|
|
21361
21914
|
node.comparisonOperator && /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "font-mono text-xs font-semibold text-gray-700", children: node.comparisonOperator }),
|
|
21362
|
-
node.value && Object.keys(node.value).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "font-mono text-xs bg-white border border-gray-200 rounded px-2 py-0.5 text-gray-800 break-all", children: Object.keys(node.value).length === 1 && "v" in node.value ? String(node.value.v) : JSON.stringify(node.value) })
|
|
21915
|
+
node.value && Object.keys(node.value).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "font-mono text-xs bg-white border border-gray-200 rounded px-2 py-0.5 text-gray-800 break-all", children: node.type === "quantity" && node.subType === "productId" && "v" in node.value ? `product #${node.value.productId} >= ${node.value.v}` : Object.keys(node.value).length === 1 && "v" in node.value ? String(node.value.v) : JSON.stringify(node.value) })
|
|
21363
21916
|
] }) }),
|
|
21364
21917
|
isGroup && open && (node.children ?? []).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("div", { className: "mt-2 pl-4 space-y-2", children: (node.children ?? []).map((child) => /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(RuleTreeNode, { node: child, depth: depth + 1 }, child.id)) })
|
|
21365
21918
|
] });
|
|
@@ -21619,10 +22172,10 @@ function conditionToRule(c) {
|
|
|
21619
22172
|
return { ...base, type: "minAmount", comparisonOperator: "gte", value: { v: c.amount ?? "0" } };
|
|
21620
22173
|
case "minQuantity":
|
|
21621
22174
|
return { ...base, type: "quantity", comparisonOperator: "gte", value: { v: c.quantity ?? "1" } };
|
|
21622
|
-
case "
|
|
21623
|
-
return { ...base, type: "
|
|
22175
|
+
case "productMinQuantity":
|
|
22176
|
+
return { ...base, type: "quantity", subType: "productId", comparisonOperator: "gte", value: { v: c.quantity ?? "1", productId: String(c.productId ?? "") } };
|
|
21624
22177
|
case "nthOrder":
|
|
21625
|
-
return { ...base, type: "order", subType: "nthOrder", comparisonOperator: "
|
|
22178
|
+
return { ...base, type: "order", subType: "nthOrder", comparisonOperator: "eq", value: { v: c.nthOrder ?? "1" } };
|
|
21626
22179
|
case "userType":
|
|
21627
22180
|
return { ...base, type: "user", subType: "userType", comparisonOperator: "eq", value: { v: c.userType ?? "" } };
|
|
21628
22181
|
case "paymentMethod":
|
|
@@ -21688,9 +22241,16 @@ function ruleTreeToFriendly(rules) {
|
|
|
21688
22241
|
case "minAmount":
|
|
21689
22242
|
return { id: rule._clientId ?? uid(), kind: "minAmount", amount: v };
|
|
21690
22243
|
case "quantity":
|
|
22244
|
+
if (rule.subType === "productId") {
|
|
22245
|
+
return {
|
|
22246
|
+
id: rule._clientId ?? uid(),
|
|
22247
|
+
kind: "productMinQuantity",
|
|
22248
|
+
quantity: v,
|
|
22249
|
+
productId: Number(rule.value?.productId) || null,
|
|
22250
|
+
productName: void 0
|
|
22251
|
+
};
|
|
22252
|
+
}
|
|
21691
22253
|
return { id: rule._clientId ?? uid(), kind: "minQuantity", quantity: v };
|
|
21692
|
-
case "product":
|
|
21693
|
-
return { id: rule._clientId ?? uid(), kind: "Product", productId: Number(v) || null, productName: void 0 };
|
|
21694
22254
|
case "order":
|
|
21695
22255
|
return { id: rule._clientId ?? uid(), kind: "nthOrder", nthOrder: v };
|
|
21696
22256
|
case "user":
|
|
@@ -22014,7 +22574,7 @@ function ConditionCard({
|
|
|
22014
22574
|
const iconMap = {
|
|
22015
22575
|
minAmount: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.DollarSign, { className: "h-3.5 w-3.5 text-blue-500" }),
|
|
22016
22576
|
minQuantity: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.Hash, { className: "h-3.5 w-3.5 text-purple-500" }),
|
|
22017
|
-
|
|
22577
|
+
productMinQuantity: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.Hash, { className: "h-3.5 w-3.5 text-green-600" }),
|
|
22018
22578
|
nthOrder: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.ShoppingCart, { className: "h-3.5 w-3.5 text-orange-500" }),
|
|
22019
22579
|
userType: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.User, { className: "h-3.5 w-3.5 text-pink-500" }),
|
|
22020
22580
|
paymentMethod: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.DollarSign, { className: "h-3.5 w-3.5 text-indigo-500" }),
|
|
@@ -22036,7 +22596,7 @@ function ConditionCard({
|
|
|
22036
22596
|
/* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(SelectContent, { children: [
|
|
22037
22597
|
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(SelectItem, { value: "minAmount", children: "Minimum order amount" }),
|
|
22038
22598
|
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(SelectItem, { value: "minQuantity", children: "Minimum quantity" }),
|
|
22039
|
-
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(SelectItem, { value: "
|
|
22599
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(SelectItem, { value: "productMinQuantity", children: "Product" }),
|
|
22040
22600
|
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(SelectItem, { value: "nthOrder", children: "Customer's Nth order" }),
|
|
22041
22601
|
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(SelectItem, { value: "userType", children: "User type" }),
|
|
22042
22602
|
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(SelectItem, { value: "paymentMethod", children: "Payment method" }),
|
|
@@ -22056,9 +22616,33 @@ function ConditionCard({
|
|
|
22056
22616
|
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "text-xs text-gray-500 shrink-0", children: "Qty \u2265" }),
|
|
22057
22617
|
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)("input", { type: "number", min: 1, step: "1", value: condition.quantity ?? "", onChange: (e) => onChange({ ...condition, quantity: e.target.value }), className: inputCls3, placeholder: "2" })
|
|
22058
22618
|
] }),
|
|
22059
|
-
condition.kind === "
|
|
22619
|
+
condition.kind === "productMinQuantity" && /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "space-y-2", children: [
|
|
22620
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
22621
|
+
ProductPicker,
|
|
22622
|
+
{
|
|
22623
|
+
value: condition.productId,
|
|
22624
|
+
label: condition.productName,
|
|
22625
|
+
onChange: (id, name) => onChange({ ...condition, productId: id, productName: name })
|
|
22626
|
+
}
|
|
22627
|
+
),
|
|
22628
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
22629
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "text-xs text-gray-500 shrink-0", children: "Minimum quantity of this product" }),
|
|
22630
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
22631
|
+
"input",
|
|
22632
|
+
{
|
|
22633
|
+
type: "number",
|
|
22634
|
+
min: 1,
|
|
22635
|
+
step: "1",
|
|
22636
|
+
value: condition.quantity ?? "",
|
|
22637
|
+
onChange: (e) => onChange({ ...condition, quantity: e.target.value }),
|
|
22638
|
+
className: inputCls3,
|
|
22639
|
+
placeholder: "2"
|
|
22640
|
+
}
|
|
22641
|
+
)
|
|
22642
|
+
] })
|
|
22643
|
+
] }),
|
|
22060
22644
|
condition.kind === "nthOrder" && /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
22061
|
-
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "text-xs text-gray-500 shrink-0", children: "Order number
|
|
22645
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "text-xs text-gray-500 shrink-0", children: "Order number =" }),
|
|
22062
22646
|
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)("input", { type: "number", min: 1, step: "1", value: condition.nthOrder ?? "", onChange: (e) => onChange({ ...condition, nthOrder: e.target.value }), className: inputCls3, placeholder: "2" }),
|
|
22063
22647
|
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "text-xs text-gray-400 shrink-0", children: "(e.g. 2 = 2nd+ order)" })
|
|
22064
22648
|
] }),
|
|
@@ -22128,7 +22712,7 @@ function DiscountConditionsBuilder({
|
|
|
22128
22712
|
const missingNameIds = [];
|
|
22129
22713
|
for (const g of groups) {
|
|
22130
22714
|
for (const c of g.conditions) {
|
|
22131
|
-
if (c.kind === "
|
|
22715
|
+
if (c.kind === "productMinQuantity" && c.productId && !c.productName)
|
|
22132
22716
|
missingNameIds.push({ type: "product", id: c.id, entityId: c.productId, groupId: g.id });
|
|
22133
22717
|
if (c.kind === "category" && c.categoryId && !c.categoryName)
|
|
22134
22718
|
missingNameIds.push({ type: "category", id: c.id, entityId: c.categoryId, groupId: g.id });
|