Add Field App

The field app is for the users. It’s the interface designed for mobile devices.

The field app is known as the “frontend” in web terminology. The backend for the field app is the field service.

The Peek field app is built with an Angular web build.

In this document, we’ll add the start of both the field and office builds for the plugin.

We only scratch the surface of using Angular, that`s outside the scope of this guide.

See Developing With The Frontends to learn more about how Peek pieces together the frontend code from the various plugins.

Field App File Structure

Add Directory field

The field directory will contain the plugins the field Angular application requires.

Angular “Lazy Loads” this part of the plugin, meaning it only loads it when the user navigates to the page, and unloads it when it’s finished.

This allows large, single page web applications to be made. Anything related to the user interface should be lazy loaded.


Create directory peek_plugin_tutorial/_private/field

Create an empty package file in the field directory, peek_plugin_tutorial/_private/field/__init__.py

Commands:

mkdir peek_plugin_tutorial/_private/field
touch peek_plugin_tutorial/_private/field/__init__.py

Add File tutorial.component.mweb.html

The tutorial.component.mweb.html file is the web app HTML view for the Angular component tutorial.component.ts.

This is standard HTML that is compiled by Angular. Angular compiles the HTML, looking for Angular directives, and alters it in place in the browser.

For more information about Angular directives, See:


Create the file peek_plugin_tutorial/_private/field/tutorial.component.mweb.html and populate it with the following contents.

<div class="container">
    <h1 class="text-center">Tutorial Plugin</h1>
    <p>Angular2 Lazy Loaded Module</p>
    <p>This is the root of the field app for the Tutorial plugin</p>
</div>

Add File tutorial.component.ts

The tutorial.component.ts is the Angular Component for the field app page. It’s loaded by the default route defined in tutorial.module.ts.

Note

The one Angular component drives both the Capacitor and Web app views. More on this later.


Create the file peek_plugin_tutorial/_private/field/tutorial.component.ts and populate it with the following contents.

import {Component} from "@angular/core";

@Component({
    selector: 'plugin-tutorial',
    templateUrl: 'tutorial.component.mweb.html',
    moduleId: module.id
})
export class TutorialComponent {

    constructor() {

    }

}

Add File tutorial.module.ts

The tutorial.module.ts is the main Angular module of the plugin.

This file can describe other routes, that will load other components. This is standard Angular.

See NgModule for more


Create the file peek_plugin_tutorial/_private/field/tutorial.module.ts and populate it with the following contents.

import {CommonModule} from "@angular/common";
import {NgModule} from "@angular/core";
import {Routes} from "@angular/router";

import { PeekModuleFactory } from "@synerty/peek-plugin-base-js"

// Import the default route component
import {TutorialComponent} from "./tutorial.component";


// Define the child routes for this plugin
export const pluginRoutes: Routes = [
    {
        path: '',
        pathMatch:'full',
        component: TutorialComponent
    }

];

// Define the root module for this plugin.
// This module is loaded by the lazy loader, what ever this defines is what is started.
// When it first loads, it will look up the routs and then select the component to load.
@NgModule({
    imports: [
        CommonModule,
        PeekModuleFactory.RouterModule,
        PeekModuleFactory.RouterModule.forChild(pluginRoutes),
        ...PeekModuleFactory.FormsModules
    ],
    exports: [],
    providers: [],
    declarations: [TutorialComponent]
})
export class TutorialModule
{
}

Download Icon icon.png

The Peek field interface has a home screen with apps on it, this icon will be the tutorial plugins app icon.

../../_images/TutorialExampleIcon.png

Create directory peek_plugin_tutorial/_private/field-assets


Download this plugin app icon TutorialExampleIcon.png to peek_plugin_tutorial/_private/field-assets/icon.png

Edit File plugin_package.json

Finally, Edit the file peek_plugin_tutorial/plugin_package.json to tell the platform that we want to use the field service:

  1. Add “field” to the requiresServices section so it looks like

    "requiresServices": [
        "field"
    ]
    
  2. Add the field section after requiresServices section:

    "field": {
        "showHomeLink": true,
        "appDir": "_private/field-app",
        "appModule": "tutorial.module#TutorialModule",
        "assetDir": "_private/field-assets",
        "icon": "/assets/peek_plugin_tutorial/icon.png"
    }
    
  3. Ensure your JSON is still valid (Your IDE may help here)

Here is an example

{
    ...
    "requiresServices": [
        ...
        "field"
    ],
    ...
    "field": {
        "showHomeLink": true,
        "appDir": "_private/field-app",
        "appModule": "tutorial.module#TutorialModule",
        "assetDir": "_private/field-assets",
        "icon": "/assets/peek_plugin_tutorial/icon.png"
    }
}

Add Field Service

This document is a stripped version of Add Logic Service.

Add File FieldEntryHook.py

Create the file peek_plugin_tutorial/_private/field/FieldEntryHook.py and populate it with the following contents.

import logging

from peek_plugin_base.field.PluginFieldEntryHookABC import PluginFieldEntryHookABC

logger = logging.getLogger(__name__)


class FieldEntryHook(PluginFieldEntryHookABC):
    def __init__(self, *args, **kwargs):
        """" Constructor """
        # Call the base classes constructor
        PluginFieldEntryHookABC.__init__(self, *args, **kwargs)

        #: Loaded Objects, This is a list of all objects created when we start
        self._loadedObjects = []

    def load(self) -> None:
        """ Load

        This will be called when the plugin is loaded, just after the db is migrated.
        Place any custom initialiastion steps here.

        """
        logger.debug("Loaded")

    def start(self):
        """ Load

        This will be called when the plugin is loaded, just after the db is migrated.
        Place any custom initialiastion steps here.

        """
        logger.debug("Started")

    def stop(self):
        """ Stop

        This method is called by the platform to tell the peek app to shutdown and stop
        everything it's doing
        """
        # Shutdown and dereference all objects we constructed when we started
        while self._loadedObjects:
            self._loadedObjects.pop().shutdown()

        logger.debug("Stopped")

    def unload(self):
        """Unload

        This method is called after stop is called, to unload any last resources
        before the PLUGIN is unlinked from the platform

        """
        logger.debug("Unloaded")

Edit peek_plugin_tutorial/__init__.py

Edit the file peek_plugin_tutorial/__init__.py, and add the following:

from peek_plugin_base.field.PluginFieldEntryHookABC import PluginFieldEntryHookABC
from typing import Type


def peekFieldEntryHook() -> Type[PluginFieldEntryHookABC]:
    from ._private.field.FieldEntryHook import FieldEntryHook
    return FieldEntryHook

Edit plugin_package.json

Edit the file peek_plugin_tutorial/plugin_package.json :

  1. Add “field” to the requiresServices section so it looks like

    "requiresServices": [
        "field",
    ]
    
  2. Add the field section after requiresServices section:

    "field": {
    },
    
  3. Ensure your JSON is still valid (Your IDE may help here)

Here is an example

{
    "plugin": {
        ...
    },
    "requiresServices": [
        "field",
    ],
    "field": {
    },
}

The plugin should now be ready for the field to load.

Running on the Field Service

Edit ~/peek-field-service.home/config.json:

  1. Ensure logging.level is set to “DEBUG”

  2. Add “peek_plugin_tutorial” to the plugin.enabled array

Note

It would be helpful if this is the only plugin enabled at this point.

It should something like this:

{
    ...
    "logging": {
        "level": "DEBUG"
    },
    ...
    "plugin": {
        "enabled": [
            "peek_plugin_tutorial"
        ],
        ...
    },
    ...
}

Note

This file is created in Administration. Running the Field Service will also create the file.

Check File ~/peek-field-service.home/config.json

Check the ~/peek-field-service.home/config.json file:

  1. Ensure frontend.webBuildEnabled is set to true, with no quotes

  2. Ensure frontend.webBuildPrepareEnabled is set to true, with no quotes

Note

It would be helpful if this is the only plugin enabled at this point.

Example:

{
    ...
    "frontend": {
        ...
        "webBuildEnabled": true,
        "webBuildPrepareEnabled": true
    },
    ...
}

Run run_peek_office_service

You can now run the peek office service, you should see your plugin load.

peek@_peek:~$ run_peek_office_service
...
DEBUG peek_plugin_tutorial._private.office.OfficeEntryHook:Loaded
DEBUG peek_plugin_tutorial._private.office.OfficeEntryHook:Started
...
INFO peek_platform.frontend.WebBuilder:Rebuilding frontend distribution
...
INFO txhttputil.site.SiteUtil:Peek Office App is alive and listening on http://10.211.55.14:8000
...

Now bring up a web browser and navigate to http://localhost:8000 or the IP mentioned in the output of run_peek_field_service.

If you see this, then congratulations, you’ve just enabled your plugin to use the Peek Platform, Field Service Web App.

../../_images/LearnAddFieldWebHomeScreen.png

Click on the Tutorial app, you should then see your plugins default route component.

../../_images/LearnAddFieldWebPluginScreen.png