mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) Fix display of formatted dates in reference columns
Summary: Reference/referencelist columns displaying date/datetime columns didn't show the formatting of that column, formatting them as ISO instead. One weird effect of this was that opening the editor suddenly changed the format because the editor formatted the dates correctly. You can see this in the checkin doc as an example. This was discussed in https://grist.slack.com/archives/C0234CPPXPA/p1636482208111800. Here's the main point: > both use the visible column formatter's formatAny. the editor uses the value from the visible column, which for a date column is a raw timestamp number. the cell display uses the value from the display column which is of type Any so the value is wrapped in a list starting with 'd'. the former gets formatted according to the formatting options, but the latter just gets formatted as ISO. Probably a good solution to the broader problem is to ensure that the display column has the same type and widget options as the visible column. That seems potentially messy, so I did something easier: fix `DateFormatter` to accept encoded date/datetime objects. It still receives the correct widget options from the visible column as before but can handle the values from the display column. This might also have other uses in the future. Test Plan: - Fixed several tests which previously expected the buggy behaviour. - Converted ValueFormatter.js tests to typescript and cleaned up the existing code slightly. - Added tests for DateFormatter and DateTimeFormatter to the ValueFormatter test suite, which only tested numbers before. Reviewers: dsagal Reviewed By: dsagal Subscribers: dsagal Differential Revision: https://phab.getgrist.com/D3190
This commit is contained in:
parent
c470c4041b
commit
9d62e67369
@ -1,13 +1,14 @@
|
|||||||
// tslint:disable:max-classes-per-file
|
// tslint:disable:max-classes-per-file
|
||||||
|
|
||||||
import {CellValue} from 'app/common/DocActions';
|
import {CellValue} from 'app/common/DocActions';
|
||||||
|
import {DocumentSettings} from 'app/common/DocumentSettings';
|
||||||
import * as gristTypes from 'app/common/gristTypes';
|
import * as gristTypes from 'app/common/gristTypes';
|
||||||
import * as gutil from 'app/common/gutil';
|
import * as gutil from 'app/common/gutil';
|
||||||
import {buildNumberFormat, NumberFormatOptions} from 'app/common/NumberFormat';
|
import {buildNumberFormat, NumberFormatOptions} from 'app/common/NumberFormat';
|
||||||
|
import {GristObjCode} from 'app/plugin/GristData';
|
||||||
import {decodeObject, GristDateTime} from 'app/plugin/objtypes';
|
import {decodeObject, GristDateTime} from 'app/plugin/objtypes';
|
||||||
import isPlainObject = require('lodash/isPlainObject');
|
|
||||||
import * as moment from 'moment-timezone';
|
import * as moment from 'moment-timezone';
|
||||||
import {DocumentSettings} from 'app/common/DocumentSettings';
|
import isPlainObject = require('lodash/isPlainObject');
|
||||||
|
|
||||||
export {PENDING_DATA_PLACEHOLDER} from 'app/plugin/objtypes';
|
export {PENDING_DATA_PLACEHOLDER} from 'app/plugin/objtypes';
|
||||||
|
|
||||||
@ -49,7 +50,7 @@ export function formatDecoded(value: unknown, isTopLevel: boolean = true): strin
|
|||||||
export type IsRightTypeFunc = (value: CellValue) => boolean;
|
export type IsRightTypeFunc = (value: CellValue) => boolean;
|
||||||
|
|
||||||
export class BaseFormatter {
|
export class BaseFormatter {
|
||||||
public readonly isRightType: IsRightTypeFunc;
|
protected isRightType: IsRightTypeFunc;
|
||||||
|
|
||||||
constructor(public type: string, public widgetOpts: object, public docSettings: DocumentSettings) {
|
constructor(public type: string, public widgetOpts: object, public docSettings: DocumentSettings) {
|
||||||
this.isRightType = gristTypes.isRightType(gristTypes.extractTypeFromColType(type)) ||
|
this.isRightType = gristTypes.isRightType(gristTypes.extractTypeFromColType(type)) ||
|
||||||
@ -121,13 +122,40 @@ class DateFormatter extends BaseFormatter {
|
|||||||
|
|
||||||
constructor(type: string, widgetOpts: DateFormatOptions, docSettings: DocumentSettings, timezone: string = 'UTC') {
|
constructor(type: string, widgetOpts: DateFormatOptions, docSettings: DocumentSettings, timezone: string = 'UTC') {
|
||||||
super(type, widgetOpts, docSettings);
|
super(type, widgetOpts, docSettings);
|
||||||
|
// Allow encoded dates/datetimes ([d, number] or [D, number, timezone])
|
||||||
|
// which are found in formula columns of type Any,
|
||||||
|
// particularly reference display columns which are formatted here according to the visible column
|
||||||
|
// which will have the correct column type and options.
|
||||||
|
// Since these encoded objects are not expected in a Date/Datetime column and require
|
||||||
|
// being handled differently from just a number,
|
||||||
|
// we don't change `gristTypes.isRightType` which is used elsewhere.
|
||||||
|
this.isRightType = (value: any) => (
|
||||||
|
value === null ||
|
||||||
|
typeof value === "number" ||
|
||||||
|
Array.isArray(value) && (
|
||||||
|
value[0] === GristObjCode.Date ||
|
||||||
|
value[0] === GristObjCode.DateTime
|
||||||
|
)
|
||||||
|
);
|
||||||
this._dateTimeFormat = widgetOpts.dateFormat || 'YYYY-MM-DD';
|
this._dateTimeFormat = widgetOpts.dateFormat || 'YYYY-MM-DD';
|
||||||
this._timezone = timezone;
|
this._timezone = timezone;
|
||||||
}
|
}
|
||||||
|
|
||||||
public format(value: any): string {
|
public format(value: any): string {
|
||||||
if (value === null) { return ''; }
|
if (value === null) {
|
||||||
const time = moment.tz(value * 1000, this._timezone);
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// For a DateTime object in an Any column, use the provided timezone (`value[2]`)
|
||||||
|
// Otherwise use the timezone configured for a DateTime column.
|
||||||
|
let timezone = this._timezone;
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
timezone = value[2] || timezone;
|
||||||
|
value = value[1];
|
||||||
|
}
|
||||||
|
// Now `value` is a number
|
||||||
|
|
||||||
|
const time = moment.tz(value * 1000, timezone);
|
||||||
return time.format(this._dateTimeFormat);
|
return time.format(this._dateTimeFormat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user