(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:
George Gevoian
2024-05-29 14:55:21 -07:00
parent 50077540e2
commit 72066bf0e4
27 changed files with 426 additions and 268 deletions

View File

@@ -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;
`);

View File

@@ -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, () =>