mirror of
https://github.com/SuiteCRM/SuiteCRM-Core.git
synced 2025-09-07 10:36:27 +08:00
Add Merge bulk action
- Add base frontend bulk action handling -- Add max min validations -- Add generic backend bulk action process call - Add front end redirect handler -- Can be re-used by several bulk actions if needed - Add MergeRecordsBulkAction.php backend handler -- Handle the the bulk action process request -- Tells front end if extra handling is needed - Fix bug list view metadata sent to the front end
This commit is contained in:
parent
8a5a002e76
commit
8881bc85f9
13 changed files with 433 additions and 23 deletions
|
@ -22,7 +22,7 @@ parameters:
|
||||||
key: merge
|
key: merge
|
||||||
labelKey: LBL_MERGE_DUPLICATES
|
labelKey: LBL_MERGE_DUPLICATES
|
||||||
params:
|
params:
|
||||||
min: 1
|
min: 2
|
||||||
max: 5
|
max: 5
|
||||||
acl:
|
acl:
|
||||||
- edit
|
- edit
|
||||||
|
|
|
@ -22,8 +22,8 @@ export interface SelectionDataSource {
|
||||||
|
|
||||||
export interface BulkActionDataSource {
|
export interface BulkActionDataSource {
|
||||||
getBulkActions(): Observable<BulkActionsMap>;
|
getBulkActions(): Observable<BulkActionsMap>;
|
||||||
|
|
||||||
executeBulkAction(action: string): void;
|
executeBulkAction(action: string): void;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BulkActionViewModel {
|
export interface BulkActionViewModel {
|
||||||
|
|
17
core/app/src/services/message/message.service.spec.mock.ts
Normal file
17
core/app/src/services/message/message.service.spec.mock.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import {MessageService} from '@services/message/message.service';
|
||||||
|
|
||||||
|
class MessageServiceSpy extends MessageService {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
addSuccessMessageByKey(labelKey: string): number {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
addDangerMessageByKey(labelKey: string): number {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const messageServiceMock = new MessageServiceSpy();
|
|
@ -14,6 +14,7 @@ export interface Process {
|
||||||
async: boolean;
|
async: boolean;
|
||||||
type: string;
|
type: string;
|
||||||
options: ProcessOptions;
|
options: ProcessOptions;
|
||||||
|
data?: ProcessOptions;
|
||||||
messages: string[];
|
messages: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,17 +37,6 @@ export class ProcessService {
|
||||||
protected graphqlName = 'process';
|
protected graphqlName = 'process';
|
||||||
protected coreName = 'Process';
|
protected coreName = 'Process';
|
||||||
|
|
||||||
protected fieldsMetadata = {
|
|
||||||
fields: [
|
|
||||||
'id',
|
|
||||||
'_id',
|
|
||||||
'status',
|
|
||||||
'async',
|
|
||||||
'type',
|
|
||||||
'options'
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
protected createFieldsMetadata = {
|
protected createFieldsMetadata = {
|
||||||
fields: [
|
fields: [
|
||||||
'_id',
|
'_id',
|
||||||
|
@ -54,6 +44,7 @@ export class ProcessService {
|
||||||
'async',
|
'async',
|
||||||
'type',
|
'type',
|
||||||
'messages',
|
'messages',
|
||||||
|
'data'
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -68,9 +59,9 @@ export class ProcessService {
|
||||||
* Submit and action/process request
|
* Submit and action/process request
|
||||||
* Returns observable
|
* Returns observable
|
||||||
*
|
*
|
||||||
* @returns Observable<any>
|
* @param {string} type to create
|
||||||
* @param type
|
* @param {object} options to send
|
||||||
* @param options
|
* @returns {object} Observable<any>
|
||||||
*/
|
*/
|
||||||
public submit(type: string, options: ProcessOptions): Observable<Process> {
|
public submit(type: string, options: ProcessOptions): Observable<Process> {
|
||||||
return this.create(type, options);
|
return this.create(type, options);
|
||||||
|
@ -84,9 +75,9 @@ export class ProcessService {
|
||||||
/**
|
/**
|
||||||
* Create a process on the backend
|
* Create a process on the backend
|
||||||
*
|
*
|
||||||
* @returns Observable<any>
|
* @param {string} type to create
|
||||||
* @param type
|
* @param {object} options to send
|
||||||
* @param options
|
* @returns {object} Observable<any>
|
||||||
*/
|
*/
|
||||||
protected create(type: string, options: ProcessOptions): Observable<Process> {
|
protected create(type: string, options: ProcessOptions): Observable<Process> {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import {RedirectBulkAction} from '@services/process/processes/bulk-action/actions/redirect/redirect.bulk-action';
|
||||||
|
import {messageServiceMock} from '@services/message/message.service.spec.mock';
|
||||||
|
import {Router} from '@angular/router';
|
||||||
|
import {TestBed} from '@angular/core/testing';
|
||||||
|
import {RouterTestingModule} from '@angular/router/testing';
|
||||||
|
|
||||||
|
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
RouterTestingModule
|
||||||
|
],
|
||||||
|
}).compileComponents().then();
|
||||||
|
|
||||||
|
const router = TestBed.get(Router); // Just if we need to test Route Service functionality
|
||||||
|
|
||||||
|
|
||||||
|
export const redirectBulkActionMock = new RedirectBulkAction(router, messageServiceMock);
|
|
@ -0,0 +1,36 @@
|
||||||
|
import {BulkActionHandler, BulkActionHandlerData} from '@services/process/processes/bulk-action/bulk-action.model';
|
||||||
|
import {Injectable} from '@angular/core';
|
||||||
|
import {Router} from '@angular/router';
|
||||||
|
import {MessageService} from '@services/message/message.service';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class RedirectBulkAction extends BulkActionHandler {
|
||||||
|
key = 'redirect';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected router: Router,
|
||||||
|
protected message: MessageService,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
run(data: BulkActionHandlerData): void {
|
||||||
|
|
||||||
|
if (!data || !data.route) {
|
||||||
|
this.message.addDangerMessageByKey('LBL_MISSING_HANDLER_DATA_ROUTE');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
queryParams: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (data.queryParams) {
|
||||||
|
params.queryParams = data.queryParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.router.navigate([data.route], params).then();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
export interface BulkActionHandlerData {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class BulkActionHandler {
|
||||||
|
abstract key: string;
|
||||||
|
|
||||||
|
abstract run(data: BulkActionHandlerData): void;
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
import {Observable, of} from 'rxjs';
|
||||||
|
import {shareReplay} from 'rxjs/operators';
|
||||||
|
import {RecordMutationGQL} from '@services/api/graphql-api/api.record.create';
|
||||||
|
import {FetchResult} from 'apollo-link';
|
||||||
|
import {ProcessService} from '@services/process/process.service';
|
||||||
|
import {appStateStoreMock} from '@store/app-state/app-state.store.spec.mock';
|
||||||
|
import {BulkActionProcess} from '@services/process/processes/bulk-action/bulk-action';
|
||||||
|
import {messageServiceMock} from '@services/message/message.service.spec.mock';
|
||||||
|
import {redirectBulkActionMock} from '@services/process/processes/bulk-action/actions/redirect/redirect.bulk-action.spec.mock';
|
||||||
|
|
||||||
|
export const bulkActionMockData = {
|
||||||
|
'bulk-merge': {
|
||||||
|
data: {
|
||||||
|
createProcess: {
|
||||||
|
process: {
|
||||||
|
_id: 'bulk-password',
|
||||||
|
status: 'success',
|
||||||
|
async: false,
|
||||||
|
type: 'bulk-password',
|
||||||
|
messages: [],
|
||||||
|
data: {}
|
||||||
|
},
|
||||||
|
clientMutationId: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class BulkActionProcessMutationGQLSpy extends RecordMutationGQL {
|
||||||
|
constructor() {
|
||||||
|
super(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
|
public create(
|
||||||
|
graphqlModuleName: string,
|
||||||
|
coreModuleName: string,
|
||||||
|
input: { [key: string]: any },
|
||||||
|
metadata: { fields: string[] }
|
||||||
|
): Observable<FetchResult<any>> {
|
||||||
|
|
||||||
|
return of(bulkActionMockData[input.options.action]).pipe(shareReplay());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eslint-enable @typescript-eslint/no-unused-vars */
|
||||||
|
}
|
||||||
|
|
||||||
|
const processServiceMock = new ProcessService(new BulkActionProcessMutationGQLSpy());
|
||||||
|
|
||||||
|
export const bulkActionProcessMock = new BulkActionProcess(
|
||||||
|
processServiceMock,
|
||||||
|
appStateStoreMock,
|
||||||
|
messageServiceMock,
|
||||||
|
redirectBulkActionMock
|
||||||
|
);
|
|
@ -0,0 +1,91 @@
|
||||||
|
import {Injectable} from '@angular/core';
|
||||||
|
import {Observable} from 'rxjs';
|
||||||
|
import {catchError, take, tap} from 'rxjs/operators';
|
||||||
|
import {Process, ProcessService} from '@services/process/process.service';
|
||||||
|
import {AppStateStore} from '@store/app-state/app-state.store';
|
||||||
|
import {SearchCriteria} from '@store/list-view/list-view.store';
|
||||||
|
import {MessageService} from '@services/message/message.service';
|
||||||
|
import {BulkActionHandler} from '@services/process/processes/bulk-action/bulk-action.model';
|
||||||
|
import {RedirectBulkAction} from '@services/process/processes/bulk-action/actions/redirect/redirect.bulk-action';
|
||||||
|
|
||||||
|
export interface BulkActionProcessInput {
|
||||||
|
action: string;
|
||||||
|
module: string;
|
||||||
|
criteria?: SearchCriteria;
|
||||||
|
ids?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class BulkActionProcess {
|
||||||
|
|
||||||
|
actions: { [key: string]: BulkActionHandler } = {};
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private processService: ProcessService,
|
||||||
|
private appStateStore: AppStateStore,
|
||||||
|
protected message: MessageService,
|
||||||
|
protected redirectActionHandler: RedirectBulkAction
|
||||||
|
) {
|
||||||
|
this.actions[redirectActionHandler.key] = redirectActionHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send bulk action request
|
||||||
|
*
|
||||||
|
* @param {string} action to submit
|
||||||
|
* @param {string} data to send
|
||||||
|
* @returns {{}} Observable<Process>
|
||||||
|
*/
|
||||||
|
public run(action: string, data: BulkActionProcessInput): Observable<Process> {
|
||||||
|
const options = {
|
||||||
|
...data
|
||||||
|
};
|
||||||
|
|
||||||
|
this.appStateStore.updateLoading(action, true);
|
||||||
|
|
||||||
|
return this.processService
|
||||||
|
.submit(action, options)
|
||||||
|
.pipe(
|
||||||
|
take(1),
|
||||||
|
tap((process: Process) => {
|
||||||
|
this.appStateStore.updateLoading(action, false);
|
||||||
|
|
||||||
|
let handler = 'addSuccessMessageByKey';
|
||||||
|
if (process.status === 'error') {
|
||||||
|
handler = 'addDangerMessageByKey';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.messages) {
|
||||||
|
process.messages.forEach(message => {
|
||||||
|
this.message[handler](message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.status === 'error') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.data && !process.data.handler) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const actionHandler: BulkActionHandler = this.actions[process.data.handler];
|
||||||
|
|
||||||
|
if (!actionHandler) {
|
||||||
|
this.message.addDangerMessageByKey('LBL_MISSING_HANDLER');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
actionHandler.run(process.data.params);
|
||||||
|
|
||||||
|
}),
|
||||||
|
catchError(err => {
|
||||||
|
this.message.addDangerMessageByKey('LBL_BULK_ACTION_ERROR');
|
||||||
|
this.appStateStore.updateLoading(action, false);
|
||||||
|
throw err;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,8 @@ import {metadataStoreMock} from '@store/metadata/metadata.store.spec.mock';
|
||||||
import {mockModuleNavigation} from '@services/navigation/module-navigation/module-navigation.service.spec.mock';
|
import {mockModuleNavigation} from '@services/navigation/module-navigation/module-navigation.service.spec.mock';
|
||||||
import {localStorageServiceMock} from '@services/local-storage/local-storage.service.spec.mock';
|
import {localStorageServiceMock} from '@services/local-storage/local-storage.service.spec.mock';
|
||||||
import {deepClone} from '@base/utils/object-utils';
|
import {deepClone} from '@base/utils/object-utils';
|
||||||
|
import {bulkActionProcessMock} from '@services/process/processes/bulk-action/bulk-action.spec.mock';
|
||||||
|
import {messageServiceMock} from '@services/message/message.service.spec.mock';
|
||||||
|
|
||||||
/* eslint-disable camelcase, @typescript-eslint/camelcase */
|
/* eslint-disable camelcase, @typescript-eslint/camelcase */
|
||||||
export const listviewMockData = {
|
export const listviewMockData = {
|
||||||
|
@ -159,7 +161,9 @@ export const listviewStoreMock = new ListViewStore(
|
||||||
navigationMock,
|
navigationMock,
|
||||||
mockModuleNavigation,
|
mockModuleNavigation,
|
||||||
metadataStoreMock,
|
metadataStoreMock,
|
||||||
localStorageServiceMock
|
localStorageServiceMock,
|
||||||
|
bulkActionProcessMock,
|
||||||
|
messageServiceMock
|
||||||
);
|
);
|
||||||
|
|
||||||
listviewStoreMock.init('accounts').pipe(take(1)).subscribe();
|
listviewStoreMock.init('accounts').pipe(take(1)).subscribe();
|
||||||
|
|
|
@ -24,6 +24,8 @@ import {ModuleNavigation} from '@services/navigation/module-navigation/module-na
|
||||||
import {ChartTypesMap, BulkActionsMap, Metadata, MetadataStore} from '@store/metadata/metadata.store.service';
|
import {ChartTypesMap, BulkActionsMap, Metadata, MetadataStore} from '@store/metadata/metadata.store.service';
|
||||||
import {LocalStorageService} from '@services/local-storage/local-storage.service';
|
import {LocalStorageService} from '@services/local-storage/local-storage.service';
|
||||||
import {SortDirection} from '@components/sort-button/sort-button.model';
|
import {SortDirection} from '@components/sort-button/sort-button.model';
|
||||||
|
import {BulkActionProcess, BulkActionProcessInput} from '@services/process/processes/bulk-action/bulk-action';
|
||||||
|
import {MessageService} from '@services/message/message.service';
|
||||||
|
|
||||||
export interface FieldMap {
|
export interface FieldMap {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
|
@ -191,7 +193,9 @@ export class ListViewStore extends ViewStore
|
||||||
protected navigationStore: NavigationStore,
|
protected navigationStore: NavigationStore,
|
||||||
protected moduleNavigation: ModuleNavigation,
|
protected moduleNavigation: ModuleNavigation,
|
||||||
protected metadataStore: MetadataStore,
|
protected metadataStore: MetadataStore,
|
||||||
protected localStorage: LocalStorageService
|
protected localStorage: LocalStorageService,
|
||||||
|
protected bulkAction: BulkActionProcess,
|
||||||
|
protected message: MessageService,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
super(appStateStore, languageStore, navigationStore, moduleNavigation, metadataStore);
|
super(appStateStore, languageStore, navigationStore, moduleNavigation, metadataStore);
|
||||||
|
@ -442,8 +446,50 @@ export class ListViewStore extends ViewStore
|
||||||
}
|
}
|
||||||
|
|
||||||
executeBulkAction(action: string): void {
|
executeBulkAction(action: string): void {
|
||||||
// To implement
|
const selection = this.internalState.selection;
|
||||||
console.log(action);
|
const definition = this.metadata.listView.bulkActions[action];
|
||||||
|
const actionName = `bulk-${action}`;
|
||||||
|
|
||||||
|
this.message.removeMessages();
|
||||||
|
|
||||||
|
if (definition.params.min && selection.count < definition.params.min) {
|
||||||
|
let message = this.appStrings.LBL_TOO_FEW_SELECTED;
|
||||||
|
message = message.replace('{min}', definition.params.min);
|
||||||
|
this.message.addDangerMessage(message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (definition.params.max && selection.count > definition.params.max) {
|
||||||
|
let message = this.appStrings.LBL_TOO_MANY_SELECTED;
|
||||||
|
message = message.replace('{max}', definition.params.max);
|
||||||
|
this.message.addDangerMessage(message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
action: actionName,
|
||||||
|
module: this.internalState.module,
|
||||||
|
criteria: null,
|
||||||
|
ids: null
|
||||||
|
} as BulkActionProcessInput;
|
||||||
|
|
||||||
|
|
||||||
|
if (selection.all && selection.count > this.internalState.records.length) {
|
||||||
|
data.criteria = this.internalState.criteria;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selection.all && selection.count <= this.internalState.records.length) {
|
||||||
|
data.ids = [];
|
||||||
|
this.internalState.records.forEach(record => {
|
||||||
|
data.ids.push(record.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selection.all) {
|
||||||
|
data.ids = Object.keys(selection.selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bulkAction.run(actionName, data).subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -60,6 +60,12 @@ class Process
|
||||||
*/
|
*/
|
||||||
protected $options;
|
protected $options;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ApiProperty
|
||||||
|
* @var array|null
|
||||||
|
*/
|
||||||
|
protected $data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Id
|
* Get Id
|
||||||
* @return string|null
|
* @return string|null
|
||||||
|
@ -186,4 +192,25 @@ class Process
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get data
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
public function getData(): ?array
|
||||||
|
{
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set data
|
||||||
|
* @param array|null $data
|
||||||
|
* @return Process
|
||||||
|
*/
|
||||||
|
public function setData(?array $data): Process
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
116
core/src/Service/BulkActions/MergeRecordsBulkAction.php
Normal file
116
core/src/Service/BulkActions/MergeRecordsBulkAction.php
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service\BulkActions;
|
||||||
|
|
||||||
|
use ApiPlatform\Core\Exception\InvalidArgumentException;
|
||||||
|
use App\Entity\Process;
|
||||||
|
use App\Service\ModuleNameMapperInterface;
|
||||||
|
use App\Service\ProcessHandlerInterface;
|
||||||
|
use Psr\Log\LoggerAwareInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
class MergeRecordsBulkAction implements ProcessHandlerInterface, LoggerAwareInterface
|
||||||
|
{
|
||||||
|
protected const MSG_OPTIONS_NOT_FOUND = 'Process options is not defined';
|
||||||
|
protected const PROCESS_TYPE = 'bulk-merge';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var LoggerInterface
|
||||||
|
*/
|
||||||
|
private $logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ModuleNameMapperInterface
|
||||||
|
*/
|
||||||
|
private $moduleNameMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MergeRecordsBulkAction constructor.
|
||||||
|
* @param ModuleNameMapperInterface $moduleNameMapper
|
||||||
|
*/
|
||||||
|
public function __construct(ModuleNameMapperInterface $moduleNameMapper)
|
||||||
|
{
|
||||||
|
$this->moduleNameMapper = $moduleNameMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getProcessType(): string
|
||||||
|
{
|
||||||
|
return self::PROCESS_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function requiredAuthRole(): string
|
||||||
|
{
|
||||||
|
return 'ROLE_USER';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function configure(Process $process): void
|
||||||
|
{
|
||||||
|
//This process is synchronous
|
||||||
|
//We aren't going to store a record on db
|
||||||
|
//thus we will use process type as the id
|
||||||
|
$process->setId(self::PROCESS_TYPE);
|
||||||
|
$process->setAsync(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function validate(Process $process): void
|
||||||
|
{
|
||||||
|
if (empty($process->getOptions())) {
|
||||||
|
throw new InvalidArgumentException(self::MSG_OPTIONS_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
$options = $process->getOptions();
|
||||||
|
|
||||||
|
if (empty($options['module']) || empty($options['action'])) {
|
||||||
|
throw new InvalidArgumentException(self::MSG_OPTIONS_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($options['ids'])) {
|
||||||
|
throw new InvalidArgumentException(self::MSG_OPTIONS_NOT_FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function run(Process $process)
|
||||||
|
{
|
||||||
|
$options = $process->getOptions();
|
||||||
|
|
||||||
|
$responseData = [
|
||||||
|
'handler' => 'redirect',
|
||||||
|
'params' => [
|
||||||
|
'route' => 'merge-records/index',
|
||||||
|
'queryParams' => [
|
||||||
|
'action_module' => $this->moduleNameMapper->toLegacy($options['module']),
|
||||||
|
'uid' => implode(',', $options['ids']),
|
||||||
|
'return_module' => $this->moduleNameMapper->toLegacy($options['module']),
|
||||||
|
'return_action' => 'index',
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$process->setStatus('success');
|
||||||
|
$process->setMessages([]);
|
||||||
|
$process->setData($responseData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function setLogger(LoggerInterface $logger): void
|
||||||
|
{
|
||||||
|
$this->logger = $logger;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue