# 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
ListView
will now preserve state when you visit an associated entity (FG-2) (opens new window)ListView
will automatically keep the active row in viewListView
shows a notification when anEntity
has been created, updated or deleted. FG-46 (opens new window), FG-47 (opens new window), FG-48 (opens new window)Page
will automatically determine itsentity
based on theroute
(overridable) and alsoprovide
itPage
will automatically determine if thisentity
is active (and will hide it when it is not)Entity
will use injected$entity
based on thePage
componentEntity
will now close the entity as expected whilst preserving theListView
state; and to top things off: you can re-open it! (FG-8) (opens new window)useEntity
anduseEntityObject
now export aprefix
that can be set inentities.json
for use in the i18n-callFields
automatically injects the$fields
and$errors
- All props can be removed! (FG-31) (opens new window)Relations
automatically 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
,store
andaxios
instance - There is a new
defineRelation
-composable that returns anicon
and a method to visit that relation ShareButton
is added. FG-45 (opens new window)
# BREAKING CHANGES
Page
doesn't have adetail
andlist
slot anymore, it has only adefault
slotPage
will automatically setup a navigation path for you (can be disabled via theisNavigationPathEnabled
-prop)Page
will automatically fetch the i18n translations based on the correspondingprefix
Entity
has now acreate
-prop instead ofcreate-new
useEntity
only allows a reactiveroute
androuter
useEntity
does not exportvisitDetail
,visitList
andvisitNew
anymore; useuseRoute
ordefineRelaton
insteaduseEntity
does not exportsetupNavigationPath
andclearNavigationPath
anymore; useuseNavigationPath
insteadSplitView
has been removed, for the time beingDetailView
(was already deprecated) is now completely removed from the export
# Dependencies
vue-scrollto
has been removedscroll-into-view
has been added@fortawesome/fontawesome-free
has 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.vue
inside the entity-folder to the root-folder and name it the same as the corresponding folder. - 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
- Make sure that the 'root'-entity (e.g.
customers.vue
) only contains aPage
and 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.vue
contains 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
,errors
props 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
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>
- Search for
Relations
andFields
and remove all the props; they are no longer needed! - Make sure that all
setupNavigationPath
calls 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