| |
|
|
| 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; |
| }); |
|
|