diff --git a/app/client/aclui/AccessRules.ts b/app/client/aclui/AccessRules.ts index aa1745f9..4a3a208a 100644 --- a/app/client/aclui/AccessRules.ts +++ b/app/client/aclui/AccessRules.ts @@ -11,6 +11,7 @@ import {GristDoc} from 'app/client/components/GristDoc'; import {logTelemetryEvent} from 'app/client/lib/telemetry'; import {reportError, UserError} from 'app/client/models/errors'; import {TableData} from 'app/client/models/TableData'; +import {withInfoTooltip} from 'app/client/ui/tooltips'; import {shadowScroll} from 'app/client/ui/shadowScroll'; import {bigBasicButton, bigPrimaryButton} from 'app/client/ui2018/buttons'; import {squareCheckbox} from 'app/client/ui2018/checkbox'; @@ -690,8 +691,7 @@ class TableRules extends Disposable { cssIconButton(icon('Dots'), {style: 'margin-left: auto'}, menu(() => [ menuItemAsync(() => this._addColumnRuleSet(), t("Add Column Rule")), - menuItemAsync(() => this._addDefaultRuleSet(), t("Add Default Rule"), - dom.cls('disabled', use => Boolean(use(this._defaultRuleSet)))), + menuItemAsync(() => this._addDefaultRuleSet(), t("Add Table-wide Rule")), menuItemAsync(() => this._accessRules.removeTableRules(this), t("Delete Table Rules")), ]), testId('rule-table-menu-btn'), @@ -813,9 +813,13 @@ class TableRules extends Disposable { } private _addDefaultRuleSet() { - if (!this._defaultRuleSet.get()) { + const ruleSet = this._defaultRuleSet.get(); + if (!ruleSet) { DefaultObsRuleSet.create(this._defaultRuleSet, this._accessRules, this, this._haveColumnRules); this.addDefaultRules(this._accessRules.getSeedRules()); + } else { + const part = ruleSet.addRulePart(ruleSet.getDefaultCondition()); + setTimeout(() => part.focusEditor?.(), 0); } } } @@ -1034,6 +1038,12 @@ abstract class ObsRuleSet extends Disposable { return body.length > 0 && body[body.length - 1].hasEmptyCondition(use); } + public getDefaultCondition(): ObsRulePart|null { + const body = this._body.get(); + const last = body.length > 0 ? body[body.length - 1] : null; + return last?.hasEmptyCondition(unwrap) ? last : null; + } + /** * Which permission bits to allow the user to set. */ @@ -1129,8 +1139,9 @@ class DefaultObsRuleSet extends ObsRuleSet { return [ cssCenterContent.cls(''), cssDefaultLabel( - dom.text(use => this._haveColumnRules && use(this._haveColumnRules) ? 'All Other' : 'All'), - ) + dom.domComputed(use => this._haveColumnRules && use(this._haveColumnRules), (haveColRules) => + haveColRules ? withInfoTooltip('All', 'accessRulesTableWide') : 'All') + ), ]; } } @@ -1544,6 +1555,8 @@ class ObsRulePart extends Disposable { // Whether the rule part, and if it's valid or being checked. public ruleStatus: Computed; + public focusEditor: (() => void)|undefined; + // Formula to show in the formula editor. private _aclFormula = Observable.create(this, this._rulePart?.aclFormula || ""); @@ -1679,6 +1692,7 @@ class ObsRulePart extends Disposable { ); }), getSuggestions: (prefix) => this._completions.get(), + customiseEditor: (editor) => { this.focusEditor = () => editor.focus(); }, }), testId('rule-acl-formula'), ), diff --git a/app/client/ui/GristTooltips.ts b/app/client/ui/GristTooltips.ts index f1a7f18c..fe67d075 100644 --- a/app/client/ui/GristTooltips.ts +++ b/app/client/ui/GristTooltips.ts @@ -50,7 +50,8 @@ export type Tooltip = | 'addColumnConditionalStyle' | 'uuid' | 'lookups' - | 'formulaColumn'; + | 'formulaColumn' + | 'accessRulesTableWide'; export type TooltipContentFunc = (...domArgs: DomElementArg[]) => DomContents; @@ -135,6 +136,9 @@ see or edit which parts of your document.') ), ...args, ), + accessRulesTableWide: (...args: DomElementArg[]) => cssTooltipContent( + dom('div', t('These rules are applied after all column rules have been processed, if applicable.')) + ), }; export interface BehavioralPromptContent {