Files
OpenGFW/web/dist/assets/RulesView-SxOStRNP.js
T
meiandClaude Opus 5 5a7722d1d2 feat: add embedded web UI
Adds an optional web dashboard served by OpenGFW itself, enabled with a new
`web` section in the config file.

Backend (web package, decoupled from engine/io so it builds on any OS):
- hub.go collects statistics off the engine logger callbacks: atomic counters,
  two ring-buffered time series (10s and 1min buckets), top N hosts/blocked
  destinations/rules/analyzers, and a 512 entry event buffer fanned out to
  connected clients over SSE. Slow clients drop frames instead of blocking
  the engine.
- api.go exposes /api/v1 for info, meta, metrics, events, the SSE stream and
  ruleset read/validate/replace.
- auth.go implements password login with in-memory session tokens and login
  rate limiting. Mutating endpoints require the bearer token (the session
  cookie is only accepted for GET), which makes them CSRF-safe.
- cmd/web.go implements the rule manager: rules are compiled before anything
  is written, the file is replaced atomically and the engine is hot reloaded.
  The SIGHUP handler now shares that same path.
- web/devserver serves the UI with synthetic traffic for frontend work on
  machines where the engine itself cannot be built.

Frontend (web/frontend, Vue 3 + Vite + Tailwind CSS v4 + Reka UI):
dashboard, live event feed with analyzer property inspection, visual and YAML
rule editors, analyzer overview and settings. Responsive down to phone sizes
with a bottom tab bar and bottom-sheet dialogs, plus light/dark themes and
English/Chinese translations.

The built UI in web/dist is committed and embedded with go:embed so that
`go build` works without Node; CI builds the frontend and checks that the
committed output is up to date.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 08:09:11 +08:00

37 lines
20 KiB
JavaScript

import{c as E,B as ge,d as M,x as be,o as c,h as C,C as F,g as B,a as q,j as $,F as N,r as ie,D as ke,E as xe,G as Q,p as u,w as o,H as L,u as e,I as we,J as de,P as W,m as V,K as ce,L as Ve,n as Ce,e as X,f as Y,M as T,N as j,l as n,b as g,t as r,s as I,O as qe,Q as $e,k as b,_ as Se,R as P,y as Ie,z as K}from"./index-D3ZCYstt.js";import{_ as ze}from"./PageHeader.vue_vue_type_script_setup_true_lang-CDyKzgiP.js";import{_ as O}from"./Badge.vue_vue_type_script_setup_true_lang--8bF8KCa.js";import{_ as te,T as Ae}from"./Modal.vue_vue_type_script_setup_true_lang-gNNtNPLv.js";import{V as Be,u as Me,P as Re,_ as se}from"./Select.vue_vue_type_script_setup_true_lang-C15l-n0X.js";import{u as Ee,c as Te}from"./Collection-D-pf6tmY.js";import{i as Pe,m as Ue,c as He,_ as ue,a as je,b as ne}from"./TabsTrigger.vue_vue_type_script_setup_true_lang-DTNukDpV.js";/**
* @license lucide-vue-next v0.469.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const Oe=E("ArrowDownIcon",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);/**
* @license lucide-vue-next v0.469.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const Fe=E("ArrowUpIcon",[["path",{d:"m5 12 7-7 7 7",key:"hav0vg"}],["path",{d:"M12 19V5",key:"x0mq9r"}]]);/**
* @license lucide-vue-next v0.469.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const Ne=E("FileCode2Icon",[["path",{d:"M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4",key:"1pf5j1"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"m5 12-3 3 3 3",key:"oke12k"}],["path",{d:"m9 18 3-3-3-3",key:"112psh"}]]);/**
* @license lucide-vue-next v0.469.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const Le=E("PencilIcon",[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",key:"1a8usu"}],["path",{d:"m15 5 4 4",key:"1mk7zo"}]]);/**
* @license lucide-vue-next v0.469.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const De=E("PlusIcon",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);/**
* @license lucide-vue-next v0.469.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const Je=E("RotateCcwIcon",[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}]]);/**
* @license lucide-vue-next v0.469.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const Ke=E("SaveIcon",[["path",{d:"M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z",key:"1c8476"}],["path",{d:"M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7",key:"1ydtos"}],["path",{d:"M7 3v4a1 1 0 0 0 1 1h7",key:"t51u73"}]]);function Ge(){var l,t;const k=(t=(l=ge())==null?void 0:l.vnode)==null?void 0:t.scopeId;return k?{[k]:""}:{}}var Qe=M({inheritAttrs:!1,__name:"VisuallyHiddenInputBubble",props:{name:{type:String,required:!0},value:{type:null,required:!0},checked:{type:Boolean,required:!1,default:void 0},required:{type:Boolean,required:!1},disabled:{type:Boolean,required:!1},feature:{type:String,required:!1,default:"fully-hidden"}},setup(k){const l=k,{primitiveElement:t,currentElement:i}=Ee(),m=B(()=>l.checked??l.value);return be(m,(f,p)=>{if(!i.value)return;const _=i.value,w=window.HTMLInputElement.prototype,v=Object.getOwnPropertyDescriptor(w,"value").set;if(v&&f!==p){const A=new Event("input",{bubbles:!0}),S=new Event("change",{bubbles:!0});v.call(_,f),_.dispatchEvent(A),_.dispatchEvent(S)}}),(f,p)=>(c(),C(Be,F({ref_key:"primitiveElement",ref:t},{...l,...f.$attrs},{as:"input"}),null,16))}}),oe=Qe,We=M({inheritAttrs:!1,__name:"VisuallyHiddenInput",props:{name:{type:String,required:!0},value:{type:null,required:!0},checked:{type:Boolean,required:!1,default:void 0},required:{type:Boolean,required:!1},disabled:{type:Boolean,required:!1},feature:{type:String,required:!1,default:"fully-hidden"}},setup(k){const l=k,t=B(()=>typeof l.value=="object"&&Array.isArray(l.value)&&l.value.length===0&&l.required),i=B(()=>typeof l.value=="string"||typeof l.value=="number"||typeof l.value=="boolean"||l.value===null||l.value===void 0?[{name:l.name,value:l.value}]:typeof l.value=="object"&&Array.isArray(l.value)?l.value.flatMap((m,f)=>typeof m=="object"?Object.entries(m).map(([p,_])=>({name:`${l.name}[${f}][${p}]`,value:_})):{name:`${l.name}[${f}]`,value:m}):l.value!==null&&typeof l.value=="object"&&!Array.isArray(l.value)?Object.entries(l.value).map(([m,f])=>({name:`${l.name}[${m}]`,value:f})):[]);return(m,f)=>(c(),q(N,null,[$(" We render single input if it's required "),t.value?(c(),C(oe,F({key:m.name},{...l,...m.$attrs},{name:m.name,value:m.value}),null,16,["name","value"])):(c(!0),q(N,{key:1},ie(i.value,p=>(c(),C(oe,F({key:p.name},{ref_for:!0},{...l,...m.$attrs},{name:p.name,value:p.value}),null,16,["name","value"]))),128))],2112))}}),Xe=We;const[Ye,Ze]=Te("SwitchRoot");var ea=M({inheritAttrs:!1,__name:"SwitchRoot",props:{defaultValue:{type:null,required:!1},modelValue:{type:null,required:!1,default:void 0},disabled:{type:Boolean,required:!1},id:{type:String,required:!1},value:{type:String,required:!1,default:"on"},trueValue:{type:null,required:!1,default:()=>!0},falseValue:{type:null,required:!1,default:()=>!1},asChild:{type:Boolean,required:!1},as:{type:null,required:!1,default:"button"},name:{type:String,required:!1},required:{type:Boolean,required:!1}},emits:["update:modelValue"],setup(k,{emit:l}){const t=k,i=l,{disabled:m}=ke(t),f=xe(t,"modelValue",i,{defaultValue:t.defaultValue??t.falseValue,passive:t.modelValue===void 0}),p=B(()=>f.value===t.trueValue);function _(){m.value||(f.value=p.value?t.falseValue:t.trueValue)}const{forwardRef:w,currentElement:h}=Q(),v=Me(h),A=Ge(),S=B(()=>{var x;return t.id&&h.value?(x=document.querySelector(`[for="${t.id}"]`))==null?void 0:x.innerText:void 0});return Ze({checked:p,toggleCheck:_,disabled:m}),(x,D)=>(c(),q(N,null,[u(e(W),F({id:x.id,ref:e(w),role:"switch",type:x.as==="button"?"button":void 0,value:x.value,"aria-label":x.$attrs["aria-label"]||S.value,"aria-checked":p.value,"aria-required":x.required,"data-state":p.value?"checked":"unchecked","data-disabled":e(m)?"":void 0,"as-child":x.asChild,as:x.as,disabled:e(m)},{...e(A),...x.$attrs},{onClick:_,onKeydown:we(de(_,["prevent"]),["enter"])}),{default:o(()=>[L(x.$slots,"default",{modelValue:e(f),checked:p.value})]),_:3},16,["id","type","value","aria-label","aria-checked","aria-required","data-state","data-disabled","as-child","as","disabled","onKeydown"]),e(v)&&x.name?(c(),C(e(Xe),F({key:0,type:"checkbox",name:x.name,disabled:e(m),required:x.required,value:x.value,checked:p.value},e(A)),null,16,["name","disabled","required","value","checked"])):$("v-if",!0)],64))}}),aa=ea,la=M({__name:"SwitchThumb",props:{asChild:{type:Boolean,required:!1},as:{type:null,required:!1,default:"span"}},setup(k){const l=Ye();return Q(),(t,i)=>(c(),C(e(W),{"data-state":e(l).checked.value?"checked":"unchecked","data-disabled":e(l).disabled.value?"":void 0,"as-child":t.asChild,as:t.as},{default:o(()=>[L(t.$slots,"default")]),_:3},8,["data-state","data-disabled","as-child","as"]))}}),ta=la,sa=M({__name:"TabsContent",props:{value:{type:[String,Number],required:!0},forceMount:{type:Boolean,required:!1},asChild:{type:Boolean,required:!1},as:{type:null,required:!1}},setup(k){const l=k,{forwardRef:t}=Q(),i=Pe(),m=B(()=>Ue(i.baseId,l.value)),f=B(()=>He(i.baseId,l.value)),p=B(()=>l.value===i.modelValue.value),_=V(p.value);return ce(()=>{i.registerContent(l.value),requestAnimationFrame(()=>{_.value=!1})}),Ve(()=>{i.unregisterContent(l.value)}),(w,h)=>(c(),C(e(Re),{present:w.forceMount||p.value,"force-mount":""},{default:o(({present:v})=>[u(e(W),{id:f.value,ref:e(t),"as-child":w.asChild,as:w.as,role:"tabpanel","data-state":p.value?"active":"inactive","data-orientation":e(i).orientation.value,"aria-labelledby":m.value,hidden:!v,tabindex:"0",style:Ce({animationDuration:_.value?"0s":void 0})},{default:o(()=>[!e(i).unmountOnHide.value||v?L(w.$slots,"default",{key:0}):$("v-if",!0)]),_:2},1032,["id","as-child","as","data-state","data-orientation","aria-labelledby","hidden","style"])]),_:3},8,["present"]))}}),ua=sa;const na=M({__name:"Switch",props:{class:{},modelValue:{type:Boolean},id:{}},emits:["update:modelValue"],setup(k,{emit:l}){const t=k,i=l;return(m,f)=>(c(),C(e(aa),{id:t.id,"model-value":t.modelValue,class:X(e(Y)("peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border border-transparent transition-colors outline-none focus-visible:ring-[3px] focus-visible:ring-ring/40 disabled:cursor-not-allowed disabled:opacity-50",t.class)),"onUpdate:modelValue":f[0]||(f[0]=p=>i("update:modelValue",p))},{default:o(()=>[u(e(ta),{class:"bg-background pointer-events-none block size-4 rounded-full shadow-sm ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0.5"})]),_:1},8,["id","model-value","class"]))}}),re=M({__name:"TabsContent",props:{class:{},value:{}},setup(k){const l=k;return(t,i)=>(c(),C(e(ua),{value:l.value,class:X(e(Y)("outline-none",l.class))},{default:o(()=>[L(t.$slots,"default")]),_:3},8,["value","class"]))}}),oa=["value"],G=M({__name:"Textarea",props:{class:{},modelValue:{}},emits:["update:modelValue"],setup(k,{emit:l}){const t=k,i=l;return(m,f)=>(c(),q("textarea",{value:t.modelValue,class:X(e(Y)("border-input bg-background flex min-h-20 w-full rounded-md border px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none sm:text-sm","placeholder:text-muted-foreground field-sizing-content","focus-visible:border-ring focus-visible:ring-ring/40 focus-visible:ring-[3px]","disabled:cursor-not-allowed disabled:opacity-50",t.class)),onInput:f[0]||(f[0]=p=>i("update:modelValue",p.target.value))},null,42,oa))}}),ra={class:"hidden sm:inline"},ia={class:"hidden sm:inline"},da={class:"mb-3 flex flex-wrap items-center gap-2"},ca={key:1,class:"text-muted-foreground ml-auto hidden truncate font-mono text-[11px] sm:inline"},va={key:0,class:"border-destructive/40 bg-destructive/10 text-destructive mb-3 rounded-lg border px-3 py-2 font-mono text-xs break-words whitespace-pre-wrap"},ma={key:0,class:"text-muted-foreground py-12 text-center text-sm"},fa={key:1,class:"flex flex-col gap-2"},pa={class:"flex items-start justify-between gap-3"},_a={class:"flex min-w-0 flex-col gap-1.5"},ya={class:"flex flex-wrap items-center gap-1.5"},ha={class:"text-muted-foreground font-mono text-[11px] tabular-nums"},ga={class:"truncate text-sm font-medium"},ba={class:"text-muted-foreground bg-muted/60 rounded-md px-2 py-1.5 font-mono text-[11px] leading-relaxed break-all sm:text-xs"},ka={class:"flex shrink-0 flex-col gap-1 sm:flex-row"},xa={key:0,class:"text-muted-foreground py-10 text-center text-sm"},wa={class:"text-muted-foreground mt-2 text-xs"},Va={class:"flex flex-col gap-2"},Ca={class:"grid gap-4 sm:grid-cols-2"},qa={class:"flex flex-col gap-2"},$a={class:"flex flex-col justify-end gap-2"},Sa={class:"flex h-9 items-center"},Ia={key:0,class:"flex flex-col gap-4"},za={class:"flex flex-col gap-2"},Aa={class:"flex flex-col gap-2"},Ba={class:"flex flex-col gap-2"},Ma={key:1,class:"text-destructive text-sm"},Oa=M({__name:"RulesView",setup(k){const l=V("visual"),t=V([]),i=V(""),m=V(""),f=V(null),p=V(!0),_=V(!1),w=V(!1),h=V(""),v=V(null),A=V(-1),S=V(-1),x=B(()=>{var a;return[{value:"",label:n("rules.actionNone")},...(((a=f.value)==null?void 0:a.actions)??[]).map(s=>({value:s,label:n(`action.${s}`)}))]}),D=B(()=>{var a;return(((a=f.value)==null?void 0:a.modifiers)??[]).map(s=>({value:s,label:s}))}),ve=a=>{switch(a){case"allow":return"allow";case"block":return"block";case"drop":return"drop";case"modify":return"modify";default:return"muted"}};ce(async()=>{try{const[a,s]=await Promise.all([T.rules(),T.meta()]);t.value=a.rules??[],i.value=a.raw,m.value=a.path,f.value=s}catch(a){h.value=a instanceof j?a.message:String(a)}finally{p.value=!1}});async function Z(a){if(!(a===l.value||_.value)){_.value=!0,h.value="";try{const s=await T.validateRules(a==="yaml"?{rules:t.value}:{raw:i.value});if(a==="yaml")i.value=s.raw;else{if(!s.valid){h.value=s.error??n("rules.invalid");return}t.value=s.rules??[]}l.value=a}catch(s){h.value=s instanceof j?s.message:String(s)}finally{_.value=!1}}}function ee(){return l.value==="yaml"?{raw:i.value}:{rules:t.value}}async function me(){_.value=!0,h.value="";try{const a=await T.validateRules(ee());a.valid?K.success(n("rules.valid")):h.value=a.error??n("rules.invalid")}catch(a){h.value=a instanceof j?a.message:String(a)}finally{_.value=!1}}async function fe(){_.value=!0,h.value="";try{const a=await T.saveRules(ee());t.value=a.rules??[],i.value=a.raw,w.value=!1,K.success(n("rules.saved"),n("rules.count",{n:t.value.length}))}catch(a){h.value=a instanceof j?a.message:String(a),K.error(n("rules.invalid"),h.value)}finally{_.value=!1}}async function pe(){_.value=!0,h.value="";try{const a=await T.rules();t.value=a.rules??[],i.value=a.raw,w.value=!1}catch(a){h.value=a instanceof j?a.message:String(a)}finally{_.value=!1}}function ae(a,s){const z=a+s;if(z<0||z>=t.value.length)return;const d=[...t.value],[y]=d.splice(a,1);d.splice(z,0,y),t.value=d,w.value=!0}function _e(){A.value=-1,v.value={name:"",action:"block",log:!1,expr:""},U.value="{}"}function ye(a){var s;A.value=a,v.value={...t.value[a]},U.value=JSON.stringify(((s=t.value[a].modifier)==null?void 0:s.args)??{},null,2)}const U=V("{}"),R=V("");function le(){var z,d;const a=v.value;if(!a)return;if(!a.name.trim()){R.value=n("rules.nameRequired");return}if(!a.expr.trim()){R.value=n("rules.exprRequired");return}if(a.action==="modify")try{const y=JSON.parse(U.value||"{}");a.modifier={name:((z=a.modifier)==null?void 0:z.name)??((d=D.value[0])==null?void 0:d.value)??"",args:y}}catch{R.value="JSON";return}else a.modifier=null;const s=[...t.value];A.value>=0?s[A.value]=a:s.push(a),t.value=s,w.value=!0,v.value=null,R.value=""}function he(a){t.value=t.value.filter((s,z)=>z!==a),w.value=!0,S.value=-1}return(a,s)=>{var z;return c(),q("div",null,[u(ze,{title:e(n)("rules.title"),description:e(n)("rules.subtitle")},{actions:o(()=>[u(e(I),{variant:"ghost",size:"sm",disabled:_.value,onClick:pe},{default:o(()=>[u(e(Je),{class:"size-3.5"}),g("span",ra,r(e(n)("common.refresh")),1)]),_:1},8,["disabled"]),u(e(I),{variant:"outline",size:"sm",disabled:_.value,onClick:me},{default:o(()=>[u(e(qe),{class:"size-3.5"}),g("span",ia,r(e(n)("rules.validate")),1)]),_:1},8,["disabled"]),u(e(I),{size:"sm",disabled:_.value,onClick:fe},{default:o(()=>[_.value?(c(),C(e($e),{key:0,class:"size-3.5 animate-spin"})):(c(),C(e(Ke),{key:1,class:"size-3.5"})),b(" "+r(e(n)("rules.save")),1)]),_:1},8,["disabled"])]),_:1},8,["title","description"]),g("div",da,[u(e(ue),{"model-value":l.value,"onUpdate:modelValue":Z},{default:o(()=>[u(e(je),null,{default:o(()=>[u(e(ne),{value:"visual"},{default:o(()=>[b(r(e(n)("rules.visual")),1)]),_:1}),u(e(ne),{value:"yaml"},{default:o(()=>[u(e(Ne)),b(" "+r(e(n)("rules.yaml")),1)]),_:1})]),_:1})]),_:1},8,["model-value"]),u(e(O),{variant:"secondary"},{default:o(()=>[b(r(e(n)("rules.count",{n:t.value.length})),1)]),_:1}),w.value?(c(),C(e(O),{key:0,variant:"drop"},{default:o(()=>[b(r(e(n)("rules.unsaved")),1)]),_:1})):$("",!0),m.value?(c(),q("span",ca,r(m.value),1)):$("",!0)]),h.value?(c(),q("p",va,r(h.value),1)):$("",!0),u(e(ue),{"model-value":l.value,"onUpdate:modelValue":Z},{default:o(()=>[u(e(re),{value:"visual"},{default:o(()=>[p.value?(c(),q("div",ma,r(e(n)("common.loading")),1)):(c(),q("div",fa,[(c(!0),q(N,null,ie(t.value,(d,y)=>(c(),C(e(Se),{key:`${d.name}-${y}`,class:"p-3 sm:p-4"},{default:o(()=>{var H;return[g("div",pa,[g("div",_a,[g("div",ya,[g("span",ha,"#"+r(y+1),1),g("span",ga,r(d.name),1),d.action?(c(),C(e(O),{key:0,variant:ve(d.action),class:"uppercase"},{default:o(()=>[b(r(e(n)(`action.${d.action}`)),1)]),_:2},1032,["variant"])):$("",!0),d.log?(c(),C(e(O),{key:1,variant:"log"},{default:o(()=>[b(r(e(n)("action.log")),1)]),_:1})):$("",!0),(H=d.modifier)!=null&&H.name?(c(),C(e(O),{key:2,variant:"outline"},{default:o(()=>[b(r(d.modifier.name),1)]),_:2},1024)):$("",!0)]),g("code",ba,r(d.expr),1)]),g("div",ka,[u(e(I),{variant:"ghost",size:"icon-sm","aria-label":e(n)("rules.moveUp"),disabled:y===0,onClick:J=>ae(y,-1)},{default:o(()=>[u(e(Fe),{class:"size-3.5"})]),_:1},8,["aria-label","disabled","onClick"]),u(e(I),{variant:"ghost",size:"icon-sm","aria-label":e(n)("rules.moveDown"),disabled:y===t.value.length-1,onClick:J=>ae(y,1)},{default:o(()=>[u(e(Oe),{class:"size-3.5"})]),_:1},8,["aria-label","disabled","onClick"]),u(e(I),{variant:"ghost",size:"icon-sm","aria-label":e(n)("common.edit"),onClick:J=>ye(y)},{default:o(()=>[u(e(Le),{class:"size-3.5"})]),_:1},8,["aria-label","onClick"]),u(e(I),{variant:"ghost",size:"icon-sm",class:"text-destructive","aria-label":e(n)("common.delete"),onClick:J=>S.value=y},{default:o(()=>[u(e(Ae),{class:"size-3.5"})]),_:1},8,["aria-label","onClick"])])])]}),_:2},1024))),128)),t.value.length?$("",!0):(c(),q("p",xa,r(e(n)("rules.empty")),1)),u(e(I),{variant:"outline",class:"mt-1 w-full",onClick:_e},{default:o(()=>[u(e(De),{class:"size-4"}),b(" "+r(e(n)("rules.add")),1)]),_:1})]))]),_:1}),u(e(re),{value:"yaml"},{default:o(()=>[u(e(G),{modelValue:i.value,"onUpdate:modelValue":[s[0]||(s[0]=d=>i.value=d),s[1]||(s[1]=d=>w.value=!0)],spellcheck:"false",class:"h-[60vh] resize-y font-mono text-xs leading-relaxed"},null,8,["modelValue"]),g("p",wa,r(e(n)("rules.hint")),1)]),_:1})]),_:1},8,["model-value"]),u(e(te),{open:v.value!==null,title:A.value>=0?e(n)("rules.editTitle"):e(n)("rules.addTitle"),"onUpdate:open":s[9]||(s[9]=d=>!d&&(v.value=null,R.value=""))},{footer:o(()=>[u(e(I),{variant:"outline",onClick:s[8]||(s[8]=d=>(v.value=null,R.value=""))},{default:o(()=>[b(r(e(n)("common.cancel")),1)]),_:1}),u(e(I),{onClick:le},{default:o(()=>[b(r(e(n)("common.save")),1)]),_:1})]),default:o(()=>{var d;return[v.value?(c(),q("form",{key:0,class:"flex flex-col gap-4",onSubmit:de(le,["prevent"])},[g("div",Va,[u(e(P),{for:"rule-name"},{default:o(()=>[b(r(e(n)("rules.name")),1)]),_:1}),u(e(Ie),{id:"rule-name",modelValue:v.value.name,"onUpdate:modelValue":s[2]||(s[2]=y=>v.value.name=y),placeholder:e(n)("rules.namePlaceholder")},null,8,["modelValue","placeholder"])]),g("div",Ca,[g("div",qa,[u(e(P),null,{default:o(()=>[b(r(e(n)("rules.action")),1)]),_:1}),u(e(se),{"model-value":v.value.action??"",options:x.value,"onUpdate:modelValue":s[3]||(s[3]=y=>v.value.action=y)},null,8,["model-value","options"])]),g("div",$a,[u(e(P),{for:"rule-log"},{default:o(()=>[b(r(e(n)("rules.log")),1)]),_:1}),g("div",Sa,[u(e(na),{id:"rule-log",modelValue:v.value.log,"onUpdate:modelValue":s[4]||(s[4]=y=>v.value.log=y)},null,8,["modelValue"])])])]),v.value.action==="modify"?(c(),q("div",Ia,[g("div",za,[u(e(P),null,{default:o(()=>[b(r(e(n)("rules.modifier")),1)]),_:1}),u(e(se),{"model-value":((d=v.value.modifier)==null?void 0:d.name)??"",options:D.value,"onUpdate:modelValue":s[5]||(s[5]=y=>{var H;return v.value.modifier={name:y,args:(H=v.value.modifier)==null?void 0:H.args}})},null,8,["model-value","options"])]),g("div",Aa,[u(e(P),{for:"rule-args"},{default:o(()=>[b(r(e(n)("rules.modifierArgs")),1)]),_:1}),u(e(G),{id:"rule-args",modelValue:U.value,"onUpdate:modelValue":s[6]||(s[6]=y=>U.value=y),class:"font-mono text-xs",rows:"4"},null,8,["modelValue"])])])):$("",!0),g("div",Ba,[u(e(P),{for:"rule-expr"},{default:o(()=>[b(r(e(n)("rules.expr")),1)]),_:1}),u(e(G),{id:"rule-expr",modelValue:v.value.expr,"onUpdate:modelValue":s[7]||(s[7]=y=>v.value.expr=y),spellcheck:"false",placeholder:e(n)("rules.exprPlaceholder"),class:"min-h-28 font-mono text-xs leading-relaxed"},null,8,["modelValue","placeholder"])]),R.value?(c(),q("p",Ma,r(R.value),1)):$("",!0)],32)):$("",!0)]}),_:1},8,["open","title"]),u(e(te),{open:S.value>=0,title:e(n)("common.delete"),description:S.value>=0?e(n)("rules.deleteConfirm",{name:((z=t.value[S.value])==null?void 0:z.name)??""}):"","onUpdate:open":s[12]||(s[12]=d=>!d&&(S.value=-1))},{footer:o(()=>[u(e(I),{variant:"outline",onClick:s[10]||(s[10]=d=>S.value=-1)},{default:o(()=>[b(r(e(n)("common.cancel")),1)]),_:1}),u(e(I),{variant:"destructive",onClick:s[11]||(s[11]=d=>he(S.value))},{default:o(()=>[b(r(e(n)("common.delete")),1)]),_:1})]),_:1},8,["open","title","description"])])}}});export{Oa as default};