(core) Add a Plus button below a rule set when there is no default rule

Summary:
- If you type into the "Everyone" / "Everyone Else" rule, and it stops being
  the default rule, there will now be an extra row with a "+" button to add a
  new default rule
- Switch to ACE-supported auto-resizing (for better scrollbars handling)
- Tweak ACE padding styles for better-looking scrolling.

Test Plan: Added a test case for the extra "+" button.

Reviewers: paulfitz

Reviewed By: paulfitz

Differential Revision: https://phab.getgrist.com/D2796
This commit is contained in:
Dmitry S 2021-05-03 11:58:29 -04:00
parent 2f26f140c8
commit 18268d7838
2 changed files with 30 additions and 19 deletions

View File

@ -18,9 +18,11 @@ export function aclFormulaEditor(options: ACLFormulaOptions) {
// Set various editor options. // Set various editor options.
editor.setTheme('ace/theme/chrome'); editor.setTheme('ace/theme/chrome');
editor.setOptions({enableLiveAutocompletion: true}); // ACE editor resizes automatically when maxLines is set.
editor.setOptions({enableLiveAutocompletion: true, maxLines: 10});
editor.renderer.setShowGutter(false); // Default line numbers to hidden editor.renderer.setShowGutter(false); // Default line numbers to hidden
editor.renderer.setPadding(0); editor.renderer.setPadding(5);
editor.renderer.setScrollMargin(4, 4, 0, 0);
editor.$blockScrolling = Infinity; editor.$blockScrolling = Infinity;
editor.setReadOnly(options.readOnly); editor.setReadOnly(options.readOnly);
editor.setFontSize('12'); editor.setFontSize('12');
@ -64,23 +66,9 @@ export function aclFormulaEditor(options: ACLFormulaOptions) {
// Disable Tab/Shift+Tab commands to restore their regular behavior. // Disable Tab/Shift+Tab commands to restore their regular behavior.
(editor.commands as any).removeCommands(['indent', 'outdent']); (editor.commands as any).removeCommands(['indent', 'outdent']);
function resize() {
if (editor.renderer.lineHeight === 0) {
// Reschedule the resize, since it's not ready yet. Seems to happen occasionally.
setTimeout(resize, 50);
}
editorElem.style.width = 'auto';
editorElem.style.height = (Math.max(1, session.getScreenLength()) * editor.renderer.lineHeight) + 'px';
editor.resize();
}
// Set the editor's initial value. // Set the editor's initial value.
editor.setValue(options.initialValue); editor.setValue(options.initialValue);
// Resize the editor on change, and initially once it's attached to the page.
editor.on('change', resize);
setTimeout(resize, 0);
return cssConditionInputAce( return cssConditionInputAce(
cssConditionInputAce.cls('-disabled', options.readOnly), cssConditionInputAce.cls('-disabled', options.readOnly),
dom.onDispose(() => editor.destroy()), dom.onDispose(() => editor.destroy()),
@ -91,7 +79,7 @@ export function aclFormulaEditor(options: ACLFormulaOptions) {
const cssConditionInputAce = styled('div', ` const cssConditionInputAce = styled('div', `
width: 100%; width: 100%;
min-height: 28px; min-height: 28px;
padding: 5px 6px 5px 6px; padding: 1px;
border-radius: 3px; border-radius: 3px;
border: 1px solid transparent; border: 1px solid transparent;
cursor: pointer; cursor: pointer;
@ -123,5 +111,6 @@ const cssConditionInputAce = styled('div', `
`); `);
const cssAcePlaceholder = styled('div', ` const cssAcePlaceholder = styled('div', `
padding: 4px 5px;
opacity: 0.5; opacity: 0.5;
`); `);

View File

@ -726,6 +726,18 @@ abstract class ObsRuleSet extends Disposable {
), ),
cssCell4(cssRuleBody.cls(''), cssCell4(cssRuleBody.cls(''),
dom.forEach(this._body, part => part.buildRulePartDom()), dom.forEach(this._body, part => part.buildRulePartDom()),
dom.maybe(use => !this.hasDefaultCondition(use), () =>
cssColumnGroup(
{style: 'min-height: 28px'},
cssCellIcon(
cssIconButton(icon('Plus'),
dom.on('click', () => this.addRulePart(null)),
testId('rule-add'),
)
),
testId('rule-extra-add'),
)
),
), ),
testId('rule-set'), testId('rule-set'),
); );
@ -738,8 +750,9 @@ abstract class ObsRuleSet extends Disposable {
} }
} }
public addRulePart(beforeRule: ObsRulePart) { public addRulePart(beforeRule: ObsRulePart|null) {
const i = this._body.get().indexOf(beforeRule); const body = this._body.get();
const i = beforeRule ? body.indexOf(beforeRule) : body.length;
this._body.splice(i, 0, ObsRulePart.create(this._body, this, undefined)); this._body.splice(i, 0, ObsRulePart.create(this._body, this, undefined));
} }
@ -768,6 +781,11 @@ abstract class ObsRuleSet extends Disposable {
return body[body.length - 1] === part; return body[body.length - 1] === part;
} }
public hasDefaultCondition(use: UseCB): boolean {
const body = use(this._body);
return body.length > 0 && body[body.length - 1].hasEmptyCondition(use);
}
/** /**
* Which permission bits to allow the user to set. * Which permission bits to allow the user to set.
*/ */
@ -1127,6 +1145,10 @@ class ObsRulePart extends Disposable {
}; };
} }
public hasEmptyCondition(use: UseCB): boolean {
return use(this._aclFormula) === '';
}
public matches(use: UseCB, aclFormula: string, permissionsText: string): boolean { public matches(use: UseCB, aclFormula: string, permissionsText: string): boolean {
return (use(this._aclFormula) === aclFormula && return (use(this._aclFormula) === aclFormula &&
permissionSetToText(use(this._permissions)) === permissionsText); permissionSetToText(use(this._permissions)) === permissionsText);