-
Notifications
You must be signed in to change notification settings - Fork 52
Description
I'm trying to setup AdminJS on a simple fastify backend, using typeorm and postges. I have been having issues getting a file upload to work, suggesting there is no id property set on the resource.
Following the example app for a single file, the upload form seems to work, but when I save it the backend gives the error:
{
"statusCode": 500,
"code": "ENOENT",
"error": "Internal Server Error",
"message": "ENOENT: no such file or directory, mkdir 'C:\\Users\\rw3iss\\Sites\\api-fastify\\public\\files\\id() {\n
const idProperty = this.resource.properties().find(p => p.isId());\n
if (!idProperty) {\n
throw new Error(`Resource: \"${this.resource.id()}\" does not have an id property`);\n
}\n
return this.params[idProperty.name()];\n }'"
}
relevant package.json dependency versions are:
"dependencies": {
"@adminjs/fastify": "^4.1.3",
"@adminjs/passwords": "^4.0.0",
"@adminjs/typeorm": "^5.0.1",
"@adminjs/upload": "^4.0.2",
"@fastify/session": "^10.9.0",
"adminjs": "^7.8.7",
"connect-pg-simple": "^9.0.1",
"fastify": "^4.28.1",
"pg": "^8.12.0",
}
The typeorm File entity is defined as:
import { BaseEntity, Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';
@Entity({ name: 'files' })
export class File extends BaseEntity {
@PrimaryGeneratedColumn()
public id: number;
@Column({ name: 'key', nullable: true, type: 'varchar' })
public key: string;
@Column({ nullable: true, type: 'varchar' })
public bucket: string;
@Column({ nullable: true, type: 'varchar' })
public mime: string;
@Column('int', { nullable: true })
public size: number;
@Column('varchar', { nullable: true })
public comment: string;
@CreateDateColumn({ name: 'created_at' })
public createdAt: Date;
@UpdateDateColumn({ name: 'updated_at' })
public updatedAt: Date;
}
export interface IFile {
id: number;
key: string;
bucket: string;
mime: string;
size: number;
comment: string | null;
}
The AdminJS File resource:
import uploadFeature from '@adminjs/upload';
import { BaseRecord } from 'adminjs';
import { File } from './../file.entity';
import { CreateResourceResult } from './CreateResourceResult';
const localUploadProvider = {
bucket: 'public/files',
opts: {
baseUrl: '/files',
},
};
export const createFileResource = (componentLoader): CreateResourceResult<typeof File> => ({
resource: File,
options: {
listProperties: ['id', 'key', 'bucket', 'path']
},
features: [
uploadFeature({
componentLoader,
provider: {
local: localUploadProvider
},
multiple: false,
properties: {
file: 'file',
filename: 'filename',
filePath: 'filePath',
filesToDelete: 'filesToDelete',
key: 'key',
mimeType: 'mime',
bucket: 'bucket',
size: 'size'
},
validation: {
mimeTypes: ['image/jpeg', 'image/png']
},
uploadPath: (record: BaseRecord, filename) => {
console.log(`get upload path`, record.id, filename);
return `${record.id}/${filename}`;
}
})
],
});
The AdminJS config/initialization is:
const app = Fastify({ logger: config.debug });
app.register(fastifyTypeorm, config.postgres);
app.register(fastifyStatic, {
root: path.join(import.meta.dirname, 'public'),
prefix: '/',
})
const componentLoader = new ComponentLoader();
const fileResource = createFileResource(componentLoader);
const admin = new AdminJS({
rootPath: '/admin',
componentLoader,
resources: [
fileResource
]
})
admin.watch();
await AdminJSFastify.buildAuthenticatedRouter(
admin,
{
authenticate,
cookiePassword: config.adminJs.cookieSecret,
cookieName: config.adminJs.cookieSecret,
},
app,
{
store: sessionStore as any,
saveUninitialized: true,
secret: config.adminJs.cookieSecret,
cookie: {
httpOnly: config.isProduction,
secure: config.isProduction
},
}
)
Here's a screenshot of the upload page after saving:

In trying to debug I notice the adminjs library tries to assign the properties, but it seems the id property never has _isId: true, I only ever see it false for any property, even after the property decoration is finished and merged:
PropertyDecorator {
property: Property {
_path: 'id',
_type: 'string',
_isId: false,
_isSortable: true,
_position: 1,
column: ColumnMetadata {
I've tried to add the isId: true property to the File resource id property, but it still never shows _isId: true anywhere.
{
resource: File,
options: {
listProperties: ['id', 'key', 'bucket', 'path'],
properties: {
id: {
isId: true
}
}, ...
Any ideas? I don't know if this an issue in the typeorm adapter or the adminjs BaseAdapter not loading those properties as expected, or maybe my config is wrong. I have been trying to dig further into the adminjs and upload feature code to see why. Still working it out...