npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@envage/hapi-govuk-journey-map

v0.1.1

Published

A hapi plugin for mapping journeys through a hapi web service

Downloads

3

Readme

Hapi GOV.UK Journey Map

Build Status Known Vulnerabilities Code Climate Test Coverage

Overview

This plugin makes it easier to visualise, create and maintain journeys through a hapi web service.

It achieves this by placing reusable journeys into modules each containing a set of pages or routes that when combined make a self contained reusable journey.

Examples of such modules would be an address module, a contact module and a file upload module.

A way of configuring the journey within the module and connections between modules is with mapping files. Within the POC, YAML was used to describe the journey configuration within each mapping file.

Installation

npm install --save @envage/hapi-govuk-journey-map

Usage

The best way to describe this is with an example:

Registering

Please note that the required "setQueryData" and "getQueryData" functions will be explained in Branching.

Register the plugin as follows:

const cache = {}

const { resolve } = require('path')

module.exports = {
  plugin: require('@envage/hapi-govuk-journey-map'),
  options: {
    modulePath: resolve(`${process.cwd()}/src/server/modules`),
    setQueryData: (request, data) => {
      Object.assign(cache, data)
    },
    getQueryData: (request) => {
      return { ...cache }
    },
    journeyMapPath: '/journey-map',
    journeyMapView: '/journey-map.njk'
  }
}

Mapping

Please note that each of the entries within the following files ultimately generate routes within a hapi service.

Example mapping files for a simple journey:

  • Root map:
--- # Root map 

home:
  path: "/"
  route: home.route

applicant:
  path: "/applicant"
  module: contact

complete:
  path: "/complete"
  route: complete.route
  • Contact map:
--- # Contact map

name:
  path: "/name"
  route: contact-name.route

address:
  path: "/address"
  module: address

email:
  path: "/email"
  route: contact-email.route
  • Address map:
--- # Address map

search:
  path: "/search"
  route: address-search.route
  
select:
  path: "/select"
  route: address-select.route

entry:
  path: "/entry"
  route: address-entry.route

The idea is that the navigation through the routes (pages) starts in the root map and flows through each adjacent route. When the module property is set, the flow moves to the start of that modules map and flows through that map. After processing the last route, the flow returns to the previous map and continues.

As I have included no branching in the above map, I would expect the paths (pages) to be traversed in the following order:

- /
- /applicant/name
- /applicant/address/search
- /applicant/address/select
- /applicant/address/entry
- /applicant/email
- /complete

Note that the paths are generated with the parent module path prefixing the current path in each module's map.

The routemap object can be retrieved with the getRouteMap function.

File structure

The file structure in the project for these modules would be as follows:

.
+-- modules
|   +-- complete.route.js
|   +-- home.route.js
|   +-- map.yml
|   +-- address
|   |   +--address.map.yml
|   |   +--address-entry.view.njk
|   |   +--address-entry.route.js
|   |   +--address-search.view.njk
|   |   +--address-search.route.js
|   |   +--address-select.view.njk
|   |   +--address-select.route.js
|   +-- contact
|   |   +--contact.map.yml
|   |   +--contact-email.view.njk
|   |   +--contact-email.route.js
|   |   +--contact-name.view.njk
|   |   +--contact-name.route.js

The following is an example of a route file. I have chosen "contact-name.route.js" for this purpose. Please note that in the following example "Application" is used to persist the contact name:

const Application = require('../../dao/application')
const view = 'contact/contact-name.view.njk'
const pageHeading = 'Please enter your name'

module.exports = [{
  method: 'GET',
  handler: async function (request, h) {
    const { contact = {} } = await Application.get(request)
    return h.view(view, {
      pageHeading,
      value: contact.name
    })
  }
}, {
  method: 'POST',
  handler: async function (request, h) {
    const { contact = {} } = await Application.get(request)
    const { name = '' }  = request.payload
    contact.name = name
    await Application.update(request, { contact })
    return h.continue
  }
}]

Branching

In order to allow branching, it's necessary to allow a query to be asked with a set of alternative routes to go to based on the result of that query.

--- # Address map

manual-check:
  path: "/manual-check"
  route: address-manual-check
  next:
    query: postcodeLookUpEnabled
    when:
      yes: search
      no: entry

search:
  path: "/search"
  route: address-search.route
  
select:
  path: "/select"
  route: address-select.route

entry:
  path: "/entry"
  route: address-entry.route

In the above map, the value of "postcodeLookUpEnabled" (please notes that you can call this query whatever you like) is used to determine the branching.

In the above case a value of "yes" would branch to "search" where as "no" would skip both "search" and "select" and jump straight to "entry"

In order to make this work the "postcodeLookUpEnabled" value needs to be set to "yes" or "no" within the route file. This can be done using the "setQueryData" method.

Please see the extract of a route file below as an example:

.
.
const { setQueryData } = require('@envage/hapi-govuk-journey-map')
.
.
}, {
  method: 'POST',
  handler: async function (request, h) {
    if (process.env.POSTCODE_LOOKUP_ENABLED) {
      setQueryData(request, { postcodeLookUPEnabled: 'yes'})    
    } else {
      setQueryData(request, { postcodeLookUPEnabled: 'no'})    
    } 
    return h.continue
  }
}
.
.
.

Enquiry routes

The enquiry routes will be available if the journeyMapPath option is configured In the following example the journeyMapPath is set to '/journey-map'

/journey-map
/journey-map/{id}

These routes will be automatically loaded when the plugin is registered to return json describing the internal generated map

If the JourneyMapView parameter is set, the view will be displayed with the dat in the variable map otherwise json is returned.

Getting route details

When writing a route handler you may want to retrieve route details. The following functions can be used for this:

getRoute retrieves details about a named route:

const { getRoute } = require('@envage/hapi-govuk-journey-map')
.
.
const route = await getRoute('route-id')

getCurrent retrieves details about the current route:

const { getCurrent } = require('@envage/hapi-govuk-journey-map')
.
.
const route = await getCurrent(request)

getNextRoute retrives the route that is next in the flow:

const { getNextRoute } = require('@envage/hapi-govuk-journey-map')
.
.
const nextRoute = getNextRoute(request)

Module options

When reusing a module it is desirable to be able to pass options to it. For example, a file upload screen could have a filetype string and a list of allowed file extensions passed to it, allowing it to be reused for different types of file. These options are passed in the following way:

site-plan-upload:
  path: "/site-plan-upload"
  module: "upload"
  options:
    filetype: "Site plan"
    extensions: ["PNG", "PDF"]

These can then be accessed from a route handler within the module like this:

const { getCurrent } = require('@envage/hapi-govuk-journey-map')
.
.
const route = await getCurrent(request)
const { filetype, extensions } = route.parent.options

Development and Test

When developing this plugin, simply clone this repository

git clone https://github.com/DEFRA/hapi-govuk-journey-map.git

and run

npm install

Running tests

Unit tests can be run using

npm run unit-test

Publishing to npm

Note that each time the module is published to npm, the version number in the package.json file must be updated in accordance with semantic versioning Also note that the module must be published as public

npm publish --access public

Contributing to this project

If you have an idea you'd like to contribute please log an issue.

All contributions should be submitted via a pull request.

Note that we use Standard JS style, you can check your code using

npm run lint

Licence

THIS INFORMATION IS LICENSED UNDER THE CONDITIONS OF THE OPEN GOVERNMENT LICENCE found at:

http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3

The following attribution statement MUST be cited in your products and applications when using this information.

Contains public sector information licensed under the Open Government licence v3

About the licence

The Open Government Licence (OGL) was developed by the Controller of Her Majesty's Stationery Office (HMSO) to enable information providers in the public sector to license the use and re-use of their information under a common open licence.

It is designed to encourage use and re-use of information freely and flexibly, with only a few conditions.