diff --git a/packages/rmf-dashboard-framework/src/components/tasks/task-schedule-utils.test.ts b/packages/rmf-dashboard-framework/src/components/tasks/task-schedule-utils.test.ts
index f4da64a31..1ec6e0735 100644
--- a/packages/rmf-dashboard-framework/src/components/tasks/task-schedule-utils.test.ts
+++ b/packages/rmf-dashboard-framework/src/components/tasks/task-schedule-utils.test.ts
@@ -1,13 +1,12 @@
import { Period, ScheduledTask, ScheduledTaskScheduleOutput } from 'api-client';
import { addMinutes, endOfDay, endOfMinute, startOfDay } from 'date-fns';
-import { describe, expect, it, vi } from 'vitest';
+import { describe, expect, it } from 'vitest';
import { RecurringDays } from './task-form';
import {
apiScheduleToSchedule,
scheduleToEvents,
scheduleWithSelectedDay,
- toISOStringWithTimezone,
} from './task-schedule-utils';
import { makeTaskRequest } from './test-data.test';
@@ -482,18 +481,3 @@ describe('apiScheduleToSchedule', () => {
expect(result.at).toEqual(new Date());
});
});
-
-describe('toISOStringWithTimezone', () => {
- it('should format date with positive timezone offset', () => {
- const date = new Date('2023-10-27T01:00:00.000Z'); // UTC
- const expectedOffset = '+08:00'; // Example: Singapore Time (UTC+8)
-
- // Mock the timezone offset of the date object.
- const spy = vi.spyOn(date, 'getTimezoneOffset').mockImplementation(() => -480); // -480 minutes = +08:00 hours
-
- const result = toISOStringWithTimezone(date);
- expect(result).toContain(expectedOffset);
- expect(result).toEqual('2023-10-27T09:00:00+08:00');
- spy.mockRestore();
- });
-});
diff --git a/packages/rmf-dashboard-framework/src/components/tasks/tasks-window.test.tsx b/packages/rmf-dashboard-framework/src/components/tasks/tasks-window.test.tsx
new file mode 100644
index 000000000..c479a28ff
--- /dev/null
+++ b/packages/rmf-dashboard-framework/src/components/tasks/tasks-window.test.tsx
@@ -0,0 +1,48 @@
+import { fireEvent, screen } from '@testing-library/react';
+import React, { act } from 'react';
+import { describe, expect, it, vi } from 'vitest';
+
+import { RmfApiProvider } from '../../hooks';
+import { MockRmfApi, render, TestProviders } from '../../utils/test-utils.test';
+import { AppEvents } from '../app-events';
+import { TasksWindow } from './tasks-window';
+
+vi.mock('../app-events', () => ({
+ AppEvents: {
+ refreshTaskApp: {
+ subscribe: vi.fn(() => ({ unsubscribe: vi.fn() })),
+ next: vi.fn(),
+ },
+ },
+}));
+
+describe('Tasks window', () => {
+ const rmfApi = new MockRmfApi();
+ rmfApi.tasksApi.queryTaskStatesTasksGet = vi.fn().mockResolvedValue({ data: [] });
+
+ const Base = (props: React.PropsWithChildren<{}>) => {
+ return (
+
+ {props.children}
+
+ );
+ };
+
+ it('renders without crashing', () => {
+ const root = render(
+
+
+ ,
+ );
+ expect(root.getByText('Tasks')).toBeTruthy();
+ });
+
+ it('triggers task refresh when Refresh button is clicked', () => {
+ render( {}} />);
+ const refreshButton = screen.getByTestId('refresh-button');
+ act(() => {
+ fireEvent.click(refreshButton);
+ });
+ expect(AppEvents.refreshTaskApp.next).toHaveBeenCalled();
+ });
+});
diff --git a/packages/rmf-dashboard-framework/src/components/tasks/tasks-window.tsx b/packages/rmf-dashboard-framework/src/components/tasks/tasks-window.tsx
index bd697f144..5f18e609a 100644
--- a/packages/rmf-dashboard-framework/src/components/tasks/tasks-window.tsx
+++ b/packages/rmf-dashboard-framework/src/components/tasks/tasks-window.tsx
@@ -33,7 +33,7 @@ import { exportCsvFull, exportCsvMinimal } from './utils';
const RefreshTaskQueueTableInterval = 15000;
const QueryLimit = 100;
-enum TaskTablePanel {
+export enum TaskTablePanel {
QueueTable = 0,
Schedule = 1,
}
@@ -182,35 +182,43 @@ export const TasksWindow = React.memo(
labelFilter = `${filterColumn.substring(6)}=${filterValue}`;
}
- const resp = await rmfApi.tasksApi.queryTaskStatesTasksGet(
- filterColumn && filterColumn === 'id_' ? filterValue : undefined,
- filterColumn && filterColumn === 'category' ? filterValue : undefined,
- filterColumn && filterColumn === 'requester' ? filterValue : undefined,
- filterColumn && filterColumn === 'assigned_to' ? filterValue : undefined,
- filterColumn && filterColumn === 'status' ? filterValue : undefined,
- labelFilter,
- filterColumn && filterColumn === 'unix_millis_request_time' ? filterValue : undefined,
- filterColumn && filterColumn === 'unix_millis_start_time' ? filterValue : undefined,
- filterColumn && filterColumn === 'unix_millis_finish_time' ? filterValue : undefined,
- GET_LIMIT,
- (tasksState.page - 1) * GET_LIMIT, // Datagrid component need to start in page 1. Otherwise works wrong
- orderBy,
- undefined,
- );
- const results = resp.data as TaskState[];
- const newTasks = results.slice(0, GET_LIMIT);
+ try {
+ const resp = await rmfApi.tasksApi.queryTaskStatesTasksGet(
+ filterColumn && filterColumn === 'id_' ? filterValue : undefined,
+ filterColumn && filterColumn === 'category' ? filterValue : undefined,
+ filterColumn && filterColumn === 'requester' ? filterValue : undefined,
+ filterColumn && filterColumn === 'assigned_to' ? filterValue : undefined,
+ filterColumn && filterColumn === 'status' ? filterValue : undefined,
+ labelFilter,
+ filterColumn && filterColumn === 'unix_millis_request_time' ? filterValue : undefined,
+ filterColumn && filterColumn === 'unix_millis_start_time' ? filterValue : undefined,
+ filterColumn && filterColumn === 'unix_millis_finish_time' ? filterValue : undefined,
+ GET_LIMIT,
+ (tasksState.page - 1) * GET_LIMIT, // Datagrid component need to start in page 1. Otherwise works wrong
+ orderBy,
+ undefined,
+ );
+ const results = resp.data as TaskState[];
+ const newTasks = results.slice(0, GET_LIMIT);
- setTasksState((old) => ({
- ...old,
- isLoading: false,
- data: newTasks,
- total:
- results.length === GET_LIMIT
- ? tasksState.page * GET_LIMIT + 1
- : tasksState.page * GET_LIMIT - 9,
- }));
+ setTasksState((old) => ({
+ ...old,
+ isLoading: false,
+ data: newTasks,
+ total:
+ results.length === GET_LIMIT
+ ? tasksState.page * GET_LIMIT + 1
+ : tasksState.page * GET_LIMIT - 9,
+ }));
+ } catch (e) {
+ appController.showAlert(
+ 'error',
+ `Failed to query task states: ${(e as Error).message}`,
+ );
+ }
})();
}, [
+ appController,
rmfApi,
refreshTaskAppCount,
tasksState.page,
@@ -340,6 +348,7 @@ export const TasksWindow = React.memo(