export function ApplicationComponent()

in client/web/src/settings/ApplicationComponent.js [33:281]


export function ApplicationComponent(props) {
  const dispatch = useDispatch();
  const {
    appConfig,
    dbOptions,
    hasTenants,
    loading,
    error,
    message,
    osOptions,
    updateConfiguration,
  } = props;

  console.log('App Config:', appConfig);
  const LINUX = 'LINUX';
  const WINDOWS = 'WINDOWS';
  const FSX = 'FSX';
  const EFS = 'EFS';

  const os = !!appConfig.operatingSystem
    ? appConfig.operatingSystem === LINUX
      ? LINUX
      : WINDOWS
    : '';
  const db = !!appConfig.database
    ? {
        ...appConfig.database,
        //This is frail, but try to see if the incoming password is base64d
        //If so, assume it's encrypted
        //Also store a copy in the encryptedPassword field
        hasEncryptedPassword: !!appConfig.database.password.match(/^[A-Za-z0-9=+/\s ]+$/),
        encryptedPassword: appConfig.database.password,
      }
    : {
        engine: '',
        family: '',
        version: '',
        instance: '',
        username: '',
        password: '',
        hasEncryptedPassword: false,
        encryptedPassword: '',
        database: '',
        bootstrapFilename: '',
      };

  const getParts = (dateTime) => {
    const parts = dateTime.split(':');
    const day = parts[0];
    const times = parts.slice(1);
    const timeStr = times.join(':');
    return [day, timeStr];
  };

  const updateConfig = (values) => {
    updateConfiguration(values);
    window.scrollTo(0, 0);
  };

  const getFsx = (fsx) => {
    if (!fsx) {
      return {
        storageGb: 32,
        throughputMbs: 8,
        backupRetentionDays: 7,
        dailyBackupTime: '01:00',
        weeklyMaintenanceTime: '07:01:00',
        weeklyMaintenanceDay: '1',
        windowsMountDrive: 'G:',
      };
    }
    const [day, time] = getParts(fsx.weeklyMaintenanceTime);
    return {
      ...fsx,
      weeklyMaintenanceTime: time,
      weeklyMaintenanceDay: day,
    };
  };

  const filesystem = {
    ...appConfig.filesystem,
    mountPoint: appConfig.filesystem?.mountPoint || '',
    // Start off with FSX if Windows and EFS if Linux
    fileSystemType: appConfig.filesystem?.fileSystemType || (os !== LINUX ? FSX : EFS),

    efs: appConfig.filesystem?.efs || {
      lifecycle: '0',
      encryptAtRest: '',
    },
    fsx: getFsx(appConfig.filesystem?.fsx),
  };

  const initialValues = {
    operatingSystem: os,
    windowsVersion: os !== LINUX ? appConfig.operatingSystem : '',
    name: appConfig.name || '',
    domainName: appConfig.domainName || '',
    sslCertArn: appConfig.sslCertArn || '',
    computeSize: appConfig.computeSize || '',
    containerPort: appConfig.containerPort || 80,
    minCount: appConfig.minCount || 1,
    maxCount: appConfig.maxCount || 1,
    healthCheckURL: appConfig.healthCheckURL || '/index.html',

    database: {
      ...db,
      password: db.hasEncryptedPassword ? db.password.substring(0, 8) : db.password,
    },
    filesystem: filesystem,
    billing: appConfig.billing || {
      apiKey: '',
    },

    provisionDb: !!appConfig.database,
    provisionFS: !!appConfig.filesystem,
    provisionBilling: !!appConfig.billing,
  };

  const validationSpecs = Yup.object({
    operatingSystem: Yup.string().required('Container OS is a required field'),
    name: Yup.string().required('Name is a required field.'),
    computeSize: Yup.string().required('Compute size is a required field.'),
    database: Yup.object().when('provisionDb', {
      is: true,
      then: Yup.object({
        engine: Yup.string().required('Engine is required'),
        version: Yup.string().required('Version is required'),
        instance: Yup.string().required('Instance is required'),
        username: Yup.string()
          .matches('^[a-zA-Z]+[a-zA-Z0-9_$]*$', 'Username is not valid')
          .required('Username is required'),
        password: Yup.string()
          .matches('^[a-zA-Z0-9/@"\' ]{8,}$', 'Password is not valid')
          .required('Password is required'),
        database: Yup.string(),
      }),
      otherwise: Yup.object(),
    }),
    filesystem: Yup.object().when('provisionFS', {
      is: true,
      then: Yup.object({
        mountPoint: Yup.string().when('fileSystemType', {
          is: EFS,
          then: Yup.string()
            .matches(/^(\/[a-zA-Z._-]+)*$/, 'Invalid path. Ex: /mnt')
            .max(100, "The full path can't exceed 100 characters in length")
            .test(
              'subdirectories',
              'The path can only include up to four subdirectories',
              (val) => (val?.match(/\//g) || []).length <= 4
            )
            .required(),
          otherwise: Yup.string()
            .matches(
              /^[a-zA-Z]:\\(((?![<>:"/\\|?*]).)+((?<![ .])\\)?)*$/,
              'Invalid path. Ex: C:\\data'
            )
            .required(),
        }),
        fsx: Yup.object().when('fileSystemType', {
          is: FSX,
          then: Yup.object({
            storageGb: Yup.number()
              .required()
              .min(32, 'Storage minimum is 32 GB')
              .max(1048, 'Storage maximum is 1048 GB'),
            throughputMbs: Yup.number()
              .required()
              .min(8, 'Throughput minimum is 8 MB/s')
              .max(2048, 'Throughput maximum is 2048 MB/s'),
            backupRetentionDays: Yup.number()
              .required()
              .min(7, 'Minimum retention time is 7 days')
              .max(35, 'Maximum retention time is 35 days'),
            dailyBackupTime: Yup.string().required('Daily backup time is required'),
            weeklyMaintenanceTime: Yup.string().required('Weekly maintenance time is required'),
            windowsMountDrive: Yup.string().required('Windows mount drive is required'),
          }),
          otherwise: Yup.object().nullable(),
        }),
        efs: Yup.object().when('fileSystemType', {
          is: EFS,
          then: Yup.object({
            encryptAtRest: Yup.bool(),
            lifecycle: Yup.number().required('Lifecycle is required'),
            filesystemLifecycle: Yup.string(),
          }),
          otherwise: Yup.object().nullable(),
        }),
      }),
      otherwise: Yup.object(),
    }),
    containerPort: Yup.number()
      .integer('Container port must be an integer value.')
      .required('Container port is a required field.'),
    minCount: Yup.number()
      .required('Minimum count is a required field.')
      .integer('Minimum count must be an integer value')
      .min(1, 'Minimum count must be at least ${min}'),
    maxCount: Yup.number()
      .required('Maximum count is a required field.')
      .integer('Maximum count must be an integer value')
      .max(10, 'Maximum count can be no larger than ${max}')
      .test('match', 'Maximum count cannot be smaller than minimum count', function (maxCount) {
        return maxCount >= this.parent.minCount;
      }),
    windowsVersion: Yup.string().when('operatingSystem', {
      is: (containerOs) => containerOs && containerOs === WINDOWS,
      then: Yup.string().required('Windows version is a required field'),
      otherwise: Yup.string().nullable(),
    }),

    healthCheckURL: Yup.string()
      .required('Health Check URL is a required field')
      .matches(/^\//, 'Health Check must start with forward slash (/)'),
    provisionDb: Yup.boolean(),
    provisionFS: Yup.boolean(),
    provisionBilling: Yup.boolean(),
  });

  const onFileSelected = (formik, file) => {
    formik.setFieldValue('database.bootstrapFilename', file.name);
    props.onFileSelected(file);
  };

  const dismissError = () => {
    dispatch(dismissConfigError());
  };

  const dismissMessage = () => {
    dispatch(dismissConfigMessage());
  };

  const isSubmitting = () => {
    return loading !== 'idle';
  };

  return (
    <LoadingOverlay active={isSubmitting()} spinner text="Loading configuration...">
      <div className="animated fadeIn">
        {hasTenants && (
          <Alert color="primary">
            <span>
              <i className="fa fa-info-circle" /> Note: some settings cannot be modified once you
              have deployed tenants.
            </span>
          </Alert>
        )}
        {/* {loading !== "idle" && <div>Loading...</div>} */}