/**
* @file Save and load functionality
* @module @@actions/save
*/
import { dispatch, dispatchSet, getState } from '@@app-state';
import * as ModelState from '@@app-state/model/state';
import * as SettingsState from '@@app-state/settings/state';
import * as SolidState from '@@app-state/solid/state';
import { view, mergeDeepRight, isEmpty} from 'ramda';
import {getEndpoint, getDataSchemaURL, getFilename} from '@@selectors';
import { getLastLocalState, saveLocalState } from '@@storage';
import { Graph } from '@@graph';
import { saveFile } from '@@actions/solid/files';
import { message } from 'antd';
import { openSaveOverwritePrompt } from '@@components/controls/save-overwrite-modal';
/**
* Generates JSON save data.
* First updates the entities with their respective graph node positions and exports this data.
* @function
* @returns {{model: (*|(function(*=): (*)))}}
*/
export const generateSaveData = () => {
const bBoxesById = Graph.getBBoxesById();
dispatch(ModelState.setBoundingBoxes(bBoxesById));
return {model: view(ModelState.rootLens, getState())};
}
/**
* @function
* @param update
*/
export const updateLocalSettings = update => {
const {settings} = getLastLocalState();
saveLocalState({settings: mergeDeepRight(settings, update)});
}
/**
* Saves data either remotely or locally, based on whether a remote save location is already established.
* @function
* @returns {void|Promise<*>}
*/
export const saveData = () => {
const state = getState();
const remoteFileURL = view(SolidState.modelFileLocation, state);
if (remoteFileURL) {
return saveFile({uri: remoteFileURL, data: generateSaveData(), webId: view(SolidState.webId, state)});
} else {
return saveDataLocally();
}
};
/**
* Downloads the model data as .json
* @function
*/
export const downloadData = () => {
const data = generateSaveData();
const dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(data));
const downloadNode = document.createElement('a');
downloadNode.setAttribute('href', dataStr);
downloadNode.setAttribute('download', 'application-model.json');
document.body.appendChild(downloadNode);
downloadNode.click();
downloadNode.remove();
};
/**
* Saves data locally, prompting the user if they want to overwrite their current browser data should it change significantly.
* @function
*/
export const saveDataLocally = () => {
const saveData = generateSaveData();
// endpoint/data schema/filename
const toCheck = [getDataSchemaURL, getFilename, getEndpoint];
const oldSave = getLastLocalState();
const promptOverwrite = !isEmpty(oldSave) && toCheck.some(s => s(oldSave)) && toCheck.some(s => s(saveData)) && toCheck.some(selector => selector(saveData) !== selector(oldSave));
const onOk = () => {
saveLocalState(saveData);
dispatchSet(ModelState.dirty, false);
dispatchSet(SettingsState.lastSave, Date.now());
message.success('Data saved locally.');
};
if (promptOverwrite) {
openSaveOverwritePrompt({
onOk,
dataSchemaURL: {
old: getDataSchemaURL(oldSave),
new: getDataSchemaURL(saveData)
},
filename: {
old: getFilename(oldSave),
new: getFilename(saveData)
},
endpointURL: {
old: getEndpoint(oldSave),
new: getEndpoint(saveData)
},
})
} else {
onOk();
}
}