Skip to content
Snippets Groups Projects
Unverified Commit 90d3fced authored by Chris Beer's avatar Chris Beer Committed by GitHub
Browse files

Merge pull request #2002 from ProjectMirador/1874-import-workspace-config-initial-implementation

Initial implementation import workspace config
parents 9a00105c 2a659e59
Branches
Tags
No related merge requests found
...@@ -23,11 +23,16 @@ ...@@ -23,11 +23,16 @@
"downloadExport": "Download/Export workspace", "downloadExport": "Download/Export workspace",
"downloadExportWorkspace": "Download/Export workspace", "downloadExportWorkspace": "Download/Export workspace",
"elastic": "Elastic", "elastic": "Elastic",
"errorDialogConfirm": "OK",
"errorDialogTitle": "An error occurred",
"exitFullScreen": "Exit full screen", "exitFullScreen": "Exit full screen",
"expandSidePanel": "Expand sidebar", "expandSidePanel": "Expand sidebar",
"fetchManifest": "Add", "fetchManifest": "Add",
"gallery": "Gallery", "gallery": "Gallery",
"fullScreen": "Full Screen",
"hideZoomControls": "Hide zoom controls", "hideZoomControls": "Hide zoom controls",
"import" : "Import",
"importWorkspace": "Import workspace",
"item": "Item: {{label}}", "item": "Item: {{label}}",
"language": "Language", "language": "Language",
"light": "Light theme", "light": "Light theme",
......
...@@ -18,6 +18,8 @@ const ActionTypes = { ...@@ -18,6 +18,8 @@ const ActionTypes = {
TOGGLE_WORKSPACE_EXPOSE_MODE: 'TOGGLE_WORKSPACE_EXPOSE_MODE', TOGGLE_WORKSPACE_EXPOSE_MODE: 'TOGGLE_WORKSPACE_EXPOSE_MODE',
ADD_MANIFEST: 'ADD_MANIFEST', ADD_MANIFEST: 'ADD_MANIFEST',
ADD_WINDOW: 'ADD_WINDOW', ADD_WINDOW: 'ADD_WINDOW',
ADD_ERROR: 'ADD_ERROR',
IMPORT_CONFIG: 'IMPORT_CONFIG',
SET_CANVAS: 'SET_CANVAS', SET_CANVAS: 'SET_CANVAS',
MAXIMIZE_WINDOW: 'MAXIMIZE_WINDOW', MAXIMIZE_WINDOW: 'MAXIMIZE_WINDOW',
MINIMIZE_WINDOW: 'MINIMIZE_WINDOW', MINIMIZE_WINDOW: 'MINIMIZE_WINDOW',
...@@ -28,6 +30,7 @@ const ActionTypes = { ...@@ -28,6 +30,7 @@ const ActionTypes = {
REQUEST_MANIFEST: 'REQUEST_MANIFEST', REQUEST_MANIFEST: 'REQUEST_MANIFEST',
RECEIVE_MANIFEST: 'RECEIVE_MANIFEST', RECEIVE_MANIFEST: 'RECEIVE_MANIFEST',
RECEIVE_MANIFEST_FAILURE: 'RECEIVE_MANIFEST_FAILURE', RECEIVE_MANIFEST_FAILURE: 'RECEIVE_MANIFEST_FAILURE',
REMOVE_ERROR: 'REMOVE_ERROR',
SET_CONFIG: 'SET_CONFIG', SET_CONFIG: 'SET_CONFIG',
SET_WINDOW_THUMBNAIL_POSITION: 'SET_WINDOW_THUMBNAIL_POSITION', SET_WINDOW_THUMBNAIL_POSITION: 'SET_WINDOW_THUMBNAIL_POSITION',
SET_WINDOW_VIEW_TYPE: 'SET_WINDOW_VIEW_TYPE', SET_WINDOW_VIEW_TYPE: 'SET_WINDOW_VIEW_TYPE',
......
import ActionTypes from './action-types'; import ActionTypes from './action-types';
/**
* importConfig - action creator
*
* @param {Object} config
* @memberof ActionCreators
*/
export function importConfig(config) {
return { config, type: ActionTypes.IMPORT_CONFIG };
}
/** /**
* setConfig - action creator * setConfig - action creator
* *
......
import uuid from 'uuid/v4';
import ActionTypes from './action-types';
/**
* addError - action creator
* @param {string} error
*/
export function addError(error) {
return {
id: `error-${uuid()}`,
message: error,
type: ActionTypes.ADD_ERROR,
};
}
/**
* removeError - action creator
* @param {string} id
*/
export function removeError(id) {
return { id, type: ActionTypes.REMOVE_ERROR };
}
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
*/ */
export * from './companionWindow'; export * from './companionWindow';
export * from './config'; export * from './config';
export * from './errors';
export * from './window'; export * from './window';
export * from './manifest'; export * from './manifest';
export * from './infoResponse'; export * from './infoResponse';
......
...@@ -69,11 +69,13 @@ export function addWindow(options) { ...@@ -69,11 +69,13 @@ export function addWindow(options) {
companionWindows: [ companionWindows: [
{ {
content: 'info', content: 'info',
default: true,
id: cwDefault, id: cwDefault,
position: 'left', position: 'left',
}, },
{ {
content: 'thumbnail_navigation', content: 'thumbnail_navigation',
default: true,
id: cwThumbs, id: cwThumbs,
position: options.thumbnailNavigationPosition position: options.thumbnailNavigationPosition
|| config.thumbnailNavigation.defaultPosition, || config.thumbnailNavigation.defaultPosition,
......
import {
difference,
keys,
omit,
slice,
values,
} from 'lodash';
import ActionTypes from './action-types'; import ActionTypes from './action-types';
import { importConfig } from './config';
import { addWindow, removeWindow, updateWindow } from './window';
import { addCompanionWindow, removeCompanionWindow, updateCompanionWindow } from './companionWindow';
import { updateViewport } from './canvas';
import { fetchManifest } from './manifest';
/** /**
* setWorkspaceFullscreen - action creator * setWorkspaceFullscreen - action creator
...@@ -85,3 +97,95 @@ export function toggleWorkspaceExposeMode() { ...@@ -85,3 +97,95 @@ export function toggleWorkspaceExposeMode() {
type: ActionTypes.TOGGLE_WORKSPACE_EXPOSE_MODE, type: ActionTypes.TOGGLE_WORKSPACE_EXPOSE_MODE,
}; };
} }
/**
* importWorkspace - action creator
*/
export function importWorkspace(stateExport) {
return (dispatch, getState) => {
const { viewers } = stateExport || {};
const { companionWindows } = stateExport || {};
const {
exposeModeOn,
height,
viewportPosition,
width,
} = stateExport.workspace;
const imWins = values(stateExport.windows);
const exWins = values(getState().windows);
const exWinCnt = exWins.length > imWins.length ? imWins.length : exWins.length;
/* do window independent stuff at first */
dispatch(importConfig(stateExport.config));
getState().workspace.exposeModeOn !== exposeModeOn && dispatch(toggleWorkspaceExposeMode());
dispatch(setWorkspaceViewportDimensions({ height, width }));
dispatch(setWorkspaceViewportPosition(viewportPosition));
/* now import the windows */
/*
If the existing workspace already contains windows (exWins),
we can re-use them in order to optimize the performance.
As we only can only re-use the amount of windows to be imported maximally,
slice all additional windows before
*/
const exIds = slice(exWins, 0, exWinCnt).map((exWin) => {
const imWin = imWins.shift();
const viewer = viewers[imWin.id];
dispatch(fetchManifest(imWin.manifestId));
/* remove exisiting companionWindows, except the ones marked as default */
exWin.companionWindowIds
.filter(cwId1 => !getState().companionWindows[cwId1].default)
.map(cwId2 => dispatch(removeCompanionWindow(exWin.id, cwId2)));
/* update window */
dispatch(updateWindow(exWin.id, omit(imWin, 'id', 'companionWindowIds', 'thumbnailNavigationId')));
/* update default companionWindows */
exWin.companionWindowIds
// eslint-disable-next-line max-len
.filter(cwId => getState().companionWindows[cwId] && getState().companionWindows[cwId].default)
.map((cwId) => {
const newCw = values(companionWindows)
.find(cw => cw.default && cw.content === getState().companionWindows[cwId].content);
return dispatch(updateCompanionWindow(exWin.id, cwId, omit(newCw, 'id')));
});
/* create non-default companion windows */
imWin.companionWindowIds
.filter(cwId => !companionWindows[cwId].default)
.map(cwId => dispatch(addCompanionWindow(exWin.id, omit(companionWindows[cwId], 'id'))));
dispatch(updateViewport(exWin.id, viewer));
return exWin.id;
});
/* create new windows for additionally imported ones */
const imIds = imWins.map((imWin) => {
const viewer = viewers[imWin.id];
dispatch(fetchManifest(imWin.manifestId));
dispatch(addWindow(omit(imWin, ['companionWindowIds', 'thumbnailNavigationId'])));
dispatch(updateViewport(imWin.id, viewer));
/* create non-default companion windows */
values(companionWindows)
.filter(cw => !cw.default)
.map(cw => dispatch(addCompanionWindow(imWin.id, { ...omit(cw, 'id') }, {})));
/* update default companion windows */
values(companionWindows)
.filter(cw => cw.default)
.map((cwNew) => {
const cwOld = values(getState().companionWindows)
.find(el => el.content === cwNew.content);
return dispatch(updateCompanionWindow(imWin.id, cwOld.id, omit(cwNew, 'id')));
});
return imWin.id;
});
/* close surplus windows */
difference(keys(getState().windows), exIds.concat(imIds))
.map(winId => dispatch(removeWindow(winId)));
};
}
...@@ -7,6 +7,7 @@ import ActionTypes from '../actions/action-types'; ...@@ -7,6 +7,7 @@ import ActionTypes from '../actions/action-types';
export const configReducer = (state = {}, action) => { export const configReducer = (state = {}, action) => {
switch (action.type) { switch (action.type) {
case ActionTypes.UPDATE_CONFIG: case ActionTypes.UPDATE_CONFIG:
case ActionTypes.IMPORT_CONFIG:
return deepmerge(state, action.config); return deepmerge(state, action.config);
case ActionTypes.SET_CONFIG: case ActionTypes.SET_CONFIG:
return action.config; return action.config;
......
import without from 'lodash/without';
import ActionTypes from '../actions/action-types';
const defaultState = { items: [] };
/**
* errorsReducer
*/
export const errorsReducer = (state = defaultState, action) => {
let ret;
switch (action.type) {
case ActionTypes.ADD_ERROR:
return { ...state, [action.id]: { id: action.id, message: action.message }, items: [...state.items, action.id] }; // eslint-disable-line max-len
case ActionTypes.REMOVE_ERROR:
ret = Object.keys(state).reduce((object, key) => {
if (key !== action.id) {
object[key] = state[key]; // eslint-disable-line no-param-reassign
}
return object;
}, {});
ret.items = without(ret.items, action.id);
return ret;
default:
return state;
}
};
export * from './companionWindows'; export * from './companionWindows';
export * from './errors';
export * from './workspace'; export * from './workspace';
export * from './windows'; export * from './windows';
export * from './manifests'; export * from './manifests';
......
...@@ -2,6 +2,7 @@ import { combineReducers } from 'redux'; ...@@ -2,6 +2,7 @@ import { combineReducers } from 'redux';
import { import {
companionWindowsReducer, companionWindowsReducer,
configReducer, configReducer,
errorsReducer,
infoResponsesReducer, infoResponsesReducer,
manifestsReducer, manifestsReducer,
viewersReducer, viewersReducer,
...@@ -20,6 +21,7 @@ export default function createRootReducer(pluginReducers) { ...@@ -20,6 +21,7 @@ export default function createRootReducer(pluginReducers) {
annotations: annotationsReducer, annotations: annotationsReducer,
companionWindows: companionWindowsReducer, companionWindows: companionWindowsReducer,
config: configReducer, config: configReducer,
errors: errorsReducer,
infoResponses: infoResponsesReducer, infoResponses: infoResponsesReducer,
manifests: manifestsReducer, manifests: manifestsReducer,
viewers: viewersReducer, viewers: viewersReducer,
......
...@@ -9,3 +9,10 @@ export const getFullScreenEnabled = createSelector( ...@@ -9,3 +9,10 @@ export const getFullScreenEnabled = createSelector(
[getWorkspace], [getWorkspace],
workspace => workspace.isFullscreenEnabled, workspace => workspace.isFullscreenEnabled,
); );
/** Returns the latest error from the state
* @param {object} state
*/
export function getLatestError(state) {
return state.errors.items[0] && state.errors[state.errors.items[0]];
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment