openapi-spec-reader (#10)
### Summary of Changes:
1. **Spec-Driven Enums**:
- Updated `openapi_loader.ts` to collect all standalone enum schemas (e.g., `FetchRequestStatus`) into the `AppConfig.enums` map.
- Implemented `mergeProperties` and `oneOf`/`anyOf` resolution in `openapi_loader.ts` to ensure complex schemas like `FetchRequest` (using `allOf`) and `source` (using `oneOf`) are correctly parsed.
2. **Customizable Labeling**:
- Added `enumOption` (template-based) and `enumLabels` (mapping-based) to the config and field types.
- Implemented `resolveTemplate` in `utils/options.ts` to handle placeholders like `'{name} {number}'` or plain field names.
3. **UI Integration**:
- **`FormField.tsx`**: Updated relation and enum selects to use `getFieldOptions()` for correct key/value pairs and labels. Added value normalization to extract keys from API objects.
- **`EnhancedTable.tsx`**: Updated `valueOptions` to use key/value pairs for `singleSelect` and updated `FieldRenderer` to show the human-readable label for enums.
- **`FilterBar.tsx`**: Updated `extractOptions` to use spec-driven labels for enum filters.
- **`ResourceView.tsx`**: Centralized filter matching logic into a `getDisplayString` helper, ensuring filter comparisons use the same templates as the UI labels.
4. **App Fixes**:
- `FetchRequests.tsx` and `FetchRequestDetail.tsx` now derive status and format options from the OpenAPI spec via `useConfig()` instead of using hardcoded arrays.
Reviewed-on: #10
Co-authored-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com>
Co-committed-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import { Box, Paper, CircularProgress } from '@mui/material';
|
||||
import { ResourceConfig } from '../types/config';
|
||||
import type { ResourceField } from '../types/config';
|
||||
import { useResource } from '../hooks/useResource';
|
||||
import { resolveTemplate } from '../utils/options';
|
||||
import GenericForm from './GenericForm';
|
||||
import EnhancedTable from './EnhancedTable';
|
||||
import FilterBar from './FilterBar';
|
||||
@@ -15,11 +16,16 @@ interface ResourceViewProps {
|
||||
|
||||
import { GridPaginationModel } from '@mui/x-data-grid';
|
||||
|
||||
function getFilterDisplayFields(field: ResourceField): string[] {
|
||||
if (!field.displayField) return [];
|
||||
return (Array.isArray(field.displayField) ? field.displayField : [field.displayField]).filter(
|
||||
(df): df is string => !!df
|
||||
);
|
||||
function getDisplayString(item: any, field: ResourceField): string {
|
||||
if (item == null || typeof item !== 'object') return String(item ?? '');
|
||||
if (field.enumOption?.value) return resolveTemplate(field.enumOption.value, item);
|
||||
const df = field.displayField;
|
||||
if (!df) return item.name ?? item.title ?? item.label ?? item.id ?? JSON.stringify(item);
|
||||
if (Array.isArray(df)) {
|
||||
const parts = df.map((k: string) => item[k]).filter((v: any) => v != null);
|
||||
return parts.length > 0 ? parts.join(' ') : '';
|
||||
}
|
||||
return String(item[df] ?? '');
|
||||
}
|
||||
|
||||
function applyClientFilters(
|
||||
@@ -59,18 +65,12 @@ function applyClientFilters(
|
||||
|
||||
if (Array.isArray(filterValue)) {
|
||||
if (field.type === "array" && Array.isArray(itemValue)) {
|
||||
return itemValue.some((el: any) => {
|
||||
if (el != null && typeof el === "object") {
|
||||
const dispFields = getFilterDisplayFields(field);
|
||||
return dispFields.some((df) => filterValue.includes(String(el[df])));
|
||||
}
|
||||
return filterValue.includes(String(el));
|
||||
});
|
||||
return itemValue.some((el: any) =>
|
||||
filterValue.includes(getDisplayString(el, field))
|
||||
);
|
||||
}
|
||||
if (itemValue && typeof itemValue === "object") {
|
||||
const dispFields = getFilterDisplayFields(field);
|
||||
const itemDisplay = dispFields.map((df) => itemValue[df]).filter((v) => v != null).join(" ");
|
||||
return filterValue.includes(itemDisplay);
|
||||
return filterValue.includes(getDisplayString(itemValue, field));
|
||||
}
|
||||
return filterValue.includes(String(itemValue));
|
||||
}
|
||||
@@ -82,18 +82,13 @@ function applyClientFilters(
|
||||
}
|
||||
|
||||
if (field.type === "array" && Array.isArray(itemValue)) {
|
||||
return itemValue.some((el: any) => {
|
||||
if (el != null && typeof el === "object") {
|
||||
const dispFields = getFilterDisplayFields(field);
|
||||
return dispFields.some((df) => String(el[df]) === String(filterValue));
|
||||
}
|
||||
return String(el) === String(filterValue);
|
||||
});
|
||||
return itemValue.some((el: any) =>
|
||||
getDisplayString(el, field) === String(filterValue)
|
||||
);
|
||||
}
|
||||
|
||||
if (itemValue && typeof itemValue === "object") {
|
||||
const dispFields = getFilterDisplayFields(field);
|
||||
return dispFields.some((df) => String(itemValue[df]) === String(filterValue));
|
||||
return getDisplayString(itemValue, field) === String(filterValue);
|
||||
}
|
||||
|
||||
return String(itemValue) === String(filterValue);
|
||||
|
||||
Reference in New Issue
Block a user