Skip to content
Merged
12 changes: 12 additions & 0 deletions backend/api/inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ class PatientState(Enum):
DEAD = "DEAD"


@strawberry.enum
class TaskPriority(Enum):
P1 = "P1"
P2 = "P2"
P3 = "P3"
P4 = "P4"


@strawberry.input
class PropertyValueInput:
definition_id: strawberry.ID
Expand Down Expand Up @@ -104,6 +112,8 @@ class CreateTaskInput:
assignee_id: strawberry.ID | None = None
previous_task_ids: list[strawberry.ID] | None = None
properties: list[PropertyValueInput] | None = None
priority: TaskPriority | None = None
estimated_time: int | None = None


@strawberry.input
Expand All @@ -116,6 +126,8 @@ class UpdateTaskInput:
previous_task_ids: list[strawberry.ID] | None = None
properties: list[PropertyValueInput] | None = None
checksum: str | None = None
priority: TaskPriority | None = strawberry.UNSET
estimated_time: int | None = strawberry.UNSET


@strawberry.input
Expand Down
8 changes: 8 additions & 0 deletions backend/api/resolvers/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ async def create_task(self, info: Info, data: CreateTaskInput) -> TaskType:
patient_id=data.patient_id,
assignee_id=data.assignee_id,
due_date=normalize_datetime_to_utc(data.due_date),
priority=data.priority.value if data.priority else None,
estimated_time=data.estimated_time,
)

if data.properties is not None:
Expand Down Expand Up @@ -284,6 +286,12 @@ async def update_task(
else None
)

if data.priority is not strawberry.UNSET:
task.priority = data.priority.value if data.priority else None

if data.estimated_time is not strawberry.UNSET:
task.estimated_time = data.estimated_time

if data.properties is not None:
property_service = TaskMutation._get_property_service(db)
await property_service.process_properties(
Expand Down
2 changes: 2 additions & 0 deletions backend/api/types/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class TaskType:
update_date: datetime | None
assignee_id: strawberry.ID | None
patient_id: strawberry.ID
priority: str | None
estimated_time: int | None

@strawberry.field
async def assignee(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""Add priority and estimated_time to tasks.

Revision ID: add_task_priority_time
Revises: 0de3078888ba
Create Date: 2025-12-19 00:00:00.000000
"""

from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


revision: str = "add_task_priority_time"
down_revision: Union[str, Sequence[str], None] = "0de3078888ba"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
op.add_column(
"tasks",
sa.Column("priority", sa.String(), nullable=True),
)
op.add_column(
"tasks",
sa.Column("estimated_time", sa.Integer(), nullable=True),
)


def downgrade() -> None:
op.drop_column("tasks", "estimated_time")
op.drop_column("tasks", "priority")
4 changes: 3 additions & 1 deletion backend/database/models/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from typing import TYPE_CHECKING

from database.models.base import Base
from sqlalchemy import Boolean, Column, ForeignKey, String, Table
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, Table
from sqlalchemy.orm import Mapped, mapped_column, relationship

if TYPE_CHECKING:
Expand Down Expand Up @@ -44,6 +44,8 @@ class Task(Base):
nullable=True,
)
patient_id: Mapped[str] = mapped_column(ForeignKey("patients.id"))
priority: Mapped[str | None] = mapped_column(String, nullable=True)
estimated_time: Mapped[int | None] = mapped_column(Integer, nullable=True)

assignee: Mapped[User | None] = relationship(
"User",
Expand Down
41 changes: 35 additions & 6 deletions web/api/gql/generated.ts

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions web/api/graphql/GetMyTasks.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ query GetMyTasks {
description
done
dueDate
priority
estimatedTime
creationDate
updateDate
patient {
Expand Down
2 changes: 2 additions & 0 deletions web/api/graphql/GetPatient.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ query GetPatient($id: ID!) {
description
done
dueDate
priority
estimatedTime
updateDate
assignee {
id
Expand Down
2 changes: 2 additions & 0 deletions web/api/graphql/GetPatients.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ query GetPatients($locationId: ID, $rootLocationIds: [ID!], $states: [PatientSta
description
done
dueDate
priority
estimatedTime
creationDate
updateDate
assignee {
Expand Down
2 changes: 2 additions & 0 deletions web/api/graphql/GetTask.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ query GetTask($id: ID!) {
description
done
dueDate
priority
estimatedTime
checksum
patient {
id
Expand Down
2 changes: 2 additions & 0 deletions web/api/graphql/GetTasks.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ query GetTasks($rootLocationIds: [ID!], $assigneeId: ID) {
description
done
dueDate
priority
estimatedTime
creationDate
updateDate
patient {
Expand Down
6 changes: 6 additions & 0 deletions web/api/graphql/TaskMutations.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,14 @@ mutation UpdateTask($id: ID!, $data: UpdateTaskInput!) {
description
done
dueDate
priority
estimatedTime
updateDate
checksum
patient {
id
name
}
assignee {
id
name
Expand Down
49 changes: 37 additions & 12 deletions web/components/tasks/TaskCardView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ type FlexibleTask = {
description?: string | null,
done: boolean,
dueDate?: Date | string | null,
priority?: string | null,
estimatedTime?: number | null,
updateDate?: Date | string | null,
patient?: {
id: string,
Expand Down Expand Up @@ -111,13 +113,24 @@ export const TaskCardView = ({ task, onToggleDone: _onToggleDone, onClick, showA
</div>
<div className={clsx('flex-1 min-w-0 overflow-hidden', { 'pb-16': showPatient })}>
<div className="flex items-center justify-between gap-2 mb-2 flex-wrap min-w-0">
<div
className={clsx(
'font-semibold text-lg min-w-0 flex-1 truncate',
{ 'line-through text-description': task.done }
<div className="flex items-center gap-2 min-w-0 flex-1">
{(task as FlexibleTask).priority && (
<div className={clsx(
'w-2 h-2 rounded-full shrink-0',
(task as FlexibleTask).priority === 'P1' ? 'bg-red-500' :
(task as FlexibleTask).priority === 'P2' ? 'bg-orange-500' :
(task as FlexibleTask).priority === 'P3' ? 'bg-yellow-500' :
(task as FlexibleTask).priority === 'P4' ? 'bg-blue-500' : ''
)} />
)}
>
{taskName}
<div
className={clsx(
'font-semibold text-lg min-w-0 flex-1 truncate',
{ 'line-through text-description': task.done }
)}
>
{taskName}
</div>
</div>
{task.assignee && (
<div className="flex items-center gap-1.5 text-base text-description shrink-0 min-w-0">
Expand Down Expand Up @@ -156,12 +169,24 @@ export const TaskCardView = ({ task, onToggleDone: _onToggleDone, onClick, showA
)}
</div>
)}
{dueDate && (
<div className={clsx('absolute bottom-5 right-5 flex items-center gap-2 text-sm text-description', dueDateColorClass)}>
<Clock className="size-4" />
<SmartDate date={dueDate} mode="relative" showTime={true} />
</div>
)}
<div className="absolute bottom-5 right-5 flex items-center gap-3 text-sm text-description">
{(task as FlexibleTask).estimatedTime && (
<div className="flex items-center gap-1">
<Clock className="size-4" />
<span>
{(task as FlexibleTask).estimatedTime! < 60
? `${(task as FlexibleTask).estimatedTime}m`
: `${Math.floor((task as FlexibleTask).estimatedTime! / 60)}h ${(task as FlexibleTask).estimatedTime! % 60}m`}
</span>
</div>
)}
{dueDate && (
<div className={clsx('flex items-center gap-2', dueDateColorClass)}>
<Clock className="size-4" />
<SmartDate date={dueDate} mode="relative" showTime={true} />
</div>
)}
</div>
</button>
)
}
Expand Down
Loading
Loading