|
|
|
|
|
import { Grid, GridOptions } from 'ag-grid-community'; |
|
import { Notyf } from 'notyf'; |
|
|
|
import bookmark from '../assets/icons/bookmark.svg?raw'; |
|
import bookmarked from '../assets/icons/bookmark-filled.svg?raw'; |
|
import cancelIcon from '../assets/icons/cancel.svg?raw'; |
|
import deleteIcon from '../assets/icons/delete.svg?raw'; |
|
import playIcon from '../assets/icons/play.svg?raw'; |
|
import rotateIcon from '../assets/icons/rotate.svg?raw'; |
|
import searchIcon from '../assets/icons/search.svg?raw'; |
|
import { debounce } from '../utils/debounce'; |
|
import { extractArgs } from '../utils/extract-args'; |
|
import { formatDate } from '../utils/format-date'; |
|
|
|
import { createHistoryTasksStore } from './stores/history.store'; |
|
import { createPendingTasksStore } from './stores/pending.store'; |
|
import { createSharedStore } from './stores/shared.store'; |
|
import { ProgressResponse, ResponseStatus, Task, TaskStatus } from './types'; |
|
|
|
import 'ag-grid-community/styles/ag-grid.css'; |
|
import 'ag-grid-community/styles/ag-theme-alpine.css'; |
|
import 'notyf/notyf.min.css'; |
|
import './index.scss'; |
|
|
|
let notyf: Notyf; |
|
|
|
declare global { |
|
function gradioApp(): HTMLElement; |
|
function randomId(): string; |
|
function origRandomId(): string; |
|
function get_tab_index(name: string): number; |
|
function create_submit_args(args: any[]): any[]; |
|
function requestProgress( |
|
id: string, |
|
progressContainer: HTMLElement, |
|
imagesContainer: HTMLElement, |
|
onDone?: () => void, |
|
onProgress?: (res: ProgressResponse) => void, |
|
): void; |
|
function onUiLoaded(callback: () => void): void; |
|
function notify(response: ResponseStatus): void; |
|
function submit(...args: any[]): any[]; |
|
function submit_img2img(...args: any[]): any[]; |
|
function submit_enqueue(...args: any[]): any[]; |
|
function submit_enqueue_img2img(...args: any[]): any[]; |
|
function agent_scheduler_status_filter_changed(value: string): void; |
|
} |
|
|
|
const sharedStore = createSharedStore({ |
|
uiAsTab: true, |
|
selectedTab: 'pending', |
|
}); |
|
|
|
const pendingStore = createPendingTasksStore({ |
|
current_task_id: null, |
|
total_pending_tasks: 0, |
|
pending_tasks: [], |
|
paused: false, |
|
}); |
|
|
|
const historyStore = createHistoryTasksStore({ |
|
total: 0, |
|
tasks: [], |
|
}); |
|
|
|
const sharedGridOptions: GridOptions<Task> = { |
|
|
|
defaultColDef: { |
|
sortable: false, |
|
filter: true, |
|
resizable: true, |
|
suppressMenu: true, |
|
}, |
|
|
|
columnDefs: [ |
|
{ |
|
field: 'name', |
|
headerName: 'Task Id', |
|
minWidth: 240, |
|
maxWidth: 240, |
|
pinned: 'left', |
|
rowDrag: true, |
|
editable: true, |
|
valueGetter: ({ data }) => data?.name ?? data?.id, |
|
cellClass: ({ data }) => [ |
|
'cursor-pointer', |
|
data?.status === 'pending' ? 'task-pending' : '', |
|
data?.status === 'running' ? 'task-running' : '', |
|
data?.status === 'done' ? 'task-done' : '', |
|
data?.status === 'failed' ? 'task-failed' : '', |
|
data?.status === 'interrupted' ? 'task-interrupted' : '', |
|
], |
|
}, |
|
{ |
|
field: 'type', |
|
headerName: 'Type', |
|
minWidth: 80, |
|
maxWidth: 80, |
|
}, |
|
{ |
|
headerName: 'Params', |
|
children: [ |
|
{ |
|
field: 'params.prompt', |
|
headerName: 'Prompt', |
|
minWidth: 200, |
|
maxWidth: 400, |
|
autoHeight: true, |
|
wrapText: true, |
|
cellStyle: { 'line-height': '24px', 'padding-top': '8px', 'padding-bottom': '8px' }, |
|
}, |
|
{ |
|
field: 'params.negative_prompt', |
|
headerName: 'Negative Prompt', |
|
minWidth: 200, |
|
maxWidth: 400, |
|
autoHeight: true, |
|
wrapText: true, |
|
cellStyle: { 'line-height': '24px', 'padding-top': '8px', 'padding-bottom': '8px' }, |
|
}, |
|
{ |
|
field: 'params.checkpoint', |
|
headerName: 'Checkpoint', |
|
minWidth: 150, |
|
maxWidth: 300, |
|
valueFormatter: ({ value }) => value || 'System', |
|
}, |
|
{ |
|
field: 'params.sampler_name', |
|
headerName: 'Sampler', |
|
width: 150, |
|
minWidth: 150, |
|
}, |
|
{ |
|
field: 'params.steps', |
|
headerName: 'Steps', |
|
minWidth: 80, |
|
maxWidth: 80, |
|
filter: 'agNumberColumnFilter', |
|
}, |
|
{ |
|
field: 'params.cfg_scale', |
|
headerName: 'CFG Scale', |
|
width: 100, |
|
minWidth: 100, |
|
filter: 'agNumberColumnFilter', |
|
}, |
|
{ |
|
field: 'params.size', |
|
headerName: 'Size', |
|
minWidth: 110, |
|
maxWidth: 110, |
|
valueGetter: ({ data }) => |
|
data?.params?.width ? `${data.params.width}x${data.params.height}` : '', |
|
}, |
|
{ |
|
field: 'params.batch', |
|
headerName: 'Batching', |
|
minWidth: 100, |
|
maxWidth: 100, |
|
valueGetter: ({ data }) => |
|
data?.params?.n_iter ? `${data.params.n_iter}x${data.params.batch_size}` : '1x1', |
|
}, |
|
], |
|
}, |
|
{ |
|
field: 'created_at', |
|
headerName: 'Queued At', |
|
minWidth: 170, |
|
valueFormatter: ({ value }) => value && formatDate(new Date(value)), |
|
}, |
|
{ |
|
field: 'updated_at', |
|
headerName: 'Updated At', |
|
minWidth: 170, |
|
valueFormatter: ({ value }) => value && formatDate(new Date(value)), |
|
}, |
|
], |
|
|
|
getRowId: ({ data }) => data.id, |
|
rowSelection: 'single', |
|
animateRows: true, |
|
pagination: true, |
|
paginationAutoPageSize: true, |
|
suppressCopyRowsToClipboard: true, |
|
suppressRowTransform: true, |
|
enableBrowserTooltips: true, |
|
readOnlyEdit: true, |
|
onCellEditRequest: ({ data, newValue, api, colDef }) => { |
|
if (colDef.field !== 'name') return; |
|
if (!newValue) return; |
|
|
|
api.showLoadingOverlay(); |
|
historyStore.renameTask(data.id, newValue).then((res) => { |
|
notify(res); |
|
const newData = { ...data, name: newValue }; |
|
const tx = { |
|
update: [newData], |
|
}; |
|
api.applyTransaction(tx); |
|
api.hideOverlay(); |
|
}); |
|
}, |
|
}; |
|
|
|
function initSearchInput(selector: string) { |
|
const searchContainer = gradioApp().querySelector(selector); |
|
if (!searchContainer) { |
|
throw new Error(`search container ${selector} not found`); |
|
} |
|
|
|
searchContainer.className = 'ts-search'; |
|
searchContainer.innerHTML = ` |
|
<div class="ts-search-icon"> |
|
${searchIcon} |
|
</div> |
|
<input type="text" class="ts-search-input" placeholder="Search" required> |
|
`; |
|
|
|
return searchContainer; |
|
} |
|
|
|
async function notify(response: ResponseStatus) { |
|
if (!notyf) { |
|
const Notyf = await import("notyf"); |
|
notyf = new Notyf.Notyf({ |
|
position: { |
|
x: 'center', |
|
y: 'bottom', |
|
}, |
|
duration: 3000, |
|
}); |
|
} |
|
|
|
if (response.success) { |
|
notyf.success(response.message); |
|
} else { |
|
notyf.error(response.message); |
|
} |
|
} |
|
|
|
window.notify = notify; |
|
window.origRandomId = window.randomId; |
|
|
|
function showTaskProgress(task_id: string, type: string | undefined, callback: () => void) { |
|
const args = extractArgs(requestProgress); |
|
|
|
const gallery: HTMLDivElement = gradioApp().querySelector( |
|
'#agent_scheduler_current_task_images', |
|
)!; |
|
|
|
|
|
if (args.includes('progressbarContainer')) { |
|
requestProgress(task_id, gallery, gallery, callback); |
|
} else { |
|
|
|
const progressDiv = document.createElement('div'); |
|
progressDiv.className = 'progressDiv'; |
|
gallery.parentNode?.insertBefore(progressDiv, gallery); |
|
requestProgress( |
|
task_id, |
|
gallery, |
|
gallery, |
|
() => { |
|
gallery.parentNode?.removeChild(progressDiv); |
|
callback(); |
|
}, |
|
(res) => { |
|
if (!res) return; |
|
const perc = res ? `${Math.round((res?.progress || 0) * 100.0)}%` : ''; |
|
const eta = res?.paused ? ' Paused' : ` ETA: ${Math.round(res?.eta || 0)}s`; |
|
progressDiv.innerText = `${perc}${eta}`; |
|
progressDiv.style.background = res |
|
? `linear-gradient(to right, var(--primary-500) 0%, var(--primary-800) ${perc}, var(--neutral-700) ${perc})` |
|
: 'var(--button-primary-background-fill)'; |
|
}, |
|
); |
|
} |
|
|
|
|
|
window.randomId = () => task_id; |
|
if (type === 'txt2img') { |
|
window.submit(); |
|
} else if (type === 'img2img') { |
|
window.submit_img2img(); |
|
} |
|
window.randomId = window.origRandomId; |
|
} |
|
|
|
function initQueueHandler() { |
|
window.submit_enqueue = function submit_enqueue(...args) { |
|
const res = create_submit_args(args); |
|
res[0] = randomId(); |
|
|
|
const btnEnqueue = document.querySelector('#txt2img_enqueue'); |
|
if (btnEnqueue) { |
|
btnEnqueue.innerHTML = 'Queued'; |
|
setTimeout(() => { |
|
btnEnqueue.innerHTML = 'Enqueue'; |
|
if (!sharedStore.getState().uiAsTab) { |
|
if (sharedStore.getState().selectedTab === 'pending') { |
|
pendingStore.refresh(); |
|
} |
|
} |
|
}, 1000); |
|
} |
|
|
|
return res; |
|
}; |
|
|
|
window.submit_enqueue_img2img = function submit_enqueue_img2img(...args) { |
|
const res = create_submit_args(args); |
|
res[0] = randomId(); |
|
res[1] = get_tab_index('mode_img2img'); |
|
|
|
const btnEnqueue = document.querySelector('#img2img_enqueue'); |
|
if (btnEnqueue) { |
|
btnEnqueue.innerHTML = 'Queued'; |
|
setTimeout(() => { |
|
btnEnqueue.innerHTML = 'Enqueue'; |
|
if (!sharedStore.getState().uiAsTab) { |
|
if (sharedStore.getState().selectedTab === 'pending') { |
|
pendingStore.refresh(); |
|
} |
|
} |
|
}, 1000); |
|
} |
|
|
|
return res; |
|
}; |
|
|
|
|
|
const interrogateCol: HTMLDivElement = gradioApp().querySelector('.interrogate-col')!; |
|
if (interrogateCol && interrogateCol.childElementCount > 2) { |
|
interrogateCol.classList.add('has-queue-button'); |
|
} |
|
|
|
|
|
const setting = gradioApp().querySelector( |
|
'#setting_queue_keyboard_shortcut textarea', |
|
) as HTMLTextAreaElement; |
|
if (setting?.value && !setting.value.includes('Disabled')) { |
|
const parts = setting.value.split('+'); |
|
const code = parts.pop(); |
|
|
|
const handleShortcut = (e: KeyboardEvent) => { |
|
if (e.code !== code) return; |
|
if (parts.includes('Shift') && !e.shiftKey) return; |
|
if (parts.includes('Alt') && !e.altKey) return; |
|
if (parts.includes('Command') && !e.metaKey) return; |
|
if ((parts.includes('Control') || parts.includes('Ctrl')) && !e.ctrlKey) return; |
|
|
|
e.preventDefault(); |
|
e.stopPropagation(); |
|
|
|
const activeTab = get_tab_index('tabs'); |
|
if (activeTab === 0) { |
|
const btn = gradioApp().querySelector<HTMLButtonElement>('#txt2img_enqueue'); |
|
btn?.click(); |
|
} else if (activeTab === 1) { |
|
const btn = gradioApp().querySelector<HTMLButtonElement>('#img2img_enqueue'); |
|
btn?.click(); |
|
} |
|
}; |
|
|
|
window.addEventListener('keydown', handleShortcut); |
|
|
|
const txt2imgPrompt = gradioApp().querySelector<HTMLTextAreaElement>( |
|
'#txt2img_prompt textarea', |
|
); |
|
if (txt2imgPrompt) { |
|
txt2imgPrompt.addEventListener('keydown', handleShortcut); |
|
} |
|
|
|
const img2imgPrompt = gradioApp().querySelector<HTMLTextAreaElement>( |
|
'#img2img_prompt textarea', |
|
); |
|
if (img2imgPrompt) { |
|
img2imgPrompt.addEventListener('keydown', handleShortcut); |
|
} |
|
} |
|
|
|
|
|
const onTaskIdChange = (id: string | null) => { |
|
if (!id) return; |
|
const task = pendingStore.getState().pending_tasks.find((t) => t.id === id); |
|
|
|
showTaskProgress(id, task?.type, pendingStore.refresh); |
|
}; |
|
pendingStore.subscribe((curr, prev) => { |
|
if (prev.current_task_id !== curr.current_task_id) { |
|
onTaskIdChange(curr.current_task_id); |
|
} |
|
}); |
|
} |
|
|
|
function initTabChangeHandler() { |
|
sharedStore.subscribe((curr, prev) => { |
|
if (!curr.uiAsTab || curr.selectedTab !== prev.selectedTab) { |
|
if (curr.selectedTab === 'pending') { |
|
pendingStore.refresh(); |
|
} else { |
|
historyStore.refresh(); |
|
} |
|
} |
|
}); |
|
|
|
|
|
const observer = new MutationObserver(function (mutationsList) { |
|
mutationsList.forEach((styleChange) => { |
|
const tab = styleChange.target as HTMLElement; |
|
const visible = tab.style.display === 'block'; |
|
if (!visible) return; |
|
|
|
if (tab.id === 'tab_agent_scheduler') { |
|
if (sharedStore.getState().selectedTab === 'pending') { |
|
pendingStore.refresh(); |
|
} else { |
|
historyStore.refresh(); |
|
} |
|
} else if (tab.id === 'agent_scheduler_pending_tasks_tab') { |
|
sharedStore.setSelectedTab('pending'); |
|
} else if (tab.id === 'agent_scheduler_history_tab') { |
|
sharedStore.setSelectedTab('history'); |
|
} |
|
}); |
|
}); |
|
if (document.getElementById('tab_agent_scheduler')) { |
|
observer.observe(document.getElementById('tab_agent_scheduler')!, { |
|
attributeFilter: ['style'], |
|
}); |
|
} else { |
|
sharedStore.setState({ uiAsTab: false }); |
|
} |
|
observer.observe(document.getElementById('agent_scheduler_pending_tasks_tab')!, { |
|
attributeFilter: ['style'], |
|
}); |
|
observer.observe(document.getElementById('agent_scheduler_history_tab')!, { |
|
attributeFilter: ['style'], |
|
}); |
|
} |
|
|
|
function initPendingTab() { |
|
const store = pendingStore; |
|
|
|
|
|
const refreshButton = gradioApp().querySelector('#agent_scheduler_action_reload')!; |
|
const pauseButton = gradioApp().querySelector('#agent_scheduler_action_pause')!; |
|
const resumeButton = gradioApp().querySelector('#agent_scheduler_action_resume')!; |
|
refreshButton.addEventListener('click', store.refresh); |
|
pauseButton.addEventListener('click', () => store.pauseQueue().then(notify)); |
|
resumeButton.addEventListener('click', () => store.resumeQueue().then(notify)); |
|
|
|
|
|
store.subscribe((curr) => { |
|
if (curr.paused) { |
|
pauseButton.classList.add('hide'); |
|
resumeButton.classList.remove('hide'); |
|
} else { |
|
pauseButton.classList.remove('hide'); |
|
resumeButton.classList.add('hide'); |
|
} |
|
}); |
|
|
|
|
|
const gridOptions: GridOptions<Task> = { |
|
...sharedGridOptions, |
|
|
|
columnDefs: [ |
|
{ |
|
field: 'priority', |
|
hide: true, |
|
sort: 'asc', |
|
}, |
|
...(sharedGridOptions.columnDefs || []), |
|
{ |
|
headerName: 'Action', |
|
pinned: 'right', |
|
minWidth: 110, |
|
maxWidth: 110, |
|
resizable: false, |
|
valueGetter: ({ data }) => data?.id, |
|
cellRenderer: ({ api, value, data }: any) => { |
|
if (!data) return undefined; |
|
|
|
const html = ` |
|
<div class="inline-flex rounded-md shadow-sm mt-1.5" role="group"> |
|
<button type="button" title="Run" ${ |
|
data.status === 'running' ? 'disabled' : '' |
|
} class="ts-btn-action ts-btn-run"> |
|
${playIcon} |
|
</button> |
|
<button type="button" title="Delete" class="ts-btn-action ts-btn-delete"> |
|
${data.status === 'pending' ? deleteIcon : cancelIcon} |
|
</button> |
|
</div> |
|
`; |
|
|
|
const placeholder = document.createElement('div'); |
|
placeholder.innerHTML = html; |
|
const node = placeholder.firstElementChild!; |
|
|
|
const btnRun = node.querySelector('button.ts-btn-run')!; |
|
btnRun.addEventListener('click', () => { |
|
api.showLoadingOverlay(); |
|
store.runTask(value).then(() => api.hideOverlay()); |
|
}); |
|
|
|
const btnDelete = node.querySelector('button.ts-btn-delete')!; |
|
btnDelete.addEventListener('click', () => { |
|
api.showLoadingOverlay(); |
|
store.deleteTask(value).then((res) => { |
|
notify(res); |
|
api.applyTransaction({ |
|
remove: [data], |
|
}); |
|
api.hideOverlay(); |
|
}); |
|
}); |
|
|
|
return node; |
|
}, |
|
}, |
|
], |
|
onColumnMoved({ columnApi }) { |
|
const colState = columnApi.getColumnState(); |
|
const colStateStr = JSON.stringify(colState); |
|
localStorage.setItem('agent_scheduler:queue_col_state', colStateStr); |
|
}, |
|
onSortChanged({ columnApi }) { |
|
const colState = columnApi.getColumnState(); |
|
const colStateStr = JSON.stringify(colState); |
|
localStorage.setItem('agent_scheduler:queue_col_state', colStateStr); |
|
}, |
|
onColumnResized({ columnApi }) { |
|
const colState = columnApi.getColumnState(); |
|
const colStateStr = JSON.stringify(colState); |
|
localStorage.setItem('agent_scheduler:queue_col_state', colStateStr); |
|
}, |
|
onGridReady: ({ api, columnApi }) => { |
|
|
|
const searchContainer = initSearchInput('#agent_scheduler_action_search'); |
|
const searchInput: HTMLInputElement = searchContainer.querySelector('input.ts-search-input')!; |
|
searchInput.addEventListener( |
|
'keyup', |
|
debounce((e: KeyboardEvent) => { |
|
api.setQuickFilter((e.target as HTMLInputElement).value); |
|
}, 200), |
|
); |
|
|
|
store.subscribe((state) => { |
|
api.setRowData(state.pending_tasks); |
|
|
|
if (state.current_task_id) { |
|
const node = api.getRowNode(state.current_task_id); |
|
if (node) { |
|
api.refreshCells({ rowNodes: [node], force: true }); |
|
} |
|
} |
|
|
|
columnApi.autoSizeAllColumns(); |
|
}); |
|
|
|
|
|
const colStateStr = localStorage.getItem('agent_scheduler:queue_col_state'); |
|
if (colStateStr) { |
|
const colState = JSON.parse(colStateStr); |
|
columnApi.applyColumnState({ state: colState, applyOrder: true }); |
|
} |
|
}, |
|
onRowDragEnd: ({ api, node, overNode }) => { |
|
const id = node.data?.id; |
|
const overId = overNode?.data?.id; |
|
if (id && overId && id !== overId) { |
|
api.showLoadingOverlay(); |
|
store.moveTask(id, overId).then(() => api.hideOverlay()); |
|
} |
|
}, |
|
}; |
|
|
|
const eGridDiv = gradioApp().querySelector<HTMLDivElement>( |
|
'#agent_scheduler_pending_tasks_grid', |
|
)!; |
|
if (document.querySelector('.dark')) { |
|
eGridDiv.className = 'ag-theme-alpine-dark'; |
|
} |
|
eGridDiv.style.height = 'calc(100vh - 300px)'; |
|
new Grid(eGridDiv, gridOptions); |
|
} |
|
|
|
function initHistoryTab() { |
|
const store = historyStore; |
|
|
|
|
|
const refreshButton = gradioApp().querySelector('#agent_scheduler_action_refresh_history')!; |
|
refreshButton.addEventListener('click', () => { |
|
store.refresh(); |
|
}); |
|
const resultTaskId: HTMLTextAreaElement = gradioApp().querySelector( |
|
'#agent_scheduler_history_selected_task textarea', |
|
)!; |
|
const resultImageId: HTMLTextAreaElement = gradioApp().querySelector( |
|
'#agent_scheduler_history_selected_image textarea', |
|
)!; |
|
const resultGallery: HTMLDivElement = gradioApp().querySelector( |
|
'#agent_scheduler_history_gallery', |
|
)!; |
|
resultGallery.addEventListener('click', (e) => { |
|
const target = e.target as HTMLImageElement; |
|
if (target.tagName === 'IMG') { |
|
const imageIdx = Array.prototype.indexOf.call( |
|
target.parentNode?.parentNode?.childNodes ?? [], |
|
target.parentNode, |
|
); |
|
resultImageId.value = imageIdx.toString(); |
|
resultImageId.dispatchEvent(new Event('input', { bubbles: true })); |
|
} |
|
}); |
|
window.agent_scheduler_status_filter_changed = function (value) { |
|
store.onFilterStatus(value?.toLowerCase() as TaskStatus); |
|
}; |
|
|
|
|
|
const gridOptions: GridOptions<Task> = { |
|
...sharedGridOptions, |
|
defaultColDef: { |
|
...sharedGridOptions.defaultColDef, |
|
sortable: true, |
|
}, |
|
|
|
columnDefs: [ |
|
{ |
|
headerName: '', |
|
field: 'bookmarked', |
|
minWidth: 55, |
|
maxWidth: 55, |
|
pinned: 'left', |
|
sort: 'desc', |
|
cellClass: 'cursor-pointer pt-3', |
|
cellRenderer: ({ data, value }: any) => { |
|
if (!data) return undefined; |
|
return value |
|
? `<span class="!text-yellow-400">${bookmarked}</span>` |
|
: `<span class="!text-gray-400">${bookmark}</span>`; |
|
}, |
|
onCellClicked: ({ data, event, api }) => { |
|
if (!data) return; |
|
event?.stopPropagation(); |
|
event?.preventDefault(); |
|
store.bookmarkTask(data.id, !data.bookmarked).then((res) => { |
|
notify(res); |
|
api.applyTransaction({ |
|
update: [{ ...data, bookmarked: !data.bookmarked }], |
|
}); |
|
}); |
|
}, |
|
}, |
|
{ |
|
field: 'priority', |
|
hide: true, |
|
sort: 'desc', |
|
}, |
|
{ |
|
...(sharedGridOptions.columnDefs || [])[0], |
|
rowDrag: false, |
|
}, |
|
...(sharedGridOptions.columnDefs || []).slice(1), |
|
{ |
|
headerName: 'Action', |
|
pinned: 'right', |
|
minWidth: 110, |
|
maxWidth: 110, |
|
resizable: false, |
|
valueGetter: ({ data }) => data?.id, |
|
cellRenderer: ({ api, data, value }: any) => { |
|
if (!data) return undefined; |
|
|
|
const html = ` |
|
<div class="inline-flex rounded-md shadow-sm mt-1.5" role="group"> |
|
<button type="button" title="Requeue" class="ts-btn-action ts-btn-run"> |
|
${rotateIcon} |
|
</button> |
|
<button type="button" title="Delete" class="ts-btn-action ts-btn-delete"> |
|
${deleteIcon} |
|
</button> |
|
</div> |
|
`; |
|
|
|
const placeholder = document.createElement('div'); |
|
placeholder.innerHTML = html; |
|
const node = placeholder.firstElementChild!; |
|
|
|
const btnRun = node.querySelector('button.ts-btn-run')!; |
|
btnRun.addEventListener('click', (e) => { |
|
e.preventDefault(); |
|
e.stopPropagation(); |
|
store.requeueTask(value).then((res) => { |
|
notify(res); |
|
}); |
|
}); |
|
|
|
const btnDelete = node.querySelector('button.ts-btn-delete')!; |
|
btnDelete.addEventListener('click', (e) => { |
|
e.preventDefault(); |
|
e.stopPropagation(); |
|
api.showLoadingOverlay(); |
|
pendingStore.deleteTask(value).then((res) => { |
|
notify(res); |
|
api.applyTransaction({ |
|
remove: [data], |
|
}); |
|
api.hideOverlay(); |
|
}); |
|
}); |
|
|
|
return node; |
|
}, |
|
}, |
|
], |
|
rowSelection: 'single', |
|
suppressRowDeselection: true, |
|
onColumnMoved({ columnApi }) { |
|
const colState = columnApi.getColumnState(); |
|
const colStateStr = JSON.stringify(colState); |
|
localStorage.setItem('agent_scheduler:history_col_state', colStateStr); |
|
}, |
|
onSortChanged({ columnApi }) { |
|
const colState = columnApi.getColumnState(); |
|
const colStateStr = JSON.stringify(colState); |
|
localStorage.setItem('agent_scheduler:history_col_state', colStateStr); |
|
}, |
|
onColumnResized({ columnApi }) { |
|
const colState = columnApi.getColumnState(); |
|
const colStateStr = JSON.stringify(colState); |
|
localStorage.setItem('agent_scheduler:history_col_state', colStateStr); |
|
}, |
|
onGridReady: ({ api, columnApi }) => { |
|
|
|
const searchContainer = initSearchInput('#agent_scheduler_action_search_history'); |
|
const searchInput: HTMLInputElement = searchContainer.querySelector('input.ts-search-input')!; |
|
searchInput.addEventListener( |
|
'keyup', |
|
debounce((e: KeyboardEvent) => { |
|
api.setQuickFilter((e.target as HTMLInputElement).value); |
|
}, 200), |
|
); |
|
|
|
store.subscribe((state) => { |
|
api.setRowData(state.tasks); |
|
columnApi.autoSizeAllColumns(); |
|
}); |
|
|
|
|
|
const colStateStr = localStorage.getItem('agent_scheduler:history_col_state'); |
|
if (colStateStr) { |
|
const colState = JSON.parse(colStateStr); |
|
columnApi.applyColumnState({ state: colState, applyOrder: true }); |
|
} |
|
}, |
|
onSelectionChanged: (e) => { |
|
const [selected] = e.api.getSelectedRows(); |
|
if (selected) { |
|
resultTaskId.value = selected.id; |
|
resultTaskId.dispatchEvent(new Event('input', { bubbles: true })); |
|
} |
|
}, |
|
}; |
|
const eGridDiv = gradioApp().querySelector<HTMLDivElement>( |
|
'#agent_scheduler_history_tasks_grid', |
|
)!; |
|
if (document.querySelector('.dark')) { |
|
eGridDiv.className = 'ag-theme-alpine-dark'; |
|
} |
|
eGridDiv.style.height = 'calc(100vh - 300px)'; |
|
new Grid(eGridDiv, gridOptions); |
|
} |
|
|
|
let agentSchedulerInitialized = false; |
|
|
|
onUiLoaded(function initAgentScheduler() { |
|
|
|
if (!document.getElementById('agent_scheduler_tabs')) { |
|
setTimeout(initAgentScheduler, 500); |
|
return; |
|
} |
|
if (agentSchedulerInitialized) return; |
|
initQueueHandler(); |
|
initTabChangeHandler(); |
|
initPendingTab(); |
|
initHistoryTab(); |
|
agentSchedulerInitialized = true; |
|
}); |
|
|