Skip to content

Commit

Permalink
Feature/delivery alerts (#768)
Browse files Browse the repository at this point in the history
* Delivery alerts backend

Signed-off-by: Aaron Chong <aaronchongth@gmail.com>

* api-client updates

Signed-off-by: Aaron Chong <aaronchongth@gmail.com>

* Adding message field to model

Signed-off-by: Aaron Chong <aaronchongth@gmail.com>

* Frontend without action calls yet

Signed-off-by: Aaron Chong <aaronchongth@gmail.com>

* Working, except refreshing removes the alerts

Signed-off-by: Aaron Chong <aaronchongth@gmail.com>

* Refresh retrieves delivery alerts too, however waiting errors are always shown

Signed-off-by: Aaron Chong <aaronchongth@gmail.com>

* Filters through all delivery alerts for unresolved and up-to-date ones to display

Signed-off-by: Aaron Chong <aaronchongth@gmail.com>

* Lint

Signed-off-by: Aaron Chong <aaronchongth@gmail.com>

* Refactored if statement, remove unnecessary null check

Signed-off-by: Aaron Chong <aaronchongth@gmail.com>

* Using comparison between alert ids to filter more efficiently

Signed-off-by: Aaron Chong <aaronchongth@gmail.com>

* Allow cancellation if task_id is present, only allow override for missing carts

Signed-off-by: Aaron Chong <aaronchongth@gmail.com>

* Update cancel button and delivery alert action only after task has been properly cancelled

Signed-off-by: Aaron Chong <aaronchongth@gmail.com>

* Only update action based on task state update when the cancel button was clicked

Signed-off-by: Aaron Chong <aaronchongth@gmail.com>

* Remove stale console log

Signed-off-by: Aaron Chong <aaronchongth@gmail.com>

---------

Signed-off-by: Aaron Chong <aaronchongth@gmail.com>
  • Loading branch information
aaronchongth committed Sep 26, 2023
1 parent 828171e commit 8add1a6
Show file tree
Hide file tree
Showing 14 changed files with 1,456 additions and 6 deletions.
5 changes: 5 additions & 0 deletions packages/api-client/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
ApiServerModelsTortoiseModelsAlertsAlertLeaf,
ApiServerModelsTortoiseModelsBeaconsBeaconStateLeaf as BeaconState,
BuildingMap,
ApiServerModelsTortoiseModelsDeliveryAlertsDeliveryAlertLeaf as DeliveryAlert,
DispenserHealth,
DispenserState,
DoorHealth,
Expand Down Expand Up @@ -124,6 +125,10 @@ export class SioClient {
subscribeAlerts(listener: Listener<Alert>): Subscription {
return this.subscribe<Alert>(`/alerts`, listener);
}

subscribeDeliveryAlerts(listener: Listener<DeliveryAlert>): Subscription {
return this.subscribe<DeliveryAlert>(`/delivery_alerts`, listener);
}
}

export * from './openapi';
540 changes: 536 additions & 4 deletions packages/api-client/lib/openapi/api.ts

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/api-client/lib/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ import { version as rmfModelVer } from 'rmf-models';

export const version = {
rmfModels: rmfModelVer,
rmfServer: '60cfa28fb26433cb33254ba1522fc00466fe7146',
rmfServer: '6ca8484298a18d0b71041295c6c7880555971461',
openapiGenerator: '6.2.1',
};
172 changes: 171 additions & 1 deletion packages/api-client/schema/index.ts

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions packages/api-server/api_server/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ async def on_sio_connect(sid: str, _environ: dict, auth: Optional[dict] = None):
app.include_router(
routes.building_map_router, prefix="/building_map", dependencies=[Depends(user_dep)]
)
app.include_router(
routes.delivery_alerts_router,
prefix="/delivery_alerts",
dependencies=[Depends(user_dep)],
)
app.include_router(
routes.doors_router, prefix="/doors", dependencies=[Depends(user_dep)]
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from .authorization import *
from .beacons import *
from .building_map import BuildingMap
from .delivery_alerts import *
from .dispenser_state import DispenserState
from .door_state import DoorState
from .fleets import FleetLog, FleetLogLog, FleetLogRobots, FleetLogRobotsLog, FleetState
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from enum import Enum

from tortoise.contrib.pydantic.creator import pydantic_model_creator
from tortoise.fields import CharEnumField, CharField
from tortoise.models import Model


class DeliveryAlert(Model):
"""
Custom alerts for custom delivery tasks
"""

class Category(str, Enum):
Missing = "missing"
Wrong = "wrong"

class Tier(str, Enum):
Warning = "warning"
Error = "error"

class Action(str, Enum):
Waiting = "waiting"
Cancel = "cancelled"
Override = "override"
Resume = "resume"

id = CharField(255, pk=True)
category = CharEnumField(Category, index=True)
tier = CharEnumField(Tier, index=True)
task_id = CharField(255, index=True, null=True)
action = CharEnumField(Action, index=True)
message = CharField(255, null=True)


DeliveryAlertPydantic = pydantic_model_creator(DeliveryAlert)
1 change: 1 addition & 0 deletions packages/api-server/api_server/rmf_io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
TaskEvents,
alert_events,
beacon_events,
delivery_alert_events,
fleet_events,
rmf_events,
task_events,
Expand Down
8 changes: 8 additions & 0 deletions packages/api-server/api_server/rmf_io/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,11 @@ def __init__(self):


beacon_events = BeaconEvents()


class DeliveryAlertEvents:
def __init__(self):
self.delivery_alerts = Subject() # DeliveryAlert


delivery_alert_events = DeliveryAlertEvents()
1 change: 1 addition & 0 deletions packages/api-server/api_server/routes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from .alerts import router as alerts_router
from .beacons import router as beacons_router
from .building_map import router as building_map_router
from .delivery_alerts import router as delivery_alerts_router
from .dispensers import router as dispensers_router
from .doors import router as doors_router
from .fleets import router as fleets_router
Expand Down
85 changes: 85 additions & 0 deletions packages/api-server/api_server/routes/delivery_alerts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
from datetime import datetime
from typing import List

from fastapi import HTTPException
from rx import operators as rxops

from api_server.fast_io import FastIORouter, SubscriptionRequest
from api_server.models import tortoise_models as ttm
from api_server.rmf_io import delivery_alert_events

router = FastIORouter(tags=["DeliveryAlerts"])


@router.sub("", response_model=ttm.DeliveryAlertPydantic)
async def sub_delivery_alerts(_req: SubscriptionRequest):
return delivery_alert_events.delivery_alerts.pipe(
rxops.filter(lambda x: x is not None)
)


@router.get("", response_model=List[ttm.DeliveryAlertPydantic])
async def get_delivery_alerts():
delivery_alerts = await ttm.DeliveryAlert.all()
return [
await ttm.DeliveryAlertPydantic.from_tortoise_orm(a) for a in delivery_alerts
]


@router.get("/{delivery_alert_id}", response_model=ttm.DeliveryAlertPydantic)
async def get_delivery_alert(delivery_alert_id: str):
delivery_alert = await ttm.DeliveryAlert.get_or_none(id=delivery_alert_id)
if delivery_alert is None:
raise HTTPException(
404, f"Delivery alert with ID {delivery_alert_id} not found"
)
delivery_alert_pydantic = await ttm.DeliveryAlertPydantic.from_tortoise_orm(
delivery_alert
)
return delivery_alert_pydantic


@router.post("", status_code=201, response_model=ttm.DeliveryAlertPydantic)
async def create_delivery_alert(category: str, tier: str, task_id: str, message: str):
timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
delivery_alert_id = f"delivery-alert-{timestamp}"
try:
delivery_alert = await ttm.DeliveryAlert.create(
id=delivery_alert_id,
category=category,
tier=tier,
task_id=task_id,
action="waiting",
message=message,
)
except Exception as e:
raise HTTPException(400, f"Could not create delivery alert: {e}") from e

delivery_alert_pydantic = await ttm.DeliveryAlertPydantic.from_tortoise_orm(
delivery_alert
)
delivery_alert_events.delivery_alerts.on_next(delivery_alert_pydantic)
return delivery_alert_pydantic


@router.post("/{delivery_alert_id}/action", response_model=ttm.DeliveryAlertPydantic)
async def update_delivery_alert_action(delivery_alert_id: str, action: str):
delivery_alert = await ttm.DeliveryAlert.get_or_none(id=delivery_alert_id)
if delivery_alert is None:
raise HTTPException(
404, f"Delivery alert with ID {delivery_alert_id} not found"
)

try:
delivery_alert.update_from_dict({"action": action})
except Exception as e:
raise HTTPException(
404,
f"Failed to update delivery alert {delivery_alert_id} with action {action}: {e}",
) from e
await delivery_alert.save()

delivery_alert_pydantic = await ttm.DeliveryAlertPydantic.from_tortoise_orm(
delivery_alert
)
return delivery_alert_pydantic
2 changes: 2 additions & 0 deletions packages/dashboard/src/components/app-base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { loadSettings, saveSettings, Settings, ThemeMode } from '../settings';
import { AppController, AppControllerContext, SettingsContext } from './app-contexts';
import AppBar from './appbar';
import { AlertStore } from './alert-store';
import { DeliveryAlertStore } from './delivery-alert-store';

const DefaultAlertDuration = 2000;
const defaultTheme = createTheme({
Expand Down Expand Up @@ -119,6 +120,7 @@ export function AppBase({ children }: React.PropsWithChildren<{}>): JSX.Element
<SettingsContext.Provider value={settings}>
<AppControllerContext.Provider value={appController}>
<AlertStore />
<DeliveryAlertStore />
{lowResolutionAlert && lowResolutionDisplayAlert()}
<Grid
container
Expand Down
Loading

0 comments on commit 8add1a6

Please sign in to comment.