mirror of
https://github.com/bknd-io/bknd/
synced 2026-08-02 08:06:00 +00:00
7d89fe4894
Added optional `fields_order` to the entity configuration schema, allowing for custom field sorting. Updated `getFields` method to support sorting based on this configuration. Adjusted related methods and UI components to handle field order during updates and serialization. Improved handling of virtual fields in various contexts.
148 lines
4.7 KiB
TypeScript
148 lines
4.7 KiB
TypeScript
import { constructEntity } from "data/schema/constructor";
|
|
import {
|
|
type TAppDataEntity,
|
|
type TAppDataEntityFields,
|
|
type TAppDataField,
|
|
type TAppDataRelation,
|
|
entitiesSchema,
|
|
entityFields,
|
|
fieldsSchema,
|
|
relationsSchema,
|
|
} from "data/data-schema";
|
|
import { useBknd } from "ui/client/bknd";
|
|
import type { TSchemaActions } from "ui/client/schema/actions";
|
|
import { bkndModals } from "ui/modals";
|
|
import { s, parse, InvalidSchemaError, transformObject } from "bknd/utils";
|
|
|
|
export function useBkndData() {
|
|
const { config, app, schema, actions: bkndActions } = useBknd();
|
|
|
|
// @todo: potentially store in ref, so it doesn't get recomputed? or use memo?
|
|
const entities = transformObject(config.data.entities ?? {}, (entity, name) => {
|
|
return constructEntity(name, entity);
|
|
});
|
|
|
|
const actions = {
|
|
entity: {
|
|
add: async (name: string, data: TAppDataEntity) => {
|
|
const validated = parse(entitiesSchema, data, {
|
|
skipMark: true,
|
|
forceParse: true,
|
|
});
|
|
// @todo: check for existing?
|
|
return await bkndActions.add("data", `entities.${name}`, validated);
|
|
},
|
|
patch: (entityName: string) => {
|
|
const entity = entities[entityName];
|
|
if (!entity) {
|
|
throw new Error(`Entity "${entityName}" not found`);
|
|
}
|
|
|
|
return {
|
|
config: async (partial: Partial<TAppDataEntity["config"]>): Promise<boolean> => {
|
|
return await bkndActions.overwrite(
|
|
"data",
|
|
`entities.${entityName}.config`,
|
|
partial,
|
|
);
|
|
},
|
|
fields: entityFieldActions(bkndActions, entityName),
|
|
};
|
|
},
|
|
},
|
|
relations: {
|
|
add: async (relation: TAppDataRelation) => {
|
|
const name = crypto.randomUUID();
|
|
const validated = parse(s.anyOf(relationsSchema), relation, {
|
|
skipMark: true,
|
|
forceParse: true,
|
|
});
|
|
return await bkndActions.add("data", `relations.${name}`, validated);
|
|
},
|
|
},
|
|
};
|
|
const $data = {
|
|
entity: (name: string) => entities[name],
|
|
modals,
|
|
system: (name: string) => ({
|
|
any: entities[name]?.type === "system",
|
|
users: name === config.auth.entity_name,
|
|
media: name === config.media.entity_name,
|
|
}),
|
|
};
|
|
|
|
return {
|
|
$data,
|
|
entities,
|
|
relations: app.relations,
|
|
config: config.data,
|
|
schema: schema.data,
|
|
actions,
|
|
};
|
|
}
|
|
|
|
const modals = {
|
|
createAny: () => bkndModals.open(bkndModals.ids.dataCreate, {}),
|
|
createEntity: () =>
|
|
bkndModals.open(bkndModals.ids.dataCreate, {
|
|
initialPath: ["entities", "entity"],
|
|
initialState: { action: "entity" },
|
|
}),
|
|
createRelation: (entity?: string) =>
|
|
bkndModals.open(bkndModals.ids.dataCreate, {
|
|
initialPath: ["entities", "relation"],
|
|
initialState: {
|
|
action: "relation",
|
|
relations: {
|
|
create: [{ source: entity, type: "n:1" } as any],
|
|
},
|
|
},
|
|
}),
|
|
createMedia: (entity?: string) =>
|
|
bkndModals.open(bkndModals.ids.dataCreate, {
|
|
initialPath: ["entities", "template-media"],
|
|
initialState: {
|
|
action: "template-media",
|
|
initial: {
|
|
entity,
|
|
},
|
|
},
|
|
}),
|
|
};
|
|
|
|
function entityFieldActions(bkndActions: TSchemaActions, entityName: string) {
|
|
return {
|
|
add: async (name: string, field: TAppDataField) => {
|
|
const validated = parse(fieldsSchema, field, {
|
|
skipMark: true,
|
|
forceParse: true,
|
|
});
|
|
return await bkndActions.add("data", `entities.${entityName}.fields.${name}`, validated);
|
|
},
|
|
patch: () => null,
|
|
set: async (fields: TAppDataEntityFields, order?: string[]) => {
|
|
try {
|
|
const validated = parse(entityFields, fields, {
|
|
skipMark: true,
|
|
forceParse: true,
|
|
});
|
|
await bkndActions.overwrite("data", `entities.${entityName}.fields`, validated);
|
|
if (order) {
|
|
await bkndActions.overwrite(
|
|
"data",
|
|
`entities.${entityName}.config.fields_order`,
|
|
order,
|
|
);
|
|
}
|
|
} catch (e) {
|
|
console.error("error", e);
|
|
if (e instanceof InvalidSchemaError) {
|
|
alert("Error updating fields: " + e.firstToString());
|
|
} else {
|
|
alert("An error occured, check console. There will be nice error handling soon.");
|
|
}
|
|
}
|
|
},
|
|
};
|
|
}
|