Rendering a custom view in Suite8 mode

Hello. Is it possible to render a custom view in Suite8 mode? I already created a custom view/action, it works and it is accessible via #/module/customAction URL but I noticed that it’s rendered in a classic mode - view is displayed in an iframe. I naively tried to add my custom action to the module_routing.yaml file with ‘true’ parameter value but it doesn’t work.

I am new to SuiteCRM 8.8 but I have many years of experience in good, old SugarCRM 5.2.0 :)))

Any help is appreciated!

Can you please try adding an entry for your module in $module_name_map and $action_name_map arrays for the custom module. I think we can check the portability(legacy to suite8) code at public/legacy/include/portability/module_name_map.php etc.

Hello Harshad. Thank you for your reply. I didn’t mention that I’m creating a custom view for Cases module so I guess that I should only add an entry to the $action_name_map array. I tried that, I even did it in an upgrade-safe way, it looks like SuiteCRM is properly reading my changes but the view is still rendered in a legacy mode. I am able to make an “alias” for my custom action, I can access my action through the name that I define in the $action_name_map array but it’s still rendered using an iframe. I will appreciate any further help!

You can find a file for legacy.module_routing at the below location.

config/services/module/module_routing.yaml

You can change the module to legacy by setting it to false.


   contacts:
      index: true // true means suite 8 view
      list: true
      record: false // false means classic view

salesagility/SuiteCRM-Core/blob/hotfix/config/services/module/module_routing.yaml

parameters:
  legacy.module_routing:
    home:
      index: false
      list: false
      record: false
    saved-search:
      index: true
      list: true
      record: false
    calls-reschedule:
      index: true
      list: true
      record: false
    calls:
      index: true
      list: true
      record: false
    tasks:
      index: true

Hi Jarek, I don’t know if the following helps you, but this will help to create a custom page just like the login page. Sharing here to get the feedback.

I have created a custom page that says just ‘hello’. The following steps helped me to achieve to add a custom page in suite8.

1.Create a new component called ‘hello’ at
extensions/defaultExt/app/src/views/custom/components/hello/hello.component.ts

import {Component, OnInit} from '@angular/core';
import {Router} from '@angular/router';

@Component({
    selector: 'scrm-test-ui',
    templateUrl: './hello.component.html',
    styleUrls: [],
})
export class HelloUiComponent implements OnInit {
    name:string = 'Harshad';
	constructor(protected router: Router) {
    }
    ngOnInit() {
		console.log('test init');
    } 
}

  1. Create the HTML UI code at
    extensions/defaultExt/app/src/views/custom/components/hello/hello.component.html
<div style="padding-top: 4rem;">
	Hello {{ name }}
</div>

  1. Create the hello module file to include the hello component at
    extensions/defaultExt/app/src/views/custom/components/hello/hello.module.ts
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {FormsModule} from '@angular/forms';
import {RouterModule} from '@angular/router';
import {HelloUiComponent} from './hello.component';

@NgModule({
    declarations: [
        HelloUiComponent
    ],
    exports: [
        HelloUiComponent
    ],
    imports: [
        FormsModule,
        CommonModule,
    ]
})
export class HelloUiModule {
}
  1. Add hello guard service at extensions/defaultExt/app/src/services/custom/hello-guard.service.ts
import {Injectable} from '@angular/core';
import {Router, UrlTree} from '@angular/router';
import {Observable, of} from 'rxjs';
import {catchError, map, take} from 'rxjs/operators';
import {AuthService, SessionStatus,SystemConfigStore,AppStateStore} from 'core';

@Injectable({
    providedIn: 'root'
})
export class HelloGuard  {
    constructor(
        protected router: Router,
        private authService: AuthService,
        protected systemConfigStore: SystemConfigStore,
        protected appStateStore: AppStateStore
    ) {
    }

    canActivate(): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
		return true;
    }
}
  1. Add the above component and guard service to config the router for the ‘hello’ page at
    extensions\defaultExt\app\src\extension.module.ts
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {provideHttpClient, withInterceptorsFromDi} from '@angular/common/http';

import {Route, Router} from '@angular/router';
import {BaseMetadataResolver,AuthGuard,SystemConfigStore} from 'core'; 
import {HelloUiComponent} from './views/custom/components/hello/hello.component';
import {HelloUiModule} from './views/custom/components/hello/hello.module';
import {HelloGuard} from './services/custom/hello-guard.service';

@NgModule({ declarations: [], imports: [CommonModule], providers: [provideHttpClient(withInterceptorsFromDi())] })
export class ExtensionModule {
    constructor(private router: Router, protected systemConfigStore: SystemConfigStore,) {
		console.log('extension module enabled');
		
		  const routes = this.router.config;
		  const configRoutes = this.systemConfigStore.getConfigValue('module_routing'); 
		  console.log(configRoutes.length);
		  routes.push({
			path: 'hello',
			component: HelloUiComponent,
			runGuardsAndResolvers: 'always',
			canActivate: [HelloGuard],
			resolve: {
				metadata: BaseMetadataResolver
			},
			data: {
				reuseRoute: false,
				load: {
					navigation: false,
					preferences: false,
					languageStrings: ['appStrings']
				}
			}		
		 });
		 console.log(routes.length);
    }
    init(): void {
    }
}
  1. Enable the extension at extensions\defaultExt\config\extension.php

    'enabled' => true,

  2. Run php bin/console cache:clear

  3. Run the following command to test the UI Angular Code
    yarn run build-dev:extension defaultExt –watch

  4. Reload the page (Control + F5)

  5. Change URL in the address bar
    image

Please let me know your feedback or suggestions. Thanks!

1 Like

Hello Harshad. First of all, I apologize for a delayed response - I’ve been busy with my old SugarCRM development over last 2 days.

I am very grateful to you for taking the time to give me such a comprehensive answer. I expected that I would need to write the code in Angular but I didn’t know where to start. Your solution works fine, thank you! I have what I wanted, a custom view in Suite8 mode.

I have one piece of advice for beginners like me. If you have never built a frontend extension before, you will not be able to run the following command:

yarn run build-dev:extension defaultExt

because you will receive the error saying:
Error: This command is not available when running the Angular CLI outside a workspace.

It’s because the angular.json file is missing in the root directory of SuiteCRM. I had to generate the angular.json file using the following command:

yarn merge-angular-json

This procedure is explained here: Frontend extension - Migrate to SuiteCRM 8.8+ :: SuiteCRM Documentation

To sum up, it’s high time to start learning Angular :slight_smile:.

I think that in the next step I will need the ability to save the data from my custom component to the database. Is there any good documentation illustrating database connection / inserting/updating a SuiteCRM module record from Angular component?