PageSourceSearch

https://app.xlift.ai/assets/TriggersPage-Bbh5o7Gw.js

js xlift.ai collected 2026-10-05 13:20:41 UTC 17,773 bytes, 1 lines download raw bytes

1import{j as e,I as W,ai as V,o as w,A as L,al as R,a4 as E,a5 as B,U as b,C as y,G as x,$ as ae,T as d,bs as v,az as H,ah as ie,ap as Z,ag as oe,D as N,E as C,W as P,F as ee,au as le,X as z,aw as _,av as X,a8 as O,S as ce,L as M,Z as de,a0 as Y,aq as ue}from"./index-dE8a1mPK.js";import{u as ge}from"./useConfirm-4D74KrCi.js";import{H as he}from"./HandleLink-CMsO54nu.js";import{I as te}from"./IconExternalLink-DcQXcLz7.js";import{E as xe}from"./EmptyState-BpgfYYCq.js";import{A as me}from"./AiWriteButton-BOd6FUXb.js";import{I as K}from"./IconPlus-B47PY1MC.js";import{S as re}from"./Switch-Bm85N10X.js";import{I as se}from"./IconTrash-DIXYcrq7.js";import{S as q}from"./Select-DebRlW67.js";import{I as U}from"./IconX-B50qDTAe.js";import{I as pe}from"./IconEye-Clupefz6.js";import{T as je}from"./TagsInput-BFXHhTYh.js";import{T as G}from"./Textarea-BtbUvWWM.js";import{N as J}from"./NumberInput-EbCp_odp.js";import{I as we}from"./IconFlask-Q5Q6JTza.js";import"./InputsGroupFieldset-C0syow2C.js";import"./OptionsDropdown-wonErrz5.js";import"./CheckIcon-DkMc45y2.js";import"./Pill-yNBbBYnE.js";import"./PillsInput-BO1u7Wrq.js";import"./get-env-uyVen0u2.js";function fe({tweetUrl:r,tweetId:o,authorHandle:u,size:m="xs",iconSize:c=12,children:t,title:i="Open tweet on X"}){const p=r||(o?`https://x.com/${(u||"i").replace(/^@/,"")}/status/${o}`:null);return p?e.jsx(W,{href:p,target:"_blank",rel:"noreferrer",size:m,onClick:a=>a.stopPropagation(),title:i,style:{display:"inline-flex",alignItems:"center",gap:4},children:t||e.jsx(te,{size:c})}):null}const ye=[{value:"mention",label:"Mention — someone @-mentions one of your accounts"},{value:"reply",label:"Reply — someone replies to one of your tweets"}],ve=[{value:"send-dm",label:"Send DM to the author"},{value:"send-reply",label:"Reply to the tweet"}],I={enabled:!0,name:"",source:"mention",filters:{keywords:[],keywordRegex:"",minTextLength:0,excludeHandles:[]},throttle:{maxPerDay:25},conditions:{notInBlocklist:!0,notDmdInLastDays:30},action:{type:"send-dm",text:"",accountId:null}};function ne(r){if(!r)return"—";const o=Date.now()-r;return o<6e4?`${Math.floor(o/1e3)}s ago`:o<36e5?`${Math.floor(o/6e4)}m ago`:o<864e5?`${Math.floor(o/36e5)}h ago`:`${Math.floor(o/864e5)}d ago`}function Ye(){const r=V(),{confirm:o,ConfirmDialog:u}=ge(),[m,c]=w.useState(null),{data:t,isLoading:i}=L({queryKey:["triggers"],queryFn:()=>b.listTriggers()}),{data:p}=L({queryKey:["triggers-fires-all"],queryFn:()=>b.listTriggerFires(null,100),refetchInterval:9e4}),{data:a}=L({queryKey:["accounts"],queryFn:()=>b.listAccounts()}),j=(t==null?void 0:t.triggers)||[],k=(p==null?void 0:p.fires)||[],S=(a==null?void 0:a.accounts)||[],l=R({mutationFn:s=>b.deleteTrigger(s),onSuccess:()=>{B("Trigger removed"),r.invalidateQueries({queryKey:["triggers"]})},onError:s=>E(s)}),f=R({mutationFn:s=>b.toggleTrigger(s),onMutate:async s=>{await r.cancelQueries({queryKey:["triggers"]});const g=r.getQueryData(["triggers"]);return r.setQueryData(["triggers"],h=>h!=null&&h.triggers?{...h,triggers:h.triggers.map(T=>T.id===s?{...T,enabled:!T.enabled}:T)}:h),{previous:g}},onError:(s,g,h)=>{h!=null&&h.previous&&r.setQueryData(["triggers"],h.previous),E(s)},onSettled:()=>r.invalidateQueries({queryKey:["triggers"]})});return e.jsxs(y,{gap:"lg",children:[e.jsxs(x,{justify:"space-between",wrap:"wrap",children:[e.jsxs("div",{children:[e.jsx(ae,{order:2,children:"Triggers"}),e.jsx(d,{c:"dimmed",size:"sm",mt:2,children:"When something happens on X — a mention, a reply — fire an automatic action. Triggers respect your blocklist + recent-contact window."})]}),e.jsx(Se,{triggersCount:j.length,onClick:()=>c("new")})]}),e.jsxs(v,{defaultValue:"triggers",children:[e.jsxs(v.List,{children:[e.jsxs(v.Tab,{value:"triggers",leftSection:e.jsx(H,{size:14}),children:["Triggers (",j.length,")"]}),e.jsxs(v.Tab,{value:"activity",leftSection:e.jsx(ie,{size:14}),children:["Activity feed (",k.length,")"]})]}),e.jsx(v.Panel,{value:"triggers",pt:"md",children:i?e.jsx(Z,{py:"xl",children:e.jsx(oe,{size:32})}):j.length===0?e.jsx(xe,{icon:e.jsx(H,{size:32,stroke:1.5,color:"var(--mantine-color-gray-6)"}),title:"No triggers yet",description:'When something happens on X — a mention or a reply with a keyword like "demo" — fire an automatic action. Triggers are the "comment X to get my Y" flow most creators run by hand.',cta:{label:"Create your first trigger",icon:e.jsx(K,{size:14}),onClick:()=>c("new")}}):e.jsx(y,{gap:"sm",children:j.map(s=>{var g,h,T,A,$,F,D;return e.jsx(N,{withBorder:!0,padding:"md",children:e.jsxs(x,{justify:"space-between",wrap:"nowrap",children:[e.jsxs(y,{gap:4,style:{flex:1},children:[e.jsxs(x,{gap:8,wrap:"wrap",children:[e.jsx(W,{onClick:()=>c(s),fw:600,children:s.name||"Untitled trigger"}),e.jsx(C,{size:"sm",color:s.enabled?"green":"gray",variant:"light",children:s.enabled?"enabled":"disabled"}),e.jsx(C,{size:"sm",variant:"dot",children:s.source}),e.jsxs(C,{size:"sm",variant:"dot",color:"violet",children:["→ ",(g=s.action)==null?void 0:g.type]})]}),e.jsxs(d,{size:"xs",c:"dimmed",children:[((h=s.stats)==null?void 0:h.fires)||0," fires · last ",ne((T=s.stats)==null?void 0:T.lastFiredAt)," · ","cap ",((A=s.throttle)==null?void 0:A.maxPerDay)||25,"/day",((F=($=s.filters)==null?void 0:$.keywords)==null?void 0:F.length)>0&&` · words: ${s.filters.keywords.join(", ")}`,((D=s.filters)==null?void 0:D.keywordRegex)&&` · regex /${s.filters.keywordRegex}/i`]})]}),e.jsxs(x,{gap:4,children:[e.jsx(re,{size:"md",checked:!!s.enabled,onChange:()=>f.mutate(s.id)}),e.jsx(P,{label:"Delete trigger",children:e.jsx(ee,{variant:"subtle",color:"red",onClick:async()=>{await o({title:`Delete trigger "${s.name}"?`,body:"The trigger stops firing immediately. Fires already queued as actions stay in place.",confirmLabel:"Delete"})&&l.mutate(s.id)},children:e.jsx(se,{size:14})})})]})]})},s.id)})})}),e.jsx(v.Panel,{value:"activity",pt:"md",children:e.jsx(Te,{fires:k,triggers:j})})]}),e.jsx(ke,{accounts:S.filter(s=>s.status==="active")}),m&&e.jsx(be,{initial:m==="new"?I:m,accounts:S.filter(s=>s.status==="active"),onClose:()=>c(null),onSaved:()=>{c(null),r.invalidateQueries({queryKey:["triggers"]})}}),e.jsx(u,{})]})}function be({initial:r,accounts:o,onClose:u,onSaved:m}){var $,F,D,Q;const c=!r.id,[t,i]=w.useState({...I,...r,filters:{...I.filters,...r.filters||{}},throttle:{...I.throttle,...r.throttle||{}},conditions:{...I.conditions,...r.conditions||{}},action:{...I.action,...r.action||{}}}),[p,a]=w.useState(!!t.filters.keywordRegex),j=t.source==="reply"&&t.action.type==="send-dm"&&((($=t.filters.keywords)==null?void 0:$.length)||0)>0,k=R({mutationFn:()=>c?b.createTrigger(t):b.updateTrigger(r.id,t),onSuccess:()=>{B(c?"Trigger created":"Trigger updated"),m()},onError:n=>E(n)}),[S,l]=w.useState(!1),[f,s]=w.useState({text:"",handle:""}),[g,h]=w.useState(null),T=R({mutationFn:()=>b.dryRunTrigger({trigger:t,sample:f}),onSuccess:n=>h(n),onError:n=>E(n)}),A=w.useMemo(()=>o.map(n=>({value:n.id,label:`@${n.handle}`})),[o]);return e.jsx(de,{opened:!0,onClose:u,title:c?"New trigger":`Edit · ${r.name||"trigger"}`,size:"lg",children:e.jsxs(y,{children:[e.jsx(M,{label:"Name",placeholder:"e.g. DM people who reply to my launch tweet",value:t.name,onChange:n=>i({...t,name:n.currentTarget.value}),required:!0}),e.jsx(q,{label:"When this happens",data:ye,value:t.source,onCh
1ange:n=>i({...t,source:n||"mention"})}),e.jsx(je,{label:"Trigger word(s)",description:t.source==="reply"?"Only fire when the reply contains one of these words (case-insensitive). Leave blank to fire on every reply.":"Only fire when the mention contains one of these words (case-insensitive). Leave blank to fire on every mention.",placeholder:"ai, demo, pricing",value:t.filters.keywords||[],onChange:n=>i({...t,filters:{...t.filters,keywords:n}}),splitChars:[","," ","Enter"],maxTags:50,clearable:!0}),p?e.jsx(M,{label:"Keyword regex (advanced)",description:"Case-insensitive. OR'd with the trigger words above. e.g. pricing|demo|help",placeholder:"leave blank to use just trigger words",value:t.filters.keywordRegex,onChange:n=>i({...t,filters:{...t.filters,keywordRegex:n.currentTarget.value}})}):e.jsx(W,{size:"xs",onClick:()=>a(!0),style:{alignSelf:"flex-start"},children:"Use regex instead (advanced)"}),e.jsxs(x,{grow:!0,children:[e.jsx(q,{label:"Do this",data:ve,value:t.action.type,onChange:n=>i({...t,action:{...t.action,type:n||"send-dm"}})}),e.jsx(q,{label:"From account",placeholder:"Use receiving account",data:A,value:t.action.accountId,onChange:n=>i({...t,action:{...t.action,accountId:n}}),clearable:!0})]}),j&&e.jsxs(Y,{color:"violet",variant:"light",icon:e.jsx(ue,{size:16}),children:[e.jsx(d,{size:"sm",fw:500,children:"Comment-to-DM mode"}),e.jsxs(d,{size:"xs",c:"dimmed",children:["When someone replies to your tweet with ",t.filters.keywords.map(n=>`"${n}"`).join(" or "),", we'll auto-DM them the message below."]})]}),e.jsxs("div",{children:[e.jsxs(x,{justify:"space-between",align:"flex-end",mb:4,children:[e.jsx(d,{size:"sm",fw:500,children:"Message"}),e.jsx(me,{kind:"trigger-message",context:{source:t.source,keywords:((F=t.filters)==null?void 0:F.keywords)||[],goal:((D=t.action)==null?void 0:D.type)==="send-dm"?"reply privately and earn a follow-up":"reply publicly with value"},current:t.action.text,onResult:n=>i({...t,action:{...t.action,text:n}})})]}),e.jsx(G,{description:"Use {{handle}} as a placeholder. Spintax {a|b} supported.",placeholder:"Hey @{{handle}}, saw your reply — quick question if you have a sec",value:t.action.text,onChange:n=>i({...t,action:{...t.action,text:n.currentTarget.value}}),autosize:!0,minRows:2,maxRows:6,required:!0})]}),e.jsxs(x,{grow:!0,children:[e.jsx(J,{label:"Max fires per day",description:"Hard cap so a viral mention storm doesn't drain your daily DM allowance",value:t.throttle.maxPerDay,onChange:n=>i({...t,throttle:{maxPerDay:Number(n)||25}}),min:1,max:500}),e.jsx(J,{label:"Don't re-contact within (days)",description:"Won't fire if we've already DM'd this handle in this window",value:t.conditions.notDmdInLastDays,onChange:n=>i({...t,conditions:{...t.conditions,notDmdInLastDays:Number(n)||0}}),min:0,max:365})]}),e.jsx(re,{label:"Enabled",checked:!!t.enabled,onChange:n=>i({...t,enabled:n.currentTarget.checked})}),e.jsxs(x,{justify:"space-between",children:[e.jsx(z,{variant:"default",leftSection:e.jsx(we,{size:14}),onClick:()=>l(n=>!n),children:"Test trigger"}),e.jsxs(x,{children:[e.jsx(z,{variant:"default",onClick:u,children:"Cancel"}),e.jsx(z,{onClick:()=>k.mutate(),loading:k.isPending,disabled:!t.name.trim()||!t.action.text.trim(),children:c?"Create":"Save"})]})]}),S&&e.jsx(N,{withBorder:!0,padding:"sm",mt:"xs",children:e.jsxs(y,{gap:"xs",children:[e.jsxs(d,{size:"sm",fw:500,children:["Dry-run against a sample ",t.source]}),e.jsxs(d,{size:"xs",c:"dimmed",children:["Type what the ",t.source," would look like and from whom. We'll run the same filters + conditions the worker uses and tell you exactly what would happen — without firing anything for real."]}),e.jsx(M,{label:"From @handle",placeholder:"some-prospect",value:f.handle,onChange:n=>s({...f,handle:n.currentTarget.value}),size:"xs"}),e.jsx(G,{label:"Tweet text",placeholder:(Q=t.filters.keywords)!=null&&Q[0]?`e.g. "${t.filters.keywords[0]}"`:"paste a sample tweet/reply",value:f.text,onChange:n=>s({...f,text:n.currentTarget.value}),autosize:!0,minRows:1,maxRows:4,size:"xs"}),e.jsx(x,{justify:"flex-end",children:e.jsx(z,{size:"xs",variant:"light",loading:T.isPending,disabled:!f.text.trim()||!f.handle.trim(),onClick:()=>{h(null),T.mutate()},children:"Run test"})}),g&&e.jsx(Y,{color:g.wouldFire?"green":"gray",variant:"light",icon:g.wouldFire?e.jsx(O,{size:16}):e.jsx(U,{size:16}),children:g.wouldFire?e.jsxs(y,{gap:2,children:[e.jsx(d,{size:"sm",fw:500,children:"Would fire"}),e.jsxs(d,{size:"xs",c:"dimmed",children:["Action: ",e.jsx("b",{children:g.actionType}),g.target?` → ${g.target}`:""]}),g.rendered&&e.jsxs(d,{size:"xs",c:"dimmed",style:{whiteSpace:"pre-wrap"},children:["Message:",e.jsx("br",{}),g.rendered]})]}):e.jsxs(y,{gap:2,children:[e.jsx(d,{size:"sm",fw:500,children:"Would NOT fire"}),e.jsxs(d,{size:"xs",c:"dimmed",children:["Reason: ",e.jsx("b",{children:g.reason})," (stage: ",g.stage,")"]})]})})]})})]})})}function Te({fires:r,triggers:o}){const[u,m]=w.useState("all"),[c,t]=w.useState("all"),i=w.useMemo(()=>r.filter(a=>!(u!=="all"&&a.triggerId!==u||c==="fired"&&!a.ok||c==="skipped"&&a.ok)),[r,u,c]),p=w.useMemo(()=>[{value:"all",label:`All triggers (${r.length})`},...o.map(a=>({value:a.id,label:`${a.name||"(untitled)"} (${r.filter(j=>j.triggerId===a.id).length})`}))],[r,o]);return e.jsx(N,{withBorder:!0,padding:"md",children:e.jsxs(y,{gap:"xs",children:[e.jsxs(x,{gap:"xs",wrap:"wrap",children:[e.jsx(q,{size:"xs",value:u,onChange:a=>m(a||"all"),data:p,w:260}),e.jsx(v,{value:c,onChange:a=>t(a||"all"),variant:"pills",children:e.jsxs(v.List,{children:[e.jsx(v.Tab,{value:"all",children:"All"}),e.jsx(v.Tab,{value:"fired",leftSection:e.jsx(O,{size:12}),children:"Fired"}),e.jsx(v.Tab,{value:"skipped",leftSection:e.jsx(U,{size:12}),children:"Skipped"})]})}),e.jsxs(d,{size:"xs",c:"dimmed",style:{marginLeft:"auto"},children:[i.length," of ",r.length]})]}),i.length===0?e.jsx(Z,{py:"xl",children:e.jsx(d,{c:"dimmed",children:"No fires match the current filters."})}):e.jsx(ce.Autosize,{mah:600,children:e.jsx(y,{gap:6,children:i.map(a=>e.jsxs(x,{gap:8,wrap:"nowrap",style:{paddingBottom:6,borderBottom:"1px solid var(--xb-line-soft)"},children:[a.ok?e.jsx(O,{size:14,color:"var(--mantine-color-green-6)"}):e.jsx(U,{size:14,color:"var(--mantine-color-red-6)"}),e.jsxs(y,{gap:0,style:{flex:1,minWidth:0},children:[e.jsxs(x,{gap:6,wrap:"nowrap",children:[e.jsxs(d,{size:"sm",fw:500,children:[a.ok?"Fired":"Skipped"," · "]}),a.authorHandle?e.jsx(he,{handle:a.authorHandle,size:"sm",fw:500}):e.jsx(d,{size:"sm",children:"@?"}),a.tweetUrl&&e.jsx(fe,{tweetUrl:a.tweetUrl}),e.jsx(C,{variant:"dot",color:"gray",size:"xs",children:a.source})]}),e.jsx(d,{size:"xs",c:"dimmed",lineClamp:1,children:a.ok?`queued ${a.tweetText||""}`:a.reason||"no reason"})]}),e.jsx(d,{size:"xs",c:"dimmed",children:ne(a.ts)})]},a.id))})})]})})}function ke({accounts:r}){var k,S;const o=V(),u=L({queryKey:["watches"],queryFn:()=>b.listWatches()}),[m,c]=w.useState(""),[t,i]=w.useState(((k=r[0])==null?void 0:k.id)||null),p=R({mutationFn:()=>{const l=ze(m);return l?t?b.watchTweet({tweetId:l,accountId:t}):Promise.reject(new Error("Pick the account to attribute new events to")):Promise.reject(new Error("Paste a tweet URL or numeric id"))},onSuccess:()=>{B("Now watching"),c(""),o.invalidateQueries({queryKey:["watches"]})},onError:l=>E(l)}),a=R({mutationFn:l=>b.unwatchTweet(l),onSuccess:()=>o.invalidateQueries({queryKey:["watches"]}),onError:l=>E(l)}),j=((S=u.data)==null?void 0:S.watches)||[];return e.jsx(N,{withBorder:!0,children:e.jsxs(y,{gap:"sm",children:[e.jsxs(x,{gap:"xs",children:[e.jsx(pe,{size:16}),e.jsx(d,{fw:600,children:"Watched tweets"}),e.jsx(C,{variant:"light",size:"xs",children:"conversation-watcher"})]}),e.jsxs(d,{size:"xs",c:"dimmed",children:["Tweets here get polled every 15 minutes for new replies. Each new reply becomes an Inbox event and fires any matching ",e.jsx("code",{children:"'reply'"})," trigger above. Requires ",e.jsx("code",{children:"TWEET_REPLY_WATCHER_ENABLED=true"})," on the backend to actually run the cron."]}),e.jsxs(x,{align:"flex-end",wrap:"wrap",gap:"xs",children:[e.jsx(M,{label:"Tweet URL or id",placeholder:"https://x.com/.../status/123456789  or  123456789",value:m,onChange:l=>c(l.currentTarget.value),style:{flex:"1 1 280px"}}),e.jsx(q,{label:"Attribute events to",data:r.map(l=>({value:l.id,label:`@${l.handle}`})),value:t,onChange:i,w:180,searchable:!0}),e.jsx(z,{leftSection:e.jsx(K,{size:14}),onClick:()=>p.mutate(),loading:p.isPending,disabled:!m.trim()||!t,children:"Watch"})]}),j.length===0&&e.jsxs(d,{size:"xs",c:"dimmed",ta:"center",py:"md",children:["No watched tweets yet. Paste a tweet URL above, or click ",e.jsx("strong",{children:"Watch for replies"})," on any inbox thread."]}),j.length>0&&e.jsx(y,{gap:4,children:j.map(l=>{var f;return e.jsxs(x,{gap:"xs",wrap:"nowrap",align:"center",children:[e.jsxs(W,{href:`https://x.com/i/status/${l.tweetId}`,target:"_blank",rel:"noreferrer",size:"xs",style:{flex:1,minWidth:0},truncate:!0,children:["/status/",l.tweetId,e.jsx(te,{size:10,style:{marginLeft:4}})]}),e.jsxs(C,{size:"xs",variant:"light",children:[l.totalReplies||0," replies seen"]}),e.jsx(C,{size:"xs",variant:"light",color:"gray",children:(f=r.find(s=>
1s.id===l.accountId))!=null&&f.handle?`@${r.find(s=>s.id===l.accountId).handle}`:l.accountId}),e.jsx(P,{label:"Stop watching",withArrow:!0,children:e.jsx(ee,{size:"sm",variant:"subtle",color:"red",onClick:()=>a.mutate(l.tweetId),children:e.jsx(se,{size:12})})})]},l.id)})})]})})}function ze(r){const o=String(r||"").trim();if(!o)return null;const u=o.match(/status\/(\d+)/);return u?u[1]:/^\d+$/.test(o)?o:null}function Se({triggersCount:r,onClick:o}){const{hasFeature:u,capFor:m,planLabel:c}=le(),t=u("triggers"),i=m("triggers"),p=i!==null&&r>=i;return t?p?e.jsx(P,{label:`Your ${c} plan caps Triggers at ${i}. Upgrade for more.`,withArrow:!0,children:e.jsxs(z,{onClick:()=>X({reason:`Your ${c} plan caps Triggers at ${i}.`,code:"plan-cap"}),variant:"light",color:"dark",leftSection:e.jsx(_,{size:14}),children:[r,"/",i," — upgrade"]})}):e.jsxs(z,{leftSection:e.jsx(K,{size:14}),onClick:o,children:["New trigger",i!==null?` (${r}/${i})`:""]}):e.jsx(P,{label:`Your ${c} plan doesn't include Triggers. Upgrade to Starter to unlock.`,withArrow:!0,children:e.jsx(z,{onClick:()=>X({reason:"Triggers is a paid feature.",code:"plan-gate"}),variant:"light",color:"dark",leftSection:e.jsx(_,{size:14}),children:"Upgrade to unlock"})})}export{Ye as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.