Members
# actionType
Type of an action - could be either resource, record or bulk.
When you define a new action - it is required.
# after Optional
After action hook. When it is given - it is performed on the returned, by handler function response.
You can use it to (just an idea)
- create log of changes done in the app
- prefetch additional data after original Handler is being performed
Creating a changelog example:
// example mongoose model
const ChangeLog = mongoose.model('ChangeLog', mongoose.Schema({
// what action
action: { type: String },
// who
userId: { type: mongoose.Types.ObjectId, ref: 'User' },
// on which resource
resource: { type: String },
// was record involved (resource and recordId creates to polymorphic relation)
recordId: { type: mongoose.Types.ObjectId },
}, { timestamps: true }))
// actual after function
const createLog = async (originalResponse, request, context) => {
// checking if object doesn't have any errors or is a delete action
if ((request.method === 'post'
&& originalResponse.record
&& !Object.keys(originalResponse.record.errors).length)
|| context.action.name === 'delete') {
await ChangeLog.create({
action: context.action.name,
// assuming in the session we store _id of the current admin
userId: context.currentAdmin && context.currentAdmin._id,
resource: context.resource.id(),
recordId: context.record && context.record.id(),
})
}
return originalResponse
}
// and attaching this function to actions for all resources
const { ACTIONS } = require('admin-bro')
ACTIONS.edit.after = createLog
ACTIONS.delete.after = createLog
ACTIONS.new.after = createLog
# before Optional
Before action hook. When it is given - it is performed before the Action#handler method.
Example of hashing password before creating it:
actions: {
new: {
before: async (request) => {
if(request.payload.password) {
request.payload = {
...request.payload,
encryptedPassword: await bcrypt.hash(request.payload.password, 10),
password: undefined,
}
}
return request
},
}
}
# component Optional
Component which will be used to render the action. To pass the component use AdminBro.bundle method.
Action components accepts ActionProps and are rendered by the BaseActionComponent
When component is set to false
then action doesn't have it's own view.
Instead after clicking button it is immediately performed. Example of
an action without a view is module:DeleteAction.
# containerWidth Optional
The max width of action HTML container.
You can put here an actual size in px or an array of widths, where different values
will be responsible for different breakpoints.
It is directly passed to action's wrapping Box component, to its width
property.
Examples
// passing regular string
containerWidth: '800px'
// passing number for 100% width
containerWidth: 1
// passing values for different breakpoints
containerWidth: [1, 1/2, 1/3]
# guard Optional
guard message - user will have to confirm it before executing an action.
new AdminBro({ resources: [{
resource: Car,
options: { actions: {
delete: {
guard: 'doYouReallyWantToDoThis',
}
}}
}]})
What you enter there goes to TranslateFunctions#translateMessage function, so in order to define the actual message you will have to specify its translation in AdminBroOptions.Locale
# handler
handler function which will be invoked by either:
- ApiController#resourceAction
- ApiController#recordAction
- or ApiController#bulkAction when user visits clicks action link.
If you are defining this action for a record it has to return:
- ActionResponse for resource action
- RecordActionResponse for record action
- BulkActionResponse for bulk action
// Handler of a 'record' action
handler: async (request, response, context) {
const user = context.record
const Cars = context._admin.findResource('Car')
const userCar = Car.findOne(context.record.param('carId'))
return {
record: user.toJSON(context.currentAdmin),
}
}
Required for new actions. For modifying already defined actions like new and edit we suggest using Action#before and Action#after hooks.
# hideActionHeader Optional
Indicates if Action Header should be hidden. Action header consist of:
- breadcrumbs
- action buttons
- action title
# icon Optional
icon name for the action. Take a look Icon component, because what you put here is passed down to it.
new AdminBro({ resources: [{
resource: Car,
options: { actions: { edit: { icon: 'Add' } } },
}]})
# isAccessible Optional
Indicates if the action can be invoked for given invocation context. You can pass a boolean or function of type IsFunction, which takes ActionContext as an argument.
You can use it as a carrier between the hooks.
Example for isVisible function which allows the user to edit cars which belongs only to her:
const canEditCars = ({ currentAdmin, record }) => {
return currentAdmin && (
currentAdmin.role === 'admin'
|| currentAdmin._id === record.param('ownerId')
)
}
new AdminBro({ resources: [{
resource: Car,
options: { actions: { edit: { isAccessible: canEditCars } } }
}]})
- See:
-
- ActionContext parameter passed to isAccessible
- IsFunction exact type of the function
View Source admin-bro/src/backend/actions/action.interface.ts, line 237
# isVisible Optional
indicates if action should be visible for given invocation context.
It also can be a simple boolean value.
True
by default.
The most common example of usage is to hide resources from the UI.
So let say we have 2 resources User and Cars:
const User = mongoose.model('User', mongoose.Schema({
email: String,
encryptedPassword: String,
}))
const Car = mongoose.model('Car', mongoose.Schema({
name: String,
ownerId: { type: mongoose.Types.ObjectId, ref: 'User' },
})
so if we want to hide Users collection, but allow people to pick user when creating cars. We can do this like this:
new AdminBro({ resources: [{
resource: User,
options: { actions: { list: { isVisible: false } } }
}]})
In contrast - when we use Action#isAccessible instead - user wont be able to pick car owner.
- See:
-
- ActionContext parameter passed to isAccessible
- IsFunction exact type of the function
View Source admin-bro/src/backend/actions/action.interface.ts, line 201
# layout Optional
Definition for the layout. Works with the edit and show actions.
With the help of LayoutElement you can put all the properties to whatever layout you like, without knowing React.
This is an example of defining a layout
const layout = [{ width: 1 / 2 }, [
['@H3', { children: 'Company data' }],
'companyName',
'companySize',
]],
[
['@H3', { children: 'Contact Info' }],
[{ flexDirection: 'row', flex: true }, [
['email', { pr: 'default', flexGrow: 1 }],
['address', { flexGrow: 1 }],
]],
],
]
Alternatively you can pass a function taking CurrentAdmin as an argument. This will allow you to show/hide given property for restricted users.
To see entire documentation and more examples visit LayoutElement
# name
Name of an action which is its uniq key. If you use one of list, search, edit, new, show, delete or bulkDelete you override existing actions. For all other keys you create a new action.
# showFilter Optional
if filter should be visible on the sidebar. Only for resource actions
Example of creating new resource action with filter
new AdminBro({ resources: [{
resource: Car,
options: { actions: {
newAction: {
type: 'resource',
showFilter: true,
}
}}
}]})
# showInDrawer Optional
Indicates if given action should be seen in a drawer or in a full screen. Default to false
Type Definitions
# ActionContext
Execution context for an action. It is passed to the Action#handler, Action#before and Action#after functions.
Apart from the properties defined below it also extends TranslateFunctions. So you can use i.e. context.translateMessage(...) and others...
Properties:
Name | Type | Attributes | Description |
---|---|---|---|
{...} |
TranslateFunction | all functions from TranslateFunctions interface. |
|
_admin |
AdminBro | current instance of AdminBro. You may use it to fetch other Resources by their names: |
|
resource |
BaseResource | Resource on which action has been invoked. Null for dashboard handler. |
|
record |
BaseRecord |
<optional> |
Record on which action has been invoked (only for actionType === 'record') |
records |
Array.<BaseRecord> |
<optional> |
Records on which action has been invoked (only for actionType === 'bulk') |
h |
ViewHelpers | view helpers |
|
action |
ActionDecorator | Object of currently invoked function. Not present for dashboard action |
|
currentAdmin |
CurrentAdmin |
<optional> |
Currently logged in admin |
{...} |
any | Any custom property which you can add to context |
# async ActionHandler(request, response, context) → {Promise.<T>}
Type of a handler function. It has to return response compatible with ActionResponse, BulkActionResponse or RecordActionResponse
Parameters:
Name | Type | Description |
---|---|---|
request |
ActionRequest | |
response |
any | |
context |
ActionContext |
# ActionRequest
ActionRequest
Properties:
Name | Type | Attributes | Description |
---|---|---|---|
params |
object | parameters passed in an URL |
|
resourceId |
string | Id of current resource |
|
recordId |
string |
<optional> |
Id of current record (in case of record action) |
recordIds |
string |
<optional> |
Id of selected records (in case of bulk action) divided by commas |
action |
string | Name of an action |
|
query |
string |
<optional> |
an optional search query string (for |
{...} |
any | ||
payload |
Record.<string, any> |
<optional> |
POST data passed to the backend |
query |
Record.<string, any> |
<optional> |
Elements of query string |
method |
'post' | 'get' | HTTP method |
# ActionResponse
Base response for all actions
Properties:
Name | Type | Attributes | Description |
---|---|---|---|
notice |
NoticeMessage |
<optional> |
Notice message which should be presented to the end user after showing the action |
redirectUrl |
string |
<optional> |
redirect path |
{...} |
any | Any other custom parameter |
# async After(response, request, context)
Type of an after hook action.
Parameters:
Name | Type | Description |
---|---|---|
response |
T | Response returned by the default ActionHandler |
request |
ActionRequest | Original request which has been sent to ActionHandler |
context |
ActionContext | Invocation context |
# async Before(request, context) → {Promise.<ActionRequest>}
Before action hook. When it is given - it is performed before the ActionHandler method.
Parameters:
Name | Type | Description |
---|---|---|
request |
ActionRequest | Request object |
context |
ActionContext | Invocation context |
# BulkActionResponse
Required response of a Record action. Extends ActionResponse
Properties:
Name | Type | Description |
---|---|---|
records |
Array.<RecordJSON> | Array of RecordJSON objects. |
# IsFunction(context)
Defines the type of Action#isAccessible and Action#isVisible functions
Parameters:
Name | Type | Description |
---|---|---|
context |
ActionContext |
# LayoutElement
LayoutElement is used to change the default layout of edit, show and new actions. You define the layout as an Array.<LayoutElement> and AdminBro renders it with React components.
You don't have to know React to create usable Layout for you actions but be sure to take a look at the possible Props which can be used to style the components. The most often used props are BoxProps, because Box is the default wrapper.
Available values for a LayoutElement type
To Action#layout you have to pass an Array.<LayoutElement>. Where each LayoutElement could have a different type defining its position and purpose.
Type definition
Those are available types for LayoutElement
Type | Purpose | Example |
---|---|---|
string | It will be changed to the property in vertical layout | layout: ['name'] |
Array.<string> | It will be changed to the properties in vertical layout | layout: [['name', 'surname']] |
[string, BoxProps] | property wrapped by Box component with BoxProps | layout: [['name', {width: 1/2}]] |
[BoxProps, Array.<LayoutElement>] | Creates a Box and nest all the child LayoutElements inside. | layout: [[{width: 1/2}, ['name', 'surname']]] |
Array.<LayoutElement> | For grouping LayoutElements inside a wrapper | layout: [['name', {mt: 'xl'}], ['surname', , {ml: 'xl'}]] |
[@ComponentName, PropsWithChildren |
if you precede first item with "@" it will create component of this name | layout: [['@Header', {children: 'User Data'}]] |
Examples
Let say you have following properties in your database: companyName
, email
, address
and companySize
1. The simplest horizontal layout:
const layout = [
'companyName',
'email',
'address',
'companySize',
]
generates:
2. Now Wrap everything with a Box of 2/3
max width and horizontal margin (mx) set to auto. This will center all inputs
const layout = [
[{ width: 2 / 3, mx: 'auto' }, [
'companyName',
'email',
'address',
'companySize',
]],
]
generates:
Hint: you can also pass an array to
width
to define how it will behave in a different responsive breakpoints.
3. Add headers between sections
const layout = [
[{ width: 2 / 3, mx: 'auto' }, [
['@H3', { children: 'Company data' }],
'companyName',
'companySize',
['@H3', { children: 'Contact Info' }],
'email',
'address',
]],
]
generates:
To inject content inside the given Component pass children props to it.
4. Make email and address 50% width
We will wrap them with a Box (default component) which is a flex. Then we will have to wrap also each of them with extra box to define paddings.
I will also align to left top section that by removing { mx: auto }
and changing width to 1 / 2
.
const layout = [{ width: 1 / 2 }, [
['@H3', { children: 'Company data' }],
'companyName',
'companySize',
]],
[
['@H3', { children: 'Contact Info' }],
[{ flexDirection: 'row', flex: true }, [
['email', { pr: 'default', flexGrow: 1 }],
['address', { flexGrow: 1 }],
]],
],
]
generates:
5. Lastly, take a look at the example with a function instead of LayoutElement.
const layout = currentAdmin => ([
['@MessageBox', {
message: `Welcome ${currentAdmin && currentAdmin.email}`,
children: 'On this page yo can do whatever you like',
variant: 'info',
mb: 'xxl',
}],
[
'companyName',
'companySize',
'email',
'address',
],
])
Generates following Show page:
# LayoutElementFunction(currentAdminopt) → {Array.<LayoutElement>}
Function returning Array
Parameters:
Name | Type | Attributes | Description |
---|---|---|---|
currentAdmin |
CurrentAdmin |
<optional> |
# RecordActionResponse
Required response of a Record action. Extends ActionResponse
Properties:
Name | Type | Description |
---|---|---|
record |
RecordJSON | Record object. |