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 setSnOptions;
|
||||||
let setSnContext;
|
let setSnContext;
|
||||||
let setSnPlugins;
|
let setSnPlugins;
|
||||||
|
let getExtensionDefinition;
|
||||||
let setModel;
|
let setModel;
|
||||||
let takeSnapshot;
|
let takeSnapshot;
|
||||||
let exportImage;
|
let exportImage;
|
||||||
@@ -33,6 +34,7 @@ describe('viz', () => {
|
|||||||
setSnOptions = jest.fn();
|
setSnOptions = jest.fn();
|
||||||
setSnContext = jest.fn();
|
setSnContext = jest.fn();
|
||||||
setSnPlugins = jest.fn();
|
setSnPlugins = jest.fn();
|
||||||
|
getExtensionDefinition = jest.fn();
|
||||||
setModel = jest.fn();
|
setModel = jest.fn();
|
||||||
takeSnapshot = jest.fn();
|
takeSnapshot = jest.fn();
|
||||||
exportImage = jest.fn();
|
exportImage = jest.fn();
|
||||||
@@ -44,6 +46,7 @@ describe('viz', () => {
|
|||||||
setSnOptions,
|
setSnOptions,
|
||||||
setSnContext,
|
setSnContext,
|
||||||
setSnPlugins,
|
setSnPlugins,
|
||||||
|
getExtensionDefinition,
|
||||||
setModel,
|
setModel,
|
||||||
takeSnapshot,
|
takeSnapshot,
|
||||||
exportImage,
|
exportImage,
|
||||||
|
|||||||
@@ -39,6 +39,17 @@ const CellBody = {
|
|||||||
className: 'njs-cell-body',
|
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) => ({
|
const initialState = (err) => ({
|
||||||
loading: false,
|
loading: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
@@ -460,7 +471,6 @@ const Cell = forwardRef(
|
|||||||
|
|
||||||
return () => {};
|
return () => {};
|
||||||
}, [types, state.sn, model, selections, layout, appLayout, language]);
|
}, [types, state.sn, model, selections, layout, appLayout, language]);
|
||||||
|
|
||||||
// Long running query
|
// Long running query
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!validating) {
|
if (!validating) {
|
||||||
@@ -477,6 +487,19 @@ const Cell = forwardRef(
|
|||||||
getQae() {
|
getQae() {
|
||||||
return state.sn.generator.qae;
|
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) {
|
toggleFocus(active) {
|
||||||
if (typeof state.sn.component.focus === 'function') {
|
if (typeof state.sn.component.focus === 'function') {
|
||||||
if (active) {
|
if (active) {
|
||||||
@@ -486,6 +509,9 @@ const Cell = forwardRef(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setOnBlurHandler(cb) {
|
||||||
|
focusHandler.current.blurCallback = cb;
|
||||||
|
},
|
||||||
setSnOptions,
|
setSnOptions,
|
||||||
setSnPlugins,
|
setSnPlugins,
|
||||||
setModel,
|
setModel,
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ export default function boot({ app, context }) {
|
|||||||
{
|
{
|
||||||
toggleFocusOfCells(cellIdToFocus) {
|
toggleFocusOfCells(cellIdToFocus) {
|
||||||
Object.keys(cells).forEach((i) => {
|
Object.keys(cells).forEach((i) => {
|
||||||
cells[i].current.toggleFocus(i === cellIdToFocus);
|
cells[i].current?.toggleFocus(i === cellIdToFocus);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
cells,
|
cells,
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ export default function viz({
|
|||||||
let onMount = null;
|
let onMount = null;
|
||||||
let onRenderResolve = null;
|
let onRenderResolve = null;
|
||||||
let viewDataObjectId;
|
let viewDataObjectId;
|
||||||
|
let originalExtensionDef;
|
||||||
|
let originalLayout;
|
||||||
|
let successfulRender = false;
|
||||||
|
|
||||||
const mounted = new Promise((resolve) => {
|
const mounted = new Promise((resolve) => {
|
||||||
onMount = resolve;
|
onMount = resolve;
|
||||||
});
|
});
|
||||||
@@ -37,6 +41,7 @@ export default function viz({
|
|||||||
override?.(); // from options.onInitialRender
|
override?.(); // from options.onInitialRender
|
||||||
onRenderResolve(); // internal promise in viz to wait for render
|
onRenderResolve(); // internal promise in viz to wait for render
|
||||||
onRender(); // from RenderConfig
|
onRender(); // from RenderConfig
|
||||||
|
successfulRender = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
let initialSnOptions = {};
|
let initialSnOptions = {};
|
||||||
@@ -194,15 +199,26 @@ export default function viz({
|
|||||||
});
|
});
|
||||||
newModel = await halo.app.createSessionObject(propertyTree.qProperty);
|
newModel = await halo.app.createSessionObject(propertyTree.qProperty);
|
||||||
viewDataObjectId = newModel.id;
|
viewDataObjectId = newModel.id;
|
||||||
|
originalExtensionDef = cellRef.current.getExtensionDefinition();
|
||||||
|
originalLayout = await model.getLayout();
|
||||||
} else if (viewDataObjectId && showDataView !== true) {
|
} else if (viewDataObjectId && showDataView !== true) {
|
||||||
newModel = model;
|
newModel = model;
|
||||||
await halo.app.destroySessionObject(viewDataObjectId);
|
await halo.app.destroySessionObject(viewDataObjectId);
|
||||||
viewDataObjectId = undefined;
|
viewDataObjectId = undefined;
|
||||||
|
originalExtensionDef = undefined;
|
||||||
|
originalLayout = undefined;
|
||||||
}
|
}
|
||||||
if (newModel) {
|
if (newModel) {
|
||||||
cellRef.current.setModel(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
|
* Listens to custom events from inside the visualization. See useEmitter
|
||||||
* @param {string} eventName Event name to listen to
|
* @param {string} eventName Event name to listen to
|
||||||
@@ -237,6 +253,25 @@ export default function viz({
|
|||||||
await rendered;
|
await rendered;
|
||||||
return cellRef.current.takeSnapshot();
|
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 ======
|
// ===== unexposed experimental API - use at own risk ======
|
||||||
__DO_NOT_USE__: {
|
__DO_NOT_USE__: {
|
||||||
mount(element) {
|
mount(element) {
|
||||||
|
|||||||
@@ -1413,6 +1413,10 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"viewDataToggled": {
|
||||||
|
"description": "Whether or not the chart has the data view toggled on.",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"addListener": {
|
"addListener": {
|
||||||
"description": "Listens to custom events from inside the visualization. See useEmitter",
|
"description": "Listens to custom events from inside the visualization. See useEmitter",
|
||||||
"kind": "function",
|
"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": {
|
"Field": {
|
||||||
"kind": "alias",
|
"kind": "alias",
|
||||||
"items": {
|
"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": {
|
"LoadType": {
|
||||||
"kind": "interface",
|
"kind": "interface",
|
||||||
"params": [
|
"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;
|
toggleDataView(showDataView?: boolean): void;
|
||||||
|
|
||||||
|
viewDataToggled: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listens to custom events from inside the visualization. See useEmitter
|
* Listens to custom events from inside the visualization. See useEmitter
|
||||||
* @param eventName Event name to listen to
|
* @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;
|
type Field = string | qix.NxDimension | qix.NxMeasure | stardust.LibraryField;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -597,16 +609,6 @@ declare namespace stardust {
|
|||||||
type: "dimension" | "measure";
|
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 {
|
interface LoadType {
|
||||||
(type: {
|
(type: {
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
@@ -216,6 +216,11 @@ function createWithHooks(generator, opts, galaxy) {
|
|||||||
return generator.component.runMenu(this, menu, event, menuBuilder);
|
return generator.component.runMenu(this, menu, event, menuBuilder);
|
||||||
},
|
},
|
||||||
focus() {
|
focus() {
|
||||||
|
const ref = generator.component.getImperativeHandle(this);
|
||||||
|
if (ref && typeof ref.focus === 'function') {
|
||||||
|
ref.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
generator.component.focus(this);
|
generator.component.focus(this);
|
||||||
},
|
},
|
||||||
blur() {
|
blur() {
|
||||||
|
|||||||
Reference in New Issue
Block a user