lula2 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import"../chunks/DsnmJJEf.js";import{at as le,p as R,ae as y,d as k,T as $,G as m,h as u,af as F,ag as M,c as i,n as A,r as n,b as v,e as N,J as D,K as Y,ak as Q,a as U,f as P,o as xe,au as be,s as V,av as ie}from"../chunks/Cby0Z7eP.js";import{l as z,p as C,i as w,a as te,s as de}from"../chunks/DqsOU3kV.js";import{g as me}from"../chunks/ByYV7ZA-.js";import{p as _e,D as we}from"../chunks/Dz1EplPN.js";import{i as j}from"../chunks/C5zWTfmV.js";import{a as K,f as ce,w as q}from"../chunks/BtOhWAVU.js";le(["change"]);var ye=M("<title> </title>"),ke=M('<svg><!><path d="M11.41 26.59L7.83 23 28 23 28 21 7.83 21 11.41 17.41 10 16 4 22 10 28 11.41 26.59zM28 10L22 4 20.59 5.41 24.17 9 4 9 4 11 24.17 11 20.59 14.59 22 16 28 10z"></path></svg>');function $e(b,t){const e=z(t,["children","$$slots","$$events","$$legacy"]),l=z(e,["size","title"]);R(t,!1);const o=$(),g=$();let f=C(t,"size",8,16),r=C(t,"title",8,void 0);y(()=>(m(e),m(r())),()=>{k(o,e["aria-label"]||e["aria-labelledby"]||r())}),y(()=>(u(o),m(e)),()=>{k(g,{"aria-hidden":u(o)?void 0:!0,role:u(o)?"img":void 0,focusable:Number(e.tabindex)===0?!0:void 0})}),F(),j();var s=ke();K(s,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:f(),height:f(),...u(g),...l}));var p=i(s);{var x=d=>{var a=ye(),c=i(a,!0);n(a),D(()=>Y(c,r())),v(d,a)};w(p,d=>{r()&&d(x)})}A(),n(s),v(b,s),N()}var ze=P('<a href="/setup" class="inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors" title="Switch control set"><!> Switch</a>'),Ce=P('<div class="text-sm text-gray-500 dark:text-gray-400">Loading...</div>');function Me(b,t){R(t,!1);const e=()=>te(ce,"$appState",l),[l,o]=de();j();var g=Q(),f=U(g);{var r=p=>{var x=ze(),d=i(x);$e(d,{size:16}),A(),n(x),v(p,x)},s=p=>{var x=Ce();v(p,x)};w(f,p=>{e().isConnected?p(r):p(s,!1)})}v(b,g),N(),o()}var Se=M("<title> </title>"),Le=M('<svg><!><path d="M31 16L24 23 22.59 21.59 28.17 16 22.59 10.41 24 9 31 16zM1 16L8 9 9.41 10.41 3.83 16 9.41 21.59 8 23 1 16z"></path><path d="M5.91 15H26.080000000000002V17H5.91z" transform="rotate(-75 15.996 16)"></path></svg>');function Ae(b,t){const e=z(t,["children","$$slots","$$events","$$legacy"]),l=z(e,["size","title"]);R(t,!1);const o=$(),g=$();let f=C(t,"size",8,16),r=C(t,"title",8,void 0);y(()=>(m(e),m(r())),()=>{k(o,e["aria-label"]||e["aria-labelledby"]||r())}),y(()=>(u(o),m(e)),()=>{k(g,{"aria-hidden":u(o)?void 0:!0,role:u(o)?"img":void 0,focusable:Number(e.tabindex)===0?!0:void 0})}),F(),j();var s=Le();K(s,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:f(),height:f(),...u(g),...l}));var p=i(s);{var x=d=>{var a=Se(),c=i(a,!0);n(a),D(()=>Y(c,r())),v(d,a)};w(p,d=>{r()&&d(x)})}A(2),n(s),v(b,s),N()}var Ee=M("<title> </title>"),He=M('<svg><!><path d="M13 21L26.17 21 23.59 23.59 25 25 30 20 25 15 23.59 16.41 26.17 19 13 19 13 21z"></path><path d="M22,14V10a1,1,0,0,0-.29-.71l-7-7A1,1,0,0,0,14,2H4A2,2,0,0,0,2,4V28a2,2,0,0,0,2,2H20a2,2,0,0,0,2-2V26H20v2H4V4h8v6a2,2,0,0,0,2,2h6v2Zm-8-4V4.41L19.59,10Z"></path></svg>');function Ve(b,t){const e=z(t,["children","$$slots","$$events","$$legacy"]),l=z(e,["size","title"]);R(t,!1);const o=$(),g=$();let f=C(t,"size",8,16),r=C(t,"title",8,void 0);y(()=>(m(e),m(r())),()=>{k(o,e["aria-label"]||e["aria-labelledby"]||r())}),y(()=>(u(o),m(e)),()=>{k(g,{"aria-hidden":u(o)?void 0:!0,role:u(o)?"img":void 0,focusable:Number(e.tabindex)===0?!0:void 0})}),F(),j();var s=He();K(s,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:f(),height:f(),...u(g),...l}));var p=i(s);{var x=d=>{var a=Ee(),c=i(a,!0);n(a),D(()=>Y(c,r())),v(d,a)};w(p,d=>{r()&&d(x)})}A(2),n(s),v(b,s),N()}var Re=M("<title> </title>"),Ne=M('<svg><!><path d="M26 24v4H6V24H4v4H4a2 2 0 002 2H26a2 2 0 002-2h0V24zM26 14L24.59 12.59 17 20.17 17 2 15 2 15 20.17 7.41 12.59 6 14 16 24 26 14z"></path></svg>');function ne(b,t){const e=z(t,["children","$$slots","$$events","$$legacy"]),l=z(e,["size","title"]);R(t,!1);const o=$(),g=$();let f=C(t,"size",8,16),r=C(t,"title",8,void 0);y(()=>(m(e),m(r())),()=>{k(o,e["aria-label"]||e["aria-labelledby"]||r())}),y(()=>(u(o),m(e)),()=>{k(g,{"aria-hidden":u(o)?void 0:!0,role:u(o)?"img":void 0,focusable:Number(e.tabindex)===0?!0:void 0})}),F(),j();var s=Ne();K(s,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:f(),height:f(),...u(g),...l}));var p=i(s);{var x=d=>{var a=Re(),c=i(a,!0);n(a),D(()=>Y(c,r())),v(d,a)};w(p,d=>{r()&&d(x)})}A(),n(s),v(b,s),N()}var Pe=M("<title> </title>"),Te=M('<svg><!><path fill-rule="evenodd" d="M16,2a14,14,0,0,0-4.43,27.28c.7.13,1-.3,1-.67s0-1.21,0-2.38c-3.89.84-4.71-1.88-4.71-1.88A3.71,3.71,0,0,0,6.24,22.3c-1.27-.86.1-.85.1-.85A2.94,2.94,0,0,1,8.48,22.9a3,3,0,0,0,4.08,1.16,2.93,2.93,0,0,1,.88-1.87c-3.1-.36-6.37-1.56-6.37-6.92a5.4,5.4,0,0,1,1.44-3.76,5,5,0,0,1,.14-3.7s1.17-.38,3.85,1.43a13.3,13.3,0,0,1,7,0c2.67-1.81,3.84-1.43,3.84-1.43a5,5,0,0,1,.14,3.7,5.4,5.4,0,0,1,1.44,3.76c0,5.38-3.27,6.56-6.39,6.91a3.33,3.33,0,0,1,.95,2.59c0,1.87,0,3.38,0,3.84s.25.81,1,.67A14,14,0,0,0,16,2Z"></path></svg>');function Be(b,t){const e=z(t,["children","$$slots","$$events","$$legacy"]),l=z(e,["size","title"]);R(t,!1);const o=$(),g=$();let f=C(t,"size",8,16),r=C(t,"title",8,void 0);y(()=>(m(e),m(r())),()=>{k(o,e["aria-label"]||e["aria-labelledby"]||r())}),y(()=>(u(o),m(e)),()=>{k(g,{"aria-hidden":u(o)?void 0:!0,role:u(o)?"img":void 0,focusable:Number(e.tabindex)===0?!0:void 0})}),F(),j();var s=Te();K(s,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:f(),height:f(),...u(g),...l}));var p=i(s);{var x=d=>{var a=Pe(),c=i(a,!0);n(a),D(()=>Y(c,r())),v(d,a)};w(p,d=>{r()&&d(x)})}A(),n(s),v(b,s),N()}var De=(b,t)=>t("csv"),Ye=(b,t)=>t("excel"),je=(b,t)=>t("json"),Ge=P('<div class="space-y-1 p-1"><button class="w-full text-left px-3 py-2 text-sm rounded-md transition-colors duration-200 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700"><div class="flex items-center gap-2"><!> <span>Export as CSV</span></div></button> <button class="w-full text-left px-3 py-2 text-sm rounded-md transition-colors duration-200 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700"><div class="flex items-center gap-2"><!> <span>Export as Excel</span></div></button> <button class="w-full text-left px-3 py-2 text-sm rounded-md transition-colors duration-200 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700"><div class="flex items-center gap-2"><!> <span>Export as JSON</span></div></button></div>'),Ie=P('<div class="flex-1 flex justify-center items-center"><div class="text-center"><div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div> <p class="text-gray-500 dark:text-gray-400">Switching control set...</p></div></div>'),Ze=P('<div class="flex-1 flex justify-center items-center"><div class="text-center"><div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div> <p class="text-gray-500 dark:text-gray-400"> </p></div></div>'),Je=P('<header class="bg-white dark:bg-gray-900 shadow-sm border-b border-gray-200 dark:border-gray-700 flex-shrink-0"><div class="w-full px-6 lg:px-8"><div class="flex justify-between items-center h-16"><div class="flex items-center"><a href="/" class="flex items-center space-x-3 hover:opacity-80 transition-opacity"><img src="/lula.png" class="h-8 w-8" alt="Lula Logo"/> <div class="flex flex-col"><span class="text-xl font-bold text-gray-900 dark:text-white">Lula</span> <span class="text-xs text-gray-500 dark:text-gray-400 -mt-1">Gitops for Compliance</span></div></a></div> <div class="flex items-center space-x-4"><!> <!> <a class="p-2 text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg transition-colors" title="Github" href="https://github.com/defenseunicorns/lula" target="_blank"><!></a></div></div></div></header> <div class="flex-1 flex gap-6 p-6 overflow-hidden"><!></div>',1),Ue=P('<div class="h-screen flex flex-col"><!></div>');function et(b,t){R(t,!0);const e=()=>te(_e,"$page",o),l=()=>te(ce,"$appState",o),[o,g]=de();let f=!1;async function r(a){try{const c=`/api/export-controls?format=${a}`,h=document.createElement("a");h.href=c,h.download="",document.body.appendChild(h),h.click(),document.body.removeChild(h)}catch(c){console.error("Export failed:",c)}}xe(()=>{q.connect();let a=null;const c=async()=>{if(f||e().url.pathname==="/setup"||l().isSwitchingControlSet)return;const h=l();if(h.isConnected){if(f=!0,(!h.name||h.name==="Unknown Control Set"||h.id==="unknown"||h.id==="default")&&(!h.controls||h.controls.length===0)){await q.scanControlSets();const E=await new Promise(G=>{const T=O=>{window.removeEventListener("control-sets-list",T),G(O.detail)};window.addEventListener("control-sets-list",T),setTimeout(()=>{window.removeEventListener("control-sets-list",T),G(null)},2e3)});E&&Array.isArray(E)&&E.length===1?(console.log("Auto-loading single control set:",E[0].path),await q.switchControlSet(E[0].path)):me("/setup")}}else a=window.setTimeout(c,500)};return a=window.setTimeout(c,100),()=>{a&&clearTimeout(a)}}),be(()=>{q.disconnect()});var s=Ue(),p=i(s);{var x=a=>{var c=Je(),h=U(c),E=i(h),G=i(E),T=V(i(G),2),O=i(T);Me(O,{});var ae=V(O,2);{var ve=_=>{we(_,{buttonLabel:"Export",get buttonIcon(){return ne},buttonClass:"inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors",dropdownClass:"w-48",children:W=>{var Z=Ge(),B=i(Z);B.__click=[De,r];var S=i(B),H=i(S);Ve(H,{class:"w-4 h-4"}),A(2),n(S),n(B);var L=V(B,2);L.__click=[Ye,r];var J=i(L),X=i(J);ne(X,{class:"w-4 h-4"}),A(2),n(J),n(L);var ee=V(L,2);ee.__click=[je,r];var oe=i(ee),pe=i(oe);Ae(pe,{class:"w-4 h-4"}),A(2),n(oe),n(ee),n(Z),v(W,Z)},$$slots:{default:!0}})};w(ae,_=>{l().isConnected&&l().controls&&l().controls.length>0&&_(ve)})}var re=V(ae,2),ue=i(re);Be(ue,{class:"w-5 h-5"}),n(re),n(T),n(G),n(E),n(h);var se=V(h,2),ge=i(se);{var fe=_=>{var I=Ie();v(_,I)},he=_=>{var I=Q(),W=U(I);{var Z=S=>{var H=Ze(),L=i(H),J=V(i(L),2),X=i(J,!0);n(J),n(L),n(H),D(()=>Y(X,l().isConnected?l().fieldSchema?"Loading controls...":"Loading schema...":"Connecting...")),v(S,H)},B=S=>{var H=Q(),L=U(H);ie(L,()=>t.children),v(S,H)};w(W,S=>{!l().isConnected||!l().controls||l().controls.length===0||!l().fieldSchema?S(Z):S(B,!1)},!0)}v(_,I)};w(ge,_=>{l().isSwitchingControlSet?_(fe):_(he,!1)})}n(se),v(a,c)},d=a=>{var c=Q(),h=U(c);ie(h,()=>t.children),v(a,c)};w(p,a=>{e().url.pathname!=="/setup"?a(x):a(d,!1)})}n(s),v(b,s),N(),g()}le(["click"]);export{et as component};
1
+ import"../chunks/DsnmJJEf.js";import{at as le,p as R,ae as y,d as k,T as $,G as m,h as u,af as F,ag as M,c as i,n as A,r as n,b as v,e as N,J as D,K as Y,ak as Q,a as U,f as P,o as xe,au as be,s as V,av as ie}from"../chunks/Cby0Z7eP.js";import{l as z,p as C,i as w,a as te,s as de}from"../chunks/DqsOU3kV.js";import{g as me}from"../chunks/Ds14DLx0.js";import{p as _e,D as we}from"../chunks/BW28MavF.js";import{i as j}from"../chunks/C5zWTfmV.js";import{a as K,f as ce,w as q}from"../chunks/BtOhWAVU.js";le(["change"]);var ye=M("<title> </title>"),ke=M('<svg><!><path d="M11.41 26.59L7.83 23 28 23 28 21 7.83 21 11.41 17.41 10 16 4 22 10 28 11.41 26.59zM28 10L22 4 20.59 5.41 24.17 9 4 9 4 11 24.17 11 20.59 14.59 22 16 28 10z"></path></svg>');function $e(b,t){const e=z(t,["children","$$slots","$$events","$$legacy"]),l=z(e,["size","title"]);R(t,!1);const o=$(),g=$();let f=C(t,"size",8,16),r=C(t,"title",8,void 0);y(()=>(m(e),m(r())),()=>{k(o,e["aria-label"]||e["aria-labelledby"]||r())}),y(()=>(u(o),m(e)),()=>{k(g,{"aria-hidden":u(o)?void 0:!0,role:u(o)?"img":void 0,focusable:Number(e.tabindex)===0?!0:void 0})}),F(),j();var s=ke();K(s,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:f(),height:f(),...u(g),...l}));var p=i(s);{var x=d=>{var a=ye(),c=i(a,!0);n(a),D(()=>Y(c,r())),v(d,a)};w(p,d=>{r()&&d(x)})}A(),n(s),v(b,s),N()}var ze=P('<a href="/setup" class="inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors" title="Switch control set"><!> Switch</a>'),Ce=P('<div class="text-sm text-gray-500 dark:text-gray-400">Loading...</div>');function Me(b,t){R(t,!1);const e=()=>te(ce,"$appState",l),[l,o]=de();j();var g=Q(),f=U(g);{var r=p=>{var x=ze(),d=i(x);$e(d,{size:16}),A(),n(x),v(p,x)},s=p=>{var x=Ce();v(p,x)};w(f,p=>{e().isConnected?p(r):p(s,!1)})}v(b,g),N(),o()}var Se=M("<title> </title>"),Le=M('<svg><!><path d="M31 16L24 23 22.59 21.59 28.17 16 22.59 10.41 24 9 31 16zM1 16L8 9 9.41 10.41 3.83 16 9.41 21.59 8 23 1 16z"></path><path d="M5.91 15H26.080000000000002V17H5.91z" transform="rotate(-75 15.996 16)"></path></svg>');function Ae(b,t){const e=z(t,["children","$$slots","$$events","$$legacy"]),l=z(e,["size","title"]);R(t,!1);const o=$(),g=$();let f=C(t,"size",8,16),r=C(t,"title",8,void 0);y(()=>(m(e),m(r())),()=>{k(o,e["aria-label"]||e["aria-labelledby"]||r())}),y(()=>(u(o),m(e)),()=>{k(g,{"aria-hidden":u(o)?void 0:!0,role:u(o)?"img":void 0,focusable:Number(e.tabindex)===0?!0:void 0})}),F(),j();var s=Le();K(s,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:f(),height:f(),...u(g),...l}));var p=i(s);{var x=d=>{var a=Se(),c=i(a,!0);n(a),D(()=>Y(c,r())),v(d,a)};w(p,d=>{r()&&d(x)})}A(2),n(s),v(b,s),N()}var Ee=M("<title> </title>"),He=M('<svg><!><path d="M13 21L26.17 21 23.59 23.59 25 25 30 20 25 15 23.59 16.41 26.17 19 13 19 13 21z"></path><path d="M22,14V10a1,1,0,0,0-.29-.71l-7-7A1,1,0,0,0,14,2H4A2,2,0,0,0,2,4V28a2,2,0,0,0,2,2H20a2,2,0,0,0,2-2V26H20v2H4V4h8v6a2,2,0,0,0,2,2h6v2Zm-8-4V4.41L19.59,10Z"></path></svg>');function Ve(b,t){const e=z(t,["children","$$slots","$$events","$$legacy"]),l=z(e,["size","title"]);R(t,!1);const o=$(),g=$();let f=C(t,"size",8,16),r=C(t,"title",8,void 0);y(()=>(m(e),m(r())),()=>{k(o,e["aria-label"]||e["aria-labelledby"]||r())}),y(()=>(u(o),m(e)),()=>{k(g,{"aria-hidden":u(o)?void 0:!0,role:u(o)?"img":void 0,focusable:Number(e.tabindex)===0?!0:void 0})}),F(),j();var s=He();K(s,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:f(),height:f(),...u(g),...l}));var p=i(s);{var x=d=>{var a=Ee(),c=i(a,!0);n(a),D(()=>Y(c,r())),v(d,a)};w(p,d=>{r()&&d(x)})}A(2),n(s),v(b,s),N()}var Re=M("<title> </title>"),Ne=M('<svg><!><path d="M26 24v4H6V24H4v4H4a2 2 0 002 2H26a2 2 0 002-2h0V24zM26 14L24.59 12.59 17 20.17 17 2 15 2 15 20.17 7.41 12.59 6 14 16 24 26 14z"></path></svg>');function ne(b,t){const e=z(t,["children","$$slots","$$events","$$legacy"]),l=z(e,["size","title"]);R(t,!1);const o=$(),g=$();let f=C(t,"size",8,16),r=C(t,"title",8,void 0);y(()=>(m(e),m(r())),()=>{k(o,e["aria-label"]||e["aria-labelledby"]||r())}),y(()=>(u(o),m(e)),()=>{k(g,{"aria-hidden":u(o)?void 0:!0,role:u(o)?"img":void 0,focusable:Number(e.tabindex)===0?!0:void 0})}),F(),j();var s=Ne();K(s,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:f(),height:f(),...u(g),...l}));var p=i(s);{var x=d=>{var a=Re(),c=i(a,!0);n(a),D(()=>Y(c,r())),v(d,a)};w(p,d=>{r()&&d(x)})}A(),n(s),v(b,s),N()}var Pe=M("<title> </title>"),Te=M('<svg><!><path fill-rule="evenodd" d="M16,2a14,14,0,0,0-4.43,27.28c.7.13,1-.3,1-.67s0-1.21,0-2.38c-3.89.84-4.71-1.88-4.71-1.88A3.71,3.71,0,0,0,6.24,22.3c-1.27-.86.1-.85.1-.85A2.94,2.94,0,0,1,8.48,22.9a3,3,0,0,0,4.08,1.16,2.93,2.93,0,0,1,.88-1.87c-3.1-.36-6.37-1.56-6.37-6.92a5.4,5.4,0,0,1,1.44-3.76,5,5,0,0,1,.14-3.7s1.17-.38,3.85,1.43a13.3,13.3,0,0,1,7,0c2.67-1.81,3.84-1.43,3.84-1.43a5,5,0,0,1,.14,3.7,5.4,5.4,0,0,1,1.44,3.76c0,5.38-3.27,6.56-6.39,6.91a3.33,3.33,0,0,1,.95,2.59c0,1.87,0,3.38,0,3.84s.25.81,1,.67A14,14,0,0,0,16,2Z"></path></svg>');function Be(b,t){const e=z(t,["children","$$slots","$$events","$$legacy"]),l=z(e,["size","title"]);R(t,!1);const o=$(),g=$();let f=C(t,"size",8,16),r=C(t,"title",8,void 0);y(()=>(m(e),m(r())),()=>{k(o,e["aria-label"]||e["aria-labelledby"]||r())}),y(()=>(u(o),m(e)),()=>{k(g,{"aria-hidden":u(o)?void 0:!0,role:u(o)?"img":void 0,focusable:Number(e.tabindex)===0?!0:void 0})}),F(),j();var s=Te();K(s,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:f(),height:f(),...u(g),...l}));var p=i(s);{var x=d=>{var a=Pe(),c=i(a,!0);n(a),D(()=>Y(c,r())),v(d,a)};w(p,d=>{r()&&d(x)})}A(),n(s),v(b,s),N()}var De=(b,t)=>t("csv"),Ye=(b,t)=>t("excel"),je=(b,t)=>t("json"),Ge=P('<div class="space-y-1 p-1"><button class="w-full text-left px-3 py-2 text-sm rounded-md transition-colors duration-200 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700"><div class="flex items-center gap-2"><!> <span>Export as CSV</span></div></button> <button class="w-full text-left px-3 py-2 text-sm rounded-md transition-colors duration-200 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700"><div class="flex items-center gap-2"><!> <span>Export as Excel</span></div></button> <button class="w-full text-left px-3 py-2 text-sm rounded-md transition-colors duration-200 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700"><div class="flex items-center gap-2"><!> <span>Export as JSON</span></div></button></div>'),Ie=P('<div class="flex-1 flex justify-center items-center"><div class="text-center"><div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div> <p class="text-gray-500 dark:text-gray-400">Switching control set...</p></div></div>'),Ze=P('<div class="flex-1 flex justify-center items-center"><div class="text-center"><div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div> <p class="text-gray-500 dark:text-gray-400"> </p></div></div>'),Je=P('<header class="bg-white dark:bg-gray-900 shadow-sm border-b border-gray-200 dark:border-gray-700 flex-shrink-0"><div class="w-full px-6 lg:px-8"><div class="flex justify-between items-center h-16"><div class="flex items-center"><a href="/" class="flex items-center space-x-3 hover:opacity-80 transition-opacity"><img src="/lula.png" class="h-8 w-8" alt="Lula Logo"/> <div class="flex flex-col"><span class="text-xl font-bold text-gray-900 dark:text-white">Lula</span> <span class="text-xs text-gray-500 dark:text-gray-400 -mt-1">Gitops for Compliance</span></div></a></div> <div class="flex items-center space-x-4"><!> <!> <a class="p-2 text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg transition-colors" title="Github" href="https://github.com/defenseunicorns/lula" target="_blank"><!></a></div></div></div></header> <div class="flex-1 flex gap-6 p-6 overflow-hidden"><!></div>',1),Ue=P('<div class="h-screen flex flex-col"><!></div>');function et(b,t){R(t,!0);const e=()=>te(_e,"$page",o),l=()=>te(ce,"$appState",o),[o,g]=de();let f=!1;async function r(a){try{const c=`/api/export-controls?format=${a}`,h=document.createElement("a");h.href=c,h.download="",document.body.appendChild(h),h.click(),document.body.removeChild(h)}catch(c){console.error("Export failed:",c)}}xe(()=>{q.connect();let a=null;const c=async()=>{if(f||e().url.pathname==="/setup"||l().isSwitchingControlSet)return;const h=l();if(h.isConnected){if(f=!0,(!h.name||h.name==="Unknown Control Set"||h.id==="unknown"||h.id==="default")&&(!h.controls||h.controls.length===0)){await q.scanControlSets();const E=await new Promise(G=>{const T=O=>{window.removeEventListener("control-sets-list",T),G(O.detail)};window.addEventListener("control-sets-list",T),setTimeout(()=>{window.removeEventListener("control-sets-list",T),G(null)},2e3)});E&&Array.isArray(E)&&E.length===1?(console.log("Auto-loading single control set:",E[0].path),await q.switchControlSet(E[0].path)):me("/setup")}}else a=window.setTimeout(c,500)};return a=window.setTimeout(c,100),()=>{a&&clearTimeout(a)}}),be(()=>{q.disconnect()});var s=Ue(),p=i(s);{var x=a=>{var c=Je(),h=U(c),E=i(h),G=i(E),T=V(i(G),2),O=i(T);Me(O,{});var ae=V(O,2);{var ve=_=>{we(_,{buttonLabel:"Export",get buttonIcon(){return ne},buttonClass:"inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors",dropdownClass:"w-48",children:W=>{var Z=Ge(),B=i(Z);B.__click=[De,r];var S=i(B),H=i(S);Ve(H,{class:"w-4 h-4"}),A(2),n(S),n(B);var L=V(B,2);L.__click=[Ye,r];var J=i(L),X=i(J);ne(X,{class:"w-4 h-4"}),A(2),n(J),n(L);var ee=V(L,2);ee.__click=[je,r];var oe=i(ee),pe=i(oe);Ae(pe,{class:"w-4 h-4"}),A(2),n(oe),n(ee),n(Z),v(W,Z)},$$slots:{default:!0}})};w(ae,_=>{l().isConnected&&l().controls&&l().controls.length>0&&_(ve)})}var re=V(ae,2),ue=i(re);Be(ue,{class:"w-5 h-5"}),n(re),n(T),n(G),n(E),n(h);var se=V(h,2),ge=i(se);{var fe=_=>{var I=Ie();v(_,I)},he=_=>{var I=Q(),W=U(I);{var Z=S=>{var H=Ze(),L=i(H),J=V(i(L),2),X=i(J,!0);n(J),n(L),n(H),D(()=>Y(X,l().isConnected?l().fieldSchema?"Loading controls...":"Loading schema...":"Connecting...")),v(S,H)},B=S=>{var H=Q(),L=U(H);ie(L,()=>t.children),v(S,H)};w(W,S=>{!l().isConnected||!l().controls||l().controls.length===0||!l().fieldSchema?S(Z):S(B,!1)},!0)}v(_,I)};w(ge,_=>{l().isSwitchingControlSet?_(fe):_(he,!1)})}n(se),v(a,c)},d=a=>{var c=Q(),h=U(c);ie(h,()=>t.children),v(a,c)};w(p,a=>{e().url.pathname!=="/setup"?a(x):a(d,!1)})}n(s),v(b,s),N(),g()}le(["click"]);export{et as component};
@@ -1 +1 @@
1
- import"../chunks/DsnmJJEf.js";import{i as u}from"../chunks/C5zWTfmV.js";import{p as h,f as g,a as l,J as v,b as d,e as _,c as s,r as a,s as x,K as o}from"../chunks/Cby0Z7eP.js";import{s as $,p}from"../chunks/ByYV7ZA-.js";const b={get error(){return p.error},get status(){return p.status}};$.updated.check;const i=b;var k=g("<h1> </h1> <p> </p>",1);function q(m,c){h(c,!1),u();var t=k(),r=l(t),n=s(r,!0);a(r);var e=x(r,2),f=s(e,!0);a(e),v(()=>{o(n,i.status),o(f,i.error?.message)}),d(m,t),_()}export{q as component};
1
+ import"../chunks/DsnmJJEf.js";import{i as u}from"../chunks/C5zWTfmV.js";import{p as h,f as g,a as l,J as v,b as d,e as _,c as s,r as a,s as x,K as o}from"../chunks/Cby0Z7eP.js";import{s as $,p}from"../chunks/Ds14DLx0.js";const b={get error(){return p.error},get status(){return p.status}};$.updated.check;const i=b;var k=g("<h1> </h1> <p> </p>",1);function q(m,c){h(c,!1),u();var t=k(),r=l(t),n=s(r,!0);a(r);var e=x(r,2),f=s(e,!0);a(e),v(()=>{o(n,i.status),o(f,i.error?.message)}),d(m,t),_()}export{q as component};
@@ -1 +1 @@
1
- import"../chunks/DsnmJJEf.js";import"../chunks/C5zWTfmV.js";import{f,a as y,b as n,c as t,r,s as w,n as C}from"../chunks/Cby0Z7eP.js";import{i as k,s as $,a as D}from"../chunks/DqsOU3kV.js";import{C as S,a as j,D as L}from"../chunks/ByvTzPiZ.js";import{s as N}from"../chunks/Dz1EplPN.js";var P=f('<div class=" h-full flex flex-col"><div class="flex-1 flex items-center justify-center p-8"><div class="text-center text-gray-500 dark:text-gray-400"><!> <h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-2">No Control Selected</h3> <p class="text-gray-600 dark:text-gray-400">Select a control from the list to view and edit its details</p></div></div></div>'),q=f('<div class="w-1/2 flex flex-col"><div class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm h-full flex flex-col"><!></div></div> <div class="w-1/2 flex flex-col"><!></div>',1);function H(m){const o=()=>D(N,"$selectedControl",x),[x,g]=$();var l=q(),a=y(l),i=t(a),p=t(i);S(p,{}),r(i),r(a);var d=w(a,2),_=t(d);{var h=e=>{j(e,{get control(){return o()}})},b=e=>{var s=P(),c=t(s),v=t(c),u=t(v);L(u,{class:"mx-auto h-16 w-16 mb-4"}),C(4),r(v),r(c),r(s),n(e,s)};k(_,e=>{o()?e(h):e(b,!1)})}r(d),n(m,l),g()}export{H as component};
1
+ import"../chunks/DsnmJJEf.js";import"../chunks/C5zWTfmV.js";import{f,a as y,b as n,c as t,r,s as w,n as C}from"../chunks/Cby0Z7eP.js";import{i as k,s as $,a as D}from"../chunks/DqsOU3kV.js";import{C as S,a as j,D as L}from"../chunks/DQAmyY_z.js";import{s as N}from"../chunks/BW28MavF.js";var P=f('<div class=" h-full flex flex-col"><div class="flex-1 flex items-center justify-center p-8"><div class="text-center text-gray-500 dark:text-gray-400"><!> <h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-2">No Control Selected</h3> <p class="text-gray-600 dark:text-gray-400">Select a control from the list to view and edit its details</p></div></div></div>'),q=f('<div class="w-1/2 flex flex-col"><div class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm h-full flex flex-col"><!></div></div> <div class="w-1/2 flex flex-col"><!></div>',1);function H(m){const o=()=>D(N,"$selectedControl",x),[x,g]=$();var l=q(),a=y(l),i=t(a),p=t(i);S(p,{}),r(i),r(a);var d=w(a,2),_=t(d);{var h=e=>{j(e,{get control(){return o()}})},b=e=>{var s=P(),c=t(s),v=t(c),u=t(v);L(u,{class:"mx-auto h-16 w-16 mb-4"}),C(4),r(v),r(c),r(s),n(e,s)};k(_,e=>{o()?e(h):e(b,!1)})}r(d),n(m,l),g()}export{H as component};
@@ -1 +1 @@
1
- import"../chunks/DsnmJJEf.js";import{p as S,u as A,d as x,o as B,f as n,a as F,b as i,e as H,c as s,g as N,r as a,s as h,h as P,n as R}from"../chunks/Cby0Z7eP.js";import{a as C,i as b,s as U}from"../chunks/DqsOU3kV.js";import{g as V}from"../chunks/ByYV7ZA-.js";import{p as q,s as _}from"../chunks/Dz1EplPN.js";import{C as G,a as J,D as K}from"../chunks/ByvTzPiZ.js";import{w}from"../chunks/BtOhWAVU.js";var O=n('<div class="absolute top-4 right-4 z-10"><div class="w-8 h-8 flex items-center justify-center rounded-full bg-blue-100 dark:bg-blue-900/30" title="Loading control..."><svg class="w-5 h-5 text-blue-600 dark:text-blue-400 animate-spin" 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></div></div>'),Q=n('<div class=" h-full flex flex-col"><div class="flex-1 flex items-center justify-center p-8"><div class="text-center text-gray-500 dark:text-gray-400"><!> <h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-2">No Control Selected</h3> <p class="text-gray-600 dark:text-gray-400">Select a control from the list to view and edit its details</p></div></div></div>'),T=n('<div class="w-1/2 flex flex-col"><div class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm h-full flex flex-col"><!></div></div> <div class="w-1/2 flex flex-col relative"><!> <!></div>',1);function se(y,k){S(k,!0);const $=()=>C(q,"$page",c),d=()=>C(_,"$selectedControl",c),[c,D]=U();let v="",r=N(!1);A(()=>{const e=$().params.id;if(!e)return;const t=decodeURIComponent(e);t&&t!==v&&w.isConnected()&&(v=t,x(r,!0),w.getControlDetails(t))}),B(()=>{const e=t=>{const o=t.detail;x(r,!1),o?_.set(o):V("/")};return window.addEventListener("control-details",e),()=>{window.removeEventListener("control-details",e)}});var f=T(),l=F(f),p=s(l),L=s(p);G(L,{}),a(p),a(l);var g=h(l,2),m=s(g);{var I=e=>{var t=O();i(e,t)};b(m,e=>{P(r)&&e(I)})}var z=h(m,2);{var j=e=>{J(e,{get control(){return d()}})},E=e=>{var t=Q(),o=s(t),u=s(o),M=s(u);K(M,{class:"mx-auto h-16 w-16 mb-4"}),R(4),a(u),a(o),a(t),i(e,t)};b(z,e=>{d()?e(j):e(E,!1)})}a(g),i(y,f),H(),D()}export{se as component};
1
+ import"../chunks/DsnmJJEf.js";import{p as S,u as A,d as x,o as B,f as n,a as F,b as i,e as H,c as s,g as N,r as a,s as h,h as P,n as R}from"../chunks/Cby0Z7eP.js";import{a as C,i as b,s as U}from"../chunks/DqsOU3kV.js";import{g as V}from"../chunks/Ds14DLx0.js";import{p as q,s as _}from"../chunks/BW28MavF.js";import{C as G,a as J,D as K}from"../chunks/DQAmyY_z.js";import{w}from"../chunks/BtOhWAVU.js";var O=n('<div class="absolute top-4 right-4 z-10"><div class="w-8 h-8 flex items-center justify-center rounded-full bg-blue-100 dark:bg-blue-900/30" title="Loading control..."><svg class="w-5 h-5 text-blue-600 dark:text-blue-400 animate-spin" 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></div></div>'),Q=n('<div class=" h-full flex flex-col"><div class="flex-1 flex items-center justify-center p-8"><div class="text-center text-gray-500 dark:text-gray-400"><!> <h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-2">No Control Selected</h3> <p class="text-gray-600 dark:text-gray-400">Select a control from the list to view and edit its details</p></div></div></div>'),T=n('<div class="w-1/2 flex flex-col"><div class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm h-full flex flex-col"><!></div></div> <div class="w-1/2 flex flex-col relative"><!> <!></div>',1);function se(y,k){S(k,!0);const $=()=>C(q,"$page",c),d=()=>C(_,"$selectedControl",c),[c,D]=U();let v="",r=N(!1);A(()=>{const e=$().params.id;if(!e)return;const t=decodeURIComponent(e);t&&t!==v&&w.isConnected()&&(v=t,x(r,!0),w.getControlDetails(t))}),B(()=>{const e=t=>{const o=t.detail;x(r,!1),o?_.set(o):V("/")};return window.addEventListener("control-details",e),()=>{window.removeEventListener("control-details",e)}});var f=T(),l=F(f),p=s(l),L=s(p);G(L,{}),a(p),a(l);var g=h(l,2),m=s(g);{var I=e=>{var t=O();i(e,t)};b(m,e=>{P(r)&&e(I)})}var z=h(m,2);{var j=e=>{J(e,{get control(){return d()}})},E=e=>{var t=Q(),o=s(t),u=s(o),M=s(u);K(M,{class:"mx-auto h-16 w-16 mb-4"}),R(4),a(u),a(o),a(t),i(e,t)};b(z,e=>{d()?e(j):e(E,!1)})}a(g),i(y,f),H(),D()}export{se as component};
@@ -1,4 +1,4 @@
1
- import"../chunks/DsnmJJEf.js";import{i as Ye}from"../chunks/C5zWTfmV.js";import{p as We,ae as Oe,d as o,T as C,G as se,h as e,af as nr,ag as Be,c as a,n as Me,r,b as v,e as Xe,J as H,K as I,ah as Nr,f as y,s as i,k as _,ai as g,a as we,aj as wr,ak as Fe,a0 as Ae,al as kr,am as sr,an as Cr,o as lt,W as st}from"../chunks/Cby0Z7eP.js";import{l as ir,p as Je,i as A,a as it,s as nt}from"../chunks/DqsOU3kV.js";import{a as Br,s as le,r as jr,e as me,i as De,b as Ne,c as Lr,d as Sr,f as Dr,w as $r}from"../chunks/BtOhWAVU.js";import{g as dt}from"../chunks/ByYV7ZA-.js";var vt=Be("<title> </title>"),gt=Be('<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 ct(he,G){const E=ir(G,["children","$$slots","$$events","$$legacy"]),de=ir(E,["size","title"]);We(G,!1);const T=C(),V=C();let B=Je(G,"size",8,16),w=Je(G,"title",8,void 0);Oe(()=>(se(E),se(w())),()=>{o(T,E["aria-label"]||E["aria-labelledby"]||w())}),Oe(()=>(e(T),se(E)),()=>{o(V,{"aria-hidden":e(T)?void 0:!0,role:e(T)?"img":void 0,focusable:Number(E.tabindex)===0?!0:void 0})}),nr(),Ye();var h=gt();Br(h,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:B(),height:B(),...e(V),...de}));var S=a(h);{var be=J=>{var F=vt(),c=a(F,!0);r(F),H(()=>I(c,w())),v(J,F)};A(S,J=>{w()&&J(be)})}Me(2),r(h),v(he,h),Xe()}var pt=Be("<title> </title>"),ut=Be('<svg><!><path d="M10 6H14V10H10zM18 6H22V10H18zM10 14H14V18H10zM18 14H22V18H18zM10 22H14V26H10zM18 22H22V26H18z"></path></svg>');function lr(he,G){const E=ir(G,["children","$$slots","$$events","$$legacy"]),de=ir(E,["size","title"]);We(G,!1);const T=C(),V=C();let B=Je(G,"size",8,16),w=Je(G,"title",8,void 0);Oe(()=>(se(E),se(w())),()=>{o(T,E["aria-label"]||E["aria-labelledby"]||w())}),Oe(()=>(e(T),se(E)),()=>{o(V,{"aria-hidden":e(T)?void 0:!0,role:e(T)?"img":void 0,focusable:Number(E.tabindex)===0?!0:void 0})}),nr(),Ye();var h=ut();Br(h,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:B(),height:B(),...e(V),...de}));var S=a(h);{var be=J=>{var F=pt(),c=a(F,!0);r(F),H(()=>I(c,w())),v(J,F)};A(S,J=>{w()&&J(be)})}Me(),r(h),v(he,h),Xe()}var bt=y('<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=y('<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=y('<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=y("<option> </option>"),ht=y("<option> </option>"),yt=y("<option> </option>"),_t=y('<span class="ml-auto text-xs text-blue-600 dark:text-blue-400">ID</span>'),wt=y('<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=y('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">No excluded fields</p>'),Ct=y('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),St=y('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p>'),$t=y('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),Dt=y('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p>'),Mt=y('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),zt=y('<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>'),At=y('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),Ft=y('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p>'),Ot=y('<th class="px-4 py-2"> </th>'),Ht=y('<td class="px-4 py-2"> </td>'),Pt=y('<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700"></tr>'),Et=y('<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=y('<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=y(`<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
1
+ import"../chunks/DsnmJJEf.js";import{i as Ye}from"../chunks/C5zWTfmV.js";import{p as We,ae as Oe,d as o,T as C,G as se,h as e,af as nr,ag as Be,c as a,n as Me,r,b as v,e as Xe,J as H,K as I,ah as Nr,f as y,s as i,k as _,ai as g,a as we,aj as wr,ak as Fe,a0 as Ae,al as kr,am as sr,an as Cr,o as lt,W as st}from"../chunks/Cby0Z7eP.js";import{l as ir,p as Je,i as A,a as it,s as nt}from"../chunks/DqsOU3kV.js";import{a as Br,s as le,r as jr,e as me,i as De,b as Ne,c as Lr,d as Sr,f as Dr,w as $r}from"../chunks/BtOhWAVU.js";import{g as dt}from"../chunks/Ds14DLx0.js";var vt=Be("<title> </title>"),gt=Be('<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 ct(he,G){const E=ir(G,["children","$$slots","$$events","$$legacy"]),de=ir(E,["size","title"]);We(G,!1);const T=C(),V=C();let B=Je(G,"size",8,16),w=Je(G,"title",8,void 0);Oe(()=>(se(E),se(w())),()=>{o(T,E["aria-label"]||E["aria-labelledby"]||w())}),Oe(()=>(e(T),se(E)),()=>{o(V,{"aria-hidden":e(T)?void 0:!0,role:e(T)?"img":void 0,focusable:Number(E.tabindex)===0?!0:void 0})}),nr(),Ye();var h=gt();Br(h,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:B(),height:B(),...e(V),...de}));var S=a(h);{var be=J=>{var F=vt(),c=a(F,!0);r(F),H(()=>I(c,w())),v(J,F)};A(S,J=>{w()&&J(be)})}Me(2),r(h),v(he,h),Xe()}var pt=Be("<title> </title>"),ut=Be('<svg><!><path d="M10 6H14V10H10zM18 6H22V10H18zM10 14H14V18H10zM18 14H22V18H18zM10 22H14V26H10zM18 22H22V26H18z"></path></svg>');function lr(he,G){const E=ir(G,["children","$$slots","$$events","$$legacy"]),de=ir(E,["size","title"]);We(G,!1);const T=C(),V=C();let B=Je(G,"size",8,16),w=Je(G,"title",8,void 0);Oe(()=>(se(E),se(w())),()=>{o(T,E["aria-label"]||E["aria-labelledby"]||w())}),Oe(()=>(e(T),se(E)),()=>{o(V,{"aria-hidden":e(T)?void 0:!0,role:e(T)?"img":void 0,focusable:Number(E.tabindex)===0?!0:void 0})}),nr(),Ye();var h=ut();Br(h,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:B(),height:B(),...e(V),...de}));var S=a(h);{var be=J=>{var F=pt(),c=a(F,!0);r(F),H(()=>I(c,w())),v(J,F)};A(S,J=>{w()&&J(be)})}Me(),r(h),v(he,h),Xe()}var bt=y('<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=y('<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=y('<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=y("<option> </option>"),ht=y("<option> </option>"),yt=y("<option> </option>"),_t=y('<span class="ml-auto text-xs text-blue-600 dark:text-blue-400">ID</span>'),wt=y('<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=y('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">No excluded fields</p>'),Ct=y('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),St=y('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p>'),$t=y('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),Dt=y('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p>'),Mt=y('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),zt=y('<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>'),At=y('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),Ft=y('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p>'),Ot=y('<th class="px-4 py-2"> </th>'),Ht=y('<td class="px-4 py-2"> </td>'),Pt=y('<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700"></tr>'),Et=y('<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=y('<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=y(`<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
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-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 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></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=y('<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(he,G){We(G,!1);const E=C(),de=Nr();let T=C(null),V=C(""),B=C(""),w=C([]),h=C([]),S=C([]),be=C(0),J=C([]),F=C([]),c=C(new Map),fe=C(1),R=C(""),Z=C(""),ie=C(""),Q=C(!1),ne=C(""),xe=C(""),ve=C(!1),ge=C(!1),$=C(null),W=C(null),ee=C(null);function u(){o(h,[]),o(S,[]),o(be,0),e(c).clear(),o(c,new Map),o(F,[]),o(R,""),o(ne,""),o(xe,""),o($,null),o(W,null),o(ee,null)}function b(l){l.preventDefault(),o(ge,!0)}function D(){o(ge,!1)}function L(l){l.preventDefault(),o(ge,!1);const n=l.dataTransfer?.files;n&&n.length>0&&Y(n[0])}function j(l){const n=l.target;n.files&&n.files.length>0&&Y(n.files[0])}async function Y(l){u(),o(V,l.name),o(T,l),o(ne,""),o(Q,!0),o(Z,e(V).replace(/\.[^.]+$/,"").replace(/[-_]/g," ")),o(ie,`Imported from ${e(V)}`);try{const n=new FormData;n.append("file",l);const z=await fetch("/api/parse-excel",{method:"POST",body:n});if(!z.ok){const x=await z.json();throw new Error(x.error||"Failed to parse file")}const k=await z.json();o(w,k.sheets||[]),o(B,k.selectedSheet||e(w)[0]),o(J,k.rowPreviews||[]),e(J).length>0&&e(fe)===1&&o(fe,e(J)[0].row),await ce(),o(ve,!0)}catch(n){o(ne,"Error reading file: "+n.message)}finally{o(Q,!1)}}async function ce(){if(!(!e(T)||!e(B))){o(Q,!0),e(c).clear(),o(c,new Map),o(R,"");try{const l=new FormData;l.append("file",e(T)),l.append("sheetName",e(B)),l.append("headerRow",e(fe).toString());const n=await fetch("/api/parse-excel-sheet",{method:"POST",body:l});if(!n.ok){const k=await n.json();throw new Error(k.error||"Failed to parse sheet")}const z=await n.json();if(o(h,z.fields||[]),o(S,z.sampleData||[]),o(be,z.controlCount||0),e(h).forEach((k,x)=>{const p=k.toLowerCase();let N="custom",q="text";p.includes("implementation")||p.includes("status")||p.includes("narrative")||p.includes("guidance")?N="implementation":(p.includes("id")||p.includes("title")||p.includes("family")||p.includes("cci")||p.includes("control")||p.includes("acronym"))&&(N="overview"),p.includes("description")||p.includes("narrative")||p.includes("guidance")||p.includes("statement")?q="textarea":p.includes("status")||p.includes("type")||p.includes("designation")?q="select":p.includes("date")?q="date":(p.includes("count")||p.includes("number"))&&(q="number"),e(c).set(k,{originalName:k,tab:N,displayOrder:x,fieldType:q,required:p.includes("id")||p.includes("title")})}),o(c,e(c)),e(R)&&!e(h).includes(e(R))&&o(R,""),!e(R)&&e(h).includes("AP Acronym")){const k=!e(S).length||e(S).every(te=>!te["AP Acronym"]||String(te["AP Acronym"]).length<25),x=e(S).map(te=>te["AP Acronym"]).filter(te=>te!=null&&te!==""&&String(te).trim()!==""),p=new Set(x),N=!x.length||p.size===x.length,q=x.length>0;k&&N&&q&&o(R,"AP Acronym")}}catch(l){o(ne,"Error loading sheet data: "+l.message)}finally{o(Q,!1)}}}function He(l){if(!l)return l;let n=l.trim().replace(/\r?\n/g," ").replace(/\s+/g," ").trim();return ze(n)}function ze(l){return l.replace(/\W+/g," ").split(/ |\s/).map(n=>n.toLowerCase()).join("-")}function re(l,n){o($,n),l.dataTransfer&&(l.dataTransfer.effectAllowed="move",l.dataTransfer.setData("text/plain",n))}function M(){o($,null),o(W,null),o(ee,null)}function pe(l,n){l.preventDefault(),o(W,n),l.dataTransfer&&(l.dataTransfer.dropEffect="move")}function ue(){o(W,null)}function ye(l,n,z){if(l.preventDefault(),e($)&&e(c).has(e($))){const k=e(c).get(e($));if(k.tab==="mappings"&&n!=="mappings"&&o(F,e(F).filter(x=>x!==e($))),n==="mappings"&&!e(F).includes(e($))&&o(F,[...e(F),e($)]),k.tab=n,z!==void 0&&n!==null){const p=Array.from(e(c).entries()).filter(([N,q])=>q.tab===n).sort((N,q)=>N[1].displayOrder-q[1].displayOrder).filter(([N])=>N!==e($));p.splice(z,0,[e($),k]),p.forEach(([N,q],te)=>{q.displayOrder=te,e(c).set(N,q)})}else if(n!==null){const x=Math.max(0,...Array.from(e(c).values()).filter(p=>p.tab===n).map(p=>p.displayOrder));k.displayOrder=x+1}e(c).set(e($),k),o(c,e(c))}o($,null),o(W,null)}function ke(l,n){l.preventDefault(),l.stopPropagation(),o(ee,n)}function Ce(){o(ee,null)}function Se(l,n,z){if(l.preventDefault(),l.stopPropagation(),e($)&&e($)!==n){const x=Array.from(e(c).entries()).filter(([p,N])=>N.tab===z).sort((p,N)=>p[1].displayOrder-N[1].displayOrder).findIndex(([p])=>p===n);x!==-1&&ye(l,z,x)}o(ee,null)}async function dr(){if(!(!e(T)||!e(V))){if(!e(R)){o(ne,"Please select a Control ID field before importing"),o(xe,"");return}if(!e(Z)||e(Z).trim()===""){o(ne,"Please enter a Control Set Name before importing"),o(xe,"");return}o(Q,!0),o(ne,""),o(xe,"");try{const l=new FormData;l.append("file",e(T),e(V)),l.append("controlIdField",e(R)),l.append("startRow",e(fe).toString()),l.append("namingConvention","kebab-case"),l.append("skipEmpty","true"),l.append("skipEmptyRows","true"),l.append("controlSetName",e(Z)||e(V).replace(/\.[^.]+$/,"")),l.append("controlSetDescription",e(ie)||`Imported from ${e(V)}`);const n=Array.from(e(c).entries()).filter(([x,p])=>p.tab!==null).map(([x,p])=>({fieldName:He(x),...p}));l.append("fieldSchema",JSON.stringify(n)),l.append("justificationFields",JSON.stringify(e(F).map(x=>He(x))));const z=await fetch("/api/import-spreadsheet",{method:"POST",body:l});if(!z.ok){const x=await z.json();throw new Error(x.error||"Import failed")}const k=await z.json();o(xe,`Successfully imported ${k.controlCount} controls into ${k.families.length} families`),de("created",{path:k.outputDir})}catch(l){o(ne,"Error importing spreadsheet: "+l.message)}finally{o(Q,!1)}}}Oe(()=>e(h),()=>{o(E,e(h).filter(l=>e(h).includes(l)))}),nr(),Ye();var Pe=Vt(),$e=a(Pe),Ee=a($e),Ze=a(Ee),Ke=a(Ze);ct(Ke,{class:"w-8 h-8 mb-4 text-gray-500 dark:text-gray-400"}),Me(4),r(Ze);var Re=i(Ze,2);r(Ee),r($e);var Ge=i($e,2);{var vr=l=>{var n=bt(),z=a(n),k=i(a(z),2),x=i(a(k)),p=i(x),N=i(a(p)),q=i(N,2),te=i(q,2);r(p),r(k),r(z),r(n),H(()=>{I(x,` ${e(V)??""} `),I(N,` ${e(w),_(()=>e(w).length)??""} | `),I(q,` ${e(h),_(()=>e(h).length)??""} | `),I(te,` ${e(be)??""}`)}),v(l,n)};A(Ge,l=>{e(V)&&l(vr)})}var Qe=i(Ge,2);{var er=l=>{var n=ft(),z=a(n),k=i(a(z),2),x=a(k,!0);r(k),r(z),r(n),H(()=>I(x,e(ne))),v(l,n)};A(Qe,l=>{e(ne)&&l(er)})}var rr=i(Qe,2);{var gr=l=>{var n=xt(),z=a(n),k=i(a(z),2),x=a(k,!0);r(k),r(z),r(n),H(()=>I(x,e(xe))),v(l,n)};A(rr,l=>{e(xe)&&l(gr)})}var cr=i(rr,2);{var X=l=>{var n=Tt(),z=we(n),k=i(a(z),2),x=a(k),p=i(a(x),2);jr(p),Me(2),r(x);var N=i(x,2),q=i(a(N),2);jr(q),Me(2),r(N),r(k);var te=i(k,2),pr=a(te),tr=i(a(pr),2);H(()=>{e(B),wr(()=>{e(w)})}),me(tr,5,()=>e(w),De,(t,s)=>{var f=mt(),m=a(f,!0);r(f);var d={};H(()=>{I(m,e(s)),d!==(d=e(s))&&(f.value=(f.__value=e(s))??"")}),v(t,f)}),r(tr),Me(2),r(pr);var ur=i(pr,2),ar=i(a(ur),2);H(()=>{e(fe),wr(()=>{e(J)})}),me(ar,5,()=>e(J),De,(t,s)=>{var f=ht(),m=a(f);r(f);var d={};H(()=>{I(m,`Row ${e(s),_(()=>e(s).row)??""}: ${e(s),_(()=>e(s).preview)??""}`),d!==(d=(e(s),_(()=>e(s).row)))&&(f.value=(f.__value=(e(s),_(()=>e(s).row)))??"")}),v(t,f)}),r(ar),Me(2),r(ur);var Mr=i(ur,2),or=i(a(Mr),2);H(()=>{e(R),wr(()=>{e(h),e(S)})});var br=a(or);br.value=br.__value="";var Zr=i(br);me(Zr,1,()=>e(h),De,(t,s)=>{const f=Ae(()=>(e(S),e(s),_(()=>e(S).length>0&&e(S)[0][e(s)]?String(e(S)[0][e(s)]).slice(0,30):""))),m=Ae(()=>(e(S),e(s),_(()=>!e(S).length||e(S).every(oe=>!oe[e(s)]||String(oe[e(s)]).length<25)))),d=Ae(()=>(e(S),e(s),_(()=>e(S).map(oe=>oe[e(s)]).filter(oe=>oe!=null&&oe!==""&&String(oe).trim()!=="")))),P=Ae(()=>new Set(e(d))),K=Ae(()=>(se(e(d)),se(e(P)),_(()=>!e(d).length||e(P).size===e(d).length))),U=Ae(()=>(se(e(d)),_(()=>e(d).length>0)));var O=Fe(),ae=we(O);{var Ue=oe=>{var _e=yt(),_r=a(_e);r(_e);var Vr={};H(()=>{I(_r,`${e(s)??""}${e(f)?` (e.g., ${e(f)})`:""}`),Vr!==(Vr=e(s))&&(_e.value=(_e.__value=e(s))??"")}),v(oe,_e)};A(ae,oe=>{e(m)&&e(K)&&e(U)&&oe(Ue)})}v(t,O)}),r(or),Me(2),r(Mr),r(te),r(z);var fr=i(z,2),zr=i(a(fr),4),xr=a(zr),Ie=i(a(xr),2),Ar=a(Ie);me(Ar,1,()=>(e(h),e(c),_(()=>e(h).filter(t=>!e(c).get(t)||e(c).get(t)?.tab===null))),t=>t,(t,s)=>{var f=wt(),m=i(a(f),2),d=a(m,!0);r(m);var P=i(m,2);{var K=U=>{var O=_t();v(U,O)};A(P,U=>{e(s)===e(R)&&U(K)})}r(f),H(()=>{Ne(f,"aria-label",`Drag ${e(s)??""} field`),I(d,e(s))}),g("dragstart",f,U=>re(U,e(s))),g("dragend",f,M),v(t,f)});var Rr=i(Ar,2);{var qr=t=>{var s=kt();v(t,s)};A(Rr,t=>{e(h),e(c),_(()=>e(h).filter(s=>!e(c).get(s)||e(c).get(s)?.tab===null).length===0)&&t(qr)})}r(Ie),r(xr);var mr=i(xr,2),Te=i(a(mr),2),Fr=a(Te);me(Fr,3,()=>(e(c),_(()=>Array.from(e(c).entries()).filter(([t,s])=>s.tab==="overview").sort((t,s)=>t[1].displayOrder-s[1].displayOrder))),([t,s])=>t,(t,s)=>{var f=kr(()=>Cr(e(s),2));let m=()=>e(f)[0];var d=Ct(),P=a(d);lr(P,{class:"w-3 h-3 mr-2 flex-shrink-0"});var K=i(P,2),U=a(K,!0);r(K),r(d),H(()=>{Ne(d,"aria-label",`${m()??""} field in Overview tab`),le(d,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
3
  ${e(ee)===m()&&e($)!==m()?"border-t-2 border-blue-500":""}`),I(U,m())}),g("dragstart",d,O=>re(O,m())),g("dragend",d,M),g("dragover",d,O=>ke(O,m())),g("dragleave",d,Ce),g("drop",d,O=>Se(O,m(),"overview")),v(t,d)});var Ur=i(Fr,2);{var Jr=t=>{var s=St();v(t,s)};A(Ur,t=>{e(c),_(()=>Array.from(e(c).entries()).filter(([s,f])=>f.tab==="overview").length===0)&&t(Jr)})}r(Te),r(mr);var hr=i(mr,2),Ve=i(a(hr),2),Or=a(Ve);me(Or,3,()=>(e(c),_(()=>Array.from(e(c).entries()).filter(([t,s])=>s.tab==="implementation").sort((t,s)=>t[1].displayOrder-s[1].displayOrder))),([t,s])=>t,(t,s)=>{var f=kr(()=>Cr(e(s),2));let m=()=>e(f)[0];var d=$t(),P=a(d);lr(P,{class:"w-3 h-3 mr-2 flex-shrink-0"});var K=i(P,2),U=a(K,!0);r(K),r(d),H(()=>{Ne(d,"aria-label",`${m()??""} field in Implementation tab`),le(d,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
4
  ${e(ee)===m()&&e($)!==m()?"border-t-2 border-green-500":""}`),I(U,m())}),g("dragstart",d,O=>re(O,m())),g("dragend",d,M),g("dragover",d,O=>ke(O,m())),g("dragleave",d,Ce),g("drop",d,O=>Se(O,m(),"implementation")),v(t,d)});var Yr=i(Or,2);{var Wr=t=>{var s=Dt();v(t,s)};A(Yr,t=>{e(c),_(()=>Array.from(e(c).entries()).filter(([s,f])=>f.tab==="implementation").length===0)&&t(Wr)})}r(Ve),r(hr);var yr=i(hr,2),je=i(a(yr),2),Hr=a(je),Xr=a(Hr);{var Kr=t=>{var s=Fe(),f=we(s);me(f,1,()=>e(F),De,(m,d)=>{var P=Mt(),K=a(P);lr(K,{class:"w-3 h-3 mr-2 flex-shrink-0"});var U=i(K,2),O=a(U,!0);r(U),r(P),H(()=>{Ne(P,"aria-label",`${e(d)??""} field in Mappings tab`),le(P,1,`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 cursor-move hover:bg-orange-200 dark:hover:bg-orange-800/30 transition-colors
@@ -1 +1 @@
1
- {"version":"1758122422367"}
1
+ {"version":"1758141471553"}
@@ -8,6 +8,7 @@ var closingBody = `
8
8
  ---
9
9
 
10
10
  <sub>**Tip:** Customize your compliance reviews with <a href="https://github.com/defenseunicorns/lula.git" class="Link--inTextBlock" target="_blank" rel="noopener noreferrer">Lula</a>.</sub>`;
11
+ var LULA_SIGNATURE = "<!-- LULA_SIGNATURE:v1 -->";
11
12
  async function postFinding(params) {
12
13
  const { octokit, postMode, owner, repo, pull_number, body } = params;
13
14
  if (postMode === "comment") {
@@ -117,7 +118,8 @@ function crawlCommand() {
117
118
  const pr = await octokit.pulls.get({ owner, repo, pull_number });
118
119
  const prBranch = pr.data.head.ref;
119
120
  const { data: files } = await octokit.pulls.listFiles({ owner, repo, pull_number });
120
- let commentBody = `## Lula Compliance Overview
121
+ let commentBody = `${LULA_SIGNATURE}
122
+ ## Lula Compliance Overview
121
123
 
122
124
  Please review the changes to ensure they meet compliance standards.
123
125
 
@@ -128,7 +130,6 @@ Lula reviewed ${files.length} files changed that affect compliance.
128
130
  `;
129
131
  for (const file of files) {
130
132
  if (file.status === "added") continue;
131
- console.log(`Commenting regarding \`${file.filename}\`.`);
132
133
  try {
133
134
  const [oldText, newText] = await Promise.all([
134
135
  fetchRawFileViaAPI({ octokit, owner, repo, path: file.filename, ref: "main" }),
@@ -136,6 +137,7 @@ Lula reviewed ${files.length} files changed that affect compliance.
136
137
  ]);
137
138
  const changedBlocks = getChangedBlocks(oldText, newText);
138
139
  for (const block of changedBlocks) {
140
+ console.log(`Commenting regarding \`${file.filename}\`.`);
139
141
  leavePost = true;
140
142
  commentBody += `
141
143
 
@@ -155,6 +157,12 @@ Lula reviewed ${files.length} files changed that affect compliance.
155
157
  console.error(`Error processing ${file.filename}: ${err}`);
156
158
  }
157
159
  }
160
+ if (opts.postMode === "comment") {
161
+ await deleteOldIssueComments({ octokit, owner, repo, pull_number });
162
+ } else {
163
+ await dismissOldReviews({ octokit, owner, repo, pull_number });
164
+ await deleteOldReviewComments({ octokit, owner, repo, pull_number });
165
+ }
158
166
  if (leavePost) {
159
167
  await postFinding({
160
168
  octokit,
@@ -176,8 +184,96 @@ ${commentBody + closingBody}
176
184
  }
177
185
  });
178
186
  }
187
+ async function deleteOldIssueComments({
188
+ octokit,
189
+ owner,
190
+ repo,
191
+ pull_number
192
+ }) {
193
+ let page = 1;
194
+ while (true) {
195
+ const { data: comments } = await octokit.issues.listComments({
196
+ owner,
197
+ repo,
198
+ issue_number: pull_number,
199
+ per_page: 100,
200
+ page
201
+ });
202
+ if (!comments.length) break;
203
+ for (const c of comments) {
204
+ const hasSignature = (c.body ?? "").includes(LULA_SIGNATURE);
205
+ if (hasSignature) {
206
+ await octokit.issues.deleteComment({ owner, repo, comment_id: c.id });
207
+ break;
208
+ }
209
+ }
210
+ page++;
211
+ }
212
+ }
213
+ async function deleteOldReviewComments({
214
+ octokit,
215
+ owner,
216
+ repo,
217
+ pull_number
218
+ }) {
219
+ let page = 1;
220
+ while (true) {
221
+ const { data: reviewComments } = await octokit.pulls.listReviewComments({
222
+ owner,
223
+ repo,
224
+ pull_number,
225
+ per_page: 100,
226
+ page
227
+ });
228
+ if (!reviewComments.length) break;
229
+ for (const rc of reviewComments) {
230
+ const hasSignature = (rc.body ?? "").includes(LULA_SIGNATURE);
231
+ if (hasSignature) {
232
+ await octokit.pulls.deleteReviewComment({ owner, repo, comment_id: rc.id });
233
+ break;
234
+ }
235
+ }
236
+ page++;
237
+ }
238
+ }
239
+ async function dismissOldReviews({
240
+ octokit,
241
+ owner,
242
+ repo,
243
+ pull_number
244
+ }) {
245
+ let page = 1;
246
+ while (true) {
247
+ const { data: reviews } = await octokit.pulls.listReviews({
248
+ owner,
249
+ repo,
250
+ pull_number,
251
+ per_page: 100,
252
+ page
253
+ });
254
+ if (!reviews.length) break;
255
+ for (const r of reviews) {
256
+ const hasSignature = (r.body ?? "").includes(LULA_SIGNATURE);
257
+ if (hasSignature) {
258
+ await octokit.pulls.dismissReview({
259
+ owner,
260
+ repo,
261
+ pull_number,
262
+ review_id: r.id,
263
+ message: "Superseded by a new Lula compliance review."
264
+ });
265
+ break;
266
+ }
267
+ }
268
+ page++;
269
+ }
270
+ }
179
271
  export {
272
+ LULA_SIGNATURE,
180
273
  crawlCommand,
274
+ deleteOldIssueComments,
275
+ deleteOldReviewComments,
276
+ dismissOldReviews,
181
277
  extractMapBlocks,
182
278
  fetchRawFileViaAPI,
183
279
  getChangedBlocks,
@@ -1951,7 +1951,10 @@ var init_fileStore = __esm({
1951
1951
  const controlId = mapping.control_id;
1952
1952
  const family = this.getControlFamily(controlId);
1953
1953
  const familyDir = join2(this.mappingsDir, family);
1954
- const mappingFile = join2(familyDir, `${controlId}-mappings.yaml`);
1954
+ const mappingFile = join2(
1955
+ familyDir,
1956
+ `${controlId.replace(/[^a-zA-Z0-9-]/g, "_")}-mappings.yaml`
1957
+ );
1955
1958
  if (!existsSync2(familyDir)) {
1956
1959
  mkdirSync(familyDir, { recursive: true });
1957
1960
  }
@@ -2049,7 +2052,10 @@ var init_fileStore = __esm({
2049
2052
  for (const [controlId, controlMappings] of mappingsByControl) {
2050
2053
  const family = this.getControlFamily(controlId);
2051
2054
  const familyDir = join2(this.mappingsDir, family);
2052
- const mappingFile = join2(familyDir, `${controlId}-mappings.yaml`);
2055
+ const mappingFile = join2(
2056
+ familyDir,
2057
+ `${controlId.replace(/[^a-zA-Z0-9-]/g, "_")}-mappings.yaml`
2058
+ );
2053
2059
  if (!existsSync2(familyDir)) {
2054
2060
  mkdirSync(familyDir, { recursive: true });
2055
2061
  }
@@ -3347,7 +3353,9 @@ var init_spreadsheetRoutes = __esm({
3347
3353
  uiType = "long_text";
3348
3354
  }
3349
3355
  let category = frontendConfig?.category || "custom";
3350
- if (!frontendConfig) {
3356
+ if (justificationFields.includes(fieldName)) {
3357
+ category = "mappings";
3358
+ } else if (!frontendConfig) {
3351
3359
  if (fieldName.includes("status") || fieldName.includes("state")) {
3352
3360
  category = "compliance";
3353
3361
  } else if (fieldName.includes("title") || fieldName.includes("name") || fieldName.includes("description")) {
@@ -3375,8 +3383,8 @@ var init_spreadsheetRoutes = __esm({
3375
3383
  // Control ID is always first
3376
3384
  category: isControlIdField ? "core" : category,
3377
3385
  // Control ID is always core
3378
- tab: isControlIdField ? "overview" : frontendConfig?.tab || void 0
3379
- // Control ID is always in overview
3386
+ tab: isControlIdField ? "overview" : justificationFields.includes(fieldName) ? "mappings" : frontendConfig?.tab || void 0
3387
+ // Use frontend config or default
3380
3388
  };
3381
3389
  if (uiType === "select") {
3382
3390
  fieldDef.options = Array.from(metadata.uniqueValues).sort();
@@ -3439,7 +3447,7 @@ var init_spreadsheetRoutes = __esm({
3439
3447
  if (fieldName === "family") return;
3440
3448
  if (justificationFields.includes(fieldName) && control[fieldName] !== void 0 && control[fieldName] !== null) {
3441
3449
  justificationContents.push(control[fieldName]);
3442
- return;
3450
+ filteredControl[fieldName] = control[fieldName];
3443
3451
  }
3444
3452
  const isInFrontendSchema = frontendFieldSchema?.some((f) => f.fieldName === fieldName);
3445
3453
  const isInFieldsMetadata = fields.hasOwnProperty(fieldName);
@@ -4709,7 +4717,7 @@ var WebSocketManager = class {
4709
4717
  totalCommits: controlHistory.totalCommits,
4710
4718
  commits: controlHistory.commits?.length || 0
4711
4719
  });
4712
- const mappingFilename = `${control.id}-mappings.yaml`;
4720
+ const mappingFilename = `${control.id.replace(/[^a-zA-Z0-9-]/g, "_")}-mappings.yaml`;
4713
4721
  const mappingPath = join5(currentPath2, "mappings", family, mappingFilename);
4714
4722
  let mappingHistory = { commits: [], totalCommits: 0 };
4715
4723
  if (existsSync6(mappingPath)) {
@@ -1933,7 +1933,10 @@ var init_fileStore = __esm({
1933
1933
  const controlId = mapping.control_id;
1934
1934
  const family = this.getControlFamily(controlId);
1935
1935
  const familyDir = join2(this.mappingsDir, family);
1936
- const mappingFile = join2(familyDir, `${controlId}-mappings.yaml`);
1936
+ const mappingFile = join2(
1937
+ familyDir,
1938
+ `${controlId.replace(/[^a-zA-Z0-9-]/g, "_")}-mappings.yaml`
1939
+ );
1937
1940
  if (!existsSync2(familyDir)) {
1938
1941
  mkdirSync(familyDir, { recursive: true });
1939
1942
  }
@@ -2031,7 +2034,10 @@ var init_fileStore = __esm({
2031
2034
  for (const [controlId, controlMappings] of mappingsByControl) {
2032
2035
  const family = this.getControlFamily(controlId);
2033
2036
  const familyDir = join2(this.mappingsDir, family);
2034
- const mappingFile = join2(familyDir, `${controlId}-mappings.yaml`);
2037
+ const mappingFile = join2(
2038
+ familyDir,
2039
+ `${controlId.replace(/[^a-zA-Z0-9-]/g, "_")}-mappings.yaml`
2040
+ );
2035
2041
  if (!existsSync2(familyDir)) {
2036
2042
  mkdirSync(familyDir, { recursive: true });
2037
2043
  }
@@ -3329,7 +3335,9 @@ var init_spreadsheetRoutes = __esm({
3329
3335
  uiType = "long_text";
3330
3336
  }
3331
3337
  let category = frontendConfig?.category || "custom";
3332
- if (!frontendConfig) {
3338
+ if (justificationFields.includes(fieldName)) {
3339
+ category = "mappings";
3340
+ } else if (!frontendConfig) {
3333
3341
  if (fieldName.includes("status") || fieldName.includes("state")) {
3334
3342
  category = "compliance";
3335
3343
  } else if (fieldName.includes("title") || fieldName.includes("name") || fieldName.includes("description")) {
@@ -3357,8 +3365,8 @@ var init_spreadsheetRoutes = __esm({
3357
3365
  // Control ID is always first
3358
3366
  category: isControlIdField ? "core" : category,
3359
3367
  // Control ID is always core
3360
- tab: isControlIdField ? "overview" : frontendConfig?.tab || void 0
3361
- // Control ID is always in overview
3368
+ tab: isControlIdField ? "overview" : justificationFields.includes(fieldName) ? "mappings" : frontendConfig?.tab || void 0
3369
+ // Use frontend config or default
3362
3370
  };
3363
3371
  if (uiType === "select") {
3364
3372
  fieldDef.options = Array.from(metadata.uniqueValues).sort();
@@ -3421,7 +3429,7 @@ var init_spreadsheetRoutes = __esm({
3421
3429
  if (fieldName === "family") return;
3422
3430
  if (justificationFields.includes(fieldName) && control[fieldName] !== void 0 && control[fieldName] !== null) {
3423
3431
  justificationContents.push(control[fieldName]);
3424
- return;
3432
+ filteredControl[fieldName] = control[fieldName];
3425
3433
  }
3426
3434
  const isInFrontendSchema = frontendFieldSchema?.some((f) => f.fieldName === fieldName);
3427
3435
  const isInFieldsMetadata = fields.hasOwnProperty(fieldName);
@@ -4686,7 +4694,7 @@ var WebSocketManager = class {
4686
4694
  totalCommits: controlHistory.totalCommits,
4687
4695
  commits: controlHistory.commits?.length || 0
4688
4696
  });
4689
- const mappingFilename = `${control.id}-mappings.yaml`;
4697
+ const mappingFilename = `${control.id.replace(/[^a-zA-Z0-9-]/g, "_")}-mappings.yaml`;
4690
4698
  const mappingPath = join5(currentPath2, "mappings", family, mappingFilename);
4691
4699
  let mappingHistory = { commits: [], totalCommits: 0 };
4692
4700
  if (existsSync5(mappingPath)) {
@@ -1933,7 +1933,10 @@ var init_fileStore = __esm({
1933
1933
  const controlId = mapping.control_id;
1934
1934
  const family = this.getControlFamily(controlId);
1935
1935
  const familyDir = join2(this.mappingsDir, family);
1936
- const mappingFile = join2(familyDir, `${controlId}-mappings.yaml`);
1936
+ const mappingFile = join2(
1937
+ familyDir,
1938
+ `${controlId.replace(/[^a-zA-Z0-9-]/g, "_")}-mappings.yaml`
1939
+ );
1937
1940
  if (!existsSync2(familyDir)) {
1938
1941
  mkdirSync(familyDir, { recursive: true });
1939
1942
  }
@@ -2031,7 +2034,10 @@ var init_fileStore = __esm({
2031
2034
  for (const [controlId, controlMappings] of mappingsByControl) {
2032
2035
  const family = this.getControlFamily(controlId);
2033
2036
  const familyDir = join2(this.mappingsDir, family);
2034
- const mappingFile = join2(familyDir, `${controlId}-mappings.yaml`);
2037
+ const mappingFile = join2(
2038
+ familyDir,
2039
+ `${controlId.replace(/[^a-zA-Z0-9-]/g, "_")}-mappings.yaml`
2040
+ );
2035
2041
  if (!existsSync2(familyDir)) {
2036
2042
  mkdirSync(familyDir, { recursive: true });
2037
2043
  }
@@ -3329,7 +3335,9 @@ var init_spreadsheetRoutes = __esm({
3329
3335
  uiType = "long_text";
3330
3336
  }
3331
3337
  let category = frontendConfig?.category || "custom";
3332
- if (!frontendConfig) {
3338
+ if (justificationFields.includes(fieldName)) {
3339
+ category = "mappings";
3340
+ } else if (!frontendConfig) {
3333
3341
  if (fieldName.includes("status") || fieldName.includes("state")) {
3334
3342
  category = "compliance";
3335
3343
  } else if (fieldName.includes("title") || fieldName.includes("name") || fieldName.includes("description")) {
@@ -3357,8 +3365,8 @@ var init_spreadsheetRoutes = __esm({
3357
3365
  // Control ID is always first
3358
3366
  category: isControlIdField ? "core" : category,
3359
3367
  // Control ID is always core
3360
- tab: isControlIdField ? "overview" : frontendConfig?.tab || void 0
3361
- // Control ID is always in overview
3368
+ tab: isControlIdField ? "overview" : justificationFields.includes(fieldName) ? "mappings" : frontendConfig?.tab || void 0
3369
+ // Use frontend config or default
3362
3370
  };
3363
3371
  if (uiType === "select") {
3364
3372
  fieldDef.options = Array.from(metadata.uniqueValues).sort();
@@ -3421,7 +3429,7 @@ var init_spreadsheetRoutes = __esm({
3421
3429
  if (fieldName === "family") return;
3422
3430
  if (justificationFields.includes(fieldName) && control[fieldName] !== void 0 && control[fieldName] !== null) {
3423
3431
  justificationContents.push(control[fieldName]);
3424
- return;
3432
+ filteredControl[fieldName] = control[fieldName];
3425
3433
  }
3426
3434
  const isInFrontendSchema = frontendFieldSchema?.some((f) => f.fieldName === fieldName);
3427
3435
  const isInFieldsMetadata = fields.hasOwnProperty(fieldName);
@@ -4686,7 +4694,7 @@ var WebSocketManager = class {
4686
4694
  totalCommits: controlHistory.totalCommits,
4687
4695
  commits: controlHistory.commits?.length || 0
4688
4696
  });
4689
- const mappingFilename = `${control.id}-mappings.yaml`;
4697
+ const mappingFilename = `${control.id.replace(/[^a-zA-Z0-9-]/g, "_")}-mappings.yaml`;
4690
4698
  const mappingPath = join5(currentPath2, "mappings", family, mappingFilename);
4691
4699
  let mappingHistory = { commits: [], totalCommits: 0 };
4692
4700
  if (existsSync5(mappingPath)) {
@@ -354,7 +354,10 @@ var FileStore = class {
354
354
  const controlId = mapping.control_id;
355
355
  const family = this.getControlFamily(controlId);
356
356
  const familyDir = join2(this.mappingsDir, family);
357
- const mappingFile = join2(familyDir, `${controlId}-mappings.yaml`);
357
+ const mappingFile = join2(
358
+ familyDir,
359
+ `${controlId.replace(/[^a-zA-Z0-9-]/g, "_")}-mappings.yaml`
360
+ );
358
361
  if (!existsSync2(familyDir)) {
359
362
  mkdirSync(familyDir, { recursive: true });
360
363
  }
@@ -452,7 +455,10 @@ var FileStore = class {
452
455
  for (const [controlId, controlMappings] of mappingsByControl) {
453
456
  const family = this.getControlFamily(controlId);
454
457
  const familyDir = join2(this.mappingsDir, family);
455
- const mappingFile = join2(familyDir, `${controlId}-mappings.yaml`);
458
+ const mappingFile = join2(
459
+ familyDir,
460
+ `${controlId.replace(/[^a-zA-Z0-9-]/g, "_")}-mappings.yaml`
461
+ );
456
462
  if (!existsSync2(familyDir)) {
457
463
  mkdirSync(familyDir, { recursive: true });
458
464
  }
@@ -294,7 +294,9 @@ router.post("/import-spreadsheet", upload.single("file"), async (req, res) => {
294
294
  uiType = "long_text";
295
295
  }
296
296
  let category = frontendConfig?.category || "custom";
297
- if (!frontendConfig) {
297
+ if (justificationFields.includes(fieldName)) {
298
+ category = "mappings";
299
+ } else if (!frontendConfig) {
298
300
  if (fieldName.includes("status") || fieldName.includes("state")) {
299
301
  category = "compliance";
300
302
  } else if (fieldName.includes("title") || fieldName.includes("name") || fieldName.includes("description")) {
@@ -322,8 +324,8 @@ router.post("/import-spreadsheet", upload.single("file"), async (req, res) => {
322
324
  // Control ID is always first
323
325
  category: isControlIdField ? "core" : category,
324
326
  // Control ID is always core
325
- tab: isControlIdField ? "overview" : frontendConfig?.tab || void 0
326
- // Control ID is always in overview
327
+ tab: isControlIdField ? "overview" : justificationFields.includes(fieldName) ? "mappings" : frontendConfig?.tab || void 0
328
+ // Use frontend config or default
327
329
  };
328
330
  if (uiType === "select") {
329
331
  fieldDef.options = Array.from(metadata.uniqueValues).sort();
@@ -386,7 +388,7 @@ router.post("/import-spreadsheet", upload.single("file"), async (req, res) => {
386
388
  if (fieldName === "family") return;
387
389
  if (justificationFields.includes(fieldName) && control[fieldName] !== void 0 && control[fieldName] !== null) {
388
390
  justificationContents.push(control[fieldName]);
389
- return;
391
+ filteredControl[fieldName] = control[fieldName];
390
392
  }
391
393
  const isInFrontendSchema = frontendFieldSchema?.some((f) => f.fieldName === fieldName);
392
394
  const isInFieldsMetadata = fields.hasOwnProperty(fieldName);