/* eslint @typescript-eslint/no-explicit-any: off */ import { FieldTypes as SealiousFieldTypes, Field as SealiousField, CollectionItem, } from "sealious"; import { Boolean, TextBasedSimpleField } from "./fields.js"; import { sealiousToFormField } from "./get-field-for-sealious.js"; import { Table } from "./table.js"; import { Table as TableControl } from "../controls/table.js"; import { Context } from "koa"; import { FormDataValue, FormData } from "../form-types.js"; import { FormControlContext } from "../controls/form-control.js"; import { HiddenInput } from "../controls/hidden-input.js"; import { FormField } from "./field.js"; function getReferencingFields( sealious_field: SealiousFieldTypes.DeepReverseSingleReference ): Record> { const referencing_collection = sealious_field.collection.app.collections[ sealious_field.referencing_collection ]; if (!referencing_collection) { throw new Error( "Unknown collection: " + sealious_field.referencing_collection ); } return referencing_collection.fields; } export class DeepReverseSingleReferenceTable extends Table< Record > { constructor( public sealious_field: SealiousFieldTypes.DeepReverseSingleReference ) { super({ selected: new Boolean(false), [sealious_field.referencing_field]: new TextBasedSimpleField(true), [sealious_field.intermediary_field_that_points_there]: new TextBasedSimpleField(true), ...Object.fromEntries( Object.values(getReferencingFields(sealious_field)) .filter( (field) => !( field instanceof SealiousFieldTypes.SingleReference ) ) .map((field) => [field.name, sealiousToFormField(field)]) ), }); } getControl(): TableControl { return new TableControl(this, { label: this.label || this.name, allow_adding: false, subfield_controls: { selected: this.columns.selected.getControl(), [this.sealious_field.referencing_field]: new HiddenInput( this.columns[this.sealious_field.referencing_field] ), [this.sealious_field.intermediary_field_that_points_there]: new HiddenInput( this.columns[ this.sealious_field.intermediary_field_that_points_there ] ), ...Object.fromEntries( Object.values(getReferencingFields(this.sealious_field)) .filter( (field) => !( field instanceof SealiousFieldTypes.SingleReference ) ) .map((field) => [ field.name, this.columns[field.name].getControl(), ]) ), }, }); } getSealiousCreateValue(_fctx: FormControlContext): Promise { throw new Error("Method not implemented."); } async postSealiousCreate( ctx: Context, created_item: CollectionItem, form_data: FormData ): Promise { // First, we remove links refering to current item const { items: to_delete } = await ctx.$app.collections[ "${toKebabCase(referencing_collection)}" ] .list(ctx.$context) .filter({ "${referencing_field}": created_item.id }) .fetch(); await Promise.all(to_delete.map((item) => item.remove(ctx.$context))); // Then, we iterate over all selected values and insert appropriate entries for the subcategories relation const referencing_fields = getReferencingFields(this.sealious_field); const { parsed: value } = await this.getParsedValue( ctx, form_data.raw_values, false ); const promises = (value || []) .filter((s) => s.selected == true) .map(async (link_info) => { await ctx.$app.collections[ "${toKebabCase(referencing_collection)}" ].create(ctx.$context, { "${referencing_field}": created_item.id, "${intermediary_field_that_points_there}": String( link_info["${intermediary_field_that_points_there}"] ), ...Object.fromEntries( Object.values(referencing_fields) .filter( (field) => !( field instanceof SealiousFieldTypes.SingleReference ) ) .map((field) => [field.name, link_info[field.name]]) ), }); }); await Promise.all(promises); } postSealiousEdit( ctx: Context, edited_item: CollectionItem, form_data: FormData ): Promise { return this.postSealiousCreate(ctx, edited_item, form_data); } async sealiousValueToForm( ctx: Context, _value: string[], item: CollectionItem ): Promise { // convert from an array to array-like object const referencing_fields = getReferencingFields(this.sealious_field); return Object.fromEntries( await Promise.all([ this.sealious_field.collection.list(ctx.$context).fetch(), this.sealious_field .getReferencingCollection() .list(ctx.$context) .fetch(), ]).then(([{ items: targets }, { items: links }]) => targets .map((target) => { return { selected: ( (item.get( this.sealious_field.name ) as string[]) || [] ).includes(target.id) ? "on" : "off", [this.sealious_field.referencing_field]: item.id, [this.sealious_field .intermediary_field_that_points_there]: target.id, ...Object.fromEntries( Object.values(referencing_fields) .filter( (field) => !( field instanceof SealiousFieldTypes.SingleReference ) ) .map((field) => [ field.name, links .find( (e) => e.get( this.sealious_field .intermediary_field_that_points_there ) == target.id && e.get( this.sealious_field .referencing_field ) == item.id ) ?.get("rank") || 0, ]) ), }; }) .entries() ) ) as FormDataValue; } }