lula2 0.6.2 → 0.6.3-nightly.1
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 +34 -0
- package/dist/_app/immutable/chunks/B9HtV8_1.js +3 -0
- package/dist/_app/immutable/chunks/{CDqxzo-U.js → CxWn_Y-j.js} +1 -1
- package/dist/_app/immutable/chunks/{CrzX_dHQ.js → Dx7QZ9kE.js} +1 -1
- package/dist/_app/immutable/entry/{app.BU_7sxPU.js → app.DI-AYM-e.js} +2 -2
- package/dist/_app/immutable/entry/start.Qohy1rto.js +1 -0
- package/dist/_app/immutable/nodes/{0.XCpjvc2-.js → 0.c6B21yPf.js} +1 -1
- package/dist/_app/immutable/nodes/{1.C1uVrnSL.js → 1.BfZiPaZF.js} +1 -1
- package/dist/_app/immutable/nodes/{2.DsoxAUFC.js → 2.CSWUUbIh.js} +1 -1
- package/dist/_app/immutable/nodes/{3.C5xOlBQo.js → 3.hCMigK9L.js} +1 -1
- package/dist/_app/immutable/nodes/4.DQ3ddGz3.js +11 -0
- package/dist/_app/version.json +1 -1
- package/dist/cli/commands/crawl.js +151 -90
- package/dist/cli/commands/ui.js +92 -11
- package/dist/cli/server/index.js +92 -11
- package/dist/cli/server/server.js +92 -11
- package/dist/cli/server/serverState.js +35 -2
- package/dist/cli/server/spreadsheetRoutes.js +56 -8
- package/dist/cli/server/websocketServer.js +92 -11
- package/dist/index.html +6 -6
- package/dist/index.js +237 -102
- package/package.json +21 -22
- package/src/lib/components/setup/SpreadsheetImport.svelte +40 -15
- package/dist/_app/immutable/chunks/DtmRvgOL.js +0 -3
- package/dist/_app/immutable/entry/start.DtOV9FzL.js +0 -1
- package/dist/_app/immutable/nodes/4.CHRd9Q51.js +0 -11
|
@@ -283,6 +283,17 @@ var FileStore = class {
|
|
|
283
283
|
if (!existsSync2(this.controlsDir)) {
|
|
284
284
|
return [];
|
|
285
285
|
}
|
|
286
|
+
let controlOrder = null;
|
|
287
|
+
try {
|
|
288
|
+
const lulaConfigPath = join2(this.baseDir, "lula.yaml");
|
|
289
|
+
if (existsSync2(lulaConfigPath)) {
|
|
290
|
+
const content = readFileSync2(lulaConfigPath, "utf8");
|
|
291
|
+
const metadata = yaml2.load(content);
|
|
292
|
+
controlOrder = metadata?.controlOrder || null;
|
|
293
|
+
}
|
|
294
|
+
} catch (error) {
|
|
295
|
+
console.error("Failed to load lula.yaml for controlOrder:", error);
|
|
296
|
+
}
|
|
286
297
|
const entries = readdirSync(this.controlsDir);
|
|
287
298
|
const yamlFiles = entries.filter((file) => file.endsWith(".yaml"));
|
|
288
299
|
if (yamlFiles.length > 0) {
|
|
@@ -301,7 +312,11 @@ var FileStore = class {
|
|
|
301
312
|
}
|
|
302
313
|
});
|
|
303
314
|
const results2 = await Promise.all(promises);
|
|
304
|
-
|
|
315
|
+
const controls2 = results2.filter((c) => c !== null);
|
|
316
|
+
if (controlOrder && controlOrder.length > 0) {
|
|
317
|
+
return this.sortControlsByOrder(controls2, controlOrder);
|
|
318
|
+
}
|
|
319
|
+
return controls2;
|
|
305
320
|
}
|
|
306
321
|
const families = entries.filter((name) => {
|
|
307
322
|
const familyPath = join2(this.controlsDir, name);
|
|
@@ -324,7 +339,25 @@ var FileStore = class {
|
|
|
324
339
|
allPromises.push(...familyPromises);
|
|
325
340
|
}
|
|
326
341
|
const results = await Promise.all(allPromises);
|
|
327
|
-
|
|
342
|
+
const controls = results.filter((c) => c !== null);
|
|
343
|
+
if (controlOrder && controlOrder.length > 0) {
|
|
344
|
+
return this.sortControlsByOrder(controls, controlOrder);
|
|
345
|
+
}
|
|
346
|
+
return controls;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Sort controls based on the provided order array
|
|
350
|
+
*/
|
|
351
|
+
sortControlsByOrder(controls, controlOrder) {
|
|
352
|
+
const orderMap = /* @__PURE__ */ new Map();
|
|
353
|
+
controlOrder.forEach((controlId, index) => {
|
|
354
|
+
orderMap.set(controlId, index);
|
|
355
|
+
});
|
|
356
|
+
return controls.sort((a, b) => {
|
|
357
|
+
const aIndex = orderMap.get(a.id) ?? Number.MAX_SAFE_INTEGER;
|
|
358
|
+
const bIndex = orderMap.get(b.id) ?? Number.MAX_SAFE_INTEGER;
|
|
359
|
+
return aIndex - bIndex;
|
|
360
|
+
});
|
|
328
361
|
}
|
|
329
362
|
/**
|
|
330
363
|
* Load mappings from mappings directory
|
|
@@ -46,6 +46,8 @@ function getCurrentControlSetPath() {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
// cli/server/spreadsheetRoutes.ts
|
|
49
|
+
var MAX_HEADER_CANDIDATES = 5;
|
|
50
|
+
var PREVIEW_COLUMNS = 4;
|
|
49
51
|
var router = express.Router();
|
|
50
52
|
var upload = multer({
|
|
51
53
|
storage: multer.memoryStorage(),
|
|
@@ -132,7 +134,7 @@ function processImportParameters(reqBody) {
|
|
|
132
134
|
frontendFieldSchema
|
|
133
135
|
};
|
|
134
136
|
}
|
|
135
|
-
async function parseUploadedFile(file) {
|
|
137
|
+
async function parseUploadedFile(file, sheetName) {
|
|
136
138
|
const fileName = file.originalname || "";
|
|
137
139
|
const isCSV = fileName.toLowerCase().endsWith(".csv");
|
|
138
140
|
let rawData = [];
|
|
@@ -141,10 +143,13 @@ async function parseUploadedFile(file) {
|
|
|
141
143
|
rawData = parseCSV(csvContent);
|
|
142
144
|
} else {
|
|
143
145
|
const workbook = XLSX.read(file.buffer, { type: "buffer" });
|
|
144
|
-
const worksheetName = workbook.SheetNames[0];
|
|
146
|
+
const worksheetName = sheetName || workbook.SheetNames[0];
|
|
145
147
|
if (!worksheetName) {
|
|
146
148
|
throw new Error("No worksheet found in file");
|
|
147
149
|
}
|
|
150
|
+
if (sheetName && !workbook.SheetNames.includes(sheetName)) {
|
|
151
|
+
throw new Error(`Sheet "${sheetName}" not found in workbook`);
|
|
152
|
+
}
|
|
148
153
|
const worksheet = workbook.Sheets[worksheetName];
|
|
149
154
|
rawData = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
150
155
|
}
|
|
@@ -156,7 +161,8 @@ router.post("/import-spreadsheet", upload.single("file"), async (req, res) => {
|
|
|
156
161
|
return res.status(400).json({ error: "No file uploaded" });
|
|
157
162
|
}
|
|
158
163
|
const params = processImportParameters(req.body);
|
|
159
|
-
const
|
|
164
|
+
const sheetName = req.body.sheetName;
|
|
165
|
+
const rawData = await parseUploadedFile(req.file, sheetName);
|
|
160
166
|
const startRowIndex = parseInt(params.startRow) - 1;
|
|
161
167
|
if (rawData.length <= startRowIndex) {
|
|
162
168
|
return res.status(400).json({ error: "Start row exceeds sheet data" });
|
|
@@ -261,6 +267,7 @@ function processSpreadsheetData(rawData, headers, startRowIndex, params) {
|
|
|
261
267
|
continue;
|
|
262
268
|
}
|
|
263
269
|
const family = extractFamilyFromControlId(controlId);
|
|
270
|
+
control._originalRowIndex = i;
|
|
264
271
|
control.family = family;
|
|
265
272
|
controls.push(control);
|
|
266
273
|
if (!families.has(family)) {
|
|
@@ -383,6 +390,7 @@ async function createOutputStructure(processedData, fieldSchema, params) {
|
|
|
383
390
|
params.controlIdField,
|
|
384
391
|
params.namingConvention
|
|
385
392
|
);
|
|
393
|
+
const controlOrder = controls.sort((a, b) => (a._originalRowIndex || 0) - (b._originalRowIndex || 0)).map((control) => control[controlIdFieldNameClean]);
|
|
386
394
|
const controlSetData = {
|
|
387
395
|
name: params.controlSetName,
|
|
388
396
|
description: params.controlSetDescription,
|
|
@@ -390,12 +398,16 @@ async function createOutputStructure(processedData, fieldSchema, params) {
|
|
|
390
398
|
control_id_field: controlIdFieldNameClean,
|
|
391
399
|
controlCount: controls.length,
|
|
392
400
|
families: uniqueFamilies,
|
|
401
|
+
controlOrder,
|
|
393
402
|
fieldSchema
|
|
394
403
|
};
|
|
395
404
|
writeFileSync(join2(baseDir, "lula.yaml"), yaml4.dump(controlSetData));
|
|
396
405
|
const controlsDir = join2(baseDir, "controls");
|
|
397
406
|
const mappingsDir = join2(baseDir, "mappings");
|
|
398
|
-
families.
|
|
407
|
+
const sortedFamilies = Array.from(families.entries()).sort(
|
|
408
|
+
(a, b) => a[0].localeCompare(b[0])
|
|
409
|
+
);
|
|
410
|
+
sortedFamilies.forEach(([family, familyControls]) => {
|
|
399
411
|
const familyDir = join2(controlsDir, family);
|
|
400
412
|
const familyMappingsDir = join2(mappingsDir, family);
|
|
401
413
|
if (!existsSync(familyDir)) {
|
|
@@ -404,7 +416,10 @@ async function createOutputStructure(processedData, fieldSchema, params) {
|
|
|
404
416
|
if (!existsSync(familyMappingsDir)) {
|
|
405
417
|
mkdirSync(familyMappingsDir, { recursive: true });
|
|
406
418
|
}
|
|
407
|
-
familyControls.
|
|
419
|
+
const sortedFamilyControls = familyControls.sort(
|
|
420
|
+
(a, b) => (a._originalRowIndex || 0) - (b._originalRowIndex || 0)
|
|
421
|
+
);
|
|
422
|
+
sortedFamilyControls.forEach((control) => {
|
|
408
423
|
const controlId = control[controlIdFieldNameClean];
|
|
409
424
|
if (!controlId) {
|
|
410
425
|
console.error("Missing control ID for control:", control);
|
|
@@ -426,7 +441,7 @@ async function createOutputStructure(processedData, fieldSchema, params) {
|
|
|
426
441
|
filteredControl.family = control.family;
|
|
427
442
|
}
|
|
428
443
|
Object.keys(control).forEach((fieldName) => {
|
|
429
|
-
if (fieldName === "family") return;
|
|
444
|
+
if (fieldName === "family" || fieldName === "_originalRowIndex") return;
|
|
430
445
|
if (params.justificationFields.includes(fieldName) && control[fieldName] !== void 0 && control[fieldName] !== null) {
|
|
431
446
|
justificationContents.push(control[fieldName]);
|
|
432
447
|
}
|
|
@@ -969,9 +984,9 @@ router.post("/parse-excel", upload.single("file"), async (req, res) => {
|
|
|
969
984
|
const worksheet = workbook.Sheets[worksheetName];
|
|
970
985
|
rows = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
971
986
|
}
|
|
972
|
-
const headerCandidates = rows.slice(0,
|
|
987
|
+
const headerCandidates = rows.slice(0, MAX_HEADER_CANDIDATES).map((row, index) => ({
|
|
973
988
|
row: index + 1,
|
|
974
|
-
preview: row.slice(0,
|
|
989
|
+
preview: row.slice(0, PREVIEW_COLUMNS).filter((v) => v !== null).filter((v) => v !== void 0).join(", ") + (row.length > 4 ? ", ..." : "")
|
|
975
990
|
}));
|
|
976
991
|
res.json({
|
|
977
992
|
sheets,
|
|
@@ -1028,6 +1043,39 @@ router.post("/parse-excel-sheet", upload.single("file"), async (req, res) => {
|
|
|
1028
1043
|
res.status(500).json({ error: "Failed to parse Excel sheet" });
|
|
1029
1044
|
}
|
|
1030
1045
|
});
|
|
1046
|
+
router.post("/parse-excel-sheet-previews", upload.single("file"), async (req, res) => {
|
|
1047
|
+
try {
|
|
1048
|
+
const { sheetName } = req.body;
|
|
1049
|
+
if (!req.file) {
|
|
1050
|
+
return res.status(400).json({ error: "No file uploaded" });
|
|
1051
|
+
}
|
|
1052
|
+
const fileName = req.file.originalname || "";
|
|
1053
|
+
const isCSV = fileName.toLowerCase().endsWith(".csv");
|
|
1054
|
+
let rows = [];
|
|
1055
|
+
if (isCSV) {
|
|
1056
|
+
const csvContent = req.file.buffer.toString("utf-8");
|
|
1057
|
+
rows = parseCSV(csvContent);
|
|
1058
|
+
} else {
|
|
1059
|
+
const workbook = XLSX.read(req.file.buffer, { type: "buffer" });
|
|
1060
|
+
if (!workbook.SheetNames.includes(sheetName)) {
|
|
1061
|
+
return res.status(400).json({ error: `Sheet "${sheetName}" not found` });
|
|
1062
|
+
}
|
|
1063
|
+
const worksheet = workbook.Sheets[sheetName];
|
|
1064
|
+
rows = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
1065
|
+
}
|
|
1066
|
+
const headerCandidates = rows.slice(0, MAX_HEADER_CANDIDATES).map((row, index) => ({
|
|
1067
|
+
row: index + 1,
|
|
1068
|
+
preview: row.slice(0, PREVIEW_COLUMNS).filter((v) => v !== null).filter((v) => v !== void 0).join(", ") + (row.length > 4 ? ", ..." : "")
|
|
1069
|
+
}));
|
|
1070
|
+
res.json({
|
|
1071
|
+
rowPreviews: headerCandidates,
|
|
1072
|
+
totalRows: rows.length
|
|
1073
|
+
});
|
|
1074
|
+
} catch (error) {
|
|
1075
|
+
console.error("Error getting sheet previews:", error);
|
|
1076
|
+
res.status(500).json({ error: "Failed to get sheet previews" });
|
|
1077
|
+
}
|
|
1078
|
+
});
|
|
1031
1079
|
var spreadsheetRoutes_default = router;
|
|
1032
1080
|
export {
|
|
1033
1081
|
applyNamingConvention,
|
|
@@ -309,6 +309,17 @@ var init_fileStore = __esm({
|
|
|
309
309
|
if (!existsSync2(this.controlsDir)) {
|
|
310
310
|
return [];
|
|
311
311
|
}
|
|
312
|
+
let controlOrder = null;
|
|
313
|
+
try {
|
|
314
|
+
const lulaConfigPath = join2(this.baseDir, "lula.yaml");
|
|
315
|
+
if (existsSync2(lulaConfigPath)) {
|
|
316
|
+
const content = readFileSync2(lulaConfigPath, "utf8");
|
|
317
|
+
const metadata = yaml2.load(content);
|
|
318
|
+
controlOrder = metadata?.controlOrder || null;
|
|
319
|
+
}
|
|
320
|
+
} catch (error) {
|
|
321
|
+
console.error("Failed to load lula.yaml for controlOrder:", error);
|
|
322
|
+
}
|
|
312
323
|
const entries = readdirSync(this.controlsDir);
|
|
313
324
|
const yamlFiles = entries.filter((file) => file.endsWith(".yaml"));
|
|
314
325
|
if (yamlFiles.length > 0) {
|
|
@@ -327,7 +338,11 @@ var init_fileStore = __esm({
|
|
|
327
338
|
}
|
|
328
339
|
});
|
|
329
340
|
const results2 = await Promise.all(promises);
|
|
330
|
-
|
|
341
|
+
const controls2 = results2.filter((c) => c !== null);
|
|
342
|
+
if (controlOrder && controlOrder.length > 0) {
|
|
343
|
+
return this.sortControlsByOrder(controls2, controlOrder);
|
|
344
|
+
}
|
|
345
|
+
return controls2;
|
|
331
346
|
}
|
|
332
347
|
const families = entries.filter((name) => {
|
|
333
348
|
const familyPath = join2(this.controlsDir, name);
|
|
@@ -350,7 +365,25 @@ var init_fileStore = __esm({
|
|
|
350
365
|
allPromises.push(...familyPromises);
|
|
351
366
|
}
|
|
352
367
|
const results = await Promise.all(allPromises);
|
|
353
|
-
|
|
368
|
+
const controls = results.filter((c) => c !== null);
|
|
369
|
+
if (controlOrder && controlOrder.length > 0) {
|
|
370
|
+
return this.sortControlsByOrder(controls, controlOrder);
|
|
371
|
+
}
|
|
372
|
+
return controls;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Sort controls based on the provided order array
|
|
376
|
+
*/
|
|
377
|
+
sortControlsByOrder(controls, controlOrder) {
|
|
378
|
+
const orderMap = /* @__PURE__ */ new Map();
|
|
379
|
+
controlOrder.forEach((controlId, index) => {
|
|
380
|
+
orderMap.set(controlId, index);
|
|
381
|
+
});
|
|
382
|
+
return controls.sort((a, b) => {
|
|
383
|
+
const aIndex = orderMap.get(a.id) ?? Number.MAX_SAFE_INTEGER;
|
|
384
|
+
const bIndex = orderMap.get(b.id) ?? Number.MAX_SAFE_INTEGER;
|
|
385
|
+
return aIndex - bIndex;
|
|
386
|
+
});
|
|
354
387
|
}
|
|
355
388
|
/**
|
|
356
389
|
* Load mappings from mappings directory
|
|
@@ -1377,7 +1410,7 @@ function processImportParameters(reqBody) {
|
|
|
1377
1410
|
frontendFieldSchema
|
|
1378
1411
|
};
|
|
1379
1412
|
}
|
|
1380
|
-
async function parseUploadedFile(file) {
|
|
1413
|
+
async function parseUploadedFile(file, sheetName) {
|
|
1381
1414
|
const fileName = file.originalname || "";
|
|
1382
1415
|
const isCSV = fileName.toLowerCase().endsWith(".csv");
|
|
1383
1416
|
let rawData = [];
|
|
@@ -1386,10 +1419,13 @@ async function parseUploadedFile(file) {
|
|
|
1386
1419
|
rawData = parseCSV(csvContent);
|
|
1387
1420
|
} else {
|
|
1388
1421
|
const workbook = XLSX.read(file.buffer, { type: "buffer" });
|
|
1389
|
-
const worksheetName = workbook.SheetNames[0];
|
|
1422
|
+
const worksheetName = sheetName || workbook.SheetNames[0];
|
|
1390
1423
|
if (!worksheetName) {
|
|
1391
1424
|
throw new Error("No worksheet found in file");
|
|
1392
1425
|
}
|
|
1426
|
+
if (sheetName && !workbook.SheetNames.includes(sheetName)) {
|
|
1427
|
+
throw new Error(`Sheet "${sheetName}" not found in workbook`);
|
|
1428
|
+
}
|
|
1393
1429
|
const worksheet = workbook.Sheets[worksheetName];
|
|
1394
1430
|
rawData = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
1395
1431
|
}
|
|
@@ -1467,6 +1503,7 @@ function processSpreadsheetData(rawData, headers, startRowIndex, params) {
|
|
|
1467
1503
|
continue;
|
|
1468
1504
|
}
|
|
1469
1505
|
const family = extractFamilyFromControlId(controlId);
|
|
1506
|
+
control._originalRowIndex = i;
|
|
1470
1507
|
control.family = family;
|
|
1471
1508
|
controls.push(control);
|
|
1472
1509
|
if (!families.has(family)) {
|
|
@@ -1589,6 +1626,7 @@ async function createOutputStructure(processedData, fieldSchema, params) {
|
|
|
1589
1626
|
params.controlIdField,
|
|
1590
1627
|
params.namingConvention
|
|
1591
1628
|
);
|
|
1629
|
+
const controlOrder = controls.sort((a, b) => (a._originalRowIndex || 0) - (b._originalRowIndex || 0)).map((control) => control[controlIdFieldNameClean]);
|
|
1592
1630
|
const controlSetData = {
|
|
1593
1631
|
name: params.controlSetName,
|
|
1594
1632
|
description: params.controlSetDescription,
|
|
@@ -1596,12 +1634,16 @@ async function createOutputStructure(processedData, fieldSchema, params) {
|
|
|
1596
1634
|
control_id_field: controlIdFieldNameClean,
|
|
1597
1635
|
controlCount: controls.length,
|
|
1598
1636
|
families: uniqueFamilies,
|
|
1637
|
+
controlOrder,
|
|
1599
1638
|
fieldSchema
|
|
1600
1639
|
};
|
|
1601
1640
|
writeFileSync2(join4(baseDir, "lula.yaml"), yaml4.dump(controlSetData));
|
|
1602
1641
|
const controlsDir = join4(baseDir, "controls");
|
|
1603
1642
|
const mappingsDir = join4(baseDir, "mappings");
|
|
1604
|
-
families.
|
|
1643
|
+
const sortedFamilies = Array.from(families.entries()).sort(
|
|
1644
|
+
(a, b) => a[0].localeCompare(b[0])
|
|
1645
|
+
);
|
|
1646
|
+
sortedFamilies.forEach(([family, familyControls]) => {
|
|
1605
1647
|
const familyDir = join4(controlsDir, family);
|
|
1606
1648
|
const familyMappingsDir = join4(mappingsDir, family);
|
|
1607
1649
|
if (!existsSync3(familyDir)) {
|
|
@@ -1610,7 +1652,10 @@ async function createOutputStructure(processedData, fieldSchema, params) {
|
|
|
1610
1652
|
if (!existsSync3(familyMappingsDir)) {
|
|
1611
1653
|
mkdirSync2(familyMappingsDir, { recursive: true });
|
|
1612
1654
|
}
|
|
1613
|
-
familyControls.
|
|
1655
|
+
const sortedFamilyControls = familyControls.sort(
|
|
1656
|
+
(a, b) => (a._originalRowIndex || 0) - (b._originalRowIndex || 0)
|
|
1657
|
+
);
|
|
1658
|
+
sortedFamilyControls.forEach((control) => {
|
|
1614
1659
|
const controlId = control[controlIdFieldNameClean];
|
|
1615
1660
|
if (!controlId) {
|
|
1616
1661
|
console.error("Missing control ID for control:", control);
|
|
@@ -1632,7 +1677,7 @@ async function createOutputStructure(processedData, fieldSchema, params) {
|
|
|
1632
1677
|
filteredControl.family = control.family;
|
|
1633
1678
|
}
|
|
1634
1679
|
Object.keys(control).forEach((fieldName) => {
|
|
1635
|
-
if (fieldName === "family") return;
|
|
1680
|
+
if (fieldName === "family" || fieldName === "_originalRowIndex") return;
|
|
1636
1681
|
if (params.justificationFields.includes(fieldName) && control[fieldName] !== void 0 && control[fieldName] !== null) {
|
|
1637
1682
|
justificationContents.push(control[fieldName]);
|
|
1638
1683
|
}
|
|
@@ -1996,12 +2041,14 @@ function exportAsJSON(controls, metadata, res) {
|
|
|
1996
2041
|
res.setHeader("Content-Disposition", `attachment; filename="${fileName}"`);
|
|
1997
2042
|
res.json(exportData);
|
|
1998
2043
|
}
|
|
1999
|
-
var router, upload, spreadsheetRoutes_default;
|
|
2044
|
+
var MAX_HEADER_CANDIDATES, PREVIEW_COLUMNS, router, upload, spreadsheetRoutes_default;
|
|
2000
2045
|
var init_spreadsheetRoutes = __esm({
|
|
2001
2046
|
"cli/server/spreadsheetRoutes.ts"() {
|
|
2002
2047
|
"use strict";
|
|
2003
2048
|
init_debug();
|
|
2004
2049
|
init_serverState();
|
|
2050
|
+
MAX_HEADER_CANDIDATES = 5;
|
|
2051
|
+
PREVIEW_COLUMNS = 4;
|
|
2005
2052
|
router = express.Router();
|
|
2006
2053
|
upload = multer({
|
|
2007
2054
|
storage: multer.memoryStorage(),
|
|
@@ -2014,7 +2061,8 @@ var init_spreadsheetRoutes = __esm({
|
|
|
2014
2061
|
return res.status(400).json({ error: "No file uploaded" });
|
|
2015
2062
|
}
|
|
2016
2063
|
const params = processImportParameters(req.body);
|
|
2017
|
-
const
|
|
2064
|
+
const sheetName = req.body.sheetName;
|
|
2065
|
+
const rawData = await parseUploadedFile(req.file, sheetName);
|
|
2018
2066
|
const startRowIndex = parseInt(params.startRow) - 1;
|
|
2019
2067
|
if (rawData.length <= startRowIndex) {
|
|
2020
2068
|
return res.status(400).json({ error: "Start row exceeds sheet data" });
|
|
@@ -2226,9 +2274,9 @@ var init_spreadsheetRoutes = __esm({
|
|
|
2226
2274
|
const worksheet = workbook.Sheets[worksheetName];
|
|
2227
2275
|
rows = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
2228
2276
|
}
|
|
2229
|
-
const headerCandidates = rows.slice(0,
|
|
2277
|
+
const headerCandidates = rows.slice(0, MAX_HEADER_CANDIDATES).map((row, index) => ({
|
|
2230
2278
|
row: index + 1,
|
|
2231
|
-
preview: row.slice(0,
|
|
2279
|
+
preview: row.slice(0, PREVIEW_COLUMNS).filter((v) => v !== null).filter((v) => v !== void 0).join(", ") + (row.length > 4 ? ", ..." : "")
|
|
2232
2280
|
}));
|
|
2233
2281
|
res.json({
|
|
2234
2282
|
sheets,
|
|
@@ -2285,6 +2333,39 @@ var init_spreadsheetRoutes = __esm({
|
|
|
2285
2333
|
res.status(500).json({ error: "Failed to parse Excel sheet" });
|
|
2286
2334
|
}
|
|
2287
2335
|
});
|
|
2336
|
+
router.post("/parse-excel-sheet-previews", upload.single("file"), async (req, res) => {
|
|
2337
|
+
try {
|
|
2338
|
+
const { sheetName } = req.body;
|
|
2339
|
+
if (!req.file) {
|
|
2340
|
+
return res.status(400).json({ error: "No file uploaded" });
|
|
2341
|
+
}
|
|
2342
|
+
const fileName = req.file.originalname || "";
|
|
2343
|
+
const isCSV = fileName.toLowerCase().endsWith(".csv");
|
|
2344
|
+
let rows = [];
|
|
2345
|
+
if (isCSV) {
|
|
2346
|
+
const csvContent = req.file.buffer.toString("utf-8");
|
|
2347
|
+
rows = parseCSV(csvContent);
|
|
2348
|
+
} else {
|
|
2349
|
+
const workbook = XLSX.read(req.file.buffer, { type: "buffer" });
|
|
2350
|
+
if (!workbook.SheetNames.includes(sheetName)) {
|
|
2351
|
+
return res.status(400).json({ error: `Sheet "${sheetName}" not found` });
|
|
2352
|
+
}
|
|
2353
|
+
const worksheet = workbook.Sheets[sheetName];
|
|
2354
|
+
rows = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
2355
|
+
}
|
|
2356
|
+
const headerCandidates = rows.slice(0, MAX_HEADER_CANDIDATES).map((row, index) => ({
|
|
2357
|
+
row: index + 1,
|
|
2358
|
+
preview: row.slice(0, PREVIEW_COLUMNS).filter((v) => v !== null).filter((v) => v !== void 0).join(", ") + (row.length > 4 ? ", ..." : "")
|
|
2359
|
+
}));
|
|
2360
|
+
res.json({
|
|
2361
|
+
rowPreviews: headerCandidates,
|
|
2362
|
+
totalRows: rows.length
|
|
2363
|
+
});
|
|
2364
|
+
} catch (error) {
|
|
2365
|
+
console.error("Error getting sheet previews:", error);
|
|
2366
|
+
res.status(500).json({ error: "Failed to get sheet previews" });
|
|
2367
|
+
}
|
|
2368
|
+
});
|
|
2288
2369
|
spreadsheetRoutes_default = router;
|
|
2289
2370
|
}
|
|
2290
2371
|
});
|
package/dist/index.html
CHANGED
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
<link rel="icon" href="/lula.png" />
|
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
8
8
|
|
|
9
|
-
<link rel="modulepreload" href="/_app/immutable/entry/start.
|
|
10
|
-
<link rel="modulepreload" href="/_app/immutable/chunks/
|
|
9
|
+
<link rel="modulepreload" href="/_app/immutable/entry/start.Qohy1rto.js">
|
|
10
|
+
<link rel="modulepreload" href="/_app/immutable/chunks/B9HtV8_1.js">
|
|
11
11
|
<link rel="modulepreload" href="/_app/immutable/chunks/DTWPdvjs.js">
|
|
12
|
-
<link rel="modulepreload" href="/_app/immutable/entry/app.
|
|
12
|
+
<link rel="modulepreload" href="/_app/immutable/entry/app.DI-AYM-e.js">
|
|
13
13
|
<link rel="modulepreload" href="/_app/immutable/chunks/DsnmJJEf.js">
|
|
14
14
|
<link rel="modulepreload" href="/_app/immutable/chunks/BXUi170M.js">
|
|
15
15
|
<link rel="modulepreload" href="/_app/immutable/chunks/WlyXjfrM.js">
|
|
@@ -19,15 +19,15 @@
|
|
|
19
19
|
<div style="display: contents">
|
|
20
20
|
<script>
|
|
21
21
|
{
|
|
22
|
-
|
|
22
|
+
__sveltekit_157sdlo = {
|
|
23
23
|
base: ""
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
const element = document.currentScript.parentElement;
|
|
27
27
|
|
|
28
28
|
Promise.all([
|
|
29
|
-
import("/_app/immutable/entry/start.
|
|
30
|
-
import("/_app/immutable/entry/app.
|
|
29
|
+
import("/_app/immutable/entry/start.Qohy1rto.js"),
|
|
30
|
+
import("/_app/immutable/entry/app.DI-AYM-e.js")
|
|
31
31
|
]).then(([kit, app]) => {
|
|
32
32
|
kit.start(app, element);
|
|
33
33
|
});
|