# Migration

# v1.28.0

Removed usersnap-plugin.

// `nuxt.config.js
const plugins = [
-  './plugins/usersnap', // Remove this one
  './plugins/runtime',
  './plugins/axios',
  './plugins/element-ui',
  './plugins/i18n',
  './plugins/vue-good-table'
]
config.plugins = plugins

# v1.26.0

This version tracks the 'dirty' state of the open entity detail view. For installation, see the README file

Run this command to update the wysiwyg editor to the latest version:

yarn upgrade @jdi/wysiwyg-editor@^1.3.1

# v1.25.0

We have noticed that some backoffices don't have a proper translations page. That is because the translations were not loaded from the correct URL. You will need to change the url from the translations-entity to /translation-codes:

{
  "translations": {
    "icon": "fa-language",
    "url": "/translation-codes",
    "prefix": "translationItem"
  }
}

# v1.24.0

This version makes use of the vuedraggable module. Please add it in your customer projects with:

$ yarn add vuedraggable@~2.24.3

# v1.21.2

# Versions file

Please make sure that the pages/entities.json file contains an entry for the versions file:

{
  "versions": {
    "url": "/cms/versions"
  }
}

# Development

For testing the version functionality on a local development environment, please copy static/version.json.example to static/version.json.

# v1.21.0

Added usersnap-plugin to gather user feedback. Be sure to follow the installation steps.

# v1.20.0

# Nuxt

Nuxt 2.17.1 is the last release the backoffice will support in the Vue 2 era. It fixes the yarn build command issue (opens new window).

Run this command to set the nuxt version to a fixed version.

$ yarn add -D nuxt@2.17.1

After that you can update the build command (in your package.json) to this:

{
  "scripts": {
  -  "build": "NODE_OPTIONS=--openssl-legacy-provider nuxt build"
  +  "build": "nuxt build"
  }
}

# Dependencies

Adds mitt as a dependency:

$ yarn add -D mitt

# News

In this version a link to the news page is added in the SideBar.

You also need to add news.vue (opens new window) to the pages to enable this route. By default this feature will be enabled. To disable this feature add features.news: false to backoffice.config.json

# Dependencies

New dependencies:

$ yarn add -D rss-parser

# v1.19.0

# PriceInput

PriceInput requires a new dependency. Make sure to install vue-currency-input@^2 See the guide how to implement it.

# Dependencies

New dependencies:

$ yarn add -D vue-currency-input@^2

# v1.17.0

# 2FA

Starting this release, the LoginForm has been deprecated. Use AuthenticationStates instead. You will need to update vue-backoffice-pages to see the "Reset 2FA" button in the Users-page. You also need to update the core to the related version.

$ yarn upgrade @jdi/vue-backoffice-pages
$ yarn upgrade @jdi/wysiwyg-editor
$ yarn add -D @bachdgvn/vue-otp-input

Also remove engines from your package.json.

WARNING

Starting this release we have aligned the usage of camelCase for permissions and relations. You need to make sure that relations with a "_" are renamed to its camelCase counterpart!

E.g. customer_orders is now customerOrders.

-  <Relation right="customer_orders" />
+  <Relation right="customerOrders" />

You can easily find them by searching for the "_", because this should not be a common character.

# Nuxt / Node 18

Upgrades node:18.16.1 to be able to update nuxt~2.17.

$ yarn remove vue-jest
$ yarn add -D @vue/vue2-jest@28 vue@~2.6 nuxt@~2.17 vuex@^3 vue-server-renderer@~2.6 vue-template-compiler@~2.6

Also update your jest.config.js to the installed vue-jest version (opens new window).

WARNING

The upgrade of nuxt requires a node upgrade. These steps are very important! Follow these steps carefully!

For the time being this is the build-script:

{
  "scripts": {
    "build": "NODE_OPTIONS=--openssl-legacy-provider nuxt build"
  }
}

Also update the Node version to node:18.16.1 in your .nvmrc (opens new window) and Jenkinsfile (opens new window).

# Mockoon

There is a new Mock in town: Mockoon (opens new window)! Read their API-docs (opens new window) for more information! Edit the mock in the Mac-app (opens new window), or start a server with this command:

$ yarn mock:start

Related package.json script:

{
  "scripts": {
    "mock:start": "mockoon-cli start --data ./mock.json --port 4444"
  }
}

Also make sure to use the new mock url in your runtime.env.json.example (opens new window).

# Dependencies

$ yarn add -D @mockoon/cli

# 1.14.0 - BOLD update

# Caution

There is a new Caution component that responds to test, accept and production. It will only be visible when you set the value to test and accept. In order for this to work, you need to add an environment setting to runtime.env.json:

{
  "#": "Allowed values: test, accept, or production",
  "environment": "test"
}

If the value is not provided, the Caution bar is not shown.

# logout button

The logout button should be removed from shortcuts in the /menu API call.

# application.title

Make sure to update application.title to BOLD Backoffice

# v1.11.0

Starting this release, we have removed the next-branch to improve time to release.

# FileUpload & ImageUpload

These components require a new setting: fileUrl. It should be set in the runtime.env.json:

{
  "api": {
    "fileUrl": "<YOUR_BACKEND_URL_HERE>/:entity/:entityId/file/:field"
  }
}

# Redirect on status 401

Changes were implemented for consistent redirection when a user's login session has expired.

WARNING

For these changes, the vue-backoffice-library needs at least version 1.7.0 of nl.jdi.mvc.security-implementation.

# ForgotPassword

This version requires version 1.7.0-develop.3 of nl.jdi.mvc.security-implementation Please note that some changes to /pages/entities.json must be made. See ForgotPasswordForm.

# FieldInfo

FieldInfo is available for customised info text on a Field. See FieldInfo for API-requirements.

Backwards compatible

The FieldInfo does not require the grandtedAuthorities If you don't want to enabled ForgotPassword, set the feature toggle to false.

# Dependencies

$ yarn add -D vue-password-strength-meter zxcvbn

# v1.6.0

# useLogin

We fixed an issue where the user was not redirected after login and a lastVisitRoute was available. This was caused by the context that was deconstructed and lost its reactivity. It is usually placed under the plugins/axios.js inside the project.

Before
export default ({ store, $axios, redirect }) => axiosPlugin.install(Vue, { store, $axios, redirect })
After
export default (context) => axiosPlugin.install(Vue, context)

See useLogin composable how to use it.

# backoffice.config.json

A configuration file is introduced to determine your basePath. An example of this file you can find in the vue-backoffice-repo.

# useMenuIcon

Introduces useMenuIcon which means that the icon is now used from the entities.json. That means the icon is no longer used from the /menu call. You might need to add the following entities in your entities.json:

{
  "logout": "fa-sign-out",
  "index": "fa-th"
}

# SidebarDrawer

If you wish to use the SidebarDrawer. Make sure to install portal-vue@^2 See the guide how to implement it.

# Dependencies

New dependencies:

$ yarn add -D portal-vue@^2
$ yarn add -D apexcharts vue-apexcharts

# v1.5.0

# ListViewFilters

In this version the /metadata call is introduced in the ListView to be able to show the ListViewFilters. This requires the backend to update to the latest version (opens new window) that supports the filters.

Backwards compatible

At the time of writing we have decided not to be backwards compatible.

# faker

The faker repo has been moved to another maintainer, so we need to update our dependencies.

$ yarn remove faker
$ yarn add --dev @faker-js/faker

In your projects replace this:

+ import { faker } from '@faker-js/faker'
- import faker from 'faker'

# v1.3.0

Introduces useLogin for redirect to the last visited route.

# v1.2.0

Introduces defineEntityRoute in favor of useRoute.

After
<script>
import { defineEntityRoute } from '@jdi/vue-backoffice-library'

export default {
  setup(_, context) {
    const [handleEntityCreated, handleCreateClick] = defineEntityRoute(context, 'customerId')
    return {
      handleEntityCreated,
      handleCreateClick
    }
  }
}
</script>
Before
<script>
import { useRoute, useContext } from '@jdi/vue-backoffice-library'

export default {
  setup(_, context) {
    const { route, router } = useContext(context)
    const { visitDetail, visitNew } = useRoute(route, router)

    return {
      visitDetail,
      visitNew
    }
  },
  methods: {
    handleEntityCreated(id) {
      this.visitDetail({
        key: 'customerId',
        value: id
      })
    },
    handleCreateClick() {
      this.visitNew()
    }
  }
}
</script>

# v1.0.0 - Tenet

This version is called Tenet. Because, with all software we work Agile; we want to gather as much information as possible and work back from that. For this version we have gathered so much information that it was almost a temporal pincer. Based on the temporal pincer we have created awesome new features.

Nested routes

Starting this release we use the concept of nested pages (opens new window). Even though I've tried to make upgrading as easy as possible, the changes are not backwards compatible as the concept is fundamentally different as we did until this point. Read this guide carefully before proceeding

Don't worry; you will mainly need to remove stuff: all the other goodies make up for the changes!

⚠️ This update will also require the backend to add two new common translations common.action.refresh, common.action.share, notifications.urlCopied.message and notifications.entityUpdated.message.

# Features

# BREAKING CHANGES

  • Page doesn't have a detail and list slot anymore, it has only a default slot
  • Page will automatically setup a navigation path for you (can be disabled via the isNavigationPathEnabled-prop)
  • Page will automatically fetch the i18n translations based on the corresponding prefix
  • Entity has now a create-prop instead of create-new
  • useEntity only allows a reactive route and router
  • useEntity does not export visitDetail, visitList and visitNew anymore; use useRoute or defineRelaton instead
  • useEntity does not export setupNavigationPath and clearNavigationPath anymore; use useNavigationPath instead
  • SplitView has been removed, for the time being
  • DetailView (was already deprecated) is now completely removed from the export

# Dependencies

$ yarn remove vue-scrollto
$ yarn add --dev scroll-into-view
$ yarn upgrade --latest @fortawesome/fontawesome-free
$ yarn add postcss@^8 postcss-loader@^4

WARNING

You should now remove the vue-scrollto-plugin from your nuxt.config.js.

TIP

Make sure that your sass, sass-loader, nuxt are up-to-date and @nuxtjs/composition-api has been installed (see previous upgrades!)

# Migration

  1. First make sure that you've done all the previous migration-steps.
  2. Copy an index.vue inside the entity-folder to the root-folder and name it the same as the corresponding folder.
  3. Repeat this step for all index.vue files that are nested inside that route. But not to the root, copy it to the same level as the folder

The folder structure should now something like this:

pages/
├── customers.vue
└── customers/
    ├── customerId/
    │   ├── contacts/
    │   ├── contacts.vue (new nested route)
    │   └── index.vue
    └── new/
        └── index.vue
  1. Make sure that the 'root'-entity (e.g. customers.vue) only contains a Page and a corresponding ListView.
Step 4
<template>
  <Page>
    <template #default="{ title, url, entityId, icon }">
      <EntityListView :title="title" :url="url" :active-id="entityId" :icon="icon" />
    </template>
  </Page>
</template>

<script>
import { Page } from '@jdi/vue-backoffice-library'
import EntityListView from '../components/customers/ListView'

export default {
  components: {
    Page,
    EntityListView
  }
}
</script>
  1. Make sure that the /new/index.vue contains only an Entity-component (remove the ListView)
  2. Also make sure to rename the create-new-prop to create
  3. Keep all the event handlers, but you can remove all the isFormDisabled, fields, permissions, errors props from the scoped-slot if you do not use them inside your EntityDetailView. If you need them for some logic (e.g. determine if some field is readonly or a field is available) then you need to keep the scoped-slot.
Step 7
<template>
  <Entity create @entity-created="handleEntityCreated">
    <EntityDetailView />
  </Entity>
</template>

<script>
import { Entity, useContext, useRoute } from '@jdi/vue-backoffice-library'
import EntityDetailView from '../../../components/customers/DetailView'

export default {
  components: {
    Entity,
    EntityDetailView
  },
  setup(_, context) {
    const { route, router } = useContext(context)
    const { visitDetail } = useRoute(route, router)

    return {
      visitDetail
    }
  },
  methods: {
    handleEntityCreated(id) {
      this.visitDetail({
        key: 'customerId',
        value: id
      })
    }
  }
}
</script>
  1. Also remove the ListView from the /customerId/index.vue-file
Step 8
<template>
  <Entity @entity-removed="handleEntityRemoved">
    <EntityDetailView />
  </Entity>
</template>

<script>
import { Entity, useContext, useRoute } from '@jdi/vue-backoffice-library'
import EntityDetailView from '../../../components/customers/DetailView'

export default {
  components: {
    Entity,
    EntityDetailView
  },
  setup(_, context) {
    const { route, router } = useContext(context)
    const { visitList } = useRoute(route, router)

    return {
      visitList
    }
  },
  methods: {
    handleEntityRemoved() {
      this.visitList()
    }
  }
}
</script>
  1. Search for Relations and Fields and remove all the props; they are no longer needed!
  2. Make sure that all setupNavigationPath calls are removed as they are now done by the Page. If you want to do them anyway, set the is-navigation-path-enabled-prop to false. But make sure that it is only done where the Page-component is used.

Read the setup-guide for how to set up a route. You can also clone the vue-backoffice for a working example.

# v1.0.0-alpha.99

This update requires the installation of the @nuxtjs/composition-api-dependency. With that you can now safely use the compositions in this library and the @nuxtjs/composition-api-compositions (opens new window).

WARNING

Make sure that you use export default (ES-modules) in your nuxt.config.js

# v1.0.0-alpha.96

The Page component does now not require a prefix-prop anymore. All translations will be automatically loaded based on the $route-slugs.

For example:

- <Page prefix="customers" />
+ <Page />

See example

TIP

All prefixes will be automatically made singular-form to comply with the backend convention. In the given example customers will be made customer.

# v1.0.0-alpha.95

# Fieldset

The Fieldset is replaced with Fields. This is following the W3C standards, but this is a breaking change.

- import { Fieldset } from '@jdi/vue-backoffice-library'
+ import { Fields } from '@jdi/vue-backoffice-library'

export default {
  components: {
-    Fieldset,
+    Fields
  }
}
- <template>
-   <Fieldset :fields="fields" :errors="errors">
-   </Fieldset>
- </template>

+ <template>
+   <Fields :fields="fields" :errors="errors">
+   </Fields>
+ </template>
Alternative method Not recommended
import { Fields as Fieldset } from '@jdi/vue-backoffice-library'

This renames the exported component. I would not recommend doing this.

# v1.0.0-alpha.88

Start with running the following commands in a terminal:

// This should create a `entities.json` file in the `/pages`-folder
$ echo "{}" > pages/entities.json

// This should upgrade to the latest versions
$ yarn add --dev @vue/composition-api @jdi/vue-backoffice-library

// This should upgrade Nuxt and its dependencies
$ yarn add --dev nuxt sass-loader@^10

// This should update eslint configs
$ yarn add --dev @jdi/eslint-config-{vue,standard} eslint-plugin-vue@^7

// This adds `pluralize`
$ yarn add --dev pluralize

After this, check if your nuxt.config.js does not override the router-config. It should look like this:

- config.router = {
-  base: '/backoffice/'
- }
+ config.router.base = '/backoffice'

TIP

All the rest is optional, all previous implementation should work perfectly fine as it is backwards compatible.

WARNING

If you want to use this new conventions, routes in the menu should always be camelCase. The API should take care of that.

# Page-prefix

The Page component now automatically determines the prefix based on the $route slugs.

- <Page prefix="customers" />
+ <Page />

See example

API

Please be aware that removing the prefix-prop also requires the API being updated. At the moment the expected prefix in the API is singular (instead of plural).

# TabPane-label

The TabPane also utilizes this entity-convention. When the name of the pane is the same as the convention, you can remove the label. It will automatically be added and translated for you based on the entity.

- <TabPane name="general" :label="$t('customers.tabs.general')" />
+ <TabPane name="general" />

See example

# Page

Previously you had to determine the url, icon and the activeId in the component. This wasn't very convenient, because you had to determine it multiple times. We have now introduced a entities.json (in the pages-folder).

+ import { useEntity } from '@jdi/vue-backoffice-library'

export default {
-  computed: {
-    entityUrl() {
-      return `/customers`
-    },
-    entityId() {
-      return this.$route.params.customerId
-    }
-  }

+  setup(_, context) {
+    // Now the `useEntity` will determined everything based on `context.root.$route`
+    const { url, icon, activeId } = useEntity(context)

+    return {
+      url,         // Will be `/customers`
+      icon,        // Returns the `icon` from the `entities.json`-file
+      activeId     // Returns the `customerId`-param from the `$route`-params
+    }
+  }
}

See examples

If you want to use the new useEntity convention with the url and icon you should migrate your constants.js to entities.json.

For example, there is a variable visitsUrl with the value /visits. This would look like this in your entities.json:

{
  "visits": {
    "icon": "fa-user-card",
    "url": "/visits"
  }
}

And in your code you can use it like this:

<script>
import { useEntityObject } from '@jdi/vue-backoffice-library'
export default {
  setup() {
    const { url, icon } = useEntityObject('visits')
    return { url, icon }
  }
}
</script>

TIP

If you follow the new $route-convention you can also use the useEntity-composition

# setupNavigationPath automation

The payload from the setupNavigationPath is automated based on the $route. All information is gathered by useNavigationPath (in combination with useRouteSlugs. If you use the convention, you do not have to define anything as payload.

<script>
- import CustomerNavigationPathInfo from "../components/customers/NavigationPathInfo"
- import UserNavigationPathInfo from "../components/users/NavigationPathInfo"
- import AddressNavigationPathInfo from "../components/addresses/NavigationPathInfo"

export default {
-   setupNavigationPath([CustomerNavigationPathInfo, UserNavigationPathInfo, AddressNavigationPathInfo])
+   setupNavigationPath()
}
</script>

See useNavigationPath examples

Previous implementation (Example)

Previously you had to determine the path yourself:

export default {
  created() {
    this.setupNavigationPath([
      {
        // The first item in the `navigationPath`
        i18nPrefix: 'customers',
        url: `/customers/123-456/info`,
        route: {
          name: `customers-customerId`,
          params: {
            customerId: '123-456'
          }
        },
        icon: 'fa-user-card'
      },
      {
        // The second item in the `navigationPath`
        i18nPrefix: 'addresses',
        url: `/addresses/789-123/info`,
        route: {
          name: `customers-customerId-addresses-addressId`,
          params: {
            customerId: '123-456',
            addressId: '789-123'
          }
        },
        icon: 'fa-user-card'
      }
      // etc.
    ])
  }
}

As you can see, this would take a lot of effort. Now it is based on the $route.

TIP

Looking for more information about compositions? Read the Composition API-guide (opens new window).

# v1.0.0-alpha.61

# Entity

The DetailView is replaced with Entity. The Entity component is now exported as DetailView, but is deprecated and will be removed in a future release.

- import { DetailView } from '@jdi/vue-backoffice-library'
+ import { Entity } from '@jdi/vue-backoffice-library'

export default {
  components: {
-    DetailView,
+    Entity
  }
}