@serhii.olishevskyi/docs 1.2.12 → 1.2.14
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/dist/{UserPopoverComponent-K7CJNYYL.mjs → UserPopoverComponent-Z7YPC3AV.mjs} +1 -1
- package/dist/{chunk-FRDK4RQX.mjs → chunk-7WZQFX6U.mjs} +315 -136
- package/dist/index.d.mts +13 -8
- package/dist/index.d.ts +13 -8
- package/dist/index.js +263 -87
- package/dist/index.mjs +2 -4
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/UI/components/data.display/UserPopoverComponent.tsx
|
|
2
|
-
import { useEffect as
|
|
2
|
+
import { useEffect as useEffect10, useState as useState14 } from "react";
|
|
3
3
|
import {
|
|
4
4
|
Popover,
|
|
5
5
|
Box as Box4,
|
|
@@ -1070,7 +1070,7 @@ var useToast = () => {
|
|
|
1070
1070
|
};
|
|
1071
1071
|
|
|
1072
1072
|
// src/context/ConfirmationProvider.tsx
|
|
1073
|
-
import { createContext as createContext10, useContext as useContext10, useState as
|
|
1073
|
+
import { createContext as createContext10, useContext as useContext10, useState as useState10, useCallback as useCallback5 } from "react";
|
|
1074
1074
|
import {
|
|
1075
1075
|
Button as Button2,
|
|
1076
1076
|
Dialog as Dialog2,
|
|
@@ -1088,14 +1088,14 @@ import {
|
|
|
1088
1088
|
} from "@mui/icons-material";
|
|
1089
1089
|
|
|
1090
1090
|
// src/i18n/TranslateText.tsx
|
|
1091
|
-
import { useState as
|
|
1091
|
+
import { useState as useState9, useRef as useRef2, useEffect as useEffect7 } from "react";
|
|
1092
1092
|
import { useTranslation as useTranslation2 } from "react-i18next";
|
|
1093
1093
|
import { Box as Box2, Popper, Paper as Paper2, MenuList, MenuItem, ListItemIcon, ListItemText } from "@mui/material";
|
|
1094
1094
|
import TranslateIcon2 from "@mui/icons-material/Translate";
|
|
1095
1095
|
import LaunchIcon from "@mui/icons-material/Launch";
|
|
1096
1096
|
|
|
1097
1097
|
// src/i18n/TranslationDialog.tsx
|
|
1098
|
-
import { useEffect as
|
|
1098
|
+
import { useEffect as useEffect6, useState as useState8 } from "react";
|
|
1099
1099
|
import {
|
|
1100
1100
|
Dialog,
|
|
1101
1101
|
DialogTitle,
|
|
@@ -1109,15 +1109,17 @@ import {
|
|
|
1109
1109
|
IconButton,
|
|
1110
1110
|
Tooltip,
|
|
1111
1111
|
Paper,
|
|
1112
|
-
Alert as Alert2
|
|
1112
|
+
Alert as Alert2,
|
|
1113
|
+
ToggleButtonGroup,
|
|
1114
|
+
ToggleButton
|
|
1113
1115
|
} from "@mui/material";
|
|
1114
1116
|
import AutoFixHighIcon from "@mui/icons-material/AutoFixHigh";
|
|
1115
1117
|
import TranslateIcon from "@mui/icons-material/Translate";
|
|
1116
1118
|
import LightbulbIcon from "@mui/icons-material/Lightbulb";
|
|
1119
|
+
import SmartToyIcon from "@mui/icons-material/SmartToy";
|
|
1117
1120
|
|
|
1118
1121
|
// src/services/translation.service.ts
|
|
1119
1122
|
var translationService = {
|
|
1120
|
-
// 1. Принимаем client первым аргументом
|
|
1121
1123
|
incrementVersion: async (client, namespace, langCodes) => {
|
|
1122
1124
|
try {
|
|
1123
1125
|
const { data } = await client.from("translation_versions").select("version, lang_code").eq("namespace", namespace);
|
|
@@ -1138,36 +1140,103 @@ var translationService = {
|
|
|
1138
1140
|
return null;
|
|
1139
1141
|
}
|
|
1140
1142
|
},
|
|
1141
|
-
|
|
1143
|
+
/**
|
|
1144
|
+
* Универсальный метод перевода с поддержкой Gemini, OpenAI и автоматическим fallback
|
|
1145
|
+
*/
|
|
1146
|
+
translateSmart: async (client, aiGenerateFn, params, openAiApiKey) => {
|
|
1142
1147
|
const languagesToTranslate = params.targetLangs || (params.targetLang ? [params.targetLang] : []);
|
|
1143
1148
|
try {
|
|
1144
1149
|
const { data, error } = await client.functions.invoke("translate-smart", { body: params });
|
|
1145
1150
|
if (!error && data) return data;
|
|
1146
1151
|
} catch {
|
|
1147
|
-
console.warn("Edge Function translate-smart \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430, \
|
|
1152
|
+
console.warn("[translationService]: Edge Function translate-smart \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430, \u043F\u0435\u0440\u0435\u0445\u043E\u0434\u0438\u043C \u043A AIProvider...");
|
|
1148
1153
|
}
|
|
1149
|
-
|
|
1150
|
-
const prompt = `Translate the source text into language codes: ${JSON.stringify(languagesToTranslate)}.
|
|
1154
|
+
const prompt = `Translate the source text into language codes: ${JSON.stringify(languagesToTranslate)}.
|
|
1151
1155
|
Source Text: "${params.text}"
|
|
1152
1156
|
${params.contextHint ? `Context Hint: "${params.contextHint}"` : ""}`;
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1157
|
+
const systemInstruction = 'You are a professional translator. Respond STRICTLY with a valid JSON object mapping language code to translated text. Example: {"en": "Hello", "uk": "\u041F\u0440\u0438\u0432\u0456\u0442"}';
|
|
1158
|
+
if (aiGenerateFn) {
|
|
1159
|
+
try {
|
|
1160
|
+
const translations = await aiGenerateFn({
|
|
1161
|
+
prompt,
|
|
1162
|
+
systemInstruction,
|
|
1163
|
+
jsonMode: true,
|
|
1164
|
+
provider: params.provider,
|
|
1165
|
+
modelName: params.modelName
|
|
1166
|
+
});
|
|
1167
|
+
if (translations) {
|
|
1168
|
+
if (params.targetLang) {
|
|
1169
|
+
return { translatedText: translations[params.targetLang] || params.text };
|
|
1170
|
+
}
|
|
1171
|
+
return { translations };
|
|
1161
1172
|
}
|
|
1162
|
-
|
|
1173
|
+
} catch (err) {
|
|
1174
|
+
console.warn(`[translationService]: \u041E\u0448\u0438\u0431\u043A\u0430 \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u0418\u0418 (${params.provider || "default"}), \u043F\u0440\u043E\u0431\u0443\u0435\u043C \u0440\u0435\u0437\u0435\u0440\u0432\u043D\u044B\u0435 \u0432\u0430\u0440\u0438\u0430\u043D\u0442\u044B...`, err);
|
|
1175
|
+
}
|
|
1176
|
+
if (params.provider === "gemini" || !params.provider) {
|
|
1177
|
+
try {
|
|
1178
|
+
console.warn("[translationService]: \u041F\u0440\u043E\u0431\u0443\u0435\u043C \u043F\u0435\u0440\u0435\u043A\u043B\u044E\u0447\u0438\u0442\u044C\u0441\u044F \u043D\u0430 OpenAI fallback...");
|
|
1179
|
+
const translations = await aiGenerateFn({
|
|
1180
|
+
prompt,
|
|
1181
|
+
systemInstruction,
|
|
1182
|
+
jsonMode: true,
|
|
1183
|
+
provider: "openai"
|
|
1184
|
+
});
|
|
1185
|
+
if (translations) {
|
|
1186
|
+
if (params.targetLang) {
|
|
1187
|
+
return { translatedText: translations[params.targetLang] || params.text };
|
|
1188
|
+
}
|
|
1189
|
+
return { translations };
|
|
1190
|
+
}
|
|
1191
|
+
} catch (fallbackErr) {
|
|
1192
|
+
console.warn("[translationService]: Fallback OpenAI \u0447\u0435\u0440\u0435\u0437 AIProvider \u043D\u0435 \u0443\u0434\u0430\u043B\u0441\u044F", fallbackErr);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
if (openAiApiKey) {
|
|
1197
|
+
try {
|
|
1198
|
+
const response = await fetch("https://api.openai.com/v1/chat/completions", {
|
|
1199
|
+
method: "POST",
|
|
1200
|
+
headers: {
|
|
1201
|
+
"Content-Type": "application/json",
|
|
1202
|
+
Authorization: `Bearer ${openAiApiKey}`
|
|
1203
|
+
},
|
|
1204
|
+
body: JSON.stringify({
|
|
1205
|
+
model: params.modelName || "gpt-4o-mini",
|
|
1206
|
+
response_format: { type: "json_object" },
|
|
1207
|
+
messages: [
|
|
1208
|
+
{ role: "system", content: systemInstruction },
|
|
1209
|
+
{ role: "user", content: prompt }
|
|
1210
|
+
],
|
|
1211
|
+
temperature: 0.3
|
|
1212
|
+
})
|
|
1213
|
+
});
|
|
1214
|
+
if (response.ok) {
|
|
1215
|
+
const result = await response.json();
|
|
1216
|
+
const content = result.choices?.[0]?.message?.content;
|
|
1217
|
+
if (content) {
|
|
1218
|
+
const translations = JSON.parse(content);
|
|
1219
|
+
if (params.targetLang) {
|
|
1220
|
+
return { translatedText: translations[params.targetLang] || params.text };
|
|
1221
|
+
}
|
|
1222
|
+
return { translations };
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
} catch (err) {
|
|
1226
|
+
console.warn("[translationService]: Direct OpenAI API error, fallback to Google Translate", err);
|
|
1163
1227
|
}
|
|
1164
1228
|
}
|
|
1165
1229
|
if (params.targetLang) {
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1230
|
+
try {
|
|
1231
|
+
const fallbackUrl = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=${params.targetLang}&dt=t&q=${encodeURIComponent(params.text)}`;
|
|
1232
|
+
const res = await fetch(fallbackUrl);
|
|
1233
|
+
if (res.ok) {
|
|
1234
|
+
const data = await res.json();
|
|
1235
|
+
const translatedText = data[0].map((x) => x[0]).join("");
|
|
1236
|
+
return { translatedText };
|
|
1237
|
+
}
|
|
1238
|
+
} catch (err) {
|
|
1239
|
+
console.error("[translationService]: Google Translate fallback failed:", err);
|
|
1171
1240
|
}
|
|
1172
1241
|
}
|
|
1173
1242
|
throw new Error("All translation strategies failed.");
|
|
@@ -1175,38 +1244,96 @@ ${params.contextHint ? `Context Hint: "${params.contextHint}"` : ""}`;
|
|
|
1175
1244
|
};
|
|
1176
1245
|
|
|
1177
1246
|
// src/context/AIProvider.tsx
|
|
1178
|
-
import { createContext as createContext9, useContext as useContext9, useMemo as useMemo5 } from "react";
|
|
1247
|
+
import { createContext as createContext9, useContext as useContext9, useEffect as useEffect5, useMemo as useMemo5, useState as useState7, useCallback as useCallback4 } from "react";
|
|
1179
1248
|
import { GoogleGenAI } from "@google/genai";
|
|
1180
1249
|
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
1181
1250
|
var AIContext = createContext9(null);
|
|
1182
|
-
var AIProvider = ({
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1251
|
+
var AIProvider = ({ children, config: initialConfig = {} }) => {
|
|
1252
|
+
const supabase = useSupabase();
|
|
1253
|
+
const [dbConfig, setDbConfig] = useState7({});
|
|
1254
|
+
const loadSettingsFromDb = useCallback4(async () => {
|
|
1255
|
+
try {
|
|
1256
|
+
const { data } = await supabase.from("app_settings").select("key, value").in("key", [
|
|
1257
|
+
"ai_provider",
|
|
1258
|
+
"gemini_api_key",
|
|
1259
|
+
"gemini_model",
|
|
1260
|
+
"openai_api_key",
|
|
1261
|
+
"openai_model"
|
|
1262
|
+
]);
|
|
1263
|
+
if (!data) return;
|
|
1264
|
+
const parseVal = (val) => {
|
|
1265
|
+
if (typeof val === "string") return val;
|
|
1266
|
+
return JSON.stringify(val).replace(/^"|"$/g, "");
|
|
1267
|
+
};
|
|
1268
|
+
let provider;
|
|
1269
|
+
let geminiApiKey;
|
|
1270
|
+
let geminiModel;
|
|
1271
|
+
let openaiApiKey;
|
|
1272
|
+
let openaiModel;
|
|
1273
|
+
data.forEach((item) => {
|
|
1274
|
+
const val = parseVal(item.value);
|
|
1275
|
+
if (item.key === "ai_provider" && (val === "gemini" || val === "openai")) {
|
|
1276
|
+
provider = val;
|
|
1277
|
+
}
|
|
1278
|
+
if (item.key === "gemini_api_key") geminiApiKey = val;
|
|
1279
|
+
if (item.key === "gemini_model") geminiModel = val;
|
|
1280
|
+
if (item.key === "openai_api_key") openaiApiKey = val;
|
|
1281
|
+
if (item.key === "openai_model") openaiModel = val;
|
|
1282
|
+
});
|
|
1283
|
+
setDbConfig({
|
|
1284
|
+
provider,
|
|
1285
|
+
gemini: { apiKey: geminiApiKey, modelName: geminiModel },
|
|
1286
|
+
openai: { apiKey: openaiApiKey, modelName: openaiModel }
|
|
1287
|
+
});
|
|
1288
|
+
} catch (err) {
|
|
1289
|
+
console.warn("[AIProvider]: Failed to load AI settings from app_settings", err);
|
|
1290
|
+
}
|
|
1291
|
+
}, [supabase]);
|
|
1292
|
+
useEffect5(() => {
|
|
1293
|
+
loadSettingsFromDb();
|
|
1294
|
+
}, [loadSettingsFromDb]);
|
|
1295
|
+
const activeProvider = dbConfig.provider || initialConfig.provider || "gemini";
|
|
1296
|
+
const geminiConfig = {
|
|
1297
|
+
apiKey: dbConfig.gemini?.apiKey || initialConfig.gemini?.apiKey || "",
|
|
1298
|
+
//import.meta.env.VITE_GEMINI_API_KEY,
|
|
1299
|
+
modelName: dbConfig.gemini?.modelName || initialConfig.gemini?.modelName || "" || //import.meta.env.VITE_GEMINI_MODEL ||
|
|
1300
|
+
"gemini-2.5-flash"
|
|
1301
|
+
};
|
|
1302
|
+
const openaiConfig = {
|
|
1303
|
+
apiKey: dbConfig.openai?.apiKey || initialConfig.openai?.apiKey || "",
|
|
1304
|
+
//import.meta.env.VITE_OPENAI_API_KEY,
|
|
1305
|
+
modelName: dbConfig.openai?.modelName || initialConfig.openai?.modelName || "" || //import.meta.env.VITE_OPENAI_MODEL ||
|
|
1306
|
+
"gpt-4o-mini"
|
|
1307
|
+
};
|
|
1190
1308
|
const contextValue = useMemo5(() => {
|
|
1191
1309
|
return {
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1310
|
+
activeProvider,
|
|
1311
|
+
config: {
|
|
1312
|
+
provider: activeProvider,
|
|
1313
|
+
gemini: geminiConfig,
|
|
1314
|
+
openai: openaiConfig
|
|
1315
|
+
},
|
|
1316
|
+
reloadConfig: loadSettingsFromDb,
|
|
1195
1317
|
generate: async ({
|
|
1196
1318
|
prompt,
|
|
1197
1319
|
systemInstruction,
|
|
1198
1320
|
jsonMode = false,
|
|
1199
|
-
temperature
|
|
1321
|
+
temperature,
|
|
1322
|
+
provider: overrideProvider,
|
|
1323
|
+
modelName: overrideModelName
|
|
1200
1324
|
}) => {
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1325
|
+
const targetProvider = overrideProvider || activeProvider;
|
|
1326
|
+
if (targetProvider === "gemini") {
|
|
1327
|
+
const key = geminiConfig.apiKey;
|
|
1328
|
+
const model = overrideModelName || geminiConfig.modelName || "gemini-2.5-flash";
|
|
1329
|
+
if (!key) {
|
|
1330
|
+
console.warn("[AIProvider]: API Key \u0434\u043B\u044F Gemini \u043D\u0435 \u0437\u0430\u0434\u0430\u043D.");
|
|
1331
|
+
return null;
|
|
1332
|
+
}
|
|
1206
1333
|
try {
|
|
1207
|
-
const ai = new GoogleGenAI({ apiKey });
|
|
1334
|
+
const ai = new GoogleGenAI({ apiKey: key });
|
|
1208
1335
|
const response = await ai.models.generateContent({
|
|
1209
|
-
model
|
|
1336
|
+
model,
|
|
1210
1337
|
contents: prompt,
|
|
1211
1338
|
config: {
|
|
1212
1339
|
systemInstruction,
|
|
@@ -1225,7 +1352,13 @@ var AIProvider = ({
|
|
|
1225
1352
|
return null;
|
|
1226
1353
|
}
|
|
1227
1354
|
}
|
|
1228
|
-
if (
|
|
1355
|
+
if (targetProvider === "openai") {
|
|
1356
|
+
const key = openaiConfig.apiKey;
|
|
1357
|
+
const model = overrideModelName || openaiConfig.modelName || "gpt-4o-mini";
|
|
1358
|
+
if (!key) {
|
|
1359
|
+
console.warn("[AIProvider]: API Key \u0434\u043B\u044F OpenAI \u043D\u0435 \u0437\u0430\u0434\u0430\u043D.");
|
|
1360
|
+
return null;
|
|
1361
|
+
}
|
|
1229
1362
|
try {
|
|
1230
1363
|
const messages = [];
|
|
1231
1364
|
if (systemInstruction) {
|
|
@@ -1236,15 +1369,19 @@ var AIProvider = ({
|
|
|
1236
1369
|
method: "POST",
|
|
1237
1370
|
headers: {
|
|
1238
1371
|
"Content-Type": "application/json",
|
|
1239
|
-
Authorization: `Bearer ${
|
|
1372
|
+
Authorization: `Bearer ${key}`
|
|
1240
1373
|
},
|
|
1241
1374
|
body: JSON.stringify({
|
|
1242
|
-
model
|
|
1375
|
+
model,
|
|
1243
1376
|
messages,
|
|
1244
1377
|
temperature,
|
|
1245
1378
|
...jsonMode ? { response_format: { type: "json_object" } } : {}
|
|
1246
1379
|
})
|
|
1247
1380
|
});
|
|
1381
|
+
if (!res.ok) {
|
|
1382
|
+
const errData = await res.json().catch(() => ({}));
|
|
1383
|
+
throw new Error(`OpenAI API status ${res.status}: ${JSON.stringify(errData)}`);
|
|
1384
|
+
}
|
|
1248
1385
|
const data = await res.json();
|
|
1249
1386
|
const content = data.choices?.[0]?.message?.content?.trim() || "";
|
|
1250
1387
|
if (jsonMode) {
|
|
@@ -1259,7 +1396,14 @@ var AIProvider = ({
|
|
|
1259
1396
|
return null;
|
|
1260
1397
|
}
|
|
1261
1398
|
};
|
|
1262
|
-
}, [
|
|
1399
|
+
}, [
|
|
1400
|
+
activeProvider,
|
|
1401
|
+
geminiConfig.apiKey,
|
|
1402
|
+
geminiConfig.modelName,
|
|
1403
|
+
openaiConfig.apiKey,
|
|
1404
|
+
openaiConfig.modelName,
|
|
1405
|
+
loadSettingsFromDb
|
|
1406
|
+
]);
|
|
1263
1407
|
return /* @__PURE__ */ jsx9(AIContext.Provider, { value: contextValue, children });
|
|
1264
1408
|
};
|
|
1265
1409
|
var useAI = () => {
|
|
@@ -1280,16 +1424,17 @@ var TranslationDialog = ({
|
|
|
1280
1424
|
onSave
|
|
1281
1425
|
}) => {
|
|
1282
1426
|
const supabase = useSupabase();
|
|
1283
|
-
const { generate } = useAI();
|
|
1284
|
-
const [languages, setLanguages] =
|
|
1285
|
-
const [values, setValues] =
|
|
1286
|
-
const [contextHint, setContextHint] =
|
|
1287
|
-
const [
|
|
1288
|
-
const [
|
|
1289
|
-
const [
|
|
1290
|
-
const [
|
|
1291
|
-
const [
|
|
1292
|
-
|
|
1427
|
+
const { generate, activeProvider: defaultProvider } = useAI();
|
|
1428
|
+
const [languages, setLanguages] = useState8([]);
|
|
1429
|
+
const [values, setValues] = useState8({});
|
|
1430
|
+
const [contextHint, setContextHint] = useState8("");
|
|
1431
|
+
const [selectedProvider, setSelectedProvider] = useState8("auto");
|
|
1432
|
+
const [loading, setLoading] = useState8(false);
|
|
1433
|
+
const [saving, setSaving] = useState8(false);
|
|
1434
|
+
const [translatingCode, setTranslatingCode] = useState8(null);
|
|
1435
|
+
const [isTranslatingAll, setIsTranslatingAll] = useState8(false);
|
|
1436
|
+
const [error, setError] = useState8(null);
|
|
1437
|
+
useEffect6(() => {
|
|
1293
1438
|
if (!open) return;
|
|
1294
1439
|
const fetchData = async () => {
|
|
1295
1440
|
setLoading(true);
|
|
@@ -1320,6 +1465,7 @@ var TranslationDialog = ({
|
|
|
1320
1465
|
};
|
|
1321
1466
|
fetchData();
|
|
1322
1467
|
}, [open, translationKey, namespace]);
|
|
1468
|
+
const effectiveProvider = selectedProvider === "auto" ? void 0 : selectedProvider;
|
|
1323
1469
|
const handleAutoTranslate = async (e, targetLang) => {
|
|
1324
1470
|
e.preventDefault();
|
|
1325
1471
|
e.stopPropagation();
|
|
@@ -1329,13 +1475,14 @@ var TranslationDialog = ({
|
|
|
1329
1475
|
const res = await translationService.translateSmart(supabase, generate, {
|
|
1330
1476
|
text: translationKey,
|
|
1331
1477
|
targetLang,
|
|
1332
|
-
contextHint
|
|
1478
|
+
contextHint,
|
|
1479
|
+
provider: effectiveProvider
|
|
1333
1480
|
});
|
|
1334
1481
|
if (res?.translatedText) {
|
|
1335
1482
|
setValues((prev) => ({ ...prev, [targetLang]: res.translatedText }));
|
|
1336
1483
|
}
|
|
1337
1484
|
} catch (err) {
|
|
1338
|
-
console.
|
|
1485
|
+
console.error(err);
|
|
1339
1486
|
setError(`Failed to translate into ${targetLang}. ${err?.message || ""}`);
|
|
1340
1487
|
} finally {
|
|
1341
1488
|
setTranslatingCode(null);
|
|
@@ -1352,7 +1499,8 @@ var TranslationDialog = ({
|
|
|
1352
1499
|
const res = await translationService.translateSmart(supabase, generate, {
|
|
1353
1500
|
text: translationKey,
|
|
1354
1501
|
targetLangs,
|
|
1355
|
-
contextHint
|
|
1502
|
+
contextHint,
|
|
1503
|
+
provider: effectiveProvider
|
|
1356
1504
|
});
|
|
1357
1505
|
if (res?.translations) {
|
|
1358
1506
|
setValues((prev) => ({ ...prev, ...res.translations }));
|
|
@@ -1395,36 +1543,76 @@ var TranslationDialog = ({
|
|
|
1395
1543
|
onClick: (e) => e.stopPropagation(),
|
|
1396
1544
|
onMouseDown: (e) => e.stopPropagation(),
|
|
1397
1545
|
children: [
|
|
1398
|
-
/* @__PURE__ */ jsxs3(
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
/* @__PURE__ */ jsxs3(
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1546
|
+
/* @__PURE__ */ jsxs3(
|
|
1547
|
+
DialogTitle,
|
|
1548
|
+
{
|
|
1549
|
+
sx: { pb: 1, display: "flex", justifyContent: "space-between", alignItems: "flex-start" },
|
|
1550
|
+
children: [
|
|
1551
|
+
/* @__PURE__ */ jsxs3(Box, { children: [
|
|
1552
|
+
"Context Translation",
|
|
1553
|
+
/* @__PURE__ */ jsxs3(
|
|
1554
|
+
Typography,
|
|
1555
|
+
{
|
|
1556
|
+
component: "div",
|
|
1557
|
+
variant: "subtitle2",
|
|
1558
|
+
color: "text.secondary",
|
|
1559
|
+
sx: { wordBreak: "break-all", mt: 0.5 },
|
|
1560
|
+
children: [
|
|
1561
|
+
"Original: ",
|
|
1562
|
+
/* @__PURE__ */ jsxs3("strong", { children: [
|
|
1563
|
+
'"',
|
|
1564
|
+
translationKey,
|
|
1565
|
+
'"'
|
|
1566
|
+
] })
|
|
1567
|
+
]
|
|
1568
|
+
}
|
|
1569
|
+
)
|
|
1570
|
+
] }),
|
|
1571
|
+
!loading && /* @__PURE__ */ jsx10(
|
|
1572
|
+
Button,
|
|
1573
|
+
{
|
|
1574
|
+
type: "button",
|
|
1575
|
+
size: "small",
|
|
1576
|
+
variant: "outlined",
|
|
1577
|
+
color: "secondary",
|
|
1578
|
+
startIcon: isTranslatingAll ? /* @__PURE__ */ jsx10(CircularProgress, { size: 16, color: "inherit" }) : /* @__PURE__ */ jsx10(TranslateIcon, { fontSize: "small" }),
|
|
1579
|
+
onClick: handleTranslateAll,
|
|
1580
|
+
disabled: isBusy,
|
|
1581
|
+
sx: { flexShrink: 0, ml: 2, whiteSpace: "nowrap" },
|
|
1582
|
+
children: isTranslatingAll ? "Translating..." : "Translate All"
|
|
1583
|
+
}
|
|
1584
|
+
)
|
|
1585
|
+
]
|
|
1586
|
+
}
|
|
1587
|
+
),
|
|
1425
1588
|
/* @__PURE__ */ jsxs3(DialogContent, { dividers: true, sx: { pt: 2 }, children: [
|
|
1426
1589
|
error && /* @__PURE__ */ jsx10(Alert2, { severity: "error", onClose: () => setError(null), sx: { mb: 2 }, children: error }),
|
|
1427
1590
|
loading ? /* @__PURE__ */ jsx10(Box, { sx: { display: "flex", justifyContent: "center", py: 4 }, children: /* @__PURE__ */ jsx10(CircularProgress, {}) }) : /* @__PURE__ */ jsxs3(Box, { sx: { display: "flex", flexDirection: "column", gap: 2.5 }, children: [
|
|
1591
|
+
/* @__PURE__ */ jsxs3(Box, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
|
|
1592
|
+
/* @__PURE__ */ jsxs3(Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
|
|
1593
|
+
/* @__PURE__ */ jsx10(SmartToyIcon, { fontSize: "small", color: "action" }),
|
|
1594
|
+
/* @__PURE__ */ jsx10(Typography, { variant: "caption", sx: { fontWeight: 600, color: "text.secondary" }, children: "AI Engine:" })
|
|
1595
|
+
] }),
|
|
1596
|
+
/* @__PURE__ */ jsxs3(
|
|
1597
|
+
ToggleButtonGroup,
|
|
1598
|
+
{
|
|
1599
|
+
size: "small",
|
|
1600
|
+
value: selectedProvider,
|
|
1601
|
+
exclusive: true,
|
|
1602
|
+
onChange: (_, val) => val && setSelectedProvider(val),
|
|
1603
|
+
disabled: isBusy,
|
|
1604
|
+
children: [
|
|
1605
|
+
/* @__PURE__ */ jsxs3(ToggleButton, { value: "auto", sx: { px: 1.5, py: 0.2, fontSize: "0.75rem" }, children: [
|
|
1606
|
+
"Auto (",
|
|
1607
|
+
defaultProvider,
|
|
1608
|
+
")"
|
|
1609
|
+
] }),
|
|
1610
|
+
/* @__PURE__ */ jsx10(ToggleButton, { value: "gemini", sx: { px: 1.5, py: 0.2, fontSize: "0.75rem" }, children: "Gemini" }),
|
|
1611
|
+
/* @__PURE__ */ jsx10(ToggleButton, { value: "openai", sx: { px: 1.5, py: 0.2, fontSize: "0.75rem" }, children: "OpenAI" })
|
|
1612
|
+
]
|
|
1613
|
+
}
|
|
1614
|
+
)
|
|
1615
|
+
] }),
|
|
1428
1616
|
/* @__PURE__ */ jsxs3(Paper, { variant: "outlined", sx: { p: 2, bgcolor: "action.hover", borderRadius: 2 }, children: [
|
|
1429
1617
|
/* @__PURE__ */ jsxs3(Box, { sx: { display: "flex", alignItems: "center", gap: 1, mb: 1 }, children: [
|
|
1430
1618
|
/* @__PURE__ */ jsx10(LightbulbIcon, { color: "warning", fontSize: "small" }),
|
|
@@ -1473,7 +1661,7 @@ var TranslationDialog = ({
|
|
|
1473
1661
|
disabled: isBusy
|
|
1474
1662
|
}
|
|
1475
1663
|
),
|
|
1476
|
-
/* @__PURE__ */ jsx10(Tooltip, { title:
|
|
1664
|
+
/* @__PURE__ */ jsx10(Tooltip, { title: `Translate using ${selectedProvider === "auto" ? defaultProvider : selectedProvider}`, children: /* @__PURE__ */ jsx10("span", { children: /* @__PURE__ */ jsx10(
|
|
1477
1665
|
IconButton,
|
|
1478
1666
|
{
|
|
1479
1667
|
type: "button",
|
|
@@ -1488,16 +1676,7 @@ var TranslationDialog = ({
|
|
|
1488
1676
|
] }),
|
|
1489
1677
|
/* @__PURE__ */ jsxs3(DialogActions, { sx: { px: 3, py: 2 }, children: [
|
|
1490
1678
|
/* @__PURE__ */ jsx10(Button, { onClick: onClose, disabled: isBusy, color: "inherit", type: "button", children: "Cancel" }),
|
|
1491
|
-
/* @__PURE__ */ jsx10(
|
|
1492
|
-
Button,
|
|
1493
|
-
{
|
|
1494
|
-
onClick: handleSaveAll,
|
|
1495
|
-
variant: "contained",
|
|
1496
|
-
disabled: isBusy,
|
|
1497
|
-
type: "button",
|
|
1498
|
-
children: saving ? "Saving..." : "Save All"
|
|
1499
|
-
}
|
|
1500
|
-
)
|
|
1679
|
+
/* @__PURE__ */ jsx10(Button, { onClick: handleSaveAll, variant: "contained", disabled: isBusy, type: "button", children: saving ? "Saving..." : "Save All" })
|
|
1501
1680
|
] })
|
|
1502
1681
|
]
|
|
1503
1682
|
}
|
|
@@ -1515,11 +1694,11 @@ var TranslateText = ({
|
|
|
1515
1694
|
const { t, i18n: i18n2 } = useTranslation2(namespace);
|
|
1516
1695
|
const { isTranslationMode, canEdit } = useTranslationEdit();
|
|
1517
1696
|
const supabase = useSupabase();
|
|
1518
|
-
const [anchorEl, setAnchorEl] =
|
|
1519
|
-
const [isDialogOpen, setIsDialogOpen] =
|
|
1697
|
+
const [anchorEl, setAnchorEl] = useState9(null);
|
|
1698
|
+
const [isDialogOpen, setIsDialogOpen] = useState9(false);
|
|
1520
1699
|
const timeoutRef = useRef2(null);
|
|
1521
1700
|
const translatedValue = t(children, values);
|
|
1522
|
-
|
|
1701
|
+
useEffect7(() => {
|
|
1523
1702
|
return () => {
|
|
1524
1703
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
1525
1704
|
};
|
|
@@ -1685,10 +1864,10 @@ var SEVERITY_ICONS = {
|
|
|
1685
1864
|
success: /* @__PURE__ */ jsx12(SuccessIcon, { color: "success", sx: { fontSize: 40 } })
|
|
1686
1865
|
};
|
|
1687
1866
|
var ConfirmationProvider = ({ overrideNamespace, children }) => {
|
|
1688
|
-
const [open, setOpen] =
|
|
1689
|
-
const [options, setOptions] =
|
|
1690
|
-
const [resolver, setResolver] =
|
|
1691
|
-
const confirm =
|
|
1867
|
+
const [open, setOpen] = useState10(false);
|
|
1868
|
+
const [options, setOptions] = useState10(null);
|
|
1869
|
+
const [resolver, setResolver] = useState10(null);
|
|
1870
|
+
const confirm = useCallback5((opts) => {
|
|
1692
1871
|
setOptions(opts);
|
|
1693
1872
|
setOpen(true);
|
|
1694
1873
|
return new Promise((resolve) => {
|
|
@@ -1763,7 +1942,7 @@ var useConfirmation = () => {
|
|
|
1763
1942
|
};
|
|
1764
1943
|
|
|
1765
1944
|
// src/context/AppSettingsProvider.tsx
|
|
1766
|
-
import { createContext as createContext11, useContext as useContext11, useEffect as
|
|
1945
|
+
import { createContext as createContext11, useContext as useContext11, useEffect as useEffect8, useState as useState11, useCallback as useCallback6 } from "react";
|
|
1767
1946
|
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
1768
1947
|
var DEFAULT_SETTINGS = {
|
|
1769
1948
|
max_group_members: 100
|
|
@@ -1771,10 +1950,10 @@ var DEFAULT_SETTINGS = {
|
|
|
1771
1950
|
var AppSettingsContext = createContext11(void 0);
|
|
1772
1951
|
var AppSettingsProvider = ({ children }) => {
|
|
1773
1952
|
const supabase = useSupabase();
|
|
1774
|
-
const [settings, setSettings] =
|
|
1775
|
-
const [loading, setLoading] =
|
|
1776
|
-
const [error, setError] =
|
|
1777
|
-
const fetchSettings =
|
|
1953
|
+
const [settings, setSettings] = useState11(DEFAULT_SETTINGS);
|
|
1954
|
+
const [loading, setLoading] = useState11(true);
|
|
1955
|
+
const [error, setError] = useState11(null);
|
|
1956
|
+
const fetchSettings = useCallback6(async () => {
|
|
1778
1957
|
try {
|
|
1779
1958
|
setLoading(true);
|
|
1780
1959
|
setError(null);
|
|
@@ -1794,10 +1973,10 @@ var AppSettingsProvider = ({ children }) => {
|
|
|
1794
1973
|
setLoading(false);
|
|
1795
1974
|
}
|
|
1796
1975
|
}, []);
|
|
1797
|
-
|
|
1976
|
+
useEffect8(() => {
|
|
1798
1977
|
fetchSettings();
|
|
1799
1978
|
}, [fetchSettings]);
|
|
1800
|
-
const getSetting =
|
|
1979
|
+
const getSetting = useCallback6((key, defaultValue) => {
|
|
1801
1980
|
if (key in settings && settings[key] !== null && settings[key] !== void 0) {
|
|
1802
1981
|
return settings[key];
|
|
1803
1982
|
}
|
|
@@ -1826,7 +2005,7 @@ var useAppSettings = () => {
|
|
|
1826
2005
|
};
|
|
1827
2006
|
|
|
1828
2007
|
// src/context/UserSettingsProvider.tsx
|
|
1829
|
-
import { createContext as createContext12, useContext as useContext12, useEffect as
|
|
2008
|
+
import { createContext as createContext12, useContext as useContext12, useEffect as useEffect9, useState as useState12, useCallback as useCallback7 } from "react";
|
|
1830
2009
|
|
|
1831
2010
|
// src/types/user.types.ts
|
|
1832
2011
|
var defaultUserSettings = {
|
|
@@ -1843,14 +2022,14 @@ var UserSettingsProvider = ({ children }) => {
|
|
|
1843
2022
|
const supabase = useSupabase();
|
|
1844
2023
|
const { user, isAuthenticated, loading: isAuthLoading } = useAuth();
|
|
1845
2024
|
const userId = user?.id;
|
|
1846
|
-
const [settings, setSettings] =
|
|
2025
|
+
const [settings, setSettings] = useState12({
|
|
1847
2026
|
id: "",
|
|
1848
2027
|
...defaultUserSettings
|
|
1849
2028
|
});
|
|
1850
|
-
const [loading, setLoading] =
|
|
1851
|
-
const [error, setError] =
|
|
1852
|
-
const [activeChatUserId, setActiveChatUserId] =
|
|
1853
|
-
const fetchSettings =
|
|
2029
|
+
const [loading, setLoading] = useState12(true);
|
|
2030
|
+
const [error, setError] = useState12(null);
|
|
2031
|
+
const [activeChatUserId, setActiveChatUserId] = useState12(null);
|
|
2032
|
+
const fetchSettings = useCallback7(async () => {
|
|
1854
2033
|
if (isAuthLoading) return;
|
|
1855
2034
|
if (!isAuthenticated || !userId) {
|
|
1856
2035
|
setSettings({ id: "", ...defaultUserSettings });
|
|
@@ -1903,10 +2082,10 @@ var UserSettingsProvider = ({ children }) => {
|
|
|
1903
2082
|
setLoading(false);
|
|
1904
2083
|
}
|
|
1905
2084
|
}, [isAuthenticated, isAuthLoading, userId]);
|
|
1906
|
-
|
|
2085
|
+
useEffect9(() => {
|
|
1907
2086
|
fetchSettings();
|
|
1908
2087
|
}, [fetchSettings]);
|
|
1909
|
-
const toggleSidebar =
|
|
2088
|
+
const toggleSidebar = useCallback7(
|
|
1910
2089
|
async (open) => {
|
|
1911
2090
|
const isExplicitBoolean = typeof open === "boolean";
|
|
1912
2091
|
const nextState = isExplicitBoolean ? open : !settings.sidebar_open;
|
|
@@ -1922,7 +2101,7 @@ var UserSettingsProvider = ({ children }) => {
|
|
|
1922
2101
|
},
|
|
1923
2102
|
[settings.sidebar_open, userId]
|
|
1924
2103
|
);
|
|
1925
|
-
const toggleChat =
|
|
2104
|
+
const toggleChat = useCallback7(
|
|
1926
2105
|
async (open) => {
|
|
1927
2106
|
const isExplicitBoolean = typeof open === "boolean";
|
|
1928
2107
|
const nextState = isExplicitBoolean ? open : !settings.chat_open;
|
|
@@ -1938,7 +2117,7 @@ var UserSettingsProvider = ({ children }) => {
|
|
|
1938
2117
|
},
|
|
1939
2118
|
[settings.chat_open, userId]
|
|
1940
2119
|
);
|
|
1941
|
-
const openChatWithUser =
|
|
2120
|
+
const openChatWithUser = useCallback7(
|
|
1942
2121
|
async (targetUserId) => {
|
|
1943
2122
|
setActiveChatUserId(targetUserId);
|
|
1944
2123
|
if (!settings.chat_open) {
|
|
@@ -1947,7 +2126,7 @@ var UserSettingsProvider = ({ children }) => {
|
|
|
1947
2126
|
},
|
|
1948
2127
|
[settings.chat_open, toggleChat]
|
|
1949
2128
|
);
|
|
1950
|
-
const setLanguage =
|
|
2129
|
+
const setLanguage = useCallback7(
|
|
1951
2130
|
async (newLanguage) => {
|
|
1952
2131
|
const previousLanguage = settings.language;
|
|
1953
2132
|
setSettings((prev) => ({ ...prev, language: newLanguage }));
|
|
@@ -1962,7 +2141,7 @@ var UserSettingsProvider = ({ children }) => {
|
|
|
1962
2141
|
},
|
|
1963
2142
|
[settings.language, userId]
|
|
1964
2143
|
);
|
|
1965
|
-
const setThemeMode =
|
|
2144
|
+
const setThemeMode = useCallback7(
|
|
1966
2145
|
async (newMode) => {
|
|
1967
2146
|
const previousMode = settings.theme_mode;
|
|
1968
2147
|
setSettings((prev) => ({ ...prev, theme_mode: newMode }));
|
|
@@ -2137,7 +2316,7 @@ var UserRoleChipComponent = ({ overrideNamespace, role }) => {
|
|
|
2137
2316
|
};
|
|
2138
2317
|
|
|
2139
2318
|
// src/UI/components/buttons/CopyClipboardButtonComponent.tsx
|
|
2140
|
-
import { useState as
|
|
2319
|
+
import { useState as useState13 } from "react";
|
|
2141
2320
|
import { IconButton as IconButton3 } from "@mui/material";
|
|
2142
2321
|
import CheckIcon from "@mui/icons-material/Check";
|
|
2143
2322
|
import CopyIcon from "@mui/icons-material/ContentCopy";
|
|
@@ -2189,7 +2368,7 @@ var CopyClipboardButtonComponent = ({
|
|
|
2189
2368
|
sx,
|
|
2190
2369
|
...iconButtonProps
|
|
2191
2370
|
}) => {
|
|
2192
|
-
const [copied, setCopied] =
|
|
2371
|
+
const [copied, setCopied] = useState13(false);
|
|
2193
2372
|
const handleCopy = async (e) => {
|
|
2194
2373
|
e.stopPropagation();
|
|
2195
2374
|
if (!textToCopy) return;
|
|
@@ -2222,9 +2401,9 @@ var CopyClipboardButtonComponent = ({
|
|
|
2222
2401
|
// src/UI/components/data.display/UserPopoverComponent.tsx
|
|
2223
2402
|
import { Fragment as Fragment2, jsx as jsx20, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2224
2403
|
var useUserStatus = (supabase, userId, open) => {
|
|
2225
|
-
const [lastSeenAt, setLastSeenAt] =
|
|
2226
|
-
const [loading, setLoading] =
|
|
2227
|
-
|
|
2404
|
+
const [lastSeenAt, setLastSeenAt] = useState14(null);
|
|
2405
|
+
const [loading, setLoading] = useState14(true);
|
|
2406
|
+
useEffect10(() => {
|
|
2228
2407
|
if (!userId || !open) {
|
|
2229
2408
|
setLastSeenAt(null);
|
|
2230
2409
|
setLoading(false);
|
|
@@ -2273,13 +2452,13 @@ var UserPopoverComponent = ({
|
|
|
2273
2452
|
const { activeCompanyId, membership: currentMembership } = useAuth();
|
|
2274
2453
|
const { openChatWithUser } = useUserSettings();
|
|
2275
2454
|
const { formatDate, formatRelativeTime } = useLocalization();
|
|
2276
|
-
const [profileData, setProfileData] =
|
|
2277
|
-
const [membershipData, setMembershipData] =
|
|
2278
|
-
const [avatarUrl, setAvatarUrl] =
|
|
2279
|
-
const [coverUrl, setCoverUrl] =
|
|
2280
|
-
const [loading, setLoading] =
|
|
2455
|
+
const [profileData, setProfileData] = useState14(null);
|
|
2456
|
+
const [membershipData, setMembershipData] = useState14(null);
|
|
2457
|
+
const [avatarUrl, setAvatarUrl] = useState14(null);
|
|
2458
|
+
const [coverUrl, setCoverUrl] = useState14(null);
|
|
2459
|
+
const [loading, setLoading] = useState14(true);
|
|
2281
2460
|
const { lastSeenAt, isOnline } = useUserStatus(supabase, userId, open);
|
|
2282
|
-
|
|
2461
|
+
useEffect10(() => {
|
|
2283
2462
|
if (!open || !userId || !activeCompanyId) return;
|
|
2284
2463
|
let isMounted = true;
|
|
2285
2464
|
setLoading(true);
|