mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
8be920dd25
Summary: Creator panel allows now to edit multiple columns at once for some options that are common for them. Options that are not common are disabled. List of options that can be edited for multiple columns: - Column behavior (but limited to empty/formula columns) - Alignment and wrapping - Default style - Number options (for numeric columns) - Column types (but only for empty/formula columns) If multiple columns of the same type are selected, most of the options are available to change, except formula, trigger formula and conditional styles. Editing column label or column id is disabled by default for multiple selection. Not related: some tests were fixed due to the change in the column label and id widget in grist-core (disabled attribute was replaced by readonly). Test Plan: Updated and new tests. Reviewers: georgegevoian Reviewed By: georgegevoian Differential Revision: https://phab.getgrist.com/D3598
127 lines
4.8 KiB
TypeScript
127 lines
4.8 KiB
TypeScript
import {DataRowModel} from 'app/client/models/DataRowModel';
|
|
import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
|
|
import {cssLabel, cssRow} from 'app/client/ui/RightPanelStyles';
|
|
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 {isFullReferencingType, isVersions} from 'app/common/gristTypes';
|
|
import {Computed, dom, styled} from 'grainjs';
|
|
|
|
/**
|
|
* Reference - The widget for displaying references to another table's records.
|
|
*/
|
|
export class Reference extends NTextBox {
|
|
private _visibleColRef: Computed<number>;
|
|
private _validCols: Computed<Array<IOptionFull<number>>>;
|
|
|
|
constructor(field: ViewFieldRec) {
|
|
super(field);
|
|
|
|
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: isFullReferencingType(use(col.type)) || use(col.isTransforming)
|
|
}))
|
|
.concat([{label: 'Row ID', value: 0, icon: 'FieldColumn'}]);
|
|
});
|
|
}
|
|
|
|
public buildConfigDom() {
|
|
return [
|
|
this.buildTransformConfigDom(),
|
|
cssLabel('CELL FORMAT'),
|
|
super.buildConfigDom()
|
|
];
|
|
}
|
|
|
|
public buildTransformConfigDom() {
|
|
const disabled = Computed.create(null, use => use(this.field.config.multiselect));
|
|
return [
|
|
cssLabel('SHOW COLUMN'),
|
|
cssRow(
|
|
dom.autoDispose(disabled),
|
|
select(this._visibleColRef, this._validCols, {
|
|
disabled
|
|
}),
|
|
testId('fbuilder-ref-col-select')
|
|
)
|
|
];
|
|
}
|
|
|
|
public buildDom(row: DataRowModel) {
|
|
// Note: we require 2 observables here because changes to the cell value (reference id)
|
|
// and the display value (display column) are not bundled. This can cause `formattedValue`
|
|
// to briefly display incorrect values (e.g. [Blank] when adding a reference to an empty cell)
|
|
// because the cell value changes before the display column has a chance to update.
|
|
//
|
|
// TODO: Look into a better solution (perhaps updating the display formula to return [Blank]).
|
|
const referenceId = Computed.create(null, (use) => {
|
|
const id = row.cells[use(this.field.colId)];
|
|
return id && use(id);
|
|
});
|
|
const formattedValue = Computed.create(null, (use) => {
|
|
let [value, hasBlankReference] = ['', false];
|
|
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 {value, hasBlankReference};
|
|
}
|
|
|
|
const displayValueObs = row.cells[use(use(this.field.displayColModel).colId)];
|
|
if (!displayValueObs) {
|
|
return {value, hasBlankReference};
|
|
}
|
|
|
|
const displayValue = use(displayValueObs);
|
|
value = isVersions(displayValue) ?
|
|
// 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.
|
|
use(this.field.formatter).formatAny(displayValue[1].local || displayValue[1].parent) :
|
|
use(this.field.formatter).formatAny(displayValue);
|
|
|
|
hasBlankReference = referenceId.get() !== 0 && value.trim() === '';
|
|
|
|
return {value, hasBlankReference};
|
|
});
|
|
|
|
return cssRef(
|
|
dom.autoDispose(formattedValue),
|
|
dom.autoDispose(referenceId),
|
|
cssRef.cls('-blank', use => use(formattedValue).hasBlankReference),
|
|
dom.style('text-align', this.alignment),
|
|
dom.cls('text_wrapping', this.wrapping),
|
|
cssRefIcon('FieldReference', testId('ref-link-icon')),
|
|
dom.text(use => {
|
|
if (use(referenceId) === 0) { return ''; }
|
|
if (use(formattedValue).hasBlankReference) { return '[Blank]'; }
|
|
return use(formattedValue).value;
|
|
})
|
|
);
|
|
}
|
|
}
|
|
|
|
const cssRefIcon = styled(icon, `
|
|
float: left;
|
|
background-color: ${colors.slate};
|
|
margin: -1px 2px 2px 0;
|
|
`);
|
|
|
|
const cssRef = styled('div.field_clip', `
|
|
&-blank {
|
|
color: ${colors.slate}
|
|
}
|
|
`);
|