Minor refactoring of schema provider

This commit is contained in:
2025-05-13 16:22:58 +02:00
parent 7aced9477c
commit 9aac1d3e34

View File

@@ -78,6 +78,18 @@ export const jsonschemaProvider = {
} }
} }
const getResourceSchema = async (resourceName: string): Promise<CrudRJSFSchema> => {
return buildResource(await getJsonschema(), resourceName)
}
const getColumns = async (resourceName: string): Promise<GridColDef[]> => {
return buildColumns(await getJsonschema(), resourceName)
}
const getFilters = async (resourceName: string, resourcePath: string): Promise<FilterField[]> => {
return buildFilters(await getJsonschema(), resourceName, resourcePath);
}
type PathParameter = { type PathParameter = {
in: string, in: string,
name:string name:string
@@ -87,10 +99,6 @@ type PathSchema = {
parameters: PathParameter[] parameters: PathParameter[]
} }
function shortenResourceName(resourceName: string) {
return convertCamelToSnake(resourceName.replace(/(-Input|-Output|Create|Update|Read)$/g, ""));
}
type FilterField = { type FilterField = {
name: string, name: string,
label: string, label: string,
@@ -98,6 +106,11 @@ type FilterField = {
operators: { name: string, label: string }[] operators: { name: string, label: string }[]
} }
type Operator = {
operator: string,
fieldName: string,
}
async function hasSearch(resourcePath: string): Promise<boolean> { async function hasSearch(resourcePath: string): Promise<boolean> {
const jst = new JsonSchemaTraverser(await getJsonschema()); const jst = new JsonSchemaTraverser(await getJsonschema());
const pathSchema = jst.getPath(resourcePath); const pathSchema = jst.getPath(resourcePath);
@@ -110,9 +123,9 @@ async function hasSearch(resourcePath: string): Promise<boolean> {
return false return false
} }
async function getFilters(resourceName: string, resourcePath: string): Promise<FilterField[]> { function buildFilters(rawSchema: RJSFSchema, resourceName: string, resourcePath: string): FilterField[] {
const shortResourceName = shortenResourceName(resourceName); const shortResourceName = shortenResourceName(resourceName);
const jst = new JsonSchemaTraverser(await getJsonschema()); const jst = new JsonSchemaTraverser(rawSchema);
const pathSchema = jst.getPath(resourcePath); const pathSchema = jst.getPath(resourcePath);
const seen: { [k: string]: number } = {}; const seen: { [k: string]: number } = {};
@@ -125,8 +138,8 @@ async function getFilters(resourceName: string, resourcePath: string): Promise<F
const field = jst.getPropertyByPath(jst.getResource(`${resourceName}Read`), fieldName) const field = jst.getPropertyByPath(jst.getResource(`${resourceName}Read`), fieldName)
filters.push({ filters.push({
name: fieldName, name: fieldName,
label: i18n.t(`schemas.${shortResourceName}.${convertCamelToSnake(fieldName)}`), label: getPropertyI18nLabel(shortResourceName, fieldName),
type: getFieldType(fieldName, field), type: getFieldFilterType(fieldName, field),
operators: [{ name: operator, label: operator }] operators: [{ name: operator, label: operator }]
}); });
} else { } else {
@@ -139,12 +152,6 @@ async function getFilters(resourceName: string, resourcePath: string): Promise<F
return filters; return filters;
} }
type Operator = {
operator: string,
fieldName: string,
}
function processParamName(param: PathParameter): Operator { function processParamName(param: PathParameter): Operator {
const nameParts = param.name.split("__") const nameParts = param.name.split("__")
@@ -154,7 +161,7 @@ function processParamName(param: PathParameter): Operator {
} }
} }
const getFieldType = (fieldName: string, field: RJSFSchema): string => { const getFieldFilterType = (fieldName: string, field: RJSFSchema): string => {
if (fieldName == "created_by" || fieldName == "updated_by") { if (fieldName == "created_by" || fieldName == "updated_by") {
return "author"; return "author";
} else if (Array.isArray(field)) { } else if (Array.isArray(field)) {
@@ -180,17 +187,11 @@ const getFieldType = (fieldName: string, field: RJSFSchema): string => {
throw "Unimplemented field type" throw "Unimplemented field type"
} }
const getColumns = async (resourceName: string): Promise<GridColDef[]> => {
return buildColumns(await getJsonschema(), resourceName)
}
function buildColumns (rawSchemas: RJSFSchema, resourceName: string, prefix: string|undefined = undefined): GridColDef[] { function buildColumns (rawSchemas: RJSFSchema, resourceName: string, prefix: string|undefined = undefined): GridColDef[] {
if (rawSchemas.components.schemas[resourceName] === undefined) { const shortResourceName = shortenResourceName(resourceName);
throw new Error(`Resource "${resourceName}" not found in schema.`); const jst = new JsonSchemaTraverser(rawSchemas);
} let resource = structuredClone(jst.getResource(resourceName));
const shortResourceName = convertCamelToSnake(resourceName.replace(/(-Input|-Output|Create|Update|Read)$/g, ""));
let resource = rawSchemas.components.schemas[resourceName];
let result: GridColDef[] = []; let result: GridColDef[] = [];
for (const prop_name in resource.properties) { for (const prop_name in resource.properties) {
let prop = resource.properties[prop_name]; let prop = resource.properties[prop_name];
@@ -264,42 +265,32 @@ function buildColumns (rawSchemas: RJSFSchema, resourceName: string, prefix: str
return result; return result;
} }
const getResourceSchema = async (resourceName: string): Promise<CrudRJSFSchema> => {
return buildResource(await getJsonschema(), resourceName)
}
function convertCamelToSnake(str: string): string {
return str.replace(/([a-zA-Z])(?=[A-Z])/g,'$1_').toLowerCase()
}
function buildResource(rawSchemas: RJSFSchema, resourceName: string) { function buildResource(rawSchemas: RJSFSchema, resourceName: string) {
if (rawSchemas.components.schemas[resourceName] === undefined) { const shortResourceName = shortenResourceName(resourceName);
throw new Error(`Resource "${resourceName}" not found in schema.`); const jst = new JsonSchemaTraverser(rawSchemas);
} let resource = structuredClone(jst.getResource(resourceName));
const shortResourceName = convertCamelToSnake(resourceName.replace(/(-Input|-Output|Create|Update|Read)$/g, ""));
let resource = structuredClone(rawSchemas.components.schemas[resourceName]);
resource.components = { schemas: {} }; resource.components = { schemas: {} };
for (let prop_name in resource.properties) { for (let prop_name in resource.properties) {
let prop = resource.properties[prop_name]; let prop = resource.properties[prop_name];
if (is_reference(prop)) { if (is_reference(prop)) {
resolveReference(rawSchemas, resource, prop); buildReference(rawSchemas, resource, prop);
} else if (is_union(prop)) { } else if (is_union(prop)) {
const union = prop.hasOwnProperty("oneOf") ? prop.oneOf : prop.anyOf; const union = prop.hasOwnProperty("oneOf") ? prop.oneOf : prop.anyOf;
for (let i in union) { for (let i in union) {
if (is_reference(union[i])) { if (is_reference(union[i])) {
resolveReference(rawSchemas, resource, union[i]); buildReference(rawSchemas, resource, union[i]);
} }
} }
} else if (is_enum(prop)) { } else if (is_enum(prop)) {
for (let i in prop.allOf) { for (let i in prop.allOf) {
if (is_reference(prop.allOf[i])) { if (is_reference(prop.allOf[i])) {
resolveReference(rawSchemas, resource, prop.allOf[i]); buildReference(rawSchemas, resource, prop.allOf[i]);
} }
} }
} else if (is_array(prop) && is_reference(prop.items)) { } else if (is_array(prop) && is_reference(prop.items)) {
resolveReference(rawSchemas, resource, prop.items); buildReference(rawSchemas, resource, prop.items);
} }
if (prop.hasOwnProperty("title")) { if (prop.hasOwnProperty("title")) {
@@ -313,16 +304,7 @@ function buildResource(rawSchemas: RJSFSchema, resourceName: string) {
return resource; return resource;
} }
let rawSchema: RJSFSchema; function buildReference(rawSchemas: RJSFSchema, resource: any, prop_reference: any) {
const getJsonschema = async (): Promise<RJSFSchema> => {
if (rawSchema === undefined) {
const response = await fetch(`${API_URL}/openapi.json`,);
rawSchema = await response.json();
}
return rawSchema;
}
function resolveReference(rawSchemas: RJSFSchema, resource: any, prop_reference: any) {
const subresourceName = get_reference_name(prop_reference); const subresourceName = get_reference_name(prop_reference);
const subresource = buildResource(rawSchemas, subresourceName); const subresource = buildResource(rawSchemas, subresourceName);
resource.components.schemas[subresourceName] = subresource; resource.components.schemas[subresourceName] = subresource;
@@ -391,6 +373,31 @@ function get_reference_name(prop: any) {
return prop['$ref'].substring(prop['$ref'].lastIndexOf('/')+1); return prop['$ref'].substring(prop['$ref'].lastIndexOf('/')+1);
} }
function convertCamelToSnake(str: string): string {
return str.replace(/([a-zA-Z])(?=[A-Z])/g,'$1_').toLowerCase()
}
function shortenResourceName(resourceName: string) {
return convertCamelToSnake(resourceName.replace(/(-Input|-Output|Create|Update|Read)$/g, ""));
}
function getPropertyI18nLabel(shortResourceName: string, fieldName: string): string {
if (meta_fields.indexOf(fieldName) > -1) {
return i18n.t(`schemas.${convertCamelToSnake(fieldName)}`);
}
const path = `schemas.${shortResourceName}.${convertCamelToSnake(fieldName)}`
return i18n.t(path)
}
let rawSchema: RJSFSchema;
const getJsonschema = async (): Promise<RJSFSchema> => {
if (rawSchema === undefined) {
const response = await fetch(`${API_URL}/openapi.json`,);
rawSchema = await response.json();
}
return rawSchema;
}
const JsonSchemaTraverser = class { const JsonSchemaTraverser = class {
private rawSchemas: RJSFSchema; private rawSchemas: RJSFSchema;