mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 16:35:42 +00:00
feat: add pagination to schedule history and consolidation approvals
- Implemented pagination in ScheduleHistoryPanel to manage large history entries. - Updated API to support pagination parameters for schedule history. - Enhanced ConsolidationApprovalsPage with tabbed navigation and pagination for approval rows. - Introduced new types for paginated responses in bookings and train scheduling services. - Added a database migration to create an index on wagon_booking_allocations for performance improvements.
This commit is contained in:
@@ -147,13 +147,36 @@ export default function TrainScheduleV2DetailPage() {
|
||||
input: { id: scheduleId ?? "" },
|
||||
enabled: Boolean(scheduleId),
|
||||
// Live phase updates come from the booking-window socket (PHASE pushes
|
||||
// invalidate this query); 60s is the self-heal net for a missed emit so
|
||||
// the workspace countdown never freezes on an expired phase.
|
||||
// invalidate this query). The fast self-heal net is the one-row phase
|
||||
// heartbeat below — this long interval is only the last-resort refresh
|
||||
// for changes the schedule row itself never sees.
|
||||
refetchInterval: 300_000,
|
||||
}),
|
||||
);
|
||||
// One-row 60s heartbeat: refetch the (expensive) full detail only when the
|
||||
// schedule row actually changed — same freshness as polling the detail
|
||||
// itself, at a fraction of the server cost.
|
||||
const phaseQuery = useQuery(
|
||||
api.trainScheduling.schedulePhase.queryOptions({
|
||||
input: { id: scheduleId ?? "" },
|
||||
enabled: Boolean(scheduleId),
|
||||
refetchInterval: 60_000,
|
||||
}),
|
||||
);
|
||||
const lastPhaseSig = useRef<string | null>(null);
|
||||
useEffect(() => {
|
||||
if (!phaseQuery.data) return;
|
||||
const sig = JSON.stringify(phaseQuery.data);
|
||||
if (lastPhaseSig.current !== null && lastPhaseSig.current !== sig) {
|
||||
void detailQuery.refetch();
|
||||
}
|
||||
lastPhaseSig.current = sig;
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [phaseQuery.data]);
|
||||
useBookingWindowSocket(Boolean(scheduleId));
|
||||
const schedule = detailQuery.data;
|
||||
// Controlled so tab-scoped queries (eligible pool) pause on other tabs.
|
||||
const [activeTab, setActiveTab] = useState<string | null>("workflow");
|
||||
const freightType: FreightType | undefined = schedule?.freightType as FreightType | undefined;
|
||||
const isDjiboutiPort = (value?: string | null) =>
|
||||
["DJIBOUTI", "DORALEH", "DMP", "DCT", "NAGAD"].some((token) =>
|
||||
@@ -221,7 +244,9 @@ export default function TrainScheduleV2DetailPage() {
|
||||
const eligibleQuery = useQuery(
|
||||
api.trainScheduling.eligibleBookings.queryOptions({
|
||||
input: { filters: eligibleFilters, freightType: eligibleFreightType },
|
||||
enabled: Boolean(schedule),
|
||||
// The eligible pool feeds the Workflow tab's bookings step only — don't
|
||||
// fetch (or refetch on invalidation) while another tab is open.
|
||||
enabled: Boolean(schedule) && activeTab === "workflow",
|
||||
}),
|
||||
);
|
||||
const preview = useMutation(api.trainScheduling.preview.mutationOptions());
|
||||
@@ -1276,7 +1301,13 @@ export default function TrainScheduleV2DetailPage() {
|
||||
) : null}
|
||||
*/}
|
||||
|
||||
<Tabs defaultValue="workflow" radius="md" color="edr-green" keepMounted={false}>
|
||||
<Tabs
|
||||
value={activeTab}
|
||||
onChange={setActiveTab}
|
||||
radius="md"
|
||||
color="edr-green"
|
||||
keepMounted={false}
|
||||
>
|
||||
<Tabs.List mb="md">
|
||||
<Tabs.Tab value="workflow" leftSection={<WorkflowIcon size={16} />}>
|
||||
Workflow
|
||||
|
||||
Reference in New Issue
Block a user