mirror of
https://github.com/ThearchyHelios/AgentLab.git
synced 2026-11-15 00:21:58 +00:00
事件触发的规模:定时任务列表里每个事件触发任务「有几条在等」一次查齐(outbox.pending_for_many:待派发数一条 SQL 按任务分组算,窗口要看的事件一次读出),不再每行查一次;每一拍派发只读触发条件的事件种类、对象对得上的任务(SQLAlchemy 的通用 JSON 访问),保存时查环一层查一次、只顺着「上游工作流运行成功结束」的边找;选对象(trigger-options)按事件、关键字查、一页最多 100 个、more 说还有没有,当前选中的总在里面,编辑页一页没列完时多一个按名称查找。顺带修:等着的时候任务改了条件、最早那条不再合条件时,「什么时候合成触发」按剩下的最早一条算(列表上的时刻和真发起的一致);一个窗口的结束时刻和这个任务已有的另一次触发撞在同一刻(别的期次早一拍发了)时往后挪,那几条事件照常发起,不再被记到已有的触发上
This commit is contained in:
@@ -36,8 +36,12 @@ export const schedules = {
|
||||
*/
|
||||
eventVariables: (event: ScheduleEventKind, opts?: RequestOptions) =>
|
||||
get<ScheduleVariable[]>(`/schedules/variables${qs({ trigger_kind: 'event', event })}`, opts),
|
||||
/** 新建、修改事件触发任务时能选的对象(能不能选、为什么由服务端判)、来源、应用。老服务端没有,回 404 */
|
||||
triggerOptions: (opts?: RequestOptions) => get<ScheduleTriggerOptions>('/schedules/trigger-options', opts),
|
||||
/**
|
||||
* 新建、修改事件触发任务时能选的对象(能不能选、为什么由服务端判)、来源、应用。老服务端没有,回 404。对象一页有上限
|
||||
* (more 为真时没给完):按事件种类、名字里的关键字再查;selected 是当前选中的那一个,总在结果里
|
||||
*/
|
||||
triggerOptions: (find?: { event?: ScheduleEventKind; q?: string; selected?: string }, opts?: RequestOptions) =>
|
||||
get<ScheduleTriggerOptions>(`/schedules/trigger-options${qs(find)}`, opts),
|
||||
/** 立即运行一次:记一条手动触发,上一次还没结束时照样按重叠策略跳过 */
|
||||
run: (id: string) => post<ScheduleRunResult>(`${at(id)}/run`),
|
||||
/** 触发历史,新的在前。before 是上一页给的 next_before */
|
||||
|
||||
@@ -43,6 +43,10 @@ export const TRIGGER_TEXT = {
|
||||
/** 不能选的对象:名字后面接服务端给的原因 */
|
||||
subjectNotOk: (name: string, reason: string) => `${name}(${reason})`,
|
||||
subjectGone: (name: string) => `${name}(已不存在)`,
|
||||
/** 对象太多、一页没列完:按名字查找 */
|
||||
subjectSearch: (label: string) => `按名称查找${label}`,
|
||||
subjectSearchHint: '只列出了一部分,输入名称中的字查找',
|
||||
subjectSearchNone: '没有名称中含这些字的',
|
||||
optionsLoading: '正在读取可选的对象…',
|
||||
optionsFailed: '无法读取可选的对象',
|
||||
optionsUnsupported: '服务端暂不支持事件触发,请升级服务端后再使用',
|
||||
|
||||
@@ -73,6 +73,28 @@ function useTriggerOptions(): OptionsState {
|
||||
return state
|
||||
}
|
||||
|
||||
/**
|
||||
* 对象太多、一页没列完(服务端的 more)时按名字查:输入停一下再查,结果只换这一种事件的对象;当前选中的那一个总带上
|
||||
* (selected),不被分页挤掉、不显示成已不存在
|
||||
*/
|
||||
function useObjectSearch(kind: ScheduleEventKind, selected: string, enabled: boolean) {
|
||||
const [q, setQ] = useState('')
|
||||
const [found, setFound] = useState<{ key: string; objects: ScheduleTriggerOptions['events'][number]['objects'] } | null>(null)
|
||||
const words = q.trim()
|
||||
const key = `${kind}\u0000${words}`
|
||||
useEffect(() => {
|
||||
if (!enabled || !words) return
|
||||
const controller = new AbortController()
|
||||
const timer = setTimeout(() => {
|
||||
api.schedules.triggerOptions({ event: kind, q: words, selected: selected || undefined }, { signal: controller.signal })
|
||||
.then((data) => setFound({ key, objects: data.events.find((e) => e.event === kind)?.objects ?? [] }))
|
||||
.catch(() => {})
|
||||
}, 300)
|
||||
return () => { clearTimeout(timer); controller.abort() }
|
||||
}, [enabled, kind, words, selected, key])
|
||||
return { q, setQ, objects: words && found?.key === key ? found.objects : null }
|
||||
}
|
||||
|
||||
export function EventSection({ value, onChange, timezone, setTimezone, savedName, error, debounceError }: {
|
||||
value: TriggerForm
|
||||
onChange: (t: TriggerForm) => void
|
||||
@@ -91,7 +113,9 @@ export function EventSection({ value, onChange, timezone, setTimezone, savedName
|
||||
const kind = value.event
|
||||
const label = TT.subject[kind]
|
||||
const entry = options.status === 'ok' ? options.data.events.find((e) => e.event === kind) : undefined
|
||||
const objects = entry?.objects ?? []
|
||||
const paged = !!entry?.more
|
||||
const search = useObjectSearch(kind, value.subjectId, paged)
|
||||
const objects = search.objects ?? entry?.objects ?? []
|
||||
const listed = objects.some((o) => o.id === value.subjectId)
|
||||
|
||||
let picker
|
||||
@@ -112,7 +136,10 @@ export function EventSection({ value, onChange, timezone, setTimezone, savedName
|
||||
aria-describedby={error ? 'schedule-trigger-subject-error' : undefined}
|
||||
onChange={(e) => set({ subjectId: e.target.value })}>
|
||||
<option value="">{objects.length ? TT.subjectPlaceholder(label) : TT.subjectEmpty[kind]}</option>
|
||||
{value.subjectId && !listed && <option value={value.subjectId}>{TT.subjectGone(savedName || value.subjectId)}</option>}
|
||||
{/* 一页没列完时不在列表里不等于不存在:写保存时记下的名字,不标「已不存在」 */}
|
||||
{value.subjectId && !listed && (
|
||||
<option value={value.subjectId}>{paged ? savedName || value.subjectId : TT.subjectGone(savedName || value.subjectId)}</option>
|
||||
)}
|
||||
{objects.map((o) => (
|
||||
<option key={o.id} value={o.id} disabled={!o.ok && o.id !== value.subjectId} data-trigger-object-ok={String(o.ok)}>
|
||||
{o.ok || !o.reason ? o.name : TT.subjectNotOk(o.name, o.reason)}
|
||||
@@ -140,7 +167,17 @@ export function EventSection({ value, onChange, timezone, setTimezone, savedName
|
||||
</div>
|
||||
|
||||
<Field label={label} htmlFor="schedule-trigger-subject" required>
|
||||
{paged && (
|
||||
<input type="search" className="field mb-1.5" value={search.q} data-trigger-subject-search=""
|
||||
placeholder={TT.subjectSearch(label)} aria-label={TT.subjectSearch(label)}
|
||||
aria-describedby="schedule-trigger-subject-search-hint" onChange={(e) => search.setQ(e.target.value)} />
|
||||
)}
|
||||
{picker}
|
||||
{paged && (
|
||||
<p id="schedule-trigger-subject-search-hint" className="mt-1 text-2xs leading-relaxed text-faint">
|
||||
{search.objects && !search.objects.length ? TT.subjectSearchNone : TT.subjectSearchHint}
|
||||
</p>
|
||||
)}
|
||||
</Field>
|
||||
{error && (
|
||||
<div id="schedule-trigger-subject-error" className="-mt-1.5 text-2xs leading-relaxed text-[var(--err)]" role="alert"
|
||||
|
||||
@@ -4172,6 +4172,8 @@ export interface ScheduleTriggerOptions {
|
||||
label: string
|
||||
subject_label: string
|
||||
objects: { id: string; name: string; ok: boolean; reason: string | null }[]
|
||||
/** 一页没给完(对象按名字排、一页有上限):界面按关键字再查。老服务端不给,当作给完了 */
|
||||
more?: boolean
|
||||
}[]
|
||||
origins: { kind: string; label: string }[]
|
||||
apps: { id: string; name: string }[]
|
||||
|
||||
Reference in New Issue
Block a user