Merge branch 'pr-385'
This commit is contained in:
@@ -7,7 +7,7 @@ from sqlalchemy.orm import Session
|
|||||||
|
|
||||||
from middleware.auth_middleware import get_current_user
|
from middleware.auth_middleware import get_current_user
|
||||||
from services.database import get_db
|
from services.database import get_db
|
||||||
from services.today_workflow_service import get_or_create_daily_workflow_plan, update_task_status
|
from services.today_workflow_service import coerce_dependencies, get_or_create_daily_workflow_plan, update_task_status
|
||||||
from models.daily_workflow_models import DailyWorkflowPlan, DailyWorkflowTask
|
from models.daily_workflow_models import DailyWorkflowPlan, DailyWorkflowTask
|
||||||
import asyncio
|
import asyncio
|
||||||
from services.intelligence.txtai_service import TxtaiIntelligenceService
|
from services.intelligence.txtai_service import TxtaiIntelligenceService
|
||||||
@@ -62,6 +62,19 @@ async def get_today_workflow(
|
|||||||
|
|
||||||
tasks = await run_in_threadpool(_fetch_tasks)
|
tasks = await run_in_threadpool(_fetch_tasks)
|
||||||
|
|
||||||
|
def _normalize_legacy_dependencies(task_rows):
|
||||||
|
rows_updated = False
|
||||||
|
for row in task_rows:
|
||||||
|
normalized_dependencies = coerce_dependencies(row.dependencies)
|
||||||
|
if row.dependencies != normalized_dependencies:
|
||||||
|
row.dependencies = normalized_dependencies
|
||||||
|
db.add(row)
|
||||||
|
rows_updated = True
|
||||||
|
if rows_updated:
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
await run_in_threadpool(_normalize_legacy_dependencies, tasks)
|
||||||
|
|
||||||
response_tasks = []
|
response_tasks = []
|
||||||
for t in tasks:
|
for t in tasks:
|
||||||
response_tasks.append(
|
response_tasks.append(
|
||||||
@@ -73,7 +86,7 @@ async def get_today_workflow(
|
|||||||
"status": "skipped" if t.status == "dismissed" else t.status,
|
"status": "skipped" if t.status == "dismissed" else t.status,
|
||||||
"priority": t.priority,
|
"priority": t.priority,
|
||||||
"estimatedTime": t.estimated_time,
|
"estimatedTime": t.estimated_time,
|
||||||
"dependencies": t.dependencies or [],
|
"dependencies": coerce_dependencies(t.dependencies),
|
||||||
"actionUrl": t.action_url,
|
"actionUrl": t.action_url,
|
||||||
"actionType": t.action_type,
|
"actionType": t.action_type,
|
||||||
"metadata": t.metadata_json or {},
|
"metadata": t.metadata_json or {},
|
||||||
|
|||||||
@@ -30,6 +30,25 @@ def _coerce_status(value: Any) -> str:
|
|||||||
return "pending"
|
return "pending"
|
||||||
|
|
||||||
|
|
||||||
|
def coerce_dependencies(value: Any) -> List[str]:
|
||||||
|
if isinstance(value, list):
|
||||||
|
return [str(dep).strip() for dep in value if str(dep).strip()]
|
||||||
|
|
||||||
|
if isinstance(value, str):
|
||||||
|
raw = value.strip()
|
||||||
|
if not raw:
|
||||||
|
return []
|
||||||
|
try:
|
||||||
|
parsed = json.loads(raw)
|
||||||
|
if isinstance(parsed, list):
|
||||||
|
return [str(dep).strip() for dep in parsed if str(dep).strip()]
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return [raw]
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
def _proposal_priority_rank(priority: str) -> int:
|
def _proposal_priority_rank(priority: str) -> int:
|
||||||
return {"low": 0, "medium": 1, "high": 2}.get(str(priority or "").lower(), 1)
|
return {"low": 0, "medium": 1, "high": 2}.get(str(priority or "").lower(), 1)
|
||||||
|
|
||||||
@@ -531,7 +550,7 @@ async def get_or_create_daily_workflow_plan(db: Session, user_id: str, date: Opt
|
|||||||
estimated_time=int(t.get("estimatedTime") or 15),
|
estimated_time=int(t.get("estimatedTime") or 15),
|
||||||
action_type=str(t.get("actionType") or "navigate").strip()[:20],
|
action_type=str(t.get("actionType") or "navigate").strip()[:20],
|
||||||
action_url=str(t.get("actionUrl") or "").strip(),
|
action_url=str(t.get("actionUrl") or "").strip(),
|
||||||
dependencies=json.dumps(t.get("dependencies") or []),
|
dependencies=coerce_dependencies(t.get("dependencies")),
|
||||||
metadata_json=t.get("metadata") or {},
|
metadata_json=t.get("metadata") or {},
|
||||||
enabled=bool(t.get("enabled", True)),
|
enabled=bool(t.get("enabled", True)),
|
||||||
created_at=datetime.utcnow(),
|
created_at=datetime.utcnow(),
|
||||||
|
|||||||
@@ -14,6 +14,39 @@ import { apiClient } from '../api/client';
|
|||||||
|
|
||||||
const isServerWorkflowId = (workflowId: string) => workflowId.startsWith('daily-');
|
const isServerWorkflowId = (workflowId: string) => workflowId.startsWith('daily-');
|
||||||
|
|
||||||
|
|
||||||
|
const normalizeDependencies = (dependencies: unknown): string[] => {
|
||||||
|
if (Array.isArray(dependencies)) {
|
||||||
|
return dependencies.map(dep => String(dep).trim()).filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof dependencies === 'string') {
|
||||||
|
const raw = dependencies.trim();
|
||||||
|
if (!raw) return [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
if (Array.isArray(parsed)) {
|
||||||
|
return parsed.map(dep => String(dep).trim()).filter(Boolean);
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
return [raw];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizeServerWorkflow = (workflow: DailyWorkflow): DailyWorkflow => ({
|
||||||
|
...workflow,
|
||||||
|
tasks: Array.isArray(workflow.tasks)
|
||||||
|
? workflow.tasks.map(task => ({
|
||||||
|
...task,
|
||||||
|
dependencies: normalizeDependencies(task.dependencies),
|
||||||
|
}))
|
||||||
|
: [],
|
||||||
|
});
|
||||||
|
|
||||||
const computeProgressAndNavigation = (workflow: DailyWorkflow): { progress: WorkflowProgress; navigation: NavigationState } => {
|
const computeProgressAndNavigation = (workflow: DailyWorkflow): { progress: WorkflowProgress; navigation: NavigationState } => {
|
||||||
const tasks = Array.isArray(workflow.tasks) ? workflow.tasks : [];
|
const tasks = Array.isArray(workflow.tasks) ? workflow.tasks : [];
|
||||||
const totalTasks = tasks.length;
|
const totalTasks = tasks.length;
|
||||||
@@ -118,9 +151,10 @@ export const useWorkflowStore = create<WorkflowState>()(
|
|||||||
const resp = await apiClient.get('/api/today-workflow', { params: date ? { date } : {} });
|
const resp = await apiClient.get('/api/today-workflow', { params: date ? { date } : {} });
|
||||||
const serverWorkflow = resp?.data?.data?.workflow as DailyWorkflow | undefined;
|
const serverWorkflow = resp?.data?.data?.workflow as DailyWorkflow | undefined;
|
||||||
if (serverWorkflow && Array.isArray(serverWorkflow.tasks)) {
|
if (serverWorkflow && Array.isArray(serverWorkflow.tasks)) {
|
||||||
const derived = computeProgressAndNavigation(serverWorkflow);
|
const normalizedWorkflow = normalizeServerWorkflow(serverWorkflow);
|
||||||
|
const derived = computeProgressAndNavigation(normalizedWorkflow);
|
||||||
set({
|
set({
|
||||||
currentWorkflow: serverWorkflow,
|
currentWorkflow: normalizedWorkflow,
|
||||||
workflowProgress: derived.progress,
|
workflowProgress: derived.progress,
|
||||||
navigationState: derived.navigation,
|
navigationState: derived.navigation,
|
||||||
isLoading: false
|
isLoading: false
|
||||||
|
|||||||
Reference in New Issue
Block a user