Skip to content

Commit

Permalink
feat: give charts access to the nebula instance through useEmbed (#650)
Browse files Browse the repository at this point in the history
* feat: experimental expose embed

* feat: expose embed for legacy supernovas

* feat: expose registered types
  • Loading branch information
Caele committed Aug 24, 2021
1 parent c940d8b commit 0d19f69
Show file tree
Hide file tree
Showing 24 changed files with 170 additions and 43 deletions.
3 changes: 2 additions & 1 deletion apis/nucleus/src/__tests__/nucleus.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ describe('nucleus', () => {
some: 'thing',
},
});
expect(typesFn.getCall(0).args[0].halo.public.galaxy).to.eql({
const { galaxy } = typesFn.getCall(0).args[0].halo.public;
expect(galaxy).to.eql({
anything: {
some: 'thing',
},
Expand Down
5 changes: 4 additions & 1 deletion apis/nucleus/src/components/Cell.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -254,13 +254,14 @@ const getType = async ({ types, name, version }) => {
return SN;
};

const loadType = async ({ dispatch, types, visualization, version, model, app, selections }) => {
const loadType = async ({ dispatch, types, visualization, version, model, app, selections, nebbie }) => {
try {
const snType = await getType({ types, name: visualization, version });
const sn = snType.create({
model,
app,
selections,
nebbie,
});
return sn;
} catch (err) {
Expand All @@ -271,6 +272,7 @@ const loadType = async ({ dispatch, types, visualization, version, model, app, s

const Cell = forwardRef(({ halo, model, initialSnOptions, initialSnPlugins, initialError, onMount }, ref) => {
const { app, types } = halo;
const { nebbie } = halo.public;

const { translator, language } = useContext(InstanceContext);
const theme = useTheme();
Expand Down Expand Up @@ -329,6 +331,7 @@ const Cell = forwardRef(({ halo, model, initialSnOptions, initialSnPlugins, init
model,
app,
selections,
nebbie,
});
if (sn) {
dispatch({ type: 'LOADED', sn, visualization });
Expand Down
2 changes: 1 addition & 1 deletion apis/nucleus/src/components/Error.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export default function Error({ title = 'Error', message = '', data = [] }) {
container
direction="column"
alignItems="center"
justify="center"
justifyContent="center"
style={{ position: 'relative', height: '100%', width: '100%' }}
>
<Grid item>
Expand Down
2 changes: 1 addition & 1 deletion apis/nucleus/src/components/Loading.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default function Loading() {
container
direction="column"
alignItems="center"
justify="center"
justifyContent="center"
style={{
position: 'absolute',
width: '100%',
Expand Down
2 changes: 1 addition & 1 deletion apis/nucleus/src/components/LongRunningQuery.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export default function LongRunningQuery({ canCancel, canRetry, api }) {
container
direction="column"
alignItems="center"
justify="center"
justifyContent="center"
className={stripes}
style={{
position: 'absolute',
Expand Down
1 change: 1 addition & 0 deletions apis/nucleus/src/components/Supernova.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ const Supernova = ({ sn, snOptions: options, snPlugins: plugins, layout, appLayo
layout,
options,
plugins,
embed: halo.public.nebbie,
context: {
constraints,
// halo.public.theme is a singleton so themeName is used as dep to make sure this effect is triggered
Expand Down
3 changes: 2 additions & 1 deletion apis/nucleus/src/components/__tests__/supernova.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ describe('<Supernova />', () => {
snPlugins: [],
layout: 'layout',
appLayout: { qLocaleInfo: 'loc' },
halo: { public: { theme: 'theme' }, app: { session: {} } },
halo: { public: { theme: 'theme', nebbie: 'embedAPI' }, app: { session: {} } },
rendererOptions: {
createNodeMock: () => ({
style: {},
Expand All @@ -126,6 +126,7 @@ describe('<Supernova />', () => {
layout: 'layout',
options: snOptions,
plugins: [],
embed: 'embedAPI',
context: {
constraints: {},
appLayout: { qLocaleInfo: 'loc' },
Expand Down
1 change: 0 additions & 1 deletion apis/nucleus/src/components/listbox/ListBoxInline.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ export function ListBoxInline({ app, fieldIdentifier, stateName = '$', options =
useEffect(() => {
if (selections) {
if (!selections.isModal(model)) {
selections.goModal('/qListObjectDef');
selections.on('deactivated', () => {
setShowToolbar(false);
});
Expand Down
16 changes: 15 additions & 1 deletion apis/nucleus/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,6 @@ function nuked(configuration = {}) {
config: configuration,
public: publicAPIs,
context: currentContext,
nebbie: null,
types: null,
};

Expand Down Expand Up @@ -380,6 +379,21 @@ function nuked(configuration = {}) {
};
return fieldSels;
},
/**
* Gets a list of registered visualization types and versions
* @function
* @returns {Array<Object>} types
* @example
* const types = n.getRegisteredTypes();
* // Contains
* //[
* // {
* // name: "barchart"
* // versions:[undefined, "1.2.0"]
* // }
* //]
*/
getRegisteredTypes: types.getList,
__DO_NOT_USE__: {
types,
},
Expand Down
27 changes: 27 additions & 0 deletions apis/nucleus/src/sn/__tests__/types.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,40 @@ describe('types', () => {
);
});

it('should instantiate a type when calling get the first time', () => {
type.withArgs({ name: 'pie', version: '1.0.3' }).returns({ name: 'pie', version: '1.0.3' });
expect(c.get({ name: 'pie', version: '1.0.3' })).to.eql({ name: 'pie', version: '1.0.3' });
expect(type).to.have.been.calledWithExactly(
{
name: 'pie',
version: '1.0.3',
},
'halo',
undefined
);
});

it('should only instantiate a type when calling get the first time', () => {
type.withArgs({ name: 'pie', version: '1.0.3' }).returns({ name: 'pie', version: '1.0.3' });
c.get({ name: 'pie', version: '1.0.3' }, 'opts');
expect(c.get({ name: 'pie', version: '1.7.0' })).to.eql({ name: 'pie', version: '1.0.3' });
});

it('should throw when registering an already registered version', () => {
c.register({ name: 'pie', version: '1.0.3' }, 'opts');
const fn = () => c.register({ name: 'pie', version: '1.0.3' }, 'opts');

expect(fn).to.throw("Supernova 'pie@1.0.3' already registered.");
});

it('should fallback to first registered version when getting unknown version', () => {
type.withArgs({ name: 'pie', version: '1.0.3' }).returns({ name: 'pie', version: '1.0.3' });
type.withArgs({ name: 'pie', version: '1.0.4' }).returns({ name: 'pie', version: '1.0.4' });
c.register({ name: 'pie', version: '1.0.3' }, 'opts');
c.register({ name: 'pie', version: '1.0.4' }, 'opts');
expect(c.get({ name: 'pie', version: '1.7.0' })).to.eql({ name: 'pie', version: '1.0.3' });
});

it('should find 1.5.1 as matching version from properties', () => {
const supportsPropertiesVersion = sinon.stub();
supportsPropertiesVersion.withArgs('1.2.0').returns(true);
Expand Down
21 changes: 19 additions & 2 deletions apis/nucleus/src/sn/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,29 @@ export function create({ halo, parent }) {
return tc[name].getMatchingVersionFromProperties(propertyVersion);
},
get(typeInfo) {
const { name, version } = typeInfo;
if (!tc[name] || !tc[name].versions[version]) {
const { name } = typeInfo;
let { version } = typeInfo;
if (!tc[name]) {
// Fall back to existing version
if (__NEBULA_DEV__) {
console.warn(`Visualization ${name} is not registered.`); // eslint-disable-line no-console
}
this.register({ name, version });
} else if (!tc[name].versions[version]) {
// Fall back to existing version
const versionToUse = Object.keys(tc[name].versions)[0];
if (__NEBULA_DEV__) {
console.warn(`Version ${version} of ${name} is not registered. Falling back to version ${versionToUse}`); // eslint-disable-line no-console
}
version = versionToUse;
}
return tc[name].get(version) || p.get(typeInfo);
},
getList: () =>
Object.keys(tc).map((key) => ({
name: key,
versions: Object.keys(tc[key].versions).map((v) => (v === 'undefined' ? undefined : v)),
})),
clearFromCache: (name) => {
if (tc[name]) {
tc[name] = undefined;
Expand Down
82 changes: 54 additions & 28 deletions apis/stardust/api-spec/spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"info": {
"name": "@nebula.js/stardust",
"description": "Product and framework agnostic integration API for Qlik's Associative Engine",
"version": "1.2.0",
"version": "1.7.0",
"license": "MIT",
"stability": "stable"
},
Expand Down Expand Up @@ -341,6 +341,17 @@
"import { useTheme } from '@nebula.js/stardust';\n\nconst theme = useTheme();\nconsole.log(theme.getContrastinColorTo('#ff0000'));"
]
},
"useEmbed": {
"description": "Gets the embed instance used.",
"stability": "experimental",
"kind": "function",
"params": [],
"returns": {
"description": "The embed instance used.",
"type": "#/definitions/Embed"
},
"examples": ["import { useEmbed } from '@nebula.js/stardust';\n\nconst embed = useEmbed();\nembed.render(...)"]
},
"useTranslator": {
"description": "Gets the translator.",
"kind": "function",
Expand Down Expand Up @@ -662,6 +673,21 @@
"examples": [
"const fieldInstance = await n.field(\"MyField\");\nfieldInstance.mount(element, { title: \"Hello Field\"});"
]
},
"getRegisteredTypes": {
"description": "Gets a list of registered visualization types and versions",
"kind": "function",
"params": [],
"returns": {
"description": "types",
"kind": "array",
"items": {
"type": "Object"
}
},
"examples": [
"const types = n.getRegisteredTypes();\n// Contains\n//[\n// {\n// name: \"barchart\"\n// versions:[undefined, \"1.2.0\"]\n// }\n//]"
]
}
}
},
Expand Down Expand Up @@ -1030,33 +1056,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};"
]
},
"Field": {
"kind": "alias",
"items": {
Expand Down Expand Up @@ -1165,6 +1164,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};"
]
},
"LoadType": {
"kind": "interface",
"params": [
Expand Down
1 change: 1 addition & 0 deletions apis/stardust/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export {
usePlugins,
useConstraints,
useOptions,
useEmbed,
onTakeSnapshot,
} from '@nebula.js/supernova';

Expand Down
2 changes: 2 additions & 0 deletions apis/supernova/__tests__/unit/creator.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ describe('creator', () => {
translator: { language: () => 'en' },
};
opts = {
nebbie: 'embedAPI',
model: 'model',
app: 'app',
selections: 'selections',
Expand All @@ -103,6 +104,7 @@ describe('creator', () => {
app: 'app',
global: undefined,
selections: 'selections',
nebbie: 'embedAPI',
element: undefined,
theme: undefined,
translator: galaxy.translator,
Expand Down
10 changes: 10 additions & 0 deletions apis/supernova/src/__tests__/hooks.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
useConstraints,
useOptions,
onTakeSnapshot,
useEmbed,
} from '../hooks';

describe('hooks', () => {
Expand Down Expand Up @@ -755,6 +756,7 @@ describe('hooks', () => {
theme: 'theme',
translator: 'translator',
plugins: 'plugins',
nebbie: 'embed',
layout: 'layout',
appLayout: 'appLayout',
constraints: 'constraints',
Expand Down Expand Up @@ -900,5 +902,13 @@ describe('hooks', () => {
c.__hooks.snaps[0].fn();
expect(spy.callCount).to.equal(1);
});
it('useEmbed', () => {
let value;
c.fn = () => {
value = useEmbed();
};
run(c);
expect(value).to.eql('embed');
});
});
});
1 change: 1 addition & 0 deletions apis/supernova/src/creator.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ function createWithHooks(generator, opts, galaxy) {
app: opts.app,
global: qGlobal,
selections: opts.selections,
nebbie: opts.nebbie,
element: undefined, // set on mount
// ---- singletons ----
deviceType: galaxy.deviceType,
Expand Down
Loading

0 comments on commit 0d19f69

Please sign in to comment.