Source: management-system/src/frontend/backend-api/ms-api-server/browser-storage.js

import { getProcessInfo } from '@/shared-frontend-backend/helpers/processHelpers.js';
import { mergeIntoObject } from '@/shared-frontend-backend/helpers/javascriptHelpers.js';
import { setDefinitionsName, addDocumentation } from '@proceed/bpmn-helper';

let processes = undefined;

/**
 * Returns all processes that are stored in the browser
 *
 * @returns {Object} an object containing all locally stored processes
 */
export function getProcesses() {
  if (!processes) {
    let storedProcesses = localStorage.processes;

    if (!storedProcesses) {
      processes = {};
    } else {
      try {
        processes = JSON.parse(storedProcesses);
      } catch (err) {
        processes = {};
      }
    }
  }

  return processes;
}

export function updateProcesses(updated) {
  processes = updated;
  localStorage.processes = JSON.stringify(updated);
}

export function updateProcess(definitionsId, updated) {
  let updatedProcesses = { ...getProcesses() };

  if (updated) {
    updatedProcesses[definitionsId] = updated;
  } else {
    delete updatedProcesses[definitionsId];
  }

  updateProcesses(updatedProcesses);
}

/**
 * Returns if a process with the given id is stored in the browser
 *
 * @param {String} processDefinitionsId
 * @returns {Boolean}
 */
export function hasProcess(processDefinitionsId) {
  return !!getProcesses()[processDefinitionsId];
}

export function isProcessLocal(processDefinitionsId) {
  if (!hasProcess(processDefinitionsId) || getProcess(processDefinitionsId).processData.shared) {
    return false;
  }

  return true;
}

/**
 * Returns the locally stored process with the given id
 *
 * @param {String} processDefinitionsId
 * @param {Object} [processes] the list of objects to search (to avoid redundant parsing)
 * @returns {Object} an Object containing the processes information
 */
export function getProcess(processDefinitionsId, processes = getProcesses()) {
  if (!processes[processDefinitionsId]) {
    throw new Error('There is no local process with the given id!');
  }

  return JSON.parse(JSON.stringify(processes[processDefinitionsId]));
}

/**
 * Adds a new process to the browsers localStorage
 *
 * @param {String} processData the process definition and additional process info
 */
export async function addProcess(initData) {
  const { bpmn } = initData;
  const date = new Date().toUTCString();
  // create meta info object
  const processData = {
    createdOn: date,
    lastEdited: date,
    inEditingBy: [],
    departments: [],
    variables: [],
    bpmn,
    ...initData,
    ...(await getProcessInfo(bpmn)),
  };

  updateProcess(processData.id, { processData, html: {}, js: {} });

  return processData;
}

/**
 * Removes a process from the localStorage
 *
 * @param {String} processDefinitionsId
 */
export function removeProcess(processDefinitionsId) {
  updateProcess(processDefinitionsId, undefined);
}

/**
 * Updates the process definition of a process in the local storage
 *
 * @param {String} processDefinitionsId
 * @param {String} bpmn the new process definition
 */
export function updateBPMN(processDefinitionsId, bpmn) {
  const process = getProcess(processDefinitionsId);
  process.processData.bpmn = bpmn;
  updateProcess(processDefinitionsId, process);
}

/**
 * Updates the meta data about a process in the local storage
 *
 * @param {String} processDefinitionsId
 * @param {String} metaChanges contains the entries to change
 */
export function updateProcessMetaData(processDefinitionsId, metaChanges) {
  const process = getProcess(processDefinitionsId);
  const processData = { ...process.processData, lastEdited: new Date().toUTCString() };
  mergeIntoObject(processData, metaChanges, true, true, true);
  process.processData = processData;

  updateProcess(processDefinitionsId, process);

  const updatedProcess = { ...processData, bpmn: undefined };
  return updatedProcess;
}

/**
 * Changes the name of a process in its definition and meta data
 *
 * @param {String} processDefinitionsId
 * @param {String} newName
 */
export async function updateProcessName(processDefinitionsId, newName) {
  const process = getProcess(processDefinitionsId);

  let { bpmn } = process.processData;
  bpmn = await setDefinitionsName(bpmn, newName);

  process.processData.bpmn = bpmn;
  process.processData.name = newName;

  updateProcess(processDefinitionsId, process);
}

/**
 * Updates a processes description in its definition and meta data
 *
 * @param {String} processDefinitionsId
 * @param {String} description
 */
export async function updateProcessDescription(processDefinitionsId, description) {
  const process = getProcess(processDefinitionsId);

  let { bpmn } = process.processData;
  bpmn = await addDocumentation(bpmn, description);

  process.processData.bpmn = bpmn;
  process.processData.description = description;

  updateProcess(processDefinitionsId, process);
}

/**
 * Returns the user task data for all user tasks in a process
 *
 * @param {String} processDefinitionsId
 * @returns {Object} contains mapping from user task filename to user task data
 */
export async function getUserTasksHTML(processDefinitionsId) {
  return getProcess(processDefinitionsId).html;
}

/**
 * Overwrites user tasks of a process with the given ones
 *
 * @param {String} definitionsId
 * @param {Object} userTasks mapping from filenames to the contained html
 */
export function saveUserTasksHtml(definitionsId, userTasks) {
  const process = getProcess(definitionsId);

  process.html = userTasks;

  updateProcess(definitionsId, process);
}

/**
 * Saves user task data for a specific process
 *
 * @param {String} definitionsId
 * @param {String} taskFileName the tasks filename that would be used if it was stored on the server
 * @param {String} html the user task data
 */
export async function saveUserTaskHTML(definitionsId, taskFileName, html) {
  const process = getProcess(definitionsId);

  process.html[taskFileName] = html;

  updateProcess(definitionsId, process);
}

/**
 * Removes data for a specific user task
 *
 * @param {String} processDefinitionsId
 * @param {String} taskFileName
 */
export async function deleteUserTaskHTML(processDefinitionsId, taskFileName) {
  const process = getProcess(processDefinitionsId);

  delete process.html[taskFileName];

  updateProcess(processDefinitionsId, process);
}

/**
 * Saves script task data for a specific task inside a process
 *
 * @param {String} processDefinitionsId
 * @param {String} taskId
 * @param {String} js
 */
export function saveScriptTaskJS(processDefinitionsId, taskId, js) {
  const process = getProcess(processDefinitionsId);

  process.js[taskId] = js;

  updateProcess(processDefinitionsId, process);
}