-
Notifications
You must be signed in to change notification settings - Fork 730
Description
Contact Details
What happened?
Trying to implement a basic CRUD admin dashboard in my AdonisJS Typescript server. When attempting to update objects in DB and the update contains a datetime, an error occurs. The issue does not occur if the update's datetime is empty. The path for the below screenshot is http://localhost:3333/admin/resources/proposals/actions/new
Bug prevalence
Whenever I try to update datetime
AdminJS dependencies version
{
"name": "myproject",
"version": "0.0.0",
"private": true,
"type": "module",
"license": "UNLICENSED",
"scripts": {
"start": "node bin/server.js",
"build": "node ace build",
"dev": "node ace serve --watch",
"test": "node ace test",
"lint": "eslint .",
"format": "prettier --write .",
"typecheck": "tsc --noEmit"
},
"imports": {
"#controllers/": "./app/controllers/.js",
"#exceptions/": "./app/exceptions/.js",
"#models/": "./app/models/.js",
"#mails/": "./app/mails/.js",
"#services/": "./app/services/.js",
"#listeners/": "./app/listeners/.js",
"#events/": "./app/events/.js",
"#middleware/": "./app/middleware/.js",
"#validators/": "./app/validators/.js",
"#providers/": "./providers/.js",
"#policies/": "./app/policies/.js",
"#abilities/": "./app/abilities/.js",
"#database/": "./database/.js",
"#start/": "./start/.js",
"#tests/": "./tests/.js",
"#config/": "./config/.js"
},
"devDependencies": {
"@adonisjs/assembler": "^7.7.0",
"@adonisjs/eslint-config": "^1.3.0",
"@adonisjs/prettier-config": "^1.3.0",
"@adonisjs/tsconfig": "^1.3.0",
"@japa/api-client": "^2.0.3",
"@japa/assert": "^3.0.0",
"@japa/plugin-adonisjs": "^3.0.1",
"@japa/runner": "^3.1.4",
"@swc/core": "^1.6.5",
"@types/jsonwebtoken": "^9.0.10",
"@types/luxon": "^3.6.2",
"@types/node": "^20.14.9",
"@types/ws": "^8.18.1",
"eslint": "^8.57.0",
"hot-hook": "^0.2.6",
"nodemon": "^3.1.10",
"pino-pretty": "^11.2.1",
"prettier": "^3.3.2",
"ts-node": "^10.9.2",
"typescript": "~5.4"
},
"dependencies": {
"@adminjs/adonis": "^1.1.1",
"@adminjs/express": "^6.1.1",
"@adonisjs/auth": "^9.2.3",
"@adonisjs/core": "^6.12.1",
"@adonisjs/cors": "^2.2.1",
"@adonisjs/lucid": "^21.7.0",
"@adonisjs/session": "^7.5.1",
"@adonisjs/websocket": "^1.0.12",
"@vinejs/vine": "^2.1.0",
"adminjs": "^7.8.17",
"adonis-lucid-filter": "^5.2.0",
"axios": "^1.10.0",
"express": "^5.1.0",
"jsonwebtoken": "^9.0.2",
"luxon": "^3.7.1",
"mysql2": "^3.14.2",
"reflect-metadata": "^0.2.2",
"socket.io": "^4.8.1",
"stripe": "^18.3.0",
"ws": "^8.18.3"
},
"hotHook": {
"boundaries": [
"./app/controllers/**/.ts",
"./app/middleware/.ts"
]
},
"eslintConfig": {
"extends": "@adonisjs/eslint-config/app"
},
"prettier": "@adonisjs/prettier-config"
}
What browsers do you see the problem on?
Chrome
Relevant log output
[13:38:39.581] ERROR (8800): Invalid value for "Proposal.updatedAt". It must be an instance of "luxon.DateTime"
request_id: "qf2sjvyzzq2ddv2xdkfwl1j5"
x-request-id: "qf2sjvyzzq2ddv2xdkfwl1j5"
err: {
"type": "",
"message": "Invalid value for \"Proposal.updatedAt\". It must be an instance of \"luxon.DateTime\"",
"stack":
Exception: Invalid value for "Proposal.updatedAt". It must be an instance of "luxon.DateTime"
at Object.prepareDateTimeColumn [as prepare] (file:///C:/myproject/node_modules/@adonisjs/lucid/build/src/orm/decorators/date_time.js:41:11)
at file:///C:/myproject/node_modules/@adonisjs/lucid/build/src/orm/base_model/index.js:847:26
at Array.reduce (<anonymous>)
at Proxy.prepareForAdapter (file:///C:/myproject/node_modules/@adonisjs/lucid/build/src/orm/base_model/index.js:844:40)
at Proxy.save (file:///C:/myproject/node_modules/@adonisjs/lucid/build/src/orm/base_model/index.js:1419:52)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at Resource2.create (C:\myproject\node_modules\@adminjs\adonis\src\adapter\resource.ts:127:5)
at async BaseRecord.create (file:///C:/myproject/node_modules/adminjs/lib/backend/adapters/record/base-record.js:191:30)
at async Object.handler (file:///C:/myproject/node_modules/adminjs/lib/backend/actions/new/new-action.js:37:16)
at async ActionDecorator.handler (file:///C:/myproject/node_modules/adminjs/lib/backend/decorators/action/action-decorator.js:56:19)
at Object.handler (C:\myproject\node_modules\@adminjs\adonis\src\plugin\router.ts:130:28)
at SessionMiddleware.handle (C:\myproject\node_modules\@adonisjs\session\src\session_middleware.ts:81:22)
"name": "Exception",
"status": 500,
"code": "E_INVALID_DATE_COLUMN_VALUE"
}
// Possibly unrelated, but also getting many duplicate logs of the following message:
Unexpected type: int unsigned fallback to stringRelevant code that's giving you issues
// adonisrc.ts:
import { defineConfig } from '@adonisjs/core/app'
export default defineConfig({
/*
|--------------------------------------------------------------------------
| Commands
|--------------------------------------------------------------------------
|
| List of ace commands to register from packages. The application commands
| will be scanned automatically from the "./commands" directory.
|
*/
commands: [
() => import('@adonisjs/core/commands'),
() => import('@adonisjs/lucid/commands'),
() => import('adonis-lucid-filter/commands'),
],
/*
|--------------------------------------------------------------------------
| Service providers
|--------------------------------------------------------------------------
|
| List of service providers to import and register when booting the
| application
|
*/
providers: [
() => import('@adonisjs/core/providers/app_provider'),
() => import('@adonisjs/core/providers/hash_provider'),
{
file: () => import('@adonisjs/core/providers/repl_provider'),
environment: ['repl', 'test'],
},
() => import('@adonisjs/core/providers/vinejs_provider'),
() => import('@adonisjs/cors/cors_provider'),
() => import('@adonisjs/lucid/database_provider'),
() => import('@adonisjs/auth/auth_provider'),
() => import('adonis-lucid-filter/provider'),
() => import('@adonisjs/session/session_provider'),
{
file: () => import('@adminjs/adonis/adminjs_provider'),
environment: ['web'],
},
() => import('./app/providers/socket_provider.js'),
],
/*
|--------------------------------------------------------------------------
| Preloads
|--------------------------------------------------------------------------
|
| List of modules to import before starting the application.
|
*/
preloads: [
() => import('#start/routes'),
() => import('#start/kernel'),
],
/*
|--------------------------------------------------------------------------
| Tests
|--------------------------------------------------------------------------
|
| List of test suites to organize tests by their type. Feel free to remove
| and add additional suites.
|
*/
tests: {
suites: [
{
files: ['tests/unit/**/*.spec(.ts|.js)'],
name: 'unit',
timeout: 2000,
},
{
files: ['tests/functional/**/*.spec(.ts|.js)'],
name: 'functional',
timeout: 30000,
},
],
forceExit: false,
},
})
// app/admin/auth.ts:
import { CurrentAdmin, DefaultAuthProvider, DefaultAuthenticatePayload } from 'adminjs'
import componentLoader from './component_loader.js'
import User from '#models/user'
import hash from '@adonisjs/core/services/hash'
const authenticate = async ({
email,
password,
}: DefaultAuthenticatePayload): Promise<CurrentAdmin | null> => {
const user = await User.findBy('email', email)
if (!user) {
return null // not found
}
const isValid = await hash.verify(user.password, password)
if (!isValid) {
return null // invalid password
}
return {
email: user.email,
id: user.id.toString(),
}
}
const authProvider = new DefaultAuthProvider({
componentLoader,
authenticate,
})
export default authProvider
// app/admin/component_loader.ts:
import { ComponentLoader } from 'adminjs'
const componentLoader = new ComponentLoader()
export default componentLoader
// config/adminjs.ts:
import { AdminJSProviderConfig, LucidResource } from '@adminjs/adonis'
import {} from '@adminjs/adonis'
import componentLoader from '../app/admin/component_loader.js'
import authProvider from '../app/admin/auth.js'
import Answer from '#models/answer'
import Category from '#models/category'
import Choice from '#models/choice'
import Customer from '#models/customer'
import Job from '#models/job'
import Payment from '#models/payment'
import Professional from '#models/professional'
import Proposal from '#models/proposal'
import Question from '#models/question'
import Service from '#models/service'
import User from '#models/user'
import Warning from '#models/warning'
import FavoritedService from '#models/favorited_service'
import ServiceAllowedProfessionalTypes from '#models/service_allowed_professional_types'
const adminjsConfig: AdminJSProviderConfig = {
adapter: {
enabled: true,
},
adminjs: {
rootPath: '/admin',
loginPath: '/admin/login',
logoutPath: '/admin/logout',
componentLoader,
resources: [
new LucidResource(Answer, 'mysql'),
new LucidResource(Category, 'mysql'),
new LucidResource(Choice, 'mysql'),
new LucidResource(Customer, 'mysql'),
new LucidResource(FavoritedService, 'mysql'),
new LucidResource(Job, 'mysql'),
new LucidResource(Payment, 'mysql'),
new LucidResource(Professional, 'mysql'),
new LucidResource(Proposal, 'mysql'),
new LucidResource(Question, 'mysql'),
new LucidResource(Service, 'mysql'),
new LucidResource(ServiceAllowedProfessionalTypes, 'mysql'),
new LucidResource(User, 'mysql'),
new LucidResource(Warning, 'mysql'),
],
pages: {},
locale: {
availableLanguages: ['en'],
language: 'en',
translations: {
en: {
actions: {},
messages: {},
labels: {},
buttons: {},
properties: {},
components: {},
pages: {},
ExampleResource: {
actions: {},
messages: {},
labels: {},
buttons: {},
properties: {},
},
},
},
},
branding: {
companyName: 'AdminJS',
theme: {},
},
settings: {
defaultPerPage: 10,
},
},
auth: {
enabled: true,
provider: authProvider,
middlewares: [],
},
middlewares: [],
}
export default adminjsConfig