import { useMemo } from 'react'; import { defineSchemaSource, DataExtensionState, parseFqdn, } from '@wix/bex-core'; import type { CollectionBackend, DataExtensionOverrides, SchemaSource, } from '@wix/bex-core'; import type { FieldsSourceProvider } from '../components/fieldsSourceProvider'; import type { ToolbarCollectionState } from '../state'; import { CollectionFieldsSourceState } from '../state/CollectionFieldsSourceState'; import { DataExtension } from '../components/DataExtension/DataExtension'; import { dataExtensionFieldsSourceFrom } from '../components/DataExtension/dataExtensionFieldsSource'; import { dataExtensionRendering } from '../components/DataExtension/dataExtensionRendering'; export interface PlatformizedSourceInput extends DataExtensionOverrides { /** The entity's fqdn — becomes the source id and query name. */ fqdn: string; /** The consumer's item data access. `find` drives the collection query — * the same code a classic `fetchData` runs. Writes are optional * capabilities; when present they feed the editable-table row mutations. */ backend: CollectionBackend; /** Row identity. Default: `item[idField]`. */ itemKey?: (item: T) => string; /** Row display label. Default: `item[displayField]`. */ itemName?: (item: T) => string; /** Default: `'id'` — the platformized standard. */ idField?: string; /** Default: `idField`. */ displayField?: string; } type SelfAttachingSource = SchemaSource & FieldsSourceProvider; /** * A source for a platformized entity: the consumer owns the items (via * `backend`) and the source adds field management and rendering of the added * fields on top. Recreated only when `fqdn` changes. */ export const usePlatformizedSource = >( input: PlatformizedSourceInput, ): SchemaSource => { return useMemo(() => createPlatformizedSource(input), [input.fqdn]); }; function createPlatformizedSource( input: PlatformizedSourceInput, ): SelfAttachingSource { const { fqdn, backend, itemKey, itemName, idField = 'id', displayField = idField, ...overrides } = input; const base = defineSchemaSource({ collectionId: fqdn, itemKey, itemName, // The added fields arrive with the collection-adapter refit; until then // the attach below renders them, and the schema carries identity only. loadSchema: async () => ({ schema: { id: fqdn, idField, displayField, fields: {} }, backend, }), }); return { ...base, // Transitional (until the adapter refit): attach the fields area through // the DataExtension glue — the same wiring as `dataExtensionTableSource`, // with the fqdn coming from the source instead of the collection config. setOnTable(toolbar: ToolbarCollectionState) { if (toolbar.collectionFieldsSource) { return; } const dataExtension = new DataExtensionState({ container: toolbar.container, fqdn: parseFqdn(fqdn), closeSidePanel: toolbar.closeSidePanel, ...overrides, }); CollectionFieldsSourceState.setOnTable(toolbar, { fieldsSource: dataExtensionFieldsSourceFrom({ dataExtension, reportBi: toolbar.reportBi, toExtendedFields: toolbar.collection.toExtendedFields, }), ...dataExtensionRendering({ dataExtension, toolbar, DataExtension, props: overrides, }), }); DataExtension.syncTableCollectionProps(toolbar); }, }; } /** Transitional (until the adapter refit): platformized sources attach their * own fields area instead of going through SchemaState. */ export const attachesItself = ( source: SchemaSource, ): source is SelfAttachingSource => 'setOnTable' in source;