mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Support user variable in dropdown conditions
Summary: Dropdown conditions can now reference a `user` variable, similar to the one available in Access Rules. Test Plan: Browser test. Reviewers: jarek, paulfitz Reviewed By: jarek, paulfitz Differential Revision: https://phab.getgrist.com/D4255
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import {buildDropdownConditionEditor} from 'app/client/components/DropdownConditionEditor';
|
||||
import {GristDoc} from 'app/client/components/GristDoc';
|
||||
import {makeT} from 'app/client/lib/localization';
|
||||
import {ViewFieldRec} from 'app/client/models/DocModel';
|
||||
import {cssLabel, cssRow} from 'app/client/ui/RightPanelStyles';
|
||||
@@ -7,7 +8,9 @@ import {textButton } from 'app/client/ui2018/buttons';
|
||||
import {testId, theme} from 'app/client/ui2018/cssVars';
|
||||
import {ISuggestionWithValue} from 'app/common/ActiveDocAPI';
|
||||
import {getPredicateFormulaProperties} from 'app/common/PredicateFormula';
|
||||
import {UserInfo} from 'app/common/User';
|
||||
import {Computed, Disposable, dom, Observable, styled} from 'grainjs';
|
||||
import isPlainObject from 'lodash/isPlainObject';
|
||||
|
||||
const t = makeT('DropdownConditionConfig');
|
||||
|
||||
@@ -99,7 +102,7 @@ export class DropdownConditionConfig extends Disposable {
|
||||
|
||||
private _editorElement: HTMLElement;
|
||||
|
||||
constructor(private _field: ViewFieldRec) {
|
||||
constructor(private _field: ViewFieldRec, private _gristDoc: GristDoc) {
|
||||
super();
|
||||
|
||||
this.autoDispose(this._text.addListener(() => {
|
||||
@@ -167,6 +170,10 @@ export class DropdownConditionConfig extends Disposable {
|
||||
|
||||
private _getAutocompleteSuggestions(): ISuggestionWithValue[] {
|
||||
const variables = ['choice'];
|
||||
const user = this._gristDoc.docPageModel.user.get();
|
||||
if (user) {
|
||||
variables.push(...getUserCompletions(user));
|
||||
}
|
||||
const refColumns = this._refColumns.get();
|
||||
if (refColumns) {
|
||||
variables.push('choice.id', ...refColumns.map(({colId}) => `choice.${colId.peek()}`));
|
||||
@@ -176,7 +183,6 @@ export class DropdownConditionConfig extends Disposable {
|
||||
...columns.map(({colId}) => `$${colId.peek()}`),
|
||||
...columns.map(({colId}) => `rec.${colId.peek()}`),
|
||||
);
|
||||
|
||||
const suggestions = [
|
||||
'and', 'or', 'not', 'in', 'is', 'True', 'False', 'None',
|
||||
'OWNER', 'EDITOR', 'VIEWER',
|
||||
@@ -186,6 +192,20 @@ export class DropdownConditionConfig extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
function getUserCompletions(user: UserInfo) {
|
||||
return Object.entries(user).flatMap(([key, value]) => {
|
||||
if (key === 'LinkKey') {
|
||||
return 'user.LinkKey.';
|
||||
} else if (isPlainObject(value)) {
|
||||
return Object.keys(value as {[key: string]: any})
|
||||
.filter(valueKey => valueKey !== 'manualSort')
|
||||
.map(valueKey => `user.${key}.${valueKey}`);
|
||||
} else {
|
||||
return `user.${key}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const cssSetDropdownConditionRow = styled(cssRow, `
|
||||
margin-top: 16px;
|
||||
`);
|
||||
|
||||
@@ -63,7 +63,7 @@ export class TypeTransform extends ColumnTransform {
|
||||
if (use(this._isFormWidget)) {
|
||||
return transformWidget.buildFormTransformConfigDom();
|
||||
} else {
|
||||
return transformWidget.buildTransformConfigDom();
|
||||
return transformWidget.buildTransformConfigDom(this.gristDoc);
|
||||
}
|
||||
}),
|
||||
dom.maybe(this._reviseTypeChange, () =>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import {GristDoc} from 'app/client/components/GristDoc';
|
||||
import {ACIndex, ACResults} from 'app/client/lib/ACIndex';
|
||||
import {makeT} from 'app/client/lib/localization';
|
||||
import {ICellItem} from 'app/client/models/ColumnACIndexes';
|
||||
import {ColumnCache} from 'app/client/models/ColumnCache';
|
||||
import {DocData} from 'app/client/models/DocData';
|
||||
import {ColumnRec} from 'app/client/models/entities/ColumnRec';
|
||||
import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
|
||||
import {TableData} from 'app/client/models/TableData';
|
||||
import {getReferencedTableId, isRefListType} from 'app/common/gristTypes';
|
||||
import {EmptyRecordView} from 'app/common/PredicateFormula';
|
||||
import {EmptyRecordView} from 'app/common/RecordView';
|
||||
import {BaseFormatter} from 'app/common/ValueFormatter';
|
||||
import {Disposable, dom, Observable} from 'grainjs';
|
||||
|
||||
@@ -26,9 +26,10 @@ export class ReferenceUtils extends Disposable {
|
||||
public readonly hasDropdownCondition = Boolean(this.field.dropdownCondition.peek()?.text);
|
||||
|
||||
private readonly _columnCache: ColumnCache<ACIndex<ICellItem>>;
|
||||
private readonly _docData = this._gristDoc.docData;
|
||||
private _dropdownConditionError = Observable.create<string | null>(this, null);
|
||||
|
||||
constructor(public readonly field: ViewFieldRec, private readonly _docData: DocData) {
|
||||
constructor(public readonly field: ViewFieldRec, private readonly _gristDoc: GristDoc) {
|
||||
super();
|
||||
|
||||
const colType = field.column().type();
|
||||
@@ -38,7 +39,7 @@ export class ReferenceUtils extends Disposable {
|
||||
}
|
||||
this.refTableId = refTableId;
|
||||
|
||||
const tableData = _docData.getTable(refTableId);
|
||||
const tableData = this._docData.getTable(refTableId);
|
||||
if (!tableData) {
|
||||
throw new Error("Invalid referenced table " + refTableId);
|
||||
}
|
||||
@@ -131,12 +132,13 @@ export class ReferenceUtils extends Disposable {
|
||||
if (!table) { throw new Error(`Table ${tableId} not found`); }
|
||||
|
||||
const {result: predicate} = dropdownConditionCompiled;
|
||||
const user = this._gristDoc.docPageModel.user.get() ?? undefined;
|
||||
const rec = table.getRecord(rowId) || new EmptyRecordView();
|
||||
return (item: ICellItem) => {
|
||||
const choice = item.rowId === 'new' ? new EmptyRecordView() : this.tableData.getRecord(item.rowId);
|
||||
if (!choice) { throw new Error(`Reference ${item.rowId} not found`); }
|
||||
|
||||
return predicate({rec, choice});
|
||||
return predicate({user, rec, choice});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import {Features, mergedFeatures, Product} from 'app/common/Features';
|
||||
import {buildUrlId, IGristUrlState, parseUrlId, UrlIdParts} from 'app/common/gristUrls';
|
||||
import {getReconnectTimeout} from 'app/common/gutil';
|
||||
import {canEdit, isOwner} from 'app/common/roles';
|
||||
import {UserInfo} from 'app/common/User';
|
||||
import {Document, NEW_DOCUMENT_CODE, Organization, UserAPI, Workspace} from 'app/common/UserAPI';
|
||||
import {Holder, Observable, subscribe} from 'grainjs';
|
||||
import {Computed, Disposable, dom, DomArg, DomElementArg} from 'grainjs';
|
||||
@@ -38,6 +39,7 @@ export interface DocInfo extends Document {
|
||||
isPreFork: boolean;
|
||||
isFork: boolean;
|
||||
isRecoveryMode: boolean;
|
||||
user: UserInfo|null;
|
||||
userOverride: UserOverride|null;
|
||||
isBareFork: boolean; // a document created without logging in, which is treated as a
|
||||
// fork without an original.
|
||||
@@ -78,6 +80,7 @@ export interface DocPageModel {
|
||||
isPrefork: Observable<boolean>;
|
||||
isFork: Observable<boolean>;
|
||||
isRecoveryMode: Observable<boolean>;
|
||||
user: Observable<UserInfo|null>;
|
||||
userOverride: Observable<UserOverride|null>;
|
||||
isBareFork: Observable<boolean>;
|
||||
isSnapshot: Observable<boolean>;
|
||||
@@ -134,6 +137,7 @@ export class DocPageModelImpl extends Disposable implements DocPageModel {
|
||||
public readonly isFork = Computed.create(this, this.currentDoc, (use, doc) => doc ? doc.isFork : false);
|
||||
public readonly isRecoveryMode = Computed.create(this, this.currentDoc,
|
||||
(use, doc) => doc ? doc.isRecoveryMode : false);
|
||||
public readonly user = Computed.create(this, this.currentDoc, (use, doc) => doc ? doc.user : null);
|
||||
public readonly userOverride = Computed.create(this, this.currentDoc, (use, doc) => doc ? doc.userOverride : null);
|
||||
public readonly isBareFork = Computed.create(this, this.currentDoc, (use, doc) => doc ? doc.isBareFork : false);
|
||||
public readonly isSnapshot = Computed.create(this, this.currentDoc, (use, doc) => doc ? doc.isSnapshot : false);
|
||||
@@ -265,8 +269,9 @@ export class DocPageModelImpl extends Disposable implements DocPageModel {
|
||||
// TODO It would be bad if a new doc gets opened while this getDoc() is pending...
|
||||
const newDoc = await getDoc(this._api, urlId);
|
||||
const isRecoveryMode = Boolean(this.currentDoc.get()?.isRecoveryMode);
|
||||
const user = this.currentDoc.get()?.user || null;
|
||||
const userOverride = this.currentDoc.get()?.userOverride || null;
|
||||
this.currentDoc.set({...buildDocInfo(newDoc, openMode), isRecoveryMode, userOverride});
|
||||
this.currentDoc.set({...buildDocInfo(newDoc, openMode), isRecoveryMode, user, userOverride});
|
||||
return newDoc;
|
||||
}
|
||||
|
||||
@@ -407,11 +412,13 @@ It also disables formulas. [{{error}}]", {error: err.message})
|
||||
linkParameters,
|
||||
originalUrlId: options.originalUrlId,
|
||||
});
|
||||
if (openDocResponse.recoveryMode || openDocResponse.userOverride) {
|
||||
doc.isRecoveryMode = Boolean(openDocResponse.recoveryMode);
|
||||
doc.userOverride = openDocResponse.userOverride || null;
|
||||
this.currentDoc.set({...doc});
|
||||
const {user, recoveryMode, userOverride} = openDocResponse;
|
||||
doc.user = user;
|
||||
if (recoveryMode || userOverride) {
|
||||
doc.isRecoveryMode = Boolean(recoveryMode);
|
||||
doc.userOverride = userOverride || null;
|
||||
}
|
||||
this.currentDoc.set({...doc});
|
||||
if (openDocResponse.docUsage) {
|
||||
this.updateCurrentDocUsage(openDocResponse.docUsage);
|
||||
}
|
||||
@@ -520,6 +527,7 @@ function buildDocInfo(doc: Document, mode: OpenDocMode | undefined): DocInfo {
|
||||
...doc,
|
||||
isFork,
|
||||
isRecoveryMode: false, // we don't know yet, will learn when doc is opened.
|
||||
user: null, // ditto.
|
||||
userOverride: null, // ditto.
|
||||
isPreFork,
|
||||
isBareFork,
|
||||
|
||||
@@ -21,7 +21,7 @@ dispose.makeDisposable(AbstractWidget);
|
||||
/**
|
||||
* Builds the DOM showing configuration buttons and fields in the sidebar.
|
||||
*/
|
||||
AbstractWidget.prototype.buildConfigDom = function() {
|
||||
AbstractWidget.prototype.buildConfigDom = function(_gristDoc) {
|
||||
throw new Error("Not Implemented");
|
||||
};
|
||||
|
||||
@@ -29,7 +29,7 @@ AbstractWidget.prototype.buildConfigDom = function() {
|
||||
* 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.
|
||||
*/
|
||||
AbstractWidget.prototype.buildTransformConfigDom = function() {
|
||||
AbstractWidget.prototype.buildTransformConfigDom = function(_gristDoc) {
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ ChoiceEditor.prototype.buildDropdownConditionFilter = function() {
|
||||
|
||||
return buildDropdownConditionFilter({
|
||||
dropdownConditionCompiled: dropdownConditionCompiled.result,
|
||||
docData: this.options.gristDoc.docData,
|
||||
gristDoc: this.options.gristDoc,
|
||||
tableId: this.options.field.tableId(),
|
||||
rowId: this.options.rowId,
|
||||
});
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import {createGroup} from 'app/client/components/commands';
|
||||
import {GristDoc} from 'app/client/components/GristDoc';
|
||||
import {ACIndexImpl, ACItem, ACResults,
|
||||
buildHighlightedDom, HighlightFunc, normalizeText} from 'app/client/lib/ACIndex';
|
||||
import {IAutocompleteOptions} from 'app/client/lib/autocomplete';
|
||||
import {makeT} from 'app/client/lib/localization';
|
||||
import {IToken, TokenField, tokenFieldStyles} from 'app/client/lib/TokenField';
|
||||
import {DocData} from 'app/client/models/DocData';
|
||||
import {colors, testId, theme} from 'app/client/ui2018/cssVars';
|
||||
import {menuCssClass} from 'app/client/ui2018/menus';
|
||||
import {createMobileButtons, getButtonMargins} from 'app/client/widgets/EditorButtons';
|
||||
@@ -12,7 +12,8 @@ import {EditorPlacement} from 'app/client/widgets/EditorPlacement';
|
||||
import {FieldOptions, NewBaseEditor} from 'app/client/widgets/NewBaseEditor';
|
||||
import {csvEncodeRow} from 'app/common/csvFormat';
|
||||
import {CellValue} from "app/common/DocActions";
|
||||
import {CompiledPredicateFormula, EmptyRecordView} from 'app/common/PredicateFormula';
|
||||
import {CompiledPredicateFormula} from 'app/common/PredicateFormula';
|
||||
import {EmptyRecordView} from 'app/common/RecordView';
|
||||
import {decodeObject, encodeObject} from 'app/plugin/objtypes';
|
||||
import {ChoiceOptions, getRenderFillColor, getRenderTextColor} from 'app/client/widgets/ChoiceTextBox';
|
||||
import {choiceToken, cssChoiceACItem, cssChoiceToken} from 'app/client/widgets/ChoiceToken';
|
||||
@@ -246,7 +247,7 @@ export class ChoiceListEditor extends NewBaseEditor {
|
||||
|
||||
return buildDropdownConditionFilter({
|
||||
dropdownConditionCompiled: dropdownConditionCompiled.result,
|
||||
docData: this.options.gristDoc.docData,
|
||||
gristDoc: this.options.gristDoc,
|
||||
tableId: this.options.field.tableId(),
|
||||
rowId: this.options.rowId,
|
||||
});
|
||||
@@ -311,7 +312,7 @@ export class ChoiceListEditor extends NewBaseEditor {
|
||||
|
||||
export interface GetACFilterFuncParams {
|
||||
dropdownConditionCompiled: CompiledPredicateFormula;
|
||||
docData: DocData;
|
||||
gristDoc: GristDoc;
|
||||
tableId: string;
|
||||
rowId: number;
|
||||
}
|
||||
@@ -319,12 +320,13 @@ export interface GetACFilterFuncParams {
|
||||
export function buildDropdownConditionFilter(
|
||||
params: GetACFilterFuncParams
|
||||
): (item: ChoiceItem) => boolean {
|
||||
const {dropdownConditionCompiled, docData, tableId, rowId} = params;
|
||||
const table = docData.getTable(tableId);
|
||||
const {dropdownConditionCompiled, gristDoc, tableId, rowId} = params;
|
||||
const table = gristDoc.docData.getTable(tableId);
|
||||
if (!table) { throw new Error(`Table ${tableId} not found`); }
|
||||
|
||||
const user = gristDoc.docPageModel.user.get() ?? undefined;
|
||||
const rec = table.getRecord(rowId) || new EmptyRecordView();
|
||||
return (item: ChoiceItem) => dropdownConditionCompiled({rec, choice: item.label});
|
||||
return (item: ChoiceItem) => dropdownConditionCompiled({user, rec, choice: item.label});
|
||||
}
|
||||
|
||||
const cssCellEditor = styled('div', `
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
FormSelectConfig,
|
||||
} from 'app/client/components/Forms/FormConfig';
|
||||
import {DropdownConditionConfig} from 'app/client/components/DropdownConditionConfig';
|
||||
import {GristDoc} from 'app/client/components/GristDoc';
|
||||
import {makeT} from 'app/client/lib/localization';
|
||||
import {DataRowModel} from 'app/client/models/DataRowModel';
|
||||
import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
|
||||
@@ -79,17 +80,17 @@ export class ChoiceTextBox extends NTextBox {
|
||||
);
|
||||
}
|
||||
|
||||
public buildConfigDom() {
|
||||
public buildConfigDom(gristDoc: GristDoc) {
|
||||
return [
|
||||
super.buildConfigDom(),
|
||||
super.buildConfigDom(gristDoc),
|
||||
this.buildChoicesConfigDom(),
|
||||
dom.create(DropdownConditionConfig, this.field),
|
||||
dom.create(DropdownConditionConfig, this.field, gristDoc),
|
||||
];
|
||||
}
|
||||
|
||||
public buildTransformConfigDom() {
|
||||
public buildTransformConfigDom(gristDoc: GristDoc) {
|
||||
return [
|
||||
super.buildConfigDom(),
|
||||
super.buildConfigDom(gristDoc),
|
||||
this.buildChoicesConfigDom(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ _.extend(DateTimeTextBox.prototype, DateTextBox.prototype);
|
||||
* Builds the config dom for the DateTime TextBox. If isTransformConfig is true,
|
||||
* builds only the necessary dom for the transform config menu.
|
||||
*/
|
||||
DateTimeTextBox.prototype.buildConfigDom = function(isTransformConfig) {
|
||||
DateTimeTextBox.prototype.buildConfigDom = function(_gristDoc, isTransformConfig) {
|
||||
const disabled = ko.pureComputed(() => {
|
||||
return this.field.config.options.disabled('timeFormat')() || this.field.column().disableEditData();
|
||||
});
|
||||
@@ -92,8 +92,8 @@ DateTimeTextBox.prototype.buildConfigDom = function(isTransformConfig) {
|
||||
);
|
||||
};
|
||||
|
||||
DateTimeTextBox.prototype.buildTransformConfigDom = function() {
|
||||
return this.buildConfigDom(true);
|
||||
DateTimeTextBox.prototype.buildTransformConfigDom = function(gristDoc) {
|
||||
return this.buildConfigDom(gristDoc, true);
|
||||
};
|
||||
|
||||
// clean up old koform styles
|
||||
|
||||
@@ -499,7 +499,7 @@ export class FieldBuilder extends Disposable {
|
||||
// the dom created by the widgetImpl to get out of sync.
|
||||
return dom('div',
|
||||
kd.maybe(() => !this._isTransformingType() && this.widgetImpl(), (widget: NewAbstractWidget) =>
|
||||
dom('div', widget.buildConfigDom())
|
||||
dom('div', widget.buildConfigDom(this.gristDoc))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FormFieldRulesConfig } from 'app/client/components/Forms/FormConfig';
|
||||
import { GristDoc } from 'app/client/components/GristDoc';
|
||||
import { fromKoSave } from 'app/client/lib/fromKoSave';
|
||||
import { makeT } from 'app/client/lib/localization';
|
||||
import { DataRowModel } from 'app/client/models/DataRowModel';
|
||||
@@ -32,7 +33,7 @@ export class NTextBox extends NewAbstractWidget {
|
||||
}));
|
||||
}
|
||||
|
||||
public buildConfigDom(): DomContents {
|
||||
public buildConfigDom(_gristDoc: GristDoc): DomContents {
|
||||
const toggle = () => {
|
||||
const newValue = !this.field.config.wrap.peek();
|
||||
this.field.config.wrap.setAndSave(newValue).catch(reportError);
|
||||
|
||||
@@ -60,7 +60,7 @@ export abstract class NewAbstractWidget extends Disposable {
|
||||
/**
|
||||
* Builds the DOM showing configuration buttons and fields in the sidebar.
|
||||
*/
|
||||
public buildConfigDom(): DomContents {
|
||||
public buildConfigDom(_gristDoc: GristDoc): DomContents {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ export abstract class NewAbstractWidget extends Disposable {
|
||||
* 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 {
|
||||
public buildTransformConfigDom(_gristDoc: GristDoc): DomContents {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* See app/common/NumberFormat for description of options we support.
|
||||
*/
|
||||
import {FormFieldRulesConfig} from 'app/client/components/Forms/FormConfig';
|
||||
import {GristDoc} from 'app/client/components/GristDoc';
|
||||
import {fromKoSave} from 'app/client/lib/fromKoSave';
|
||||
import {makeT} from 'app/client/lib/localization';
|
||||
import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
|
||||
@@ -39,7 +40,7 @@ export class NumericTextBox extends NTextBox {
|
||||
super(field);
|
||||
}
|
||||
|
||||
public buildConfigDom(): DomContents {
|
||||
public buildConfigDom(gristDoc: GristDoc): DomContents {
|
||||
// Holder for all computeds created here. It gets disposed with the returned DOM element.
|
||||
const holder = new MultiHolder();
|
||||
|
||||
@@ -89,7 +90,7 @@ export class NumericTextBox extends NTextBox {
|
||||
const disabledStyle = cssButtonSelect.cls('-disabled', disabled);
|
||||
|
||||
return [
|
||||
super.buildConfigDom(),
|
||||
super.buildConfigDom(gristDoc),
|
||||
cssLabel(t('Number Format')),
|
||||
cssRow(
|
||||
dom.autoDispose(holder),
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
FormSelectConfig
|
||||
} from 'app/client/components/Forms/FormConfig';
|
||||
import {DropdownConditionConfig} from 'app/client/components/DropdownConditionConfig';
|
||||
import {GristDoc} from 'app/client/components/GristDoc';
|
||||
import {makeT} from 'app/client/lib/localization';
|
||||
import {DataRowModel} from 'app/client/models/DataRowModel';
|
||||
import {TableRec} from 'app/client/models/DocModel';
|
||||
@@ -53,12 +54,12 @@ export class Reference extends NTextBox {
|
||||
});
|
||||
}
|
||||
|
||||
public buildConfigDom() {
|
||||
public buildConfigDom(gristDoc: GristDoc) {
|
||||
return [
|
||||
this.buildTransformConfigDom(),
|
||||
dom.create(DropdownConditionConfig, this.field),
|
||||
dom.create(DropdownConditionConfig, this.field, gristDoc),
|
||||
cssLabel(t('CELL FORMAT')),
|
||||
super.buildConfigDom(),
|
||||
super.buildConfigDom(gristDoc),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ export class ReferenceEditor extends NTextEditor {
|
||||
constructor(options: FieldOptions) {
|
||||
super(options);
|
||||
|
||||
const docData = options.gristDoc.docData;
|
||||
this._utils = new ReferenceUtils(options.field, docData);
|
||||
const gristDoc = options.gristDoc;
|
||||
this._utils = new ReferenceUtils(options.field, gristDoc);
|
||||
|
||||
const vcol = this._utils.visibleColModel;
|
||||
this._enableAddNew = (
|
||||
@@ -47,7 +47,7 @@ export class ReferenceEditor extends NTextEditor {
|
||||
|
||||
// The referenced table has probably already been fetched (because there must already be a
|
||||
// Reference widget instantiated), but it's better to avoid this assumption.
|
||||
docData.fetchTable(this._utils.refTableId).then(() => {
|
||||
gristDoc.docData.fetchTable(this._utils.refTableId).then(() => {
|
||||
if (this.isDisposed()) { return; }
|
||||
if (needReload && this.textInput.value === '') {
|
||||
this.textInput.value = undef(options.state, options.editValue, this._idToText());
|
||||
|
||||
@@ -55,8 +55,8 @@ export class ReferenceListEditor extends NewBaseEditor {
|
||||
constructor(protected options: FieldOptions) {
|
||||
super(options);
|
||||
|
||||
const docData = options.gristDoc.docData;
|
||||
this._utils = new ReferenceUtils(options.field, docData);
|
||||
const gristDoc = options.gristDoc;
|
||||
this._utils = new ReferenceUtils(options.field, gristDoc);
|
||||
|
||||
const vcol = this._utils.visibleColModel;
|
||||
this._enableAddNew = (
|
||||
@@ -130,7 +130,7 @@ export class ReferenceListEditor extends NewBaseEditor {
|
||||
|
||||
// The referenced table has probably already been fetched (because there must already be a
|
||||
// Reference widget instantiated), but it's better to avoid this assumption.
|
||||
docData.fetchTable(this._utils.refTableId).then(() => {
|
||||
gristDoc.docData.fetchTable(this._utils.refTableId).then(() => {
|
||||
if (this.isDisposed()) { return; }
|
||||
if (needReload) {
|
||||
this._tokenField.setTokens(
|
||||
|
||||
Reference in New Issue
Block a user