Ember Patterns

Forms

Move your form to it’s own component e.g:

<KbForm::Container>
  {{#if @model.schedule.isRunning}}
    <FaIcon @icon="spinner" @class="fa-pulse fa-2x" />
    Please wait ...
  {{else}}
    {{#with @model.schedule.value as |schedule|}}
      <WorkflowDeleteForm
        @schedule={{schedule}}
        @routeTransition={{this.routeTransition}}
      />
    {{/with}}
  {{/if}}
</KbForm::Container>

Using ember-changeset and validations:

import Component from "@glimmer/component"
import lookupValidator from "ember-changeset-validations"
import ScheduleValidations from "../validations/schedule"
import { action } from "@ember/object"
import { Changeset } from "ember-changeset"
import { inject as service } from "@ember/service"
import { task } from "ember-concurrency"
import { tracked } from "@glimmer/tracking"

export default class WorkflowDeleteFormComponent extends Component {
  @service kbMessages
  @tracked changeset = null

  constructor(owner, args) {
    super(owner, args)
    console.log(this.args.schedule)
    this.changeset = new Changeset(
      this.args.schedule,
      lookupValidator(ScheduleValidations),
      ScheduleValidations
    )
  }

  @action
  submitForm() {
    this.saveTask.perform()
  }

  @task *saveTask() {
    let process_id = this.changeset.get("id")
    this.changeset.validate()
    if (this.changeset.isValid) {
      try {
        yield this.changeset.save()
        if (this.args.routeTransition) {
          this.args.routeTransition(process_id)
        } else {
          console.log(
            "WorkflowDeleteFormComponent ('components/workflow-delete-form.js') no 'routeTransition'"
          )
        }
      } catch (e) {
        this.kbMessages.addError("Cannot delete the workflow process", e)
      }
    }
  }
}

In the form, highlight changeset and server side errors:

<KbForm::Form::Field::ErrorMessageChangeset
  @errorField={{this.changeset.error.deleted_comment}}
/>
<KbForm::Form::Field::ErrorMessageServer
  @errorField={{@schedule.errors.deleted_comment}}
/>

Tip

To return server side errors, check out the _deleted_comment code from ScheduledWorkflowUserViewSet (work/api.py). 08/04/2021, Not sure if this works with serializer errors or our custom_exception_handler (api/models.py).

Notifications

Use the KbMessages service: https://gitlab.com/kb/kb-base-ember-addons/-/blob/tailwind-2-update-ember/addon/services/kb-messages.js

import { inject as service } from "@ember/service"

@service kbMessages

try {
  // do something
} catch (e) {
  this.kbMessages.addError("Cannot delete the workflow process", e)
}

Slide Over

{{#if this.slideOverVisible}}
  <KbSlideOver>
    <KbSlideOver::Toggle
      @title="Add Contacts"
      @toggleSlideOver={{this.toggleSlideOver}}
    />

    // Content of Slide-over...

  </KbSlideOver>
{{/if}}

Tables / Data

Checklist

  1. Add reload: true to all findRecord and findAll methods For details, see Error Handling

  2. Add a try, catch to all store methods. Use kbMessages.addError in the catch (see example below).

  3. Test the store methods with an exception on the server (500 error).

  4. Check the user is notified if a store method returns no data.

Route:

import { inject as service } from "@ember/service"

@service kbMessages

model(params) {
  return {
    processes: this.processesTask.perform(params)
  }
}

@task *processesTask(params) {
  try {
    let processes = yield this.store.query("process", params)
    return yield processes
  } catch (e) {
    this.kbMessages.addError("Cannot load workflow processes", e)
  }
}

Template (including a spinner and nothing found):

{{#if @model.processes.isRunning}}
  <KbTable::Body::Row>
    <KbTable::Body::Cell>
      <FaIcon @icon="spinner" @class="fa-pulse fa-2x" />
      Please wait ...
    </KbTable::Body::Cell>
    <KbTable::Body::Cell />
    <KbTable::Body::Cell />
    <KbTable::Body::Cell />
    <KbTable::Body::Cell />
    <KbTable::Body::Cell />
  </KbTable::Body::Row>
{{else}}
  <KbTable::Body>
    {{#each @model.processes.value as |process|}}
      <Workflow::TableRow @process={{process}} />
    {{else}}
      <KbTable::Body::Row>
        <KbTable::Body::Cell>
          {{#if this.workflow}}
            No workflow processes found ...
          {{else}}
            Please select a workflow...
          {{/if}}
        </KbTable::Body::Cell>
        <KbTable::Body::Cell />
        <KbTable::Body::Cell />
        <KbTable::Body::Cell />
        <KbTable::Body::Cell />
        <KbTable::Body::Cell />
      </KbTable::Body::Row>
    {{/each}}
  </KbTable::Body>
{{/if}}

Template pagination (above and below the table):

{{#if @model.processes.isRunning}}
{{else}}
  <KbPagination
    @model={{@model.processes.value}}
    @page={{this.page}}
    @recordsPerPage={{this.recordsPerPage}}
    @setPage={{this.setPage}}
  />
{{/if}}