diff --git a/packages/api-client/lib/openapi/api.ts b/packages/api-client/lib/openapi/api.ts index 1a422d6e9..24b7e21cf 100644 --- a/packages/api-client/lib/openapi/api.ts +++ b/packages/api-client/lib/openapi/api.ts @@ -1838,6 +1838,31 @@ export interface MutexGroups { */ requesting?: Array; } +/** + * + * @export + * @interface Pagination + */ +export interface Pagination { + /** + * + * @type {number} + * @memberof Pagination + */ + limit: number; + /** + * + * @type {number} + * @memberof Pagination + */ + offset: number; + /** + * + * @type {Array} + * @memberof Pagination + */ + order_by: Array; +} /** * * @export @@ -5033,10 +5058,12 @@ export const AlertsApiAxiosParamCreator = function (configuration?: Configuratio /** * Returns the list of alert IDs that have yet to be responded to, while a response was required. * @summary Get Unresponded Alerts + * @param {Pagination} [pagination] * @param {*} [options] Override http request option. * @throws {RequiredError} */ getUnrespondedAlertsAlertsUnrespondedRequestsGet: async ( + pagination?: Pagination, options: AxiosRequestConfig = {}, ): Promise => { const localVarPath = `/alerts/unresponded_requests`; @@ -5051,6 +5078,8 @@ export const AlertsApiAxiosParamCreator = function (configuration?: Configuratio const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; + localVarHeaderParameter['Content-Type'] = 'application/json'; + setSearchParams(localVarUrlObj, localVarQueryParameter); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = { @@ -5058,6 +5087,11 @@ export const AlertsApiAxiosParamCreator = function (configuration?: Configuratio ...headersFromBaseOptions, ...options.headers, }; + localVarRequestOptions.data = serializeDataIfNeeded( + pagination, + localVarRequestOptions, + configuration, + ); return { url: toPathString(localVarUrlObj), @@ -5199,14 +5233,19 @@ export const AlertsApiFp = function (configuration?: Configuration) { /** * Returns the list of alert IDs that have yet to be responded to, while a response was required. * @summary Get Unresponded Alerts + * @param {Pagination} [pagination] * @param {*} [options] Override http request option. * @throws {RequiredError} */ async getUnrespondedAlertsAlertsUnrespondedRequestsGet( + pagination?: Pagination, options?: AxiosRequestConfig, ): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { const localVarAxiosArgs = - await localVarAxiosParamCreator.getUnrespondedAlertsAlertsUnrespondedRequestsGet(options); + await localVarAxiosParamCreator.getUnrespondedAlertsAlertsUnrespondedRequestsGet( + pagination, + options, + ); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -5306,14 +5345,16 @@ export const AlertsApiFactory = function ( /** * Returns the list of alert IDs that have yet to be responded to, while a response was required. * @summary Get Unresponded Alerts + * @param {Pagination} [pagination] * @param {*} [options] Override http request option. * @throws {RequiredError} */ getUnrespondedAlertsAlertsUnrespondedRequestsGet( + pagination?: Pagination, options?: any, ): AxiosPromise> { return localVarFp - .getUnrespondedAlertsAlertsUnrespondedRequestsGet(options) + .getUnrespondedAlertsAlertsUnrespondedRequestsGet(pagination, options) .then((request) => request(axios, basePath)); }, /** @@ -5410,13 +5451,17 @@ export class AlertsApi extends BaseAPI { /** * Returns the list of alert IDs that have yet to be responded to, while a response was required. * @summary Get Unresponded Alerts + * @param {Pagination} [pagination] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AlertsApi */ - public getUnrespondedAlertsAlertsUnrespondedRequestsGet(options?: AxiosRequestConfig) { + public getUnrespondedAlertsAlertsUnrespondedRequestsGet( + pagination?: Pagination, + options?: AxiosRequestConfig, + ) { return AlertsApiFp(this.configuration) - .getUnrespondedAlertsAlertsUnrespondedRequestsGet(options) + .getUnrespondedAlertsAlertsUnrespondedRequestsGet(pagination, options) .then((request) => request(this.axios, this.basePath)); } diff --git a/packages/api-client/lib/version.ts b/packages/api-client/lib/version.ts index 7c8596d2f..09afd3ea7 100644 --- a/packages/api-client/lib/version.ts +++ b/packages/api-client/lib/version.ts @@ -3,6 +3,6 @@ import { version as rmfModelVer } from 'rmf-models'; export const version = { rmfModels: rmfModelVer, - rmfServer: 'cb1b563ab8f827756f9a453ec944362d92a3ab57', + rmfServer: '06e5475f096ec8f2eae05aae7c939a612aaa11e6', openapiGenerator: '6.2.1', }; diff --git a/packages/api-client/schema/index.ts b/packages/api-client/schema/index.ts index bb7f199a5..f0227c494 100644 --- a/packages/api-client/schema/index.ts +++ b/packages/api-client/schema/index.ts @@ -242,6 +242,9 @@ export default { description: 'Returns the list of alert IDs that have yet to be responded to, while a\nresponse was required.', operationId: 'get_unresponded_alerts_alerts_unresponded_requests_get', + requestBody: { + content: { 'application/json': { schema: { $ref: '#/components/schemas/Pagination' } } }, + }, responses: { '200': { description: 'Successful Response', @@ -255,6 +258,12 @@ export default { }, }, }, + '422': { + description: 'Validation Error', + content: { + 'application/json': { schema: { $ref: '#/components/schemas/HTTPValidationError' } }, + }, + }, }, }, }, @@ -3470,6 +3479,16 @@ export default { }, }, }, + Pagination: { + title: 'Pagination', + required: ['limit', 'offset', 'order_by'], + type: 'object', + properties: { + limit: { title: 'Limit', type: 'integer' }, + offset: { title: 'Offset', type: 'integer' }, + order_by: { title: 'Order By', type: 'array', items: { type: 'string' } }, + }, + }, Param: { title: 'Param', required: ['name', 'type', 'value_int', 'value_float', 'value_string', 'value_bool'], diff --git a/packages/api-server/api_server/models/alerts.py b/packages/api-server/api_server/models/alerts.py index 93c64e996..c31a17afb 100644 --- a/packages/api-server/api_server/models/alerts.py +++ b/packages/api-server/api_server/models/alerts.py @@ -28,6 +28,7 @@ async def save(self) -> None: self.unix_millis_response_time / 1000 ), "response": self.response, + "data": self.json(), }, id=self.id, ) diff --git a/packages/api-server/api_server/models/tortoise_models/alerts.py b/packages/api-server/api_server/models/tortoise_models/alerts.py index 3317458be..0ef129559 100644 --- a/packages/api-server/api_server/models/tortoise_models/alerts.py +++ b/packages/api-server/api_server/models/tortoise_models/alerts.py @@ -13,6 +13,7 @@ class AlertResponse(Model): id = CharField(255, pk=True) response_time = DatetimeField(null=False, index=True) response = CharField(255, null=False, index=True) + data = JSONField() alert_request = OneToOneField( "models.AlertRequest", null=False, related_name="alert_response" ) diff --git a/packages/api-server/api_server/repositories/alerts.py b/packages/api-server/api_server/repositories/alerts.py index 83c6c70c4..3c71085d0 100644 --- a/packages/api-server/api_server/repositories/alerts.py +++ b/packages/api-server/api_server/repositories/alerts.py @@ -1,8 +1,8 @@ from datetime import datetime -from typing import List +from typing import List, Optional from api_server.exceptions import AlreadyExistsError, InvalidInputError, NotFoundError -from api_server.models import AlertRequest, AlertResponse +from api_server.models import AlertRequest, AlertResponse, Pagination from api_server.models import tortoise_models as ttm @@ -51,6 +51,7 @@ async def create_response(self, alert_id: str, response: str) -> AlertResponse: alert_response_model.unix_millis_response_time / 1000 ), response=response, + data=alert_response_model.json(), alert_request=alert, ) return alert_response_model @@ -78,8 +79,11 @@ async def get_alerts_of_task( alert_models = [AlertRequest.from_tortoise(alert) for alert in task_id_alerts] return alert_models - async def get_unresponded_alerts(self) -> List[AlertRequest]: - unresponded_alerts = await ttm.AlertRequest.filter( - alert_response=None, response_expected=True - ) + async def get_unresponded_alerts( + self, pagination: Optional[Pagination] + ) -> List[AlertRequest]: + query = ttm.AlertRequest.filter(alert_response=None, response_expected=True) + if pagination: + query = query.limit(pagination.limit).offset(pagination.offset) + unresponded_alerts = await query.all() return [AlertRequest.from_tortoise(alert) for alert in unresponded_alerts] diff --git a/packages/api-server/api_server/routes/alerts.py b/packages/api-server/api_server/routes/alerts.py index 69f4737ef..0bc990682 100644 --- a/packages/api-server/api_server/routes/alerts.py +++ b/packages/api-server/api_server/routes/alerts.py @@ -1,4 +1,4 @@ -from typing import List +from typing import List, Optional from fastapi import Depends, HTTPException from tortoise.exceptions import IntegrityError @@ -6,7 +6,7 @@ from api_server.exceptions import AlreadyExistsError, InvalidInputError, NotFoundError from api_server.fast_io import FastIORouter, SubscriptionRequest from api_server.gateway import rmf_gateway -from api_server.models import AlertRequest, AlertResponse +from api_server.models import AlertRequest, AlertResponse, Pagination from api_server.repositories import AlertRepository from api_server.rmf_io import alert_events @@ -107,9 +107,12 @@ async def get_alerts_of_task( @router.get("/unresponded_requests", response_model=List[AlertRequest]) -async def get_unresponded_alerts(repo: AlertRepository = Depends(AlertRepository)): +async def get_unresponded_alerts( + repo: AlertRepository = Depends(AlertRepository), + pagination: Optional[Pagination] = None, +): """ Returns the list of alert IDs that have yet to be responded to, while a response was required. """ - return await repo.get_unresponded_alerts() + return await repo.get_unresponded_alerts(pagination) diff --git a/packages/dashboard/src/components/alert-manager.tsx b/packages/dashboard/src/components/alert-manager.tsx index e0c851517..827de45d9 100644 --- a/packages/dashboard/src/components/alert-manager.tsx +++ b/packages/dashboard/src/components/alert-manager.tsx @@ -215,7 +215,6 @@ const AlertDialog = React.memo((props: AlertDialogProps) => { }} onClick={async () => { await respondToAlert(alertRequest.id, response); - AppEvents.refreshAlert.next(); setIsOpen(false); }} > @@ -297,7 +296,6 @@ export const AlertManager = React.memo(() => { [alertRequest.id]: alertRequest, }; }); - AppEvents.refreshAlert.next(); return; } }; @@ -305,20 +303,11 @@ export const AlertManager = React.memo(() => { const subs: Subscription[] = []; subs.push( - rmf.alertRequestsObsStore.subscribe( - async (alertRequest) => await pushAlertsToBeDisplayed(alertRequest), + rmf.alertRequestsObsStore.subscribe((alertRequest) => + AppEvents.alertListOpenedAlert.next(alertRequest), ), ); - subs.push( - AppEvents.alertListOpenedAlert.subscribe(async (alertRequest) => { - if (!alertRequest) { - return; - } - await pushAlertsToBeDisplayed(alertRequest); - }), - ); - subs.push( rmf.alertResponsesObsStore.subscribe((alertResponse) => { setOpenAlerts((prev) => { @@ -326,7 +315,15 @@ export const AlertManager = React.memo(() => { Object.entries(prev).filter(([key]) => key !== alertResponse.id), ); }); - AppEvents.refreshAlert.next(); + }), + ); + + subs.push( + AppEvents.alertListOpenedAlert.subscribe(async (alertRequest) => { + if (!alertRequest) { + return; + } + await pushAlertsToBeDisplayed(alertRequest); }), ); diff --git a/packages/dashboard/src/components/app-events.ts b/packages/dashboard/src/components/app-events.ts index fcfef220a..670b92836 100644 --- a/packages/dashboard/src/components/app-events.ts +++ b/packages/dashboard/src/components/app-events.ts @@ -13,7 +13,6 @@ export const AppEvents = { refreshTaskApp: new Subject(), refreshFavoriteTasks: new Subject(), refreshTaskSchedule: new Subject(), - refreshAlert: new Subject(), alertListOpenedAlert: new Subject(), disabledLayers: new ReplaySubject>(), zoom: new BehaviorSubject(null), diff --git a/packages/dashboard/src/components/appbar.tsx b/packages/dashboard/src/components/appbar.tsx index a257749e5..67dcb19ac 100644 --- a/packages/dashboard/src/components/appbar.tsx +++ b/packages/dashboard/src/components/appbar.tsx @@ -212,7 +212,8 @@ export const AppBar = React.memo(({ extraToolbarItems }: AppBarProps): React.Rea }; const subs: Subscription[] = []; - subs.push(AppEvents.refreshAlert.subscribe(updateUnrespondedAlerts)); + subs.push(rmf.alertRequestsObsStore.subscribe(updateUnrespondedAlerts)); + subs.push(rmf.alertResponsesObsStore.subscribe(updateUnrespondedAlerts)); // Get the initial number of unacknowledged alerts updateUnrespondedAlerts();