mirror of
https://github.com/qlik-oss/nebula.js.git
synced 2025-12-19 17:58:43 -05:00
feat: add viewDataToggled and toggleFocus (#1711)
* feat: add viewDataToggled and toggleFocus * fix: add imperative handle focus * fix: check blurCallback properly * feat: add support data view * feat: add setOnBlurHandler * feat: update viz api to include ext * fix: make sure viewdata returns correctly * chore: add getRenderstate * chore: clean out comment Co-authored-by: Christian Veinfors <cvs@qlik.com> * chore: shuffle support func into Cell * chore: throw error in support when in view data * chore: store support object for original chart * feat: add viewDataToggled and toggleFocus * fix: add imperative handle focus * fix: check blurCallback properly * feat: add support data view * feat: add setOnBlurHandler * feat: update viz api to include ext * fix: make sure viewdata returns correctly * chore: add getRenderstate * chore: clean out comment Co-authored-by: Christian Veinfors <cvs@qlik.com> * chore: shuffle support func into Cell * chore: throw error in support when in view data * chore: store support object for original chart * chore: fix test * fix: rename to getExtensionDefinition * fix: check if current is not undefined * chore: store outer layout --------- Co-authored-by: caele <tsm@qlik.com> Co-authored-by: Christian Veinfors <cvs@qlik.com>
This commit is contained in:
@@ -18,6 +18,7 @@ describe('viz', () => {
|
||||
let setSnOptions;
|
||||
let setSnContext;
|
||||
let setSnPlugins;
|
||||
let getExtensionDefinition;
|
||||
let setModel;
|
||||
let takeSnapshot;
|
||||
let exportImage;
|
||||
@@ -33,6 +34,7 @@ describe('viz', () => {
|
||||
setSnOptions = jest.fn();
|
||||
setSnContext = jest.fn();
|
||||
setSnPlugins = jest.fn();
|
||||
getExtensionDefinition = jest.fn();
|
||||
setModel = jest.fn();
|
||||
takeSnapshot = jest.fn();
|
||||
exportImage = jest.fn();
|
||||
@@ -44,6 +46,7 @@ describe('viz', () => {
|
||||
setSnOptions,
|
||||
setSnContext,
|
||||
setSnPlugins,
|
||||
getExtensionDefinition,
|
||||
setModel,
|
||||
takeSnapshot,
|
||||
exportImage,
|
||||
|
||||
@@ -39,6 +39,17 @@ const CellBody = {
|
||||
className: 'njs-cell-body',
|
||||
};
|
||||
|
||||
function support(prop, supportObject, layout) {
|
||||
const value = supportObject[prop];
|
||||
if (typeof value === 'function') {
|
||||
return value.call(null, layout);
|
||||
}
|
||||
if (typeof value === 'boolean') {
|
||||
return value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const initialState = (err) => ({
|
||||
loading: false,
|
||||
loaded: false,
|
||||
@@ -460,7 +471,6 @@ const Cell = forwardRef(
|
||||
|
||||
return () => {};
|
||||
}, [types, state.sn, model, selections, layout, appLayout, language]);
|
||||
|
||||
// Long running query
|
||||
useEffect(() => {
|
||||
if (!validating) {
|
||||
@@ -477,6 +487,19 @@ const Cell = forwardRef(
|
||||
getQae() {
|
||||
return state.sn.generator.qae;
|
||||
},
|
||||
getExtensionDefinition() {
|
||||
return state.sn.generator.definition.ext;
|
||||
},
|
||||
// allow input of supportObject ot override when flipped to table
|
||||
support(type, supportObject, outerLayout) {
|
||||
if (layout && state.loaded && !state.error) {
|
||||
const suppObj = supportObject || state.sn.generator.definition.ext?.support;
|
||||
if (suppObj) {
|
||||
return support(type, suppObj, outerLayout || layout);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
toggleFocus(active) {
|
||||
if (typeof state.sn.component.focus === 'function') {
|
||||
if (active) {
|
||||
@@ -486,6 +509,9 @@ const Cell = forwardRef(
|
||||
}
|
||||
}
|
||||
},
|
||||
setOnBlurHandler(cb) {
|
||||
focusHandler.current.blurCallback = cb;
|
||||
},
|
||||
setSnOptions,
|
||||
setSnPlugins,
|
||||
setModel,
|
||||
|
||||
@@ -94,7 +94,7 @@ export default function boot({ app, context }) {
|
||||
{
|
||||
toggleFocusOfCells(cellIdToFocus) {
|
||||
Object.keys(cells).forEach((i) => {
|
||||
cells[i].current.toggleFocus(i === cellIdToFocus);
|
||||
cells[i].current?.toggleFocus(i === cellIdToFocus);
|
||||
});
|
||||
},
|
||||
cells,
|
||||
|
||||
@@ -25,6 +25,10 @@ export default function viz({
|
||||
let onMount = null;
|
||||
let onRenderResolve = null;
|
||||
let viewDataObjectId;
|
||||
let originalExtensionDef;
|
||||
let originalLayout;
|
||||
let successfulRender = false;
|
||||
|
||||
const mounted = new Promise((resolve) => {
|
||||
onMount = resolve;
|
||||
});
|
||||
@@ -37,6 +41,7 @@ export default function viz({
|
||||
override?.(); // from options.onInitialRender
|
||||
onRenderResolve(); // internal promise in viz to wait for render
|
||||
onRender(); // from RenderConfig
|
||||
successfulRender = true;
|
||||
};
|
||||
|
||||
let initialSnOptions = {};
|
||||
@@ -194,15 +199,26 @@ export default function viz({
|
||||
});
|
||||
newModel = await halo.app.createSessionObject(propertyTree.qProperty);
|
||||
viewDataObjectId = newModel.id;
|
||||
originalExtensionDef = cellRef.current.getExtensionDefinition();
|
||||
originalLayout = await model.getLayout();
|
||||
} else if (viewDataObjectId && showDataView !== true) {
|
||||
newModel = model;
|
||||
await halo.app.destroySessionObject(viewDataObjectId);
|
||||
viewDataObjectId = undefined;
|
||||
originalExtensionDef = undefined;
|
||||
originalLayout = undefined;
|
||||
}
|
||||
if (newModel) {
|
||||
cellRef.current.setModel(newModel);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Whether or not the chart has the data view toggled on.
|
||||
* @type {boolean}
|
||||
*/
|
||||
get viewDataToggled() {
|
||||
return viewDataObjectId !== undefined;
|
||||
},
|
||||
/**
|
||||
* Listens to custom events from inside the visualization. See useEmitter
|
||||
* @param {string} eventName Event name to listen to
|
||||
@@ -237,6 +253,25 @@ export default function viz({
|
||||
await rendered;
|
||||
return cellRef.current.takeSnapshot();
|
||||
},
|
||||
// ===== undocumented experimental API - use at own risk ======
|
||||
/**
|
||||
* valid types: viewData, cssScaling, snapshot, exportData, exploration
|
||||
* questionable types: supportRefresh, quickMobile, fullscreen
|
||||
* deprecated?: sharing
|
||||
*
|
||||
*/
|
||||
support(type) {
|
||||
if (mountedReference && successfulRender) {
|
||||
return cellRef.current.support(type, originalExtensionDef?.support, originalLayout);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
toggleFocus(focus) {
|
||||
cellRef.current.toggleFocus(focus);
|
||||
},
|
||||
setOnBlurHandler(cb) {
|
||||
cellRef.current.setOnBlurHandler(cb);
|
||||
},
|
||||
// ===== unexposed experimental API - use at own risk ======
|
||||
__DO_NOT_USE__: {
|
||||
mount(element) {
|
||||
|
||||
@@ -1413,6 +1413,10 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"viewDataToggled": {
|
||||
"description": "Whether or not the chart has the data view toggled on.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"addListener": {
|
||||
"description": "Listens to custom events from inside the visualization. See useEmitter",
|
||||
"kind": "function",
|
||||
@@ -1723,6 +1727,33 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Plugin": {
|
||||
"description": "An object literal containing meta information about the plugin and a function containing the plugin implementation.",
|
||||
"stability": "experimental",
|
||||
"availability": {
|
||||
"since": "1.2.0"
|
||||
},
|
||||
"kind": "interface",
|
||||
"entries": {
|
||||
"info": {
|
||||
"description": "Object that can hold various meta info about the plugin",
|
||||
"kind": "object",
|
||||
"entries": {
|
||||
"name": {
|
||||
"description": "The name of the plugin",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fn": {
|
||||
"description": "The implementation of the plugin. Input and return value is up to the plugin implementation to decide based on its purpose.",
|
||||
"type": "function"
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
"const plugin = {\n info: {\n name: \"example-plugin\",\n type: \"meta-type\",\n },\n fn: () => {\n // Plugin implementation goes here\n }\n};"
|
||||
]
|
||||
},
|
||||
"Field": {
|
||||
"kind": "alias",
|
||||
"items": {
|
||||
@@ -1874,33 +1905,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Plugin": {
|
||||
"description": "An object literal containing meta information about the plugin and a function containing the plugin implementation.",
|
||||
"stability": "experimental",
|
||||
"availability": {
|
||||
"since": "1.2.0"
|
||||
},
|
||||
"kind": "interface",
|
||||
"entries": {
|
||||
"info": {
|
||||
"description": "Object that can hold various meta info about the plugin",
|
||||
"kind": "object",
|
||||
"entries": {
|
||||
"name": {
|
||||
"description": "The name of the plugin",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fn": {
|
||||
"description": "The implementation of the plugin. Input and return value is up to the plugin implementation to decide based on its purpose.",
|
||||
"type": "function"
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
"const plugin = {\n info: {\n name: \"example-plugin\",\n type: \"meta-type\",\n },\n fn: () => {\n // Plugin implementation goes here\n }\n};"
|
||||
]
|
||||
},
|
||||
"LoadType": {
|
||||
"kind": "interface",
|
||||
"params": [
|
||||
|
||||
22
apis/stardust/types/index.d.ts
vendored
22
apis/stardust/types/index.d.ts
vendored
@@ -453,6 +453,8 @@ declare namespace stardust {
|
||||
*/
|
||||
toggleDataView(showDataView?: boolean): void;
|
||||
|
||||
viewDataToggled: boolean;
|
||||
|
||||
/**
|
||||
* Listens to custom events from inside the visualization. See useEmitter
|
||||
* @param eventName Event name to listen to
|
||||
@@ -556,6 +558,16 @@ declare namespace stardust {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* An object literal containing meta information about the plugin and a function containing the plugin implementation.
|
||||
*/
|
||||
interface Plugin {
|
||||
info: {
|
||||
name: string;
|
||||
};
|
||||
fn: ()=>void;
|
||||
}
|
||||
|
||||
type Field = string | qix.NxDimension | qix.NxMeasure | stardust.LibraryField;
|
||||
|
||||
/**
|
||||
@@ -597,16 +609,6 @@ declare namespace stardust {
|
||||
type: "dimension" | "measure";
|
||||
}
|
||||
|
||||
/**
|
||||
* An object literal containing meta information about the plugin and a function containing the plugin implementation.
|
||||
*/
|
||||
interface Plugin {
|
||||
info: {
|
||||
name: string;
|
||||
};
|
||||
fn: ()=>void;
|
||||
}
|
||||
|
||||
interface LoadType {
|
||||
(type: {
|
||||
name: string;
|
||||
|
||||
@@ -216,6 +216,11 @@ function createWithHooks(generator, opts, galaxy) {
|
||||
return generator.component.runMenu(this, menu, event, menuBuilder);
|
||||
},
|
||||
focus() {
|
||||
const ref = generator.component.getImperativeHandle(this);
|
||||
if (ref && typeof ref.focus === 'function') {
|
||||
ref.focus();
|
||||
return;
|
||||
}
|
||||
generator.component.focus(this);
|
||||
},
|
||||
blur() {
|
||||
|
||||
Reference in New Issue
Block a user