Skip to content
Merged

Beta #560

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions example-app/bin/setup-db.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const setupDb = async () => {

await Tool.create([...new Array(100)].map((el, index) => ({
name: `tool ${index}`,
description: null,
})))
}

Expand Down
19 changes: 19 additions & 0 deletions example-app/cypress/integration/nested/create-nested.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/// <reference types="cypress" />
/// <reference types="../../support" />

context('resources/Nested/actions/new', () => {
before(() => {
cy.login()
})

beforeEach(() => {
Cypress.Cookies.preserveOnce(Cypress.env('COOKIE_NAME'))
cy.visit('resources/Nested/actions/new')
})

it('fills name when button is clicked', () => {
cy.get('[data-testid="name-button"]').click()
cy.get('[data-testid="property-edit-name"] input')
.should('have.value', 'my new name')
})
})
11 changes: 11 additions & 0 deletions example-app/cypress/integration/tools/create-tool.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,22 @@ context('resources/Tool/actions/new', () => {
})

it('creates new tool by hitting enter instead of clicking submit', () => {
cy.server()
cy.route({ method: 'POST', url: 'admin/api/resources/Tool/actions/new' })
.as('apiNew')

const name = 'My Name'
cy.get('[data-testid="property-edit-name"]').type(`${name}{enter}`)

cy.wait('@apiNew').then((xhr) => {
const { record } = xhr.response.body
expect(record.params.description).to.be.undefined
expect(record.params.name).to.eq(name)
})

cy.location('pathname').should('eq', '/admin/resources/Tool')

// Remove the created record, because it brakes the pagination test otherwise.
cy.get('td[data-property-name="name"]').contains(name).parents('tr')
.find('[data-testid="actions-dropdown"]')
.trigger('mouseover')
Expand Down
28 changes: 28 additions & 0 deletions example-app/cypress/integration/tools/edit-tool.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/// <reference types="cypress" />
/// <reference types="../../support" />

context('resources/Tool/actions/edit', () => {
before(() => {
cy.login()
})

beforeEach(() => {
Cypress.Cookies.preserveOnce(Cypress.env('COOKIE_NAME'))
cy.visit('resources/Tool')
})

it('leaves null value in description when it was not alter', () => {
cy.get('[data-testid="property-list-name"]').last().click()
cy.get('[data-testid="action-edit"]').click()

cy.server()
cy.route({ method: 'POST', url: 'admin/api/resources/Tool/records/*/edit' })
.as('apiEdit')
cy.get('button[type="submit"]').click()

cy.wait('@apiEdit').then((xhr) => {
const { record } = xhr.response.body
expect(record.params.description).to.eq(null)
})
})
})
2 changes: 2 additions & 0 deletions example-app/src/admin.options.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const AdminTaggable = require('./taggables/taggable.admin')
const AdminProfession = require('./professions/profession.admin')
const AdminTool = require('./tools/tool.admin')
const AdminPage = require('./pages/page.admin')
const AdminNested = require('./nested/nested.admin')

AdminBro.bundle('./components/sidebar-footer', 'SidebarFooter')
AdminBro.bundle('./components/no-records', 'NoRecords')
Expand All @@ -27,6 +28,7 @@ const options = {
AdminTool,
AdminTaggable,
AdminPage,
AdminNested,
],
version: {
admin: true,
Expand Down
18 changes: 18 additions & 0 deletions example-app/src/nested/nested.admin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const { default: AdminBro } = require('admin-bro')
const { Nested } = require('./nested.entity')

/** @type {import('admin-bro').ResourceOptions} */
const options = {
properties: {
valueTrigger: {
components: {
edit: AdminBro.bundle('./value-trigger.component.tsx'),
},
},
},
}

module.exports = {
options,
resource: Nested,
}
26 changes: 26 additions & 0 deletions example-app/src/nested/nested.entity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const mongoose = require('mongoose')

const InnerElement = new mongoose.Schema({
name: {
type: String,
required: true,
},
})

const TopArrayElement = new mongoose.Schema({
innerObjects: {
type: [InnerElement],
required: true,
},
})

const NestedSchema = new mongoose.Schema({
name: {
type: String,
},
topObjects: [TopArrayElement],
})

const Nested = mongoose.model('Nested', NestedSchema)

module.exports = { ToolSchema: NestedSchema, Nested }
25 changes: 25 additions & 0 deletions example-app/src/nested/value-trigger.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react'
import { EditPropertyProps } from 'admin-bro'
import { Button, Box } from '@admin-bro/design-system'

const ValueTrigger: React.FC<EditPropertyProps> = (props) => {
const { onChange, record } = props

const handleClick = (): void => {
onChange({
...record,
params: {
...record.params,
name: 'my new name',
},
})
}

return (
<Box mb="xxl">
<Button data-testid="name-button" type="button" onClick={handleClick}>Set Name</Button>
</Box>
)
}

export default ValueTrigger
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "admin-bro",
"version": "3.0.1",
"version": "3.1.0-beta.4",
"description": "Admin panel for apps written in node.js",
"main": "index.js",
"types": "index.d.ts",
Expand Down
41 changes: 38 additions & 3 deletions spec/backend/helpers/resource-stub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,46 @@ import BaseProperty from '../../../src/backend/adapters/base-property'
import BaseResource from '../../../src/backend/adapters/base-resource'
import ResourceDecorator from '../../../src/backend/decorators/resource-decorator'

/**
* returns properties with following absolute paths:
* - normal: number
* - nested: mixed
* - nested.normal: string
* - nested.nested: mixed
* - nested.nested.normalInner: string
* - arrayed: string (array)
* - arrayedMixed: mixed (array)
* - arrayedMixed.arrayParam: string
*
* @private
*/
const buildProperties = (): Array<BaseProperty> => {
const normalProperty = new BaseProperty({ path: 'normal', type: 'number' }) as any
const nestedProperty = new BaseProperty({ path: 'nested', type: 'mixed' }) as any
const nested2Property = new BaseProperty({ path: 'nested', type: 'mixed' }) as any
const arrayProperty = new BaseProperty({ path: 'arrayed', type: 'string' }) as any
const arrayMixedProperty = new BaseProperty({ path: 'arrayedMixed', type: 'mixed' }) as any
arrayProperty.isArray = (): boolean => true
arrayMixedProperty.isArray = (): boolean => true

nestedProperty.subProperties = (): Array<BaseProperty> => [
new BaseProperty({ path: 'normal', type: 'string' }),
nested2Property,
]
nested2Property.subProperties = (): Array<BaseProperty> => [
new BaseProperty({ path: 'normalInner', type: 'string' }),
]
arrayMixedProperty.subProperties = (): Array<BaseProperty> => [
new BaseProperty({ path: 'arrayParam', type: 'string' }),
]

return [normalProperty, nestedProperty, arrayProperty, arrayMixedProperty]
}


export const expectedResult = {
id: 'someID',
properties: [...Array(10)].map((a, i) => new BaseProperty({
path: `property.${i}`, type: 'string',
})),
properties: buildProperties(),
resourceName: 'resourceName',
databaseName: 'databaseName',
databaseType: 'mongodb',
Expand Down
4 changes: 2 additions & 2 deletions src/admin-bro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { OverridableComponent } from './frontend/utils/overridable-component'
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'), 'utf-8'))
export const VERSION = pkg.version

const defaults: AdminBroOptionsWithDefault = {
export const defaultOptions: AdminBroOptionsWithDefault = {
rootPath: DEFAULT_PATHS.rootPath,
logoutPath: DEFAULT_PATHS.logoutPath,
loginPath: DEFAULT_PATHS.loginPath,
Expand Down Expand Up @@ -160,7 +160,7 @@ class AdminBro {
* @type {AdminBroOptions}
* @description Options given by a user
*/
this.options = _.merge({}, defaults, options)
this.options = _.merge({}, defaultOptions, options)

this.initI18n()

Expand Down
13 changes: 11 additions & 2 deletions src/backend/decorators/property-decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class PropertyDecorator {
* This path serves as a key in {@link PropertyOptions} to identify which
* property has to be updated
*/
private path: string
public path: string

private _admin: AdminBro

Expand Down Expand Up @@ -202,6 +202,15 @@ class PropertyDecorator {
return !!this.overrideFromOptions(AvailablePropertyOptions.isTitle)
}

/**
* If property should be disabled in the UI
*
* @return {boolean}
*/
isDisabled(): boolean {
return !!this.options.isDisabled
}

/**
* Returns JSON representation of a property
*
Expand All @@ -219,7 +228,7 @@ class PropertyDecorator {
isRequired: this.isRequired(),
availableValues: this.availableValues(),
name: this.name(),
isDisabled: !!this.options.isDisabled,
isDisabled: this.isDisabled(),
label: this.label(),
type: this.type(),
reference: this.property.reference(),
Expand Down
Loading