mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Reference and ReferenceList formatters
Summary: Previously, ref/reflist columns were formatted entirely based on their visible column, since they received values from the visible or display columns rather than the actual row IDs. This creates `ReferenceFormatter` and `ReferenceListFormatter` which still delegate most of the formatting work to a visible column formatter but fix a few issues: - ReferenceList columns now actually use the options (e.g. date format) of the visible column to format their elements. Previously they were formatted generically because the visible column formatter wasn't expecting a list. - Invalid references aren't formatted with an `#Invalid Ref` prefix. - When the ref column displays the Row ID, it doesn't have a visible or display column. Previously this led to the references being formatted as just numbers in most cases, with special code in the widget to display them like `Table1[2]`. Now they are consistently formatted in that style throughout. Test Plan: Updated existing tests. Reviewers: jarek Reviewed By: jarek Subscribers: dsagal Differential Revision: https://phab.getgrist.com/D3212
This commit is contained in:
@@ -218,7 +218,7 @@ class FinderImpl implements IFinder {
|
||||
this._sectionTableData = tableModel.tableData;
|
||||
|
||||
this._fieldStepper.array = section.viewFields().peek();
|
||||
this._fieldFormatters = this._fieldStepper.array.map(f => f.visibleColFormatter.peek());
|
||||
this._fieldFormatters = this._fieldStepper.array.map(f => f.formatter.peek());
|
||||
return tableModel;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import {KoArray} from 'app/client/lib/koArray';
|
||||
import {DocModel, IRowModel, recordSet, refRecord, TableRec, ViewFieldRec} from 'app/client/models/DocModel';
|
||||
import {jsonObservable, ObjObservable} from 'app/client/models/modelUtil';
|
||||
import * as gristTypes from 'app/common/gristTypes';
|
||||
import {getReferencedTableId} from 'app/common/gristTypes';
|
||||
import {getReferencedTableId, isFullReferencingType} from 'app/common/gristTypes';
|
||||
import {BaseFormatter, createFormatter} from 'app/common/ValueFormatter';
|
||||
import * as ko from 'knockout';
|
||||
|
||||
@@ -56,6 +56,13 @@ export interface ColumnRec extends IRowModel<"_grist_Tables_column"> {
|
||||
// to the visibleCol associated with column.
|
||||
visibleColFormatter: ko.Computed<BaseFormatter>;
|
||||
|
||||
// A formatter for values of this column.
|
||||
// The difference between visibleColFormatter and formatter is especially important for ReferenceLists:
|
||||
// `visibleColFormatter` is for individual elements of a list, sometimes hypothetical
|
||||
// (i.e. they aren't actually referenced but they exist in the visible column and are relevant to e.g. autocomplete)
|
||||
// `formatter` formats actual cell values, e.g. a whole list from the display column.
|
||||
formatter: ko.Computed<BaseFormatter>;
|
||||
|
||||
// Helper which adds/removes/updates column's displayCol to match the formula.
|
||||
saveDisplayFormula(formula: string): Promise<void>|undefined;
|
||||
}
|
||||
@@ -118,6 +125,8 @@ export function createColumnRec(this: ColumnRec, docModel: DocModel): void {
|
||||
// Helper for Reference/ReferenceList columns, which returns a formatter according to the visibleCol
|
||||
// associated with this column. If no visible column available, return formatting for the column itself.
|
||||
this.visibleColFormatter = ko.pureComputed(() => visibleColFormatterForRec(this, this, docModel));
|
||||
|
||||
this.formatter = ko.pureComputed(() => formatterForRec(this, this, docModel, this.visibleColFormatter()));
|
||||
}
|
||||
|
||||
export function visibleColFormatterForRec(
|
||||
@@ -125,7 +134,28 @@ export function visibleColFormatterForRec(
|
||||
): BaseFormatter {
|
||||
const vcol = rec.visibleColModel();
|
||||
const documentSettings = docModel.docInfoRow.documentSettingsJson();
|
||||
return (vcol.getRowId() !== 0) ?
|
||||
createFormatter(vcol.type(), vcol.widgetOptionsJson(), documentSettings) :
|
||||
createFormatter(colRec.type(), rec.widgetOptionsJson(), documentSettings);
|
||||
const type = colRec.type();
|
||||
if (isFullReferencingType(type)) {
|
||||
if (vcol.getRowId() === 0) {
|
||||
// This column displays the Row ID, e.g. Table1[2]
|
||||
// referencedTableId may actually be empty if the table is hidden
|
||||
const referencedTableId: string = colRec.refTable()?.tableId() || "";
|
||||
return createFormatter('Id', {tableId: referencedTableId}, documentSettings);
|
||||
} else {
|
||||
return createFormatter(vcol.type(), vcol.widgetOptionsJson(), documentSettings);
|
||||
}
|
||||
} else {
|
||||
// For non-reference columns, there's no 'visible column' and we just return a regular formatter
|
||||
return createFormatter(type, rec.widgetOptionsJson(), documentSettings);
|
||||
}
|
||||
}
|
||||
|
||||
export function formatterForRec(
|
||||
rec: ColumnRec | ViewFieldRec, colRec: ColumnRec, docModel: DocModel, visibleColFormatter: BaseFormatter
|
||||
): BaseFormatter {
|
||||
const type = colRec.type();
|
||||
// Ref/RefList columns delegate most formatting to the visibleColFormatter
|
||||
const widgetOpts = {...rec.widgetOptionsJson(), visibleColFormatter};
|
||||
const documentSettings = docModel.docInfoRow.documentSettingsJson();
|
||||
return createFormatter(type, widgetOpts, documentSettings);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {ColumnRec, DocModel, IRowModel, refRecord, ViewSectionRec} from 'app/client/models/DocModel';
|
||||
import {visibleColFormatterForRec} from 'app/client/models/entities/ColumnRec';
|
||||
import {formatterForRec, visibleColFormatterForRec} from 'app/client/models/entities/ColumnRec';
|
||||
import * as modelUtil from 'app/client/models/modelUtil';
|
||||
import * as UserType from 'app/client/widgets/UserType';
|
||||
import {DocumentSettings} from 'app/common/DocumentSettings';
|
||||
@@ -74,6 +74,13 @@ export interface ViewFieldRec extends IRowModel<"_grist_Views_section_field"> {
|
||||
// to the visibleCol associated with field.
|
||||
visibleColFormatter: ko.Computed<BaseFormatter>;
|
||||
|
||||
// A formatter for values of this column.
|
||||
// The difference between visibleColFormatter and formatter is especially important for ReferenceLists:
|
||||
// `visibleColFormatter` is for individual elements of a list, sometimes hypothetical
|
||||
// (i.e. they aren't actually referenced but they exist in the visible column and are relevant to e.g. autocomplete)
|
||||
// `formatter` formats actual cell values, e.g. a whole list from the display column.
|
||||
formatter: ko.Computed<BaseFormatter>;
|
||||
|
||||
createValueParser(): (value: string) => any;
|
||||
|
||||
// Helper which adds/removes/updates field's displayCol to match the formula.
|
||||
@@ -167,6 +174,8 @@ export function createViewFieldRec(this: ViewFieldRec, docModel: DocModel): void
|
||||
// associated with this field. If no visible column available, return formatting for the field itself.
|
||||
this.visibleColFormatter = ko.pureComputed(() => visibleColFormatterForRec(this, this.column(), docModel));
|
||||
|
||||
this.formatter = ko.pureComputed(() => formatterForRec(this, this.column(), docModel, this.visibleColFormatter()));
|
||||
|
||||
this.createValueParser = function() {
|
||||
const fieldRef = this.useColOptions.peek() ? undefined : this.id.peek();
|
||||
return createParser(docModel.docData, this.colRef.peek(), fieldRef);
|
||||
|
||||
Reference in New Issue
Block a user