.. _learn_plugin_development_add_office_app:
==============
Add Office App
==============
The office app is similar to the field app. This document is a stripped version of
:ref:`learn_plugin_development_add_field_app`.
Office File Structure
---------------------
Add Package :file:`_private/office`
```````````````````````````````````
Create an empty package file in the office directory,
:file:`peek_plugin_tutorial/_private/office/__init__.py`
Commands: ::
mkdir peek_plugin_tutorial/_private/office
touch peek_plugin_tutorial/_private/office/__init__.py
Add File :file:`tutorial.component.dweb.html`
`````````````````````````````````````````````
Create the :file:`peek_plugin_tutorial/_private/office/tutorial.component.dweb.html` with the following contents:
::
Tutorial Plugin
Angular2 Lazy Loaded Module
This is the root of the office app for the Tutorial plugin
Add File :file:`tutorial.component.ts`
``````````````````````````````````````
Create the file :file:`peek_plugin_tutorial/_private/office/tutorial.component.ts` and populate it with the following contents.
::
import {Component} from "@angular/core";
@Component({
selector: 'plugin-tutorial',
templateUrl: 'tutorial.component.dweb.html',
moduleId: module.id
})
export class TutorialComponent {
constructor() {
}
}
----
Create the file :file:`peek_plugin_tutorial/_private/office/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 :file:`icon.png`
``````````````````````````````
The Peek web interface has a home screen with apps on it, this icon will be the
tutorial plugins app icon.
.. image:: TutorialExampleIcon.png
:scale: 30 %
----
Create directory :file:`peek_plugin_tutorial/_private/office-assets`
----
Download this plugin app icon
`TutorialExampleIcon.png `_
to :file:`peek_plugin_tutorial/_private/office-assets/icon.png`
Edit File :file:`plugin_package.json`
`````````````````````````````````````
Finally, Edit the file :file:`peek_plugin_tutorial/plugin_package.json` to tell the
platform that we want to use the office service:
#. Add **office** to the requiresServices section so it looks like ::
"requiresServices": [
"office"
]
#. Add the **office** section after **requiresServices** section: ::
"office": {
"appDir": "_private/office",
"appModule": "tutorial.module#TutorialModule",
"assetDir": "_private/office-assets",
"icon": "/assets/peek_plugin_tutorial/icon.png",
"showHomeLink": true,
}
#. Ensure your JSON is still valid (Your IDE may help here)
Here is an example ::
{
...
"requiresServices": [
...
"office"
],
...
"office": {
"appDir": "_private/office-app",
"appModule": "tutorial.module#TutorialModule",
"assetDir": "_private/office-assets",
"icon": "/assets/peek_plugin_tutorial/icon.png",
"showHomeLink": true,
}
}
.. _learn_plugin_development_add_office_service:
==================
Add Office Service
==================
This document is a stripped version of :ref:`learn_plugin_development_add_logic_service`.
Office Service File Structure
-----------------------------
Add File :file:`OfficeEntryHook.py`
```````````````````````````````````
Create the file :file:`peek_plugin_tutorial/_private/office/OfficeEntryHook.py`
and populate it with the following contents.
::
import logging
from peek_plugin_base.office.PluginOfficeEntryHookABC import PluginOfficeEntryHookABC
logger = logging.getLogger(__name__)
class OfficeEntryHook(PluginOfficeEntryHookABC):
def __init__(self, *args, **kwargs):
"""" Constructor """
# Call the base classes constructor
PluginOfficeEntryHookABC.__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 :file:`peek_plugin_tutorial/__init__.py`
`````````````````````````````````````````````
Edit the file :file:`peek_plugin_tutorial/__init__.py`, and add the following: ::
from peek_plugin_base.office.PluginOfficeEntryHookABC import PluginOfficeEntryHookABC
from typing import Type
def peekOfficeEntryHook() -> Type[PluginOfficeEntryHookABC]:
from ._private.office.OfficeEntryHook import OfficeEntryHook
return OfficeEntryHook
Edit :file:`plugin_package.json`
````````````````````````````````
Edit the file :file:`peek_plugin_tutorial/plugin_package.json` :
#. Add **"office"** to the requiresServices section so it looks like ::
"requiresServices": [
"office",
]
#. Add the **office** section after **requiresServices** section: ::
"office": {
}
#. Ensure your JSON is still valid (Your IDE may help here)
Here is an example ::
{
"plugin": {
...
},
"requiresServices": [
"office",
],
"office": {
}
}
----
The plugin should now be ready for the office to load.
Running on the Office Service
-----------------------------
Edit :file:`~/peek-office-service.home/config.json`:
#. Ensure **logging.level** is set to **"DEBUG"**
#. 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 :ref:`administer_peek_platform`. Running the Office
Service will also create the file.
Run :file:`run_peek_office_service`
```````````````````````````````````
Run the peek office service ::
peek@_peek:~$ run_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 txhttputil.site.SiteUtil:Peek Office Site is alive and listening on http://0.0.0.0:8002
...
Now bring up a web browser and navigate to
`http://localhost:8002 `_ or the IP mentioned in the output of
:command:`run_peek_office_service`.