Frontend Component

Plugins may or may not contain a frontend component and are instantiated by the Angular compiler. See the @icepanel/core-frontend package for frontend specific helper services.

Frontend plugin instances are created each time a view is loaded in the browser and are unique each time they are opened.

For information about communicating between frontend and backend components please see Plugin Communication.

Anguar module

Ensure the default export for your module is an Angular module so that IcePanel can instantiate it. Use methods defined in IFrontendModule to specify which Angular component should be used as the entry point for each view.

See below an example frontend Angular module.

import { CommonModule } from '@angular/common'
import { NgModule } from '@angular/core'
import { IModel, PluginType } from '@icepanel/core'
import { IcePanelFrontendModule, IFrontendModule } from '@icepanel/core-frontend'

import { PrototypeAppComponent } from './prototype-app'
import { EnvironmentAppComponent } from './environment-app'
import { SetupComponent } from './setup'

@NgModule({
  imports: [
    CommonModule,
    IcePanelFrontendModule
  ],
  declarations: [
    PrototypeAppComponent,
    EnvironmentAppComponent,
    SetupComponent
  ],

  // including the component in entryComponents allows it to be bootstrapped by IcePanel
  entryComponents: [
    PrototypeAppComponent,
    EnvironmentAppComponent,
    SetupComponent
  ]
})

export default class FrontendModule implements IFrontendModule {
  environmentComponent(model: IModel) {
    switch (model.plugin.type) {
      case PluginType.App:
        return EnvironmentAppComponent
      default:
        return null
    }
  }

  prototypeComponent(model: IModel) {
    switch (model.plugin.type) {
      case PluginType.App:
        return PrototypeAppComponent
      default:
        return null
    }
  }

  setupComponent() {
    return SetupComponent
  }
}

Accessing and modifying models

You can access and modify the prototype model by injecting the PrototypeService class into your Angular component.

See the example below for how to set the name of the current model in context inside the prototype.

import { Component } from '@angular/core'
import { IAppModel } from '@icepanel/core'
import { PrototypeService } from '@icepanel/core-frontend'

// create an Angular component
@Component({
  styleUrls: ['./style.scss'], // sass is compiled by the sass-loader and node-sass
  templateUrl: './template.html' // html template is compiled by the angular2-template-loader dependency
})
export class PrototypeAppComponent {

  // using private in the constructor generates class properties automatically
  constructor(private prototypeService: PrototypeService<IAppModel>) {}

  saveName(name: string) {
    this.prototypeService.model.name = name
    this.prototypeService.sync()
  }
}

After the prototype has been deployed you can use the EnvironmentService class to access readonly values about the environment.

import { Component, OnInit } from '@angular/core'
import { IAppModel } from '@icepanel/core'
import { EnvironmentAppComponent } from '@icepanel/core-frontend'

@Component({
  styleUrls: ['./style.scss'],
  templateUrl: './template.html'
})
export class EnvironmentAppComponent implements OnInit {
  constructor(private environmentService: EnvironmentAppComponent<IAppModel>) {}

  // ngOnInit is an Anguar lifecycle hook for when the component has loaded
  ngOnInit() {
    const name = this.environmentService.model.name
    console.log(`the name of this model is ${name}`)
  }
}

Backend communication

You can communicate with either the engine plugin using EngineService or the plugin itself using PluginService.

See the below example for how to call a method which has been exported by the backend plugin.

import { Component, OnInit } from '@angular/core'
import { IAppStatus } from '@icepanel/core'
import { PluginService } from '@icepanel/core-frontend'

@Component({
  styleUrls: ['./style.scss'],
  templateUrl: './template.html'
})
export class EnvironmentAppComponent implements OnInit {
  status: IAppStatus

  constructor(private pluginService: PluginService) {}

  async ngOnInit() {
    this.status = await this.pluginService.method('getStatus')()
    console.log(`this plugins status is ${this.status}`)
  }
}

See below how to subscribe to a PubSub topic on the backend engine plugin.

import { Component, OnInit } from '@angular/core'
import { IAppStatus, IAppModel } from '@icepanel/core'
import { EnvironmentService, EngineService, ViewSubscription } from '@icepanel/core-frontend'

@Component({
  styleUrls: ['./style.scss'],
  templateUrl: './template.html'
})
export class EnvironmentAppComponent implements OnInit {
  status: IAppStatus
  statusSub: ViewSubscription<{ status: IAppStatus }>

  constructor(
    private environmentService: EnvironmentService<IAppModel>,
    private engineService: EngineService
  ) {}

  async ngOnInit() {
    // generate the PubSub topic name which has been created
    const environmentId = this.environmentService.environment.id
    const modelId = this.environmentService.model.id
    const topicName = `status.${environmentId}.${modelId}`

    // listen for messages on the PubSub topic
    this.statusSub = await this.engineService.subscribe(topicName)
    this.statusSub.on('message', data => {
      this.status = data.status
      console.log(`this plugins status has changed to ${this.status}`)
    })
  }
}