import type { Disposable } from '@blockeditor/global/utils'; import { Slot } from '@blockeditor/global/utils'; import type { UniComponent } from '../../_common/components/uni-component/uni-component.js'; import type { TType } from '../logical/typesystem.js'; import type { ColumnDataUpdater, InsertToPosition } from '../types.js'; import type { FilterGroup, Variable } from './ast.js'; import type { CellRenderer, ColumnConfig, ColumnConfigManager, } from './columns/manager.js'; import { columnManager } from './columns/manager.js'; import { columnRenderer } from './columns/renderer.js'; import type { DataSource, DetailSlots } from './datasource/base.js'; export interface DataViewManager { get id(): string; get type(): string; get readonly(): boolean; get columnManagerList(): DataViewColumnManager[]; get columns(): string[]; get detailColumns(): string[]; get columnsWithoutFilter(): string[]; get rows(): string[]; get filter(): FilterGroup; get filterVisible(): boolean; filterSetVisible(visible: boolean): void; get vars(): Variable[]; updateFilter(filter: FilterGroup): void; cellGetValue(rowId: string, columnId: string): unknown; cellGetRenderValue(rowId: string, columnId: string): unknown; cellGetJsonValue(rowId: string, columnId: string): unknown; cellGetStringValue(rowId: string, columnId: string): string; cellGetExtra(rowId: string, columnId: string): unknown | undefined; cellSetValueFromString( columnId: string, value: string ): { value: unknown; data?: Record; }; cellUpdateRenderValue(rowId: string, columnId: string, value: unknown): void; cellUpdateValue(rowId: string, columnId: string, value: unknown): void; rowDelete(ids: string[]): void; rowAdd(insertPosition: InsertToPosition): string; columnAdd(toAfterOfColumn: InsertToPosition, type?: string): string; columnDelete(columnId: string): void; columnDuplicate(columnId: string): void; columnGet(columnId: string): DataViewColumnManager; columnGetPreColumn(columnId: string): DataViewColumnManager | undefined; columnGetNextColumn(columnId: string): DataViewColumnManager | undefined; columnGetName(columnId: string): string; columnGetType(columnId: string): string; columnGetHide(columnId: string): boolean; columnGetData(columnId: string): Record; columnGetDataType(columnId: string): TType; columnGetIndex(columnId: string): number; columnGetIdByIndex(index: number): string; columnGetReadonly(columnId: string): boolean; columnUpdateName(columnId: string, name: string): void; columnUpdateHide(columnId: string, hide: boolean): void; columnUpdateType(columnId: string, type: string): void; columnUpdateData(columnId: string, data: Record): void; get allColumnConfig(): ColumnConfig[]; get columnConfigManager(): ColumnConfigManager; getIcon(type: string): UniComponent | undefined; /** * @deprecated */ captureSync(): void; slots: { update: Slot; }; onCellUpdate( rowId: string, columnId: string, callback: () => void ): Disposable; columnMove(columnId: string, position: InsertToPosition): void; rowMove(rowId: string, position: InsertToPosition): void; duplicateView(): void; deleteView(): void; get isDeleted(): boolean; get detailSlots(): DetailSlots; } export interface DataViewColumnManager< Value = unknown, Data extends Record = Record, > { get dataViewManager(): DataViewManager; get id(): string; get index(): number; get type(): string; get dataType(): TType; get name(): string; get hide(): boolean; get data(): Data; get readonly(): boolean; get renderer(): CellRenderer; get detailRenderer(): CellRenderer; get isFirst(): boolean; get isLast(): boolean; getStringValue(rowId: string): string; getJsonValue(rowId: string): unknown; getValue(rowId: string): Value | undefined; getExtra(rowId: string): unknown; setValue(rowId: string, value: Value | undefined): void; updateData(updater: ColumnDataUpdater): void; updateHide(hide: boolean): void; updateName(name: string): void; get updateType(): undefined | ((type: string) => void); get delete(): undefined | (() => void); get duplicate(): undefined | (() => void); get icon(): UniComponent | undefined; onCellUpdate(rowId: string, callback: () => void): Disposable; /** * @deprecated */ captureSync(): void; } export abstract class BaseDataViewManager implements DataViewManager { private searchString = ''; private _filterVisible?: boolean; get rows(): string[] { return this.filteredRows(this.searchString); } protected constructor(protected dataSource: DataSource) { this.dataSource.slots.update.pipe(this.slots.update); } setSearch(str: string): void { this.searchString = str; this.slots.update.emit(); } public abstract isShow(rowId: string): boolean; private filteredRows(searchString: string) { return this.dataSource.rows.filter(id => { if (searchString) { const containsSearchString = this.columns.some(columnId => { return this.cellGetStringValue(id, columnId) ?.toLowerCase() .includes(searchString?.toLowerCase()); }); if (!containsSearchString) { return false; } } return this.isShow(id); }); } get columnManagerList(): ReturnType[] { return this.columns.map( id => this.columnGet(id) as ReturnType ); } get readonly(): boolean { return false; } public slots = { update: new Slot(), }; onCellUpdate( rowId: string, columnId: string, callback: () => void ): Disposable { return this.dataSource.onCellUpdate(rowId, columnId, callback); } public cellGetValue(rowId: string, columnId: string): unknown { return columnManager .getColumn(this.columnGetType(columnId)) .formatValue( this.dataSource.cellGetValue(rowId, columnId), this.columnGetData(columnId) ); } public cellGetJsonValue(rowId: string, columnId: string): unknown { return columnManager .getColumn(this.columnGetType(columnId)) .toJson( this.dataSource.cellGetValue(rowId, columnId), this.columnGetData(columnId) ); } public cellGetRenderValue(rowId: string, columnId: string): unknown { return this.dataSource.cellGetRenderValue(rowId, columnId); } public cellGetStringValue(rowId: string, columnId: string): string { return ( columnManager .getColumn(this.columnGetType(columnId)) .toString( this.dataSource.cellGetValue(rowId, columnId), this.columnGetData(columnId) ) ?? '' ); } public cellGetExtra(rowId: string, columnId: string): unknown { return this.dataSource.cellGetExtra(rowId, columnId); } public cellSetValueFromString(columnId: string, cellData: string) { return ( columnManager .getColumn(this.columnGetType(columnId)) .fromString(cellData, this.columnGetData(columnId)) ?? '' ); } public cellUpdateRenderValue( rowId: string, columnId: string, value: unknown ): void { this.dataSource.cellChangeValue(rowId, columnId, value); } public cellUpdateValue( rowId: string, columnId: string, value: unknown ): void { this.dataSource.cellChangeValue(rowId, columnId, value); } public columnAdd(position: InsertToPosition, type?: string): string { const id = this.dataSource.propertyAdd(position, type); this.columnMove(id, position); return id; } public columnDelete(columnId: string): void { this.dataSource.propertyDelete(columnId); } public columnDuplicate(columnId: string): void { const id = this.dataSource.propertyDuplicate(columnId); this.columnMove(id, { before: false, id: columnId, }); } public abstract columnGet(columnId: string): DataViewColumnManager; public columnGetData(columnId: string): Record { return this.dataSource.propertyGetData(columnId); } public columnGetDataType(columnId: string): TType { return columnManager .getColumn(this.columnGetType(columnId)) .dataType(this.columnGetData(columnId)); } public abstract columnGetHide(columnId: string): boolean; public abstract columnUpdateHide(columnId: string, hide: boolean): void; public columnGetIdByIndex(index: number): string { return this.columns[index]; } public columnGetReadonly(columnId: string): boolean { return this.dataSource.propertyGetReadonly(columnId); } public columnGetIndex(columnId: string): number { return this.columns.indexOf(columnId); } public columnGetName(columnId: string): string { return this.dataSource.propertyGetName(columnId); } public columnGetNextColumn( columnId: string ): DataViewColumnManager | undefined { return this.columnGet( this.columnGetIdByIndex(this.columnGetIndex(columnId) + 1) ); } public columnGetPreColumn( columnId: string ): DataViewColumnManager | undefined { return this.columnGet( this.columnGetIdByIndex(this.columnGetIndex(columnId) - 1) ); } public columnGetType(columnId: string): string { return this.dataSource.propertyGetType(columnId); } public columnUpdateData( columnId: string, data: Record ): void { this.dataSource.propertyChangeData(columnId, data); } public columnUpdateName(columnId: string, name: string): void { this.dataSource.propertyChangeName(columnId, name); } public columnUpdateType(columnId: string, type: string): void { this.dataSource.propertyChangeType(columnId, type); } public abstract get columns(): string[]; public abstract get detailColumns(): string[]; public abstract get columnsWithoutFilter(): string[]; public rowAdd(insertPosition: InsertToPosition | number): string { return this.dataSource.rowAdd(insertPosition); } public rowDelete(ids: string[]): void { this.dataSource.rowDelete(ids); } public captureSync(): void { this.dataSource.captureSync(); } public abstract get id(): string; public abstract get type(): string; public get allColumnConfig(): ColumnConfig[] { return this.dataSource.allPropertyConfig; } public get columnConfigManager(): ColumnConfigManager { return this.dataSource.columnConfigManager; } public getIcon(type: string): UniComponent | undefined { return columnRenderer.get(type).icon; } abstract columnMove(columnId: string, position: InsertToPosition): void; public abstract deleteView(): void; public abstract get isDeleted(): boolean; public get detailSlots(): DetailSlots { return this.dataSource.detailSlots; } abstract get filter(): FilterGroup; abstract updateFilter(filter: FilterGroup): void; get vars(): Variable[] { return this.columnsWithoutFilter.map(id => { const v = this.columnGet(id); return { id: v.id, name: v.name, type: columnManager.getColumn(v.type).dataType(v.data), icon: v.icon, }; }); } filterSetVisible(visible: boolean): void { this._filterVisible = visible; this.slots.update.emit(); } get filterVisible(): boolean { return this._filterVisible ?? this.filter.conditions.length > 0; } public rowMove(rowId: string, position: InsertToPosition): void { this.dataSource.rowMove(rowId, position); } public abstract duplicateView(): void; } export abstract class BaseDataViewColumnManager implements DataViewColumnManager { protected constructor( protected propertyId: string, public dataViewManager: DataViewManager ) {} get index(): number { return this.dataViewManager.columnGetIndex(this.id); } get data(): Record { return this.dataViewManager.columnGetData(this.id); } get hide(): boolean { return this.dataViewManager.columnGetHide(this.id); } get id(): string { return this.propertyId; } get isFirst(): boolean { return this.dataViewManager.columnGetIndex(this.id) === 0; } get isLast(): boolean { return ( this.dataViewManager.columnGetIndex(this.id) === this.dataViewManager.columnManagerList.length - 1 ); } get name(): string { return this.dataViewManager.columnGetName(this.id); } get renderer(): CellRenderer { return columnRenderer.get(this.type).cellRenderer; } get detailRenderer(): CellRenderer { return columnRenderer.get(this.type).detailCellRenderer ?? this.renderer; } get type(): string { return this.dataViewManager.columnGetType(this.id); } get dataType(): TType { return columnManager.getColumn(this.type).dataType(this.data); } getValue(rowId: string): unknown | undefined { return this.dataViewManager.cellGetRenderValue(rowId, this.id); } getExtra(rowId: string): unknown { return this.dataViewManager.cellGetExtra(rowId, this.id); } setValue(rowId: string, value: unknown | undefined): void { this.dataViewManager.cellUpdateRenderValue(rowId, this.id, value); } updateData(updater: ColumnDataUpdater): void { const data = this.dataViewManager.columnGetData(this.id); this.dataViewManager.columnUpdateData(this.id, { ...data, ...updater(data), }); } updateHide(hide: boolean): void { this.dataViewManager.columnUpdateHide(this.id, hide); } updateName(name: string): void { this.dataViewManager.columnUpdateName(this.id, name); } get delete(): (() => void) | undefined { return () => this.dataViewManager.columnDelete(this.id); } get duplicate(): (() => void) | undefined { return () => this.dataViewManager.columnDuplicate(this.id); } get updateType(): undefined | ((type: string) => void) { return type => this.dataViewManager.columnUpdateType(this.id, type); } get readonly(): boolean { return ( this.dataViewManager.readonly || this.dataViewManager.columnGetReadonly(this.id) ); } captureSync(): void { this.dataViewManager.captureSync(); } getJsonValue(rowId: string): unknown { return this.dataViewManager.cellGetJsonValue(rowId, this.id); } getStringValue(rowId: string): string { return this.dataViewManager.cellGetStringValue(rowId, this.id); } setValueFromString(value: string) { const result = this.dataViewManager.cellSetValueFromString(this.id, value); if (result.data) { this.dataViewManager.columnUpdateData(this.id, result.data); } return result.value; } public get icon(): UniComponent | undefined { if (!this.type) return undefined; return this.dataViewManager.getIcon(this.type); } onCellUpdate(rowId: string, callback: () => void): Disposable { return this.dataViewManager.onCellUpdate(rowId, this.id, callback); } }