mirror of
https://github.com/qlik-oss/nebula.js.git
synced 2025-12-19 17:58:43 -05:00
fix(nucleus): wait for curr selections (#117)
This commit is contained in:
@@ -1,19 +1,6 @@
|
|||||||
import vizualizationAPI from '../viz';
|
import vizualizationAPI from '../viz';
|
||||||
import ObjectAPI from './object-api';
|
import ObjectAPI from './object-api';
|
||||||
|
import { observe } from './observer';
|
||||||
export function observe(model, objectAPI) {
|
|
||||||
const onChanged = () =>
|
|
||||||
model.getLayout().then(layout => {
|
|
||||||
objectAPI.setLayout(layout);
|
|
||||||
});
|
|
||||||
model.on('changed', onChanged);
|
|
||||||
model.once('closed', () => {
|
|
||||||
model.removeListener('changed', onChanged);
|
|
||||||
objectAPI.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
onChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function initiate(getCfg, optional, context) {
|
export default function initiate(getCfg, optional, context) {
|
||||||
return context.app.getObject(getCfg.id).then(model => {
|
return context.app.getObject(getCfg.id).then(model => {
|
||||||
@@ -24,7 +11,7 @@ export default function initiate(getCfg, optional, context) {
|
|||||||
|
|
||||||
const objectAPI = new ObjectAPI(model, context, viz);
|
const objectAPI = new ObjectAPI(model, context, viz);
|
||||||
|
|
||||||
observe(model, objectAPI);
|
observe(model, layout => objectAPI.setLayout(layout)); // TODO - call unobserve when viz is destroyed
|
||||||
|
|
||||||
const api = objectAPI.getPublicAPI();
|
const api = objectAPI.getPublicAPI();
|
||||||
|
|
||||||
|
|||||||
@@ -46,14 +46,22 @@ export function observe(model, callback, property = 'layout') {
|
|||||||
affected.forEach(key => {
|
affected.forEach(key => {
|
||||||
c.props[key].state = STATES.VALIDATING;
|
c.props[key].state = STATES.VALIDATING;
|
||||||
const method = OBSERVABLE[key].filter(m => model[m])[0];
|
const method = OBSERVABLE[key].filter(m => model[m])[0];
|
||||||
model[method]().then(value => {
|
model[method]()
|
||||||
|
.then(value => {
|
||||||
if (cache[model.id] && cache[model.id].props[key]) {
|
if (cache[model.id] && cache[model.id].props[key]) {
|
||||||
if (cache[model.id].props[key].state < STATES.CLOSED && cache[model.id].props[key].state !== STATES.VALID) {
|
if (
|
||||||
|
cache[model.id].props[key].state < STATES.CLOSED &&
|
||||||
|
cache[model.id].props[key].state !== STATES.VALID
|
||||||
|
) {
|
||||||
cache[model.id].props[key].state = STATES.VALID;
|
cache[model.id].props[key].state = STATES.VALID;
|
||||||
cache[model.id].props[key].value = value;
|
cache[model.id].props[key].value = value;
|
||||||
cache[model.id].props[key].callbacks.forEach(cb => cb(value));
|
cache[model.id].props[key].callbacks.forEach(cb => cb(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
// TODO - retry?
|
||||||
|
cache[model.id].props[key].state = STATES.INVALID;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,11 +15,13 @@ const create = app => {
|
|||||||
let modalObject;
|
let modalObject;
|
||||||
// let mounted;
|
// let mounted;
|
||||||
let lyt;
|
let lyt;
|
||||||
|
let currentSelectionsModel;
|
||||||
|
let prom;
|
||||||
const api = {
|
const api = {
|
||||||
model: app,
|
model: app,
|
||||||
switchModal(object, path, accept = true) {
|
switchModal(object, path, accept = true) {
|
||||||
if (object === modalObject) {
|
if (object === modalObject) {
|
||||||
return Promise.resolve();
|
return prom || Promise.resolve();
|
||||||
}
|
}
|
||||||
if (modalObject) {
|
if (modalObject) {
|
||||||
modalObject.endSelections(accept);
|
modalObject.endSelections(accept);
|
||||||
@@ -30,17 +32,22 @@ const create = app => {
|
|||||||
// TODO check model state
|
// TODO check model state
|
||||||
modalObject = object;
|
modalObject = object;
|
||||||
api.emit('modal', modalObject._selections);
|
api.emit('modal', modalObject._selections);
|
||||||
return modalObject.beginSelections(Array.isArray(path) ? path : [path]).catch(err => {
|
prom = currentSelectionsModel.then(() => {
|
||||||
|
// do not return the call to beginSelection to avoid waiting for it's response
|
||||||
|
modalObject.beginSelections(Array.isArray(path) ? path : [path]).catch(err => {
|
||||||
if (err.code === 6003) {
|
if (err.code === 6003) {
|
||||||
// If another object already is in modal -> abort and take over
|
// If another object already is in modal -> abort and take over
|
||||||
return api.abortModal().then(() => object.beginSelections(Array.isArray(path) ? path : [path]));
|
return api.abortModal().then(() => object.beginSelections(Array.isArray(path) ? path : [path]));
|
||||||
}
|
}
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
return prom;
|
||||||
}
|
}
|
||||||
modalObject = null;
|
modalObject = null;
|
||||||
api.emit('modal-unset');
|
api.emit('modal-unset');
|
||||||
return Promise.resolve();
|
prom = Promise.resolve();
|
||||||
|
return prom;
|
||||||
},
|
},
|
||||||
isModal(objectModel) {
|
isModal(objectModel) {
|
||||||
// TODO check model state
|
// TODO check model state
|
||||||
@@ -83,7 +90,7 @@ const create = app => {
|
|||||||
|
|
||||||
eventmixin(api);
|
eventmixin(api);
|
||||||
|
|
||||||
modelCache(
|
currentSelectionsModel = modelCache(
|
||||||
{
|
{
|
||||||
qInfo: {
|
qInfo: {
|
||||||
qType: 'current-selections',
|
qType: 'current-selections',
|
||||||
@@ -94,7 +101,8 @@ const create = app => {
|
|||||||
alternateStates: [],
|
alternateStates: [],
|
||||||
},
|
},
|
||||||
app
|
app
|
||||||
).then(model => {
|
)
|
||||||
|
.then(model => {
|
||||||
observe(app, appLayout => {
|
observe(app, appLayout => {
|
||||||
const states = [...appLayout.qStateNames].map(s => ({
|
const states = [...appLayout.qStateNames].map(s => ({
|
||||||
stateName: s, // need this as reference in selection toolbar since qSelectionObject.qStateName is not in the layout
|
stateName: s, // need this as reference in selection toolbar since qSelectionObject.qStateName is not in the layout
|
||||||
@@ -134,6 +142,9 @@ const create = app => {
|
|||||||
app._selections = null; // eslint-disable-line no-param-reassign
|
app._selections = null; // eslint-disable-line no-param-reassign
|
||||||
cache[app.id] = null;
|
cache[app.id] = null;
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
// do something
|
||||||
});
|
});
|
||||||
|
|
||||||
return api;
|
return api;
|
||||||
|
|||||||
@@ -55,16 +55,18 @@ export default function(model, app) {
|
|||||||
return appAPI().switchModal(null, null, false, false);
|
return appAPI().switchModal(null, null, false, false);
|
||||||
},
|
},
|
||||||
select(s) {
|
select(s) {
|
||||||
this.begin([s.params[0]]);
|
const b = this.begin([s.params[0]]);
|
||||||
if (!appAPI().isModal()) {
|
if (!appAPI().isModal()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
hasSelected = true;
|
hasSelected = true;
|
||||||
|
b.then(() =>
|
||||||
model[s.method](...s.params).then(qSuccess => {
|
model[s.method](...s.params).then(qSuccess => {
|
||||||
if (!qSuccess) {
|
if (!qSuccess) {
|
||||||
this.clear();
|
this.clear();
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
);
|
||||||
},
|
},
|
||||||
canClear() {
|
canClear() {
|
||||||
return hasSelected && layout.qSelectionInfo.qMadeSelections;
|
return hasSelected && layout.qSelectionInfo.qMadeSelections;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"build": "nebula build",
|
"build": "nebula build",
|
||||||
"lint": "eslint src",
|
"lint": "eslint src",
|
||||||
"start": "nebula serve",
|
"start": "nebula serve",
|
||||||
"test:integration": "aw puppet --testExt '*.int.js' --glob 'test/integration/**/*.int.js' --chrome.headless true --mocha.timeout 15000"
|
"test:integration": "aw puppet --testExt '*.int.js' --glob 'test/integration/**/*.int.js'"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@after-work.js/aw": "^6.0.3",
|
"@after-work.js/aw": "^6.0.3",
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ const serve = require('@nebula.js/cli-serve'); // eslint-disable-line
|
|||||||
|
|
||||||
let s;
|
let s;
|
||||||
|
|
||||||
before(async () => {
|
before(async function setup() {
|
||||||
|
this.timeout(15000);
|
||||||
s = await serve({
|
s = await serve({
|
||||||
open: false,
|
open: false,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,8 +9,12 @@ describe('interaction', () => {
|
|||||||
|
|
||||||
await page.click('rect[data-label="K"]');
|
await page.click('rect[data-label="K"]');
|
||||||
await page.click('rect[data-label="S"]');
|
await page.click('rect[data-label="S"]');
|
||||||
|
|
||||||
|
await page.waitForSelector('button[title="Confirm selection"]');
|
||||||
await page.click('button[title="Confirm selection"]');
|
await page.click('button[title="Confirm selection"]');
|
||||||
|
|
||||||
|
await page.waitFor(100); // wait a bit to make sure websocket traffic has gone through
|
||||||
|
|
||||||
const rects = await page.$$eval('rect[data-label]', sel => sel.map(r => r.getAttribute('data-label')));
|
const rects = await page.$$eval('rect[data-label]', sel => sel.map(r => r.getAttribute('data-label')));
|
||||||
expect(rects).to.eql(['K', 'S']);
|
expect(rects).to.eql(['K', 'S']);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"build": "nebula build",
|
"build": "nebula build",
|
||||||
"lint": "eslint src",
|
"lint": "eslint src",
|
||||||
"start": "nebula serve",
|
"start": "nebula serve",
|
||||||
"test:integration": "aw puppet --testExt '*.int.js' --glob 'test/integration/**/*.int.js' --chrome.headless true --chrome.slowMo 10"
|
"test:integration": "aw puppet --testExt '*.int.js' --glob 'test/integration/**/*.int.js'"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@after-work.js/aw": "^6.0.3",
|
"@after-work.js/aw": "^6.0.3",
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ const serve = require('@nebula.js/cli-serve'); // eslint-disable-line
|
|||||||
|
|
||||||
let s;
|
let s;
|
||||||
|
|
||||||
before(async () => {
|
before(async function setup() {
|
||||||
|
this.timeout(15000); // to allow time for the server to start
|
||||||
s = await serve({
|
s = await serve({
|
||||||
build: false,
|
build: false,
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user