(core) Conditional formatting rules

Summary:
Adding conditional formatting rules feature.

Each column can have multiple styling rules which are applied in order
when evaluated to a truthy value.

- The creator panel has a new section: Cell Style
- New user action AddEmptyRule for adding an empty rule
- New columns in _grist_Table_columns and fields

A new color picker will be introduced in a follow-up diff (as it is also
used in choice/choice list/filters).

Design document:
https://grist.quip.com/FVzfAgoO5xOF/Conditional-Formatting-Implementation-Design

Test Plan: new tests

Reviewers: georgegevoian

Reviewed By: georgegevoian

Subscribers: alexmojaki

Differential Revision: https://phab.getgrist.com/D3282
This commit is contained in:
Jarosław Sadziński
2022-03-22 14:41:11 +01:00
parent 96a34122a5
commit b1c3943bf4
25 changed files with 952 additions and 231 deletions

View File

@@ -3,14 +3,19 @@
* so is friendlier and clearer to derive TypeScript classes from.
*/
import {DocComm} from 'app/client/components/DocComm';
import {GristDoc} from 'app/client/components/GristDoc';
import {DocData} from 'app/client/models/DocData';
import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
import {SaveableObjObservable} from 'app/client/models/modelUtil';
import {cssLabel, cssRow} from 'app/client/ui/RightPanel';
import {colorSelect} from 'app/client/ui2018/ColorSelect';
import {CellStyle} from 'app/client/widgets/CellStyle';
import {BaseFormatter} from 'app/common/ValueFormatter';
import {Computed, Disposable, DomContents, fromKo, Observable} from 'grainjs';
import {
Disposable,
dom,
DomContents,
fromKo,
Observable,
} from 'grainjs';
export interface Options {
// A hex value to set the default widget text color. Default to '#000000' if omitted.
@@ -33,42 +38,33 @@ export abstract class NewAbstractWidget extends Disposable {
protected valueFormatter: Observable<BaseFormatter>;
protected textColor: Observable<string>;
protected fillColor: Observable<string>;
protected readonly defaultTextColor: string;
constructor(protected field: ViewFieldRec, opts: Options = {}) {
super();
const {defaultTextColor = '#000000'} = opts;
this.defaultTextColor = defaultTextColor;
this.options = field.widgetOptionsJson;
this.textColor = Computed.create(this, (use) => (
use(this.field.textColor) || defaultTextColor
)).onWrite((val) => this.field.textColor(val === defaultTextColor ? undefined : val));
this.fillColor = fromKo(this.field.fillColor);
this.valueFormatter = fromKo(field.formatter);
}
/**
* Builds the DOM showing configuration buttons and fields in the sidebar.
*/
public buildConfigDom(): DomContents { return null; }
public buildConfigDom(): DomContents {
return null;
}
/**
* Builds the transform prompt config DOM in the few cases where it is necessary.
* Child classes need not override this function if they do not require transform config options.
*/
public buildTransformConfigDom(): DomContents { return null; }
public buildTransformConfigDom(): DomContents {
return null;
}
public buildColorConfigDom(): Element[] {
return [
cssLabel('CELL COLOR'),
cssRow(
colorSelect(
this.textColor,
this.fillColor,
// Calling `field.widgetOptionsJson.save()` saves both fill and text color settings.
() => this.field.widgetOptionsJson.save()
)
)
];
public buildColorConfigDom(gristDoc: GristDoc): DomContents {
return dom.create(CellStyle, this.field, gristDoc, this.defaultTextColor);
}
/**
@@ -88,5 +84,7 @@ export abstract class NewAbstractWidget extends Disposable {
/**
* Returns the docComm object for communicating with the server.
*/
protected _getDocComm(): DocComm { return this._getDocData().docComm; }
protected _getDocComm(): DocComm {
return this._getDocData().docComm;
}
}