mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) Fixing bug with collapsed custom widget.
Summary: Fix for a bug. Custom widget when collapsed and expanded was disconnecting from Grist, as WidgetFrame was disposed to early. Test Plan: Added new Reviewers: georgegevoian Reviewed By: georgegevoian Differential Revision: https://phab.getgrist.com/D4109
This commit is contained in:
parent
3210eee24f
commit
9262e1f1ef
@ -242,7 +242,7 @@ export class CustomView extends Disposable {
|
|||||||
const {baseUrl, access, showAfterReady, widgetId, pluginId} = options;
|
const {baseUrl, access, showAfterReady, widgetId, pluginId} = options;
|
||||||
const documentSettings = this.gristDoc.docData.docSettings();
|
const documentSettings = this.gristDoc.docData.docSettings();
|
||||||
const readonly = this.gristDoc.isReadonly.get();
|
const readonly = this.gristDoc.isReadonly.get();
|
||||||
return grains.create(WidgetFrame, {
|
const frame = WidgetFrame.create(null, {
|
||||||
url: baseUrl || this.getEmptyWidgetPage(),
|
url: baseUrl || this.getEmptyWidgetPage(),
|
||||||
widgetId,
|
widgetId,
|
||||||
pluginId,
|
pluginId,
|
||||||
@ -304,6 +304,12 @@ export class CustomView extends Disposable {
|
|||||||
gristDoc: this.gristDoc,
|
gristDoc: this.gristDoc,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Can't use dom.create() because it seems buggy in this context. This dom will be detached
|
||||||
|
// and attached several times, and dom.create() doesn't seem to handle that well as it returns an
|
||||||
|
// array of nodes (comment, node, comment) and it somehow breaks the dispose order. Collapsed widgets
|
||||||
|
// relay on a correct order of dispose, and are detaching nodes just before they are disposed, so if
|
||||||
|
// the order is wrong, the node is disposed without being detached first.
|
||||||
|
return grains.update(frame.buildDom(), dom.autoDispose(frame));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,17 +185,17 @@ export class WidgetFrame extends DisposableWithEvents {
|
|||||||
|
|
||||||
public buildDom() {
|
public buildDom() {
|
||||||
const onElem = this._options.onElem ?? ((el: HTMLIFrameElement) => el);
|
const onElem = this._options.onElem ?? ((el: HTMLIFrameElement) => el);
|
||||||
return onElem(
|
this._iframe = dom(
|
||||||
(this._iframe = dom(
|
'iframe',
|
||||||
'iframe',
|
dom.style('visibility', use => use(this._visible) ? 'visible' : 'hidden'),
|
||||||
dom.style('visibility', use => use(this._visible) ? 'visible' : 'hidden'),
|
dom.cls('clipboard_focus'),
|
||||||
dom.cls('clipboard_focus'),
|
dom.cls('custom_view'),
|
||||||
dom.cls('custom_view'),
|
dom.attr('src', use => this._getUrl(use(this._widget))),
|
||||||
dom.attr('src', use => this._getUrl(use(this._widget))),
|
hooks.iframeAttributes,
|
||||||
hooks.iframeAttributes,
|
testId('ready', this._readyCalled),
|
||||||
testId('ready', this._readyCalled),
|
self => void onElem(self),
|
||||||
))
|
|
||||||
);
|
);
|
||||||
|
return this._iframe;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getUrl(widget: ICustomWidget|null): string {
|
private _getUrl(widget: ICustomWidget|null): string {
|
||||||
|
@ -4,11 +4,12 @@ import {getCollapsedSection, openCollapsedSectionMenu} from 'test/nbrowser/ViewL
|
|||||||
import {assert, driver, Key, WebElement, WebElementPromise} from 'mocha-webdriver';
|
import {assert, driver, Key, WebElement, WebElementPromise} from 'mocha-webdriver';
|
||||||
import {arrayRepeat} from 'app/plugin/gutil';
|
import {arrayRepeat} from 'app/plugin/gutil';
|
||||||
import {addStatic, serveSomething} from 'test/server/customUtil';
|
import {addStatic, serveSomething} from 'test/server/customUtil';
|
||||||
|
import {AccessLevel} from 'app/common/CustomWidget';
|
||||||
|
|
||||||
const GAP = 16; // Distance between buttons representing collapsed widgets.
|
const GAP = 16; // Distance between buttons representing collapsed widgets.
|
||||||
|
|
||||||
describe("ViewLayoutCollapse", function() {
|
describe("ViewLayoutCollapse", function() {
|
||||||
this.timeout(40000);
|
this.timeout('50s');
|
||||||
const cleanup = setupTestSuite();
|
const cleanup = setupTestSuite();
|
||||||
gu.bigScreen();
|
gu.bigScreen();
|
||||||
let session: gu.Session;
|
let session: gu.Session;
|
||||||
@ -19,6 +20,45 @@ describe("ViewLayoutCollapse", function() {
|
|||||||
await gu.openPage("Overview");
|
await gu.openPage("Overview");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('fix: custom widget should restart when added back after collapsing', async function() {
|
||||||
|
const revert = await gu.begin();
|
||||||
|
|
||||||
|
// Add custom section.
|
||||||
|
await gu.addNewPage('Table', 'Companies');
|
||||||
|
await gu.addNewSection('Custom', 'Companies', { selectBy: 'COMPANIES'});
|
||||||
|
|
||||||
|
// Serve custom widget.
|
||||||
|
const widgetServer = await serveSomething(app => {
|
||||||
|
addStatic(app);
|
||||||
|
});
|
||||||
|
cleanup.addAfterAll(widgetServer.shutdown);
|
||||||
|
await gu.openWidgetPanel();
|
||||||
|
await gu.setWidgetUrl(widgetServer.url + '/probe/index.html');
|
||||||
|
await gu.widgetAccess(AccessLevel.full);
|
||||||
|
|
||||||
|
// Collapse it.
|
||||||
|
await collapseByMenu('COMPANIES Custom');
|
||||||
|
|
||||||
|
// Now restore its position.
|
||||||
|
await addToMainByMenu('COMPANIES Custom');
|
||||||
|
|
||||||
|
// Collapsed widget used to lost connection with Grist as it was disposed to early.
|
||||||
|
// Make sure that this widget can call the API.
|
||||||
|
await gu.doInIframe(async () => {
|
||||||
|
await gu.waitToPass(async () => {
|
||||||
|
assert.equal(await driver.find('#output').getText(),
|
||||||
|
`["Companies","Investments","Companies_summary_category_code","Investments_summary_funded_year",` +
|
||||||
|
`"Investments_summary_Company_category_code_funded_year","Investments_summary_Company_category_code"]`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Make sure we don't have an error.
|
||||||
|
await gu.checkForErrors();
|
||||||
|
await revert();
|
||||||
|
});
|
||||||
|
|
||||||
it('fix: custom widget should not throw errors when collapsed', async function() {
|
it('fix: custom widget should not throw errors when collapsed', async function() {
|
||||||
const revert = await gu.begin();
|
const revert = await gu.begin();
|
||||||
|
|
||||||
@ -33,9 +73,7 @@ describe("ViewLayoutCollapse", function() {
|
|||||||
cleanup.addAfterAll(widgetServer.shutdown);
|
cleanup.addAfterAll(widgetServer.shutdown);
|
||||||
await gu.openWidgetPanel();
|
await gu.openWidgetPanel();
|
||||||
await gu.setWidgetUrl(widgetServer.url + '/probe/index.html');
|
await gu.setWidgetUrl(widgetServer.url + '/probe/index.html');
|
||||||
await driver.find('.test-config-widget-access .test-select-open').click();
|
await gu.widgetAccess(AccessLevel.full);
|
||||||
await driver.findContent('.test-select-menu li', 'Full document access').click();
|
|
||||||
await gu.waitForServer();
|
|
||||||
|
|
||||||
// Collapse it.
|
// Collapse it.
|
||||||
await collapseByMenu('COMPANIES Custom');
|
await collapseByMenu('COMPANIES Custom');
|
||||||
|
@ -894,8 +894,17 @@ export async function importUrlDialog(url: string): Promise<void> {
|
|||||||
* Executed passed function in the context of given iframe, and then switching back to original context
|
* Executed passed function in the context of given iframe, and then switching back to original context
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export async function doInIframe<T>(iframe: WebElement, func: () => Promise<T>) {
|
export async function doInIframe<T>(func: () => Promise<T>): Promise<T>
|
||||||
|
export async function doInIframe<T>(iframe: WebElement, func: () => Promise<T>): Promise<T>
|
||||||
|
export async function doInIframe<T>(frameOrFunc: WebElement|(() => Promise<T>), func?: () => Promise<T>): Promise<T> {
|
||||||
try {
|
try {
|
||||||
|
let iframe: WebElement;
|
||||||
|
if (!func) {
|
||||||
|
func = frameOrFunc as () => Promise<T>;
|
||||||
|
iframe = await driver.findWait('iframe', 5000);
|
||||||
|
} else {
|
||||||
|
iframe = frameOrFunc as WebElement;
|
||||||
|
}
|
||||||
await driver.switchTo().frame(iframe);
|
await driver.switchTo().frame(iframe);
|
||||||
return await func();
|
return await func();
|
||||||
} finally {
|
} finally {
|
||||||
|
Loading…
Reference in New Issue
Block a user