Plan Workflow > add plan workflow editor to tenant configuration
This commit is contained in:
parent
d8959d4180
commit
e29912a354
|
@ -217,6 +217,10 @@ export enum AppPermission {
|
|||
EditUsageLimit = "EditUsageLimit",
|
||||
DeleteUsageLimit = "DeleteUsageLimit",
|
||||
|
||||
//PlanWorkflow
|
||||
EditPlanWorkflow = "EditPlanWorkflow",
|
||||
DeletePlanWorkflow = "DeletePlanWorkflow",
|
||||
|
||||
|
||||
// UI Pages
|
||||
ViewDescriptionTemplateTypePage = "ViewDescriptionTemplateTypePage",
|
||||
|
@ -245,5 +249,6 @@ export enum AppPermission {
|
|||
ViewUsageLimitPage = "ViewUsageLimitPage",
|
||||
ViewPlanStatusPage = "ViewPlanStatusPage",
|
||||
ViewDescriptionStatusPage = "ViewDescriptionStatusPage",
|
||||
ViewPlanWorkflowPage = "ViewPlanWorkflowPage"
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ import { RouterUtilsService } from './services/router/router-utils.service';
|
|||
import { UsageLimitService } from './services/usage-limit/usage.service';
|
||||
import { PlanStatusService } from './services/plan/plan-status.service';
|
||||
import { DescriptionStatusService } from './services/description-status/description-status.service';
|
||||
import { PlanWorkflowService } from './services/plan/plan-workflow.service';
|
||||
//
|
||||
//
|
||||
// This is shared module that provides all the services. Its imported only once on the AppModule.
|
||||
|
@ -119,7 +120,8 @@ export class CoreServiceModule {
|
|||
RouterUtilsService,
|
||||
UsageLimitService,
|
||||
PlanStatusService,
|
||||
DescriptionStatusService
|
||||
DescriptionStatusService,
|
||||
PlanWorkflowService
|
||||
],
|
||||
};
|
||||
}
|
||||
|
|
|
@ -13,6 +13,6 @@ export interface PlanWorkflowDefinitionPersist {
|
|||
}
|
||||
|
||||
export interface PlanWorkflowDefinitionTransitionPersist {
|
||||
fromStatus: Guid;
|
||||
toStatus: Guid;
|
||||
fromStatusId: Guid;
|
||||
toStatusId: Guid;
|
||||
}
|
|
@ -3,19 +3,12 @@ import { Guid } from "@common/types/guid";
|
|||
import { IsActive } from "../common/enum/is-active.enum";
|
||||
|
||||
export class PlanWorkflowLookup extends Lookup implements PlanWorkflowFilter{
|
||||
ids: Guid[];
|
||||
excludedIds: Guid[];
|
||||
like: string;
|
||||
isActive: IsActive[];
|
||||
|
||||
tenantId: Guid;
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
export interface PlanWorkflowFilter {
|
||||
ids: Guid[];
|
||||
excludedIds: Guid[];
|
||||
like: string;
|
||||
isActive: IsActive[];
|
||||
tenantId: Guid;
|
||||
}
|
|
@ -22,6 +22,7 @@ export class AnalyticsService {
|
|||
public static DepositEditor: string = 'Admin: TenantConfigurations';
|
||||
public static FileTransformerEditor: string = 'Admin: TenantConfigurations';
|
||||
public static LogoEditor: string = 'Admin: TenantConfigurations';
|
||||
public static PlanWorkflowEditor: string = 'Admin: TenantConfigurations';
|
||||
public static ContactContent: string = 'Contact Content';
|
||||
public static RecentEditedActivity: string = 'Recent DMP Activity';
|
||||
public static DescriptionEditor: string = 'Description Editor';
|
||||
|
|
|
@ -8,6 +8,10 @@ import { QueryResult } from "@common/model/query-result";
|
|||
import { catchError, Observable, throwError } from "rxjs";
|
||||
import { PlanStatusPersist } from "@app/core/model/plan-status/plan-status-persist";
|
||||
import { Guid } from "@common/types/guid";
|
||||
import { PlanLookup } from "@app/core/query/plan.lookup";
|
||||
import { FilterService } from "@common/modules/text-filter/filter-service";
|
||||
import { IsActive } from "@notification-service/core/enum/is-active.enum";
|
||||
import { nameof } from "ts-simple-nameof";
|
||||
|
||||
@Injectable()
|
||||
export class PlanStatusService {
|
||||
|
@ -16,6 +20,7 @@ export class PlanStatusService {
|
|||
constructor(
|
||||
private http: BaseHttpV2Service,
|
||||
private configurationService: ConfigurationService,
|
||||
private filterService: FilterService
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -50,4 +55,30 @@ export class PlanStatusService {
|
|||
.delete<PlanStatus>(url).pipe(
|
||||
catchError((error: any) => throwError(() => error)));
|
||||
}
|
||||
|
||||
buildLookup(params: {
|
||||
like?: string,
|
||||
excludedIds?: Guid[],
|
||||
ids?: Guid[],
|
||||
lookupFields?: string[],
|
||||
size?: number,
|
||||
order?: string[]
|
||||
}): PlanStatusLookup {
|
||||
const {like, excludedIds, ids, lookupFields, size = 100, order} = params;
|
||||
const lookup = new PlanLookup();
|
||||
lookup.isActive = [IsActive.Active];
|
||||
|
||||
lookup.order = { items: order ?? [nameof<PlanStatus>(x => x.name)] };
|
||||
lookup.page = { size, offset: 0 };
|
||||
|
||||
if (excludedIds && excludedIds.length > 0) { lookup.excludedIds = excludedIds; }
|
||||
if (ids && ids.length > 0) { lookup.ids = ids; }
|
||||
if (like) { lookup.like = this.filterService.transformLike(like); }
|
||||
if(lookupFields){
|
||||
lookup.project = {
|
||||
fields: lookupFields
|
||||
}
|
||||
};
|
||||
return lookup;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
import { HttpHeaders } from "@angular/common/http";
|
||||
import { Injectable } from "@angular/core";
|
||||
import { BaseHttpV2Service } from "../http/base-http-v2.service";
|
||||
import { ConfigurationService } from "../configuration/configuration.service";
|
||||
import { PlanWorkflowPersist } from "@app/core/model/plan-workflow/plan-workflow-persist";
|
||||
import { PlanWorkflow } from "@app/core/model/plan-workflow/plan-workflow";
|
||||
import { catchError, map, Observable, of, throwError } from "rxjs";
|
||||
import { PlanWorkflowLookup } from "@app/core/query/plan-workflow.lookup";
|
||||
import { QueryResult } from "@common/model/query-result";
|
||||
import { Guid } from "@common/types/guid";
|
||||
|
||||
@Injectable()
|
||||
export class PlanWorkflowService {
|
||||
private headers = new HttpHeaders();
|
||||
|
||||
constructor(
|
||||
private http: BaseHttpV2Service,
|
||||
private configurationService: ConfigurationService,
|
||||
) {
|
||||
}
|
||||
|
||||
private get apiBase(): string { return `${this.configurationService.server}plan-workflow`; }
|
||||
|
||||
getCurrent(reqFields: string[] = []): Observable<PlanWorkflow> {
|
||||
const url = `${this.apiBase}/current-tenant`;
|
||||
const options = { params: { f: reqFields } };
|
||||
return this.http
|
||||
.get<PlanWorkflow>(url, options).pipe(
|
||||
catchError((error: any) => throwError(() => error)));
|
||||
}
|
||||
|
||||
query(q: PlanWorkflowLookup): Observable<QueryResult<PlanWorkflow>> {
|
||||
const url = `${this.apiBase}/query`;
|
||||
return this.http.post<QueryResult<PlanWorkflow>>(url, q).pipe(
|
||||
catchError((error: any) => throwError(() => error))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
persist(item: PlanWorkflowPersist): Observable<PlanWorkflow> {
|
||||
const url = `${this.apiBase}/persist`;
|
||||
|
||||
return this.http
|
||||
.post<PlanWorkflow>(url, item).pipe(
|
||||
catchError((error: any) => throwError(() => error)));
|
||||
}
|
||||
|
||||
delete(id: Guid): Observable<void> {
|
||||
const url = `${this.apiBase}/${id}`;
|
||||
|
||||
return this.http
|
||||
.delete<void>(url).pipe(
|
||||
catchError((error: any) => throwError(() => error)));
|
||||
}
|
||||
}
|
|
@ -95,6 +95,7 @@ export class PlanStatusEditorModel extends BaseEditorModel implements PlanStatus
|
|||
|
||||
export interface PlanStatusForm {
|
||||
id: FormControl<Guid>;
|
||||
hash: FormControl<string>;
|
||||
name: FormControl<string>;
|
||||
description: FormControl<string>;
|
||||
internalStatus: FormControl<PlanStatusEnum>;
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
import { FormArray, FormControl, FormGroup, ValidatorFn, Validators } from "@angular/forms";
|
||||
import { PlanWorkflow } from "@app/core/model/plan-workflow/plan-workflow";
|
||||
import { PlanWorkflowDefinitionPersist, PlanWorkflowPersist } from "@app/core/model/plan-workflow/plan-workflow-persist";
|
||||
import { BaseEditorModel } from "@common/base/base-form-editor-model";
|
||||
import { BackendErrorValidator } from "@common/forms/validation/custom-validator";
|
||||
import { Validation, ValidationContext } from "@common/forms/validation/validation-context";
|
||||
import { Guid } from "@common/types/guid";
|
||||
|
||||
export class PlanWorkflowEditorModel extends BaseEditorModel implements PlanWorkflowPersist {
|
||||
name: string = 'default';
|
||||
description: string;
|
||||
definition: PlanWorkflowDefinitionPersist;
|
||||
|
||||
public fromModel(item: PlanWorkflow): PlanWorkflowEditorModel {
|
||||
if(item){
|
||||
super.fromModel(item);
|
||||
this.description = item.description;
|
||||
this.definition = {
|
||||
startingStatusId: item.definition?.startingStatus?.id ?? null,
|
||||
statusTransitions: []
|
||||
};
|
||||
item.definition?.statusTransitions?.forEach((st) =>
|
||||
this.definition.statusTransitions.push({
|
||||
fromStatusId: st.fromStatus?.id,
|
||||
toStatusId: st.toStatus?.id
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
buildForm(params: {context?: ValidationContext, disabled?: boolean}): FormGroup<PlanWorkflowForm> {
|
||||
const {context, disabled = false} = params;
|
||||
const mainContext = context ?? this.createValidationContext();
|
||||
const formGroup = new FormGroup<PlanWorkflowForm>({
|
||||
id: new FormControl({value: this.id, disabled }, mainContext.getValidation('id').validators),
|
||||
hash: new FormControl({value: this.hash, disabled }, mainContext.getValidation('hash').validators),
|
||||
name: new FormControl({value: this.name, disabled}, mainContext.getValidation('name').validators),
|
||||
description: new FormControl({value: this.description, disabled}, mainContext.getValidation('description').validators),
|
||||
definition: new FormGroup<PlanWorkflowDefinitionForm>({
|
||||
startingStatusId: new FormControl({value: this.definition?.startingStatusId, disabled}, mainContext.getValidation('startingStatusId').validators),
|
||||
statusTransitions: new FormArray<FormGroup<PlanWorkflowDefinitionTransitionForm>>([], mainContext.getValidation('statusTransitions').validators)
|
||||
}, mainContext.getValidation('definition').validators)
|
||||
})
|
||||
|
||||
this.definition?.statusTransitions?.forEach((st, index) => {
|
||||
const itemContext = context ?? this.createValidationContext(`StatusTransition[${index}]`)
|
||||
formGroup.controls.definition.controls.statusTransitions.push(new FormGroup({
|
||||
fromStatusId: new FormControl({value: st.fromStatusId,disabled}, itemContext.getValidation('fromStatusId').validators),
|
||||
toStatusId: new FormControl({value: st.toStatusId,disabled}, itemContext.getValidation('fromStatusId').validators)
|
||||
}, this.differentStatusId()))
|
||||
})
|
||||
|
||||
return formGroup;
|
||||
}
|
||||
|
||||
buildStatusTransitionForm(index: number): FormGroup<PlanWorkflowDefinitionTransitionForm> {
|
||||
const itemContext = this.createValidationContext(`StatusTransition[${index}]`)
|
||||
return new FormGroup({
|
||||
fromStatusId: new FormControl(null, itemContext.getValidation('fromStatusId').validators),
|
||||
toStatusId: new FormControl(null, itemContext.getValidation('toStatusId').validators)
|
||||
}, this.differentStatusId())
|
||||
}
|
||||
|
||||
reApplyDefinitionValidators(formGroup: FormGroup<PlanWorkflowDefinitionForm>) {
|
||||
if(!formGroup?.controls?.statusTransitions?.length) { return; }
|
||||
formGroup.controls.statusTransitions.controls.forEach((st, index) => {
|
||||
const context = this.createValidationContext(`StatusTransition[${index}]`);
|
||||
st.clearValidators();
|
||||
st.addValidators(this.differentStatusId());
|
||||
st.controls.fromStatusId.clearValidators();
|
||||
st.controls.fromStatusId.addValidators(context.getValidation('fromStatusId').validators);
|
||||
st.controls.toStatusId.clearValidators();
|
||||
st.controls.toStatusId.addValidators(context.getValidation('toStatusId').validators);
|
||||
})
|
||||
}
|
||||
|
||||
createValidationContext(rootPath?: string): ValidationContext {
|
||||
const baseContext: ValidationContext = new ValidationContext();
|
||||
const baseValidationArray: Validation[] = new Array<Validation>();
|
||||
baseValidationArray.push({ key: 'id', validators: [BackendErrorValidator(this.validationErrorModel, `${rootPath}id`)] });
|
||||
baseValidationArray.push({ key: 'name', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, `${rootPath}name`)] });
|
||||
baseValidationArray.push({ key: 'description', validators: [BackendErrorValidator(this.validationErrorModel, `${rootPath}description`)] });
|
||||
baseValidationArray.push({ key: 'hash', validators: [] });
|
||||
baseValidationArray.push({ key: 'definition', validators: [BackendErrorValidator(this.validationErrorModel, `${rootPath}definition`)] });
|
||||
baseValidationArray.push({ key: 'statusTransitions', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, `${rootPath}statusTransitions`)] });
|
||||
baseValidationArray.push({ key: 'startingStatusId', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, `${rootPath}startingStatusId`)] });
|
||||
baseValidationArray.push({ key: 'fromStatusId', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, `${rootPath}fromStatusId`)] });
|
||||
baseValidationArray.push({ key: 'toStatusId', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, `${rootPath}toStatusId`)] });
|
||||
|
||||
baseContext.validation = baseValidationArray;
|
||||
return baseContext;
|
||||
}
|
||||
|
||||
differentStatusId(): ValidatorFn {
|
||||
return (formGroup: FormGroup<PlanWorkflowDefinitionTransitionForm>): { [key: string]: any } => {
|
||||
const fromStatusId = formGroup?.controls?.fromStatusId?.value;
|
||||
const toStatusId = formGroup?.controls?.toStatusId?.value;
|
||||
if(!fromStatusId || !toStatusId){
|
||||
return null;
|
||||
}
|
||||
return fromStatusId?.toString().toLowerCase() == toStatusId?.toString()?.toLowerCase() ?
|
||||
{'differentStatusId': true} : null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface PlanWorkflowForm {
|
||||
id: FormControl<Guid>;
|
||||
hash: FormControl<string>;
|
||||
name: FormControl<string>;
|
||||
description: FormControl<string>;
|
||||
definition: FormGroup<PlanWorkflowDefinitionForm>;
|
||||
}
|
||||
|
||||
export interface PlanWorkflowDefinitionForm {
|
||||
startingStatusId: FormControl<Guid>;
|
||||
statusTransitions: FormArray<FormGroup<PlanWorkflowDefinitionTransitionForm>>
|
||||
}
|
||||
|
||||
export interface PlanWorkflowDefinitionTransitionForm {
|
||||
fromStatusId: FormControl<Guid>;
|
||||
toStatusId: FormControl<Guid>;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
import { Injectable } from "@angular/core";
|
||||
import { PlanWorkflow, PlanWorkflowDefinition, PlanWorkflowDefinitionTransition } from "@app/core/model/plan-workflow/plan-workflow";
|
||||
import { PlanWorkflowService } from "@app/core/services/plan/plan-workflow.service";
|
||||
import { BaseEditorResolver } from "@common/base/base-editor.resolver";
|
||||
import { takeUntil } from "rxjs";
|
||||
import { nameof } from "ts-simple-nameof";
|
||||
|
||||
@Injectable()
|
||||
export class PlanWorkflowEditorResolver extends BaseEditorResolver {
|
||||
|
||||
constructor(private planWorkflowService: PlanWorkflowService) {
|
||||
super();
|
||||
}
|
||||
|
||||
public static lookupFields(): string[] {
|
||||
return [
|
||||
...BaseEditorResolver.lookupFields(),
|
||||
nameof<PlanWorkflow>(x => x.name),
|
||||
nameof<PlanWorkflow>(x => x.description),
|
||||
nameof<PlanWorkflow>(x => x.definition),
|
||||
|
||||
[nameof<PlanWorkflow>(x => x.definition), nameof<PlanWorkflowDefinition>(x => x.startingStatus.id)].join('.'),
|
||||
[nameof<PlanWorkflow>(x => x.definition), nameof<PlanWorkflowDefinition>(x => x.startingStatus.name)].join('.'),
|
||||
[nameof<PlanWorkflow>(x => x.definition), nameof<PlanWorkflowDefinition>(x => x.statusTransitions)].join('.'),
|
||||
[nameof<PlanWorkflow>(x => x.definition), nameof<PlanWorkflowDefinition>(x => x.statusTransitions), nameof<PlanWorkflowDefinitionTransition>(x => x.fromStatus.id)].join('.'),
|
||||
[nameof<PlanWorkflow>(x => x.definition), nameof<PlanWorkflowDefinition>(x => x.statusTransitions), nameof<PlanWorkflowDefinitionTransition>(x => x.fromStatus.name)].join('.'),
|
||||
[nameof<PlanWorkflow>(x => x.definition), nameof<PlanWorkflowDefinition>(x => x.statusTransitions), nameof<PlanWorkflowDefinitionTransition>(x => x.toStatus.id)].join('.'),
|
||||
[nameof<PlanWorkflow>(x => x.definition), nameof<PlanWorkflowDefinition>(x => x.statusTransitions), nameof<PlanWorkflowDefinitionTransition>(x => x.toStatus.name)].join('.'),
|
||||
]
|
||||
}
|
||||
|
||||
resolve() {
|
||||
|
||||
const fields = [
|
||||
...PlanWorkflowEditorResolver.lookupFields()
|
||||
];
|
||||
|
||||
return this.planWorkflowService.getCurrent(fields).pipe(takeUntil(this._destroyed));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
<div *ngIf="formGroup" class="container-fluid plan-workflow">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<mat-form-field class="w-100">
|
||||
<mat-label>{{'PLAN-WORKFLOW-EDITOR.FIELDS.STARTING-STATUS' | translate}}*</mat-label>
|
||||
<app-single-auto-complete
|
||||
[required]="true"
|
||||
[formControl]="definitionForm?.controls?.startingStatusId"
|
||||
placeholder="{{'PLAN-WORKFLOW-EDITOR.ACTIONS.SELECT-PLAN-STATUS' | translate}}"
|
||||
[configuration]="planStatusAutoCompleteConfiguration"
|
||||
/>
|
||||
<mat-error *ngIf="definitionForm?.controls?.startingStatusId.hasError('backendError')">{{definitionForm?.controls?.startingStatusId.getError('backendError').message}}</mat-error>
|
||||
<mat-error *ngIf="definitionForm?.controls.startingStatusId.hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button mat-button class="action-btn row" type="button" (click)="addStatusTransition()" [disabled]="formGroup.disabled">{{'PLAN-WORKFLOW-EDITOR.ACTIONS.ADD-STATUS-TRANSITION' | translate}}</button>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<mat-error class="pl-3 pt-2" *ngIf="definitionForm?.touched && definitionForm?.controls?.statusTransitions?.hasError('required')">
|
||||
{{'PLAN-WORKFLOW-EDITOR.ERRORS.STATUS-TRANSITION-REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
@for(transitionForm of definitionForm?.controls?.statusTransitions?.controls; track transitionForm; let index = $index){
|
||||
<div class="col-12">
|
||||
<div class="row mb-3 d-flex align-items-center">
|
||||
<div class="col-auto d-flex">
|
||||
<mat-card-title>{{'PLAN-WORKFLOW-EDITOR.FIELDS.STATUS-TRANSITION' | translate}} {{index + 1}}</mat-card-title>
|
||||
</div>
|
||||
<div class="col-auto d-flex">
|
||||
<button mat-icon-button class="action-list-icon" matTooltip="{{'PLAN-WORKFLOW-EDITOR.ACTIONS.REMOVE-STATUS-TRANSITION' | translate}}" (click)="removeStatusTransition(index)" [disabled]="formGroup.disabled">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6">
|
||||
<mat-form-field class="w-100">
|
||||
<mat-label>{{'PLAN-WORKFLOW-EDITOR.FIELDS.FROM-STATUS' | translate}}*</mat-label>
|
||||
<app-single-auto-complete
|
||||
[required]="true"
|
||||
[formControl]="transitionForm?.controls?.fromStatusId"
|
||||
placeholder="{{'PLAN-WORKFLOW-EDITOR.ACTIONS.SELECT-PLAN-STATUS' | translate}}"
|
||||
[configuration]="planStatusAutoCompleteConfiguration"
|
||||
/>
|
||||
<mat-error *ngIf="transitionForm?.controls?.fromStatusId.hasError('backendError')">{{transitionForm?.controls?.fromStatusId.getError('backendError').message}}</mat-error>
|
||||
<mat-error *ngIf="transitionForm?.controls.fromStatusId.hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6">
|
||||
<mat-form-field class="w-100">
|
||||
<mat-label>{{'PLAN-WORKFLOW-EDITOR.FIELDS.TO-STATUS' | translate}}*</mat-label>
|
||||
<app-single-auto-complete
|
||||
[required]="true"
|
||||
[formControl]="transitionForm?.controls?.toStatusId"
|
||||
placeholder="{{'PLAN-WORKFLOW-EDITOR.ACTIONS.SELECT-PLAN-STATUS' | translate}}"
|
||||
[configuration]="planStatusAutoCompleteConfiguration"
|
||||
/>
|
||||
<mat-error *ngIf="transitionForm?.controls?.toStatusId.hasError('backendError')">{{transitionForm?.controls?.toStatusId.getError('backendError').message}}</mat-error>
|
||||
<mat-error *ngIf="transitionForm?.controls.toStatusId.hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-error class="pl-3" *ngIf="transitionForm.hasError('differentStatusId')">{{'PLAN-WORKFLOW-EDITOR.ERRORS.DIFFERENT-STATUS' | translate}}</mat-error>
|
||||
}
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="row actions-row">
|
||||
<div class="col"></div>
|
||||
@if(canDelete){
|
||||
<div class="col-auto">
|
||||
<button class="normal-btn-sm" (click)="delete()">
|
||||
{{'TENANT-CONFIGURATION-EDITOR.ACTIONS.RESET-TO-DEFAULT' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
@if(canSave){
|
||||
<div class="col-auto">
|
||||
<button class="normal-btn-sm" (click)="formSubmit()">
|
||||
{{'TENANT-CONFIGURATION-EDITOR.ACTIONS.SAVE' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,24 @@
|
|||
.plan-workflow {
|
||||
.action-btn {
|
||||
border-radius: 30px;
|
||||
background-color: var(--secondary-color);
|
||||
border: 1px solid transparent;
|
||||
padding-left: 2em;
|
||||
padding-right: 2em;
|
||||
box-shadow: 0px 3px 6px #1E202029;
|
||||
|
||||
transition-property: background-color, color;
|
||||
transition-duration: 200ms;
|
||||
transition-delay: 50ms;
|
||||
transition-timing-function: ease-in-out;
|
||||
&:disabled{
|
||||
background-color: #CBCBCB;
|
||||
color: #FFF;
|
||||
border: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep label {
|
||||
margin: 0;
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { BasePendingChangesComponent } from '@common/base/base-pending-changes.component';
|
||||
import { map, Observable, takeUntil } from 'rxjs';
|
||||
import { PlanWorkflowDefinitionForm, PlanWorkflowEditorModel, PlanWorkflowForm } from '../plan-workflow-editor.model';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { PlanWorkflowService } from '@app/core/services/plan/plan-workflow.service';
|
||||
import { AnalyticsService } from '@app/core/services/matomo/analytics-service';
|
||||
import { PlanWorkflow } from '@app/core/model/plan-workflow/plan-workflow';
|
||||
import { PlanWorkflowEditorResolver } from '../plan-workflow-editor.resolver';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { HttpError, HttpErrorHandlingService } from '@common/modules/errors/error-handling/http-error-handling.service';
|
||||
import { AppPermission } from '@app/core/common/enum/permission.enum';
|
||||
import { AuthService } from '@app/core/services/auth/auth.service';
|
||||
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
|
||||
import { LoggingService } from '@app/core/services/logging/logging-service';
|
||||
import { FormService } from '@common/forms/form-service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { PlanWorkflowPersist } from '@app/core/model/plan-workflow/plan-workflow-persist';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
|
||||
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
|
||||
import { PlanStatusEnum } from '@app/core/common/enum/plan-status';
|
||||
import { PlanStatus } from '@app/core/model/plan-status/plan-status';
|
||||
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
|
||||
import { PlanStatusService } from '@app/core/services/plan/plan-status.service';
|
||||
import { nameof } from 'ts-simple-nameof';
|
||||
import { Guid } from '@common/types/guid';
|
||||
|
||||
@Component({
|
||||
selector: 'app-plan-workflow-editor',
|
||||
templateUrl: './plan-workflow-editor.component.html',
|
||||
styleUrl: './plan-workflow-editor.component.scss'
|
||||
})
|
||||
export class PlanWorkflowEditorComponent extends BasePendingChangesComponent implements OnInit{
|
||||
formGroup: FormGroup<PlanWorkflowForm>;
|
||||
editorModel: PlanWorkflowEditorModel;
|
||||
|
||||
constructor(
|
||||
protected dialog: MatDialog,
|
||||
protected language: TranslateService,
|
||||
protected formService: FormService,
|
||||
protected uiNotificationService: UiNotificationService,
|
||||
protected httpErrorHandlingService: HttpErrorHandlingService,
|
||||
protected authService: AuthService,
|
||||
protected enumUtils: EnumUtils,
|
||||
private logger: LoggingService,
|
||||
private planWorkflowService: PlanWorkflowService,
|
||||
private analyticsService: AnalyticsService,
|
||||
private planStatusService: PlanStatusService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.analyticsService.trackPageView(AnalyticsService.PlanWorkflowEditor);
|
||||
this.getItem((entity) => {
|
||||
this.prepareForm(entity);
|
||||
if (this.formGroup && this.editorModel.belongsToCurrentTenant == false) {
|
||||
this.formGroup.disable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected getItem(successFunction: (item: PlanWorkflow) => void) {
|
||||
this.planWorkflowService.getCurrent(PlanWorkflowEditorResolver.lookupFields())
|
||||
.pipe(takeUntil(this._destroyed))
|
||||
.subscribe({
|
||||
next: (data) => successFunction(data),
|
||||
error: (error) => this.onCallbackError(error)
|
||||
});
|
||||
}
|
||||
|
||||
protected prepareForm(data: PlanWorkflow) {
|
||||
try {
|
||||
this.editorModel = data ? new PlanWorkflowEditorModel().fromModel(data) : new PlanWorkflowEditorModel();
|
||||
this.formGroup = this.editorModel.buildForm({disabled: !this.authService.hasPermission(AppPermission.EditPlanWorkflow)});
|
||||
|
||||
} catch (error) {
|
||||
this.logger.error('Could not parse PlanWorkflow item: ' + data + error);
|
||||
this.uiNotificationService.snackBarNotification(this.language.instant('COMMONS.ERRORS.DEFAULT'), SnackBarNotificationLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
protected refreshData(): void {
|
||||
this.getItem((entity) => {
|
||||
this.prepareForm(entity);
|
||||
if (this.formGroup && this.editorModel.belongsToCurrentTenant == false) {
|
||||
this.formGroup.disable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
protected get canDelete(): boolean {
|
||||
return this.editorModel?.id && this.authService.hasPermission(this.authService.permissionEnum.DeletePlanWorkflow);
|
||||
}
|
||||
|
||||
protected get canSave(): boolean {
|
||||
return this.formGroup.touched && this.authService.hasPermission(this.authService.permissionEnum.EditPlanWorkflow);
|
||||
}
|
||||
|
||||
protected get definitionForm(): FormGroup<PlanWorkflowDefinitionForm> {
|
||||
return this.formGroup?.controls?.definition;
|
||||
}
|
||||
|
||||
protected onCallbackError(errorResponse: HttpErrorResponse) {
|
||||
this.httpErrorHandlingService.handleBackedRequestError(errorResponse)
|
||||
|
||||
const error: HttpError = this.httpErrorHandlingService.getError(errorResponse);
|
||||
if (error.statusCode === 400) {
|
||||
this.editorModel.validationErrorModel.fromJSONObject(errorResponse.error);
|
||||
this.formService.validateAllFormFields(this.formGroup);
|
||||
}
|
||||
}
|
||||
|
||||
protected onCallbackSuccess(): void {
|
||||
this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success);
|
||||
this.refreshData();
|
||||
}
|
||||
|
||||
formSubmit(): void {
|
||||
this.editorModel.validationErrorModel.clear();
|
||||
this.formService.removeAllBackEndErrors(this.formGroup);
|
||||
|
||||
this.formService.touchAllFormFields(this.formGroup);
|
||||
this.formService.validateAllFormFields(this.formGroup);
|
||||
|
||||
if (!this.formGroup?.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.persistEntity();
|
||||
}
|
||||
|
||||
persistEntity(): void {
|
||||
const formData = JSON.parse(JSON.stringify(this.formGroup.value)) as PlanWorkflowPersist;
|
||||
|
||||
|
||||
|
||||
this.planWorkflowService.persist(formData)
|
||||
.pipe(takeUntil(this._destroyed)).subscribe({
|
||||
complete: () => this.onCallbackSuccess(),
|
||||
error: (error) => this.onCallbackError(error)
|
||||
});
|
||||
}
|
||||
|
||||
delete() {
|
||||
const value = this.formGroup.value;
|
||||
if (value.id) {
|
||||
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
|
||||
maxWidth: '300px',
|
||||
data: {
|
||||
message: this.language.instant('TENANT-CONFIGURATION-EDITOR.RESET-TO-DEFAULT-DIALOG.RESET-TO-DEFAULT'),
|
||||
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
|
||||
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL')
|
||||
}
|
||||
});
|
||||
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
|
||||
if (result) {
|
||||
this.planWorkflowService.delete(value.id).pipe(takeUntil(this._destroyed))
|
||||
.subscribe({
|
||||
complete: () => {
|
||||
this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-RESET'), SnackBarNotificationLevel.Success);
|
||||
this.prepareForm(null);
|
||||
},
|
||||
error: (error) => this.onCallbackError(error)
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
addStatusTransition(){
|
||||
const index = this.formGroup.controls.definition.controls.statusTransitions.length;
|
||||
this.formGroup.controls.definition.controls.statusTransitions.push(this.editorModel.buildStatusTransitionForm(index));
|
||||
this.formGroup.markAsTouched();
|
||||
}
|
||||
|
||||
removeStatusTransition(index: number){
|
||||
this.formGroup.controls.definition.controls.statusTransitions.removeAt(index);
|
||||
this.editorModel.reApplyDefinitionValidators(this.formGroup.controls.definition);
|
||||
this.formGroup.markAsTouched();
|
||||
}
|
||||
|
||||
canDeactivate(): boolean | Observable<boolean> {
|
||||
return this.formGroup ? !this.formGroup.dirty : true;
|
||||
}
|
||||
|
||||
private planStatusLookupFields = [
|
||||
nameof<PlanStatus>(x => x.id),
|
||||
nameof<PlanStatus>(x => x.name),
|
||||
]
|
||||
|
||||
planStatusAutoCompleteConfiguration: SingleAutoCompleteConfiguration = {
|
||||
initialItems: (data?: any) => this.planStatusService.query(
|
||||
this.planStatusService.buildLookup({
|
||||
size: 20, lookupFields: this.planStatusLookupFields
|
||||
})).pipe(map(x => x.items)),
|
||||
filterFn: (searchQuery: string, data?: any) => this.planStatusService.query(
|
||||
this.planStatusService.buildLookup({
|
||||
size: 20,
|
||||
like: searchQuery,
|
||||
lookupFields: this.planStatusLookupFields
|
||||
})
|
||||
).pipe(map(x => x.items)),
|
||||
getSelectedItem: (id: Guid) => this.planStatusService.getSingle(id, this.planStatusLookupFields),
|
||||
displayFn: (item: PlanStatus) => item.name,
|
||||
titleFn: (item: PlanStatus) => item.name,
|
||||
valueAssign: (item: PlanStatus) => {this.formGroup.markAsTouched(); return item.id},
|
||||
};
|
||||
}
|
|
@ -73,7 +73,15 @@
|
|||
<app-tenant-configuration-notifier-list-editor></app-tenant-configuration-notifier-list-editor>
|
||||
</ng-template>
|
||||
</mat-expansion-panel>
|
||||
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>{{'TENANT-CONFIGURATION-EDITOR.PLAN-WORKFLOW.TITLE' | translate}}</mat-panel-title>
|
||||
<mat-panel-description>{{'TENANT-CONFIGURATION-EDITOR.PLAN-WORKFLOW.HINT' | translate}}</mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
<ng-template matExpansionPanelContent>
|
||||
<app-plan-workflow-editor></app-plan-workflow-editor>
|
||||
</ng-template>
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -20,6 +20,7 @@ import { FileTransformerEditorComponent } from './editor/file-transformer/file-t
|
|||
import { LogoEditorComponent } from './editor/logo/logo-editor.component';
|
||||
import { NgxColorsModule } from 'ngx-colors';
|
||||
import { NotifierListModule } from '@notification-service/ui/admin/tenant-configuration/notifier-list/notifier-list-editor.module';
|
||||
import { PlanWorkflowEditorComponent } from './editor/plan-workflow/plan-workflow-editor/plan-workflow-editor.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
|
@ -45,7 +46,8 @@ import { NotifierListModule } from '@notification-service/ui/admin/tenant-config
|
|||
DefaultUserLocaleEditorComponent,
|
||||
DepositEditorComponent,
|
||||
FileTransformerEditorComponent,
|
||||
LogoEditorComponent
|
||||
LogoEditorComponent,
|
||||
PlanWorkflowEditorComponent
|
||||
]
|
||||
})
|
||||
export class TenantConfigurationModule { }
|
||||
|
|
|
@ -476,11 +476,16 @@
|
|||
"RESET-TO-DEFAULT-DIALOG": {
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
},
|
||||
"PLAN-WORKFLOW": {
|
||||
"TITLE": "Plan Workflow",
|
||||
"HINT": "Configure the workflow for this tenant's plans"
|
||||
},
|
||||
"ACTIONS": {
|
||||
"SAVE": "Save",
|
||||
"UPLOAD": "Upload",
|
||||
"DOWNLOAD": "Download",
|
||||
"ADD-SOURCE": "Add Source",
|
||||
"REMOVE-SOURCE": "Remove Source",
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
}
|
||||
},
|
||||
|
@ -2522,6 +2527,23 @@
|
|||
"CONFIRM": "Confirm"
|
||||
}
|
||||
},
|
||||
"PLAN-WORKFLOW-EDITOR": {
|
||||
"ACTIONS": {
|
||||
"SELECT-PLAN-STATUS": "Select plan status",
|
||||
"ADD-STATUS-TRANSITION": "Add status transition",
|
||||
"REMOVE-STATUS-TRANSITION": "Remove status transition"
|
||||
},
|
||||
"FIELDS": {
|
||||
"STARTING-STATUS": "Starting Status",
|
||||
"STATUS-TRANSITION": "Status Transition",
|
||||
"FROM-STATUS": "From Status",
|
||||
"TO-STATUS": "To Status"
|
||||
},
|
||||
"ERRORS": {
|
||||
"DIFFERENT-STATUS": "Transition statuses must be different",
|
||||
"STATUS-TRANSITION-REQUIRED": "At least one Status transition pair must be defined"
|
||||
}
|
||||
},
|
||||
"copy": "Copy",
|
||||
"clone": "Clone",
|
||||
"new-version": "New Version"
|
||||
|
|
|
@ -476,11 +476,16 @@
|
|||
"RESET-TO-DEFAULT-DIALOG": {
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
},
|
||||
"PLAN-WORKFLOW": {
|
||||
"TITLE": "Plan Workflow",
|
||||
"HINT": "Configure the workflow for this tenant's plans"
|
||||
},
|
||||
"ACTIONS": {
|
||||
"SAVE": "Save",
|
||||
"UPLOAD": "Upload",
|
||||
"DOWNLOAD": "Download",
|
||||
"ADD-SOURCE": "Add Source",
|
||||
"REMOVE-SOURCE": "Remove Source",
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
}
|
||||
},
|
||||
|
@ -2522,6 +2527,23 @@
|
|||
"CONFIRM": "Confirm"
|
||||
}
|
||||
},
|
||||
"PLAN-WORKFLOW-EDITOR": {
|
||||
"ACTIONS": {
|
||||
"SELECT-PLAN-STATUS": "Select plan status",
|
||||
"ADD-STATUS-TRANSITION": "Add status transition",
|
||||
"REMOVE-STATUS-TRANSITION": "Remove status transition"
|
||||
},
|
||||
"FIELDS": {
|
||||
"STARTING-STATUS": "Starting Status",
|
||||
"STATUS-TRANSITION": "Status Transition",
|
||||
"FROM-STATUS": "From Status",
|
||||
"TO-STATUS": "To Status"
|
||||
},
|
||||
"ERRORS": {
|
||||
"DIFFERENT-STATUS": "Transition statuses must be different",
|
||||
"STATUS-TRANSITION-REQUIRED": "At least one Status transition pair must be defined"
|
||||
}
|
||||
},
|
||||
"copy": "Copy",
|
||||
"clone": "Clone",
|
||||
"new-version": "New Version"
|
||||
|
|
|
@ -450,6 +450,10 @@
|
|||
"TITLE": "File Transformer Plugins",
|
||||
"HINT": "Change file transformer plugins"
|
||||
},
|
||||
"PLAN-WORKFLOW": {
|
||||
"TITLE": "Plan Workflow",
|
||||
"HINT": "Configure the workflow for this tenant's plans"
|
||||
},
|
||||
"FIELDS": {
|
||||
"TIMEZONE": "Timezone",
|
||||
"CULTURE": "Format",
|
||||
|
@ -479,6 +483,7 @@
|
|||
"UPLOAD": "Upload",
|
||||
"DOWNLOAD": "Download",
|
||||
"ADD-SOURCE": "Add Source",
|
||||
"REMOVE-SOURCE": "Remove Source",
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
}
|
||||
},
|
||||
|
@ -2522,6 +2527,23 @@
|
|||
"CONFIRM": "Confirm"
|
||||
}
|
||||
},
|
||||
"PLAN-WORKFLOW-EDITOR": {
|
||||
"ACTIONS": {
|
||||
"SELECT-PLAN-STATUS": "Select plan status",
|
||||
"ADD-STATUS-TRANSITION": "Add status transition",
|
||||
"REMOVE-STATUS-TRANSITION": "Remove status transition"
|
||||
},
|
||||
"FIELDS": {
|
||||
"STARTING-STATUS": "Starting Status",
|
||||
"STATUS-TRANSITION": "Status Transition",
|
||||
"FROM-STATUS": "From Status",
|
||||
"TO-STATUS": "To Status"
|
||||
},
|
||||
"ERRORS": {
|
||||
"DIFFERENT-STATUS": "Transition statuses must be different",
|
||||
"STATUS-TRANSITION-REQUIRED": "At least one Status transition pair must be defined"
|
||||
}
|
||||
},
|
||||
"copy": "Copy",
|
||||
"clone": "Clone",
|
||||
"new-version": "New Version"
|
||||
|
|
|
@ -476,11 +476,16 @@
|
|||
"RESET-TO-DEFAULT-DIALOG": {
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
},
|
||||
"PLAN-WORKFLOW": {
|
||||
"TITLE": "Plan Workflow",
|
||||
"HINT": "Configure the workflow for this tenant's plans"
|
||||
},
|
||||
"ACTIONS": {
|
||||
"SAVE": "Save",
|
||||
"UPLOAD": "Upload",
|
||||
"DOWNLOAD": "Download",
|
||||
"ADD-SOURCE": "Add Source",
|
||||
"REMOVE-SOURCE": "Remove Source",
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
}
|
||||
},
|
||||
|
@ -2522,6 +2527,23 @@
|
|||
"CONFIRM": "Confirm"
|
||||
}
|
||||
},
|
||||
"PLAN-WORKFLOW-EDITOR": {
|
||||
"ACTIONS": {
|
||||
"SELECT-PLAN-STATUS": "Select plan status",
|
||||
"ADD-STATUS-TRANSITION": "Add status transition",
|
||||
"REMOVE-STATUS-TRANSITION": "Remove status transition"
|
||||
},
|
||||
"FIELDS": {
|
||||
"STARTING-STATUS": "Starting Status",
|
||||
"STATUS-TRANSITION": "Status Transition",
|
||||
"FROM-STATUS": "From Status",
|
||||
"TO-STATUS": "To Status"
|
||||
},
|
||||
"ERRORS": {
|
||||
"DIFFERENT-STATUS": "Transition statuses must be different",
|
||||
"STATUS-TRANSITION-REQUIRED": "At least one Status transition pair must be defined"
|
||||
}
|
||||
},
|
||||
"copy": "Copy",
|
||||
"clone": "Clone",
|
||||
"new-version": "New Version"
|
||||
|
|
|
@ -476,11 +476,16 @@
|
|||
"RESET-TO-DEFAULT-DIALOG": {
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
},
|
||||
"PLAN-WORKFLOW": {
|
||||
"TITLE": "Plan Workflow",
|
||||
"HINT": "Configure the workflow for this tenant's plans"
|
||||
},
|
||||
"ACTIONS": {
|
||||
"SAVE": "Save",
|
||||
"UPLOAD": "Upload",
|
||||
"DOWNLOAD": "Download",
|
||||
"ADD-SOURCE": "Add Source",
|
||||
"REMOVE-SOURCE": "Remove Source",
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
}
|
||||
},
|
||||
|
@ -2522,6 +2527,23 @@
|
|||
"CONFIRM": "Confirm"
|
||||
}
|
||||
},
|
||||
"PLAN-WORKFLOW-EDITOR": {
|
||||
"ACTIONS": {
|
||||
"SELECT-PLAN-STATUS": "Select plan status",
|
||||
"ADD-STATUS-TRANSITION": "Add status transition",
|
||||
"REMOVE-STATUS-TRANSITION": "Remove status transition"
|
||||
},
|
||||
"FIELDS": {
|
||||
"STARTING-STATUS": "Starting Status",
|
||||
"STATUS-TRANSITION": "Status Transition",
|
||||
"FROM-STATUS": "From Status",
|
||||
"TO-STATUS": "To Status"
|
||||
},
|
||||
"ERRORS": {
|
||||
"DIFFERENT-STATUS": "Transition statuses must be different",
|
||||
"STATUS-TRANSITION-REQUIRED": "At least one Status transition pair must be defined"
|
||||
}
|
||||
},
|
||||
"copy": "Copy",
|
||||
"clone": "Clone",
|
||||
"new-version": "New Version"
|
||||
|
|
|
@ -476,11 +476,16 @@
|
|||
"RESET-TO-DEFAULT-DIALOG": {
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
},
|
||||
"PLAN-WORKFLOW": {
|
||||
"TITLE": "Plan Workflow",
|
||||
"HINT": "Configure the workflow for this tenant's plans"
|
||||
},
|
||||
"ACTIONS": {
|
||||
"SAVE": "Save",
|
||||
"UPLOAD": "Upload",
|
||||
"DOWNLOAD": "Download",
|
||||
"ADD-SOURCE": "Add Source",
|
||||
"REMOVE-SOURCE": "Remove Source",
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
}
|
||||
},
|
||||
|
@ -2522,6 +2527,23 @@
|
|||
"CONFIRM": "Confirm"
|
||||
}
|
||||
},
|
||||
"PLAN-WORKFLOW-EDITOR": {
|
||||
"ACTIONS": {
|
||||
"SELECT-PLAN-STATUS": "Select plan status",
|
||||
"ADD-STATUS-TRANSITION": "Add status transition",
|
||||
"REMOVE-STATUS-TRANSITION": "Remove status transition"
|
||||
},
|
||||
"FIELDS": {
|
||||
"STARTING-STATUS": "Starting Status",
|
||||
"STATUS-TRANSITION": "Status Transition",
|
||||
"FROM-STATUS": "From Status",
|
||||
"TO-STATUS": "To Status"
|
||||
},
|
||||
"ERRORS": {
|
||||
"DIFFERENT-STATUS": "Transition statuses must be different",
|
||||
"STATUS-TRANSITION-REQUIRED": "At least one Status transition pair must be defined"
|
||||
}
|
||||
},
|
||||
"copy": "Copy",
|
||||
"clone": "Clone",
|
||||
"new-version": "New Version"
|
||||
|
|
|
@ -476,11 +476,16 @@
|
|||
"RESET-TO-DEFAULT-DIALOG": {
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
},
|
||||
"PLAN-WORKFLOW": {
|
||||
"TITLE": "Plan Workflow",
|
||||
"HINT": "Configure the workflow for this tenant's plans"
|
||||
},
|
||||
"ACTIONS": {
|
||||
"SAVE": "Save",
|
||||
"UPLOAD": "Upload",
|
||||
"DOWNLOAD": "Download",
|
||||
"ADD-SOURCE": "Add Source",
|
||||
"REMOVE-SOURCE": "Remove Source",
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
}
|
||||
},
|
||||
|
@ -2522,6 +2527,23 @@
|
|||
"CONFIRM": "Confirm"
|
||||
}
|
||||
},
|
||||
"PLAN-WORKFLOW-EDITOR": {
|
||||
"ACTIONS": {
|
||||
"SELECT-PLAN-STATUS": "Select plan status",
|
||||
"ADD-STATUS-TRANSITION": "Add status transition",
|
||||
"REMOVE-STATUS-TRANSITION": "Remove status transition"
|
||||
},
|
||||
"FIELDS": {
|
||||
"STARTING-STATUS": "Starting Status",
|
||||
"STATUS-TRANSITION": "Status Transition",
|
||||
"FROM-STATUS": "From Status",
|
||||
"TO-STATUS": "To Status"
|
||||
},
|
||||
"ERRORS": {
|
||||
"DIFFERENT-STATUS": "Transition statuses must be different",
|
||||
"STATUS-TRANSITION-REQUIRED": "At least one Status transition pair must be defined"
|
||||
}
|
||||
},
|
||||
"copy": "Copy",
|
||||
"clone": "Clone",
|
||||
"new-version": "New Version"
|
||||
|
|
|
@ -476,11 +476,16 @@
|
|||
"RESET-TO-DEFAULT-DIALOG": {
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
},
|
||||
"PLAN-WORKFLOW": {
|
||||
"TITLE": "Plan Workflow",
|
||||
"HINT": "Configure the workflow for this tenant's plans"
|
||||
},
|
||||
"ACTIONS": {
|
||||
"SAVE": "Save",
|
||||
"UPLOAD": "Upload",
|
||||
"DOWNLOAD": "Download",
|
||||
"ADD-SOURCE": "Add Source",
|
||||
"REMOVE-SOURCE": "Remove Source",
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
}
|
||||
},
|
||||
|
@ -2522,6 +2527,23 @@
|
|||
"CONFIRM": "Confirm"
|
||||
}
|
||||
},
|
||||
"PLAN-WORKFLOW-EDITOR": {
|
||||
"ACTIONS": {
|
||||
"SELECT-PLAN-STATUS": "Select plan status",
|
||||
"ADD-STATUS-TRANSITION": "Add status transition",
|
||||
"REMOVE-STATUS-TRANSITION": "Remove status transition"
|
||||
},
|
||||
"FIELDS": {
|
||||
"STARTING-STATUS": "Starting Status",
|
||||
"STATUS-TRANSITION": "Status Transition",
|
||||
"FROM-STATUS": "From Status",
|
||||
"TO-STATUS": "To Status"
|
||||
},
|
||||
"ERRORS": {
|
||||
"DIFFERENT-STATUS": "Transition statuses must be different",
|
||||
"STATUS-TRANSITION-REQUIRED": "At least one Status transition pair must be defined"
|
||||
}
|
||||
},
|
||||
"copy": "Copy",
|
||||
"clone": "Clone",
|
||||
"new-version": "New Version"
|
||||
|
|
|
@ -476,11 +476,16 @@
|
|||
"RESET-TO-DEFAULT-DIALOG": {
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
},
|
||||
"PLAN-WORKFLOW": {
|
||||
"TITLE": "Plan Workflow",
|
||||
"HINT": "Configure the workflow for this tenant's plans"
|
||||
},
|
||||
"ACTIONS": {
|
||||
"SAVE": "Save",
|
||||
"UPLOAD": "Upload",
|
||||
"DOWNLOAD": "Download",
|
||||
"ADD-SOURCE": "Add Source",
|
||||
"REMOVE-SOURCE": "Remove Source",
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
}
|
||||
},
|
||||
|
@ -2522,6 +2527,23 @@
|
|||
"CONFIRM": "Confirm"
|
||||
}
|
||||
},
|
||||
"PLAN-WORKFLOW-EDITOR": {
|
||||
"ACTIONS": {
|
||||
"SELECT-PLAN-STATUS": "Select plan status",
|
||||
"ADD-STATUS-TRANSITION": "Add status transition",
|
||||
"REMOVE-STATUS-TRANSITION": "Remove status transition"
|
||||
},
|
||||
"FIELDS": {
|
||||
"STARTING-STATUS": "Starting Status",
|
||||
"STATUS-TRANSITION": "Status Transition",
|
||||
"FROM-STATUS": "From Status",
|
||||
"TO-STATUS": "To Status"
|
||||
},
|
||||
"ERRORS": {
|
||||
"DIFFERENT-STATUS": "Transition statuses must be different",
|
||||
"STATUS-TRANSITION-REQUIRED": "At least one Status transition pair must be defined"
|
||||
}
|
||||
},
|
||||
"copy": "Copy",
|
||||
"clone": "Clone",
|
||||
"new-version": "New Version"
|
||||
|
|
|
@ -476,11 +476,16 @@
|
|||
"RESET-TO-DEFAULT-DIALOG": {
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
},
|
||||
"PLAN-WORKFLOW": {
|
||||
"TITLE": "Plan Workflow",
|
||||
"HINT": "Configure the workflow for this tenant's plans"
|
||||
},
|
||||
"ACTIONS": {
|
||||
"SAVE": "Save",
|
||||
"UPLOAD": "Upload",
|
||||
"DOWNLOAD": "Download",
|
||||
"ADD-SOURCE": "Add Source",
|
||||
"REMOVE-SOURCE": "Remove Source",
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
}
|
||||
},
|
||||
|
@ -2522,6 +2527,23 @@
|
|||
"CONFIRM": "Confirm"
|
||||
}
|
||||
},
|
||||
"PLAN-WORKFLOW-EDITOR": {
|
||||
"ACTIONS": {
|
||||
"SELECT-PLAN-STATUS": "Select plan status",
|
||||
"ADD-STATUS-TRANSITION": "Add status transition",
|
||||
"REMOVE-STATUS-TRANSITION": "Remove status transition"
|
||||
},
|
||||
"FIELDS": {
|
||||
"STARTING-STATUS": "Starting Status",
|
||||
"STATUS-TRANSITION": "Status Transition",
|
||||
"FROM-STATUS": "From Status",
|
||||
"TO-STATUS": "To Status"
|
||||
},
|
||||
"ERRORS": {
|
||||
"DIFFERENT-STATUS": "Transition statuses must be different",
|
||||
"STATUS-TRANSITION-REQUIRED": "At least one Status transition pair must be defined"
|
||||
}
|
||||
},
|
||||
"copy": "Copy",
|
||||
"clone": "Clone",
|
||||
"new-version": "New Version"
|
||||
|
|
|
@ -476,11 +476,16 @@
|
|||
"RESET-TO-DEFAULT-DIALOG": {
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
},
|
||||
"PLAN-WORKFLOW": {
|
||||
"TITLE": "Plan Workflow",
|
||||
"HINT": "Configure the workflow for this tenant's plans"
|
||||
},
|
||||
"ACTIONS": {
|
||||
"SAVE": "Save",
|
||||
"UPLOAD": "Upload",
|
||||
"DOWNLOAD": "Download",
|
||||
"ADD-SOURCE": "Add Source",
|
||||
"REMOVE-SOURCE": "Remove Source",
|
||||
"RESET-TO-DEFAULT": "Reset To Default"
|
||||
}
|
||||
},
|
||||
|
@ -2522,6 +2527,23 @@
|
|||
"CONFIRM": "Confirm"
|
||||
}
|
||||
},
|
||||
"PLAN-WORKFLOW-EDITOR": {
|
||||
"ACTIONS": {
|
||||
"SELECT-PLAN-STATUS": "Select plan status",
|
||||
"ADD-STATUS-TRANSITION": "Add status transition",
|
||||
"REMOVE-STATUS-TRANSITION": "Remove status transition"
|
||||
},
|
||||
"FIELDS": {
|
||||
"STARTING-STATUS": "Starting Status",
|
||||
"STATUS-TRANSITION": "Status Transition",
|
||||
"FROM-STATUS": "From Status",
|
||||
"TO-STATUS": "To Status"
|
||||
},
|
||||
"ERRORS": {
|
||||
"DIFFERENT-STATUS": "Transition statuses must be different",
|
||||
"STATUS-TRANSITION-REQUIRED": "At least one Status transition pair must be defined"
|
||||
}
|
||||
},
|
||||
"copy": "Copy",
|
||||
"clone": "Clone",
|
||||
"new-version": "New Version"
|
||||
|
|
Loading…
Reference in New Issue