lula2 0.6.2 → 0.6.3-nightly.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_app/immutable/chunks/{CrzX_dHQ.js → CnwkJbO2.js} +1 -1
- package/dist/_app/immutable/chunks/{CDqxzo-U.js → MTDiNHJy.js} +1 -1
- package/dist/_app/immutable/chunks/rc9CiIba.js +3 -0
- package/dist/_app/immutable/entry/{app.BU_7sxPU.js → app.C9fkwjMz.js} +2 -2
- package/dist/_app/immutable/entry/start.D2hMBZNv.js +1 -0
- package/dist/_app/immutable/nodes/{0.XCpjvc2-.js → 0.DTEvfwsS.js} +1 -1
- package/dist/_app/immutable/nodes/{1.C1uVrnSL.js → 1.CVMum2jU.js} +1 -1
- package/dist/_app/immutable/nodes/{2.DsoxAUFC.js → 2.D-DlyZaW.js} +1 -1
- package/dist/_app/immutable/nodes/{3.C5xOlBQo.js → 3.CEMIejLc.js} +1 -1
- package/dist/_app/immutable/nodes/4.BRRWt-Y5.js +11 -0
- package/dist/_app/version.json +1 -1
- package/dist/cli/commands/ui.js +45 -6
- package/dist/cli/server/index.js +45 -6
- package/dist/cli/server/server.js +45 -6
- package/dist/cli/server/spreadsheetRoutes.js +44 -5
- package/dist/cli/server/websocketServer.js +45 -6
- package/dist/index.html +6 -6
- package/dist/index.js +45 -6
- 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
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import"../chunks/DsnmJJEf.js";import{i as We}from"../chunks/Cq7PwVfU.js";import{p as Xe,am as Ve,d as o,T as k,G as pe,h as e,an as $r,ao as Ne,c as a,n as ke,r as t,b as d,e as Ke,J as P,K as I,ap as Nr,f as x,s as i,aq as c,a as we,ar as xr,aj as Ae,a3 as ze,ak as hr,al as tr,as as yr,k as de,o as ot,W as st}from"../chunks/DTWPdvjs.js";import{l as ar,p as Ye,i as M,a as lt,s as it}from"../chunks/BXUi170M.js";import{a as Lr,s as se,r as jr,e as ge,b as Je,c as Vr,d as _r,i as Cr,f as Sr,w as wr}from"../chunks/e7OeeeKP.js";import{g as nt}from"../chunks/rc9CiIba.js";function dt(ue){return function(...U){var F=U[0];return F.stopPropagation(),ue?.apply(this,U)}}var vt=Ne("<title> </title>"),ct=Ne('<svg><!><path d="M11 18L12.41 19.41 15 16.83 15 29 17 29 17 16.83 19.59 19.41 21 18 16 13 11 18z"></path><path d="M23.5,22H23V20h.5a4.5,4.5,0,0,0,.36-9L23,11l-.1-.82a7,7,0,0,0-13.88,0L9,11,8.14,11a4.5,4.5,0,0,0,.36,9H9v2H8.5A6.5,6.5,0,0,1,7.2,9.14a9,9,0,0,1,17.6,0A6.5,6.5,0,0,1,23.5,22Z"></path></svg>');function gt(ue,U){const F=ar(U,["children","$$slots","$$events","$$legacy"]),J=ar(F,["size","title"]);Xe(U,!1);const H=k(),j=k();let R=Ye(U,"size",8,16),b=Ye(U,"title",8,void 0);Ve(()=>(pe(F),pe(b())),()=>{o(H,F["aria-label"]||F["aria-labelledby"]||b())}),Ve(()=>(e(H),pe(F)),()=>{o(j,{"aria-hidden":e(H)?void 0:!0,role:e(H)?"img":void 0,focusable:Number(F.tabindex)===0?!0:void 0})}),$r(),We();var S=ct();Lr(S,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:R(),height:R(),...e(j),...J}));var K=a(S);{var G=E=>{var g=vt(),N=a(g,!0);t(g),P(()=>I(N,b())),d(E,g)};M(K,E=>{b()&&E(G)})}ke(2),t(S),d(ue,S),Ke()}var pt=Ne("<title> </title>"),ut=Ne('<svg><!><path d="M10 6H14V10H10zM18 6H22V10H18zM10 14H14V18H10zM18 14H22V18H18zM10 22H14V26H10zM18 22H22V26H18z"></path></svg>');function kr(ue,U){const F=ar(U,["children","$$slots","$$events","$$legacy"]),J=ar(F,["size","title"]);Xe(U,!1);const H=k(),j=k();let R=Ye(U,"size",8,16),b=Ye(U,"title",8,void 0);Ve(()=>(pe(F),pe(b())),()=>{o(H,F["aria-label"]||F["aria-labelledby"]||b())}),Ve(()=>(e(H),pe(F)),()=>{o(j,{"aria-hidden":e(H)?void 0:!0,role:e(H)?"img":void 0,focusable:Number(F.tabindex)===0?!0:void 0})}),$r(),We();var S=ut();Lr(S,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:R(),height:R(),...e(j),...J}));var K=a(S);{var G=E=>{var g=pt(),N=a(g,!0);t(g),P(()=>I(N,b())),d(E,g)};M(K,E=>{b()&&E(G)})}ke(),t(S),d(ue,S),Ke()}var bt=x('<div class="p-4 text-sm text-blue-800 rounded-lg bg-blue-50 dark:bg-gray-800 dark:text-blue-400"><div class="flex items-center"><svg class="flex-shrink-0 inline w-4 h-4 mr-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20"><path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"></path></svg> <div><span class="font-medium">File loaded:</span> <div class="mt-1"><span class="font-medium">Sheets:</span> <span class="font-medium">Fields:</span> <span class="font-medium">Controls found:</span> </div></div></div></div>'),ft=x('<div class="p-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400"><div class="flex items-center"><svg class="flex-shrink-0 inline w-4 h-4 mr-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20"><path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"></path></svg> <span> </span></div></div>'),mt=x('<div class="p-4 text-sm text-green-800 rounded-lg bg-green-50 dark:bg-gray-800 dark:text-green-400"><div class="flex items-center"><svg class="flex-shrink-0 inline w-4 h-4 mr-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20"><path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"></path></svg> <span> </span></div></div>'),xt=x("<option> </option>"),ht=x("<option> </option>"),yt=x("<option> </option>"),_t=x('<span class="ml-auto text-xs text-blue-600 dark:text-blue-400">ID</span>'),wt=x('<div draggable="true" role="button" tabindex="0" class="flex items-center px-3 py-2 bg-gray-100 dark:bg-gray-700 text-gray-500 dark:text-gray-400 rounded text-sm cursor-move hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors opacity-75"><svg class="w-3 h-3 mr-2 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20"><path d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z"></path></svg> <span class="truncate line-through"> </span> <!></div>'),kt=x('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">No excluded fields</p>'),Ct=x('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),St=x('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p>'),$t=x('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),Dt=x('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p>'),Mt=x('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),zt=x('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p>'),At=x('<div draggable="false" role="button" tabindex="0" class="flex items-center px-3 py-2 bg-orange-100 dark:bg-orange-900/30 text-orange-800 dark:text-orange-300 rounded text-sm hover:bg-orange-200 dark:hover:bg-orange-800/30 transition-colors"><span class="truncate"> </span> <button class="ml-auto text-gray-400 hover:text-red-500 dark:text-gray-500 dark:hover:text-red-400" title="Remove from mappings">×</button></div>'),Ft=x('<div role="region" aria-label="Justification field drop zone"><p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p></div>'),Ot=x('<th class="px-4 py-2"> </th>'),Pt=x('<td class="px-4 py-2"> </td>'),Ht=x('<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700"></tr>'),Et=x('<div class="bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-800 dark:to-gray-900 rounded-lg p-4 border border-gray-200 dark:border-gray-700"><h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Sample Data Preview</h3> <div class="overflow-x-auto"><table class="w-full text-sm text-left text-gray-500 dark:text-gray-400"><thead class="text-xs text-gray-700 uppercase bg-gray-100 dark:bg-gray-600 dark:text-gray-400"><tr></tr></thead><tbody></tbody></table></div></div>'),It=x('<span class="flex items-center"><svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg> Importing...</span>'),Tt=x(`<div class="bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-800 dark:to-gray-900 rounded-lg p-4 border border-gray-200 dark:border-gray-700"><h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Import Options</h3> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4"><div><label for="controlSetName" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Control Set Name <span class="text-red-500">*</span></label> <input type="text" id="controlSetName" placeholder="e.g., NIST 800-53 Rev 4" class="bg-white border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:text-white" required/> <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">This will be used as the display name and folder name</p></div> <div><label for="controlSetDescription" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Description</label> <input type="text" id="controlSetDescription" placeholder="Optional description" class="bg-white border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:text-white"/> <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Brief description of this control set</p></div></div> <div class="grid grid-cols-1 md:grid-cols-2 gap-4"><div><label for="sheet" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Sheet</label> <select id="sheet" class="bg-white border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:text-white"></select> <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Select which worksheet contains your control data</p></div> <div><label for="headerRow" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Select Header Row</label> <select id="headerRow" class="bg-white border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:text-white"></select> <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Select the row containing column headers</p></div> <div><label for="controlIdField" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Control ID Field <span class="text-red-500">*</span></label> <select id="controlIdField" required><option disabled>Select Control ID field</option><!></select> <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Column containing unique control identifiers (e.g., AC-1, SC-7)</p></div></div></div> <div class="bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-800 dark:to-gray-900 rounded-lg p-4 border border-gray-200 dark:border-gray-700"><h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">Organize Fields</h3> <p class="text-sm text-gray-600 dark:text-gray-400 mb-4">Drag fields to organize them. <strong>Overview fields</strong> will appear as table columns in
|
|
2
|
+
the controls list.</p> <div class="grid grid-cols-1 lg:grid-cols-5 gap-4"><div class="border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800"><div class="p-3 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700 rounded-t-lg"><h4 class="text-sm font-semibold text-gray-700 dark:text-gray-300">Excluded Fields</h4> <p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Not imported</p></div> <div role="region" aria-label="Excluded fields drop zone"><!> <!></div></div> <div class="border border-blue-300 dark:border-blue-700 rounded-lg bg-white dark:bg-gray-800"><div class="p-3 border-b border-blue-200 dark:border-blue-800 bg-blue-50 dark:bg-blue-900/20 rounded-t-lg"><h4 class="text-sm font-semibold text-blue-700 dark:text-blue-300">Overview Tab</h4> <p class="text-xs text-blue-600 dark:text-blue-400 mt-1">Shows in details & table columns</p></div> <div role="region" aria-label="Overview tab drop zone"><!> <!></div></div> <div class="border border-green-300 dark:border-green-700 rounded-lg bg-white dark:bg-gray-800"><div class="p-3 border-b border-green-200 dark:border-green-800 bg-green-50 dark:bg-green-900/20 rounded-t-lg"><h4 class="text-sm font-semibold text-green-700 dark:text-green-300">Implementation Tab</h4> <p class="text-xs text-green-600 dark:text-green-400 mt-1">Status & compliance</p></div> <div role="region" aria-label="Implementation tab drop zone"><!> <!></div></div> <div class="border border-purple-300 dark:border-purple-700 rounded-lg bg-white dark:bg-gray-800"><div class="p-3 border-b border-purple-200 dark:border-purple-800 bg-purple-50 dark:bg-purple-900/20 rounded-t-lg"><h4 class="text-sm font-semibold text-purple-700 dark:text-purple-300">Custom Tab</h4> <p class="text-xs text-purple-600 dark:text-purple-400 mt-1">Additional fields</p></div> <div role="region" aria-label="Custom fields drop zone"><!> <!></div></div> <div class="border border-orange-300 dark:border-orange-700 rounded-lg bg-white dark:bg-gray-800"><div class="p-3 border-b border-orange-200 dark:border-orange-800 bg-orange-50 dark:bg-orange-900/20 rounded-t-lg"><h4 class="text-sm font-semibold text-orange-700 dark:text-orange-300">Mappings Tab</h4> <p class="text-xs text-orange-600 dark:text-orange-400 mt-1">Pre-populate justification for a control mapping</p></div> <div role="region" aria-label="Justifications tab drop zone"><div class="space-y-2"><!></div></div></div></div></div> <!> <div class="flex justify-center"><button class="px-5 py-2.5 text-white bg-blue-600 hover:bg-blue-700 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm disabled:opacity-50 disabled:cursor-not-allowed"><!></button></div>`,1),jt=x('<div class="space-y-6"><div role="button" tabindex="0" class="relative"><label><div class="flex flex-col items-center justify-center pt-5 pb-6"><!> <p class="mb-2 text-sm text-gray-500 dark:text-gray-400"><span class="font-semibold">Click to upload</span> or drag and drop</p> <p class="text-xs text-gray-500 dark:text-gray-400">XLSX, XLS or CSV files</p></div> <input type="file" class="hidden" accept=".xlsx,.xls,.csv"/></label></div> <!> <!> <!> <!></div>');function Vt(ue,U){Xe(U,!1);const F=Nr();let J=k(null),H=k(""),j=k(""),R=k([]),b=k([]),S=k([]),K=k(0),G=k([]),E=k([]),g=k(new Map),N=k(1),L=k(""),xe=k(""),Y=k(""),Q=k(!1),ee=k(""),be=k(""),Ce=k(!1),re=k(!1),$=k(null),Z=k(null),te=k(null);function Se(){o(b,[]),o(S,[]),o(K,0),e(g).clear(),o(g,new Map),o(E,[]),o(L,""),o(ee,""),o(be,""),o($,null),o(Z,null),o(te,null)}function p(s){s.preventDefault(),o(re,!0)}function u(){o(re,!1)}function D(s){s.preventDefault(),o(re,!1);const n=s.dataTransfer?.files;n&&n.length>0&&T(n[0])}function V(s){const n=s.target;n.files&&n.files.length>0&&T(n.files[0])}async function T(s){Se(),o(H,s.name),o(J,s),o(ee,""),o(Q,!0),o(xe,e(H).replace(/\.[^.]+$/,"").replace(/[-_]/g," ")),o(Y,`Imported from ${e(H)}`);try{const n=new FormData;n.append("file",s);const y=await fetch("/api/parse-excel",{method:"POST",body:n});if(!y.ok){const z=await y.json();throw new Error(z.error||"Failed to parse file")}const h=await y.json();o(R,h.sheets||[]),o(j,h.selectedSheet||e(R)[0]),o(G,h.rowPreviews||[]),e(G).length>0&&e(N)===1&&o(N,e(G)[0].row),await q(),o(Ce,!0)}catch(n){o(ee,"Error reading file: "+n.message)}finally{o(Q,!1)}}async function q(){if(!(!e(J)||!e(j))){o(Q,!0),e(g).clear(),o(g,new Map),o(L,"");try{const s=new FormData;s.append("file",e(J)),s.append("sheetName",e(j));const n=await fetch("/api/parse-excel-sheet-previews",{method:"POST",body:s});if(n.ok){const w=await n.json();o(G,w.rowPreviews||[]),e(G).length>0&&!e(G).some(A=>A.row===e(N))&&o(N,e(G)[0].row)}else{const w=await n.json();throw new Error(w.error||"Failed to load sheet previews")}const y=new FormData;y.append("file",e(J)),y.append("sheetName",e(j)),y.append("headerRow",e(N).toString());const h=await fetch("/api/parse-excel-sheet",{method:"POST",body:y});if(!h.ok){const w=await h.json();throw new Error(w.error||"Failed to parse sheet")}const z=await h.json();if(o(b,z.fields||[]),o(S,z.sampleData||[]),o(K,z.controlCount||0),e(b).forEach((w,A)=>{const _=w.toLowerCase();let ce="custom",fe="text";_.includes("implementation")||_.includes("status")||_.includes("narrative")||_.includes("guidance")?ce="implementation":(_.includes("id")||_.includes("title")||_.includes("family")||_.includes("cci")||_.includes("control")||_.includes("acronym"))&&(ce="overview"),_.includes("description")||_.includes("narrative")||_.includes("guidance")||_.includes("statement")?fe="textarea":_.includes("status")||_.includes("type")||_.includes("designation")?fe="select":_.includes("date")?fe="date":(_.includes("count")||_.includes("number"))&&(fe="number"),e(g).set(w,{originalName:w,tab:ce,displayOrder:A,fieldType:fe,required:_.includes("id")||_.includes("title")})}),o(g,e(g)),e(L)&&!e(b).includes(e(L))&&o(L,""),!e(L)&&e(b).includes("AP Acronym")){const w=!e(S).length||e(S).every(ne=>!ne["AP Acronym"]||String(ne["AP Acronym"]).length<25),A=e(S).map(ne=>ne["AP Acronym"]).filter(ne=>ne!=null&&ne!==""&&String(ne).trim()!==""),_=new Set(A),ce=!A.length||_.size===A.length,fe=A.length>0;w&&ce&&fe&&o(L,"AP Acronym")}}catch(s){o(ee,"Error loading sheet data: "+s.message)}finally{o(Q,!1)}}}function ve(s){if(!s)return s;let n=s.trim().replace(/\r?\n/g," ").replace(/\s+/g," ").trim();return Le(n)}function Le(s){return s.replace(/\W+/g," ").split(/ |\s/).map(n=>n.toLowerCase()).join("-")}function he(s,n){o($,n),s.dataTransfer&&(s.dataTransfer.effectAllowed="move",s.dataTransfer.setData("text/plain",n))}function ae(){o($,null),o(Z,null),o(te,null)}function C(s,n){s.preventDefault(),o(Z,n),s.dataTransfer&&(s.dataTransfer.dropEffect="move")}function le(){o(Z,null)}function ie(s,n,y){if(s.preventDefault(),e($)&&e(g).has(e($))){const h=e(g).get(e($));if(n==="mappings")e(E).includes(e($))||o(E,[...e(E),e($)]);else{if(h.tab=n,y!==void 0&&n!==null){const w=Array.from(e(g).entries()).filter(([A,_])=>_.tab===n).sort((A,_)=>A[1].displayOrder-_[1].displayOrder).filter(([A])=>A!==e($));w.splice(y,0,[e($),h]),w.forEach(([A,_],ce)=>{_.displayOrder=ce,e(g).set(A,_)})}else if(n!==null){const z=Math.max(0,...Array.from(e(g).values()).filter(w=>w.tab===n).map(w=>w.displayOrder));h.displayOrder=z+1}e(g).set(e($),h),o(g,e(g))}}o($,null),o(Z,null)}function Fe(s,n){s.preventDefault(),s.stopPropagation(),o(te,n)}function $e(){o(te,null)}function De(s,n,y){if(s.preventDefault(),s.stopPropagation(),e($)&&e($)!==n){const z=Array.from(e(g).entries()).filter(([w,A])=>A.tab===y).sort((w,A)=>w[1].displayOrder-A[1].displayOrder).findIndex(([w])=>w===n);z!==-1&&ie(s,y,z)}o(te,null)}async function Be(){if(!(!e(J)||!e(H))){if(!e(L)){o(ee,"Please select a Control ID field before importing"),o(be,"");return}if(!e(xe)||e(xe).trim()===""){o(ee,"Please enter a Control Set Name before importing"),o(be,"");return}o(Q,!0),o(ee,""),o(be,"");try{const s=new FormData;s.append("file",e(J),e(H)),s.append("controlIdField",e(L)),s.append("startRow",e(N).toString()),s.append("sheetName",e(j)),s.append("namingConvention","kebab-case"),s.append("skipEmpty","true"),s.append("skipEmptyRows","true"),s.append("controlSetName",e(xe)||e(H).replace(/\.[^.]+$/,"")),s.append("controlSetDescription",e(Y)||`Imported from ${e(H)}`);const n=Array.from(e(g).entries()).filter(([h,z])=>z.tab!==null).map(([h,z])=>({fieldName:ve(h),...z}));s.append("fieldSchema",JSON.stringify(n)),s.append("justificationFields",JSON.stringify(e(E).map(h=>ve(h))));let y;try{if(y=await fetch("/api/import-spreadsheet",{method:"POST",body:s}),!y.ok){const z=await y.json();throw new Error(z.error||"Import failed")}const h=await y.json();o(be,`Successfully imported ${h.controlCount} controls into ${h.families.length} families`),F("created",{path:h.outputDir})}catch(h){console.error("Error importing spreadsheet:",h)}}catch(s){o(ee,"Error importing spreadsheet: "+s.message)}finally{o(Q,!1)}}}We();var Re=jt(),ye=a(Re),Ze=a(ye),Oe=a(Ze),or=a(Oe);gt(or,{class:"w-8 h-8 mb-4 text-gray-500 dark:text-gray-400"}),ke(4),t(Oe);var Ge=i(Oe,2);t(Ze),t(ye);var Pe=i(ye,2);{var sr=s=>{var n=bt(),y=a(n),h=i(a(y),2),z=i(a(h)),w=i(z),A=i(a(w)),_=i(A,2),ce=i(_,2);t(w),t(h),t(y),t(n),P(()=>{I(z,` ${e(H)??""} `),I(A,` ${e(R).length??""} | `),I(_,` ${e(b).length??""} | `),I(ce,` ${e(K)??""}`)}),d(s,n)};M(Pe,s=>{e(H)&&s(sr)})}var Qe=i(Pe,2);{var lr=s=>{var n=ft(),y=a(n),h=i(a(y),2),z=a(h,!0);t(h),t(y),t(n),P(()=>I(z,e(ee))),d(s,n)};M(Qe,s=>{e(ee)&&s(lr)})}var qe=i(Qe,2);{var ir=s=>{var n=mt(),y=a(n),h=i(a(y),2),z=a(h,!0);t(h),t(y),t(n),P(()=>I(z,e(be))),d(s,n)};M(qe,s=>{e(be)&&s(ir)})}var nr=i(qe,2);{var dr=s=>{var n=Tt(),y=we(n),h=i(a(y),2),z=a(h),w=i(a(z),2);jr(w),ke(2),t(z);var A=i(z,2),_=i(a(A),2);jr(_),ke(2),t(A),t(h);var ce=i(h,2),fe=a(ce),ne=i(a(fe),2);P(()=>{e(j),xr(()=>{e(R)})}),ge(ne,5,()=>e(R),r=>r,(r,l)=>{var f=xt(),m=a(f,!0);t(f);var v={};P(()=>{I(m,e(l)),v!==(v=e(l))&&(f.value=(f.__value=e(l))??"")}),d(r,f)}),t(ne),ke(2),t(fe);var vr=i(fe,2),er=i(a(vr),2);P(()=>{e(N),xr(()=>{e(G)})}),ge(er,5,()=>e(G),r=>r.row,(r,l)=>{var f=ht(),m=a(f);t(f);var v={};P(()=>{I(m,`Row ${e(l).row??""}: ${e(l).preview??""}`),v!==(v=e(l).row)&&(f.value=(f.__value=e(l).row)??"")}),d(r,f)}),t(er),ke(2),t(vr);var Dr=i(vr,2),rr=i(a(Dr),2);P(()=>{e(L),xr(()=>{e(b),e(S)})});var cr=a(rr);cr.value=cr.__value="";var Br=i(cr);ge(Br,1,()=>e(b),r=>r,(r,l)=>{const f=ze(()=>e(S).length>0&&e(S)[0][e(l)]?String(e(S)[0][e(l)]).slice(0,30):""),m=ze(()=>!e(S).length||e(S).every(oe=>!oe[e(l)]||String(oe[e(l)]).length<25)),v=ze(()=>e(S).map(oe=>oe[e(l)]).filter(oe=>oe!=null&&oe!==""&&String(oe).trim()!=="")),W=ze(()=>new Set(e(v))),X=ze(()=>!e(v).length||e(W).size===e(v).length),B=ze(()=>e(v).length>0);var O=Ae(),me=we(O);{var Me=oe=>{var _e=yt(),mr=a(_e);t(_e);var Tr={};P(()=>{I(mr,`${e(l)??""}${e(f)?` (e.g., ${e(f)})`:""}`),Tr!==(Tr=e(l))&&(_e.value=(_e.__value=e(l))??"")}),d(oe,_e)};M(me,oe=>{e(m)&&e(X)&&e(B)&&oe(Me)})}d(r,O)}),t(rr),ke(2),t(Dr),t(ce),t(y);var gr=i(y,2),Mr=i(a(gr),4),pr=a(Mr),He=i(a(pr),2),zr=a(He);ge(zr,1,()=>e(b).filter(r=>!e(g).get(r)||e(g).get(r)?.tab===null),r=>r,(r,l)=>{var f=wt(),m=i(a(f),2),v=a(m,!0);t(m);var W=i(m,2);{var X=B=>{var O=_t();d(B,O)};M(W,B=>{e(l)===e(L)&&B(X)})}t(f),P(()=>{Je(f,"aria-label",`Drag ${e(l)??""} field`),I(v,e(l))}),c("dragstart",f,B=>he(B,e(l))),c("dragend",f,ae),d(r,f)});var Rr=i(zr,2);{var Zr=r=>{var l=kt();d(r,l)};M(Rr,r=>{e(b).filter(l=>!e(g).get(l)||e(g).get(l)?.tab===null).length===0&&r(Zr)})}t(He),t(pr);var ur=i(pr,2),Ee=i(a(ur),2),Ar=a(Ee);ge(Ar,3,()=>Array.from(e(g).entries()).filter(([r,l])=>l.tab==="overview").sort((r,l)=>r[1].displayOrder-l[1].displayOrder),([r,l])=>r,(r,l)=>{var f=hr(()=>yr(e(l),2));let m=()=>e(f)[0];var v=Ct(),W=a(v);kr(W,{class:"w-3 h-3 mr-2 flex-shrink-0"});var X=i(W,2),B=a(X,!0);t(X),t(v),P(()=>{Je(v,"aria-label",`${m()??""} field in Overview tab`),se(v,1,`flex items-center px-3 py-2 bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-300 rounded text-sm cursor-move hover:bg-blue-200 dark:hover:bg-blue-800/30 transition-colors
|
|
3
|
+
${e(te)===m()&&e($)!==m()?"border-t-2 border-blue-500":""}`),I(B,m())}),c("dragstart",v,O=>he(O,m())),c("dragend",v,ae),c("dragover",v,O=>Fe(O,m())),c("dragleave",v,$e),c("drop",v,O=>De(O,m(),"overview")),d(r,v)});var qr=i(Ar,2);{var Ur=r=>{var l=St();d(r,l)};M(qr,r=>{Array.from(e(g).entries()).filter(([l,f])=>f.tab==="overview").length===0&&r(Ur)})}t(Ee),t(ur);var br=i(ur,2),Ie=i(a(br),2),Fr=a(Ie);ge(Fr,3,()=>Array.from(e(g).entries()).filter(([r,l])=>l.tab==="implementation").sort((r,l)=>r[1].displayOrder-l[1].displayOrder),([r,l])=>r,(r,l)=>{var f=hr(()=>yr(e(l),2));let m=()=>e(f)[0];var v=$t(),W=a(v);kr(W,{class:"w-3 h-3 mr-2 flex-shrink-0"});var X=i(W,2),B=a(X,!0);t(X),t(v),P(()=>{Je(v,"aria-label",`${m()??""} field in Implementation tab`),se(v,1,`flex items-center px-3 py-2 bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-300 rounded text-sm cursor-move hover:bg-green-200 dark:hover:bg-green-800/30 transition-colors
|
|
4
|
+
${e(te)===m()&&e($)!==m()?"border-t-2 border-green-500":""}`),I(B,m())}),c("dragstart",v,O=>he(O,m())),c("dragend",v,ae),c("dragover",v,O=>Fe(O,m())),c("dragleave",v,$e),c("drop",v,O=>De(O,m(),"implementation")),d(r,v)});var Jr=i(Fr,2);{var Yr=r=>{var l=Dt();d(r,l)};M(Jr,r=>{Array.from(e(g).entries()).filter(([l,f])=>f.tab==="implementation").length===0&&r(Yr)})}t(Ie),t(br);var fr=i(br,2),Te=i(a(fr),2),Or=a(Te);ge(Or,3,()=>Array.from(e(g).entries()).filter(([r,l])=>l.tab==="custom").sort((r,l)=>r[1].displayOrder-l[1].displayOrder),([r,l])=>r,(r,l)=>{var f=hr(()=>yr(e(l),2));let m=()=>e(f)[0];var v=Mt(),W=a(v);kr(W,{class:"w-3 h-3 mr-2 flex-shrink-0"});var X=i(W,2),B=a(X,!0);t(X),t(v),P(()=>{Je(v,"aria-label",`${m()??""} field in Custom tab`),se(v,1,`flex items-center px-3 py-2 bg-purple-100 dark:bg-purple-900/30 text-purple-800 dark:text-purple-300 rounded text-sm cursor-move hover:bg-purple-200 dark:hover:bg-purple-800/30 transition-colors
|
|
5
|
+
${e(te)===m()&&e($)!==m()?"border-t-2 border-purple-500":""}`),I(B,m())}),c("dragstart",v,O=>he(O,m())),c("dragend",v,ae),c("dragover",v,O=>Fe(O,m())),c("dragleave",v,$e),c("drop",v,O=>De(O,m(),"custom")),d(r,v)});var Wr=i(Or,2);{var Xr=r=>{var l=zt();d(r,l)};M(Wr,r=>{Array.from(e(g).entries()).filter(([l,f])=>f.tab==="custom").length===0&&r(Xr)})}t(Te),t(fr);var Pr=i(fr,2),je=i(a(Pr),2),Hr=a(je),Kr=a(Hr);{var Gr=r=>{var l=Ae(),f=we(l);ge(f,1,()=>e(E),Cr,(m,v)=>{var W=At(),X=a(W),B=a(X,!0);t(X);var O=i(X,2);t(W),P(()=>I(B,e(v))),c("click",O,dt(()=>{o(E,e(E).filter(me=>me!==e(v)))})),d(m,W)}),d(r,l)},Qr=r=>{var l=Ft();P(()=>se(l,1,`p-4 transition-colors
|
|
6
|
+
${e(Z)==="mappings"?"bg-orange-50 dark:bg-orange-900/10":""}`)),c("dragover",l,f=>{f.preventDefault(),C(f,"mappings")}),c("dragleave",l,le),c("drop",l,f=>{if(f.preventDefault(),e($)&&e(g).has(e($))){e(E).includes(e($))||o(E,[...e(E),e($)]);const m=e(g).get(e($));m.tab="mappings",e(g).set(e($),m),o(g,new Map(e(g))),o(Z,null)}}),d(r,l)};M(Kr,r=>{e(E).length>0?r(Gr):r(Qr,!1)})}t(Hr),t(je),t(Pr),t(Mr),t(gr);var Er=i(gr,2);{var et=r=>{var l=Et(),f=i(a(l),2),m=a(f),v=a(m),W=a(v);ge(W,5,()=>e(b).slice(0,5),B=>B,(B,O)=>{var me=Ot(),Me=a(me,!0);t(me),P(()=>I(Me,e(O))),d(B,me)}),t(W),t(v);var X=i(v);ge(X,5,()=>e(S),Cr,(B,O)=>{var me=Ht();ge(me,5,()=>e(b).slice(0,5),Me=>Me,(Me,oe)=>{var _e=Pt(),mr=a(_e,!0);t(_e),P(()=>I(mr,e(O)[e(oe)]||"")),d(Me,_e)}),t(me),d(B,me)}),t(X),t(m),t(f),t(l),d(r,l)};M(Er,r=>{e(S).length>0&&r(et)})}var Ir=i(Er,2),Ue=a(Ir),rt=a(Ue);{var tt=r=>{var l=It();d(r,l)},at=r=>{var l=tr("Import to Control Set");d(r,l)};M(rt,r=>{e(Q)?r(tt):r(at,!1)})}t(Ue),t(Ir),P(()=>{se(rr,1,`bg-white border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:text-white ${e(L)?"":"border-red-500"}`),se(He,1,`p-3 min-h-[400px] max-h-[600px] overflow-y-auto space-y-2 transition-colors
|
|
7
|
+
${e(Z)===null?"bg-gray-100 dark:bg-gray-800":""}`),se(Ee,1,`p-3 min-h-[400px] max-h-[600px] overflow-y-auto space-y-2 transition-colors
|
|
8
|
+
${e(Z)==="overview"?"bg-blue-50 dark:bg-blue-900/10":""}`),se(Ie,1,`p-3 min-h-[400px] max-h-[600px] overflow-y-auto space-y-2 transition-colors
|
|
9
|
+
${e(Z)==="implementation"?"bg-green-50 dark:bg-green-900/10":""}`),se(Te,1,`p-3 min-h-[400px] max-h-[600px] overflow-y-auto space-y-2 transition-colors
|
|
10
|
+
${e(Z)==="custom"?"bg-purple-50 dark:bg-purple-900/10":""}`),se(je,1,`p-3 min-h-[400px] max-h-[600px] overflow-y-auto transition-colors
|
|
11
|
+
${e(Z)==="mappings"?"bg-orange-50 dark:bg-orange-900/10":""}`),Ue.disabled=e(Q)||!e(J)||!e(L),Je(Ue,"title",e(L)?"":"Please select a Control ID field")}),Vr(w,()=>e(xe),r=>o(xe,r)),Vr(_,()=>e(Y),r=>o(Y,r)),_r(ne,()=>e(j),r=>o(j,r)),c("change",ne,async()=>{await q()}),_r(er,()=>e(N),r=>o(N,r)),c("change",er,q),_r(rr,()=>e(L),r=>o(L,r)),c("dragover",He,r=>C(r,null)),c("dragleave",He,le),c("drop",He,r=>ie(r,null)),c("dragover",Ee,r=>C(r,"overview")),c("dragleave",Ee,le),c("drop",Ee,r=>ie(r,"overview")),c("dragover",Ie,r=>C(r,"implementation")),c("dragleave",Ie,le),c("drop",Ie,r=>ie(r,"implementation")),c("dragover",Te,r=>C(r,"custom")),c("dragleave",Te,le),c("drop",Te,r=>ie(r,"custom")),c("dragover",je,r=>C(r,"mappings")),c("dragleave",je,le),c("drop",je,r=>ie(r,"mappings")),c("click",Ue,Be),d(s,n)};M(nr,s=>{e(Ce)&&e(b).length>0&&s(dr)})}t(Re),P(()=>se(Ze,1,`flex flex-col items-center justify-center w-full h-64 border-2 border-dashed rounded-lg cursor-pointer transition-all duration-300 ${e(re)?"border-blue-500 bg-blue-50 dark:bg-blue-900/20":"border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600"}`)),c("change",Ge,V),c("dragover",ye,p),c("dragleave",ye,u),c("drop",ye,D),d(ue,Re),Ke()}var Nt=x('<span class="ml-2"> </span>'),Lt=x('<div class="text-sm text-gray-500 dark:text-gray-400"><span class="font-medium"> </span> <!></div>'),Bt=x('<div class="text-center space-y-6"><div class="p-6 bg-gradient-to-br from-green-50 to-emerald-50 dark:from-green-900/20 dark:to-emerald-900/20 rounded-lg border-2 border-green-500"><svg class="w-12 h-12 text-green-600 mx-auto mb-4" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path></svg> <h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">Already Using Control Set</h3> <p class="text-gray-600 dark:text-gray-400 mb-4">You are already using the only available control set in this project.</p> <!></div> <div class="flex justify-center gap-4"><a href="/" class="px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors shadow-lg">Continue to Controls</a> <button class="px-6 py-3 bg-gray-200 hover:bg-gray-300 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-900 dark:text-white font-medium rounded-lg transition-colors">Import New Control Set</button></div></div>'),Rt=x('<div class="p-4 text-sm text-yellow-800 rounded-lg bg-yellow-50 dark:bg-gray-800 dark:text-yellow-300"><div class="flex items-center"><svg class="flex-shrink-0 inline w-4 h-4 mr-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20"><path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"></path></svg> <span> </span></div></div>'),Zt=x('<p class="text-sm text-gray-600 dark:text-gray-400 mt-1"> </p>'),qt=x('<span class="text-xs text-gray-500 dark:text-gray-400"><svg class="inline w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M4 3a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V5a2 2 0 00-2-2H4zm12 12H4l4-8 3 6 2-4 3 6z" clip-rule="evenodd"></path></svg> </span>'),Ut=x('<div class="flex flex-col items-center"><svg class="w-8 h-8 text-green-600" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path></svg> <span class="text-xs text-green-600 font-medium mt-1">Current</span></div>'),Jt=Ne('<svg class="w-8 h-8 text-blue-600" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path></svg>'),Yt=Ne('<svg class="w-8 h-8 text-gray-300 dark:text-gray-600" fill="none" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle cx="10" cy="10" r="9" stroke="currentColor" stroke-width="2"></circle></svg>'),Wt=x('<div role="button" tabindex="0"><div class="flex items-center justify-between"><div class="flex-1"><div class="flex items-center gap-3"><h3 class="text-lg font-semibold text-gray-900 dark:text-white"> </h3> <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200"> </span></div> <!> <div class="flex items-center gap-4 mt-2"><span class="text-xs text-gray-500 dark:text-gray-400"><svg class="inline w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M2 6a2 2 0 012-2h12a2 2 0 012 2v8a2 2 0 01-2 2H4a2 2 0 01-2-2V6zm2-1a1 1 0 00-1 1v8a1 1 0 001 1h12a1 1 0 001-1V6a1 1 0 00-1-1H4z" clip-rule="evenodd"></path></svg> </span> <!></div></div> <div class="flex items-center ml-4"><!></div></div></div>'),Xt=x('<div class="mt-6 flex justify-center"><button class="px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors shadow-lg">Use Selected Control Set</button></div>'),Kt=x('<div class="space-y-3"></div> <!>',1),Gt=x('<div class="space-y-6"><div class="text-center"><h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-2">Select an Existing Control Set</h2> <p class="text-gray-600 dark:text-gray-400">Choose from control sets found in your project directory</p></div> <!></div>');function Qt(ue,U){Xe(U,!1);const F=()=>lt(Sr,"$appState",J),[J,H]=it(),j=k(),R=Nr();let b=Ye(U,"controlSets",24,()=>[]),S=k(""),K=k(null);function G(Y){g(Y)||o(K,Y)}function E(){e(K)&&!g(e(K))&&R("selected",{path:e(K).path})}function g(Y){const Q=e(j)?.replace(/\/$/,""),ee=Y.path?.replace(/\/$/,"");return!!(Q&&ee&&Q===ee)}Ve(()=>F(),()=>{o(j,F().currentPath||"")}),Ve(()=>pe(b()),()=>{if(b())if(b().length===0)o(S,"No existing control sets found. Try importing from a spreadsheet instead.");else{const Y=b().filter(Q=>!g(Q));Y.length===1?o(K,Y[0]):Y.length===0&&b().length>0&&o(S,"already-using-only-set")}}),$r(),We();var N=Gt(),L=i(a(N),2);{var xe=Y=>{var Q=Ae(),ee=we(Q);{var be=re=>{var $=Bt(),Z=a($),te=i(a(Z),6);{var Se=D=>{var V=Lt(),T=a(V),q=a(T,!0);t(T);var ve=i(T,2);{var Le=he=>{var ae=Nt(),C=a(ae);t(ae),P(()=>I(C,`(${pe(b()),de(()=>b()[0].controlCount)??""} controls)`)),d(he,ae)};M(ve,he=>{pe(b()),de(()=>b()[0].controlCount)&&he(Le)})}t(V),P(()=>I(q,(pe(b()),de(()=>b()[0].name)))),d(D,V)};M(te,D=>{pe(b()),de(()=>b().length>0)&&D(Se)})}t(Z);var p=i(Z,2),u=i(a(p),2);t(p),t($),c("click",u,()=>R("tab-change",{tab:"import"})),d(re,$)},Ce=re=>{var $=Ae(),Z=we($);{var te=p=>{var u=Rt(),D=a(u),V=i(a(D),2),T=a(V,!0);t(V),t(D),t(u),P(()=>I(T,e(S))),d(p,u)},Se=p=>{var u=Ae(),D=we(u);{var V=T=>{var q=Kt(),ve=we(q);ge(ve,5,b,Cr,(ae,C)=>{const le=ze(()=>(e(C),de(()=>g(e(C)))));var ie=Wt(),Fe=a(ie),$e=a(Fe),De=a($e),Be=a(De),Re=a(Be,!0);t(Be);var ye=i(Be,2),Ze=a(ye);t(ye),t(De);var Oe=i(De,2);{var or=s=>{var n=Zt(),y=a(n,!0);t(n),P(()=>I(y,(e(C),de(()=>e(C).description)))),d(s,n)};M(Oe,s=>{e(C),de(()=>e(C).description)&&s(or)})}var Ge=i(Oe,2),Pe=a(Ge),sr=i(a(Pe));t(Pe);var Qe=i(Pe,2);{var lr=s=>{var n=qt(),y=i(a(n));t(n),P(()=>I(y,` ${e(C),de(()=>e(C).file)??""}`)),d(s,n)};M(Qe,s=>{e(C),de(()=>e(C).file)&&s(lr)})}t(Ge),t($e);var qe=i($e,2),ir=a(qe);{var nr=s=>{var n=Ut();d(s,n)},dr=s=>{var n=Ae(),y=we(n);{var h=w=>{var A=Jt();d(w,A)},z=w=>{var A=Yt();d(w,A)};M(y,w=>{e(K)===e(C)?w(h):w(z,!1)},!0)}d(s,n)};M(ir,s=>{e(le)?s(nr):s(dr,!1)})}t(qe),t(Fe),t(ie),P(()=>{se(ie,1,`p-4 bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-800 dark:to-gray-900 rounded-lg border-2 transition-all duration-200 ${e(le)?"border-green-500 !bg-gradient-to-br from-green-50 to-emerald-50 dark:from-green-900/20 dark:to-emerald-900/20 cursor-not-allowed opacity-75":e(K)===e(C)?"border-blue-500 !bg-gradient-to-br from-blue-50 to-indigo-50 dark:from-blue-900/20 dark:to-indigo-900/20 shadow-lg cursor-pointer":"border-gray-200 dark:border-gray-700 hover:border-blue-300 dark:hover:border-blue-700 hover:shadow-md cursor-pointer"}`),I(Re,(e(C),de(()=>e(C).name))),I(Ze,`${e(C),de(()=>e(C).controlCount||0)??""} controls`),I(sr,` ${e(C),de(()=>e(C).path||"root")??""}`)}),c("click",ie,()=>!e(le)&&G(e(C))),c("keydown",ie,s=>s.key==="Enter"&&!e(le)&&G(e(C))),d(ae,ie)}),t(ve);var Le=i(ve,2);{var he=ae=>{var C=Xt(),le=a(C);t(C),c("click",le,E),d(ae,C)};M(Le,ae=>{e(K)&&ae(he)})}d(T,q)};M(D,T=>{pe(b()),de(()=>b().length>0)&&T(V)},!0)}d(p,u)};M(Z,p=>{e(S)?p(te):p(Se,!1)},!0)}d(re,$)};M(ee,re=>{e(S)==="already-using-only-set"?re(be):re(Ce,!1)},!0)}d(Y,Q)};M(L,Y=>{Y(xe,!1)})}t(N),d(ue,N),Ke(),H()}var ea=x('<div class="flex justify-center mb-8"><div class="bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-800 dark:to-gray-900 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 inline-flex"><button data-testid="tab-existing">Select Existing Control Set</button> <button data-testid="tab-import">Import New from Spreadsheet</button></div></div>'),ra=x('<div data-testid="pane-import"><!></div>'),ta=x('<div data-testid="pane-existing"><!></div>'),aa=x('<div data-testid="switch-overlay" class="absolute inset-0 bg-gray-900 bg-opacity-50 flex items-center justify-center rounded-lg"><div class="bg-white dark:bg-gray-700 rounded-lg p-6 text-center"><svg class="animate-spin h-8 w-8 text-blue-600 mx-auto mb-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg> <p class="text-gray-900 dark:text-white">Switching control set...</p></div></div>'),oa=x('<div class=" p-4"><div class="max-w-6xl mx-auto"><div class="text-center py-8"><h1 class="text-4xl font-extrabold text-gray-900 dark:text-white mb-4 flex items-center justify-center gap-3"><img src="/lula.png" class="h-12 w-12" alt="Lula"/> <span id="title">Lula</span></h1> <p id="description" class="text-lg text-gray-600 dark:text-gray-400"><!></p></div> <!> <div class="bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-800 dark:to-gray-900 rounded-lg shadow-xl p-6 relative border border-gray-200 dark:border-gray-700"><!> <!></div></div></div>');function ca(ue,U){Xe(U,!1);let F=k("import"),J=k(""),H=k(!1),j=k(!1),R=k([]);ot(()=>{wr.connect();const p=Sr.subscribe(D=>{D.name&&D.name!=="Unknown Control Set"&&D.id!=="unknown"&&D.id!=="default"&&o(J,D.currentPath||"")}),u=async D=>{const V=D.detail;if(V&&V.controlSets){if(o(R,V.controlSets||[]),o(H,e(R).length>0),e(R).length===1){const T=e(R)[0];if(!(e(J)&&e(J).includes(T.path))&&!e(J)){console.log("Only one control set found and none loaded, auto-loading:",T.path),await b(T.path);return}}e(H)&&o(F,"existing")}};return window.addEventListener("control-sets-list",u),wr.scanControlSets().catch(D=>{console.error("Error scanning control sets:",D)}),()=>{p(),window.removeEventListener("control-sets-list",u)}});async function b(p){console.log("Starting control set switch to:",p),o(j,!0);try{await wr.switchControlSet(p),console.log("WebSocket command sent, waiting for state update..."),await new Promise(u=>{let D=0;const V=50,T=setInterval(()=>{D++;const q=st(Sr);!q.isSwitchingControlSet&&q.currentPath&&q.currentPath.includes(p)?(clearInterval(T),console.log("Control set switch completed successfully"),u()):D>=V&&(clearInterval(T),console.error("Control set switch timed out"),alert("Control set switch timed out. Please try again."),u())},100)}),o(j,!1),nt("/")}catch(u){console.error("Error switching control set:",u),alert("Failed to switch control set: "+u.message),o(j,!1)}}async function S(p){const{path:u}=p.detail;await b(u)}async function K(p){const{path:u}=p.detail;await b(u)}function G(p){const{tab:u}=p.detail;u&&o(F,u)}We();var E=oa(),g=a(E),N=a(g),L=i(a(N),2),xe=a(L);{var Y=p=>{var u=tr("You have an existing control set. You can continue using it or create a new one.");d(p,u)},Q=p=>{var u=Ae(),D=we(u);{var V=q=>{var ve=tr("Select an existing control set or import a new one from a spreadsheet.");d(q,ve)},T=q=>{var ve=tr("Let's get started by importing a control set from a spreadsheet.");d(q,ve)};M(D,q=>{e(H)?q(V):q(T,!1)},!0)}d(p,u)};M(xe,p=>{e(J)?p(Y):p(Q,!1)})}t(L),t(N);var ee=i(N,2);{var be=p=>{var u=ea(),D=a(u),V=a(D),T=i(V,2);t(D),t(u),P(()=>{se(V,1,`px-6 py-3 rounded-l-lg font-medium transition-colors ${e(F)==="existing"?"bg-blue-600 text-white":"text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white"}`),se(T,1,`px-6 py-3 rounded-r-lg font-medium transition-colors ${e(F)==="import"?"bg-blue-600 text-white":"text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white"}`)}),c("click",V,()=>o(F,"existing")),c("click",T,()=>o(F,"import")),d(p,u)};M(ee,p=>{e(H)&&p(be)})}var Ce=i(ee,2),re=a(Ce);{var $=p=>{var u=ra(),D=a(u);Vt(D,{$$events:{created:S}}),t(u),d(p,u)},Z=p=>{var u=ta(),D=a(u);Qt(D,{get controlSets(){return e(R)},$$events:{selected:K,"tab-change":G}}),t(u),d(p,u)};M(re,p=>{e(F)==="import"?p($):p(Z,!1)})}var te=i(re,2);{var Se=p=>{var u=aa();d(p,u)};M(te,p=>{e(j)&&p(Se)})}t(Ce),t(g),t(E),d(ue,E),Ke()}export{ca as component};
|
package/dist/_app/version.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"
|
|
1
|
+
{"version":"1759969891884"}
|
package/dist/cli/commands/ui.js
CHANGED
|
@@ -2948,7 +2948,7 @@ function processImportParameters(reqBody) {
|
|
|
2948
2948
|
frontendFieldSchema
|
|
2949
2949
|
};
|
|
2950
2950
|
}
|
|
2951
|
-
async function parseUploadedFile(file) {
|
|
2951
|
+
async function parseUploadedFile(file, sheetName) {
|
|
2952
2952
|
const fileName = file.originalname || "";
|
|
2953
2953
|
const isCSV = fileName.toLowerCase().endsWith(".csv");
|
|
2954
2954
|
let rawData = [];
|
|
@@ -2957,10 +2957,13 @@ async function parseUploadedFile(file) {
|
|
|
2957
2957
|
rawData = parseCSV(csvContent);
|
|
2958
2958
|
} else {
|
|
2959
2959
|
const workbook = XLSX.read(file.buffer, { type: "buffer" });
|
|
2960
|
-
const worksheetName = workbook.SheetNames[0];
|
|
2960
|
+
const worksheetName = sheetName || workbook.SheetNames[0];
|
|
2961
2961
|
if (!worksheetName) {
|
|
2962
2962
|
throw new Error("No worksheet found in file");
|
|
2963
2963
|
}
|
|
2964
|
+
if (sheetName && !workbook.SheetNames.includes(sheetName)) {
|
|
2965
|
+
throw new Error(`Sheet "${sheetName}" not found in workbook`);
|
|
2966
|
+
}
|
|
2964
2967
|
const worksheet = workbook.Sheets[worksheetName];
|
|
2965
2968
|
rawData = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
2966
2969
|
}
|
|
@@ -3567,12 +3570,14 @@ function exportAsJSON(controls, metadata, res) {
|
|
|
3567
3570
|
res.setHeader("Content-Disposition", `attachment; filename="${fileName}"`);
|
|
3568
3571
|
res.json(exportData);
|
|
3569
3572
|
}
|
|
3570
|
-
var router, upload, spreadsheetRoutes_default;
|
|
3573
|
+
var MAX_HEADER_CANDIDATES, PREVIEW_COLUMNS, router, upload, spreadsheetRoutes_default;
|
|
3571
3574
|
var init_spreadsheetRoutes = __esm({
|
|
3572
3575
|
"cli/server/spreadsheetRoutes.ts"() {
|
|
3573
3576
|
"use strict";
|
|
3574
3577
|
init_debug();
|
|
3575
3578
|
init_serverState();
|
|
3579
|
+
MAX_HEADER_CANDIDATES = 5;
|
|
3580
|
+
PREVIEW_COLUMNS = 4;
|
|
3576
3581
|
router = express.Router();
|
|
3577
3582
|
upload = multer({
|
|
3578
3583
|
storage: multer.memoryStorage(),
|
|
@@ -3585,7 +3590,8 @@ var init_spreadsheetRoutes = __esm({
|
|
|
3585
3590
|
return res.status(400).json({ error: "No file uploaded" });
|
|
3586
3591
|
}
|
|
3587
3592
|
const params = processImportParameters(req.body);
|
|
3588
|
-
const
|
|
3593
|
+
const sheetName = req.body.sheetName;
|
|
3594
|
+
const rawData = await parseUploadedFile(req.file, sheetName);
|
|
3589
3595
|
const startRowIndex = parseInt(params.startRow) - 1;
|
|
3590
3596
|
if (rawData.length <= startRowIndex) {
|
|
3591
3597
|
return res.status(400).json({ error: "Start row exceeds sheet data" });
|
|
@@ -3797,9 +3803,9 @@ var init_spreadsheetRoutes = __esm({
|
|
|
3797
3803
|
const worksheet = workbook.Sheets[worksheetName];
|
|
3798
3804
|
rows = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
3799
3805
|
}
|
|
3800
|
-
const headerCandidates = rows.slice(0,
|
|
3806
|
+
const headerCandidates = rows.slice(0, MAX_HEADER_CANDIDATES).map((row, index) => ({
|
|
3801
3807
|
row: index + 1,
|
|
3802
|
-
preview: row.slice(0,
|
|
3808
|
+
preview: row.slice(0, PREVIEW_COLUMNS).filter((v) => v !== null).filter((v) => v !== void 0).join(", ") + (row.length > 4 ? ", ..." : "")
|
|
3803
3809
|
}));
|
|
3804
3810
|
res.json({
|
|
3805
3811
|
sheets,
|
|
@@ -3856,6 +3862,39 @@ var init_spreadsheetRoutes = __esm({
|
|
|
3856
3862
|
res.status(500).json({ error: "Failed to parse Excel sheet" });
|
|
3857
3863
|
}
|
|
3858
3864
|
});
|
|
3865
|
+
router.post("/parse-excel-sheet-previews", upload.single("file"), async (req, res) => {
|
|
3866
|
+
try {
|
|
3867
|
+
const { sheetName } = req.body;
|
|
3868
|
+
if (!req.file) {
|
|
3869
|
+
return res.status(400).json({ error: "No file uploaded" });
|
|
3870
|
+
}
|
|
3871
|
+
const fileName = req.file.originalname || "";
|
|
3872
|
+
const isCSV = fileName.toLowerCase().endsWith(".csv");
|
|
3873
|
+
let rows = [];
|
|
3874
|
+
if (isCSV) {
|
|
3875
|
+
const csvContent = req.file.buffer.toString("utf-8");
|
|
3876
|
+
rows = parseCSV(csvContent);
|
|
3877
|
+
} else {
|
|
3878
|
+
const workbook = XLSX.read(req.file.buffer, { type: "buffer" });
|
|
3879
|
+
if (!workbook.SheetNames.includes(sheetName)) {
|
|
3880
|
+
return res.status(400).json({ error: `Sheet "${sheetName}" not found` });
|
|
3881
|
+
}
|
|
3882
|
+
const worksheet = workbook.Sheets[sheetName];
|
|
3883
|
+
rows = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
3884
|
+
}
|
|
3885
|
+
const headerCandidates = rows.slice(0, MAX_HEADER_CANDIDATES).map((row, index) => ({
|
|
3886
|
+
row: index + 1,
|
|
3887
|
+
preview: row.slice(0, PREVIEW_COLUMNS).filter((v) => v !== null).filter((v) => v !== void 0).join(", ") + (row.length > 4 ? ", ..." : "")
|
|
3888
|
+
}));
|
|
3889
|
+
res.json({
|
|
3890
|
+
rowPreviews: headerCandidates,
|
|
3891
|
+
totalRows: rows.length
|
|
3892
|
+
});
|
|
3893
|
+
} catch (error) {
|
|
3894
|
+
console.error("Error getting sheet previews:", error);
|
|
3895
|
+
res.status(500).json({ error: "Failed to get sheet previews" });
|
|
3896
|
+
}
|
|
3897
|
+
});
|
|
3859
3898
|
spreadsheetRoutes_default = router;
|
|
3860
3899
|
}
|
|
3861
3900
|
});
|
package/dist/cli/server/index.js
CHANGED
|
@@ -2930,7 +2930,7 @@ function processImportParameters(reqBody) {
|
|
|
2930
2930
|
frontendFieldSchema
|
|
2931
2931
|
};
|
|
2932
2932
|
}
|
|
2933
|
-
async function parseUploadedFile(file) {
|
|
2933
|
+
async function parseUploadedFile(file, sheetName) {
|
|
2934
2934
|
const fileName = file.originalname || "";
|
|
2935
2935
|
const isCSV = fileName.toLowerCase().endsWith(".csv");
|
|
2936
2936
|
let rawData = [];
|
|
@@ -2939,10 +2939,13 @@ async function parseUploadedFile(file) {
|
|
|
2939
2939
|
rawData = parseCSV(csvContent);
|
|
2940
2940
|
} else {
|
|
2941
2941
|
const workbook = XLSX.read(file.buffer, { type: "buffer" });
|
|
2942
|
-
const worksheetName = workbook.SheetNames[0];
|
|
2942
|
+
const worksheetName = sheetName || workbook.SheetNames[0];
|
|
2943
2943
|
if (!worksheetName) {
|
|
2944
2944
|
throw new Error("No worksheet found in file");
|
|
2945
2945
|
}
|
|
2946
|
+
if (sheetName && !workbook.SheetNames.includes(sheetName)) {
|
|
2947
|
+
throw new Error(`Sheet "${sheetName}" not found in workbook`);
|
|
2948
|
+
}
|
|
2946
2949
|
const worksheet = workbook.Sheets[worksheetName];
|
|
2947
2950
|
rawData = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
2948
2951
|
}
|
|
@@ -3549,12 +3552,14 @@ function exportAsJSON(controls, metadata, res) {
|
|
|
3549
3552
|
res.setHeader("Content-Disposition", `attachment; filename="${fileName}"`);
|
|
3550
3553
|
res.json(exportData);
|
|
3551
3554
|
}
|
|
3552
|
-
var router, upload, spreadsheetRoutes_default;
|
|
3555
|
+
var MAX_HEADER_CANDIDATES, PREVIEW_COLUMNS, router, upload, spreadsheetRoutes_default;
|
|
3553
3556
|
var init_spreadsheetRoutes = __esm({
|
|
3554
3557
|
"cli/server/spreadsheetRoutes.ts"() {
|
|
3555
3558
|
"use strict";
|
|
3556
3559
|
init_debug();
|
|
3557
3560
|
init_serverState();
|
|
3561
|
+
MAX_HEADER_CANDIDATES = 5;
|
|
3562
|
+
PREVIEW_COLUMNS = 4;
|
|
3558
3563
|
router = express.Router();
|
|
3559
3564
|
upload = multer({
|
|
3560
3565
|
storage: multer.memoryStorage(),
|
|
@@ -3567,7 +3572,8 @@ var init_spreadsheetRoutes = __esm({
|
|
|
3567
3572
|
return res.status(400).json({ error: "No file uploaded" });
|
|
3568
3573
|
}
|
|
3569
3574
|
const params = processImportParameters(req.body);
|
|
3570
|
-
const
|
|
3575
|
+
const sheetName = req.body.sheetName;
|
|
3576
|
+
const rawData = await parseUploadedFile(req.file, sheetName);
|
|
3571
3577
|
const startRowIndex = parseInt(params.startRow) - 1;
|
|
3572
3578
|
if (rawData.length <= startRowIndex) {
|
|
3573
3579
|
return res.status(400).json({ error: "Start row exceeds sheet data" });
|
|
@@ -3779,9 +3785,9 @@ var init_spreadsheetRoutes = __esm({
|
|
|
3779
3785
|
const worksheet = workbook.Sheets[worksheetName];
|
|
3780
3786
|
rows = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
3781
3787
|
}
|
|
3782
|
-
const headerCandidates = rows.slice(0,
|
|
3788
|
+
const headerCandidates = rows.slice(0, MAX_HEADER_CANDIDATES).map((row, index) => ({
|
|
3783
3789
|
row: index + 1,
|
|
3784
|
-
preview: row.slice(0,
|
|
3790
|
+
preview: row.slice(0, PREVIEW_COLUMNS).filter((v) => v !== null).filter((v) => v !== void 0).join(", ") + (row.length > 4 ? ", ..." : "")
|
|
3785
3791
|
}));
|
|
3786
3792
|
res.json({
|
|
3787
3793
|
sheets,
|
|
@@ -3838,6 +3844,39 @@ var init_spreadsheetRoutes = __esm({
|
|
|
3838
3844
|
res.status(500).json({ error: "Failed to parse Excel sheet" });
|
|
3839
3845
|
}
|
|
3840
3846
|
});
|
|
3847
|
+
router.post("/parse-excel-sheet-previews", upload.single("file"), async (req, res) => {
|
|
3848
|
+
try {
|
|
3849
|
+
const { sheetName } = req.body;
|
|
3850
|
+
if (!req.file) {
|
|
3851
|
+
return res.status(400).json({ error: "No file uploaded" });
|
|
3852
|
+
}
|
|
3853
|
+
const fileName = req.file.originalname || "";
|
|
3854
|
+
const isCSV = fileName.toLowerCase().endsWith(".csv");
|
|
3855
|
+
let rows = [];
|
|
3856
|
+
if (isCSV) {
|
|
3857
|
+
const csvContent = req.file.buffer.toString("utf-8");
|
|
3858
|
+
rows = parseCSV(csvContent);
|
|
3859
|
+
} else {
|
|
3860
|
+
const workbook = XLSX.read(req.file.buffer, { type: "buffer" });
|
|
3861
|
+
if (!workbook.SheetNames.includes(sheetName)) {
|
|
3862
|
+
return res.status(400).json({ error: `Sheet "${sheetName}" not found` });
|
|
3863
|
+
}
|
|
3864
|
+
const worksheet = workbook.Sheets[sheetName];
|
|
3865
|
+
rows = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
3866
|
+
}
|
|
3867
|
+
const headerCandidates = rows.slice(0, MAX_HEADER_CANDIDATES).map((row, index) => ({
|
|
3868
|
+
row: index + 1,
|
|
3869
|
+
preview: row.slice(0, PREVIEW_COLUMNS).filter((v) => v !== null).filter((v) => v !== void 0).join(", ") + (row.length > 4 ? ", ..." : "")
|
|
3870
|
+
}));
|
|
3871
|
+
res.json({
|
|
3872
|
+
rowPreviews: headerCandidates,
|
|
3873
|
+
totalRows: rows.length
|
|
3874
|
+
});
|
|
3875
|
+
} catch (error) {
|
|
3876
|
+
console.error("Error getting sheet previews:", error);
|
|
3877
|
+
res.status(500).json({ error: "Failed to get sheet previews" });
|
|
3878
|
+
}
|
|
3879
|
+
});
|
|
3841
3880
|
spreadsheetRoutes_default = router;
|
|
3842
3881
|
}
|
|
3843
3882
|
});
|
|
@@ -2930,7 +2930,7 @@ function processImportParameters(reqBody) {
|
|
|
2930
2930
|
frontendFieldSchema
|
|
2931
2931
|
};
|
|
2932
2932
|
}
|
|
2933
|
-
async function parseUploadedFile(file) {
|
|
2933
|
+
async function parseUploadedFile(file, sheetName) {
|
|
2934
2934
|
const fileName = file.originalname || "";
|
|
2935
2935
|
const isCSV = fileName.toLowerCase().endsWith(".csv");
|
|
2936
2936
|
let rawData = [];
|
|
@@ -2939,10 +2939,13 @@ async function parseUploadedFile(file) {
|
|
|
2939
2939
|
rawData = parseCSV(csvContent);
|
|
2940
2940
|
} else {
|
|
2941
2941
|
const workbook = XLSX.read(file.buffer, { type: "buffer" });
|
|
2942
|
-
const worksheetName = workbook.SheetNames[0];
|
|
2942
|
+
const worksheetName = sheetName || workbook.SheetNames[0];
|
|
2943
2943
|
if (!worksheetName) {
|
|
2944
2944
|
throw new Error("No worksheet found in file");
|
|
2945
2945
|
}
|
|
2946
|
+
if (sheetName && !workbook.SheetNames.includes(sheetName)) {
|
|
2947
|
+
throw new Error(`Sheet "${sheetName}" not found in workbook`);
|
|
2948
|
+
}
|
|
2946
2949
|
const worksheet = workbook.Sheets[worksheetName];
|
|
2947
2950
|
rawData = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
2948
2951
|
}
|
|
@@ -3549,12 +3552,14 @@ function exportAsJSON(controls, metadata, res) {
|
|
|
3549
3552
|
res.setHeader("Content-Disposition", `attachment; filename="${fileName}"`);
|
|
3550
3553
|
res.json(exportData);
|
|
3551
3554
|
}
|
|
3552
|
-
var router, upload, spreadsheetRoutes_default;
|
|
3555
|
+
var MAX_HEADER_CANDIDATES, PREVIEW_COLUMNS, router, upload, spreadsheetRoutes_default;
|
|
3553
3556
|
var init_spreadsheetRoutes = __esm({
|
|
3554
3557
|
"cli/server/spreadsheetRoutes.ts"() {
|
|
3555
3558
|
"use strict";
|
|
3556
3559
|
init_debug();
|
|
3557
3560
|
init_serverState();
|
|
3561
|
+
MAX_HEADER_CANDIDATES = 5;
|
|
3562
|
+
PREVIEW_COLUMNS = 4;
|
|
3558
3563
|
router = express.Router();
|
|
3559
3564
|
upload = multer({
|
|
3560
3565
|
storage: multer.memoryStorage(),
|
|
@@ -3567,7 +3572,8 @@ var init_spreadsheetRoutes = __esm({
|
|
|
3567
3572
|
return res.status(400).json({ error: "No file uploaded" });
|
|
3568
3573
|
}
|
|
3569
3574
|
const params = processImportParameters(req.body);
|
|
3570
|
-
const
|
|
3575
|
+
const sheetName = req.body.sheetName;
|
|
3576
|
+
const rawData = await parseUploadedFile(req.file, sheetName);
|
|
3571
3577
|
const startRowIndex = parseInt(params.startRow) - 1;
|
|
3572
3578
|
if (rawData.length <= startRowIndex) {
|
|
3573
3579
|
return res.status(400).json({ error: "Start row exceeds sheet data" });
|
|
@@ -3779,9 +3785,9 @@ var init_spreadsheetRoutes = __esm({
|
|
|
3779
3785
|
const worksheet = workbook.Sheets[worksheetName];
|
|
3780
3786
|
rows = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
3781
3787
|
}
|
|
3782
|
-
const headerCandidates = rows.slice(0,
|
|
3788
|
+
const headerCandidates = rows.slice(0, MAX_HEADER_CANDIDATES).map((row, index) => ({
|
|
3783
3789
|
row: index + 1,
|
|
3784
|
-
preview: row.slice(0,
|
|
3790
|
+
preview: row.slice(0, PREVIEW_COLUMNS).filter((v) => v !== null).filter((v) => v !== void 0).join(", ") + (row.length > 4 ? ", ..." : "")
|
|
3785
3791
|
}));
|
|
3786
3792
|
res.json({
|
|
3787
3793
|
sheets,
|
|
@@ -3838,6 +3844,39 @@ var init_spreadsheetRoutes = __esm({
|
|
|
3838
3844
|
res.status(500).json({ error: "Failed to parse Excel sheet" });
|
|
3839
3845
|
}
|
|
3840
3846
|
});
|
|
3847
|
+
router.post("/parse-excel-sheet-previews", upload.single("file"), async (req, res) => {
|
|
3848
|
+
try {
|
|
3849
|
+
const { sheetName } = req.body;
|
|
3850
|
+
if (!req.file) {
|
|
3851
|
+
return res.status(400).json({ error: "No file uploaded" });
|
|
3852
|
+
}
|
|
3853
|
+
const fileName = req.file.originalname || "";
|
|
3854
|
+
const isCSV = fileName.toLowerCase().endsWith(".csv");
|
|
3855
|
+
let rows = [];
|
|
3856
|
+
if (isCSV) {
|
|
3857
|
+
const csvContent = req.file.buffer.toString("utf-8");
|
|
3858
|
+
rows = parseCSV(csvContent);
|
|
3859
|
+
} else {
|
|
3860
|
+
const workbook = XLSX.read(req.file.buffer, { type: "buffer" });
|
|
3861
|
+
if (!workbook.SheetNames.includes(sheetName)) {
|
|
3862
|
+
return res.status(400).json({ error: `Sheet "${sheetName}" not found` });
|
|
3863
|
+
}
|
|
3864
|
+
const worksheet = workbook.Sheets[sheetName];
|
|
3865
|
+
rows = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
3866
|
+
}
|
|
3867
|
+
const headerCandidates = rows.slice(0, MAX_HEADER_CANDIDATES).map((row, index) => ({
|
|
3868
|
+
row: index + 1,
|
|
3869
|
+
preview: row.slice(0, PREVIEW_COLUMNS).filter((v) => v !== null).filter((v) => v !== void 0).join(", ") + (row.length > 4 ? ", ..." : "")
|
|
3870
|
+
}));
|
|
3871
|
+
res.json({
|
|
3872
|
+
rowPreviews: headerCandidates,
|
|
3873
|
+
totalRows: rows.length
|
|
3874
|
+
});
|
|
3875
|
+
} catch (error) {
|
|
3876
|
+
console.error("Error getting sheet previews:", error);
|
|
3877
|
+
res.status(500).json({ error: "Failed to get sheet previews" });
|
|
3878
|
+
}
|
|
3879
|
+
});
|
|
3841
3880
|
spreadsheetRoutes_default = router;
|
|
3842
3881
|
}
|
|
3843
3882
|
});
|
|
@@ -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" });
|
|
@@ -969,9 +975,9 @@ router.post("/parse-excel", upload.single("file"), async (req, res) => {
|
|
|
969
975
|
const worksheet = workbook.Sheets[worksheetName];
|
|
970
976
|
rows = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
971
977
|
}
|
|
972
|
-
const headerCandidates = rows.slice(0,
|
|
978
|
+
const headerCandidates = rows.slice(0, MAX_HEADER_CANDIDATES).map((row, index) => ({
|
|
973
979
|
row: index + 1,
|
|
974
|
-
preview: row.slice(0,
|
|
980
|
+
preview: row.slice(0, PREVIEW_COLUMNS).filter((v) => v !== null).filter((v) => v !== void 0).join(", ") + (row.length > 4 ? ", ..." : "")
|
|
975
981
|
}));
|
|
976
982
|
res.json({
|
|
977
983
|
sheets,
|
|
@@ -1028,6 +1034,39 @@ router.post("/parse-excel-sheet", upload.single("file"), async (req, res) => {
|
|
|
1028
1034
|
res.status(500).json({ error: "Failed to parse Excel sheet" });
|
|
1029
1035
|
}
|
|
1030
1036
|
});
|
|
1037
|
+
router.post("/parse-excel-sheet-previews", upload.single("file"), async (req, res) => {
|
|
1038
|
+
try {
|
|
1039
|
+
const { sheetName } = req.body;
|
|
1040
|
+
if (!req.file) {
|
|
1041
|
+
return res.status(400).json({ error: "No file uploaded" });
|
|
1042
|
+
}
|
|
1043
|
+
const fileName = req.file.originalname || "";
|
|
1044
|
+
const isCSV = fileName.toLowerCase().endsWith(".csv");
|
|
1045
|
+
let rows = [];
|
|
1046
|
+
if (isCSV) {
|
|
1047
|
+
const csvContent = req.file.buffer.toString("utf-8");
|
|
1048
|
+
rows = parseCSV(csvContent);
|
|
1049
|
+
} else {
|
|
1050
|
+
const workbook = XLSX.read(req.file.buffer, { type: "buffer" });
|
|
1051
|
+
if (!workbook.SheetNames.includes(sheetName)) {
|
|
1052
|
+
return res.status(400).json({ error: `Sheet "${sheetName}" not found` });
|
|
1053
|
+
}
|
|
1054
|
+
const worksheet = workbook.Sheets[sheetName];
|
|
1055
|
+
rows = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
1056
|
+
}
|
|
1057
|
+
const headerCandidates = rows.slice(0, MAX_HEADER_CANDIDATES).map((row, index) => ({
|
|
1058
|
+
row: index + 1,
|
|
1059
|
+
preview: row.slice(0, PREVIEW_COLUMNS).filter((v) => v !== null).filter((v) => v !== void 0).join(", ") + (row.length > 4 ? ", ..." : "")
|
|
1060
|
+
}));
|
|
1061
|
+
res.json({
|
|
1062
|
+
rowPreviews: headerCandidates,
|
|
1063
|
+
totalRows: rows.length
|
|
1064
|
+
});
|
|
1065
|
+
} catch (error) {
|
|
1066
|
+
console.error("Error getting sheet previews:", error);
|
|
1067
|
+
res.status(500).json({ error: "Failed to get sheet previews" });
|
|
1068
|
+
}
|
|
1069
|
+
});
|
|
1031
1070
|
var spreadsheetRoutes_default = router;
|
|
1032
1071
|
export {
|
|
1033
1072
|
applyNamingConvention,
|
|
@@ -1377,7 +1377,7 @@ function processImportParameters(reqBody) {
|
|
|
1377
1377
|
frontendFieldSchema
|
|
1378
1378
|
};
|
|
1379
1379
|
}
|
|
1380
|
-
async function parseUploadedFile(file) {
|
|
1380
|
+
async function parseUploadedFile(file, sheetName) {
|
|
1381
1381
|
const fileName = file.originalname || "";
|
|
1382
1382
|
const isCSV = fileName.toLowerCase().endsWith(".csv");
|
|
1383
1383
|
let rawData = [];
|
|
@@ -1386,10 +1386,13 @@ async function parseUploadedFile(file) {
|
|
|
1386
1386
|
rawData = parseCSV(csvContent);
|
|
1387
1387
|
} else {
|
|
1388
1388
|
const workbook = XLSX.read(file.buffer, { type: "buffer" });
|
|
1389
|
-
const worksheetName = workbook.SheetNames[0];
|
|
1389
|
+
const worksheetName = sheetName || workbook.SheetNames[0];
|
|
1390
1390
|
if (!worksheetName) {
|
|
1391
1391
|
throw new Error("No worksheet found in file");
|
|
1392
1392
|
}
|
|
1393
|
+
if (sheetName && !workbook.SheetNames.includes(sheetName)) {
|
|
1394
|
+
throw new Error(`Sheet "${sheetName}" not found in workbook`);
|
|
1395
|
+
}
|
|
1393
1396
|
const worksheet = workbook.Sheets[worksheetName];
|
|
1394
1397
|
rawData = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
1395
1398
|
}
|
|
@@ -1996,12 +1999,14 @@ function exportAsJSON(controls, metadata, res) {
|
|
|
1996
1999
|
res.setHeader("Content-Disposition", `attachment; filename="${fileName}"`);
|
|
1997
2000
|
res.json(exportData);
|
|
1998
2001
|
}
|
|
1999
|
-
var router, upload, spreadsheetRoutes_default;
|
|
2002
|
+
var MAX_HEADER_CANDIDATES, PREVIEW_COLUMNS, router, upload, spreadsheetRoutes_default;
|
|
2000
2003
|
var init_spreadsheetRoutes = __esm({
|
|
2001
2004
|
"cli/server/spreadsheetRoutes.ts"() {
|
|
2002
2005
|
"use strict";
|
|
2003
2006
|
init_debug();
|
|
2004
2007
|
init_serverState();
|
|
2008
|
+
MAX_HEADER_CANDIDATES = 5;
|
|
2009
|
+
PREVIEW_COLUMNS = 4;
|
|
2005
2010
|
router = express.Router();
|
|
2006
2011
|
upload = multer({
|
|
2007
2012
|
storage: multer.memoryStorage(),
|
|
@@ -2014,7 +2019,8 @@ var init_spreadsheetRoutes = __esm({
|
|
|
2014
2019
|
return res.status(400).json({ error: "No file uploaded" });
|
|
2015
2020
|
}
|
|
2016
2021
|
const params = processImportParameters(req.body);
|
|
2017
|
-
const
|
|
2022
|
+
const sheetName = req.body.sheetName;
|
|
2023
|
+
const rawData = await parseUploadedFile(req.file, sheetName);
|
|
2018
2024
|
const startRowIndex = parseInt(params.startRow) - 1;
|
|
2019
2025
|
if (rawData.length <= startRowIndex) {
|
|
2020
2026
|
return res.status(400).json({ error: "Start row exceeds sheet data" });
|
|
@@ -2226,9 +2232,9 @@ var init_spreadsheetRoutes = __esm({
|
|
|
2226
2232
|
const worksheet = workbook.Sheets[worksheetName];
|
|
2227
2233
|
rows = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
2228
2234
|
}
|
|
2229
|
-
const headerCandidates = rows.slice(0,
|
|
2235
|
+
const headerCandidates = rows.slice(0, MAX_HEADER_CANDIDATES).map((row, index) => ({
|
|
2230
2236
|
row: index + 1,
|
|
2231
|
-
preview: row.slice(0,
|
|
2237
|
+
preview: row.slice(0, PREVIEW_COLUMNS).filter((v) => v !== null).filter((v) => v !== void 0).join(", ") + (row.length > 4 ? ", ..." : "")
|
|
2232
2238
|
}));
|
|
2233
2239
|
res.json({
|
|
2234
2240
|
sheets,
|
|
@@ -2285,6 +2291,39 @@ var init_spreadsheetRoutes = __esm({
|
|
|
2285
2291
|
res.status(500).json({ error: "Failed to parse Excel sheet" });
|
|
2286
2292
|
}
|
|
2287
2293
|
});
|
|
2294
|
+
router.post("/parse-excel-sheet-previews", upload.single("file"), async (req, res) => {
|
|
2295
|
+
try {
|
|
2296
|
+
const { sheetName } = req.body;
|
|
2297
|
+
if (!req.file) {
|
|
2298
|
+
return res.status(400).json({ error: "No file uploaded" });
|
|
2299
|
+
}
|
|
2300
|
+
const fileName = req.file.originalname || "";
|
|
2301
|
+
const isCSV = fileName.toLowerCase().endsWith(".csv");
|
|
2302
|
+
let rows = [];
|
|
2303
|
+
if (isCSV) {
|
|
2304
|
+
const csvContent = req.file.buffer.toString("utf-8");
|
|
2305
|
+
rows = parseCSV(csvContent);
|
|
2306
|
+
} else {
|
|
2307
|
+
const workbook = XLSX.read(req.file.buffer, { type: "buffer" });
|
|
2308
|
+
if (!workbook.SheetNames.includes(sheetName)) {
|
|
2309
|
+
return res.status(400).json({ error: `Sheet "${sheetName}" not found` });
|
|
2310
|
+
}
|
|
2311
|
+
const worksheet = workbook.Sheets[sheetName];
|
|
2312
|
+
rows = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null });
|
|
2313
|
+
}
|
|
2314
|
+
const headerCandidates = rows.slice(0, MAX_HEADER_CANDIDATES).map((row, index) => ({
|
|
2315
|
+
row: index + 1,
|
|
2316
|
+
preview: row.slice(0, PREVIEW_COLUMNS).filter((v) => v !== null).filter((v) => v !== void 0).join(", ") + (row.length > 4 ? ", ..." : "")
|
|
2317
|
+
}));
|
|
2318
|
+
res.json({
|
|
2319
|
+
rowPreviews: headerCandidates,
|
|
2320
|
+
totalRows: rows.length
|
|
2321
|
+
});
|
|
2322
|
+
} catch (error) {
|
|
2323
|
+
console.error("Error getting sheet previews:", error);
|
|
2324
|
+
res.status(500).json({ error: "Failed to get sheet previews" });
|
|
2325
|
+
}
|
|
2326
|
+
});
|
|
2288
2327
|
spreadsheetRoutes_default = router;
|
|
2289
2328
|
}
|
|
2290
2329
|
});
|