opf/openproject

View on GitHub
frontend/src/app/features/projects/components/copy-project/copy-project.component.ts

Summary

Maintainability
A
1 hr
Test Coverage
import {
  IDynamicFieldGroupConfig,
  IOPFormlyFieldSettings,
  IOPFormlyTemplateOptions,
} from 'core-app/shared/components/dynamic-forms/typings';
import { ApiV3Service } from 'core-app/core/apiv3/api-v3.service';
import { I18nService } from 'core-app/core/i18n/i18n.service';
import { PathHelperService } from 'core-app/core/path-helper/path-helper.service';
import { UntilDestroyedMixin } from 'core-app/shared/helpers/angular/until-destroyed.mixin';
import { CurrentProjectService } from 'core-app/core/current-project/current-project.service';
import { Component, OnInit } from '@angular/core';
import { JobStatusModalService } from 'core-app/features/job-status/job-status-modal.service';


@Component({
  templateUrl: './copy-project.component.html',
})
export class CopyProjectComponent extends UntilDestroyedMixin implements OnInit {
  dynamicFieldsSettingsPipe = this.fieldSettingsPipe.bind(this);

  fieldGroups:IDynamicFieldGroupConfig[];

  formUrl:string;

  hiddenFields:string[] = [
    'createdAt',
    'identifier',
    'active',
  ];

  text = {
    advancedSettingsLabel: this.I18n.t('js.forms.advanced_settings'),
    copySettingsLabel: this.I18n.t('js.project.copy.copy_options'),
  };

  constructor(
    private apiV3Service:ApiV3Service,
    private currentProjectService:CurrentProjectService,
    private pathHelperService:PathHelperService,
    private jobStatusModalService:JobStatusModalService,
    private I18n:I18nService,
  ) {
    super();
  }

  ngOnInit():void {
    this.formUrl = this.apiV3Service.projects.id(this.currentProjectService.id!).copy.form.path;
    this.fieldGroups = [
      {
        name: this.text.advancedSettingsLabel,
        fieldsFilter: (field:IOPFormlyFieldSettings) => !this.isMeta(field.templateOptions?.property) && !this.isPrimaryAttribute(field.templateOptions),
      },
      {
        name: this.text.copySettingsLabel,
        fieldsFilter: (field:IOPFormlyFieldSettings) => this.isMeta(field.templateOptions?.property),
      },
    ];
  }

  onSubmitted(response:HalSource) {
    this.jobStatusModalService.show(response.jobId as string);
  }

  private isHiddenField(key:string|undefined):boolean {
    return !!key && this.hiddenFields.includes(key);
  }

  private fieldSettingsPipe(dynamicFieldsSettings:IOPFormlyFieldSettings[]):IOPFormlyFieldSettings[] {
    return this.sortedCopyFields(dynamicFieldsSettings)
      .map((field) => ({ ...field, hide: this.isHiddenField(field.key) }));
  }

  private isPrimaryAttribute(to?:IOPFormlyTemplateOptions):boolean {
    if (!to) {
      return false;
    }

    return (to.required
      && !to.hasDefault
      && to.payloadValue == null)
      || to.property === 'name'
      || to.property === 'parent';
  }

  private isMeta(property:string|undefined):boolean {
    return !!property && (property.startsWith('copy') || property === 'sendNotifications');
  }

  // Sorts the copy options by their label.
  // The order of the rest of the fields is left unchanged but all copy options are returned first.
  private sortedCopyFields(dynamicFieldsSettings:IOPFormlyFieldSettings[]):IOPFormlyFieldSettings[] {
    const sortedCopyFields = dynamicFieldsSettings
      .filter((field) => field.key && field.key.startsWith('_meta.copy'))
      .sort((fieldA, fieldB) => {
        if (!fieldA.templateOptions
          || !fieldA.templateOptions.label
          || !fieldB.templateOptions
          || !fieldB.templateOptions.label) {
          return 0;
        }

        return fieldA.templateOptions.label.localeCompare(fieldB.templateOptions.label);
      });

    const nonCopyFields = dynamicFieldsSettings
      .filter((field) => !field.key || !field.key.startsWith('_meta.copy'));

    // Now all copy fields are before the non Copy fields.
    // That way, the "Sent notifications" is after the copy fields.
    // For the rest, it does not make a difference since the _meta
    // fields are rendered in a separate group.
    return sortedCopyFields.concat(nonCopyFields);
  }
}