From 537aef94ff04ac5c17c677fd24420fe7b9fb2797 Mon Sep 17 00:00:00 2001 From: Vishesh 'ironeagle' Bangotra Date: Tue, 18 Aug 2026 13:01:55 +0530 Subject: [PATCH] resolve relative media URLs against the API base in react-openapi - add resolveMediaUrl() in fields/utils.ts: prefixes /uploads/... and other relative paths with the configured baseApiUrl, leaves absolute http/data/blob URLs untouched - use it for every image render: ListCellRenderer, DetailFieldRenderer, ImageField form preview, and FileUploadField preview/href (which hardcoded /uploads/) - drop the Expense-side resolveLogoUrl hack and logo pre-normalization; the Expenses page now renders logos through the same react-openapi path as the admin entity list --- .../src/components/fields/DetailFieldRenderer.tsx | 5 ++++- .../src/components/fields/ListCellRenderer.tsx | 6 +++--- .../components/fields/renderers/FileUploadField.tsx | 7 +++++-- .../src/components/fields/renderers/ImageField.tsx | 5 ++++- react-openapi/src/components/fields/utils.ts | 12 ++++++++++++ src/Expense/Expense.tsx | 13 ++----------- src/Expense/types.ts | 7 ------- 7 files changed, 30 insertions(+), 25 deletions(-) diff --git a/react-openapi/src/components/fields/DetailFieldRenderer.tsx b/react-openapi/src/components/fields/DetailFieldRenderer.tsx index d21d583..423981e 100644 --- a/react-openapi/src/components/fields/DetailFieldRenderer.tsx +++ b/react-openapi/src/components/fields/DetailFieldRenderer.tsx @@ -3,6 +3,8 @@ import { Box, Typography, Avatar } from "@mui/material"; import type { FieldConfig } from "../../types"; import { ListCellRenderer } from "./ListCellRenderer"; import { CurrencyField } from "./renderers/CurrencyField"; +import { resolveMediaUrl } from "./utils"; +import { useAppContext } from "../../context/AppContext"; interface DetailFieldProps { field: FieldConfig; @@ -12,6 +14,7 @@ interface DetailFieldProps { } export function DetailFieldRenderer({ field, value, displayFormat, basePath }: DetailFieldProps) { + const { config } = useAppContext(); if (field.hidden?.detail) return null; return ( @@ -22,7 +25,7 @@ export function DetailFieldRenderer({ field, value, displayFormat, basePath }: D {field.uiType === "currency" ? ( ) : field.uiType === "image" ? ( - + ) : ( )} diff --git a/react-openapi/src/components/fields/ListCellRenderer.tsx b/react-openapi/src/components/fields/ListCellRenderer.tsx index df08350..598dd16 100644 --- a/react-openapi/src/components/fields/ListCellRenderer.tsx +++ b/react-openapi/src/components/fields/ListCellRenderer.tsx @@ -2,7 +2,7 @@ import React, { useState } from "react"; import { useNavigate } from "react-router-dom"; import { Box, Typography, Chip, Avatar, Dialog, DialogTitle, DialogContent, DialogActions, Button, Grid } from "@mui/material"; import type { FieldConfig } from "../../types"; -import { applyDisplayFormat } from "./utils"; +import { applyDisplayFormat, resolveMediaUrl } from "./utils"; import { InlineRefField } from "./renderers/InlineRefField"; import { CurrencyField } from "./renderers/CurrencyField"; import { extractFields } from "../../transformers/field-config"; @@ -17,7 +17,7 @@ interface ListCellProps { export function ListCellRenderer({ field, value, displayFormat, basePath }: ListCellProps) { const navigate = useNavigate(); - const { schemas } = useAppContext(); + const { schemas, config } = useAppContext(); const [inlineItem, setInlineItem] = useState(null); if (value === null || value === undefined) { @@ -138,7 +138,7 @@ export function ListCellRenderer({ field, value, displayFormat, basePath }: List } if (field.uiType === "image" && value) { - return ; + return ; } if (field.uiType === "currency" && value != null && !Number.isNaN(Number(value))) { diff --git a/react-openapi/src/components/fields/renderers/FileUploadField.tsx b/react-openapi/src/components/fields/renderers/FileUploadField.tsx index 1bfc338..803b9ca 100644 --- a/react-openapi/src/components/fields/renderers/FileUploadField.tsx +++ b/react-openapi/src/components/fields/renderers/FileUploadField.tsx @@ -2,6 +2,8 @@ import React from "react"; import { Box, Typography, Avatar, Chip, Button, FormHelperText } from "@mui/material"; import type { FieldConfig } from "../../../types"; import { getApi } from "../../../hooks/useApi"; +import { useAppContext } from "../../../context/AppContext"; +import { resolveMediaUrl } from "../utils"; interface Props { field: FieldConfig; @@ -19,6 +21,7 @@ const acceptMap: Record = { export function FileUploadField({ field, value, onChange }: Props) { const uploadConfig = field.upload!; const inputRef = React.useRef(null); + const { config } = useAppContext(); const handleUpload = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; @@ -51,12 +54,12 @@ export function FileUploadField({ field, value, onChange }: Props) { {value ? ( uploadConfig.type === "image" ? ( - + ) : ( diff --git a/react-openapi/src/components/fields/renderers/ImageField.tsx b/react-openapi/src/components/fields/renderers/ImageField.tsx index 0292ba0..0f8cb52 100644 --- a/react-openapi/src/components/fields/renderers/ImageField.tsx +++ b/react-openapi/src/components/fields/renderers/ImageField.tsx @@ -3,6 +3,8 @@ import { Box, Typography, Avatar, FormHelperText } from "@mui/material"; import Button from "@mui/material/Button"; import type { FieldConfig } from "../../../types"; import { getApi } from "../../../hooks/useApi"; +import { useAppContext } from "../../../context/AppContext"; +import { resolveMediaUrl } from "../utils"; interface Props { field: FieldConfig; @@ -13,6 +15,7 @@ interface Props { } export function ImageField({ field, value, onChange, id, uploadUrl }: Props) { + const { config } = useAppContext(); const handleUpload = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; @@ -47,7 +50,7 @@ export function ImageField({ field, value, onChange, id, uploadUrl }: Props) { {field.label} {value ? ( - + ) : (