mirror of
https://github.com/open-webui/open-webui.git
synced 2026-05-06 02:48:13 -05:00
refac
This commit is contained in:
@@ -45,7 +45,10 @@ class AutomationRun(Base):
|
||||
error = Column(Text, nullable=True)
|
||||
created_at = Column(BigInteger, nullable=False)
|
||||
|
||||
__table_args__ = (Index('ix_automation_run_automation_id', 'automation_id'),)
|
||||
__table_args__ = (
|
||||
Index('ix_automation_run_automation_id', 'automation_id'),
|
||||
Index('ix_automation_run_aid_created', 'automation_id', 'created_at'),
|
||||
)
|
||||
|
||||
|
||||
####################
|
||||
@@ -308,6 +311,37 @@ class AutomationRunTable:
|
||||
)
|
||||
return AutomationRunModel.model_validate(row) if row else None
|
||||
|
||||
def get_latest_batch(
|
||||
self, automation_ids: list[str], db: Optional[Session] = None
|
||||
) -> dict[str, AutomationRunModel]:
|
||||
"""Fetch the latest run for each automation in a single query."""
|
||||
if not automation_ids:
|
||||
return {}
|
||||
with get_db_context(db) as db:
|
||||
# Subquery: max created_at per automation_id
|
||||
subq = (
|
||||
db.query(
|
||||
AutomationRun.automation_id,
|
||||
func.max(AutomationRun.created_at).label('max_created'),
|
||||
)
|
||||
.filter(AutomationRun.automation_id.in_(automation_ids))
|
||||
.group_by(AutomationRun.automation_id)
|
||||
.subquery()
|
||||
)
|
||||
rows = (
|
||||
db.query(AutomationRun)
|
||||
.join(
|
||||
subq,
|
||||
(AutomationRun.automation_id == subq.c.automation_id)
|
||||
& (AutomationRun.created_at == subq.c.max_created),
|
||||
)
|
||||
.all()
|
||||
)
|
||||
return {
|
||||
row.automation_id: AutomationRunModel.model_validate(row)
|
||||
for row in rows
|
||||
}
|
||||
|
||||
def get_by_automation(
|
||||
self,
|
||||
automation_id: str,
|
||||
|
||||
@@ -61,6 +61,7 @@ def check_automation_access(automation, user):
|
||||
|
||||
|
||||
def enrich_automation(automation: AutomationModel, db: Session, tz: str = None) -> AutomationResponse:
|
||||
"""Full enrichment for single-item views (includes next_runs computation)."""
|
||||
last_run = AutomationRuns.get_latest(automation.id, db=db)
|
||||
return AutomationResponse(
|
||||
**automation.model_dump(),
|
||||
@@ -97,8 +98,18 @@ async def get_automation_items(
|
||||
db=db,
|
||||
)
|
||||
|
||||
# Batch-fetch latest runs in a single query instead of N+1
|
||||
ids = [item.id for item in result.items]
|
||||
latest_runs = AutomationRuns.get_latest_batch(ids, db=db) if ids else {}
|
||||
|
||||
return {
|
||||
'items': [enrich_automation(item, db, tz=user.timezone) for item in result.items],
|
||||
'items': [
|
||||
AutomationResponse(
|
||||
**item.model_dump(),
|
||||
last_run=latest_runs.get(item.id),
|
||||
)
|
||||
for item in result.items
|
||||
],
|
||||
'total': result.total,
|
||||
}
|
||||
|
||||
|
||||
@@ -47,8 +47,8 @@
|
||||
|
||||
let page = 1;
|
||||
|
||||
// Debounce only query changes
|
||||
$: if (query !== undefined) {
|
||||
// Debounce only query changes (gate behind loaded to prevent double-fetch on mount)
|
||||
$: if (loaded && query !== undefined) {
|
||||
loading = true;
|
||||
clearTimeout(searchDebounceTimer);
|
||||
searchDebounceTimer = setTimeout(() => {
|
||||
@@ -57,8 +57,8 @@
|
||||
}, 300);
|
||||
}
|
||||
|
||||
// Immediate response to page/filter changes
|
||||
$: if (page && statusFilter !== undefined) {
|
||||
// Immediate response to page/filter changes (gate behind loaded)
|
||||
$: if (loaded && page && statusFilter !== undefined) {
|
||||
getAutomationList();
|
||||
}
|
||||
|
||||
@@ -171,6 +171,8 @@
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
// Explicit initial fetch — reactive blocks will handle subsequent changes
|
||||
await getAutomationList();
|
||||
|
||||
return () => {
|
||||
clearTimeout(searchDebounceTimer);
|
||||
|
||||
Reference in New Issue
Block a user