Skip to content

Commit

Permalink
refactor: object selections (#256)
Browse files Browse the repository at this point in the history
  • Loading branch information
stoffeastrom committed Jan 15, 2020
1 parent 58ea812 commit 301c8aa
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 317 deletions.
21 changes: 15 additions & 6 deletions apis/nucleus/src/components/Cell.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Supernova from './Supernova';
import useRect from '../hooks/useRect';
import useLayout from '../hooks/useLayout';
import InstanceContext from '../contexts/InstanceContext';
import { createObjectSelectionAPI } from '../selections';
import useObjectSelections from '../hooks/useObjectSelections';

const initialState = err => ({
loading: false,
Expand Down Expand Up @@ -90,7 +90,6 @@ const handleModal = ({ sn, layout, model }) => {
return;
}
if (selections.id === model.id) {
selections.setLayout(layout);
if (layout && layout.qSelectionInfo && layout.qSelectionInfo.qInSelections && !selections.isModal()) {
const { targets } = sn.generator.qae.data;
const firstPropertyPath = targets[0].propertyPath;
Expand Down Expand Up @@ -139,14 +138,14 @@ const getType = async ({ types, name, version }) => {
return SN;
};

const loadType = async ({ dispatch, types, name, version, layout, model, app }) => {
const loadType = async ({ dispatch, types, name, version, layout, model, app, selections }) => {
try {
const snType = await getType({ types, name, version });
// Layout might have changed since we requested the new type -> quick return
if (layout.visualization !== name) {
return undefined;
}
const selections = createObjectSelectionAPI(model, app);

const sn = snType.create({
model,
app,
Expand All @@ -169,12 +168,13 @@ const Cell = forwardRef(({ corona, model, initialSnContext, initialSnOptions, in

const { translator, language } = useContext(InstanceContext);
const theme = useTheme();
const cellRef = useRef();
const [state, dispatch] = useReducer(contentReducer, initialState(initialError));
const [layout, { validating, canCancel, canRetry }, longrunning] = useLayout(model);
const [contentRef, contentRect, , contentNode] = useRect();
const [snContext, setSnContext] = useState(initialSnContext);
const [snOptions, setSnOptions] = useState(initialSnOptions);
const cellRef = useRef();
const [selections] = useObjectSelections(app, model);

useEffect(() => {
if (initialError) {
Expand All @@ -190,7 +190,16 @@ const Cell = forwardRef(({ corona, model, initialSnContext, initialSnOptions, in
handleModal({ sn: state.sn, layout, model });
};
const load = async (withLayout, version) => {
const sn = await loadType({ dispatch, types, name: withLayout.visualization, version, layout, model, app });
const sn = await loadType({
dispatch,
types,
name: withLayout.visualization,
version,
layout,
model,
app,
selections,
});
if (sn) {
dispatch({ type: 'LOADED', sn });
onMount();
Expand Down
16 changes: 7 additions & 9 deletions apis/nucleus/src/components/listbox/ListBoxPopover.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ import useLayout from '../../hooks/useLayout';
import ListBox from './ListBox';
import createListboxSelectionToolbar from './listbox-selection-toolbar';

import { createObjectSelectionAPI } from '../../selections';
import SelectionToolbarWithDefault, { SelectionToolbar } from '../SelectionToolbar';

import InstanceContext from '../../contexts/InstanceContext';

import ListBoxSearch from './ListBoxSearch';
import useObjectSelections from '../../hooks/useObjectSelections';

export default function ListBoxPopover({ alignTo, show, close, app, fieldName, stateName = '$' }) {
const theme = useTheme();
Expand Down Expand Up @@ -70,23 +70,21 @@ export default function ListBoxPopover({ alignTo, show, close, app, fieldName, s

const moreAlignTo = useRef();
const [showSelectionsMenu, setShowSelectionsMenu] = useState(false);
const [selections] = useObjectSelections(app, model);

if (!model || !layout || !translator) {
if (!model || !layout || !translator || !selections) {
return null;
}

const sel = createObjectSelectionAPI(model, app);
sel.setLayout(layout);

const isLocked = layout.qListObject.qDimensionInfo.qLocked === true;
const open = show && Boolean(alignTo.current);

if (open) {
sel.goModal('/qListObjectDef');
selections.goModal('/qListObjectDef');
}
const popoverClose = (e, reason) => {
const accept = reason !== 'escapeKeyDown';
sel.noModal(accept);
selections.noModal(accept);
close();
};

Expand Down Expand Up @@ -144,7 +142,7 @@ export default function ListBoxPopover({ alignTo, show, close, app, fieldName, s
<Grid item>
<SelectionToolbarWithDefault
layout={layout}
api={sel}
api={selections}
xItems={[moreItem]}
onConfirm={popoverClose}
onCancel={() => popoverClose(null, 'escapeKeyDown')}
Expand All @@ -154,7 +152,7 @@ export default function ListBoxPopover({ alignTo, show, close, app, fieldName, s
<Grid item xs>
<div ref={moreAlignTo} />
<ListBoxSearch model={model} />
<ListBox model={model} selections={sel} direction="ltr" />
<ListBox model={model} selections={selections} direction="ltr" />
{showSelectionsMenu && (
<Popover
open={showSelectionsMenu}
Expand Down
31 changes: 15 additions & 16 deletions apis/nucleus/src/hooks/useAppSelections.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint no-underscore-dangle: 0 */
import { useEffect } from 'react';
import useAppSelectionsNavigation from './useAppSelectionsNavigation';
import { useAppSelectionsStore } from '../stores/selectionsStore';
import { useAppSelectionsStore, objectSelectionsStore } from '../stores/selectionsStore';
import createKeyStore from '../stores/createKeyStore';

function createAppSelections({ app, currentSelectionsLayout, navState }) {
Expand All @@ -14,24 +14,23 @@ function createAppSelections({ app, currentSelectionsLayout, navState }) {
if (object === modalObjectStore.get(key)) {
return Promise.resolve();
}
if (modalObjectStore.get(key)) {
modalObjectStore.get(key).endSelections(accept);
modalObjectStore.get(key)._selections.emit('deactivated');
const currentObject = modalObjectStore.get(key);
if (currentObject) {
currentObject.endSelections(accept);
const objectSelections = objectSelectionsStore.get(currentObject.id);
objectSelections.emit('deactivated');
}
if (object && object !== null) {
// TODO check model state
modalObjectStore.set(key, object);
// do not return the call to beginSelection to avoid waiting for it's response
modalObjectStore
.get(key)
.beginSelections(Array.isArray(path) ? path : [path])
.catch(err => {
if (err.code === 6003) {
// If another object already is in modal -> abort and take over
return appSelections.abortModal().then(() => object.beginSelections(Array.isArray(path) ? path : [path]));
}
throw err;
});
object.beginSelections(Array.isArray(path) ? path : [path]).catch(err => {
if (err.code === 6003) {
// If another object already is in modal -> abort and take over
return appSelections.abortModal().then(() => object.beginSelections(Array.isArray(path) ? path : [path]));
}
throw err;
});
return Promise.resolve();
}
modalObjectStore.set(key, null);
Expand All @@ -40,9 +39,9 @@ function createAppSelections({ app, currentSelectionsLayout, navState }) {
isInModal() {
return modalObjectStore.get(key) !== null;
},
isModal(objectModel) {
isModal(object) {
// TODO check model state
return objectModel ? modalObjectStore.get(key) === objectModel : modalObjectStore.get(key) !== null;
return object ? modalObjectStore.get(key) === object : modalObjectStore.get(key) !== null;
},
abortModal(accept = true) {
if (!modalObjectStore.get(key)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/* eslint no-underscore-dangle: 0 */
import eventmixin from './event-mixin';

import { appSelectionsStore } from '../stores/selectionsStore';
import { useEffect } from 'react';
import { useObjectSelectionsStore } from '../stores/selectionsStore';
import useAppSelections from './useAppSelections';
import eventmixin from '../selections/event-mixin';
import useLayout from './useLayout';

const event = () => {
let prevented = false;
Expand All @@ -13,15 +15,10 @@ const event = () => {
};
};

export default function(model, app) {
if (model._selections) {
return model._selections;
}
// const appAPI = () => app._selections;
const appAPI = () => appSelectionsStore.get(app.id);
let hasSelected = false;
function createObjectSelections({ appSelections, model }) {
let layout;
let isActive = false;
let layout = {};
let hasSelected = false;

/**
* @interface
Expand All @@ -45,7 +42,7 @@ export default function(model, app) {
}
isActive = true;
this.emit('activated');
return appAPI().switchModal(model, paths, true);
return appSelections.switchModal(model, paths, true);
},
/**
* @returns {Promise}
Expand All @@ -66,7 +63,7 @@ export default function(model, app) {
isActive = false;
this.emit('confirmed');
this.emit('deactivated');
return appAPI().switchModal(null, null, true);
return appSelections.switchModal(null, null, true);
},
/**
* @returns {Promise}
Expand All @@ -76,7 +73,7 @@ export default function(model, app) {
isActive = false;
this.emit('canceled'); // FIXME - spelling?
this.emit('deactivated');
return appAPI().switchModal(null, null, false, false);
return appSelections.switchModal(null, null, false, false);
},
/**
* @param {object} s
Expand All @@ -85,7 +82,7 @@ export default function(model, app) {
*/
select(s) {
const b = this.begin([s.params[0]]);
if (!appAPI().isModal()) {
if (!appSelections.isModal()) {
return Promise.resolve();
}
hasSelected = true;
Expand All @@ -104,7 +101,7 @@ export default function(model, app) {
if (layout && layout.qListObject && layout.qListObject.qDimensionInfo) {
return !layout.qListObject.qDimensionInfo.qLocked;
}
return hasSelected && layout.qSelectionInfo.qMadeSelections;
return hasSelected || (layout && layout.qSelectionInfo.qMadeSelections);
},
/**
* @returns {boolean}
Expand All @@ -113,7 +110,7 @@ export default function(model, app) {
if (layout && layout.qListObject && layout.qListObject.qDimensionInfo) {
return !layout.qListObject.qDimensionInfo.qLocked;
}
return hasSelected && layout.qSelectionInfo.qMadeSelections;
return hasSelected || (layout && layout.qSelectionInfo.qMadeSelections);
},
/**
* @returns {boolean}
Expand All @@ -131,26 +128,46 @@ export default function(model, app) {
/**
* @returns {boolean}
*/
isModal: () => appAPI().isModal(model),
isModal: () => appSelections.isModal(model),
/**
* @param {string[]} paths
* @returns {Promise}
*/
goModal: paths => appAPI().switchModal(model, paths, false),
goModal: paths => appSelections.switchModal(model, paths, false),
/**
* @param {boolean} [accept=false]
* @returns {Promise}
*/
noModal: (accept = false) => appAPI().switchModal(null, null, accept),
noModal: (accept = false) => appSelections.switchModal(null, null, accept),
/**
* @returns {Promise}
*/
abortModal: () => appAPI().abortModal(true),
abortModal: () => appSelections.abortModal(true),
};

eventmixin(api);

model._selections = api; // eslint-disable-line no-param-reassign

return api;
}

export default function useObjectSelections(app, model) {
const [appSelections] = useAppSelections(app);
const [layout] = useLayout(model);
const key = model ? model.id : null;
const [objectSelectionsStore] = useObjectSelectionsStore();
let objectSelections = objectSelectionsStore.get(key);

useEffect(() => {
if (!appSelections || !model || objectSelections) return;

objectSelections = createObjectSelections({ appSelections, model });
objectSelectionsStore.set(key, objectSelections);
}, [appSelections, model]);

useEffect(() => {
if (!objectSelections) return;
objectSelections.setLayout(layout);
}, [objectSelections, layout]);

return [objectSelections];
}
Loading

0 comments on commit 301c8aa

Please sign in to comment.