lula2 0.3.3 → 0.3.4-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.
Files changed (56) hide show
  1. package/dist/_app/immutable/assets/0.D6CB7gA7.css +1 -0
  2. package/dist/_app/immutable/chunks/BITsSGhD.js +65 -0
  3. package/dist/_app/immutable/chunks/BcKIo18J.js +3 -0
  4. package/dist/_app/immutable/chunks/{C9p1zaS8.js → BhjtS45v.js} +1 -1
  5. package/dist/_app/immutable/chunks/{cvagBx-i.js → BkFSJLu9.js} +1 -1
  6. package/dist/_app/immutable/chunks/CHdfnWSV.js +1 -0
  7. package/dist/_app/immutable/chunks/{ZLxiKtk1.js → CzIDw1HQ.js} +1 -1
  8. package/dist/_app/immutable/chunks/{DkTmghUd.js → DknPZycG.js} +1 -1
  9. package/dist/_app/immutable/chunks/{C2RwV308.js → DwdPeWTx.js} +1 -1
  10. package/dist/_app/immutable/chunks/{EhHGBAhB.js → vNis_B2V.js} +1 -1
  11. package/dist/_app/immutable/entry/{app.DlQKiOqI.js → app.rFT55pRO.js} +2 -2
  12. package/dist/_app/immutable/entry/start.BWvTyytY.js +1 -0
  13. package/dist/_app/immutable/nodes/{0.BebGxk-A.js → 0.CMylckYT.js} +1 -1
  14. package/dist/_app/immutable/nodes/{1.DfUs1HjM.js → 1.DPLsosR-.js} +1 -1
  15. package/dist/_app/immutable/nodes/{2.CrOeZTVE.js → 2.DvLMOmaz.js} +1 -1
  16. package/dist/_app/immutable/nodes/{3.D6SgInYh.js → 3.hM9U_7ZV.js} +1 -1
  17. package/dist/_app/immutable/nodes/4.DNVoxjQw.js +11 -0
  18. package/dist/_app/version.json +1 -1
  19. package/dist/cli/commands/ui.js +10 -10
  20. package/dist/cli/server/index.js +10 -10
  21. package/dist/cli/server/server.js +10 -10
  22. package/dist/cli/server/websocketServer.js +10 -10
  23. package/dist/index.html +10 -10
  24. package/dist/index.js +10 -10
  25. package/package.json +20 -21
  26. package/src/lib/components/control-sets/ControlSetSelector.svelte +1 -1
  27. package/src/lib/components/controls/ControlDetailsPanel.svelte +1 -1
  28. package/src/lib/components/controls/ControlsList.svelte +4 -48
  29. package/src/lib/components/controls/DynamicControlEditor.svelte +2 -2
  30. package/src/lib/components/controls/MappingCard.svelte +1 -1
  31. package/src/lib/components/controls/MappingForm.svelte +1 -1
  32. package/src/lib/components/controls/renderers/EditableFieldRenderer.svelte +1 -1
  33. package/src/lib/components/controls/renderers/FieldRenderer.svelte +2 -2
  34. package/src/lib/components/controls/tabs/CustomFieldsTab.svelte +2 -2
  35. package/src/lib/components/controls/tabs/ImplementationTab.svelte +3 -3
  36. package/src/lib/components/controls/tabs/MappingsTab.svelte +1 -1
  37. package/src/lib/components/controls/tabs/OverviewTab.svelte +4 -4
  38. package/src/lib/components/controls/tabs/TimelineTab.svelte +2 -3
  39. package/src/lib/components/controls/utils/ProcessedTextRenderer.svelte +4 -4
  40. package/src/lib/components/forms/DynamicControlForm.svelte +10 -10
  41. package/src/lib/components/forms/DynamicField.svelte +4 -4
  42. package/src/lib/components/forms/FormField.svelte +1 -1
  43. package/src/lib/components/setup/ExistingControlSets.svelte +1 -1
  44. package/src/lib/components/setup/SpreadsheetImport.svelte +8 -10
  45. package/src/lib/components/ui/CustomDropdown.svelte +1 -1
  46. package/src/lib/components/ui/FilterBuilder.svelte +4 -4
  47. package/src/lib/components/ui/TabNavigation.svelte +1 -1
  48. package/src/lib/components/version-control/DiffViewer.svelte +1 -1
  49. package/src/lib/components/version-control/YamlDiffViewer.svelte +2 -2
  50. package/src/stores/compliance.ts +2 -69
  51. package/dist/_app/immutable/assets/0.BeyRWDYp.css +0 -1
  52. package/dist/_app/immutable/chunks/BTTmO90G.js +0 -65
  53. package/dist/_app/immutable/chunks/Dz_3mPpR.js +0 -1
  54. package/dist/_app/immutable/chunks/z5X83jua.js +0 -3
  55. package/dist/_app/immutable/entry/start.CuPBZjFh.js +0 -1
  56. package/dist/_app/immutable/nodes/4.Be0URtGy.js +0 -11
@@ -0,0 +1,11 @@
1
+ import"../chunks/DsnmJJEf.js";import{i as Je}from"../chunks/DknPZycG.js";import{p as Ye,am as Te,d as o,T as k,G as ge,h as e,an as $r,ao as Ve,c as a,n as _e,r as t,b as d,e as We,J as F,K as E,ap as Lr,f as h,s as i,aq as g,a as ye,ar as mr,aj as Me,a0 as De,ak as hr,al as rr,as as yr,k as de,o as ot,W as lt}from"../chunks/BhjtS45v.js";import{l as tr,p as Ue,i as M,a as st,s as it}from"../chunks/DwdPeWTx.js";import{a as Nr,s as se,r as Vr,e as ce,b as qe,c as jr,d as _r,i as Cr,f as Sr,w as wr}from"../chunks/CzIDw1HQ.js";import{g as nt}from"../chunks/BcKIo18J.js";function dt(pe){return function(...q){var z=q[0];return z.stopPropagation(),pe?.apply(this,q)}}var vt=Ve("<title> </title>"),ct=Ve('<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(pe,q){const z=tr(q,["children","$$slots","$$events","$$legacy"]),X=tr(z,["size","title"]);Ye(q,!1);const O=k(),L=k();let N=Ue(q,"size",8,16),f=Ue(q,"title",8,void 0);Te(()=>(ge(z),ge(f())),()=>{o(O,z["aria-label"]||z["aria-labelledby"]||f())}),Te(()=>(e(O),ge(z)),()=>{o(L,{"aria-hidden":e(O)?void 0:!0,role:e(O)?"img":void 0,focusable:Number(z.tabindex)===0?!0:void 0})}),$r(),Je();var S=ct();Nr(S,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:N(),height:N(),...e(L),...X}));var K=a(S);{var re=P=>{var p=vt(),U=a(p,!0);t(p),F(()=>E(U,f())),d(P,p)};M(K,P=>{f()&&P(re)})}_e(2),t(S),d(pe,S),We()}var pt=Ve("<title> </title>"),ut=Ve('<svg><!><path d="M10 6H14V10H10zM18 6H22V10H18zM10 14H14V18H10zM18 14H22V18H18zM10 22H14V26H10zM18 22H22V26H18z"></path></svg>');function kr(pe,q){const z=tr(q,["children","$$slots","$$events","$$legacy"]),X=tr(z,["size","title"]);Ye(q,!1);const O=k(),L=k();let N=Ue(q,"size",8,16),f=Ue(q,"title",8,void 0);Te(()=>(ge(z),ge(f())),()=>{o(O,z["aria-label"]||z["aria-labelledby"]||f())}),Te(()=>(e(O),ge(z)),()=>{o(L,{"aria-hidden":e(O)?void 0:!0,role:e(O)?"img":void 0,focusable:Number(z.tabindex)===0?!0:void 0})}),$r(),Je();var S=ut();Nr(S,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:N(),height:N(),...e(L),...X}));var K=a(S);{var re=P=>{var p=pt(),U=a(p,!0);t(p),F(()=>E(U,f())),d(P,p)};M(K,P=>{f()&&P(re)})}_e(),t(S),d(pe,S),We()}var bt=h('<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=h('<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>'),xt=h('<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>'),mt=h("<option> </option>"),ht=h("<option> </option>"),yt=h("<option> </option>"),_t=h('<span class="ml-auto text-xs text-blue-600 dark:text-blue-400">ID</span>'),wt=h('<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=h('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">No excluded fields</p>'),Ct=h('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),St=h('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p>'),$t=h('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),Dt=h('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p>'),Mt=h('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),zt=h('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p>'),At=h('<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=h('<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=h('<th class="px-4 py-2"> </th>'),Pt=h('<td class="px-4 py-2"> </td>'),Ht=h('<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700"></tr>'),Et=h('<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=h('<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=h(`<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),Vt=h('<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 jt(pe,q){Ye(q,!1);const z=Lr();let X=k(null),O=k(""),L=k(""),N=k([]),f=k([]),S=k([]),K=k(0),re=k([]),P=k([]),p=k(new Map),U=k(1),V=k(""),fe=k(""),J=k(""),G=k(!1),Q=k(""),ue=k(""),we=k(!1),te=k(!1),$=k(null),B=k(null),ae=k(null);function ke(){o(f,[]),o(S,[]),o(K,0),e(p).clear(),o(p,new Map),o(P,[]),o(V,""),o(Q,""),o(ue,""),o($,null),o(B,null),o(ae,null)}function u(l){l.preventDefault(),o(te,!0)}function b(){o(te,!1)}function D(l){l.preventDefault(),o(te,!1);const n=l.dataTransfer?.files;n&&n.length>0&&I(n[0])}function T(l){const n=l.target;n.files&&n.files.length>0&&I(n.files[0])}async function I(l){ke(),o(O,l.name),o(X,l),o(Q,""),o(G,!0),o(fe,e(O).replace(/\.[^.]+$/,"").replace(/[-_]/g," ")),o(J,`Imported from ${e(O)}`);try{const n=new FormData;n.append("file",l);const y=await fetch("/api/parse-excel",{method:"POST",body:n});if(!y.ok){const w=await y.json();throw new Error(w.error||"Failed to parse file")}const _=await y.json();o(N,_.sheets||[]),o(L,_.selectedSheet||e(N)[0]),o(re,_.rowPreviews||[]),e(re).length>0&&e(U)===1&&o(U,e(re)[0].row),await Z(),o(we,!0)}catch(n){o(Q,"Error reading file: "+n.message)}finally{o(G,!1)}}async function Z(){if(!(!e(X)||!e(L))){o(G,!0),e(p).clear(),o(p,new Map),o(V,"");try{const l=new FormData;l.append("file",e(X)),l.append("sheetName",e(L)),l.append("headerRow",e(U).toString());const n=await fetch("/api/parse-excel-sheet",{method:"POST",body:l});if(!n.ok){const _=await n.json();throw new Error(_.error||"Failed to parse sheet")}const y=await n.json();if(o(f,y.fields||[]),o(S,y.sampleData||[]),o(K,y.controlCount||0),e(f).forEach((_,w)=>{const v=_.toLowerCase();let H="custom",R="text";v.includes("implementation")||v.includes("status")||v.includes("narrative")||v.includes("guidance")?H="implementation":(v.includes("id")||v.includes("title")||v.includes("family")||v.includes("cci")||v.includes("control")||v.includes("acronym"))&&(H="overview"),v.includes("description")||v.includes("narrative")||v.includes("guidance")||v.includes("statement")?R="textarea":v.includes("status")||v.includes("type")||v.includes("designation")?R="select":v.includes("date")?R="date":(v.includes("count")||v.includes("number"))&&(R="number"),e(p).set(_,{originalName:_,tab:H,displayOrder:w,fieldType:R,required:v.includes("id")||v.includes("title")})}),o(p,e(p)),e(V)&&!e(f).includes(e(V))&&o(V,""),!e(V)&&e(f).includes("AP Acronym")){const _=!e(S).length||e(S).every(ee=>!ee["AP Acronym"]||String(ee["AP Acronym"]).length<25),w=e(S).map(ee=>ee["AP Acronym"]).filter(ee=>ee!=null&&ee!==""&&String(ee).trim()!==""),v=new Set(w),H=!w.length||v.size===w.length,R=w.length>0;_&&H&&R&&o(V,"AP Acronym")}}catch(l){o(Q,"Error loading sheet data: "+l.message)}finally{o(G,!1)}}}function ve(l){if(!l)return l;let n=l.trim().replace(/\r?\n/g," ").replace(/\s+/g," ").trim();return je(n)}function je(l){return l.replace(/\W+/g," ").split(/ |\s/).map(n=>n.toLowerCase()).join("-")}function xe(l,n){o($,n),l.dataTransfer&&(l.dataTransfer.effectAllowed="move",l.dataTransfer.setData("text/plain",n))}function oe(){o($,null),o(B,null),o(ae,null)}function C(l,n){l.preventDefault(),o(B,n),l.dataTransfer&&(l.dataTransfer.dropEffect="move")}function ie(){o(B,null)}function ne(l,n,y){if(l.preventDefault(),e($)&&e(p).has(e($))){const _=e(p).get(e($));if(n==="mappings")e(P).includes(e($))||o(P,[...e(P),e($)]);else{if(_.tab=n,y!==void 0&&n!==null){const v=Array.from(e(p).entries()).filter(([H,R])=>R.tab===n).sort((H,R)=>H[1].displayOrder-R[1].displayOrder).filter(([H])=>H!==e($));v.splice(y,0,[e($),_]),v.forEach(([H,R],ee)=>{R.displayOrder=ee,e(p).set(H,R)})}else if(n!==null){const w=Math.max(0,...Array.from(e(p).values()).filter(v=>v.tab===n).map(v=>v.displayOrder));_.displayOrder=w+1}e(p).set(e($),_),o(p,e(p))}}o($,null),o(B,null)}function ze(l,n){l.preventDefault(),l.stopPropagation(),o(ae,n)}function Ce(){o(ae,null)}function Se(l,n,y){if(l.preventDefault(),l.stopPropagation(),e($)&&e($)!==n){const w=Array.from(e(p).entries()).filter(([v,H])=>H.tab===y).sort((v,H)=>v[1].displayOrder-H[1].displayOrder).findIndex(([v])=>v===n);w!==-1&&ne(l,y,w)}o(ae,null)}async function Le(){if(!(!e(X)||!e(O))){if(!e(V)){o(Q,"Please select a Control ID field before importing"),o(ue,"");return}if(!e(fe)||e(fe).trim()===""){o(Q,"Please enter a Control Set Name before importing"),o(ue,"");return}o(G,!0),o(Q,""),o(ue,"");try{const l=new FormData;l.append("file",e(X),e(O)),l.append("controlIdField",e(V)),l.append("startRow",e(U).toString()),l.append("namingConvention","kebab-case"),l.append("skipEmpty","true"),l.append("skipEmptyRows","true"),l.append("controlSetName",e(fe)||e(O).replace(/\.[^.]+$/,"")),l.append("controlSetDescription",e(J)||`Imported from ${e(O)}`);const n=Array.from(e(p).entries()).filter(([w,v])=>v.tab!==null).map(([w,v])=>({fieldName:ve(w),...v}));l.append("fieldSchema",JSON.stringify(n)),l.append("justificationFields",JSON.stringify(e(P).map(w=>ve(w))));const y=await fetch("/api/import-spreadsheet",{method:"POST",body:l});if(!y.ok){const w=await y.json();throw new Error(w.error||"Import failed")}const _=await y.json();o(ue,`Successfully imported ${_.controlCount} controls into ${_.families.length} families`),z("created",{path:_.outputDir})}catch(l){o(Q,"Error importing spreadsheet: "+l.message)}finally{o(G,!1)}}}Je();var Ne=Vt(),me=a(Ne),Be=a(me),Ae=a(Be),ar=a(Ae);gt(ar,{class:"w-8 h-8 mb-4 text-gray-500 dark:text-gray-400"}),_e(4),t(Ae);var Xe=i(Ae,2);t(Be),t(me);var Fe=i(me,2);{var or=l=>{var n=bt(),y=a(n),_=i(a(y),2),w=i(a(_)),v=i(w),H=i(a(v)),R=i(H,2),ee=i(R,2);t(v),t(_),t(y),t(n),F(()=>{E(w,` ${e(O)??""} `),E(H,` ${e(N).length??""} | `),E(R,` ${e(f).length??""} | `),E(ee,` ${e(K)??""}`)}),d(l,n)};M(Fe,l=>{e(O)&&l(or)})}var Ke=i(Fe,2);{var lr=l=>{var n=ft(),y=a(n),_=i(a(y),2),w=a(_,!0);t(_),t(y),t(n),F(()=>E(w,e(Q))),d(l,n)};M(Ke,l=>{e(Q)&&l(lr)})}var Ze=i(Ke,2);{var sr=l=>{var n=xt(),y=a(n),_=i(a(y),2),w=a(_,!0);t(_),t(y),t(n),F(()=>E(w,e(ue))),d(l,n)};M(Ze,l=>{e(ue)&&l(sr)})}var ir=i(Ze,2);{var nr=l=>{var n=Tt(),y=ye(n),_=i(a(y),2),w=a(_),v=i(a(w),2);Vr(v),_e(2),t(w);var H=i(w,2),R=i(a(H),2);Vr(R),_e(2),t(H),t(_);var ee=i(_,2),dr=a(ee),Ge=i(a(dr),2);F(()=>{e(L),mr(()=>{e(N)})}),ce(Ge,5,()=>e(N),r=>r,(r,s)=>{var x=mt(),m=a(x,!0);t(x);var c={};F(()=>{E(m,e(s)),c!==(c=e(s))&&(x.value=(x.__value=e(s))??"")}),d(r,x)}),t(Ge),_e(2),t(dr);var vr=i(dr,2),Qe=i(a(vr),2);F(()=>{e(U),mr(()=>{e(re)})}),ce(Qe,5,()=>e(re),r=>r.row,(r,s)=>{var x=ht(),m=a(x);t(x);var c={};F(()=>{E(m,`Row ${e(s).row??""}: ${e(s).preview??""}`),c!==(c=e(s).row)&&(x.value=(x.__value=e(s).row)??"")}),d(r,x)}),t(Qe),_e(2),t(vr);var Dr=i(vr,2),er=i(a(Dr),2);F(()=>{e(V),mr(()=>{e(f),e(S)})});var cr=a(er);cr.value=cr.__value="";var Br=i(cr);ce(Br,1,()=>e(f),r=>r,(r,s)=>{const x=De(()=>e(S).length>0&&e(S)[0][e(s)]?String(e(S)[0][e(s)]).slice(0,30):""),m=De(()=>!e(S).length||e(S).every(le=>!le[e(s)]||String(le[e(s)]).length<25)),c=De(()=>e(S).map(le=>le[e(s)]).filter(le=>le!=null&&le!==""&&String(le).trim()!=="")),Y=De(()=>new Set(e(c))),W=De(()=>!e(c).length||e(Y).size===e(c).length),j=De(()=>e(c).length>0);var A=Me(),be=ye(A);{var $e=le=>{var he=yt(),xr=a(he);t(he);var Tr={};F(()=>{E(xr,`${e(s)??""}${e(x)?` (e.g., ${e(x)})`:""}`),Tr!==(Tr=e(s))&&(he.value=(he.__value=e(s))??"")}),d(le,he)};M(be,le=>{e(m)&&e(W)&&e(j)&&le($e)})}d(r,A)}),t(er),_e(2),t(Dr),t(ee),t(y);var gr=i(y,2),Mr=i(a(gr),4),pr=a(Mr),Oe=i(a(pr),2),zr=a(Oe);ce(zr,1,()=>e(f).filter(r=>!e(p).get(r)||e(p).get(r)?.tab===null),r=>r,(r,s)=>{var x=wt(),m=i(a(x),2),c=a(m,!0);t(m);var Y=i(m,2);{var W=j=>{var A=_t();d(j,A)};M(Y,j=>{e(s)===e(V)&&j(W)})}t(x),F(()=>{qe(x,"aria-label",`Drag ${e(s)??""} field`),E(c,e(s))}),g("dragstart",x,j=>xe(j,e(s))),g("dragend",x,oe),d(r,x)});var Zr=i(zr,2);{var Rr=r=>{var s=kt();d(r,s)};M(Zr,r=>{e(f).filter(s=>!e(p).get(s)||e(p).get(s)?.tab===null).length===0&&r(Rr)})}t(Oe),t(pr);var ur=i(pr,2),Pe=i(a(ur),2),Ar=a(Pe);ce(Ar,3,()=>Array.from(e(p).entries()).filter(([r,s])=>s.tab==="overview").sort((r,s)=>r[1].displayOrder-s[1].displayOrder),([r,s])=>r,(r,s)=>{var x=hr(()=>yr(e(s),2));let m=()=>e(x)[0];var c=Ct(),Y=a(c);kr(Y,{class:"w-3 h-3 mr-2 flex-shrink-0"});var W=i(Y,2),j=a(W,!0);t(W),t(c),F(()=>{qe(c,"aria-label",`${m()??""} field in Overview tab`),se(c,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(ae)===m()&&e($)!==m()?"border-t-2 border-blue-500":""}`),E(j,m())}),g("dragstart",c,A=>xe(A,m())),g("dragend",c,oe),g("dragover",c,A=>ze(A,m())),g("dragleave",c,Ce),g("drop",c,A=>Se(A,m(),"overview")),d(r,c)});var qr=i(Ar,2);{var Ur=r=>{var s=St();d(r,s)};M(qr,r=>{Array.from(e(p).entries()).filter(([s,x])=>x.tab==="overview").length===0&&r(Ur)})}t(Pe),t(ur);var br=i(ur,2),He=i(a(br),2),Fr=a(He);ce(Fr,3,()=>Array.from(e(p).entries()).filter(([r,s])=>s.tab==="implementation").sort((r,s)=>r[1].displayOrder-s[1].displayOrder),([r,s])=>r,(r,s)=>{var x=hr(()=>yr(e(s),2));let m=()=>e(x)[0];var c=$t(),Y=a(c);kr(Y,{class:"w-3 h-3 mr-2 flex-shrink-0"});var W=i(Y,2),j=a(W,!0);t(W),t(c),F(()=>{qe(c,"aria-label",`${m()??""} field in Implementation tab`),se(c,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(ae)===m()&&e($)!==m()?"border-t-2 border-green-500":""}`),E(j,m())}),g("dragstart",c,A=>xe(A,m())),g("dragend",c,oe),g("dragover",c,A=>ze(A,m())),g("dragleave",c,Ce),g("drop",c,A=>Se(A,m(),"implementation")),d(r,c)});var Jr=i(Fr,2);{var Yr=r=>{var s=Dt();d(r,s)};M(Jr,r=>{Array.from(e(p).entries()).filter(([s,x])=>x.tab==="implementation").length===0&&r(Yr)})}t(He),t(br);var fr=i(br,2),Ee=i(a(fr),2),Or=a(Ee);ce(Or,3,()=>Array.from(e(p).entries()).filter(([r,s])=>s.tab==="custom").sort((r,s)=>r[1].displayOrder-s[1].displayOrder),([r,s])=>r,(r,s)=>{var x=hr(()=>yr(e(s),2));let m=()=>e(x)[0];var c=Mt(),Y=a(c);kr(Y,{class:"w-3 h-3 mr-2 flex-shrink-0"});var W=i(Y,2),j=a(W,!0);t(W),t(c),F(()=>{qe(c,"aria-label",`${m()??""} field in Custom tab`),se(c,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(ae)===m()&&e($)!==m()?"border-t-2 border-purple-500":""}`),E(j,m())}),g("dragstart",c,A=>xe(A,m())),g("dragend",c,oe),g("dragover",c,A=>ze(A,m())),g("dragleave",c,Ce),g("drop",c,A=>Se(A,m(),"custom")),d(r,c)});var Wr=i(Or,2);{var Xr=r=>{var s=zt();d(r,s)};M(Wr,r=>{Array.from(e(p).entries()).filter(([s,x])=>x.tab==="custom").length===0&&r(Xr)})}t(Ee),t(fr);var Pr=i(fr,2),Ie=i(a(Pr),2),Hr=a(Ie),Kr=a(Hr);{var Gr=r=>{var s=Me(),x=ye(s);ce(x,1,()=>e(P),Cr,(m,c)=>{var Y=At(),W=a(Y),j=a(W,!0);t(W);var A=i(W,2);t(Y),F(()=>E(j,e(c))),g("click",A,dt(()=>{o(P,e(P).filter(be=>be!==e(c)))})),d(m,Y)}),d(r,s)},Qr=r=>{var s=Ft();F(()=>se(s,1,`p-4 transition-colors
6
+ ${e(B)==="mappings"?"bg-orange-50 dark:bg-orange-900/10":""}`)),g("dragover",s,x=>{x.preventDefault(),C(x,"mappings")}),g("dragleave",s,ie),g("drop",s,x=>{if(x.preventDefault(),e($)&&e(p).has(e($))){e(P).includes(e($))||o(P,[...e(P),e($)]);const m=e(p).get(e($));m.tab="mappings",e(p).set(e($),m),o(p,new Map(e(p))),o(B,null)}}),d(r,s)};M(Kr,r=>{e(P).length>0?r(Gr):r(Qr,!1)})}t(Hr),t(Ie),t(Pr),t(Mr),t(gr);var Er=i(gr,2);{var et=r=>{var s=Et(),x=i(a(s),2),m=a(x),c=a(m),Y=a(c);ce(Y,5,()=>e(f).slice(0,5),j=>j,(j,A)=>{var be=Ot(),$e=a(be,!0);t(be),F(()=>E($e,e(A))),d(j,be)}),t(Y),t(c);var W=i(c);ce(W,5,()=>e(S),Cr,(j,A)=>{var be=Ht();ce(be,5,()=>e(f).slice(0,5),$e=>$e,($e,le)=>{var he=Pt(),xr=a(he,!0);t(he),F(()=>E(xr,e(A)[e(le)]||"")),d($e,he)}),t(be),d(j,be)}),t(W),t(m),t(x),t(s),d(r,s)};M(Er,r=>{e(S).length>0&&r(et)})}var Ir=i(Er,2),Re=a(Ir),rt=a(Re);{var tt=r=>{var s=It();d(r,s)},at=r=>{var s=rr("Import to Control Set");d(r,s)};M(rt,r=>{e(G)?r(tt):r(at,!1)})}t(Re),t(Ir),F(()=>{se(er,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(V)?"":"border-red-500"}`),se(Oe,1,`p-3 min-h-[400px] max-h-[600px] overflow-y-auto space-y-2 transition-colors
7
+ ${e(B)===null?"bg-gray-100 dark:bg-gray-800":""}`),se(Pe,1,`p-3 min-h-[400px] max-h-[600px] overflow-y-auto space-y-2 transition-colors
8
+ ${e(B)==="overview"?"bg-blue-50 dark:bg-blue-900/10":""}`),se(He,1,`p-3 min-h-[400px] max-h-[600px] overflow-y-auto space-y-2 transition-colors
9
+ ${e(B)==="implementation"?"bg-green-50 dark:bg-green-900/10":""}`),se(Ee,1,`p-3 min-h-[400px] max-h-[600px] overflow-y-auto space-y-2 transition-colors
10
+ ${e(B)==="custom"?"bg-purple-50 dark:bg-purple-900/10":""}`),se(Ie,1,`p-3 min-h-[400px] max-h-[600px] overflow-y-auto transition-colors
11
+ ${e(B)==="mappings"?"bg-orange-50 dark:bg-orange-900/10":""}`),Re.disabled=e(G)||!e(X)||!e(V),qe(Re,"title",e(V)?"":"Please select a Control ID field")}),jr(v,()=>e(fe),r=>o(fe,r)),jr(R,()=>e(J),r=>o(J,r)),_r(Ge,()=>e(L),r=>o(L,r)),g("change",Ge,()=>{Z()}),_r(Qe,()=>e(U),r=>o(U,r)),g("change",Qe,Z),_r(er,()=>e(V),r=>o(V,r)),g("dragover",Oe,r=>C(r,null)),g("dragleave",Oe,ie),g("drop",Oe,r=>ne(r,null)),g("dragover",Pe,r=>C(r,"overview")),g("dragleave",Pe,ie),g("drop",Pe,r=>ne(r,"overview")),g("dragover",He,r=>C(r,"implementation")),g("dragleave",He,ie),g("drop",He,r=>ne(r,"implementation")),g("dragover",Ee,r=>C(r,"custom")),g("dragleave",Ee,ie),g("drop",Ee,r=>ne(r,"custom")),g("dragover",Ie,r=>C(r,"mappings")),g("dragleave",Ie,ie),g("drop",Ie,r=>ne(r,"mappings")),g("click",Re,Le),d(l,n)};M(ir,l=>{e(we)&&e(f).length>0&&l(nr)})}t(Ne),F(()=>se(Be,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(te)?"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"}`)),g("change",Xe,T),g("dragover",me,u),g("dragleave",me,b),g("drop",me,D),d(pe,Ne),We()}var Lt=h('<span class="ml-2"> </span>'),Nt=h('<div class="text-sm text-gray-500 dark:text-gray-400"><span class="font-medium"> </span> <!></div>'),Bt=h('<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>'),Zt=h('<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>'),Rt=h('<p class="text-sm text-gray-600 dark:text-gray-400 mt-1"> </p>'),qt=h('<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=h('<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=Ve('<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=Ve('<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=h('<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=h('<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=h('<div class="space-y-3"></div> <!>',1),Gt=h('<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(pe,q){Ye(q,!1);const z=()=>st(Sr,"$appState",X),[X,O]=it(),L=k(),N=Lr();let f=Ue(q,"controlSets",24,()=>[]),S=k(""),K=k(null);function re(J){p(J)||o(K,J)}function P(){e(K)&&!p(e(K))&&N("selected",{path:e(K).path})}function p(J){const G=e(L)?.replace(/\/$/,""),Q=J.path?.replace(/\/$/,"");return!!(G&&Q&&G===Q)}Te(()=>z(),()=>{o(L,z().currentPath||"")}),Te(()=>ge(f()),()=>{if(f())if(f().length===0)o(S,"No existing control sets found. Try importing from a spreadsheet instead.");else{const J=f().filter(G=>!p(G));J.length===1?o(K,J[0]):J.length===0&&f().length>0&&o(S,"already-using-only-set")}}),$r(),Je();var U=Gt(),V=i(a(U),2);{var fe=J=>{var G=Me(),Q=ye(G);{var ue=te=>{var $=Bt(),B=a($),ae=i(a(B),6);{var ke=D=>{var T=Nt(),I=a(T),Z=a(I,!0);t(I);var ve=i(I,2);{var je=xe=>{var oe=Lt(),C=a(oe);t(oe),F(()=>E(C,`(${ge(f()),de(()=>f()[0].controlCount)??""} controls)`)),d(xe,oe)};M(ve,xe=>{ge(f()),de(()=>f()[0].controlCount)&&xe(je)})}t(T),F(()=>E(Z,(ge(f()),de(()=>f()[0].name)))),d(D,T)};M(ae,D=>{ge(f()),de(()=>f().length>0)&&D(ke)})}t(B);var u=i(B,2),b=i(a(u),2);t(u),t($),g("click",b,()=>N("tab-change",{tab:"import"})),d(te,$)},we=te=>{var $=Me(),B=ye($);{var ae=u=>{var b=Zt(),D=a(b),T=i(a(D),2),I=a(T,!0);t(T),t(D),t(b),F(()=>E(I,e(S))),d(u,b)},ke=u=>{var b=Me(),D=ye(b);{var T=I=>{var Z=Kt(),ve=ye(Z);ce(ve,5,f,Cr,(oe,C)=>{const ie=De(()=>(e(C),de(()=>p(e(C)))));var ne=Wt(),ze=a(ne),Ce=a(ze),Se=a(Ce),Le=a(Se),Ne=a(Le,!0);t(Le);var me=i(Le,2),Be=a(me);t(me),t(Se);var Ae=i(Se,2);{var ar=l=>{var n=Rt(),y=a(n,!0);t(n),F(()=>E(y,(e(C),de(()=>e(C).description)))),d(l,n)};M(Ae,l=>{e(C),de(()=>e(C).description)&&l(ar)})}var Xe=i(Ae,2),Fe=a(Xe),or=i(a(Fe));t(Fe);var Ke=i(Fe,2);{var lr=l=>{var n=qt(),y=i(a(n));t(n),F(()=>E(y,` ${e(C),de(()=>e(C).file)??""}`)),d(l,n)};M(Ke,l=>{e(C),de(()=>e(C).file)&&l(lr)})}t(Xe),t(Ce);var Ze=i(Ce,2),sr=a(Ze);{var ir=l=>{var n=Ut();d(l,n)},nr=l=>{var n=Me(),y=ye(n);{var _=v=>{var H=Jt();d(v,H)},w=v=>{var H=Yt();d(v,H)};M(y,v=>{e(K)===e(C)?v(_):v(w,!1)},!0)}d(l,n)};M(sr,l=>{e(ie)?l(ir):l(nr,!1)})}t(Ze),t(ze),t(ne),F(()=>{se(ne,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(ie)?"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"}`),E(Ne,(e(C),de(()=>e(C).name))),E(Be,`${e(C),de(()=>e(C).controlCount||0)??""} controls`),E(or,` ${e(C),de(()=>e(C).path||"root")??""}`)}),g("click",ne,()=>!e(ie)&&re(e(C))),g("keydown",ne,l=>l.key==="Enter"&&!e(ie)&&re(e(C))),d(oe,ne)}),t(ve);var je=i(ve,2);{var xe=oe=>{var C=Xt(),ie=a(C);t(C),g("click",ie,P),d(oe,C)};M(je,oe=>{e(K)&&oe(xe)})}d(I,Z)};M(D,I=>{ge(f()),de(()=>f().length>0)&&I(T)},!0)}d(u,b)};M(B,u=>{e(S)?u(ae):u(ke,!1)},!0)}d(te,$)};M(Q,te=>{e(S)==="already-using-only-set"?te(ue):te(we,!1)},!0)}d(J,G)};M(V,J=>{J(fe,!1)})}t(U),d(pe,U),We(),O()}var ea=h('<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=h('<div data-testid="pane-import"><!></div>'),ta=h('<div data-testid="pane-existing"><!></div>'),aa=h('<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=h('<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(pe,q){Ye(q,!1);let z=k("import"),X=k(""),O=k(!1),L=k(!1),N=k([]);ot(()=>{wr.connect();const u=Sr.subscribe(D=>{D.name&&D.name!=="Unknown Control Set"&&D.id!=="unknown"&&D.id!=="default"&&o(X,D.currentPath||"")}),b=async D=>{const T=D.detail;if(T&&T.controlSets){if(o(N,T.controlSets||[]),o(O,e(N).length>0),e(N).length===1){const I=e(N)[0];if(!(e(X)&&e(X).includes(I.path))&&!e(X)){console.log("Only one control set found and none loaded, auto-loading:",I.path),await f(I.path);return}}e(O)&&o(z,"existing")}};return window.addEventListener("control-sets-list",b),wr.scanControlSets().catch(D=>{console.error("Error scanning control sets:",D)}),()=>{u(),window.removeEventListener("control-sets-list",b)}});async function f(u){console.log("Starting control set switch to:",u),o(L,!0);try{await wr.switchControlSet(u),console.log("WebSocket command sent, waiting for state update..."),await new Promise(b=>{let D=0;const T=50,I=setInterval(()=>{D++;const Z=lt(Sr);!Z.isSwitchingControlSet&&Z.currentPath&&Z.currentPath.includes(u)?(clearInterval(I),console.log("Control set switch completed successfully"),b()):D>=T&&(clearInterval(I),console.error("Control set switch timed out"),alert("Control set switch timed out. Please try again."),b())},100)}),o(L,!1),nt("/")}catch(b){console.error("Error switching control set:",b),alert("Failed to switch control set: "+b.message),o(L,!1)}}async function S(u){const{path:b}=u.detail;await f(b)}async function K(u){const{path:b}=u.detail;await f(b)}function re(u){const{tab:b}=u.detail;b&&o(z,b)}Je();var P=oa(),p=a(P),U=a(p),V=i(a(U),2),fe=a(V);{var J=u=>{var b=rr("You have an existing control set. You can continue using it or create a new one.");d(u,b)},G=u=>{var b=Me(),D=ye(b);{var T=Z=>{var ve=rr("Select an existing control set or import a new one from a spreadsheet.");d(Z,ve)},I=Z=>{var ve=rr("Let's get started by importing a control set from a spreadsheet.");d(Z,ve)};M(D,Z=>{e(O)?Z(T):Z(I,!1)},!0)}d(u,b)};M(fe,u=>{e(X)?u(J):u(G,!1)})}t(V),t(U);var Q=i(U,2);{var ue=u=>{var b=ea(),D=a(b),T=a(D),I=i(T,2);t(D),t(b),F(()=>{se(T,1,`px-6 py-3 rounded-l-lg font-medium transition-colors ${e(z)==="existing"?"bg-blue-600 text-white":"text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white"}`),se(I,1,`px-6 py-3 rounded-r-lg font-medium transition-colors ${e(z)==="import"?"bg-blue-600 text-white":"text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white"}`)}),g("click",T,()=>o(z,"existing")),g("click",I,()=>o(z,"import")),d(u,b)};M(Q,u=>{e(O)&&u(ue)})}var we=i(Q,2),te=a(we);{var $=u=>{var b=ra(),D=a(b);jt(D,{$$events:{created:S}}),t(b),d(u,b)},B=u=>{var b=ta(),D=a(b);Qt(D,{get controlSets(){return e(N)},$$events:{selected:K,"tab-change":re}}),t(b),d(u,b)};M(te,u=>{e(z)==="import"?u($):u(B,!1)})}var ae=i(te,2);{var ke=u=>{var b=aa();d(u,b)};M(ae,u=>{e(L)&&u(ke)})}t(we),t(p),t(P),d(pe,P),We()}export{ca as component};
@@ -1 +1 @@
1
- {"version":"1758206542286"}
1
+ {"version":"1758241889426"}
@@ -4680,6 +4680,7 @@ var WebSocketManager = class {
4680
4680
  `${control.id}.yaml`,
4681
4681
  `${control.id.replace(/\./g, "_")}.yaml`,
4682
4682
  // AC-1.1 -> AC-1_1.yaml
4683
+ // eslint-disable-next-line no-useless-escape
4683
4684
  `${control.id.replace(/[^\w\-]/g, "_")}.yaml`
4684
4685
  // General sanitization
4685
4686
  ];
@@ -4901,17 +4902,15 @@ var WebSocketManager = class {
4901
4902
  id: control.id,
4902
4903
  family: control.family
4903
4904
  };
4904
- const fieldSchema = controlSetData.fieldSchema?.fields || {};
4905
- for (const [fieldName, fieldConfig] of Object.entries(fieldSchema)) {
4906
- if (fieldConfig.tab === "overview" && control[fieldName] !== void 0) {
4905
+ const fieldSchema = controlSetData.fieldSchema?.fields || controlSetData.field_schema?.fields || {};
4906
+ for (const [fieldName] of Object.entries(fieldSchema)) {
4907
+ if (control[fieldName] !== void 0) {
4907
4908
  metadata[fieldName] = control[fieldName];
4908
4909
  }
4909
4910
  }
4910
- if (control.title !== void 0) metadata.title = control.title;
4911
- if (control.implementation_status !== void 0)
4912
- metadata.implementation_status = control.implementation_status;
4913
- if (control.compliance_status !== void 0)
4914
- metadata.compliance_status = control.compliance_status;
4911
+ if (Object.keys(fieldSchema).length === 0) {
4912
+ Object.assign(metadata, control);
4913
+ }
4915
4914
  return metadata;
4916
4915
  });
4917
4916
  return {
@@ -4968,8 +4967,9 @@ var WebSocketManager = class {
4968
4967
  id: controlId,
4969
4968
  family: control.family || control["control-acronym"]?.toString().split("-")[0] || ""
4970
4969
  };
4971
- if (controlSetData.field_schema?.fields) {
4972
- for (const [fieldName] of Object.entries(controlSetData.field_schema.fields)) {
4970
+ const schemaFields = controlSetData.field_schema?.fields || controlSetData.fieldSchema?.fields;
4971
+ if (schemaFields) {
4972
+ for (const [fieldName] of Object.entries(schemaFields)) {
4973
4973
  if (control[fieldName] !== void 0) {
4974
4974
  summary[fieldName] = control[fieldName];
4975
4975
  }
@@ -4657,6 +4657,7 @@ var WebSocketManager = class {
4657
4657
  `${control.id}.yaml`,
4658
4658
  `${control.id.replace(/\./g, "_")}.yaml`,
4659
4659
  // AC-1.1 -> AC-1_1.yaml
4660
+ // eslint-disable-next-line no-useless-escape
4660
4661
  `${control.id.replace(/[^\w\-]/g, "_")}.yaml`
4661
4662
  // General sanitization
4662
4663
  ];
@@ -4878,17 +4879,15 @@ var WebSocketManager = class {
4878
4879
  id: control.id,
4879
4880
  family: control.family
4880
4881
  };
4881
- const fieldSchema = controlSetData.fieldSchema?.fields || {};
4882
- for (const [fieldName, fieldConfig] of Object.entries(fieldSchema)) {
4883
- if (fieldConfig.tab === "overview" && control[fieldName] !== void 0) {
4882
+ const fieldSchema = controlSetData.fieldSchema?.fields || controlSetData.field_schema?.fields || {};
4883
+ for (const [fieldName] of Object.entries(fieldSchema)) {
4884
+ if (control[fieldName] !== void 0) {
4884
4885
  metadata[fieldName] = control[fieldName];
4885
4886
  }
4886
4887
  }
4887
- if (control.title !== void 0) metadata.title = control.title;
4888
- if (control.implementation_status !== void 0)
4889
- metadata.implementation_status = control.implementation_status;
4890
- if (control.compliance_status !== void 0)
4891
- metadata.compliance_status = control.compliance_status;
4888
+ if (Object.keys(fieldSchema).length === 0) {
4889
+ Object.assign(metadata, control);
4890
+ }
4892
4891
  return metadata;
4893
4892
  });
4894
4893
  return {
@@ -4945,8 +4944,9 @@ var WebSocketManager = class {
4945
4944
  id: controlId,
4946
4945
  family: control.family || control["control-acronym"]?.toString().split("-")[0] || ""
4947
4946
  };
4948
- if (controlSetData.field_schema?.fields) {
4949
- for (const [fieldName] of Object.entries(controlSetData.field_schema.fields)) {
4947
+ const schemaFields = controlSetData.field_schema?.fields || controlSetData.fieldSchema?.fields;
4948
+ if (schemaFields) {
4949
+ for (const [fieldName] of Object.entries(schemaFields)) {
4950
4950
  if (control[fieldName] !== void 0) {
4951
4951
  summary[fieldName] = control[fieldName];
4952
4952
  }
@@ -4657,6 +4657,7 @@ var WebSocketManager = class {
4657
4657
  `${control.id}.yaml`,
4658
4658
  `${control.id.replace(/\./g, "_")}.yaml`,
4659
4659
  // AC-1.1 -> AC-1_1.yaml
4660
+ // eslint-disable-next-line no-useless-escape
4660
4661
  `${control.id.replace(/[^\w\-]/g, "_")}.yaml`
4661
4662
  // General sanitization
4662
4663
  ];
@@ -4878,17 +4879,15 @@ var WebSocketManager = class {
4878
4879
  id: control.id,
4879
4880
  family: control.family
4880
4881
  };
4881
- const fieldSchema = controlSetData.fieldSchema?.fields || {};
4882
- for (const [fieldName, fieldConfig] of Object.entries(fieldSchema)) {
4883
- if (fieldConfig.tab === "overview" && control[fieldName] !== void 0) {
4882
+ const fieldSchema = controlSetData.fieldSchema?.fields || controlSetData.field_schema?.fields || {};
4883
+ for (const [fieldName] of Object.entries(fieldSchema)) {
4884
+ if (control[fieldName] !== void 0) {
4884
4885
  metadata[fieldName] = control[fieldName];
4885
4886
  }
4886
4887
  }
4887
- if (control.title !== void 0) metadata.title = control.title;
4888
- if (control.implementation_status !== void 0)
4889
- metadata.implementation_status = control.implementation_status;
4890
- if (control.compliance_status !== void 0)
4891
- metadata.compliance_status = control.compliance_status;
4888
+ if (Object.keys(fieldSchema).length === 0) {
4889
+ Object.assign(metadata, control);
4890
+ }
4892
4891
  return metadata;
4893
4892
  });
4894
4893
  return {
@@ -4945,8 +4944,9 @@ var WebSocketManager = class {
4945
4944
  id: controlId,
4946
4945
  family: control.family || control["control-acronym"]?.toString().split("-")[0] || ""
4947
4946
  };
4948
- if (controlSetData.field_schema?.fields) {
4949
- for (const [fieldName] of Object.entries(controlSetData.field_schema.fields)) {
4947
+ const schemaFields = controlSetData.field_schema?.fields || controlSetData.fieldSchema?.fields;
4948
+ if (schemaFields) {
4949
+ for (const [fieldName] of Object.entries(schemaFields)) {
4950
4950
  if (control[fieldName] !== void 0) {
4951
4951
  summary[fieldName] = control[fieldName];
4952
4952
  }
@@ -2237,6 +2237,7 @@ var WebSocketManager = class {
2237
2237
  `${control.id}.yaml`,
2238
2238
  `${control.id.replace(/\./g, "_")}.yaml`,
2239
2239
  // AC-1.1 -> AC-1_1.yaml
2240
+ // eslint-disable-next-line no-useless-escape
2240
2241
  `${control.id.replace(/[^\w\-]/g, "_")}.yaml`
2241
2242
  // General sanitization
2242
2243
  ];
@@ -2458,17 +2459,15 @@ var WebSocketManager = class {
2458
2459
  id: control.id,
2459
2460
  family: control.family
2460
2461
  };
2461
- const fieldSchema = controlSetData.fieldSchema?.fields || {};
2462
- for (const [fieldName, fieldConfig] of Object.entries(fieldSchema)) {
2463
- if (fieldConfig.tab === "overview" && control[fieldName] !== void 0) {
2462
+ const fieldSchema = controlSetData.fieldSchema?.fields || controlSetData.field_schema?.fields || {};
2463
+ for (const [fieldName] of Object.entries(fieldSchema)) {
2464
+ if (control[fieldName] !== void 0) {
2464
2465
  metadata[fieldName] = control[fieldName];
2465
2466
  }
2466
2467
  }
2467
- if (control.title !== void 0) metadata.title = control.title;
2468
- if (control.implementation_status !== void 0)
2469
- metadata.implementation_status = control.implementation_status;
2470
- if (control.compliance_status !== void 0)
2471
- metadata.compliance_status = control.compliance_status;
2468
+ if (Object.keys(fieldSchema).length === 0) {
2469
+ Object.assign(metadata, control);
2470
+ }
2472
2471
  return metadata;
2473
2472
  });
2474
2473
  return {
@@ -2525,8 +2524,9 @@ var WebSocketManager = class {
2525
2524
  id: controlId,
2526
2525
  family: control.family || control["control-acronym"]?.toString().split("-")[0] || ""
2527
2526
  };
2528
- if (controlSetData.field_schema?.fields) {
2529
- for (const [fieldName] of Object.entries(controlSetData.field_schema.fields)) {
2527
+ const schemaFields = controlSetData.field_schema?.fields || controlSetData.fieldSchema?.fields;
2528
+ if (schemaFields) {
2529
+ for (const [fieldName] of Object.entries(schemaFields)) {
2530
2530
  if (control[fieldName] !== void 0) {
2531
2531
  summary[fieldName] = control[fieldName];
2532
2532
  }
package/dist/index.html CHANGED
@@ -6,28 +6,28 @@
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.CuPBZjFh.js">
10
- <link rel="modulepreload" href="/_app/immutable/chunks/z5X83jua.js">
11
- <link rel="modulepreload" href="/_app/immutable/chunks/C9p1zaS8.js">
12
- <link rel="modulepreload" href="/_app/immutable/entry/app.DlQKiOqI.js">
9
+ <link rel="modulepreload" href="/_app/immutable/entry/start.BWvTyytY.js">
10
+ <link rel="modulepreload" href="/_app/immutable/chunks/BcKIo18J.js">
11
+ <link rel="modulepreload" href="/_app/immutable/chunks/BhjtS45v.js">
12
+ <link rel="modulepreload" href="/_app/immutable/entry/app.rFT55pRO.js">
13
13
  <link rel="modulepreload" href="/_app/immutable/chunks/DsnmJJEf.js">
14
- <link rel="modulepreload" href="/_app/immutable/chunks/C2RwV308.js">
15
- <link rel="modulepreload" href="/_app/immutable/chunks/EhHGBAhB.js">
16
- <link rel="modulepreload" href="/_app/immutable/chunks/cvagBx-i.js">
14
+ <link rel="modulepreload" href="/_app/immutable/chunks/DwdPeWTx.js">
15
+ <link rel="modulepreload" href="/_app/immutable/chunks/vNis_B2V.js">
16
+ <link rel="modulepreload" href="/_app/immutable/chunks/BkFSJLu9.js">
17
17
  </head>
18
18
  <body data-sveltekit-preload-data="hover">
19
19
  <div style="display: contents">
20
20
  <script>
21
21
  {
22
- __sveltekit_ni8atx = {
22
+ __sveltekit_11js13k = {
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.CuPBZjFh.js"),
30
- import("/_app/immutable/entry/app.DlQKiOqI.js")
29
+ import("/_app/immutable/entry/start.BWvTyytY.js"),
30
+ import("/_app/immutable/entry/app.rFT55pRO.js")
31
31
  ]).then(([kit, app]) => {
32
32
  kit.start(app, element);
33
33
  });
package/dist/index.js CHANGED
@@ -4684,6 +4684,7 @@ var WebSocketManager = class {
4684
4684
  `${control.id}.yaml`,
4685
4685
  `${control.id.replace(/\./g, "_")}.yaml`,
4686
4686
  // AC-1.1 -> AC-1_1.yaml
4687
+ // eslint-disable-next-line no-useless-escape
4687
4688
  `${control.id.replace(/[^\w\-]/g, "_")}.yaml`
4688
4689
  // General sanitization
4689
4690
  ];
@@ -4905,17 +4906,15 @@ var WebSocketManager = class {
4905
4906
  id: control.id,
4906
4907
  family: control.family
4907
4908
  };
4908
- const fieldSchema = controlSetData.fieldSchema?.fields || {};
4909
- for (const [fieldName, fieldConfig] of Object.entries(fieldSchema)) {
4910
- if (fieldConfig.tab === "overview" && control[fieldName] !== void 0) {
4909
+ const fieldSchema = controlSetData.fieldSchema?.fields || controlSetData.field_schema?.fields || {};
4910
+ for (const [fieldName] of Object.entries(fieldSchema)) {
4911
+ if (control[fieldName] !== void 0) {
4911
4912
  metadata[fieldName] = control[fieldName];
4912
4913
  }
4913
4914
  }
4914
- if (control.title !== void 0) metadata.title = control.title;
4915
- if (control.implementation_status !== void 0)
4916
- metadata.implementation_status = control.implementation_status;
4917
- if (control.compliance_status !== void 0)
4918
- metadata.compliance_status = control.compliance_status;
4915
+ if (Object.keys(fieldSchema).length === 0) {
4916
+ Object.assign(metadata, control);
4917
+ }
4919
4918
  return metadata;
4920
4919
  });
4921
4920
  return {
@@ -4972,8 +4971,9 @@ var WebSocketManager = class {
4972
4971
  id: controlId,
4973
4972
  family: control.family || control["control-acronym"]?.toString().split("-")[0] || ""
4974
4973
  };
4975
- if (controlSetData.field_schema?.fields) {
4976
- for (const [fieldName] of Object.entries(controlSetData.field_schema.fields)) {
4974
+ const schemaFields = controlSetData.field_schema?.fields || controlSetData.fieldSchema?.fields;
4975
+ if (schemaFields) {
4976
+ for (const [fieldName] of Object.entries(schemaFields)) {
4977
4977
  if (control[fieldName] !== void 0) {
4978
4978
  summary[fieldName] = control[fieldName];
4979
4979
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lula2",
3
- "version": "0.3.3",
3
+ "version": "0.3.4-nightly.0",
4
4
  "description": "A tool for managing compliance as code in your GitHub repositories.",
5
5
  "bin": {
6
6
  "lula2": "./dist/lula2"
@@ -33,25 +33,6 @@
33
33
  "!dist/**/*.test.js*",
34
34
  "!dist/**/*.test.d.ts*"
35
35
  ],
36
- "scripts": {
37
- "dev": "vite dev --port 5173",
38
- "dev:api": "tsx --watch index.ts --debug ui --port 3000 --no-open-browser",
39
- "dev:full": "concurrently \"npm run dev:api\" \"npm run dev\"",
40
- "build": "npm run build:svelte && npm run build:cli && npm run postbuild:cli",
41
- "build:svelte": "vite build",
42
- "build:cli": "esbuild index.ts cli/**/*.ts --bundle --platform=node --target=node22 --format=esm --outdir=dist --external:express --external:commander --external:js-yaml --external:yaml --external:isomorphic-git --external:glob --external:open --external:ws --external:cors --external:multer --external:@octokit/rest --external:undici --external:exceljs --external:csv-parse",
43
- "postbuild:cli": "cp cli-wrapper.mjs dist/lula2 && chmod +x dist/lula2",
44
- "preview": "vite preview",
45
- "prepare": "svelte-kit sync || echo ''",
46
- "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json && tsc --noEmit",
47
- "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
48
- "format": "prettier --write 'src/**/*.{ts,js,svelte}' 'cli/**/*.ts' 'index.ts' 'tests/**/*.ts'",
49
- "format:check": "prettier --check 'src/**/*.{ts,js,svelte}' 'cli/**/*.ts' 'index.ts' 'tests/**/*.ts'",
50
- "lint": "prettier --check 'src/**/*.{ts,js,svelte}' 'cli/**/*.ts' 'index.ts' 'tests/**/*.ts' && eslint src cli",
51
- "test": "npm run test:unit -- --run --coverage",
52
- "test:integration": "vitest --config integration/vitest.config.integration.ts",
53
- "test:unit": "vitest"
54
- },
55
36
  "dependencies": {
56
37
  "@octokit/rest": "^22.0.0",
57
38
  "@types/ws": "^8.18.1",
@@ -124,5 +105,23 @@
124
105
  "main",
125
106
  "next"
126
107
  ]
108
+ },
109
+ "scripts": {
110
+ "dev": "vite dev --port 5173",
111
+ "dev:api": "tsx --watch index.ts --debug ui --port 3000 --no-open-browser",
112
+ "dev:full": "concurrently \"npm run dev:api\" \"npm run dev\"",
113
+ "build": "npm run build:svelte && npm run build:cli && npm run postbuild:cli",
114
+ "build:svelte": "vite build",
115
+ "build:cli": "esbuild index.ts cli/**/*.ts --bundle --platform=node --target=node22 --format=esm --outdir=dist --external:express --external:commander --external:js-yaml --external:yaml --external:isomorphic-git --external:glob --external:open --external:ws --external:cors --external:multer --external:@octokit/rest --external:undici --external:exceljs --external:csv-parse",
116
+ "postbuild:cli": "cp cli-wrapper.mjs dist/lula2 && chmod +x dist/lula2",
117
+ "preview": "vite preview",
118
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json && tsc --noEmit",
119
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
120
+ "format": "prettier --write 'src/**/*.{ts,js,svelte}' 'cli/**/*.ts' 'index.ts' 'tests/**/*.ts'",
121
+ "format:check": "prettier --check 'src/**/*.{ts,js,svelte}' 'cli/**/*.ts' 'index.ts' 'tests/**/*.ts'",
122
+ "lint": "prettier --check 'src/**/*.{ts,js,svelte}' 'cli/**/*.ts' 'index.ts' 'tests/**/*.ts' && eslint src cli",
123
+ "test": "npm run test:unit -- --run --coverage",
124
+ "test:integration": "vitest --config integration/vitest.config.integration.ts",
125
+ "test:unit": "vitest"
127
126
  }
128
- }
127
+ }
@@ -30,7 +30,7 @@
30
30
  onchange={handleChange}
31
31
  class="block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-800 dark:text-white"
32
32
  >
33
- {#each availableSets as set}
33
+ {#each availableSets as set (set.id)}
34
34
  <option value={set.id}>{set.name} {set.version}</option>
35
35
  {/each}
36
36
  </select>
@@ -139,7 +139,7 @@
139
139
  }
140
140
 
141
141
  // Handle field changes from custom tab
142
- function handleFieldChange(fieldName: string, value: any) {
142
+ function handleFieldChange(_fieldName: string, _value: any) {
143
143
  triggerAutoSave();
144
144
  }
145
145
  </script>
@@ -170,32 +170,6 @@
170
170
  goto(`/control/${encodeURIComponent(control.id)}`);
171
171
  }
172
172
 
173
- function getStatusBadgeClass(status: string) {
174
- switch (status) {
175
- case 'Implemented':
176
- return 'bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-300';
177
- case 'Planned':
178
- return 'bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-300';
179
- case 'Not Implemented':
180
- return 'bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-300';
181
- default:
182
- return 'bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-300';
183
- }
184
- }
185
-
186
- function getComplianceBadgeClass(status: string) {
187
- switch (status) {
188
- case 'Compliant':
189
- return 'bg-emerald-100 dark:bg-emerald-900/30 text-emerald-800 dark:text-emerald-300';
190
- case 'Non-Compliant':
191
- return 'bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-300';
192
- case 'Not Assessed':
193
- return 'bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-300';
194
- default:
195
- return 'bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-300';
196
- }
197
- }
198
-
199
173
  function extractDescriptionFromNested(data: any): string {
200
174
  if (typeof data === 'string') {
201
175
  return data;
@@ -224,24 +198,6 @@
224
198
  return 'No description available';
225
199
  }
226
200
 
227
- // Helper to determine if a field should be truncated and show tooltip
228
- function shouldTruncateField(field: FieldSchema | undefined, value: string): boolean {
229
- if (!value) return false;
230
-
231
- // Always show tooltip for textarea fields if content is long
232
- if (field?.ui_type === 'textarea' || field?.ui_type === 'long_text') {
233
- return value.length > 100; // Lower threshold for long text fields
234
- }
235
-
236
- // For short_text fields, only show if really long
237
- if (field?.ui_type === 'short_text') {
238
- return value.length > 200;
239
- }
240
-
241
- // Default for unknown field types
242
- return value.length > 150;
243
- }
244
-
245
201
  // Get truncation length based on field type
246
202
  function getTruncationLength(field: FieldSchema | undefined): number {
247
203
  if (field?.ui_type === 'textarea' || field?.ui_type === 'long_text') {
@@ -296,7 +252,7 @@
296
252
  <!-- Active Filters Summary -->
297
253
  {#if $activeFilters.length > 0}
298
254
  <div class="mt-2 flex flex-wrap gap-2">
299
- {#each $activeFilters as filter, index}
255
+ {#each $activeFilters as filter, index (index)}
300
256
  <div class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-300">
301
257
  <span>{filter.fieldName}: </span>
302
258
  {#if filter.operator === 'exists' || filter.operator === 'not_exists'}
@@ -342,7 +298,7 @@
342
298
  class="grid gap-4 px-6 py-3"
343
299
  style="grid-template-columns: repeat({tableColumns.length + 1}, minmax(0, 1fr)); max-width: 100%;"
344
300
  >
345
- {#each tableColumns as { fieldName, field }}
301
+ {#each tableColumns as { fieldName, field }, index (index)}
346
302
  <div
347
303
  class="text-left text-xs font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wider"
348
304
  >
@@ -391,7 +347,7 @@
391
347
  <!-- Scrollable Table Body -->
392
348
  <div class="flex-1 overflow-auto">
393
349
  <div class="divide-y divide-gray-200 dark:divide-gray-700">
394
- {#each $filteredControlsWithMappings as control}
350
+ {#each $filteredControlsWithMappings as control, index (index)}
395
351
  {@const rawDescription = (() => {
396
352
  // Cast control to any to allow dynamic field access
397
353
  const anyControl = control as any;
@@ -434,7 +390,7 @@
434
390
  tabindex="0"
435
391
  aria-label="Select control {control.id}"
436
392
  >
437
- {#each tableColumns as { fieldName, field }}
393
+ {#each tableColumns as { fieldName, field }, index (index)}
438
394
  {@const value = (control as any)[fieldName]}
439
395
  <div class="flex flex-col justify-center">
440
396
  {#if field.ui_type === 'select' && value}
@@ -193,7 +193,7 @@
193
193
  CCIs Found in Narrative
194
194
  </div>
195
195
  <div class="flex flex-wrap gap-2">
196
- {#each ccisInNarrative as cci}
196
+ {#each ccisInNarrative as cci (cci)}
197
197
  <span
198
198
  class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 dark:bg-blue-800 text-blue-800 dark:text-blue-200"
199
199
  >
@@ -215,7 +215,7 @@
215
215
  {:else if activeTab === 'mappings'}
216
216
  <div class="space-y-4">
217
217
  {#if associatedMappings.length > 0}
218
- {#each associatedMappings as mapping}
218
+ {#each associatedMappings as mapping (mapping.uuid)}
219
219
  <div
220
220
  class="border border-gray-200 dark:border-gray-600 rounded-lg p-4 bg-gray-50 dark:bg-gray-800"
221
221
  >
@@ -80,7 +80,7 @@
80
80
  <div class="mb-4">
81
81
  <h4 class="text-xs font-semibold text-gray-600 dark:text-gray-400 uppercase tracking-wider mb-2">Source References</h4>
82
82
  <div class="space-y-2">
83
- {#each mapping.source_entries as entry}
83
+ {#each mapping.source_entries as entry (entry)}
84
84
  <div class="bg-gray-50 dark:bg-gray-800 rounded-lg p-3 border border-gray-200 dark:border-gray-700">
85
85
  <div class="flex items-start justify-between">
86
86
  <span class="text-xs font-mono text-blue-600 dark:text-blue-400 break-all">
@@ -110,7 +110,7 @@
110
110
  <!-- Existing entries -->
111
111
  {#if formData.source_entries.length > 0}
112
112
  <div class="space-y-3">
113
- {#each formData.source_entries as entry, index}
113
+ {#each formData.source_entries as entry, index (index)}
114
114
  <div class="flex items-center gap-3 p-4 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm">
115
115
  <div class="flex-1 min-w-0">
116
116
  <div class="text-sm font-mono text-gray-900 dark:text-white break-all">
@@ -38,7 +38,7 @@
38
38
  class="w-full px-3 py-2 text-sm border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-900 text-gray-900 dark:text-white disabled:opacity-50 disabled:cursor-not-allowed focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:focus:ring-blue-400"
39
39
  >
40
40
  <option value="">-- Select --</option>
41
- {#each field.options as option}
41
+ {#each field.options as option (option)}
42
42
  <option value={option}>{option}</option>
43
43
  {/each}
44
44
  </select>