mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Convert a few widgets to typescript and grainjs.
Summary: No behavior changes. Diff includes an intermediate commit with only renames, for easier review. Test Plan: Existing tests should pass. Reviewers: paulfitz Reviewed By: paulfitz Differential Revision: https://phab.getgrist.com/D2669
This commit is contained in:
106
app/client/widgets/Reference.ts
Normal file
106
app/client/widgets/Reference.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import {DataRowModel} from 'app/client/models/DataRowModel';
|
||||
import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
|
||||
import {cssLabel, cssRow} from 'app/client/ui/RightPanel';
|
||||
import {colors, testId} from 'app/client/ui2018/cssVars';
|
||||
import {icon} from 'app/client/ui2018/icons';
|
||||
import {IOptionFull, select} from 'app/client/ui2018/menus';
|
||||
import {NTextBox} from 'app/client/widgets/NTextBox';
|
||||
import {isVersions} from 'app/common/gristTypes';
|
||||
import {BaseFormatter} from 'app/common/ValueFormatter';
|
||||
import {Computed, dom, styled} from 'grainjs';
|
||||
import * as ko from 'knockout';
|
||||
|
||||
/**
|
||||
* Reference - The widget for displaying references to another table's records.
|
||||
*/
|
||||
export class Reference extends NTextBox {
|
||||
private _refValueFormatter: ko.Computed<BaseFormatter>;
|
||||
private _visibleColRef: Computed<number>;
|
||||
private _validCols: Computed<Array<IOptionFull<number>>>;
|
||||
private _formatValue: Computed<(val: any) => string>;
|
||||
|
||||
constructor(field: ViewFieldRec) {
|
||||
super(field);
|
||||
|
||||
this._refValueFormatter = this.autoDispose(ko.computed(() =>
|
||||
field.createVisibleColFormatter()));
|
||||
|
||||
this._visibleColRef = Computed.create(this, (use) => use(this.field.visibleColRef));
|
||||
// Note that saveOnly is used here to prevent display value flickering on visible col change.
|
||||
this._visibleColRef.onWrite((val) => this.field.visibleColRef.saveOnly(val));
|
||||
|
||||
this._validCols = Computed.create(this, (use) => {
|
||||
const refTable = use(use(this.field.column).refTable);
|
||||
if (!refTable) { return []; }
|
||||
return use(use(refTable.columns).getObservable())
|
||||
.filter(col => !use(col.isHiddenCol))
|
||||
.map<IOptionFull<number>>(col => ({
|
||||
label: use(col.label),
|
||||
value: col.getRowId(),
|
||||
icon: 'FieldColumn',
|
||||
disabled: use(col.type).startsWith('Ref:') || use(col.isTransforming)
|
||||
}))
|
||||
.concat([{label: 'Row ID', value: 0, icon: 'FieldColumn'}]);
|
||||
});
|
||||
|
||||
// Computed returns a function that formats cell values.
|
||||
this._formatValue = Computed.create(this, (use) => {
|
||||
// If the field is pulling values from a display column, use a general-purpose formatter.
|
||||
if (use(this.field.displayColRef) !== use(this.field.colRef)) {
|
||||
const fmt = use(this._refValueFormatter);
|
||||
return (val: any) => fmt.formatAny(val);
|
||||
} else {
|
||||
const refTable = use(use(this.field.column).refTable);
|
||||
const refTableId = refTable ? use(refTable.tableId) : "";
|
||||
return (val: any) => val > 0 ? `${refTableId}[${val}]` : "";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public buildConfigDom() {
|
||||
return [
|
||||
cssLabel('SHOW COLUMN'),
|
||||
cssRow(
|
||||
select(this._visibleColRef, this._validCols),
|
||||
testId('fbuilder-ref-col-select')
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
public buildTransformConfigDom() {
|
||||
return this.buildConfigDom();
|
||||
}
|
||||
|
||||
public buildDom(row: DataRowModel) {
|
||||
const formattedValue = Computed.create(null, (use) => {
|
||||
if (use(row._isAddRow) || this.isDisposed() || use(this.field.displayColModel).isDisposed()) {
|
||||
// Work around JS errors during certain changes (noticed when visibleCol field gets removed
|
||||
// for a column using per-field settings).
|
||||
return "";
|
||||
}
|
||||
const value = row.cells[use(use(this.field.displayColModel).colId)];
|
||||
if (!value) { return ""; }
|
||||
const content = use(value);
|
||||
if (isVersions(content)) {
|
||||
// We can arrive here if the reference value is unchanged (viewed as a foreign key)
|
||||
// but the content of its displayCol has changed. Postponing doing anything about
|
||||
// this until we have three-way information for computed columns. For now,
|
||||
// just showing one version of the cell. TODO: elaborate.
|
||||
return use(this._formatValue)(content[1].local || content[1].parent);
|
||||
}
|
||||
return use(this._formatValue)(content);
|
||||
});
|
||||
return dom('div.field_clip',
|
||||
dom.autoDispose(formattedValue),
|
||||
cssRefIcon('FieldReference',
|
||||
testId('ref-link-icon')
|
||||
),
|
||||
dom.text(formattedValue)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const cssRefIcon = styled(icon, `
|
||||
background-color: ${colors.slate};
|
||||
margin: -1px 2px 2px 0;
|
||||
`);
|
||||
Reference in New Issue
Block a user