Skip to content

connoratrug/molgenis-frontend

 
 

Repository files navigation

Quality Gate Status Code Coverage Commitizen friendly

molgenis-frontend

These are stable packages for MOLGENIS. The stable packages will compose the MOLGENIS frontend. These are used in the molgenis/molgenis repository

The following will be addressed:

Environment

When developing client code, you will need to following tools:

  • Node v8.11.3 (LTS version) and included NPM version
  • Yarn v1.10.3 or greater

The project is built using lerna to manage the monorepo and yarn as the npm client.

note: It can be hard to migrate from old to new versions. Please check the troubleshooting guide if you have trouble setting up the environment.

Developing

To get started run

> yarn install
> yarn lerna bootstrap

The following will be addressed:

Commits

We use independent versioning for the packages. This makes it hard to interactively specify at release time what type of upgrade each app needs.

So please specify your changes using conventional commits. This allows lerna to deduce the version increments for each app from the commits. As a bonus, it will generate a per-app changelogs.

If you've run yarn install, you can use commitizen to formulate your commits interactively from anywhere in the repository. Just type git cz instead of git commit. It will accept command line flags too.

Allowed scopes

Use the app directory names as scopes.

Allowed types

The Angular conventional commit types.

Squash messy commits

When merging a pull request that does not use conventional commits you can squash the commits into a single conventional commit.

Usage of yarn

The following three commands can be used to install, develop and test client code:

cli2

> yarn install
> yarn dev
> yarn unit
> yarn e2e
// (to run unit and e2e together)
> yarn test 
> yarn build

cli3

> yarn install
> yarn serve
> yarn test:unit
> yarn test:e2e
> yarn build

Global commands

Third party dependencies can be added:

> yarn add <library_name>

Third party development dependencies can be added:

> yarn add --dev <library_name>

or removed:

> yarn remove <library_name>

using yarn.

Yarn produces a yarn.lock file. Commit this file to your Git repository as it ensures future builds to use the versions that were used to create the client code.

When running your client code in development on port 8081, it will help to run the MOLGENIS locally on port 8080. The vue-cli comes with a proxy table that will redirect any REST calls to localhost:8080.

Create new stable packages

If you do not have the vue-cli (version 3), please check vue-cli.

If you have the vue-cli installed you can use the following steps to quickly install a working Vue template.

> cd packages/
> vue create --preset ../preset.json <new-app-name> 

Using the preset.json is recommended. If you need specific tooling you can also choose manual.

note: Make sure you update the project-name to @molgenis-ui/#new-app# for publishing purposes in the package.json name-key of the package you created.

Update existing stable packages

You have to update the package.json in the molgenis/molgenis repository before you start developing in the frontend stable packages. The version of the app you start to develop has to be updated to [ canary ].

That way each merge with the master on this repository will be automatically picked up by the main MOLGENIS repository.

The whole development flow is working as follows.

Pull requests

PR's will build locally and will be packaged locally in a docker. The docker will be proxied in front of the https://master.dev.molgenis.org as a preview on kubernetes.

Merges with master

Merges with the master automatically will deploy on npmjs.org.

Releases

A release will automatically be done when an app is merged with the master. Lerna will determine which modules need to be released and what type of increment is needed based on the git log. Please use conventional commits so that this is determined correctly.

For more information, see the lerna version command documentation.

The modules are published to our stable repository

Deployment

When the packages are published they will be automatically deployed based upon the app-configuration in each MOLGENIS instance. The service which serves the packages is at the moment https://unpkg.com. This service serves and NPM bundle as a bundle of files.

Unpackage fetches tgz packages from npm ( @molgenis-ui ) and unzips and serves them. unpkg.com forwards requests to versioned requests.

Example configuration:

@molgenis-ui/navigator has versions: 1.0.0 , 2.0.1, 2.1.2

unpkg/@molgenis-ui/navigator is forwarded to unpkg/@molgenis-ui/navigator@2.1.2 ( latest )

unpkg/@molgenis-ui/navigator@2.0.1 Is not forwarded ( version request )

unpkg/@molgenis-ui/navigator@~2 is forwarded to unpkg/@molgenis-ui/navigator@2.0.1 ( latest within major )

Testing packages

There are three ways to test a package:

  1. Make a standalone setup and mock the API responses
  2. Proxy the MOLGENIS backend in front of the package
  3. Link the package in the MOLGENIS backend for full integration

note: the ordering of the ways to test the packages is important.

The first and second test manners should be sufficient to actually be confident that your application works. In the preview mode, where you already integrated the artifact in MOLGENIS you also test the integration.

Make a standalone setup

You always want to start with an offline setup for the package. You then need to define the state and mock responses first and have to think about the API you want to use. In cli2 and cli3 the setup is different so both are described.

cli2

When you are creating a standalone setup in cli2 you need to add an index.html file (is generated automatically). Besides this you need to add mock responses to supply you store. You can add them in #package#/config/index.js.

Example:

...
const listOfItems = require('./dev-responses/list.js')
...
  before (app) {
      app.get('#apipath#', function (req, res) {
        res.json(listOfItems)
      })
...

This before block is used by the store instead of accessing the real end-points. This is also used by the end-to-end tests to test the ui.

note: You need to use yarn to install, test, serve and develop the package. Check: Usage of yarn (cli2).

cli3

When you are creating a standalone setup in cli3 you need to add an index.html file (is generated automatically). Besides this you need to add mock responses to supply you store. You can add them in vue.config.js.

A template of vue.config.js can be found here:

// vue.config.js
module.exports = {
  chainWebpack: config => {
    config.externals({
      '#external library key#': '#library name#'
    })
  },
  devServer: {
    // In CI mode, Safari cannot contact "localhost", so as a workaround, run the dev server using the jenkins agent pod dns instead.
    host: process.env.JENKINS_AGENT_NAME || 'localhost',
    // Do not proxy in production to allow for mocking api response in e2e test ( e2e tests are run in production mode)
    proxy: process.env.NODE_ENV === 'production' ? undefined : 'http://localhost:8080',
    before: function (app, server) {
      app.get('#api path#', function (req, res) {
        res.json({
          href: '#href api#',
          items: [
            {
              _href: '#item href#',
              code: '#item code#',
            },
          ]
        })
      })
    }
  }
}

Example:

...
const listOfItems = require('./dev-responses/list.js')
...
  before: function (app, server) {
      app.get('#api path#', function (req, res) {
        res.json(listOfItems)
      })      
...

This before block is used by the store instead of accessing the real end-points. This is also used by the end-to-end tests to test the ui.

note: You need to use yarn to install, test, serve and develop the package. Check: Usage of yarn (cli3).

Proxying MOLGENIS backend

We now have two configurations for the VUE packages. One based on vue-cli2 and one based on vue-cli3.

cli2

You need to configure the MOLGENIS backend in the index.js of the vue configuration. It is usually placed here: #package#/config/index.js

You need to: 'add, change or leave it as it is', this configuration block:

Example:

...
dev: {
    ...
    proxyTable: {
      '/login': {
        target: 'http://localhost:8080'
      },
      '/api': {
        target: 'http://localhost:8080'
      },
      '/plugin/#package#': {
        target: 'http://localhost:8080'
      }
    },
...

You need to add the paths that are used by the package. In this case:

- '/login'
- '/api'
- '/plugin'

The idea is that we lean as much on public API's as possible. Then we do not need lot's of specific webservices for plugins.

note: You need to disable the before-block in the #package#/config/index.js. This way you are making sure that the package is not using the mock responses.

cli3

In cli3 you have a lot less configuration. Default the vue configuration is located partially in the package.json and in vue.config.js. To proxy we need to amend the vue.config.js.

Example:

...
 'devServer': {
    proxy: process.env.NODE_ENV === 'production' ? undefined : {
      '^/login': {
        'target': 'http://localhost:8080'
      },
      '^/api': {
        'target': 'http://localhost:8080'
      },
      '^/plugin/#package#': {
        'target': 'http://localhost:8080'
      },
...

You need to add the paths that are used by the package. In this case:

- '/login'
- '/api'
- '/plugin'

The idea is that we lean as much on public API's as possible. That we do not need lot's of specific webservices for plugins.

note: You need to disable the before-block in the vue.config.js. This way you are making sure that the package is not using the mock responses.

Using yarn link for live editing

You can use yarn link while developing to view the results directly in MOLGENIS.

Assuming you've checked out molgenis/molgenis and molgenis/molgenis-frontend repositories to directory ~/git, and want to get started working on module scripts, do this once:

  • Open both projects in IntelliJ.
  • In the molgenis project, go to the molgenis-frontend module and mark the node_modules/@molgenis-ui/scripts/dist directory as resources root. (Does not happen automatically even though the pom.xml lists it as such.)
  • Start molgenis webapp in exploded mode using IntelliJ IDEA
  • Run yarn link in ~/git/molgenis-frontend/packages/scripts.
  • Run yarn link "@molgenis-ui/scripts" in ~/git/molgenis/molgenis-frontend/
  • If the project supports webpack watch modus, start it: yarn watch

Now for each change:

  • make change in molgenis-frontend
  • (If the project does not support webpack watch modus) Manually run yarn build.
  • Wait for webpack to finish
  • Tab out to the browser. You should see a tiny progress bar in the molgenis window of IntelliJ.
  • Wait for the popup saying Compilation finished to appear.
  • Reload the browser window to see the changes

Integrate with MOLGENIS

There is a workflow you have to follow to implement new frontend code in molgenis/molgenis/molgenis-frontend.

Make sure you add the new app to the package.json.

> cd molgenis/molgenis-frontend
> 
> yarn add <new-app>

Change the version into canary.

Add to pom.xml as well.

You have to include the package in the pom.xml as well.

...
<build>
  <resources>
    <resource>
      <directory>node_modules/@molgenis-ui/##new-app##/dist</directory>
    </resource>
...

Create a molgenis/molgenis-new-app module to serve the new app

You need three files:

  • pom.xml
  • src/main/java/org/molgenis/new/app/controller.java
  • src/main/resource/templates/view-new-app.ftl

You have to create a module with the following inside your pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.molgenis</groupId>
    <artifactId>molgenis</artifactId>
    <version>#molgenis version#</version>
  </parent>

  <artifactId>molgenis-new-app</artifactId>
  <name>#new app#</name>
  <description>Plugin module for serving new app.</description>

  <!-- start optional -->
  <dependencies>
    <dependency>
      <groupId>org.molgenis</groupId>
      <artifactId>#depedant module#</artifactId>
      <version>${project.version}</version>
    </dependency>
  </dependencies>
  <!-- end optional -->  
</project>

You create in src/main/resources/templates/ a view-new-app.ftl file with the content below.

<#include "resource-macros.ftl">
<#include "molgenis-header.ftl">
<#include "molgenis-footer.ftl">

<#assign js = []>
<#assign css = ["#new app#/app.css"]>
<#assign version = 2>

<@header css js version/>
    <div id="app"></div>

    <script type="text/javascript">
        window.__INITIAL_STATE__ = {
            baseUrl: '${baseUrl}',
            lng: '${lng}',
            fallbackLng: '${fallbackLng}',
            isSuperUser: ${isSuperUser?c}
        }
    </script>

    <script type=text/javascript src="<@resource_href "/js/#new app name#/manifest.js"/>"></script>
    <script type=text/javascript src="<@resource_href "/js/#new app name#/vendor.js"/>"></script>
    <script type=text/javascript src="<@resource_href "/js/#new app name#/app.js"/>"></script>

<@footer version/>

You have to create a controller in src/main/java/org/molgenis/new/app with the following content:

@Controller
@RequestMapping(URI)
public class NewAppController extends VuePluginController {
  private static final Logger LOG = LoggerFactory.getLogger(NewAppController.class);

  public static final String NEW_APP = "new-app";
  public static final String URI = PLUGIN_URI_PREFIX + NEW_APP;

  public NewAppController(
      MenuReaderService menuReaderService,
      AppSettings appSettings,
      UserAccountService userAccountService) {
    super(URI, menuReaderService, appSettings, userAccountService);
  }

  @GetMapping("/**")
  public String init(Model model) {
    super.init(model, NEW_APP);
    return "view-new-app";
  }
}

That is it.

Preview frontend with alternative backend using CI rancher cluster

You can link the generated PR preview to a alternative backend service

  • Login to rancher ( or use cli).
  • Find the preview config ( Menu item 'config-maps', use search to find the preview version you are looking for).
  • Edit the ...-config file, change the 'proxy_pass' location to use the alternative backend service ( save after edit).
  • Go to the Workloads page and find the preview version you are looking for.
  • Scale down to 0, and scale back up to 1 ( this will create a new container that uses the updated config).

Guidelines

Below you can find some guidelines + code examples for stuff that we view is standard when creating a MOLGENIS plugin.

Use Font awesome for icons1

<i class="fa fa-plus"></i>

Write unit tests for mutations, actions, getters and other pure JS code

// utils.spec.js

import { swapArrayElements } from 'utils'

describe('swapArrayElements', () => {
    it('should swap the location of two objects in an array', () => {
        const array = [1, 2, 3, 4, 5]

        const actual = swapArrayElements(array, 2, 3)
        const expected = [1, 2, 4, 3, 5]

        expect(expected).to.deep.equal(actual)
    })
})

Create named Vue components

// ComponentA.vue

<script>
    export default {
        name: 'component-A'
    }
</script>

To allow theme changes to affect all specific color sets, use sass mixins and variables1 when setting colors

<style lang="scss">
  @import "~variables";
  @import "~mixins";
  
   .some_class {
      background-color: $red;
    }
    
    .some_other_class {
      background-color: darken($red, 20%)
    }
</style>

When using Vuex for your state, use TypeScript to add typing your state parameters1

// state.js
export type State = {
  message: ?string
  isUpdated: boolean
}

const state: State = {
  message: null,
  isUpdated: false
}

Use i18n for labels

<button>{{ 'back-to-home-button' | i18n }}</button>

When writing actions or mutations for your store, use constants for the different types

// mutations.js
export default {
    'setMessage' (state, message) {
        state.message = message
    }
}

Jenkins CI/CD

Pull requests / commits to pull requests

Whenever a PR is created or commits are being made to a PR a trigger is sent to Jenkins to start building a preview.

For our build we use Lerna. We let Lerna check against the change target (mostly master) to see which packages have been changed and only test / build those.

Build script

You can find a custom build script that checks if a dist folder exists (eg, has been created by Lerna) and copies that to a temp docker dir.

docker/copy_package_dist_dirs.sh

Preview container

For the preview we have some special nginx config

docker/preview-config/conf.d/preview.conf

which will proxy all packages to master.dev.molgenis.org that have not been found in the preview container

About

Frontend code for MOLGENIS

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 41.8%
  • TypeScript 31.9%
  • Vue 22.7%
  • CSS 2.6%
  • HTML 0.7%
  • SCSS 0.1%
  • Other 0.2%