Skip to content

Commit

Permalink
Closes #396 - Set from Related Record Logic
Browse files Browse the repository at this point in the history
  • Loading branch information
mpuyosa91 committed Dec 6, 2023
1 parent b11036d commit 5d0879d
Show file tree
Hide file tree
Showing 6 changed files with 445 additions and 26 deletions.
79 changes: 62 additions & 17 deletions core/app/common/src/lib/record/field.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@
* the words "Supercharged by SuiteCRM".
*/

import {SearchCriteriaFieldFilter} from '../views/list/search-criteria.model';
import {isArray, isEqual, isObject, isString, uniq} from 'lodash-es';
import {BehaviorSubject, Observable} from 'rxjs';
import {AsyncValidatorFn, FormArray, FormControl, ValidatorFn} from '@angular/forms';
import {SearchCriteriaFieldFilter} from '../views/list/search-criteria.model';
import {Record} from './record.model';
import {FieldLogicMap} from '../actions/field-logic-action.model';
import {ObjectMap} from '../types/object-map';
import {ViewMode} from '../views/view.model';
import {deepClone} from '../utils/object-utils';

export type DisplayType = 'none' | 'show' | 'readonly' | 'inline' | 'disabled' | 'default';

Expand Down Expand Up @@ -97,7 +99,7 @@ export interface FieldDefinition {
default?: string;
modes?: ViewMode[];
relationship?: string;
relationshipMetadata?: RelationshipMetadata
relationshipMetadata?: RelationshipMetadata;

[key: string]: any;
}
Expand Down Expand Up @@ -157,6 +159,16 @@ export interface AttributeDependency {
types: string[];
}

export interface FieldValue {
value?: string;
valueList?: string[];
valueObject?: any;
}

export interface FieldValueMap {
[key: string]: FieldValue;
}

export interface Field {
type: string;
value?: string;
Expand Down Expand Up @@ -232,23 +244,38 @@ export class BaseField implements Field {
}

set value(value: string) {
const changed = value !== this.valueState;
if (!isString(value)) {
this.setValue(value);
return;
}

this.valueState = value;
const valueClean: string = value.trim();

if (changed) {
this.emitValueChanges();
if (isEqual(this.valueState, valueClean)) {
return;
}

this.valueState = valueClean;
this.emitValueChanges();
}

get valueList(): string[] {
return this.valueListState;
}

set valueList(value: string[]) {
if (!isArray(value)) {
this.setValue(value);
return;
}

this.valueListState = value;
const valueListClean: string[] = uniq(deepClone(value));

if (isEqual(this.valueListState, valueListClean)) {
return;
}

this.valueListState = valueListClean;
this.emitValueChanges();
}

Expand All @@ -257,7 +284,16 @@ export class BaseField implements Field {
}

set valueObject(value: any) {
this.valueObjectState = value;
if (!isObject(value)) {
this.setValue(value);
return;
}

if (isEqual(this.valueObjectState, value)) {
return;
}

this.valueObjectState = deepClone(value);
this.emitValueChanges();
}

Expand All @@ -266,23 +302,32 @@ export class BaseField implements Field {
}

set valueObjectArray(value: ObjectMap[]) {
if (isEqual(this.valueObjectArrayState, value)) {
return;
}

this.valueObjectArrayState = value;
this.emitValueChanges();
}

protected emitValueChanges() {
public setValue(value: string | string[] | any): void {
if (isString(value)) {
this.value = value;
} else if (isArray(value)) {
this.valueList = value;
} else if (isObject(value)) {
this.valueObject = value;
} else {
this.value = value?.toString() ?? '';
}
}

protected emitValueChanges(): void {
this.valueSubject.next({
value: this.valueState,
valueList: this.valueListState,
valueObject: this.valueObjectState
})
});
}
}

export interface FieldValue {
value?: string;
valueList?: string[];
valueObject?: any;
}


3 changes: 3 additions & 0 deletions core/app/core/src/lib/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -361,11 +361,13 @@ export * from './fields/enum/templates/edit/enum.component';
export * from './fields/enum/templates/edit/enum.module';
export * from './fields/field-logic/field-logic.action';
export * from './fields/field-logic/field-logic.manager';
export * from './fields/field-logic/actionable-field-logic/actionable-field-logic.action';
export * from './fields/field-logic/currency-conversion/update-base-currency.action';
export * from './fields/field-logic/currency-conversion/update-currency.action';
export * from './fields/field-logic/display-type/display-type.action';
export * from './fields/field-logic/email-primary-select/email-primary-select.action';
export * from './fields/field-logic/required/required.action';
export * from './fields/field-logic/set-field-from-related/set-field-from-related.action';
export * from './fields/field-logic/update-flex-relate-module/update-flex-relate-module.action';
export * from './fields/file/templates/detail/file.component';
export * from './fields/file/templates/detail/file.module';
Expand Down Expand Up @@ -453,6 +455,7 @@ export * from './services/formatters/number/number-formatter.service';
export * from './services/formatters/phone/phone-formatter.service';
export * from './services/language/dynamic-label.service';
export * from './services/local-storage/local-storage.service';
export * from './services/logic/active-logic-checker.service';
export * from './services/message/message.service';
export * from './services/metadata/base-metadata.resolver';
export * from './services/metadata/base-module.resolver';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* SuiteCRM is a customer relationship management program developed by SalesAgility Ltd.
* Copyright (C) 2023 SalesAgility Ltd.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by the
* Free Software Foundation with the addition of the following permission added
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
* IN WHICH THE COPYRIGHT IS OWNED BY SALESAGILITY, SALESAGILITY DISCLAIMS THE
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* In accordance with Section 7(b) of the GNU Affero General Public License
* version 3, these Appropriate Legal Notices must retain the display of the
* "Supercharged by SuiteCRM" logo. If the display of the logos is not reasonably
* feasible for technical reasons, the Appropriate Legal Notices must display
* the words "Supercharged by SuiteCRM".
*/

import {isArray, isString} from 'lodash-es';
import {
Action,
ALL_VIEW_MODES,
Field,
Record,
} from 'common';
import { FieldLogicActionData, FieldLogicActionHandler } from '../field-logic.action';
import {ActiveLogicChecker} from '../../../services/logic/active-logic-checker.service';

export type FieldValueTypes = string | string[] | object;

export abstract class ActionableFieldLogicActionHandler extends FieldLogicActionHandler {
modes = ALL_VIEW_MODES;

protected constructor(
protected activeLogicChecker: ActiveLogicChecker,
) {
super();
}

run(data: FieldLogicActionData, action: Action): void {
const record = data.record;
const field = data.field;
if (!record || !field) {
return;
}
const params = action.params ?? {};

const logicIsActive = this.activeLogicChecker.run(record, action);

this.executeLogic(logicIsActive, params, field, record);
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
shouldDisplay(data: FieldLogicActionData): boolean {
return true;
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
executeLogic(logicIsActive: boolean, params: { [p: string]: any }, field: Field, record: Record): void {
}

protected updateValue(value: FieldValueTypes, field: Field, record: Record): void {
if (isString(value)) {
field.value = value;
} else if (isArray(value)) {
field.valueList = value;
} else {
field.valueObject = value;
}

field.formControl.setValue(value);

// re-validate the parent form-control after value update
record.formGroup.updateValueAndValidity({onlySelf: true, emitEvent: true});
}
}
25 changes: 16 additions & 9 deletions core/app/core/src/lib/fields/field-logic/field-logic.manager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* SuiteCRM is a customer relationship management program developed by SalesAgility Ltd.
* Copyright (C) 2021 SalesAgility Ltd.
* Copyright (C) 2023 SalesAgility Ltd.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by the
Expand All @@ -27,7 +27,7 @@
import {Injectable} from '@angular/core';
import {BaseActionManager} from '../../services/actions/base-action-manager.service';
import {FieldLogicActionData, FieldLogicActionHandlerMap} from './field-logic.action';
import {Action, ActionContext, ActionHandlerMap, Field, ModeActions, Record, ViewMode} from 'common';
import {Action, ActionContext, Field, ModeActions, Record, ViewMode} from 'common';
import {DisplayTypeAction} from './display-type/display-type.action';
import {EmailPrimarySelectAction} from './email-primary-select/email-primary-select.action';
import {RequiredAction} from './required/required.action';
Expand All @@ -37,7 +37,7 @@ import {UpdateFlexRelateModuleAction} from './update-flex-relate-module/update-f
import {UpdateValueAction} from './update-value/update-value.action';
import {UpdateValueBackendAction} from './update-value-backend/update-value-backend.action';
import {DisplayTypeBackendAction} from './display-type-backend/display-type-backend.action';
import {RecordActionData} from '../../views/record/actions/record.action';
import {SetFieldFromRelatedAction} from './set-field-from-related/set-field-from-related.action';

@Injectable({
providedIn: 'root'
Expand All @@ -62,7 +62,8 @@ export class FieldLogicManager extends BaseActionManager<FieldLogicActionData> {
updateValue: UpdateValueAction,
updateFlexRelateModule: UpdateFlexRelateModuleAction,
updateValueBackend: UpdateValueBackendAction,
dislayTypeBackend: DisplayTypeBackendAction
dislayTypeBackend: DisplayTypeBackendAction,
setFieldFromRelatedAction: SetFieldFromRelatedAction,
) {
super();
displayType.modes.forEach(mode => this.actions[mode][displayType.key] = displayType);
Expand All @@ -74,16 +75,18 @@ export class FieldLogicManager extends BaseActionManager<FieldLogicActionData> {
updateValue.modes.forEach(mode => this.actions[mode][updateValue.key] = updateValue);
updateValueBackend.modes.forEach(mode => this.actions[mode][updateValueBackend.key] = updateValueBackend);
dislayTypeBackend.modes.forEach(mode => this.actions[mode][dislayTypeBackend.key] = dislayTypeBackend);
setFieldFromRelatedAction.modes.forEach(mode => this.actions[mode][setFieldFromRelatedAction.key] = setFieldFromRelatedAction);
}

/**
* Run logic for the given field
* @param {object} field
* @param {object} mode
* @param {object} record
* @param triggeringStatus
*
* @param {Field} field Field
* @param {ViewMode} mode Mode
* @param {Record} record Record
* @param {string} triggeringStatus Triggering Status
*/
runLogic(field: Field, mode: ViewMode, record: Record, triggeringStatus: string = ''): void {
runLogic(field: Field, mode: ViewMode, record: Record, triggeringStatus = ''): void {
if (!field.logic) {
return;
}
Expand All @@ -104,6 +107,7 @@ export class FieldLogicManager extends BaseActionManager<FieldLogicActionData> {

/**
* Run the action using given context
*
* @param action
* @param mode
* @param context
Expand All @@ -114,6 +118,7 @@ export class FieldLogicManager extends BaseActionManager<FieldLogicActionData> {

/**
* Run front end action
*
* @param {object} action
* @param {object} mode
* @param {object} context
Expand All @@ -126,6 +131,7 @@ export class FieldLogicManager extends BaseActionManager<FieldLogicActionData> {

/**
* Get module name
*
* @param {object} context
*/
protected getModuleName(context?: ActionContext): string {
Expand All @@ -141,6 +147,7 @@ export class FieldLogicManager extends BaseActionManager<FieldLogicActionData> {

/**
* Parse mode actions
*
* @param declaredActions
* @param mode
* @param triggeringStatus
Expand Down
Loading

0 comments on commit 5d0879d

Please sign in to comment.