jccguimaraes/project-viewer-plus

View on GitHub
lib/project-viewer-plus.js

Summary

Maintainability
C
1 day
Test Coverage
import path from 'path';
import etch from 'etch';
import { CompositeDisposable, Disposable } from 'atom';

import Config from './constants/config';
import {
  PLUGIN_NAME,
  DATABASE_FILE,
  LEGACY_DATABASE_FILE,
  DOCK_URI
} from './constants/base';
import state from './services/state';
import { readFile, saveFile } from './services/file';
import { transformLegacyContent } from './services/legacy';
import MainContainer from './containers/main';
import SelectList from './containers/select-list';
import EditorContainer from './containers/editor';
import ConfirmDelete from './components/confirm-delete';

/**
 * Package's entry point class
 */
export default class PVP {
  /**
   * Returns this package configuration object specific to Atom
   * @returns {Object} the package configuration
   */
  get config () {
    return Config;
  }

  /**
   * Atom's lifecycle method which gets called when the package is activated
   * @param {Object} serialized serialized content, should be dealt by atom
   * deserialization process
   * @param {Object} serialized.state current state
   */
  async activate (serialized = {}) {
    etch.setScheduler(atom.views);

    this.subscriptions = new CompositeDisposable(
      atom.workspace.addOpener(uri => this.mainOpener(uri)),
      new Disposable(() => {
        atom.workspace.getPaneItems().forEach(item => {
          if (item instanceof MainContainer) {
            item.destroy();
          }
        });
      })
    );

    state.activate();

    if (atom.workspace.paneForURI(DOCK_URI)) {
      this.mainContainer.activate();
    }

    this.readState(serialized.state);
    this.addCommands();
    this.addList();
  }

  /**
   * Atom's lifecycle method which gets called when the package is deactivated
   */
  async deactivate () {
    this.subscriptions.dispose();
    state.deactivate();

    const pane = atom.workspace.paneForURI(DOCK_URI);

    if (pane) {
      pane.destroy();
    }
  }

  /* eslint-disable-next-line require-jsdoc */
  mainOpener (uri) {
    if (uri === DOCK_URI) {
      this.createMainView();
      this.mainContainer.activate(true);
      return this.mainContainer;
    }
  }

  /* eslint-disable-next-line require-jsdoc */
  createMainView () {
    this.mainContainer = new MainContainer();
    return this.mainContainer;
  }

  /* eslint-disable-next-line require-jsdoc */
  addList () {
    // this compoment has performance issues
    // this.selectList = new SelectList();
  }

  /**
   * handler to show the Select List view.
   */
  toggleSelectList () {
    // this.selectList.show();
  }

  /* eslint-disable-next-line require-jsdoc */
  addEntry (parentId) {
    this.openEditor(null, parentId);
  }

  /* eslint-disable-next-line require-jsdoc */
  editEntry (id) {
    this.openEditor(id);
  }

  /* eslint-disable-next-line require-jsdoc */
  deleteEntry (id) {
    const item = new ConfirmDelete(id);
    atom.workspace.addModalPanel({ item });
  }

  /**
   * Handler to register commands
   */
  addCommands () {
    this.subscriptions.add(
      atom.commands.add('atom-workspace', {
        'project-viewer-plus:clear-current-state': () => {
          state.clearState();
        },
        'project-viewer-plus:save-file': () => {
          this.saveFile();
        },
        'project-viewer-plus:edit-file': () => {
          this.editFile();
        },
        'project-viewer-plus:open-editor': () => {
          this.openEditor();
        },
        'project-viewer-plus:read-file': async () => {
          const content = await this.readFile();
          if (!content) {
            return atom.notifications.addError(
              'project-viewer-plus: no **database** file found',
              { icon: 'bookmark' }
            );
          }
          try {
            state.initializeState(content, true);
          }
          catch (e) {
            atom.notifications.addError(
              'project-viewer-plus: error reading **database** from file',
              { icon: 'bookmark' }
            );
          }
        },
        'project-viewer-plus:read-legacy-file': async () => {
          const content = await this.readLegacyFile();
          if (!content) {
            return atom.notifications.addInfo(
              'project-viewer-plus: no **legacy** database file found',
              { icon: 'bookmark' }
            );
          }
          try {
            state.initializeState(transformLegacyContent(content.root), true);
          }
          catch (e) {
            atom.notifications.addError(
              'project-viewer-plus: error reading **database** from file',
              { icon: 'bookmark' }
            );
          }
        },
        'project-viewer-plus:toggle-visibility': () =>
          this.toggleMainVisibility(),
        'project-viewer-plus:toggle-focus': () => this.toggleMainFocus(),
        'project-viewer-plus:toggle-list': () => this.toggleSelectList(),
        'project-viewer-plus:add-entry': evt =>
          this.addEntry(
            evt.target.nodeName !== 'UL' && evt.target.closest('li')
              ? evt.target.closest('li').id
              : NaN
          ),
        'project-viewer-plus:edit-entry': evt =>
          evt.target.closest('li') &&
          this.editEntry(evt.target.closest('li').id),
        'project-viewer-plus:delete-entry': evt =>
          evt.target.closest('li') &&
          this.deleteEntry(evt.target.closest('li').id)
      })
    );
  }

  /* eslint-disable-next-line require-jsdoc */
  toggleMainVisibility () {
    atom.workspace.toggle(DOCK_URI);
  }

  /* eslint-disable-next-line require-jsdoc */
  toggleMainFocus () {
    if (this.mainContainer) {
      this.mainContainer.toggleFocus();
    }
  }

  /**
   * handler to read from the current file schema
   * @returns {Object} JSON parsed file content
   */
  readFile () {
    const filePath = path.join(
      atom.config.get(`${PLUGIN_NAME}.database.localPath`),
      atom.config.get(`${PLUGIN_NAME}.database.fileName`)
    );

    return readFile(filePath);
  }

  /**
   * handler to read from the legacy file schema
   * @returns {Object} JSON parsed file content
   */
  readLegacyFile () {
    const filePath = path.join(
      atom.config.get(`${PLUGIN_NAME}.database.localPath`),
      LEGACY_DATABASE_FILE
    );

    return readFile(filePath);
  }

  /**
   * Atom's lifecycle method which gets called when the package is activated
   * @param {Object} [currentState] current state, should be dealt by atom
   *                                deserialization process
   */
  async readState (currentState) {
    let content;

    try {
      return state.initializeState(currentState, true);
    }
    catch (err) {
      currentState = await this.readFile();
    }

    try {
      return state.initializeState(currentState, true);
    }
    catch (err) {
      content = await this.readLegacyFile();
    }

    try {
      currentState = transformLegacyContent(content.root);
      return state.initializeState(currentState, true);
    }
    catch (err) {
      currentState = { groups: [], projects: [] };
    }

    try {
      return state.initializeState(currentState, true);
    }
    catch (err) {
      atom.notifications.addError(
        'project-viewer-plus: could not create state',
        { icon: 'bookmark' }
      );
    }
  }

  /**
   * handler to save the current state to the file.
   * @param {string} id - the entry id if in edit mode
   */
  async saveFile () {
    const filePath = path.join(
      atom.config.get(`${PLUGIN_NAME}.database.localPath`),
      atom.config.get(`${PLUGIN_NAME}.database.fileName`)
    );

    await saveFile(
      filePath,
      JSON.stringify(state.serializeGroupById(NaN, false), null, 2)
    );
  }

  /**
   * handler to open the Editor view.
   */
  async editFile () {
    const filePath = path.join(
      atom.config.get(`${PLUGIN_NAME}.database.localPath`),
      atom.config.get(`${PLUGIN_NAME}.database.fileName`)
    );
    atom.workspace.open(filePath);
  }

  /**
   * handler to open the Editor view.
   * @param {string} id - the entry id if in edit mode
   * @param {string} parentId - the entry parent id if in edit mode
   */
  async openEditor (id, parentId) {
    atom.workspace.open(await new EditorContainer(id, parentId));
  }

  /**
   * Atom's internal serialization method.
   * @returns {Object} serialized state
   */
  serialize () {
    return {
      state: state.serializeGroupById(),
      deserializer: 'project-viewer-plus/main'
    };
  }

  /* eslint-disable-next-line require-jsdoc */
  deserializeProjectViewerPlusView (serialized) {
    return this.createMainView();
  }
}