updated sse supporting react-openapi

This commit is contained in:
2026-06-18 20:32:34 +05:30
parent 0a668cf98d
commit 154b15fe51
28 changed files with 2132 additions and 440 deletions

View File

@@ -47,8 +47,9 @@ import type {
} from "./features/fetch-requests";
import { RETRY_MAX, formatApiError } from "./features/fetch-requests";
import { useNavigate } from "react-router-dom";
import { useResourceByName, useConfig, defaultFieldComponents } from "../react-openapi";
import type { ResourceField } from "../react-openapi";
import { useAppContext, useResource, FormFieldRenderer } from "../react-openapi";
import type { FieldConfig } from "../react-openapi";
import { useMutation, useQuery } from "@tanstack/react-query";
const statusColors: Record<FetchRequestStatus, "default" | "primary" | "warning" | "info" | "success" | "error"> = {
pending: "default",
@@ -70,6 +71,16 @@ const statusIcons: Record<FetchRequestStatus, React.ReactNode> = {
failed: <ErrorIcon sx={{ fontSize: 16, color: "error.main" }} />,
};
const STATUS_OPTIONS: FetchRequestStatus[] = [
"pending",
"processing",
"paused",
"raw_expenses_done",
"enriched_done",
"completed",
"failed",
];
function formatDate(iso: string) {
const d = new Date(iso);
return d.toLocaleString();
@@ -107,33 +118,48 @@ export default function FetchRequests() {
const [accountFilter, setAccountFilter] = React.useState("");
const [sourceFilter, setSourceFilter] = React.useState<"all" | "file" | "email">("all");
const { useList, useCreate, usePatch, useDelete, components } = useResourceByName("fetch-requests", { fieldComponents: defaultFieldComponents });
const { data: listData, isLoading, isFetching, refetch } = useList({
...(statusFilter.length > 0 ? { status: statusFilter.join(",") } : {}),
...(accountFilter ? { account_name: accountFilter } : {}),
...(sourceFilter !== "all" ? { source_type: sourceFilter } : {}),
const { resources } = useAppContext();
const fetchRequestsRes = resources.find(r => r.name === "fetch-requests")!;
const { list, create, update, remove } = useResource(fetchRequestsRes);
const { data: listData, isLoading, isFetching, refetch } = useQuery({
queryKey: ["fetch-requests", "list", { statusFilter, accountFilter, sourceFilter }],
queryFn: () => list({
...(statusFilter.length > 0 ? { status: statusFilter.join(",") } : {}),
...(accountFilter ? { account_name: accountFilter } : {}),
...(sourceFilter !== "all" ? { source_type: sourceFilter } : {}),
}),
});
const { useList: useAccountsList } = useResourceByName("accounts");
const { data: accountsData } = useAccountsList();
const accountsResource = resources.find(r => r.name === "accounts");
const { list: listAccounts } = accountsResource ? useResource(accountsResource) : { list: async () => ({ items: [] }) };
const { data: accountsData } = useQuery({
queryKey: ["accounts", "list"],
queryFn: () => listAccounts(),
enabled: !!accountsResource,
});
const accountOptions: string[] = React.useMemo(() => {
return (accountsData?.data ?? []).map((a: any) => a.name).filter(Boolean);
return (accountsData?.items ?? []).map((a: any) => a.name).filter(Boolean);
}, [accountsData]);
const config = useConfig();
const fetchRes = config?.resources.find((r: any) => r.name === "fetch-requests");
const formatField: ResourceField | undefined = fetchRes?.fields?.source?.schema?.format;
const formatOptions: string[] = formatField?.options ?? [];
const startDateField: ResourceField | undefined = fetchRes?.fields?.start_date;
const endDateField: ResourceField | undefined = fetchRes?.fields?.end_date;
const payorUsernameField: ResourceField | undefined = fetchRes?.fields?.payor_username;
const formatField: FieldConfig | undefined = fetchRequestsRes?.orderedFields.find(f => f.name === "format");
const formatOptions: string[] = formatField?.enumValues ?? [];
const startDateField: FieldConfig | undefined = fetchRequestsRes?.orderedFields.find(f => f.name === "start_date");
const endDateField: FieldConfig | undefined = fetchRequestsRes?.orderedFields.find(f => f.name === "end_date");
const payorUsernameField: FieldConfig | undefined = fetchRequestsRes?.orderedFields.find(f => f.name === "payor_username");
const createMutation = useCreate();
const updateMutation = usePatch();
const deleteMutation = useDelete();
const createMutation = useMutation({
mutationFn: (data: any) => create(data),
});
const updateMutation = useMutation({
mutationFn: ({ id, data }: { id: string; data: any }) => update(id, data),
});
const deleteMutation = useMutation({
mutationFn: (id: string) => remove(id),
});
const uploadMutation = useUploadFile();
const requests = listData?.data ?? [];
const requests = listData?.items ?? [];
const handleUpload = async () => {
if (!file) return;
@@ -262,9 +288,8 @@ export default function FetchRequests() {
Uploaded as: {uploadedPath}
</Alert>
)}
{formatField && components?.FormField ? (
<components.FormField
name="format"
{formatField ? (
<FormFieldRenderer
field={formatField}
value={format}
onChange={setFormat}
@@ -282,9 +307,8 @@ export default function FetchRequests() {
</>
) : (
<>
{formatField && components?.FormField ? (
<components.FormField
name="format"
{formatField ? (
<FormFieldRenderer
field={formatField}
value={format}
onChange={setFormat}
@@ -314,9 +338,8 @@ export default function FetchRequests() {
)}
sx={{ "& .MuiOutlinedInput-root": { height: "auto", minHeight: "2.5rem" } }}
/>
{payorUsernameField && components?.FormField ? (
<components.FormField
name="payor_username"
{payorUsernameField ? (
<FormFieldRenderer
field={payorUsernameField}
value={payorUsername}
onChange={setPayorUsername}
@@ -326,10 +349,9 @@ export default function FetchRequests() {
)}
<Box sx={{ display: "flex", gap: 2 }}>
{startDateField && components?.date ? (
{startDateField ? (
<Box sx={{ flex: 1 }}>
<components.date
name="start_date"
<FormFieldRenderer
field={startDateField}
value={startDate}
onChange={setStartDate}
@@ -347,10 +369,9 @@ export default function FetchRequests() {
sx={{ flex: 1 }}
/>
)}
{endDateField && components?.date ? (
{endDateField ? (
<Box sx={{ flex: 1 }}>
<components.date
name="end_date"
<FormFieldRenderer
field={endDateField}
value={endDate}
onChange={setEndDate}
@@ -391,7 +412,7 @@ export default function FetchRequests() {
input={<OutlinedInput label="Status" />}
renderValue={(selected) => (selected as string[]).join(", ")}
>
{(config?.enums?.FetchRequestStatus ?? []).map((s: string) => (
{STATUS_OPTIONS.map((s: string) => (
<MenuItem key={s} value={s}>{s.replace(/_/g, " ")}</MenuItem>
))}
</Select>