diff --git a/README.md b/README.md index 4dcd6c5b..50695029 100644 --- a/README.md +++ b/README.md @@ -245,6 +245,42 @@ app.use(basePath, serverAdapter.getRouter()); You will then find the bull-board UI at the following address `https:///my-base-path/queues`. +### Setting request options for the UI client +If you need to change the [axios config](https://www.npmjs.com/package/axios#request-config) for the UI client (for example, to enable [CSRF protection](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie)), add a middleware which sets a serializable value on res.locals.clientOptions: + +```js +const Queue = require('bull') +const { createBullBoard } = require('@bull-board/api') +const { BullAdapter } = require('@bull-board/api/bullAdapter') +const { ExpressAdapter } = require('@bull-board/express') + +const basePath = '/my-base-path'; + +const someQueue = new Queue('someQueueName') +const serverAdapter = new ExpressAdapter(); +serverAdapter.setBasePath(basePath) + +createBullBoard({ + queues: [ + new BullAdapter(someQueue), + ], + serverAdapter +}) + +// ... express server configuration + +app.use(basePath, + (req, res, next) => { + res.locals.clientOptions = JSON.stringify({ + headers: { + 'x-csrf-token': 'my-secret-value' + } + }); + next(); + }, + serverAdapter.getRouter()); +``` + ## Contributing First, thank you for being interested in helping out, your time is always appreciated in every way. 💯 diff --git a/packages/ui/src/index.ejs b/packages/ui/src/index.ejs index cb24437f..b1709374 100644 --- a/packages/ui/src/index.ejs +++ b/packages/ui/src/index.ejs @@ -12,6 +12,9 @@ +<% if (clientOptions) { %> + +<% } %>
Loading...
diff --git a/packages/ui/src/index.tsx b/packages/ui/src/index.tsx index 6fd920ab..1baf862d 100644 --- a/packages/ui/src/index.tsx +++ b/packages/ui/src/index.tsx @@ -11,7 +11,8 @@ import './toastify.css'; const basePath = ((window as any).__basePath__ = document.head.querySelector('base')?.getAttribute('href') || ''); -const api = new Api({ basePath }); +const clientOptions = JSON.parse(document.getElementById('__CLIENT_OPTIONS__')?.textContent || '{}'); +const api = new Api({ basePath, clientOptions }); const uiConfig = JSON.parse(document.getElementById('__UI_CONFIG__')?.textContent || '{}'); render( diff --git a/packages/ui/src/services/Api.ts b/packages/ui/src/services/Api.ts index 5975d57e..e452dd59 100644 --- a/packages/ui/src/services/Api.ts +++ b/packages/ui/src/services/Api.ts @@ -6,14 +6,14 @@ import { Status, } from '@bull-board/api/typings/app'; import { GetJobResponse, GetQueuesResponse } from '@bull-board/api/typings/responses'; -import Axios, { AxiosInstance, AxiosResponse } from 'axios'; +import Axios, { AxiosInstance, AxiosResponse, AxiosRequestConfig } from 'axios'; import { toast } from 'react-toastify'; export class Api { private axios: AxiosInstance; - constructor({ basePath }: { basePath: string } = { basePath: '' }) { - this.axios = Axios.create({ baseURL: `${basePath}api` }); + constructor({ basePath = '', clientOptions = {} }: { basePath: string, clientOptions: AxiosRequestConfig }) { + this.axios = Axios.create({ baseURL: `${basePath}api`, ...clientOptions }); this.axios.interceptors.response.use(this.handleResponse, this.handleError); } diff --git a/packages/ui/webpack.config.js b/packages/ui/webpack.config.js index 3eb0b667..d74155f3 100644 --- a/packages/ui/webpack.config.js +++ b/packages/ui/webpack.config.js @@ -98,6 +98,7 @@ module.exports = { templateParameters: { basePath, uiConfig: '<%- uiConfig %>', + clientOptions: '<%- clientOptions %>', title: '<%= title %>', favIconDefault: '<%= favIconDefault %>', favIconAlternative: '<%= favIconAlternative %>',