# Migration
# v1.31.0
# Sentry
This version adds a sentry-plugin. It requires the following dependency:
$ yarn add -D @sentry/vue@8.36.0
# Impersonate user
Update vue-backoffice-pages to get the Impersonate-button in the ListView of users.
# v1.30.0
This version makes use of the keycloak-js module. Please add it in your customer projects with:
$ yarn add -D keycloak-js@22.0.5
# 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
ListViewwill now preserve state when you visit an associated entity (FG-2) (opens new window)ListViewwill automatically keep the active row in viewListViewshows a notification when anEntityhas been created, updated or deleted. FG-46 (opens new window), FG-47 (opens new window), FG-48 (opens new window)Pagewill automatically determine itsentitybased on theroute(overridable) and alsoprovideitPagewill automatically determine if thisentityis active (and will hide it when it is not)Entitywill use injected$entitybased on thePagecomponentEntitywill now close the entity as expected whilst preserving theListViewstate; and to top things off: you can re-open it! (FG-8) (opens new window)useEntityanduseEntityObjectnow export aprefixthat can be set inentities.jsonfor use in the i18n-callFieldsautomatically injects the$fieldsand$errors- All props can be removed! (FG-31) (opens new window)Relationsautomatically injects the$relations- All props can be removed! (FG-31) (opens new window)- There is a new
useEntitySearch-composable for when you want to fetch a list of entities (FG-29) (opens new window) - There is a new
useEntityCrud-composable for when you want to do your own CRUD on an entity (FG-54) (opens new window) - There is a new
useContext-composable that returns a reactiveroute,router,storeandaxiosinstance - There is a new
defineRelation-composable that returns aniconand a method to visit that relation ShareButtonis added. FG-45 (opens new window)
# BREAKING CHANGES
Pagedoesn't have adetailandlistslot anymore, it has only adefaultslotPagewill automatically setup a navigation path for you (can be disabled via theisNavigationPathEnabled-prop)Pagewill automatically fetch the i18n translations based on the correspondingprefixEntityhas now acreate-prop instead ofcreate-newuseEntityonly allows a reactiverouteandrouteruseEntitydoes not exportvisitDetail,visitListandvisitNewanymore; useuseRouteordefineRelatoninsteaduseEntitydoes not exportsetupNavigationPathandclearNavigationPathanymore; useuseNavigationPathinsteadSplitViewhas been removed, for the time beingDetailView(was already deprecated) is now completely removed from the export
# Dependencies
vue-scrolltohas been removedscroll-into-viewhas been added@fortawesome/fontawesome-freehas been updated to v6 - Some icons have been renamed (opens new window)
$ 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
- First make sure that you've done all the previous migration-steps.
- Copy an
index.vueinside the entity-folder to the root-folder and name it the same as the corresponding folder. - Repeat this step for all
index.vuefiles 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
- Make sure that the 'root'-entity (e.g.
customers.vue) only contains aPageand a correspondingListView.
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>
- Make sure that the
/new/index.vuecontains only anEntity-component (remove theListView) - Also make sure to rename the
create-new-prop tocreate - Keep all the event handlers, but you can remove all the
isFormDisabled,fields,permissions,errorsprops from the scoped-slot if you do not use them inside yourEntityDetailView. 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>
- Also remove the
ListViewfrom 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>
- Search for
RelationsandFieldsand remove all the props; they are no longer needed! - Make sure that all
setupNavigationPathcalls are removed as they are now done by thePage. If you want to do them anyway, set theis-navigation-path-enabled-prop tofalse. But make sure that it is only done where thePage-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 />
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 />
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" />
# 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
+ }
+ }
}
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
}
}
← SCSS