mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) Disable formula timing UI for non-owners
Summary: For non-owners, the timing section of Document Settings is now disabled. For non-editors, the "Reload" section is disabled. Test Plan: Added a test case for timing being disabled. Reviewers: jarek Reviewed By: jarek Differential Revision: https://phab.getgrist.com/D4275
This commit is contained in:
parent
76d94483ad
commit
51a34835c5
@ -1,3 +1,4 @@
|
|||||||
|
import {hoverTooltip} from 'app/client/ui/tooltips';
|
||||||
import {transition} from 'app/client/ui/transitions';
|
import {transition} from 'app/client/ui/transitions';
|
||||||
import {toggle} from 'app/client/ui2018/checkbox';
|
import {toggle} from 'app/client/ui2018/checkbox';
|
||||||
import {mediaSmall, testId, theme, vars} from 'app/client/ui2018/cssVars';
|
import {mediaSmall, testId, theme, vars} from 'app/client/ui2018/cssVars';
|
||||||
@ -21,6 +22,7 @@ export function AdminSectionItem(owner: IDisposableOwner, options: {
|
|||||||
description?: DomContents,
|
description?: DomContents,
|
||||||
value?: DomContents,
|
value?: DomContents,
|
||||||
expandedContent?: DomContents,
|
expandedContent?: DomContents,
|
||||||
|
disabled?: false|string,
|
||||||
}) {
|
}) {
|
||||||
const itemContent = (...prefix: DomContents[]) => [
|
const itemContent = (...prefix: DomContents[]) => [
|
||||||
cssItemName(
|
cssItemName(
|
||||||
@ -34,7 +36,7 @@ export function AdminSectionItem(owner: IDisposableOwner, options: {
|
|||||||
testId(`admin-panel-item-value-${options.id}`),
|
testId(`admin-panel-item-value-${options.id}`),
|
||||||
dom.on('click', ev => ev.stopPropagation())),
|
dom.on('click', ev => ev.stopPropagation())),
|
||||||
];
|
];
|
||||||
if (options.expandedContent) {
|
if (options.expandedContent && !options.disabled) {
|
||||||
const isCollapsed = Observable.create(owner, true);
|
const isCollapsed = Observable.create(owner, true);
|
||||||
return cssItem(
|
return cssItem(
|
||||||
cssItemShort(
|
cssItemShort(
|
||||||
@ -56,7 +58,13 @@ export function AdminSectionItem(owner: IDisposableOwner, options: {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return cssItem(
|
return cssItem(
|
||||||
cssItemShort(itemContent()),
|
cssItemShort(itemContent(),
|
||||||
|
cssItemShort.cls('-disabled', Boolean(options.disabled)),
|
||||||
|
options.disabled ? hoverTooltip(options.disabled, {
|
||||||
|
placement: 'bottom-end',
|
||||||
|
modifiers: {offset: {offset: '0, -10'}},
|
||||||
|
}) : null,
|
||||||
|
),
|
||||||
testId(`admin-panel-item-${options.id}`),
|
testId(`admin-panel-item-${options.id}`),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -109,6 +117,9 @@ const cssItemShort = styled('div', `
|
|||||||
&-expandable:hover {
|
&-expandable:hover {
|
||||||
background-color: ${theme.lightHover};
|
background-color: ${theme.lightHover};
|
||||||
}
|
}
|
||||||
|
&-disabled {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
|
||||||
@container line (max-width: 500px) {
|
@container line (max-width: 500px) {
|
||||||
& {
|
& {
|
||||||
@ -157,6 +168,10 @@ const cssItemValue = styled('div', `
|
|||||||
margin: -16px;
|
margin: -16px;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
cursor: auto;
|
cursor: auto;
|
||||||
|
|
||||||
|
.${cssItemShort.className}-disabled & {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const cssCollapseIcon = styled(icon, `
|
const cssCollapseIcon = styled(icon, `
|
||||||
|
@ -28,6 +28,7 @@ import {EngineCode} from 'app/common/DocumentSettings';
|
|||||||
import {commonUrls, GristLoadConfig} from 'app/common/gristUrls';
|
import {commonUrls, GristLoadConfig} from 'app/common/gristUrls';
|
||||||
import {not, propertyCompare} from 'app/common/gutil';
|
import {not, propertyCompare} from 'app/common/gutil';
|
||||||
import {getCurrency, locales} from 'app/common/Locales';
|
import {getCurrency, locales} from 'app/common/Locales';
|
||||||
|
import {isOwner, isOwnerOrEditor} from 'app/common/roles';
|
||||||
import {Computed, Disposable, dom, fromKo, IDisposableOwner, makeTestId, Observable, styled} from 'grainjs';
|
import {Computed, Disposable, dom, fromKo, IDisposableOwner, makeTestId, Observable, styled} from 'grainjs';
|
||||||
import * as moment from 'moment-timezone';
|
import * as moment from 'moment-timezone';
|
||||||
|
|
||||||
@ -58,6 +59,8 @@ export class DocSettingsPage extends Disposable {
|
|||||||
const canChangeEngine = getSupportedEngineChoices().length > 0;
|
const canChangeEngine = getSupportedEngineChoices().length > 0;
|
||||||
const docPageModel = this._gristDoc.docPageModel;
|
const docPageModel = this._gristDoc.docPageModel;
|
||||||
const isTimingOn = this._gristDoc.isTimingOn;
|
const isTimingOn = this._gristDoc.isTimingOn;
|
||||||
|
const isDocOwner = isOwner(docPageModel.currentDoc.get());
|
||||||
|
const isDocEditor = isOwnerOrEditor(docPageModel.currentDoc.get());
|
||||||
|
|
||||||
return cssContainer(
|
return cssContainer(
|
||||||
dom.create(AdminSection, t('Document Settings'), [
|
dom.create(AdminSection, t('Document Settings'), [
|
||||||
@ -115,6 +118,7 @@ export class DocSettingsPage extends Disposable {
|
|||||||
'This allows diagnosing which formulas are responsible for slow performance when a ' +
|
'This allows diagnosing which formulas are responsible for slow performance when a ' +
|
||||||
'document is first opened, or when a document responds to changes.'
|
'document is first opened, or when a document responds to changes.'
|
||||||
)),
|
)),
|
||||||
|
disabled: isDocOwner ? false : t('Only available to document owners'),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
dom.create(AdminSectionItem, {
|
dom.create(AdminSectionItem, {
|
||||||
@ -122,6 +126,7 @@ export class DocSettingsPage extends Disposable {
|
|||||||
name: t('Reload'),
|
name: t('Reload'),
|
||||||
description: t('Hard reset of data engine'),
|
description: t('Hard reset of data engine'),
|
||||||
value: cssSmallButton(t('Reload data engine'), dom.on('click', this._reloadEngine.bind(this, true))),
|
value: cssSmallButton(t('Reload data engine'), dom.on('click', this._reloadEngine.bind(this, true))),
|
||||||
|
disabled: isDocEditor ? false : t('Only available to document editors'),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
canChangeEngine ? dom.create(AdminSectionItem, {
|
canChangeEngine ? dom.create(AdminSectionItem, {
|
||||||
|
@ -166,6 +166,30 @@ describe("Timing", function () {
|
|||||||
await driver.findWait('.test-raw-data-list', 2000);
|
await driver.findWait('.test-raw-data-list', 2000);
|
||||||
assert.deepEqual(await driver.findAll('.test-raw-data-table-id', e => e.getText()), ['Table1']);
|
assert.deepEqual(await driver.findAll('.test-raw-data-table-id', e => e.getText()), ['Table1']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should be disabled for non-owners', async function() {
|
||||||
|
await userApi.updateDocPermissions(docId, {users: {
|
||||||
|
[gu.translateUser('user2').email]: 'editors',
|
||||||
|
}});
|
||||||
|
|
||||||
|
const session = await gu.session().teamSite.user('user2').login();
|
||||||
|
await session.loadDoc(`/doc/${docId}`);
|
||||||
|
await gu.openDocumentSettings();
|
||||||
|
|
||||||
|
const start = driver.find('.test-settings-timing-start');
|
||||||
|
assert.equal(await start.isPresent(), true);
|
||||||
|
|
||||||
|
// Check that we have an informative tooltip.
|
||||||
|
await start.mouseMove();
|
||||||
|
assert.match(await driver.findWait('.test-tooltip', 2000).getText(), /Only available to document owners/);
|
||||||
|
|
||||||
|
// Nothing should happen on click. We click the location rather than the element, since the
|
||||||
|
// element isn't actually clickable.
|
||||||
|
await start.mouseMove();
|
||||||
|
await driver.withActions(a => a.press().release());
|
||||||
|
await driver.sleep(100);
|
||||||
|
assert.equal(await driver.find(".test-settings-timing-modal").isPresent(), false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const element = (testId: string) => ({
|
const element = (testId: string) => ({
|
||||||
|
Loading…
Reference in New Issue
Block a user