mirror of
https://github.com/SuiteCRM/SuiteCRM-Core.git
synced 2025-09-04 10:14:13 +08:00
Add support for extra query parameters on classic view
- Update ClassicView Graphql API -- add custom query for retrieving the classic view -- add custom resolver - Add ClassicView legacy handler - Update ClassicView angular rendering -- add classic view facade -- add classic-view graphql query -- remove rest classic-view request - Update ClassicView angular resolver -- send information about extra query params - Add custom router re-use strategy -- Allow configuring if a given route should be re-used -- Disable re-usage in classic view routes
This commit is contained in:
parent
3bce817795
commit
ec5688c2e0
17 changed files with 447 additions and 131 deletions
|
@ -57,7 +57,8 @@
|
|||
"App\\DataFixtures\\": "core/src/DataFixtures/",
|
||||
"App\\DataProvider\\": "core/src/DataProvider/",
|
||||
"App\\Services\\": "core/src/Service/",
|
||||
"App\\EventListener\\": "core/src/EventListener/"
|
||||
"App\\EventListener\\": "core/src/EventListener/",
|
||||
"App\\Resolver\\": "core/src/Resolver/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
|
|
|
@ -11,3 +11,11 @@ parameters:
|
|||
modulelistmenu: modulelistmenu
|
||||
favorites: favorites
|
||||
noaccess: noaccess
|
||||
step1: step1
|
||||
composeview: compose
|
||||
wizardhome: wizard-home
|
||||
campaigndiagnostic: diagnostic
|
||||
webtoleadcreation: web-to-lead
|
||||
resourcelist: resource-list
|
||||
quick_radius: quick-radius
|
||||
|
||||
|
|
|
@ -22,77 +22,101 @@ parameters:
|
|||
frontend: notes
|
||||
core: Notes
|
||||
Leads:
|
||||
frontend: leads
|
||||
core: Leads
|
||||
frontend: leads
|
||||
core: Leads
|
||||
Contacts:
|
||||
frontend: contacts
|
||||
core: Contacts
|
||||
frontend: contacts
|
||||
core: Contacts
|
||||
Accounts:
|
||||
frontend: accounts
|
||||
core: Accounts
|
||||
frontend: accounts
|
||||
core: Accounts
|
||||
Opportunities:
|
||||
frontend: opportunities
|
||||
core: Opportunities
|
||||
frontend: opportunities
|
||||
core: Opportunities
|
||||
Import:
|
||||
frontend: import
|
||||
core: Import
|
||||
Emails:
|
||||
frontend: emails
|
||||
core: Emails
|
||||
frontend: emails
|
||||
core: Emails
|
||||
EmailTemplates:
|
||||
frontend: email-templates
|
||||
core: EmailTemplates
|
||||
frontend: email-templates
|
||||
core: EmailTemplates
|
||||
InboundEmail:
|
||||
frontend: inbound-email
|
||||
core: InboundEmail
|
||||
MailMerge:
|
||||
frontend: mail-merge
|
||||
core: MailMerge
|
||||
Schedulers:
|
||||
frontend: schedulers
|
||||
core: Schedulers
|
||||
Campaigns:
|
||||
frontend: campaigns
|
||||
core: Campaigns
|
||||
frontend: campaigns
|
||||
core: Campaigns
|
||||
Targets:
|
||||
frontend: targets
|
||||
core: Targets
|
||||
Prospects:
|
||||
frontend: prospects
|
||||
core: Prospects
|
||||
frontend: prospects
|
||||
core: Prospects
|
||||
ProspectLists:
|
||||
frontend: prospect-lists
|
||||
core: ProspectLists
|
||||
frontend: prospect-lists
|
||||
core: ProspectLists
|
||||
Documents:
|
||||
frontend: documents
|
||||
core: Documents
|
||||
frontend: documents
|
||||
core: Documents
|
||||
Cases:
|
||||
frontend: cases
|
||||
core: Cases
|
||||
frontend: cases
|
||||
core: Cases
|
||||
Project:
|
||||
frontend: project
|
||||
core: Project
|
||||
frontend: project
|
||||
core: Project
|
||||
ProjectTask:
|
||||
frontend: project-task
|
||||
core: ProjectTask
|
||||
Bugs:
|
||||
frontend: bugs
|
||||
core: Bugs
|
||||
frontend: bugs
|
||||
core: Bugs
|
||||
ResourceCalendar:
|
||||
frontend: resource-calendar
|
||||
core: ResourceCalendar
|
||||
frontend: resource-calendar
|
||||
core: ResourceCalendar
|
||||
AOBH_BusinessHours:
|
||||
frontend: business-hours
|
||||
core: BusinessHours
|
||||
frontend: business-hours
|
||||
core: BusinessHours
|
||||
Spots:
|
||||
frontend: spots
|
||||
core: Spots
|
||||
frontend: spots
|
||||
core: Spots
|
||||
SecurityGroups:
|
||||
frontend: security-groups
|
||||
core: SecurityGroups
|
||||
frontend: security-groups
|
||||
core: SecurityGroups
|
||||
ACL:
|
||||
frontend: acl
|
||||
core: ACL
|
||||
frontend: acl
|
||||
core: ACL
|
||||
ACLRoles:
|
||||
frontend: acl-roles
|
||||
core: ACLRoles
|
||||
frontend: acl-roles
|
||||
core: ACLRoles
|
||||
Roles:
|
||||
frontend: roles
|
||||
core: Roles
|
||||
Configurator:
|
||||
frontend: configurator
|
||||
core: Configurator
|
||||
frontend: configurator
|
||||
core: Configurator
|
||||
UserPreferences:
|
||||
frontend: user-preferences
|
||||
core: UserPreferences
|
||||
frontend: user-preferences
|
||||
core: UserPreferences
|
||||
Users:
|
||||
frontend: users
|
||||
core: Users
|
||||
SavedSearch:
|
||||
frontend: saved-search
|
||||
core: SavedSearch
|
||||
frontend: saved-search
|
||||
core: SavedSearch
|
||||
Studio:
|
||||
frontend: studio
|
||||
core: Studio
|
||||
frontend: studio
|
||||
core: Studio
|
||||
Connectors:
|
||||
frontend: connectors
|
||||
core: Connectors
|
||||
frontend: connectors
|
||||
core: Connectors
|
||||
SugarFeed:
|
||||
frontend: sugar-feed
|
||||
core: SugarFeed
|
||||
|
@ -154,8 +178,8 @@ parameters:
|
|||
frontend: events
|
||||
core: Events
|
||||
FP_Event_Locations:
|
||||
frontend: event-Locations
|
||||
core: EventLocations
|
||||
frontend: event-locations
|
||||
core: EventLocations
|
||||
AOS_Contracts:
|
||||
frontend: contracts
|
||||
core: Contracts
|
||||
|
@ -220,14 +244,17 @@ parameters:
|
|||
frontend: report-conditions
|
||||
core: ReportConditions
|
||||
AOW_WorkFlow:
|
||||
frontend: workFlow
|
||||
core: WorkFlow
|
||||
frontend: workflow
|
||||
core: Workflow
|
||||
AOW_Actions:
|
||||
frontend: workflow-actions
|
||||
core: WorkflowActions
|
||||
frontend: workflow-actions
|
||||
core: WorkflowActions
|
||||
AOW_Processed:
|
||||
frontend: workflow-processed
|
||||
core: WorflowProcessed
|
||||
frontend: workflow-processed
|
||||
core: WorflowProcessed
|
||||
AOW_Conditions:
|
||||
frontend: workflow-conditions
|
||||
core: WorkflowConditions
|
||||
frontend: workflow-conditions
|
||||
core: WorkflowConditions
|
||||
Help:
|
||||
frontend: help
|
||||
core: Help
|
||||
|
|
26
core/app/src/app/app-router-reuse-strategy.ts
Normal file
26
core/app/src/app/app-router-reuse-strategy.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import {ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy} from '@angular/router';
|
||||
|
||||
export class AppRouteReuseStrategy implements RouteReuseStrategy {
|
||||
|
||||
shouldDetach(route: ActivatedRouteSnapshot): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void {
|
||||
}
|
||||
|
||||
shouldAttach(route: ActivatedRouteSnapshot): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
|
||||
if (future.data && future.data.reuseRoute === false) {
|
||||
return false;
|
||||
}
|
||||
return future.routeConfig === curr.routeConfig;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {Routes, RouterModule} from '@angular/router';
|
||||
import {ClassicViewUiComponent} from '@components/classic-view/classic-view.component';
|
||||
import {ClassicViewResolver} from '@services/api/resolvers/classic-view.resolver';
|
||||
import {ClassicViewResolver} from '@services/classic-view/classic-view.resolver';
|
||||
import {BaseMetadataResolver} from '@services/metadata/base-metadata.resolver';
|
||||
import {AuthGuard} from '../services/auth/auth-guard.service';
|
||||
import {ListComponent} from '@views/list/list.component';
|
||||
|
@ -25,19 +25,31 @@ const routes: Routes = [
|
|||
path: ':module',
|
||||
component: ClassicViewUiComponent,
|
||||
canActivate: [AuthGuard],
|
||||
resolve: {view: ClassicViewResolver}
|
||||
runGuardsAndResolvers: 'always',
|
||||
resolve: {view: ClassicViewResolver},
|
||||
data: {
|
||||
reuseRoute: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: ':module/:action',
|
||||
component: ClassicViewUiComponent,
|
||||
canActivate: [AuthGuard],
|
||||
resolve: {view: ClassicViewResolver}
|
||||
runGuardsAndResolvers: 'always',
|
||||
resolve: {view: ClassicViewResolver},
|
||||
data: {
|
||||
reuseRoute: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: ':module/:action/:record',
|
||||
component: ClassicViewUiComponent,
|
||||
canActivate: [AuthGuard],
|
||||
resolve: {view: ClassicViewResolver}
|
||||
runGuardsAndResolvers: 'always',
|
||||
resolve: {view: ClassicViewResolver},
|
||||
data: {
|
||||
reuseRoute: false
|
||||
}
|
||||
},
|
||||
{path: '**', redirectTo: 'Login'},
|
||||
];
|
||||
|
|
|
@ -31,6 +31,8 @@ import {
|
|||
import {environment} from '../environments/environment';
|
||||
import {FetchPolicy} from 'apollo-client/core/watchQueryOptions';
|
||||
import {FullPageSpinnerComponent} from '@components/full-page-spinner/full-page-spinner.component';
|
||||
import {RouteReuseStrategy} from '@angular/router';
|
||||
import {AppRouteReuseStrategy} from './app-router-reuse-strategy';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -60,6 +62,9 @@ import {FullPageSpinnerComponent} from '@components/full-page-spinner/full-page-
|
|||
BrowserAnimationsModule,
|
||||
NgbModule
|
||||
],
|
||||
providers: [
|
||||
{provide: RouteReuseStrategy, useClass: AppRouteReuseStrategy}
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
entryComponents: []
|
||||
})
|
||||
|
|
|
@ -6,6 +6,8 @@ import {HttpClientTestingModule, HttpTestingController} from '@angular/common/ht
|
|||
|
||||
import {LoginUiComponent} from './login.component';
|
||||
import {ApiService} from '../../services/api/api.service';
|
||||
import {ApolloTestingModule} from 'apollo-angular/testing';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
|
||||
describe('LoginComponent', () => {
|
||||
let component: LoginUiComponent;
|
||||
|
@ -14,7 +16,13 @@ describe('LoginComponent', () => {
|
|||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
imports: [RouterTestingModule, HttpClientTestingModule, FormsModule],
|
||||
imports: [
|
||||
RouterTestingModule,
|
||||
HttpClientTestingModule,
|
||||
FormsModule,
|
||||
ApolloTestingModule,
|
||||
BrowserAnimationsModule
|
||||
],
|
||||
declarations: [LoginUiComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
|
|
@ -278,31 +278,4 @@ export class ApiService {
|
|||
): boolean {
|
||||
return this.request({type: 'GET', url}, onSuccess, onError);
|
||||
}
|
||||
|
||||
getClassicView(routeParams: ParamMap): Observable<any> {
|
||||
|
||||
let url = API_URL
|
||||
let module = routeParams.get('module') || '';
|
||||
url += '/classic-views/' + module;
|
||||
|
||||
let params = new HttpParams();
|
||||
routeParams.keys.forEach((name) => {
|
||||
let value = routeParams.get(name);
|
||||
|
||||
if (name = 'module'){
|
||||
return;
|
||||
}
|
||||
|
||||
if (value == null || value == undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
params = params.set(name, value);
|
||||
});
|
||||
|
||||
return this.http.get(url, {
|
||||
params: params
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
import {Injectable} from '@angular/core';
|
||||
import {
|
||||
Resolve,
|
||||
ActivatedRouteSnapshot,
|
||||
RouterStateSnapshot
|
||||
} from '@angular/router';
|
||||
|
||||
|
||||
import {ApiService} from "../api.service";
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class ClassicViewResolver implements Resolve<any> {
|
||||
|
||||
constructor(private apiService: ApiService) {
|
||||
}
|
||||
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
|
||||
return this.apiService.getClassicView(route.paramMap);
|
||||
}
|
||||
}
|
45
core/app/src/services/classic-view/api.classic-view.get.ts
Normal file
45
core/app/src/services/classic-view/api.classic-view.get.ts
Normal file
|
@ -0,0 +1,45 @@
|
|||
import {Injectable} from '@angular/core';
|
||||
import {Apollo} from 'apollo-angular';
|
||||
import gql from 'graphql-tag';
|
||||
import {Observable} from 'rxjs';
|
||||
import {ApolloQueryResult} from 'apollo-client';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ClassicViewGQL {
|
||||
|
||||
constructor(private apollo: Apollo) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch data either from backend
|
||||
*
|
||||
* @param module to get from
|
||||
* @param id of the record
|
||||
* @param params
|
||||
* @param metadata with the fields to ask for
|
||||
*/
|
||||
public fetch(module: string,
|
||||
params: { [key: string]: string },
|
||||
metadata: { fields: string[] }): Observable<ApolloQueryResult<any>> {
|
||||
|
||||
const fields = metadata.fields;
|
||||
|
||||
const queryOptions = {
|
||||
query: gql`
|
||||
query getClassicView($module: String!, $params: Iterable) {
|
||||
getClassicView(module:$module, params:$params) {
|
||||
${fields.join('\n')}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
module,
|
||||
params
|
||||
},
|
||||
};
|
||||
|
||||
return this.apollo.query(queryOptions);
|
||||
}
|
||||
}
|
77
core/app/src/services/classic-view/classic-view.facade.ts
Normal file
77
core/app/src/services/classic-view/classic-view.facade.ts
Normal file
|
@ -0,0 +1,77 @@
|
|||
import {Injectable} from '@angular/core';
|
||||
import {Observable} from 'rxjs';
|
||||
import {map} from 'rxjs/operators';
|
||||
|
||||
import {ClassicViewGQL} from './api.classic-view.get';
|
||||
|
||||
export interface ClassicView {
|
||||
id: string;
|
||||
_id: string;
|
||||
action: string;
|
||||
record: string;
|
||||
html: string;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ClassicViewFacade {
|
||||
|
||||
protected fieldsMetadata = {
|
||||
fields: [
|
||||
'id',
|
||||
'_id',
|
||||
'action',
|
||||
'record',
|
||||
'html'
|
||||
]
|
||||
};
|
||||
|
||||
constructor(private classicViewGQL: ClassicViewGQL) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Public Api
|
||||
*/
|
||||
|
||||
/**
|
||||
* Load ClassicView from the backend.
|
||||
* Returns observable to be used in resolver if needed
|
||||
*
|
||||
* @returns Observable<any>
|
||||
*/
|
||||
public load($module: string, $params: { [key: string]: string }): Observable<any> {
|
||||
return this.fetch($module, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal API
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Fetch the classic view from the backend
|
||||
*
|
||||
* @returns Observable<any>
|
||||
*/
|
||||
protected fetch($module: string, $params: { [key: string]: string }): Observable<ClassicView> {
|
||||
|
||||
return this.classicViewGQL.fetch($module, $params, this.fieldsMetadata)
|
||||
.pipe(map(({data}) => {
|
||||
const classicView: ClassicView = {
|
||||
id: null,
|
||||
_id: null,
|
||||
action: null,
|
||||
record: null,
|
||||
html: null,
|
||||
};
|
||||
|
||||
if (data.getClassicView) {
|
||||
return data.getClassicView;
|
||||
}
|
||||
|
||||
return classicView;
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
33
core/app/src/services/classic-view/classic-view.resolver.ts
Normal file
33
core/app/src/services/classic-view/classic-view.resolver.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import {Injectable} from '@angular/core';
|
||||
import {
|
||||
Resolve,
|
||||
ActivatedRouteSnapshot,
|
||||
RouterStateSnapshot
|
||||
} from '@angular/router';
|
||||
|
||||
|
||||
import {ClassicViewFacade} from '@services/classic-view/classic-view.facade';
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class ClassicViewResolver implements Resolve<any> {
|
||||
|
||||
constructor(private classicViewFacade: ClassicViewFacade) {
|
||||
}
|
||||
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
|
||||
const params = {
|
||||
...route.queryParams
|
||||
}
|
||||
|
||||
if (route.params.action) {
|
||||
params.action = route.params.action;
|
||||
}
|
||||
|
||||
if (route.params.record) {
|
||||
params.record = route.params.record;
|
||||
}
|
||||
|
||||
return this.classicViewFacade.load(route.params.module, params);
|
||||
}
|
||||
}
|
40
core/legacy/ClassicViewHandler.php
Normal file
40
core/legacy/ClassicViewHandler.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace SuiteCRM\Core\Legacy;
|
||||
|
||||
use App\Entity\ClassicView;
|
||||
|
||||
class ClassicViewHandler extends LegacyHandler
|
||||
{
|
||||
|
||||
/**
|
||||
* Get app strings for given $language
|
||||
* @param string $module
|
||||
* @param array $params
|
||||
* @return ClassicView|null
|
||||
*/
|
||||
public function getClassicView(string $module, array $params): ?ClassicView
|
||||
{
|
||||
$output = new ClassicView();
|
||||
$output->setId('123');
|
||||
|
||||
$html = '<h1>HTML working</h1><script>alert(\'JS Working\');</script><button onClick="alert(\'JS Working\');">Click Me</button>';
|
||||
$html .= '<br/><a href="index.php?module=Contacts&action=ListView">Legacy Link to Contacts List View</a>';
|
||||
$html .= '<br/><strong>Legacy folder Image:</strong>';
|
||||
$html .= '<img src="themes/default/images/company_logo.png" alt="SuiteCRM" style="margin: 5px 0;">';
|
||||
$html .= '<br/><strong>Legacy Link with extra params: </strong>' . '<a href="index.php?module=Import&action=Step1&import_module=Accounts&return_module=Accounts&return_action=index">Legacy Link to Accounts Import</a>';
|
||||
$html .= '<br/><strong>Received Params:</strong>';
|
||||
$html .= '<br/><ul><li><strong>Module: </strong> "' . $module . '"</li>';
|
||||
if (!empty($params)) {
|
||||
foreach ($params as $key => $value) {
|
||||
$html .= '<li><strong>' . $key . '</strong> "' . $value . '"</li>';
|
||||
}
|
||||
}
|
||||
$html .= '</ul>';
|
||||
|
||||
$output->setHtml($html);
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ namespace App\DataProvider;
|
|||
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
|
||||
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
|
||||
use App\Entity\ClassicView;
|
||||
use SuiteCRM\Core\Legacy\ClassicViewHandler;
|
||||
|
||||
/**
|
||||
* Class ClassicViewItemDataProvider
|
||||
|
@ -12,6 +13,21 @@ use App\Entity\ClassicView;
|
|||
*/
|
||||
final class ClassicViewItemDataProvider implements ItemDataProviderInterface, RestrictedDataProviderInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @var ClassicViewHandler
|
||||
*/
|
||||
private $classicViewHandler;
|
||||
|
||||
/**
|
||||
* ClassicViewItemDataProvider constructor.
|
||||
* @param ClassicViewHandler $classicViewHandler
|
||||
*/
|
||||
public function __construct(ClassicViewHandler $classicViewHandler)
|
||||
{
|
||||
$this->classicViewHandler = $classicViewHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defined supported resources
|
||||
* @param string $resourceClass
|
||||
|
@ -34,15 +50,11 @@ final class ClassicViewItemDataProvider implements ItemDataProviderInterface, Re
|
|||
*/
|
||||
public function getItem(string $resourceClass, $id, string $operationName = null, array $context = []): ?ClassicView
|
||||
{
|
||||
$output = new ClassicView();
|
||||
$output->setId('123');
|
||||
$params = [];
|
||||
if (!empty($context['args']) && !empty($context['args']['params'])) {
|
||||
$params = $context['args']['params'];
|
||||
}
|
||||
|
||||
$html = '<h1>HTML working</h1><script>alert(\'JS Working\');</script><button onClick="alert(\'JS Working\');">Click Me</button>';
|
||||
$html .= '<br/><a href="index.php?module=Contacts&action=ListView">Legacy Link to Contacts List View</a>';
|
||||
$html .= '<br/><strong>Legacy folder Image:</strong>';
|
||||
$html .= '<img src="themes/default/images/company_logo.png" alt="SuiteCRM" style="margin: 5px 0;">';
|
||||
$output->setHtml($html);
|
||||
|
||||
return $output;
|
||||
return $this->classicViewHandler->getClassicView($id, $params);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ namespace App\Entity;
|
|||
|
||||
use ApiPlatform\Core\Annotation\ApiProperty;
|
||||
use ApiPlatform\Core\Annotation\ApiResource;
|
||||
use App\Resolver\ClassicViewResolver;
|
||||
|
||||
/**
|
||||
* @ApiResource(
|
||||
|
@ -39,6 +40,15 @@ use ApiPlatform\Core\Annotation\ApiResource;
|
|||
* },
|
||||
* collectionOperations={
|
||||
* },
|
||||
* graphql={
|
||||
* "get"={
|
||||
* "item_query"=ClassicViewResolver::class,
|
||||
* "args"={
|
||||
* "module"={"type"="String!"},
|
||||
* "params"={"type"="Iterable" , "description"="legacy query params list"}
|
||||
* }
|
||||
* },
|
||||
* },
|
||||
* )
|
||||
*/
|
||||
class ClassicView
|
||||
|
@ -66,7 +76,7 @@ class ClassicView
|
|||
/**
|
||||
* The action
|
||||
*
|
||||
* @var string
|
||||
* @var string|null
|
||||
*
|
||||
* @ApiProperty(
|
||||
* attributes={
|
||||
|
@ -78,12 +88,12 @@ class ClassicView
|
|||
* }
|
||||
* )
|
||||
*/
|
||||
protected $action;
|
||||
protected $action = null;
|
||||
|
||||
/**
|
||||
* The record.
|
||||
*
|
||||
* @var string
|
||||
* @var string|null
|
||||
*
|
||||
* @ApiProperty(
|
||||
* attributes={
|
||||
|
@ -94,7 +104,7 @@ class ClassicView
|
|||
* }
|
||||
* )
|
||||
*/
|
||||
protected $record;
|
||||
protected $record = null;
|
||||
|
||||
/**
|
||||
* The view html.
|
||||
|
@ -132,9 +142,9 @@ class ClassicView
|
|||
|
||||
/**
|
||||
* Set Action
|
||||
* @param string $action
|
||||
* @param string|null $action
|
||||
*/
|
||||
public function setAction(string $action): void
|
||||
public function setAction(?string $action): void
|
||||
{
|
||||
$this->action = $action;
|
||||
}
|
||||
|
@ -150,9 +160,9 @@ class ClassicView
|
|||
|
||||
/**
|
||||
* Set Record
|
||||
* @param string $record
|
||||
* @param string|null $record
|
||||
*/
|
||||
public function setRecord(string $record): void
|
||||
public function setRecord(?string $record): void
|
||||
{
|
||||
$this->record = $record;
|
||||
}
|
||||
|
|
36
core/src/Resolver/ClassicViewResolver.php
Normal file
36
core/src/Resolver/ClassicViewResolver.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace App\Resolver;
|
||||
|
||||
use ApiPlatform\Core\GraphQl\Resolver\QueryItemResolverInterface;
|
||||
use App\Entity\ClassicView;
|
||||
use SuiteCRM\Core\Legacy\ClassicViewHandler;
|
||||
|
||||
class ClassicViewResolver implements QueryItemResolverInterface
|
||||
{
|
||||
/**
|
||||
* @var ClassicViewHandler
|
||||
*/
|
||||
private $classicViewHandler;
|
||||
|
||||
/**
|
||||
* ClassicViewResolver constructor.
|
||||
* @param ClassicViewHandler $classicViewHandler
|
||||
*/
|
||||
public function __construct(ClassicViewHandler $classicViewHandler)
|
||||
{
|
||||
$this->classicViewHandler = $classicViewHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassicView|null $item
|
||||
*
|
||||
* @param array $context
|
||||
* @return ClassicView
|
||||
*/
|
||||
public function __invoke($item, array $context)
|
||||
{
|
||||
return $this->classicViewHandler->getClassicView($context['args']['module'], $context['args']['params']);
|
||||
}
|
||||
}
|
|
@ -76,11 +76,20 @@ class RouteConverter
|
|||
$action = $request->query->get('action');
|
||||
$record = $request->query->get('record');
|
||||
|
||||
if (empty($module)){
|
||||
if (empty($module)) {
|
||||
throw new InvalidArgumentException('No module defined');
|
||||
}
|
||||
|
||||
return $this->buildRoute($module, $action, $record);
|
||||
$route = $this->buildRoute($module, $action, $record);
|
||||
|
||||
if (null !== $queryString = $request->getQueryString()) {
|
||||
$queryString = $this->removeParameter($queryString, 'module', $module);
|
||||
$queryString = $this->removeParameter($queryString, 'action', $action);
|
||||
$queryString = $this->removeParameter($queryString, 'record', $record);
|
||||
$queryString = '?' . Request::normalizeQueryString($queryString);
|
||||
}
|
||||
|
||||
return $route . $queryString;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -159,4 +168,19 @@ class RouteConverter
|
|||
{
|
||||
return $this->moduleNameMapper->toFrontEnd($module);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $queryString
|
||||
* @param string|null $param
|
||||
* @param string|null $value
|
||||
* @return string|string[]|null
|
||||
*/
|
||||
protected function removeParameter(?string $queryString, ?string $param, ?string $value)
|
||||
{
|
||||
if (empty($value) || empty($param) || empty($queryString)) {
|
||||
return $queryString;
|
||||
}
|
||||
|
||||
return str_replace("$param=$value", '', $queryString);;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue