auth0-extensions/auth0-delegated-administration-extension

View on GitHub
client/utils/useDefaultFields.js

Summary

Maintainability
A
4 hrs
Test Coverage
import _ from 'lodash';

const applyDefaults = (type, fields, property, defaults) => {
  const field = _.find(fields, { property });

  if (field) {
    if (_.isBoolean(field[type]) && field[type] === false)
      return _.remove(fields, { property });
    return _.defaults(field, defaults);
  }
  return fields.unshift(defaults);
};

export const useUsernameField = (isEditField, fields, connections, hasSelectedConnection, initialValues) => {
  const type = isEditField ? 'edit' : 'create';
  const selectedConnection = _.find(connections, (conn) => conn.name === hasSelectedConnection);
  const requireUsername = selectedConnection && selectedConnection.options ? selectedConnection.options.requires_username : false;
  const noUsername = connections.length > 0
    ? !requireUsername && (!initialValues || !initialValues.username)
    // if we have no connections, we *might* need a username field, we don't know - 
    // because we don't have the connections to check
    : false;

  const defaults = {
    property: 'username',
    label: 'Username',
    disable: noUsername,
    [type]: {
      type: 'text',
      // if we have no connections we should show the field but not require it
      required: connections.length > 0
    }
  };

  return applyDefaults(type, fields, 'username', defaults);
};

export const useMembershipsField = (isEditField, fields, hasMembership, memberships, createMemberships, getDictValue) => {
  const type = isEditField ? 'edit' : 'create';
  const allMemberships = _(memberships || [])
    .concat(hasMembership)
    .uniq()
    .sort()
    .value();

  if (allMemberships.length <= 1 && !createMemberships) {
    return _.remove(fields, { property: 'memberships' });
  }

  const defaults = {
    property: 'memberships',
    label: getDictValue('memberships', 'Memberships'),
    [type]: {
      type: 'select',
      component: 'InputMultiCombo',
      options: allMemberships.map(m => ({ value: m, label: m }))
    }
  };

  return applyDefaults(type, fields, 'memberships', defaults);
};

export const useConnectionsField = (isEditField, fields, connections, onConnectionChange) => {
  const type = isEditField ? 'edit' : 'create';
  // if we have exactly one connection then don't show this field and use that connection
  // however if we have zero connections, we should show the free text connections field
  if (!connections || connections.length === 1) {
    return _.remove(fields, { property: 'connection' });
  }

  const isConnectionLimitExceeded = connections.length === 0;

  const defaults = {
    property: 'connection',
    label: isConnectionLimitExceeded ? 'Connection Name' : 'Connection',
    [type]: {
      required: true,
      type: isConnectionLimitExceeded ? 'text' : 'select',
      component: isConnectionLimitExceeded ? 'InputText' : 'InputCombo',
      options: isConnectionLimitExceeded ? undefined : connections.map(conn => ({ value: conn.name, label: conn.name })),
      onChange: onConnectionChange
    }
  };

  return applyDefaults(type, fields, 'connection', defaults);
};

export const useMfaField = (isEditField, fields, providers, onProviderChange) => {
  const type = isEditField ? 'edit' : 'create';

  const defaults = {
    property: 'multifactor',
    label: 'MFA Provider',
    [type]: {
      required: true,
      type: 'select',
      component: 'InputCombo',
      options: providers.map(prov => ({ value: prov, label: prov })),
      onChange: onProviderChange
    }
  };

  return applyDefaults(type, fields, 'multifactor', defaults);
};

export const useDisabledConnectionField = (isEditField, fields, connection, connections) => {
  const type = isEditField ? 'edit' : 'create';

  if (!connection || !connections || connections.length < 2) {
    return _.remove(fields, { property: 'connection' });
  }

  const defaults = {
    property: 'connection',
    label: 'Connection',
    [type]: {
      type: 'text',
      disabled: true
    }
  };

  applyDefaults(type, fields, 'connection', defaults);

  const field = _.find(fields, { property: 'connection' });
  // If connection is an editable field, we need to display it on other pages, but only as disabled
  if (field && (
      (_.isObject(field[type]) && field[type].disabled !== true) || _.isBoolean(field[type])
    )) field[type] = defaults[type];
};

export const usePasswordFields = (isEditField, fields) => {
  const type = isEditField ? 'edit' : 'create';
  const repeatPasswordDefaults = {
    property: 'repeatPassword',
    label: 'Repeat Password',
    [type]: {
      required: true,
      type: 'password',
      component: 'InputText',
      validationFunction:
        (value, values) =>
          (value !== values.password ? 'passwords must match' : false )
    }
  };

  const passwordDefaults = {
    property: 'password',
    label: 'Password',
    [type]: {
      required: true,
      type: 'password',
      component: 'InputText'
    }
  };

  applyDefaults(type, fields, 'repeatPassword', repeatPasswordDefaults);
  applyDefaults(type, fields, 'password', passwordDefaults);
};

export const useEmailField = (isEditField, fields) => {
  const type = isEditField ? 'edit' : 'create';
  const defaults = {
    property: 'email',
    label: 'Email',
    [type]: {
      type: 'text',
      component: 'InputText',
      required: true
    }
  };

  applyDefaults(type, fields, 'email', defaults);
};

export const useClientField = (isEditField, fields, clients) => {
  const type = isEditField ? 'edit' : 'create';
  const defaults = {
    property: 'client',
    label: 'Client',
    [type]: {
      type: 'select',
      component: 'InputCombo',
      required: false,
      options: clients.map(option => ({ value: option.client_id, label: option.name}))
    }
  };

  applyDefaults(type, fields, 'client', defaults);
};

export const useDisabledEmailField = (isEditField, fields) => {
  const type = isEditField ? 'edit' : 'create';
  const defaults = {
    property: 'email',
    label: 'Email',
    [type]: {
      type: 'text',
      component: 'InputText',
      disabled: true
    }
  };

  applyDefaults(type, fields, 'email', defaults);

  const field = _.find(fields, { property: 'email' });
  // If connection is an editable field, we need to display it on other pages, but only as disabled
  if (field && (
      (_.isObject(field[type]) && field[type].disabled !== true) || _.isBoolean(field[type])
    )) field[type] = defaults[type];
};