<commit_before>import React, { PropTypes } from 'react';
import { Button } from 'react-bootstrap';
import Select from 'react-select';
import { PermissionsApi, PrincipalsApi } from 'loom-data';
import StringConsts from '../../../../utils/Consts/StringConsts';
import { Permission } from '../../../../core/permissions/Permission';
import ActionConsts from '../../../../utils/Consts/ActionConsts';
import { USER, ROLE, AUTHENTICATED_USER } from '../../../../utils/Consts/UserRoleConsts';
import styles from '../styles.module.css';

const views = {
  GLOBAL: 0,
  ROLES: 1,
  EMAILS: 2
};

const orders = {
  FIRST: 'first',
  LAST: 'last'
}

const permissionLevels = {
  hidden: [],
  discover: [Permission.DISCOVER.name],
  link: [Permission.DISCOVER.name, Permission.LINK.name],
  read: [Permission.DISCOVER.name, Permission.LINK.name, Permission.READ.name],
  write: [Permission.DISCOVER.name, Permission.LINK.name, Permission.READ.name, Permission.WRITE.name],
  owner: [Permission.DISCOVER.name, Permission.LINK.name, Permission.READ.name, Permission.WRITE.name, Permission.OWNER.name]
};

const viewLabels = {
  0: 'Everyone',
  1: 'Roles',
  2: 'Emails'
};

const accessOptions = {
  Hidden: 'Hidden',
  Discover: 'Discover',
  Link: 'Link',
  Read: 'Read',
  Write: 'Write',
  Owner: 'Owner'
};

const permissionOptions = {
  Discover: 'Discover',
  Link: 'Link',
  Read: 'Read',
  Write: 'Write',
  Owner: 'Owner'
};

export class PermissionsPanel extends React.Component {
  static propTypes = {
    entitySetId: PropTypes.string,
    propertyTypeId: PropTypes.string,
  }

  constructor(props) {
    super(props);
    const options = (this.props.propertyTypeId === undefined) ?
      Object.keys(accessOptions) : Object.keys(permissionOptions);
    this.state = {
      view: views.GLOBAL,
      updateSuccess: false,
      updateError: false,
      globalValue: options[0],
      roleAcls: { Discover: [], Link: [], Read: [], Write: [] },
      userAcls: { Discover: [], Link: [], Read: [], Write: [], Owner: [] },
      rolesView: accessOptions.Write,
      emailsView: accessOptions.Write,
      newRoleValue: '',
      newEmailValue: '',
      allUsersById: {},
      allRolesList: new Set(),
      loadUsersError: false
    };
  }

  componentDidMount() {
    this.loadAcls(false);
  }

  loadAllUsersAndRoles = () => {
    let allUsersById = {};
    const allRolesList = new Set();
    const myId = JSON.parse(localStorage.profile).user_id;
    PrincipalsApi.getAllUsers()
    .then((users) => {
      allUsersById = users;
      Object.keys(users).forEach((userId) => {
        users[userId].roles.forEach((role) => {
          if (role !== AUTHENTICATED_USER) allRolesList.add(role);
        });
      });
      allUsersById[myId] = null;
      this.setState({
        allUsersById,
        allRolesList,
        loadUsersError: false
      });
    }).catch(() => {
      this.setState({ loadUsersError: true });
    });
  }

  getPermission = (permissions) => {
    if (permissions.includes(permissionOptions.Owner.toUpperCase())) return permissionOptions.Owner;
    if (permissions.includes(permissionOptions.Write.toUpperCase())) return permissionOptions.Write;
    if (permissions.includes(permissionOptions.Read.toUpperCase())) return permissionOptions.Read;
    if (permissions.includes(permissionOptions.Link.toUpperCase())) return permissionOptions.Link;
    return permissionOptions.Discover;
  }

  updateStateAcls = (aces, updateSuccess) => {
    let globalValue = accessOptions[0];
    const roleAcls = { Discover: [], Link: [], Read: [], Write: [] };
    const userAcls = { Discover: [], Link: [], Read: [], Write: [], Owner: [] };
    aces.forEach((ace) => {
      if (ace.permissions.length > 0) {
        if (ace.principal.type === ROLE) {
          if (ace.principal.id === AUTHENTICATED_USER) {
            globalValue = this.getPermission(ace.permissions);
          }
          else {
            roleAcls[this.getPermission(ace.permissions)].push(ace.principal.id);
          }
        }
        else {
          userAcls[this.getPermission(ace.permissions)].push(ace.principal.id);
        }
      }
    });
    this.setState({
      globalValue,
      roleAcls,
      userAcls,
      updateSuccess,
      newRoleValue: '',
      newEmailValue: '',
      updateError: false
    });
  }

  loadAcls = (updateSuccess) => {
    const { propertyTypeId, entitySetId } = this.props;
    const aclKey = [entitySetId];
    if (propertyTypeId) aclKey.push(propertyTypeId);
    this.loadAllUsersAndRoles();
    PermissionsApi.getAcl(aclKey)
    .then((acls) => {
      this.updateStateAcls(acls.aces, updateSuccess);
    }).catch(() => {
      this.setState({ updateError: true });
    });
  }

  shouldShowSuccess = {
    true: styles.updateSuccess,
    false: styles.hidden
  }

  shouldShowError = {
    true: styles.errorMsg,
    false: styles.hidden
  }

  switchView = (view) => {
    this.setState({
      view,
      updateSuccess: false,
      updateError: false
    });
  }

  getSelectedClassName = (view) => {
    return (view === this.state.view) ? `${styles.edmNavbarButton} ${styles.edmNavbarButtonSelected}` : styles.edmNavbarButton;
  }

  getFirstLastClassName = (order) => {
    var firstLastClassName;
    if (order) {
      if (order === 'first') {
        firstLastClassName = styles.firstEdmButton;
      } else if (order === 'last') {
        firstLastClassName = styles.lastEdmButton;
      };

      return firstLastClassName;
    }

    return null;
  }

  getClassName = (view, order) => {
    var selectedClassName = this.getSelectedClassName(view);
    var firstLastClassName = this.getFirstLastClassName(order);

    return `${selectedClassName} ${firstLastClassName}`;
  }

  getPanelViewContents = () => {
    switch (this.state.view) {
      case views.ROLES:
        return this.getRolesView();
      case views.EMAILS:
        return this.getEmailsView();
      case views.GLOBAL:
      default:
        return this.getGlobalView();
    }
  }

  updatePermissions(action, principal, view) {
    const { entitySetId, propertyTypeId } = this.props;
    const permissions = (action === ActionConsts.REMOVE) ?
      [view.toUpperCase()] : permissionLevels[view.toLowerCase()];
    const aclKey = [entitySetId];
    if (propertyTypeId) aclKey.push(propertyTypeId);
    const aces = [{ principal, permissions }];
    const acl = { aclKey, aces };
    const req = { action, acl };
    PermissionsApi.updateAcl(req)
    .then(() => {
      this.loadAcls(true);
    }).catch(() => {
      this.setState({
        updateError: true
      });
    });
  }

  updateGlobalPermissions = () => {
    this.updateRoles(ActionConsts.SET, AUTHENTICATED_USER, this.state.globalValue);
  }

  updateDropdownValue = (e) => {
    this.setState({ globalValue: e.value });
  }

  buttonStyle = (view, viewState) => {
    return (view === viewState) ? `${styles.edmNavbarButton} ${styles.edmNavbarButtonSelected}` : styles.edmNavbarButton;
  }

  getGlobalView = () => {
    const optionNames = (this.props.propertyTypeId === undefined) ?
      Object.keys(accessOptions) : Object.keys(permissionOptions);
    const options = optionNames.filter(name => name !== accessOptions.Owner).map((name) => {
      return {
        value: name,
        label: name
      };
    });
    return (

Unable to load permissions.

Choose the default permissions for all authenticated users:

          <Select
              options={options}
              onChange={this.updateDropdownValue}
              value={this.state.globalValue} />

        <Button
            bsStyle="primary"
            onClick={this.updateGlobalPermissions}>Save changes</Button>

    );
  }

  changeRolesView = (newView) => {
    this.setState({ rolesView: newView });
  }

  updateRoles = (action, role, view) => {
    const principal = {
      type: ROLE,
      id: role
    };

    // Only if changes were made, save changes
    if (role) {
      this.updatePermissions(action, principal, view);
    }
  }

  handleNewRoleChange = (e) => {
    const newRoleValue = (e && e !== undefined) ? e.value : StringConsts.EMPTY;
    this.setState({ newRoleValue });
  }

  viewPermissionTypeButton = (permission, fn, currView) => {
    if (permission === accessOptions.Hidden && this.props.propertyTypeId !== undefined) return null;
    return (
      <button
          onClick={() => {
            fn(permission);
          }}
          className={this.buttonStyle(permission, currView)}>

{permission}

      </button>
    );
  }

  getRoleOptions = (roleList) => {
    const roleOptionsSet = this.state.allRolesList;
    const roleOptions = [];
    roleList.forEach((role) => {
      roleOptionsSet.delete(role);
    });
    roleOptionsSet.forEach((role) => {
      roleOptions.push({ value: role, label: role });
    });
    return roleOptions;
  }

  getRolesView = () => {
    const { roleAcls, rolesView, newRoleValue } = this.state;
    const roleList = roleAcls[rolesView];
    const roleOptions = this.getRoleOptions(roleList);
    const hiddenBody = roleList.map((role) => {
      return (

            <button
                onClick={() => {
                  this.updateRoles(ActionConsts.REMOVE, role, rolesView);
                }}
                className={styles.deleteButton}>-</button>

          <div className={`${styles.inline} ${styles.padLeft}`}>{role}

      );
    });
    return (

Unable to load roles.

Choose default permissions for specific roles.

        <div className={`${styles.inline} ${styles.padTop}`}>
          {this.viewPermissionTypeButton(accessOptions.Write, this.changeRolesView, rolesView)}
          {this.viewPermissionTypeButton(accessOptions.Read, this.changeRolesView, rolesView)}
          {this.viewPermissionTypeButton(accessOptions.Link, this.changeRolesView, rolesView)}
          {this.viewPermissionTypeButton(accessOptions.Discover, this.changeRolesView, rolesView)}

          {hiddenBody}

          <Select
              value={newRoleValue}
              options={roleOptions}
              onChange={this.handleNewRoleChange}
              className={`${styles.inputBox} ${styles.permissionInputWidth}`} />
            <Button
              bsStyle="primary"
              className={`${styles.spacerMargin}`}
              onClick={() => {
                this.updateRoles(ActionConsts.SET, newRoleValue, rolesView);
              }}>Save</Button>

    );
  }

  changeEmailsView = (newView) => {
    this.setState({ emailsView: newView });
  }

  updateEmails = (action, userId, view) => {
    const principal = {
      type: USER,
      id: userId
    };
    this.updatePermissions(action, principal, view);
  }

  handleNewEmailChange = (e) => {
    const newEmailValue = (e && e !== undefined) ? e.value : StringConsts.EMPTY;
    this.setState({ newEmailValue });
  }

  getEmailOptions = (userIdList) => {
    const emailOptions = [];
    Object.keys(this.state.allUsersById).forEach((id) => {
      if (!userIdList.includes(id) && this.state.allUsersById[id] && this.state.allUsersById[id].email) {
        emailOptions.push({ label: this.state.allUsersById[id].email, value: id });
      }
    });
    return emailOptions;
  }

  getEmailsView = () => {
    const { userAcls, emailsView, newEmailValue } = this.state;
    const userIdList = userAcls[emailsView].filter((userId) => {
      return (this.state.allUsersById[userId] && this.state.allUsersById[userId].email);
    });

    const emailOptions = this.getEmailOptions(userIdList);
    const emailListBody = userIdList.map((userId) => {
      return (

            <button
                onClick={() => {
                  this.updateEmails(ActionConsts.REMOVE, userId, emailsView);
                }}
                className={styles.deleteButton}>-</button>

          <div className={`${styles.inline} ${styles.padLeft}`}>{this.state.allUsersById[userId].email}

      );
    });

    return (

Unable to load users.

Choose permissions for specific users.

        <div className={`${styles.padTop} ${styles.inline}`}>
          {this.viewPermissionTypeButton(accessOptions.Owner, this.changeEmailsView, emailsView)}
          {this.viewPermissionTypeButton(accessOptions.Write, this.changeEmailsView, emailsView)}
          {this.viewPermissionTypeButton(accessOptions.Read, this.changeEmailsView, emailsView)}
          {this.viewPermissionTypeButton(accessOptions.Link, this.changeEmailsView, emailsView)}
          {this.viewPermissionTypeButton(accessOptions.Discover, this.changeEmailsView, emailsView)}

          {emailListBody}

          <Select
              value={newEmailValue}
              options={emailOptions}
              onChange={this.handleNewEmailChange}
              className={`${styles.inputBox} ${styles.permissionInputWidth}`} />
            <Button
              bsStyle="primary"
              className={`${styles.spacerMargin}`}
              onClick={() => {
                this.updateEmails(ActionConsts.SET, newEmailValue, emailsView);
              }}>Save</Button>

    );
  }

  renderViewButton = (view, order) => {
    return (
      <button
          onClick={() => {
            this.switchView(view);
          }}
          className={this.getClassName(view, order)}>

{viewLabels[view]}

      </button>
    );
  }

  render() {
    return (

            {this.renderViewButton(views.GLOBAL, orders.FIRST)}
            {this.renderViewButton(views.ROLES)}
            {this.renderViewButton(views.EMAILS, orders.LAST)}

{this.getPanelViewContents()}

          Your changes have been saved.

          Unable to save changes.

    );
  }
}

export default PermissionsPanel;
<commit_msg>Add rounded corners to all Manage Permissions modal tab bars<commit_after>import React, { PropTypes } from 'react';
import { Button } from 'react-bootstrap';
import Select from 'react-select';
import { PermissionsApi, PrincipalsApi } from 'loom-data';
import StringConsts from '../../../../utils/Consts/StringConsts';
import { Permission } from '../../../../core/permissions/Permission';
import ActionConsts from '../../../../utils/Consts/ActionConsts';
import { USER, ROLE, AUTHENTICATED_USER } from '../../../../utils/Consts/UserRoleConsts';
import styles from '../styles.module.css';

const views = {
  GLOBAL: 0,
  ROLES: 1,
  EMAILS: 2
};

const orders = {
  FIRST: 'first',
  LAST: 'last'
}

const permissionLevels = {
  hidden: [],
  discover: [Permission.DISCOVER.name],
  link: [Permission.DISCOVER.name, Permission.LINK.name],
  read: [Permission.DISCOVER.name, Permission.LINK.name, Permission.READ.name],
  write: [Permission.DISCOVER.name, Permission.LINK.name, Permission.READ.name, Permission.WRITE.name],
  owner: [Permission.DISCOVER.name, Permission.LINK.name, Permission.READ.name, Permission.WRITE.name, Permission.OWNER.name]
};

const viewLabels = {
  0: 'Everyone',
  1: 'Roles',
  2: 'Emails'
};

const accessOptions = {
  Hidden: 'Hidden',
  Discover: 'Discover',
  Link: 'Link',
  Read: 'Read',
  Write: 'Write',
  Owner: 'Owner'
};

const permissionOptions = {
  Discover: 'Discover',
  Link: 'Link',
  Read: 'Read',
  Write: 'Write',
  Owner: 'Owner'
};

export class PermissionsPanel extends React.Component {
  static propTypes = {
    entitySetId: PropTypes.string,
    propertyTypeId: PropTypes.string,
  }

  constructor(props) {
    super(props);
    const options = (this.props.propertyTypeId === undefined) ?
      Object.keys(accessOptions) : Object.keys(permissionOptions);
    this.state = {
      view: views.GLOBAL,
      updateSuccess: false,
      updateError: false,
      globalValue: options[0],
      roleAcls: { Discover: [], Link: [], Read: [], Write: [] },
      userAcls: { Discover: [], Link: [], Read: [], Write: [], Owner: [] },
      rolesView: accessOptions.Write,
      emailsView: accessOptions.Write,
      newRoleValue: '',
      newEmailValue: '',
      allUsersById: {},
      allRolesList: new Set(),
      loadUsersError: false
    };
  }

  componentDidMount() {
    this.loadAcls(false);
  }

  loadAllUsersAndRoles = () => {
    let allUsersById = {};
    const allRolesList = new Set();
    const myId = JSON.parse(localStorage.profile).user_id;
    PrincipalsApi.getAllUsers()
    .then((users) => {
      allUsersById = users;
      Object.keys(users).forEach((userId) => {
        users[userId].roles.forEach((role) => {
          if (role !== AUTHENTICATED_USER) allRolesList.add(role);
        });
      });
      allUsersById[myId] = null;
      this.setState({
        allUsersById,
        allRolesList,
        loadUsersError: false
      });
    }).catch(() => {
      this.setState({ loadUsersError: true });
    });
  }

  getPermission = (permissions) => {
    if (permissions.includes(permissionOptions.Owner.toUpperCase())) return permissionOptions.Owner;
    if (permissions.includes(permissionOptions.Write.toUpperCase())) return permissionOptions.Write;
    if (permissions.includes(permissionOptions.Read.toUpperCase())) return permissionOptions.Read;
    if (permissions.includes(permissionOptions.Link.toUpperCase())) return permissionOptions.Link;
    return permissionOptions.Discover;
  }

  updateStateAcls = (aces, updateSuccess) => {
    let globalValue = accessOptions[0];
    const roleAcls = { Discover: [], Link: [], Read: [], Write: [] };
    const userAcls = { Discover: [], Link: [], Read: [], Write: [], Owner: [] };
    aces.forEach((ace) => {
      if (ace.permissions.length > 0) {
        if (ace.principal.type === ROLE) {
          if (ace.principal.id === AUTHENTICATED_USER) {
            globalValue = this.getPermission(ace.permissions);
          }
          else {
            roleAcls[this.getPermission(ace.permissions)].push(ace.principal.id);
          }
        }
        else {
          userAcls[this.getPermission(ace.permissions)].push(ace.principal.id);
        }
      }
    });
    this.setState({
      globalValue,
      roleAcls,
      userAcls,
      updateSuccess,
      newRoleValue: '',
      newEmailValue: '',
      updateError: false
    });
  }

  loadAcls = (updateSuccess) => {
    const { propertyTypeId, entitySetId } = this.props;
    const aclKey = [entitySetId];
    if (propertyTypeId) aclKey.push(propertyTypeId);
    this.loadAllUsersAndRoles();
    PermissionsApi.getAcl(aclKey)
    .then((acls) => {
      this.updateStateAcls(acls.aces, updateSuccess);
    }).catch(() => {
      this.setState({ updateError: true });
    });
  }

  shouldShowSuccess = {
    true: styles.updateSuccess,
    false: styles.hidden
  }

  shouldShowError = {
    true: styles.errorMsg,
    false: styles.hidden
  }

  switchView = (view) => {
    this.setState({
      view,
      updateSuccess: false,
      updateError: false
    });
  }

/**************WORKSPACE*****************/
  getClassName = (view, order) => {
    var selectedClassName = this.getSelectedClassName(view);
    var firstLastClassName = this.getFirstLastClassName(order);

    return `${selectedClassName} ${firstLastClassName}`;
  }

  getSelectedClassName = (view) => {
    return (view === this.state.view) ? `${styles.edmNavbarButton} ${styles.edmNavbarButtonSelected}` : styles.edmNavbarButton;
  }

  getFirstLastClassName = (order) => {
    var firstLastClassName;
    if (order) {
      if (order === 'first') {
        firstLastClassName = styles.firstEdmButton;
      } else if (order === 'last') {
        firstLastClassName = styles.lastEdmButton;
      };

      return firstLastClassName;
    }

    return null;
  }

////////////

  buttonStyle = (view, viewState, order) => {
    var buttonSelectedStyle = this.buttonSelectedStyle(view, viewState);
    var buttonFirstLastStyle = this.buttonFirstLastStyle(order);

    return `${buttonSelectedStyle} ${buttonFirstLastStyle}`;
  }

  buttonSelectedStyle = (view, viewState) => {
    return (view === viewState) ? `${styles.edmNavbarButton} ${styles.edmNavbarButtonSelected}` : styles.edmNavbarButton;
  }

  buttonFirstLastStyle = (order) => {
    var firstLastClassName;
    if (order) {
      if (order === 'first') {
        firstLastClassName = styles.firstEdmButton;
      } else if (order === 'last') {
        firstLastClassName = styles.lastEdmButton;
      };

      return firstLastClassName;
    }

    return null;
  }

  /**************WORKSPACE*****************/

  getPanelViewContents = () => {
    switch (this.state.view) {
      case views.ROLES:
        return this.getRolesView();
      case views.EMAILS:
        return this.getEmailsView();
      case views.GLOBAL:
      default:
        return this.getGlobalView();
    }
  }

  updatePermissions(action, principal, view) {
    const { entitySetId, propertyTypeId } = this.props;
    const permissions = (action === ActionConsts.REMOVE) ?
      [view.toUpperCase()] : permissionLevels[view.toLowerCase()];
    const aclKey = [entitySetId];
    if (propertyTypeId) aclKey.push(propertyTypeId);
    const aces = [{ principal, permissions }];
    const acl = { aclKey, aces };
    const req = { action, acl };
    PermissionsApi.updateAcl(req)
    .then(() => {
      this.loadAcls(true);
    }).catch(() => {
      this.setState({
        updateError: true
      });
    });
  }

  updateGlobalPermissions = () => {
    this.updateRoles(ActionConsts.SET, AUTHENTICATED_USER, this.state.globalValue);
  }

  updateDropdownValue = (e) => {
    this.setState({ globalValue: e.value });
  }

  // buttonStyle = (view, viewState, order) => {
  //   var buttonSelectedStyle = this.buttonSelectedStyle(view, viewState);
  //   var buttonFirstLastStyle = this.buttonFirstLastStyle(order);
  //
  //   return `${buttonSelectedStyle} ${buttonFirstLastStyle}`;
  // }
  //
  // buttonSelectedStyle = (view, viewState) => {
  //   return (view === viewState) ? `${styles.edmNavbarButton} ${styles.edmNavbarButtonSelected}` : styles.edmNavbarButton;
  // }
  //
  // buttonFirstLastStyle = (order) => {
  //   var firstLastClassName;
  //   if (order) {
  //     if (order === 'first') {
  //       firstLastClassName = styles.firstEdmButton;
  //     } else if (order === 'last') {
  //       firstLastClassName = styles.lastEdmButton;
  //     };
  //
  //     return firstLastClassName;
  //   }
  //
  //   return null;
  // }

  getGlobalView = () => {
    const optionNames = (this.props.propertyTypeId === undefined) ?
      Object.keys(accessOptions) : Object.keys(permissionOptions);
    const options = optionNames.filter(name => name !== accessOptions.Owner).map((name) => {
      return {
        value: name,
        label: name
      };
    });
    return (

Unable to load permissions.

Choose the default permissions for all authenticated users:

          <Select
              options={options}
              onChange={this.updateDropdownValue}
              value={this.state.globalValue} />

        <Button
            bsStyle="primary"
            onClick={this.updateGlobalPermissions}>Save changes</Button>

    );
  }

  changeRolesView = (newView) => {
    this.setState({ rolesView: newView });
  }

  updateRoles = (action, role, view) => {
    const principal = {
      type: ROLE,
      id: role
    };

    // Only if changes were made, save changes
    if (role) {
      this.updatePermissions(action, principal, view);
    }
  }

  handleNewRoleChange = (e) => {
    const newRoleValue = (e && e !== undefined) ? e.value : StringConsts.EMPTY;
    this.setState({ newRoleValue });
  }

  viewPermissionTypeButton = (permission, fn, currView, order) => {
    if (permission === accessOptions.Hidden && this.props.propertyTypeId !== undefined) return null;
    return (
      <button
          onClick={() => {
            fn(permission);
          }}
          className={this.buttonStyle(permission, currView, order)}>

{permission}

      </button>
    );
  }

  getRoleOptions = (roleList) => {
    const roleOptionsSet = this.state.allRolesList;
    const roleOptions = [];
    roleList.forEach((role) => {
      roleOptionsSet.delete(role);
    });
    roleOptionsSet.forEach((role) => {
      roleOptions.push({ value: role, label: role });
    });
    return roleOptions;
  }

  getRolesView = () => {
    const { roleAcls, rolesView, newRoleValue } = this.state;
    const roleList = roleAcls[rolesView];
    const roleOptions = this.getRoleOptions(roleList);
    const hiddenBody = roleList.map((role) => {
      return (

            <button
                onClick={() => {
                  this.updateRoles(ActionConsts.REMOVE, role, rolesView);
                }}
                className={styles.deleteButton}>-</button>

          <div className={`${styles.inline} ${styles.padLeft}`}>{role}

      );
    });
    return (

Unable to load roles.

Choose default permissions for specific roles.

        <div className={`${styles.inline} ${styles.padTop}`}>
          {this.viewPermissionTypeButton(accessOptions.Write, this.changeRolesView, rolesView, orders.FIRST)}
          {this.viewPermissionTypeButton(accessOptions.Read, this.changeRolesView, rolesView)}
          {this.viewPermissionTypeButton(accessOptions.Link, this.changeRolesView, rolesView)}
          {this.viewPermissionTypeButton(accessOptions.Discover, this.changeRolesView, rolesView, orders.LAST)}

          {hiddenBody}

          <Select
              value={newRoleValue}
              options={roleOptions}
              onChange={this.handleNewRoleChange}
              className={`${styles.inputBox} ${styles.permissionInputWidth}`} />
            <Button
              bsStyle="primary"
              className={`${styles.spacerMargin}`}
              onClick={() => {
                this.updateRoles(ActionConsts.SET, newRoleValue, rolesView);
              }}>Save</Button>

    );
  }

  changeEmailsView = (newView) => {
    this.setState({ emailsView: newView });
  }

  updateEmails = (action, userId, view) => {
    const principal = {
      type: USER,
      id: userId
    };
    this.updatePermissions(action, principal, view);
  }

  handleNewEmailChange = (e) => {
    const newEmailValue = (e && e !== undefined) ? e.value : StringConsts.EMPTY;
    this.setState({ newEmailValue });
  }

  getEmailOptions = (userIdList) => {
    const emailOptions = [];
    Object.keys(this.state.allUsersById).forEach((id) => {
      if (!userIdList.includes(id) && this.state.allUsersById[id] && this.state.allUsersById[id].email) {
        emailOptions.push({ label: this.state.allUsersById[id].email, value: id });
      }
    });
    return emailOptions;
  }

  getEmailsView = () => {
    const { userAcls, emailsView, newEmailValue } = this.state;
    const userIdList = userAcls[emailsView].filter((userId) => {
      return (this.state.allUsersById[userId] && this.state.allUsersById[userId].email);
    });

    const emailOptions = this.getEmailOptions(userIdList);
    const emailListBody = userIdList.map((userId) => {
      return (

            <button
                onClick={() => {
                  this.updateEmails(ActionConsts.REMOVE, userId, emailsView);
                }}
                className={styles.deleteButton}>-</button>

          <div className={`${styles.inline} ${styles.padLeft}`}>{this.state.allUsersById[userId].email}

      );
    });

    return (

Unable to load users.

Choose permissions for specific users.

        <div className={`${styles.padTop} ${styles.inline}`}>
          {this.viewPermissionTypeButton(accessOptions.Owner, this.changeEmailsView, emailsView, orders.FIRST)}
          {this.viewPermissionTypeButton(accessOptions.Write, this.changeEmailsView, emailsView)}
          {this.viewPermissionTypeButton(accessOptions.Read, this.changeEmailsView, emailsView)}
          {this.viewPermissionTypeButton(accessOptions.Link, this.changeEmailsView, emailsView)}
          {this.viewPermissionTypeButton(accessOptions.Discover, this.changeEmailsView, emailsView, orders.LAST)}

          {emailListBody}

          <Select
              value={newEmailValue}
              options={emailOptions}
              onChange={this.handleNewEmailChange}
              className={`${styles.inputBox} ${styles.permissionInputWidth}`} />
            <Button
              bsStyle="primary"
              className={`${styles.spacerMargin}`}
              onClick={() => {
                this.updateEmails(ActionConsts.SET, newEmailValue, emailsView);
              }}>Save</Button>

    );
  }

  renderViewButton = (view, order) => {
    return (
      <button
          onClick={() => {
            this.switchView(view);
          }}
          className={this.getClassName(view, order)}>

{viewLabels[view]}

      </button>
    );
  }

  render() {
    return (

            {this.renderViewButton(views.GLOBAL, orders.FIRST)}
            {this.renderViewButton(views.ROLES)}
            {this.renderViewButton(views.EMAILS, orders.LAST)}

{this.getPanelViewContents()}

          Your changes have been saved.

          Unable to save changes.

    );
  }
}

export default PermissionsPanel;
<|endoftext|>


<commit_before>import {LitElement, html} from "lit";
import UtilsNew from "../../core/utilsNew.js";
import "./clinical-analysis-grid.js";

export default class ClinicalAnalysisGroup extends LitElement {

    constructor() {
        super();
        this.#init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            opencgaSession: {
                type: Object,
            },
            query: {
                type: Object,
            },
            active: {
                type: Boolean,
            },
            config: {
                type: Object,
            },
        };
    }

    #init() {
        this._prefix = UtilsNew.randomString(8);
        this._config = this.getDefaultConfig();
        this.activeGroup = this._config.groups[0];
        this.groups = [];
    }

    updated(changedProperties) {
        if (changedProperties.has("opencgaSession") || changedProperties.has("config") || changedProperties.has("active")) {
            this.propertyObserver();
        }
    }

    propertyObserver() {
        if (this.opencgaSession && this.active) {
            this._config = {
                ...this.getDefaultConfig(),
                ...this.config,
                toolbar: {
                    ...(this.config.toolbar || {}),
                    showCreate: false, // Hide create button in each grid
                },
            };

            this.updateGroups();
        }
    }

    updateGroups() {
        this.groups = []; // Reset groups
        this.requestUpdate();
        this.opencgaSession.opencgaClient.clinical()
            .distinct(this.activeGroup.distinctField, {
                study: this.opencgaSession.study.fqn,
            })
            .then(response => {
                this.groups = response.getResults();

                // Check if a custom sorting function has been provided
                if (typeof this.activeGroup.customSort === "function") {
                    this.groups = this.activeGroup.customSort(this.groups);
                }

                this.requestUpdate();
            });
    }

    onGroupChange(newGroup) {
        this.activeGroup = newGroup;
        this.updateGroups();
    }

    onQueryComplete(event, item) {
        const totalResults = event.detail.value?.responses[0]?.numTotalResults || 0;
        if (totalResults > 0) {
            this.querySelector(`#${this._prefix}GroupCount${item}`).textContent = `(${totalResults} cases)`;
        }
    }

    onRowUpdate() {
        // If a row has been updated, we force a refresh of all groups
        this.updateGroups();
    }

    render() {
        return html`

                    ${this.config?.toolbar?.showCreate ? html`

                            New

                    ` : null}

                        <button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown">

                            Group by
                        </button>

                            ${this._config.groups.map(group => html`

                                     this.onGroupChange(group)}">

                                            <input
                                                type="radio"
                                                name="CaseGroupBy"
                                                style="margin-top:0px;"
                                                ?checked="${group.id === this.activeGroup.id}"
                                            />
                                            ${group.display.title}

                            `)}

                ${this.groups.map(item => html`

                            ${item || this.activeGroup.display.emptyTitle}

                        <clinical-analysis-grid
                            .opencgaSession="${this.opencgaSession}"
                            .config="${this._config}"
                            .query="${{
                                ...this.query,
                                [this.activeGroup.queryField]: item,
                            }}"
                            .active="${true}"
                            @rowUpdate="${() => this.onRowUpdate()}"
                            @queryComplete="${e => this.onQueryComplete(e, item)}">
                        </clinical-analysis-grid>

                `)}

        `;
    }

    getDefaultConfig() {
        return {
            groups: [
                {
                    id: "analyst",
                    distinctField: "analyst.id",
                    queryField: "analystId",
                    display: {
                        title: "Analyst",
                        icon: "fa-user-circle",
                        emptyTitle: "Unassigned",
                    },
                },
                {
                    id: "status",
                    title: "Status",
                    distinctField: "status.id",
                    queryField: "status",
                    customSort: items => {
                        // We are assuming values are always sorted from less to most important
                        return items.reverse();
                    },
                    display: {
                        title: "Status",
                        icon: "fa-dot-circle",
                        emptyTitle: "NO_STATUS",
                    },
                },
                {
                    id: "priority",
                    distinctField: "priority.id",
                    queryField: "priority",
                    customSort: items => {
                        // We are assuming values are always sorted from less to most important
                        return items.reverse();
                    },
                    display: {
                        title: "Priority",
                        icon: "fa-flag",
                        emptyTitle: "NO_PRIORITY",
                    },
                },
            ],
        };
    }

}

customElements.define("clinical-analysis-group", ClinicalAnalysisGroup);
<commit_msg>wc: fix wrong counts in group view #TASK-1524<commit_after>import {LitElement, html} from "lit";
import UtilsNew from "../../core/utilsNew.js";
import "./clinical-analysis-grid.js";

export default class ClinicalAnalysisGroup extends LitElement {

    constructor() {
        super();
        this.#init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            opencgaSession: {
                type: Object,
            },
            query: {
                type: Object,
            },
            active: {
                type: Boolean,
            },
            config: {
                type: Object,
            },
        };
    }

    #init() {
        this._prefix = UtilsNew.randomString(8);
        this._config = this.getDefaultConfig();
        this.activeGroup = this._config.groups[0];
        this.groups = [];
    }

    updated(changedProperties) {
        if (changedProperties.has("opencgaSession") || changedProperties.has("config") || changedProperties.has("active")) {
            this.propertyObserver();
        }
    }

    propertyObserver() {
        if (this.opencgaSession && this.active) {
            this._config = {
                ...this.getDefaultConfig(),
                ...this.config,
                toolbar: {
                    ...(this.config.toolbar || {}),
                    showCreate: false, // Hide create button in each grid
                },
            };

            this.updateGroups();
        }
    }

    updateGroups() {
        this.groups = []; // Reset groups
        this.requestUpdate();
        this.opencgaSession.opencgaClient.clinical()
            .distinct(this.activeGroup.distinctField, {
                study: this.opencgaSession.study.fqn,
            })
            .then(response => {
                this.groups = response.getResults();

                // Check if a custom sorting function has been provided
                if (typeof this.activeGroup.customSort === "function") {
                    this.groups = this.activeGroup.customSort(this.groups);
                }

                this.requestUpdate();
            });
    }

    onGroupChange(newGroup) {
        this.activeGroup = newGroup;
        this.updateGroups();
    }

    onQueryComplete(event, item) {
        const totalResults = event.detail.value?.responses[0]?.numTotalResults || 0;
        this.querySelector(`#${this._prefix}GroupCount${item}`).textContent = `(${totalResults} cases)`;
    }

    onRowUpdate() {
        // If a row has been updated, we force a refresh of all groups
        this.updateGroups();
    }

    render() {
        return html`

                    ${this.config?.toolbar?.showCreate ? html`

                            New

                    ` : null}

                        <button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown">

                            Group by
                        </button>

                            ${this._config.groups.map(group => html`

                                     this.onGroupChange(group)}">

                                            <input
                                                type="radio"
                                                name="CaseGroupBy"
                                                style="margin-top:0px;"
                                                ?checked="${group.id === this.activeGroup.id}"
                                            />
                                            ${group.display.title}

                            `)}

                ${this.groups.map(item => html`

                            ${item || this.activeGroup.display.emptyTitle}

                        <clinical-analysis-grid
                            .opencgaSession="${this.opencgaSession}"
                            .config="${this._config}"
                            .query="${{
                                ...this.query,
                                [this.activeGroup.queryField]: item,
                            }}"
                            .active="${true}"
                            @rowUpdate="${() => this.onRowUpdate()}"
                            @queryComplete="${e => this.onQueryComplete(e, item)}">
                        </clinical-analysis-grid>

                `)}

        `;
    }

    getDefaultConfig() {
        return {
            groups: [
                {
                    id: "analyst",
                    distinctField: "analyst.id",
                    queryField: "analystId",
                    display: {
                        title: "Analyst",
                        icon: "fa-user-circle",
                        emptyTitle: "Unassigned",
                    },
                },
                {
                    id: "status",
                    title: "Status",
                    distinctField: "status.id",
                    queryField: "status",
                    customSort: items => {
                        // We are assuming values are always sorted from less to most important
                        return items.reverse();
                    },
                    display: {
                        title: "Status",
                        icon: "fa-dot-circle",
                        emptyTitle: "NO_STATUS",
                    },
                },
                {
                    id: "priority",
                    distinctField: "priority.id",
                    queryField: "priority",
                    customSort: items => {
                        // We are assuming values are always sorted from less to most important
                        return items.reverse();
                    },
                    display: {
                        title: "Priority",
                        icon: "fa-flag",
                        emptyTitle: "NO_PRIORITY",
                    },
                },
            ],
        };
    }

}

customElements.define("clinical-analysis-group", ClinicalAnalysisGroup);
<|endoftext|>


<commit_before>(function(){
  var _comm = new window.Comm(),
      _manifest = {};

  /*
   *TODO: this should be something we reuse from src/ui/widget/textbox.js
   * with require.  We need to expose butter internals to editors.
   * https://webmademovies.lighthouseapp.com/projects/65733/tickets/1174
   */

  function __highlight( e ){
    var input = e.target;
    input.select();
    input.removeEventListener( "focus", __highlight, false );
  }

  function __ignoreMouseUp( e ){
    e.preventDefault();
    var input = e.target;
    input.removeEventListener( "mouseup", __ignoreMouseUp, false );
  }

  function __addListeners( input ){
    input.addEventListener( "focus", __highlight, false );
    input.addEventListener( "mouseup", __ignoreMouseUp, false );
  }

  function __TextboxWrapper( input ){
console.log( input.type );
    if( !( input && ( input.type === "text" || input.type === "number" || input.type === "url" ) ) ){
      throw "Expected an input element of type text, number or url";
    }

    input.addEventListener( "blur", function( e ){
      __addListeners( e.target );
    }, false);

    __addListeners( input );

    return input;

  }

  document.addEventListener( "DOMContentLoaded", function( e ){

    function sendData( alsoClose ){
      alsoClose = !!alsoClose;
      var popcornOptions = {};
      for( var item in _manifest ) {
        if( _manifest.hasOwnProperty( item ) ) {
          var elem = document.getElementById( item );
          popcornOptions[ item ] = elem.type === "checkbox" ? elem.checked : elem.value;
        }
      }
      document.getElementById( "message" ).innerHTML = "";
      _comm.send( "submit", {
        eventData: popcornOptions,
        alsoClose: alsoClose
      });
    } //sendData

    function okPressed( e ) {
      sendData( true );
    }

    function cancelPressed( e ) {
      _comm.send( "cancel" );
    }

    document.addEventListener( "keydown", function( e ) {
      if( e.keyCode === 13 ) {
        okPressed( e );
      } else if( e.keyCode === 27 ) {
        cancelPressed( e );
      }
    }, false);

    _comm.listen( "close", function( e ){
      // use this to process something right before the editor closes
    });

    _comm.listen( "trackeventupdated", function( e ){
      for( var item in _manifest ){
        if( _manifest.hasOwnProperty( item ) ) {
          var element = document.getElementById( item );
          element.value = e.data[ item ];
        }
      } //for
    });

    _comm.listen( "trackeventupdatefailed", function( e ) {
      if( e.data === "invalidtime" ){
        document.getElementById( "message" ).innerHTML = "You've entered an invalid start or end time. Please verify that they are both greater than 0, the end time is equal to or less than the media's duration, and that the start time is less than the end time.";
      } //if
    });

    _comm.listen( "trackeventdata", function( e ){
      var popcornOptions = e.data.popcornOptions,
          targets = e.data.targets,
          media = e.data.media,
          table = document.getElementById( "table" ),
          mediaName = "Current Media Element",
          elemToFocus,
          createElement = {
            defaultValue: function( item, val ) {
              // Don't print "undefined" or the like
              if ( val === undefined || typeof val === "object" ) {
                if ( item.default ) {
                  val = item.default;
                } else {
                  val = item.type === "number" ? 0 : "";
                }
              }
              return val;
            },
            input: function( manifest, manifestProp ) {
              var manifestItem = manifest[ manifestProp ],
                  elem = document.createElement( manifestItem.elem ),
                  type = manifestItem.type;

              elem.type = type;
              elem.id = manifestProp;
              elem.style.width = "100%";
              elem.placeholder = "Empty";

              if( type !== "checkbox" ) {
                __TextboxWrapper( elem );
              }

              elem.value = elem.checked = this.defaultValue( manifestItem, popcornOptions[ manifestProp ] );
              return elem;
            },
            select: function( manifest, manifestProp, items ) {
              var manifestItem = manifest[ manifestProp ],
                  elem = document.createElement( "SELECT" ),
                  option;

              items = items || manifestItem.options;

              elem.id = manifestProp;

              for ( var i = 0, l = items.length; i < l; i++ ) {
                option = document.createElement( "OPTION" );
                option.value = items[ i ];
                option.innerHTML = items[ i ];
                elem.appendChild( option );
              }
              if ( manifestProp === "target" ) {
                option = document.createElement( "OPTION" );
                option.value = "Media Element";
                option.innerHTML =  mediaName;
                elem.appendChild( option );
              }
              elem.value = this.defaultValue( manifestItem, popcornOptions[ manifestProp ] );
              return elem;
            }
          };

      if ( media && media.name && media.target ) {
        mediaName += " (\"" + media.name + "\": " + media.target + ")";
      }

      _manifest = e.data.manifest.options;

      function createRow( item, data ) {
        var row = document.createElement( "TR" ),
            col1 = document.createElement( "TD" ),
            col2 = document.createElement( "TD" ),
            currentItem = _manifest[ item ],
            itemLabel = currentItem.label || item,
            field;

        if ( itemLabel === "In" ) {
          itemLabel = "Start (seconds)";
        } else if ( itemLabel === "Out" ) {
          itemLabel = "End (seconds)";
        }

        col1.innerHTML = "" + itemLabel + "";

        field = createElement[ currentItem.elem ]( _manifest, item, data );

        col2.appendChild( field );
        field.addEventListener( "change", function( e ){
          sendData( false );
        }, false );

        // Remember first control added in editor so we can focus
        elemToFocus = elemToFocus || field;

        row.appendChild( col1 );
        row.appendChild( col2 );
        table.appendChild( row );
      }

      _manifest.target = {
        elem: "select",
        label: "Target"
      };

      for ( var item in _manifest ) {
        if ( item === "target" ) {
          createRow( item, targets );
        } else {
          createRow( item );
        }
      }

      // Focus the first element in the editor
      if ( elemToFocus && elemToFocus.focus ) {
        elemToFocus.focus();
      }
      sendData( false );
    });
  }, false );
}());
<commit_msg>Removed console.log as per review [#1371]<commit_after>(function(){
  var _comm = new window.Comm(),
      _manifest = {};

  /*
   *TODO: this should be something we reuse from src/ui/widget/textbox.js
   * with require.  We need to expose butter internals to editors.
   * https://webmademovies.lighthouseapp.com/projects/65733/tickets/1174
   */

  function __highlight( e ){
    var input = e.target;
    input.select();
    input.removeEventListener( "focus", __highlight, false );
  }

  function __ignoreMouseUp( e ){
    e.preventDefault();
    var input = e.target;
    input.removeEventListener( "mouseup", __ignoreMouseUp, false );
  }

  function __addListeners( input ){
    input.addEventListener( "focus", __highlight, false );
    input.addEventListener( "mouseup", __ignoreMouseUp, false );
  }

  function __TextboxWrapper( input ){

    if( !( input && ( input.type === "text" || input.type === "number" || input.type === "url" ) ) ){
      throw "Expected an input element of type text, number or url";
    }

    input.addEventListener( "blur", function( e ){
      __addListeners( e.target );
    }, false);

    __addListeners( input );

    return input;

  }

  document.addEventListener( "DOMContentLoaded", function( e ){

    function sendData( alsoClose ){
      alsoClose = !!alsoClose;
      var popcornOptions = {};
      for( var item in _manifest ) {
        if( _manifest.hasOwnProperty( item ) ) {
          var elem = document.getElementById( item );
          popcornOptions[ item ] = elem.type === "checkbox" ? elem.checked : elem.value;
        }
      }
      document.getElementById( "message" ).innerHTML = "";
      _comm.send( "submit", {
        eventData: popcornOptions,
        alsoClose: alsoClose
      });
    } //sendData

    function okPressed( e ) {
      sendData( true );
    }

    function cancelPressed( e ) {
      _comm.send( "cancel" );
    }

    document.addEventListener( "keydown", function( e ) {
      if( e.keyCode === 13 ) {
        okPressed( e );
      } else if( e.keyCode === 27 ) {
        cancelPressed( e );
      }
    }, false);

    _comm.listen( "close", function( e ){
      // use this to process something right before the editor closes
    });

    _comm.listen( "trackeventupdated", function( e ){
      for( var item in _manifest ){
        if( _manifest.hasOwnProperty( item ) ) {
          var element = document.getElementById( item );
          element.value = e.data[ item ];
        }
      } //for
    });

    _comm.listen( "trackeventupdatefailed", function( e ) {
      if( e.data === "invalidtime" ){
        document.getElementById( "message" ).innerHTML = "You've entered an invalid start or end time. Please verify that they are both greater than 0, the end time is equal to or less than the media's duration, and that the start time is less than the end time.";
      } //if
    });

    _comm.listen( "trackeventdata", function( e ){
      var popcornOptions = e.data.popcornOptions,
          targets = e.data.targets,
          media = e.data.media,
          table = document.getElementById( "table" ),
          mediaName = "Current Media Element",
          elemToFocus,
          createElement = {
            defaultValue: function( item, val ) {
              // Don't print "undefined" or the like
              if ( val === undefined || typeof val === "object" ) {
                if ( item.default ) {
                  val = item.default;
                } else {
                  val = item.type === "number" ? 0 : "";
                }
              }
              return val;
            },
            input: function( manifest, manifestProp ) {
              var manifestItem = manifest[ manifestProp ],
                  elem = document.createElement( manifestItem.elem ),
                  type = manifestItem.type;

              elem.type = type;
              elem.id = manifestProp;
              elem.style.width = "100%";
              elem.placeholder = "Empty";

              if( type !== "checkbox" ) {
                __TextboxWrapper( elem );
              }

              elem.value = elem.checked = this.defaultValue( manifestItem, popcornOptions[ manifestProp ] );
              return elem;
            },
            select: function( manifest, manifestProp, items ) {
              var manifestItem = manifest[ manifestProp ],
                  elem = document.createElement( "SELECT" ),
                  option;

              items = items || manifestItem.options;

              elem.id = manifestProp;

              for ( var i = 0, l = items.length; i < l; i++ ) {
                option = document.createElement( "OPTION" );
                option.value = items[ i ];
                option.innerHTML = items[ i ];
                elem.appendChild( option );
              }
              if ( manifestProp === "target" ) {
                option = document.createElement( "OPTION" );
                option.value = "Media Element";
                option.innerHTML =  mediaName;
                elem.appendChild( option );
              }
              elem.value = this.defaultValue( manifestItem, popcornOptions[ manifestProp ] );
              return elem;
            }
          };

      if ( media && media.name && media.target ) {
        mediaName += " (\"" + media.name + "\": " + media.target + ")";
      }

      _manifest = e.data.manifest.options;

      function createRow( item, data ) {
        var row = document.createElement( "TR" ),
            col1 = document.createElement( "TD" ),
            col2 = document.createElement( "TD" ),
            currentItem = _manifest[ item ],
            itemLabel = currentItem.label || item,
            field;

        if ( itemLabel === "In" ) {
          itemLabel = "Start (seconds)";
        } else if ( itemLabel === "Out" ) {
          itemLabel = "End (seconds)";
        }

        col1.innerHTML = "" + itemLabel + "";

        field = createElement[ currentItem.elem ]( _manifest, item, data );

        col2.appendChild( field );
        field.addEventListener( "change", function( e ){
          sendData( false );
        }, false );

        // Remember first control added in editor so we can focus
        elemToFocus = elemToFocus || field;

        row.appendChild( col1 );
        row.appendChild( col2 );
        table.appendChild( row );
      }

      _manifest.target = {
        elem: "select",
        label: "Target"
      };

      for ( var item in _manifest ) {
        if ( item === "target" ) {
          createRow( item, targets );
        } else {
          createRow( item );
        }
      }

      // Focus the first element in the editor
      if ( elemToFocus && elemToFocus.focus ) {
        elemToFocus.focus();
      }
      sendData( false );
    });
  }, false );
}());
<|endoftext|>


<commit_before>'use strict';

module.exports = {
  plugins: [
    'import',
  ],
  parserOptions: {
    ecmaVersion: 2017,
    sourceType: 'module',
  },
  settings: {
    'import/resolver': {
      node: {
        extensions: ['.js', '.jsx'],
      },
    },
    'import/extensions': ['.js', '.jsx'],
    'import/ignore': ['node_modules'],
  },
  rules: {
    // static analysis
    'import/no-unresolved': ['error', {commonjs: true}],
    'import/named': 'error',
    'import/default': 'error',
    'import/namespace': 'error',
    'import/no-restricted-paths': 'off',
    'import/no-absolute-path': 'error',
    'import/no-dynamic-require': 'error',
    'import/no-internal-modules': 'off',
    'import/no-webpack-loader-syntax': 'error',

    // helpful warnings
    'import/export': 'error',
    'import/no-named-as-default': 'error',
    'import/no-named-as-default-member': 'error',
    // unstable rule: https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-deprecated.md
    'import/no-deprecated': 'off',
    'import/no-extraneous-dependencies': 'error',
    'import/no-mutable-exports': 'error',

    // module systems
    'import/unambiguous': 'error',
    'import/no-commonjs': 'off',
    'import/no-amd': 'error',
    'import/no-nodejs-modules': 'off',

    // style guide
    'import/first': 'error',
    'import/no-duplicates': 'error',
    'import/no-namespace': 'off',
    'import/extensions': ['error', {js: 'never', jsx: 'never'}],
    'import/order': ['error', {'newlines-between': 'never'}],
    'import/newline-after-import': 'error',
    'import/prefer-default-export': 'error',
    'import/max-dependencies': 'off',
    'import/no-unassigned-import': 'off',
  },
};
<commit_msg>Add `import/no-named-default` rule<commit_after>'use strict';

module.exports = {
  plugins: [
    'import',
  ],
  parserOptions: {
    ecmaVersion: 2017,
    sourceType: 'module',
  },
  settings: {
    'import/resolver': {
      node: {
        extensions: ['.js', '.jsx'],
      },
    },
    'import/extensions': ['.js', '.jsx'],
    'import/ignore': ['node_modules'],
  },
  rules: {
    // static analysis
    'import/no-unresolved': ['error', {commonjs: true}],
    'import/named': 'error',
    'import/default': 'error',
    'import/namespace': 'error',
    'import/no-restricted-paths': 'off',
    'import/no-absolute-path': 'error',
    'import/no-dynamic-require': 'error',
    'import/no-internal-modules': 'off',
    'import/no-webpack-loader-syntax': 'error',

    // helpful warnings
    'import/export': 'error',
    'import/no-named-as-default': 'error',
    'import/no-named-as-default-member': 'error',
    // unstable rule: https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-deprecated.md
    'import/no-deprecated': 'off',
    'import/no-extraneous-dependencies': 'error',
    'import/no-mutable-exports': 'error',

    // module systems
    'import/unambiguous': 'error',
    'import/no-commonjs': 'off',
    'import/no-amd': 'error',
    'import/no-nodejs-modules': 'off',

    // style guide
    'import/first': 'error',
    'import/no-duplicates': 'error',
    'import/no-namespace': 'off',
    'import/extensions': ['error', {js: 'never', jsx: 'never'}],
    'import/order': ['error', {'newlines-between': 'never'}],
    'import/newline-after-import': 'error',
    'import/prefer-default-export': 'error',
    'import/max-dependencies': 'off',
    'import/no-unassigned-import': 'off',
    'import/no-named-default': 'error',
  },
};
<|endoftext|>


<commit_before>// @license
// Copyright (c) 2017 Google Inc. All rights reserved.
// This code may only be used under the BSD style license found at
// http://polymer.github.io/LICENSE.txt
// Code distributed by Google as part of this project is also
// subject to an additional IP rights grant found at
// http://polymer.github.io/PATENTS.txt
'use strict';

const assert = require('assert');
const Identifier = require('./identifier.js');
const Symbols = require('./symbols.js');
const Entity = require('./entity.js');
const Relation = require('./relation.js');
let identifier = Symbols.identifier;
const tracing = require("../tracelib/trace.js");
const scheduler = require('./scheduler.js');

// TODO: This won't be needed once runtime is transferred between contexts.
function cloneData(data) {
  return JSON.parse(JSON.stringify(data));
}

function restore(entry, scope) {
  let {id, data} = entry;
  var entity = Entity.fromLiteral(id, cloneData(data));
  var type = scope.typeFor(entity);
  entity.constructor = type.entityClass;
  // TODO: Relation magic should happen elsewhere, and be better.
  if (scope.typeFor(entity).isRelation) {
    let ids = data.map(literal => Identifier.fromLiteral(literal, scope));
    let entities = ids.map(id => scope._viewFor(id.type.viewOf(scope)).get(id));
    assert(!entities.includes(undefined));
    entity = new Relation(...entities);
    entity.entities = entities;
    entity[identifier] = id;
  }
  return entity;
}

class ViewBase {
  constructor(type, scope, name) {
    var trace = tracing.start({cat: 'view', name: 'ViewBase::constructor', args: {type: type.key, name: name}});
    this._type = type;
    this._scope = scope;
    this._listeners = new Map();
    this._listenersCheckpoint = null;
    this._version = 0;
    this._versionCheckpoint = null;
    this._checkpointed = false;
    this._pendingCallbacks = 0;
    this.name = name;
    trace.end();
  }
  get type() {
    return this._type;
  }
  // TODO: add 'once' which returns a promise.
  on(kind,  callback, target, trigger) {
    assert(target !== undefined);
    let listeners = this._listeners.get(kind) || new Map();
    listeners.set(callback, {version: -Infinity, target});
    this._listeners.set(kind, listeners);
    if (trigger) {
      this._fire(kind);
    }
  }
  _mutate() {
    this._version++;
  }
  _fire(kind, details) {
    var listenerMap = this._listeners.get(kind);
    if (!listenerMap || listenerMap.size == 0)
      return;

    var callTrace = tracing.start({cat: 'view', name: 'ViewBase::_fire', args: {kind, type: this._type.key,
        pending: this._pendingCallbacks, name: this.name, listeners: listenerMap.size}});

    if (this._pendingCallbacks == 0 && this._dirty) {
      this._dirty();
    }
    this._pendingCallbacks++;

    // TODO: wire up a target (particle)
    let version = this._version;
    let eventRecords = [];

    for (let [callback, registration] of listenerMap.entries()) {
      let target = registration.target;
      eventRecords.push({target, version, callback, kind, details});
    }

    scheduler.enqueue(this, eventRecords);

    callTrace.end();
  }

  dispatch({kind, callback, version, details}) {
    // TODO: We're currently dropping events.
    version = this._version;
    let registration = this._listeners.get(kind).get(callback);
    if (version <= registration.version) {
      return;
    }
    registration.version = version;
    callback(this, details);
  }

  pendingCallbackCompleted() {
    this._pendingCallbacks--;
    if (this._pendingCallbacks == 0 && this._clean) {
      this._clean();
    }
  }

  _serialize(entity) {
    let id = entity[identifier];
    let data = cloneData(entity.toLiteral());
    return {
      id,
      data: data,
    };
  }
  _restore(entry) {
    return restore(entry, this._scope);
  }
  checkpoint() {
    if (this._checkpointed)
      return false;
    this._versionCheckpoint = this._version;
    this._checkpointed = true;
    this._listenersCheckpoint = new Map(Array.from(this._listeners.entries()).map(([kind, listenerVersions]) => {
      return [kind, new Map(listenerVersions.entries().map(([callback, {version, target}]) => [callback, {version, target}]))];
    }));
    return true;
  }
  revert() {
    if (!this._checkpointed)
      return false;
    this._version = this._versionCheckpoint;
    this._versionCheckpoint = null;
    this._listeners = this._listenersCheckpoint;
    this._listenersCheckpoint = null;
    this._checkpointed = false;
    return true;
  }
}

class View extends ViewBase {
  constructor(type, scope, name) {
    super(type, scope, name);
    this._items = [];
    this._itemsCheckpoint = null;
  }
  get(id) {
    for (let entry of this._items) {
      if (JSON.stringify(entry.id) == JSON.stringify(id)) {
        return this._restore(entry);
      }
    }
  }
  traceInfo() {
    return {items: this._items.length};
  }
  query() {
    // TODO
  }
  // HACK: replace this with some kind of iterator thing?
  toList() {
    return this._items.map(entry => this._restore(entry));
  }
  // thing()

  store(entity) {
    var trace = tracing.start({cat: "view", name: "View::store", args: {name: this.name}});
    var serialization = this._serialize(entity);
    this._items.push(serialization);
    trace.update({entity: serialization});
    this._mutate();
    this._fire('change');
    trace.end();
  }

  on(kind, callback, target) {
    let trigger = kind == 'change';
    super.on(kind, callback, target, trigger);
  }

  remove(id) {
    // TODO
  }
  // TODO: Something about iterators??
  // TODO: Something about changing order?
  checkpoint() {
    if (!super.checkpoint())
      return;
    this._itemsCheckpoint = this._items.concat();
  }
  revert() {
    if (!super.revert())
      return;
    this._items = this._itemsCheckpoint;
    this._itemsCheckpoint = null;
  }
}

class Variable extends ViewBase {
  constructor(type, scope, name) {
    super(type, scope, name);
    this._stored = null;
    this._storedCheckpoint = null;
  }
  traceInfo() {
    return {stored: this._stored !== null};
  }
  // HACK: this should be async
  get() {
    if (this._stored == null)
      return undefined;
    return this._restore(this._stored);
  }
  set(entity) {
    if (entity[identifier] == undefined)
      entity[identifier] = this._scope._newIdentifier(this, this._scope.typeFor(entity));
    this._stored = this._serialize(entity);
    this._mutate();
    this._fire('change');
  }
  on(kind, callback, target) {
    let trigger = kind == 'change';
    super.on(kind, callback, target, trigger);
  }
  checkpoint() {
    if (!super.checkpoint())
      return;
    this._storedCheckpoint = this._stored;
  }
  revert() {
    if (!super.revert())
      return;
    this._stored = this._storedCheckpoint;
    this._storedCheckpoint = null;
  }
}

Object.assign(module.exports, {
  View,
  Variable,
});
<commit_msg>Added assert<commit_after>// @license
// Copyright (c) 2017 Google Inc. All rights reserved.
// This code may only be used under the BSD style license found at
// http://polymer.github.io/LICENSE.txt
// Code distributed by Google as part of this project is also
// subject to an additional IP rights grant found at
// http://polymer.github.io/PATENTS.txt
'use strict';

const assert = require('assert');
const Identifier = require('./identifier.js');
const Symbols = require('./symbols.js');
const Entity = require('./entity.js');
const Relation = require('./relation.js');
let identifier = Symbols.identifier;
const tracing = require("../tracelib/trace.js");
const scheduler = require('./scheduler.js');

// TODO: This won't be needed once runtime is transferred between contexts.
function cloneData(data) {
  return JSON.parse(JSON.stringify(data));
}

function restore(entry, scope) {
  let {id, data} = entry;
  var entity = Entity.fromLiteral(id, cloneData(data));
  var type = scope.typeFor(entity);
  entity.constructor = type.entityClass;
  // TODO: Relation magic should happen elsewhere, and be better.
  if (scope.typeFor(entity).isRelation) {
    let ids = data.map(literal => Identifier.fromLiteral(literal, scope));
    let entities = ids.map(id => scope._viewFor(id.type.viewOf(scope)).get(id));
    assert(!entities.includes(undefined));
    entity = new Relation(...entities);
    entity.entities = entities;
    entity[identifier] = id;
  }
  return entity;
}

class ViewBase {
  constructor(type, scope, name) {
    var trace = tracing.start({cat: 'view', name: 'ViewBase::constructor', args: {type: type.key, name: name}});
    this._type = type;
    this._scope = scope;
    this._listeners = new Map();
    this._listenersCheckpoint = null;
    this._version = 0;
    this._versionCheckpoint = null;
    this._checkpointed = false;
    this._pendingCallbacks = 0;
    this.name = name;
    trace.end();
  }
  get type() {
    return this._type;
  }
  // TODO: add 'once' which returns a promise.
  on(kind,  callback, target, trigger) {
    assert(target !== undefined, "must provide a target to register a view event handler");
    let listeners = this._listeners.get(kind) || new Map();
    listeners.set(callback, {version: -Infinity, target});
    this._listeners.set(kind, listeners);
    if (trigger) {
      this._fire(kind);
    }
  }
  _mutate() {
    this._version++;
  }
  _fire(kind, details) {
    var listenerMap = this._listeners.get(kind);
    if (!listenerMap || listenerMap.size == 0)
      return;

    var callTrace = tracing.start({cat: 'view', name: 'ViewBase::_fire', args: {kind, type: this._type.key,
        pending: this._pendingCallbacks, name: this.name, listeners: listenerMap.size}});

    if (this._pendingCallbacks == 0 && this._dirty) {
      this._dirty();
    }
    this._pendingCallbacks++;

    // TODO: wire up a target (particle)
    let version = this._version;
    let eventRecords = [];

    for (let [callback, registration] of listenerMap.entries()) {
      let target = registration.target;
      eventRecords.push({target, version, callback, kind, details});
    }

    scheduler.enqueue(this, eventRecords);

    callTrace.end();
  }

  dispatch({kind, callback, version, details}) {
    // TODO: We're currently dropping events.
    version = this._version;
    let registration = this._listeners.get(kind).get(callback);
    if (version <= registration.version) {
      return;
    }
    registration.version = version;
    callback(this, details);
  }

  pendingCallbackCompleted() {
    this._pendingCallbacks--;
    if (this._pendingCallbacks == 0 && this._clean) {
      this._clean();
    }
  }

  _serialize(entity) {
    let id = entity[identifier];
    let data = cloneData(entity.toLiteral());
    return {
      id,
      data: data,
    };
  }
  _restore(entry) {
    return restore(entry, this._scope);
  }
  checkpoint() {
    if (this._checkpointed)
      return false;
    this._versionCheckpoint = this._version;
    this._checkpointed = true;
    this._listenersCheckpoint = new Map(Array.from(this._listeners.entries()).map(([kind, listenerVersions]) => {
      return [kind, new Map(listenerVersions.entries().map(([callback, {version, target}]) => [callback, {version, target}]))];
    }));
    return true;
  }
  revert() {
    if (!this._checkpointed)
      return false;
    this._version = this._versionCheckpoint;
    this._versionCheckpoint = null;
    this._listeners = this._listenersCheckpoint;
    this._listenersCheckpoint = null;
    this._checkpointed = false;
    return true;
  }
}

class View extends ViewBase {
  constructor(type, scope, name) {
    super(type, scope, name);
    this._items = [];
    this._itemsCheckpoint = null;
  }
  get(id) {
    for (let entry of this._items) {
      if (JSON.stringify(entry.id) == JSON.stringify(id)) {
        return this._restore(entry);
      }
    }
  }
  traceInfo() {
    return {items: this._items.length};
  }
  query() {
    // TODO
  }
  // HACK: replace this with some kind of iterator thing?
  toList() {
    return this._items.map(entry => this._restore(entry));
  }
  // thing()

  store(entity) {
    var trace = tracing.start({cat: "view", name: "View::store", args: {name: this.name}});
    var serialization = this._serialize(entity);
    this._items.push(serialization);
    trace.update({entity: serialization});
    this._mutate();
    this._fire('change');
    trace.end();
  }

  on(kind, callback, target) {
    let trigger = kind == 'change';
    super.on(kind, callback, target, trigger);
  }

  remove(id) {
    // TODO
  }
  // TODO: Something about iterators??
  // TODO: Something about changing order?
  checkpoint() {
    if (!super.checkpoint())
      return;
    this._itemsCheckpoint = this._items.concat();
  }
  revert() {
    if (!super.revert())
      return;
    this._items = this._itemsCheckpoint;
    this._itemsCheckpoint = null;
  }
}

class Variable extends ViewBase {
  constructor(type, scope, name) {
    super(type, scope, name);
    this._stored = null;
    this._storedCheckpoint = null;
  }
  traceInfo() {
    return {stored: this._stored !== null};
  }
  // HACK: this should be async
  get() {
    if (this._stored == null)
      return undefined;
    return this._restore(this._stored);
  }
  set(entity) {
    if (entity[identifier] == undefined)
      entity[identifier] = this._scope._newIdentifier(this, this._scope.typeFor(entity));
    this._stored = this._serialize(entity);
    this._mutate();
    this._fire('change');
  }
  on(kind, callback, target) {
    let trigger = kind == 'change';
    super.on(kind, callback, target, trigger);
  }
  checkpoint() {
    if (!super.checkpoint())
      return;
    this._storedCheckpoint = this._stored;
  }
  revert() {
    if (!super.revert())
      return;
    this._stored = this._storedCheckpoint;
    this._storedCheckpoint = null;
  }
}

Object.assign(module.exports, {
  View,
  Variable,
});
<|endoftext|>


<commit_before>const Base = require('./primitive/Base');
class Version extends Base {
  constructor({value = null, hidden = false, nickname, alias, details, builds} = {}) {
    if(value){
      value = ''+value;
    }
    super({value, hidden, nickname, alias, details, builds});
  }

  /**
   * Determine if the version is lower, equal or higher than the specified value
   *
   * @param  operator string   The operator, must be <, <=, =, >= or >
   * @param  compare mixed    The value, can be an integer, float or string with a version number
   *
   * @return boolean
   */
  is(operator = null, compare = null) {
    let valid = false;
    if (operator !== null) {
      if (compare === null) {
        compare = operator;
        operator = '=';
      }
      compare = ''+compare;
      const regExp = /\./;
      const min = Math.min((regExp.exec(this.value) || []).length, (regExp.exec(compare)|| []).length) + 1;
      const v1 = this.toValue(this.value, min);
      const v2 = this.toValue(compare, min);
      switch (operator) {
        case '<':
          valid = v1 < v2;
          break;
        case '<=':
          valid = v1 <= v2;
          break;
        case '=':
          valid = v1 === v2;
          break;
        case '>':
          valid = v1 > v2;
          break;
        case '>=':
          valid = v1 >= v2;
          break;
      }
    }
    return valid;
  }

  /**
   * Return an object with each part of the version number
   *
   * @return Object
   */
  getParts() {
    const parts = this.value.split('.');
    return {
      'major': Number(parts[0] || 0),
      'minor': Number(parts[1] || 0),
      'patch': Number(parts[2] || 0),
    };
  }

  /**
   * Return the major version as an integer
   *
   * @return integer
   */

  getMajor() {
    return this.getParts().major;
  }

  /**
   * Return the minor version as an integer
   *
   * @return integer
   */
  getMinor() {
    return this.getParts().minor;
  }

  /**
   * Return the patch number as an integer
   *
   * @return integer
   */
  getPatch() {
    return this.getParts().patch;
  }

  /**
   * Convert a version string seperated by dots into a float that can be compared
   *
   * @internal
   *
   * @param  value string   Version string, with elements seperated by a dot
   * @param  count int      The maximum precision
   *
   * @return Number
   */
  toValue(value = null, count = null) {
    if (value === null) {
      value = this.value;
    }
    let parts = value.split('.');
    if (count !== null) {
      parts = parts.slice(0, count);
    }
    let result = parts[0];
    if (parts.length > 1) {
      result += '.';
      count = parts.length;
      for (let p = 1; p < count; p++) {
        let tempString = `0000${parts[p]}`;
        result += tempString.substr(tempString.length - 4);
      }
    }
    return Number(result);
  }

  /**
   * Return the version as a float
   *
   * @return Number
   */
  toFloat() {
    return parseFloat(this.value);
  }

  /**
   * Return the version as an integer
   *
   * @return Number
   */
  toNumber() {
    return parseInt(this.value, 10);
  }

  /**
   * Return the version as a human readable string
   *
   * @return string
   */
  toString() {
    if (this.alias) {
      return this.alias;
    }
    let version = '';
    if (this.nickname) {
      version = `${this.nickname} `;
    }
    if (this.value) {
      const matches = this.value.match(/([0-9]+)(?:\.([0-9]+))?(?:\.([0-9]+))?(?:\.([0-9]+))?(?:([ab])([0-9]+))?/);
      if (matches) {
        let v = [matches[1]];
        if (matches[2]) {
          v.push(matches[2]);
        }
        if (matches[3]) {
          v.push(matches[3]);
        }
        if (matches[4]) {
          v.push(matches[4]);
        }
        if (this.details) {
          if (this.details < 0) {
            v.splice(this.details, 0 - this.details);
          }
          if (this.details > 0) {
            v.splice(this.details, v.length - this.details);
          }
        }
        if (typeof this.builds !== 'undefined' && !this.builds) {
          const count = v.length;
          for (let i = 0; i < count; i++) {
            if (v[i] > 999) {
              v.splice(i, 1);
            }
          }
        }
        version += v.join('.');
        if (matches[5]) {
          version += `${matches[5]}${matches[6] || ''}`;
        }
      }
    }
    return version;
  }

  /**
   * Get an array of all defined properties
   *
   * @internal
   *
   * @return Object
   */
  toObject() {
    const result = {};
    if (this.value) {
      if (this.details) {
        const parts = this.value.split('.').splice(0, this.details);
        result.value = parts.join('.');
      } else {
        result.value = this.value;
      }
    }
    if (this.alias) {
      result.alias = this.alias;
    }
    if (this.nickname) {
      result.nickname = this.nickname;
    }
    if (result.value && !result.alias && !result.nickname) {
      return result.value;
    }
    return result;
  }
}

module.exports = Version;<commit_msg>Fix JSDoc<commit_after>const Base = require('./primitive/Base');
/**
 * Class representing a Version.
 * @extends Base
 */
class Version extends Base {
  /**
   * constructor
   *
   * @param {string|number} [value] The version value
   * @param {boolean} [hidden=false] define if the version is hidden
   * @param {string} [nickname] define the version nickname
   * @param {string} [alias] define the version alias
   * @param {number} [details] define the details value
   * @param {boolean} [builds] define the details value
   *
   * @internal
   */
  constructor({value, hidden = false, nickname, alias, details, builds} = {}) {
    if (value) {
      value = '' + value;
    }
    super({value, hidden, nickname, alias, details, builds});
  }

  /**
   * Determine if the version is lower, equal or higher than the specified value
   *
   * @param {string}        operator   The operator, must be <, <=, =, >= or >
   * @param {number|string} [compare]    The value, can be an integer, float or string with a version number
   *
   * @return {boolean}
   */
  is(operator, compare) {
    let valid = false;
    if (operator) {
      if (!compare) {
        compare = operator;
        operator = '=';
      }
      compare = '' + compare;
      const regExp = /\./;
      const min = Math.min((regExp.exec(this.value) || []).length, (regExp.exec(compare) || []).length) + 1;
      const v1 = this.toValue(this.value, min);
      const v2 = this.toValue(compare, min);
      switch (operator) {
        case '<':
          valid = v1 < v2;
          break;
        case '<=':
          valid = v1 <= v2;
          break;
        case '=':
          valid = v1 === v2;
          break;
        case '>':
          valid = v1 > v2;
          break;
        case '>=':
          valid = v1 >= v2;
          break;
      }
    }
    return valid;
  }

  /**
   * Return an object with each part of the version number
   *
   * @return {object}
   */
  getParts() {
    const parts = this.value.split('.');
    return {
      'major': Number(parts[0] || 0),
      'minor': Number(parts[1] || 0),
      'patch': Number(parts[2] || 0),
    };
  }

  /**
   * Return the major version as an integer
   *
   * @return {number}
   */
  getMajor() {
    return this.getParts().major;
  }

  /**
   * Return the minor version as an integer
   *
   * @return {number}
   */
  getMinor() {
    return this.getParts().minor;
  }

  /**
   * Return the patch number as an integer
   *
   * @return {number}
   */
  getPatch() {
    return this.getParts().patch;
  }

  /**
   * Convert a version string seperated by dots into a float that can be compared
   *
   * @internal
   *
   * @param {string} value   Version string, with elements seperated by a dot
   * @param {number} count   The maximum precision
   *
   * @return {number}
   */
  toValue(value = '', count = NaN) {
    if (!value) {
      value = this.value;
    }
    let parts = value.split('.');
    if (!isNaN(count)) {
      parts = parts.slice(0, count);
    }
    let result = parts[0];
    if (parts.length > 1) {
      result += '.';
      count = parts.length;
      for (let p = 1; p < count; p++) {
        let tempString = `0000${parts[p]}`;
        result += tempString.substr(tempString.length - 4);
      }
    }
    return Number(result);
  }

  /**
   * Return the version as a float
   *
   * @return {number}
   */
  toFloat() {
    return parseFloat(this.value);
  }

  /**
   * Return the version as an integer
   *
   * @return {int}
   */
  toNumber() {
    return parseInt(this.value, 10);
  }

  /**
   * Return the version as a human readable string
   *
   * @return {string}
   */
  toString() {
    if (this.alias) {
      return this.alias;
    }
    let version = '';
    if (this.nickname) {
      version = `${this.nickname} `;
    }
    if (this.value) {
      const matches = this.value.match(/([0-9]+)(?:\.([0-9]+))?(?:\.([0-9]+))?(?:\.([0-9]+))?(?:([ab])([0-9]+))?/);
      if (matches) {
        let v = [matches[1]];
        if (matches[2]) {
          v.push(matches[2]);
        }
        if (matches[3]) {
          v.push(matches[3]);
        }
        if (matches[4]) {
          v.push(matches[4]);
        }
        if (this.details) {
          if (this.details < 0) {
            v.splice(this.details, 0 - this.details);
          }
          if (this.details > 0) {
            v.splice(this.details, v.length - this.details);
          }
        }
        if (typeof this.builds !== 'undefined' && !this.builds) {
          const count = v.length;
          for (let i = 0; i < count; i++) {
            if (v[i] > 999) {
              v.splice(i, 1);
            }
          }
        }
        version += v.join('.');
        if (matches[5]) {
          version += `${matches[5]}${matches[6] || ''}`;
        }
      }
    }
    return version;
  }

  /**
   * Get an object with all defined properties
   *
   * @internal
   *
   * @return {object}
   */
  toObject() {
    const result = {};
    if (this.value) {
      if (this.details) {
        const parts = this.value.split('.').splice(0, this.details);
        result.value = parts.join('.');
      } else {
        result.value = this.value;
      }
    }
    if (this.alias) {
      result.alias = this.alias;
    }
    if (this.nickname) {
      result.nickname = this.nickname;
    }
    if (result.value && !result.alias && !result.nickname) {
      return result.value;
    }
    return result;
  }
}

module.exports = Version;
<|endoftext|>


<commit_before>'use strict';

let ExtractTextPlugin = require("extract-text-webpack-plugin");

class Config {
    constructor(cwd) {
        this._config = {
            cwd: cwd,
            context: sysPath.join(cwd, 'src'),
            entry: {},
            entryGroup: {},
            output: {
                dev: {
                    path: "./dev",
                    filename: "[name][ext]"
                },
                prd: {
                    path: "./prd",
                    filename: "[name].min[ext]"
                }
            },
            module: {
                preLoaders: [],
                loaders: [{
                    test: /\.json$/,
                    loader: require.resolve('json-loader')
                }, {
                    test: /\.(html|string|tpl)$/,
                    loader: require.resolve('html-loader')
                }, {
                    test: /\.css$/,
                    loader: ExtractTextPlugin.extract(
                        require.resolve('style-loader'),
                        require.resolve('css-loader')
                    )
                }],
                postLoaders: []
            },
            plugins: [
                require('../plugins/extTemplatedPathPlugin.js'),
                require('../plugins/requireModulePlugin.js'),
            ],
            resolve: {
                root: [],
                extensions: ['', '.js', '.css', '.json', '.string', '.tpl'],
                alias: {},
            },
            entryExtNames: {
                css: ['.css'],
                js: ['.js']
            },
            requireRules: [
                'node_modules|package.json:main|index.js'
            ],
            devtool: 'cheap-module-source-map'
        };
    }
    setExports(files) {
        [].concat(files).forEach((file) => {
            const entryFile = Array.isArray(file) ? file[file.length - 1] : file

            var name = entryFile.replace(/\.\w+$/g, '');
            if (name.indexOf('./') == 0) {
                name = name.substring(2);
            } else if (name[0] == '/') {
                name = name.substring(1);
            }
            this._config.entry[name] = Array.isArray(file) ? file : [file];
        });
        return this;
    }
    setGroupExports(group, exportsArr) {
        let exportGroup = this._config.entryGroup;
        exportGroup[group] = exportGroup[group] ? exportGroup[group].concat(exportsArr) : exportsArr;

        this.setExports(exportsArr);
    }
    setOutput(output) {
        extend(this._config.output, output);
        return this;
    }
    setSync(syncConfig) {
        if(syncConfig){
            if(typeof syncConfig === 'object') {
                this._config.sync = syncConfig;
            } else if (typeof syncConfig === 'function') {
                this._config.sync = syncConfig();
            }
        }
    }
    setCompile(compileConfig) {
        if(compileConfig){
            let nextConfig = {}

            if(typeof compileConfig === 'object') {
                nextConfig = compileConfig
            } else if (typeof compileConfig === 'function') {
                nextConfig = compileConfig(Object.assign({}, this._config)) || {};
            }

            if(nextConfig.context && !sysPath.isAbsolute(nextConfig.context)){
                nextConfig.context = sysPath.resolve(this._config.cwd, nextConfig.context)
            }

            const context = nextConfig.context || this._config.context
            const relativeContext = sysPath.relative(this._config.cwd, context)
            if(nextConfig.resolve.alias) {
                let alias = nextConfig.resolve.alias
                Object.keys(alias).map(function(key, i){
                    alias[key] = sysPath.relative(relativeContext, alias[key])
                })
                extend(true, this._config.resolve.alias, alias);
            }

            this._config.resolve.root.push(context)

            extend(true, this._config, nextConfig);
        }
    }
    getConfig() {
        return this._config;
    }
};

module.exports = Config;
<commit_msg>fix(config): 修复设置loaders不生效<commit_after>'use strict';

let ExtractTextPlugin = require("extract-text-webpack-plugin");

class Config {
    constructor(cwd) {
        this._config = {
            cwd: cwd,
            context: sysPath.join(cwd, 'src'),
            entry: {},
            entryGroup: {},
            output: {
                dev: {
                    path: "./dev",
                    filename: "[name][ext]"
                },
                prd: {
                    path: "./prd",
                    filename: "[name].min[ext]"
                }
            },
            module: {
                preLoaders: [],
                loaders: [{
                    test: /\.json$/,
                    loader: require.resolve('json-loader')
                }, {
                    test: /\.(html|string|tpl)$/,
                    loader: require.resolve('html-loader')
                }, {
                    test: /\.css$/,
                    loader: ExtractTextPlugin.extract(
                        require.resolve('style-loader'),
                        require.resolve('css-loader')
                    )
                }],
                postLoaders: []
            },
            plugins: [
                require('../plugins/extTemplatedPathPlugin.js'),
                require('../plugins/requireModulePlugin.js'),
            ],
            resolve: {
                root: [],
                extensions: ['', '.js', '.css', '.json', '.string', '.tpl'],
                alias: {},
            },
            entryExtNames: {
                css: ['.css'],
                js: ['.js']
            },
            requireRules: [
                'node_modules|package.json:main|index.js'
            ],
            devtool: 'cheap-module-source-map'
        };
    }
    setExports(files) {
        [].concat(files).forEach((file) => {
            const entryFile = Array.isArray(file) ? file[file.length - 1] : file

            var name = entryFile.replace(/\.\w+$/g, '');
            if (name.indexOf('./') == 0) {
                name = name.substring(2);
            } else if (name[0] == '/') {
                name = name.substring(1);
            }
            this._config.entry[name] = Array.isArray(file) ? file : [file];
        });
        return this;
    }
    setGroupExports(group, exportsArr) {
        let exportGroup = this._config.entryGroup;
        exportGroup[group] = exportGroup[group] ? exportGroup[group].concat(exportsArr) : exportsArr;

        this.setExports(exportsArr);
    }
    setOutput(output) {
        extend(this._config.output, output);
        return this;
    }
    setSync(syncConfig) {
        if(syncConfig){
            if(typeof syncConfig === 'object') {
                this._config.sync = syncConfig;
            } else if (typeof syncConfig === 'function') {
                this._config.sync = syncConfig();
            }
        }
    }
    setCompile(compileConfig) {
        if(compileConfig){
            let nextConfig = {}

            // 获取用户定义的compile配置
            if(typeof compileConfig === 'object') {
                nextConfig = compileConfig
            } else if (typeof compileConfig === 'function') {
                nextConfig = compileConfig(Object.assign({}, this._config)) || {};
            }

            // 处理context
            if(nextConfig.context && !sysPath.isAbsolute(nextConfig.context)){
                nextConfig.context = sysPath.resolve(this._config.cwd, nextConfig.context)
            }

            // 处理loaders => loader
            nextConfig.module.loaders.map((loader, i) => {
                if(loader.loaders && !loader.loader) {
                    loader.loader = loader.loaders.join("!")
                }
                return loader
            })

            // 处理alias
            const context = nextConfig.context || this._config.context
            const relativeContext = sysPath.relative(this._config.cwd, context)
            if(nextConfig.resolve.alias) {
                let alias = nextConfig.resolve.alias
                Object.keys(alias).map(function(key, i){
                    alias[key] = sysPath.relative(relativeContext, alias[key])
                })
                extend(true, this._config.resolve.alias, alias);
            }

            this._config.resolve.root.push(context)

            extend(true, this._config, nextConfig);
        }
    }
    getConfig() {
        return this._config;
    }
};

module.exports = Config;
<|endoftext|>


<commit_before>//
// Yahoo
//
// Register Yahoo developer
(function(hello){

function formatError(o){
	if(o && "meta" in o && "error_type" in o.meta){
		o.error = {
			code : o.meta.error_type,
			message : o.meta.error_message
		};
	}
}

function formatFriends(o){
	formatError(o);
	paging(o);
	var contact,field;
	if(o.query&&o.query.results&&o.query.results.contact){
		o.data = o.query.results.contact;
		delete o.query;
		if(!(o.data instanceof Array)){
			o.data = [o.data];
		}
		for(var i=0;i<o.data.length;i++){
			contact = o.data[i];
			contact.id = null;
			for(var j=0;j<contact.fields.length;j++){
				field = contact.fields[j];
				if(field.type === 'email'){
					contact.email = field.value;
				}
				if(field.type === 'name'){
					contact.first_name = field.value.givenName;
					contact.last_name = field.value.familyName;
					contact.name = field.value.givenName + ' ' + field.value.familyName;
				}
				if(field.type === 'yahooid'){
					contact.id = field.value;
				}
			}
		}
	}
	return o;
}

function paging(res){

	// PAGING
	// http://developer.yahoo.com/yql/guide/paging.html#local_limits
	if(res.query && res.query.count){
		res['paging'] = {
			next : '?start='+res.query.count
		};
	}
}

var yql = function(q){
	return 'https://query.yahooapis.com/v1/yql?q=' + (q + ' limit @{limit|100} offset @{start|0}').replace(" ", '%20') + "&format=json";
};

hello.init({
	'yahoo' : {
		// Ensure that you define an oauth_proxy
		oauth : {
			version : "1.0a",
			auth	: "https://api.login.yahoo.com/oauth/v2/request_auth",
			request : 'https://api.login.yahoo.com/oauth/v2/get_request_token',
			token	: 'https://api.login.yahoo.com/oauth/v2/get_token'
		},

		// AutoRefresh
		// Signin once token expires?
		autorefresh : false,

		/*
		// AUTO REFRESH FIX: Bug in Yahoo can't get this to work with node-oauth-shim
		login : function(o){
			// Is the user already logged in
			var auth = hello('yahoo').getAuthResponse();

			// Is this a refresh token?
			if(o.options.display==='none'&&auth&&auth.access_token&&auth.refresh_token){
				// Add the old token and the refresh token, including path to the query
				// See http://developer.yahoo.com/oauth/guide/oauth-refreshaccesstoken.html
				o.qs.access_token = auth.access_token;
				o.qs.refresh_token = auth.refresh_token;
				o.qs.token_url = 'https://api.login.yahoo.com/oauth/v2/get_token';
			}
		},
		*/

		base	: "https://social.yahooapis.com/v1/",

		get : {
			"me"		: yql('select * from social.profile(0) where guid=me'),
			"me/friends"	: yql('select * from social.contacts(0) where guid=me'),
			"me/following"	: yql('select * from social.contacts(0) where guid=me')
		},
		wrap : {
			me : function(o){
				formatError(o);
				if(o.query&&o.query.results&&o.query.results.profile){
					o = o.query.results.profile;
					o.id = o.guid;
					o.name = o.givenName + ' ' +o.familyName;
					o.last_name = o.familyName;
					o.first_name = o.givenName;
					o.email = o.emails?o.emails.handle:null;
					o.thumbnail = o.image?o.image.imageUrl:null;
				}
				return o;
			},
			// Can't get ID's
			// It might be better to loop through the social.relationshipd table with has unique ID's of users.
			"me/friends" : formatFriends,
			"me/following" : formatFriends,
			"default" : function(res){
				paging(res);
				return res;
			}
		},
		xhr : false
	}
});

})(hello);
<commit_msg>Update yahoo yql formatting<commit_after>//
// Yahoo
//
// Register Yahoo developer
(function(hello){

function formatError(o){
	if(o && "meta" in o && "error_type" in o.meta){
		o.error = {
			code : o.meta.error_type,
			message : o.meta.error_message
		};
	}
}

function formatFriends(o){
	formatError(o);
	paging(o);
	var contact,field;
	if(o.query&&o.query.results&&o.query.results.contact){
		o.data = o.query.results.contact;
		delete o.query;
		if(!(o.data instanceof Array)){
			o.data = [o.data];
		}
		for(var i=0;i<o.data.length;i++){
			contact = o.data[i];
			contact.id = null;
			for(var j=0;j<contact.fields.length;j++){
				field = contact.fields[j];
				if(field.type === 'email'){
					contact.email = field.value;
				}
				if(field.type === 'name'){
					contact.first_name = field.value.givenName;
					contact.last_name = field.value.familyName;
					contact.name = field.value.givenName + ' ' + field.value.familyName;
				}
				if(field.type === 'yahooid'){
					contact.id = field.value;
				}
			}
		}
	}
	return o;
}

function paging(res){

	// PAGING
	// http://developer.yahoo.com/yql/guide/paging.html#local_limits
	if(res.query && res.query.count){
		res['paging'] = {
			next : '?start='+res.query.count
		};
	}
}

var yql = function(q){
	return 'https://query.yahooapis.com/v1/yql?q=' + (q + ' limit @{limit|100} offset @{start|0}').replace(/\s/g, '%20') + "&format=json";
};

hello.init({
	'yahoo' : {
		// Ensure that you define an oauth_proxy
		oauth : {
			version : "1.0a",
			auth	: "https://api.login.yahoo.com/oauth/v2/request_auth",
			request : 'https://api.login.yahoo.com/oauth/v2/get_request_token',
			token	: 'https://api.login.yahoo.com/oauth/v2/get_token'
		},

		// AutoRefresh
		// Signin once token expires?
		autorefresh : false,

		/*
		// AUTO REFRESH FIX: Bug in Yahoo can't get this to work with node-oauth-shim
		login : function(o){
			// Is the user already logged in
			var auth = hello('yahoo').getAuthResponse();

			// Is this a refresh token?
			if(o.options.display==='none'&&auth&&auth.access_token&&auth.refresh_token){
				// Add the old token and the refresh token, including path to the query
				// See http://developer.yahoo.com/oauth/guide/oauth-refreshaccesstoken.html
				o.qs.access_token = auth.access_token;
				o.qs.refresh_token = auth.refresh_token;
				o.qs.token_url = 'https://api.login.yahoo.com/oauth/v2/get_token';
			}
		},
		*/

		base	: "https://social.yahooapis.com/v1/",

		get : {
			"me"		: yql('select * from social.profile(0) where guid=me'),
			"me/friends"	: yql('select * from social.contacts(0) where guid=me'),
			"me/following"	: yql('select * from social.contacts(0) where guid=me')
		},
		wrap : {
			me : function(o){
				formatError(o);
				if(o.query&&o.query.results&&o.query.results.profile){
					o = o.query.results.profile;
					o.id = o.guid;
					o.name = o.givenName + ' ' +o.familyName;
					o.last_name = o.familyName;
					o.first_name = o.givenName;
					o.email = o.emails?o.emails.handle:null;
					o.thumbnail = o.image?o.image.imageUrl:null;
				}
				return o;
			},
			// Can't get ID's
			// It might be better to loop through the social.relationshipd table with has unique ID's of users.
			"me/friends" : formatFriends,
			"me/following" : formatFriends,
			"default" : function(res){
				paging(res);
				return res;
			}
		},
		xhr : false
	}
});

})(hello);
<|endoftext|>


<commit_before>module.exports = {
  APP_NAME: 'app-name',
  PROTOCOL: 'http://',
  HOST: '127.0.0.1',
  PORT: 3030
}<commit_msg>Update env config with db_user and db_password fields<commit_after>module.exports = {
  APP_NAME: 'app-name',
  PROTOCOL: 'http://',
  HOST: '127.0.0.1',
  PORT: 3030,
  DB_USER: '',
  DB_PASSWORD: ''
}<|endoftext|>