Closed Nikhiladiga closed 4 years ago
Right now we don't have an out-of-the-box solution for uploading files. To achieve that you have to override custom field: check out https://softwarebrothers.github.io/admin-bro-dev/tutorial-04-customizing-resources.html
@wojtek-krysiak Hi there would it be possible for you to provide a code example for image upload? I've tried to override that by using a simple text input and uploading a base64 but it kinda destroys everything.. PayloadTooLargeError. it can be solved, using app.use(bodyParser.json({ limit: "50mb" })) but still problematic
I've managed to add quilljs based on your example, is it possible to customize it and allow to add an image through the wysiwyg?
cheers
DT
working on the upload plugin right now. It should be ready at the weekend.
@wojtek-krysiak awesome, cheers for that!
@wojtek-krysiak I can't wait for it xD.
@wojtek-krysiak Hello, could you please update regarding the new feature eta? just need to plan dev on my end :-) Cheers
DT
Hi @wojtek-krysiak can I use the plugin now?
Hi @wojtek-krysiak, did you get the chance to complete this feature?
cheers
DT
Sorry for the late response.
So - I have one bad and one good news.
The bad: Unfortunately, we decided not to build a full-featured upload plugin because it will require to handle different storages (AWS S3, local file system etc).
The good: That is why we added DropArea
component and change a way of how data is sent from the frontend to the API (from application-json to multipart) so files can be handled easily. Everything is in beta and we are still testing it - so in order to try it out you have to install:
"admin-bro": "^1.5.0-beta.5",
"admin-bro-expressjs": "^0.4.0-beta.2",
and install express-formidable
- since it is now a peerDependency
for admin-bro-expressjs
This is am actual component code in typescript we use:
import React, { FC } from 'react';
import { unflatten } from 'flat';
import { BasePropertyProps, DropArea, PropertyInEdit } from 'admin-bro';
import { MIME_TYPES, MAX_SIZE } from '../../../photo/photo.constants';
const EditImageProperty: FC<BasePropertyProps> = ({ property, record, onChange }) => {
const params = unflatten(record.params);
const fileObject = params.filename ? {
name: params.filename,
size: params.size,
type: params.mimeType,
file: params.file,
} : null;
const onUpload = (files: FileList): void => {
const newRecord = { ...record };
const [file] = files;
onChange({
...newRecord,
params: {
...newRecord.params,
file,
filename: file.name,
size: file.size,
mimeType: file.type,
},
});
};
return (
<PropertyInEdit property={property}>
<DropArea
fileObject={fileObject}
onUpload={onUpload}
propertyName={property.name}
validate={{
mimeTypes: MIME_TYPES,
maxSize: MAX_SIZE,
}}
/>
</PropertyInEdit>
);
};
export default EditImageProperty;
example validation consts:
export const MIME_TYPES = ['image/jpeg', 'image/gif', 'image/tiff', 'image/png'];
export const MAX_SIZE = 1024 * 5000; // 5 MB;
and after hook for new
and edit
actions:
const uploadFile = async (
response: NewActionResponse | EditActionResponse,
request,
context,
): Promise<NewActionResponse> => {
const { record } = context;
const { payload } = request;
if (record.isValid() && payload?.file) {
const { file } = payload;
// here is the logic for uploading to S3 (in our case) - but you also can write this to
// hdd or whatever else... file is a formidable object
const photo = await service.findAndUpdateFileInfo(+record.id(), file);
return {
...response,
record: new BaseRecord(photo, context.resource).toJSON(context.currentAdmin),
};
}
return response;
};
file is a formidable object which has this interface: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/formidable/index.d.ts#L47
path
is there the most important property - it is the path to tmp file created by formidable.
After more tests I will publish this as a stable release and add documentation.
If you have any issues - let me know.
and don't forget that in delete hook you will have to remove the file :)
@wojtek-krysiak cheers for that! Will give it a try
@wojtek-krysiak thanks for this great work!
I just start to use it, but I come across a few errors. Here is my error:
import React, { FC } from 'react';
Module "
xxx/xxx/my-admin-app/node_moudles/react` has no exported memeber 'FC'
Here are my steps:
yarn add admin-bro@1.5.0-beta.5
yarn add admin-bro-expressjs@0.4.0-beta.2
yarn add express-formidable
const adminBro = new AdminBro({
resources: [User, Admin,
{ resource: WireFrame, options: {
actions: {
show: {
label: 'Show me that',
icon: 'fas fa-eye',
// isVisible: (resource, record) => record.param('email') !== '',
isVisible: true
},
newAction: {
actionType: ['record'],
label: 'Publish',
icon: 'fas fa-eye',
isVisible: true,
handler: async (request, response, data) => {
return {
record: data.record.toJSON()
}
},
component: AdminBro.bundle('./components/upload_action_compontent')
},
} ,
listProperties: ['name', 'version']}
}],
rootPath: '/admin',
})
See the errors. Not sure the file format should be .ts, or anything I missed, thanks a lot!
Hi, the example was written in typescript :) - FC is a type.
if you use raw JS in your project this code has to be transpiled. If you don't like to do this manually you can use http://www.typescriptlang.org/play/index.html.
The other solution would be to leave typescript on the components but you will have to install @types/react
:
yarn add --dev @types/react
Wojciech, there is the typo in the drop-area.tsx
file.
line 253: <h1>Dop Here</h1>
@wojtek-krysiak than you in advance for your awesome admin panel! I have an issue uploading images with your comented component in the live demo code example. The component put inside the record params the file info with the upload function.
const newRecord = {...record}
const [file] = files
console.log('valor de record después del onChange', file)
onChange({
...newRecord,
params: {
...newRecord.params,
[`${property.name}.file`]: file,
[`${property.name}.name`]: file.name,
[`${property.name}.size`]: file.size,
[`${property.name}.type`]: file.type,
}
})
event.preventDefault()
}
but when you get the payload inthe upload.js uploadphoto.file is always empty and I don't now why... any suggestions? thank you!
@wojtek-krysiak than you in advance for your awesome admin panel! I have an issue uploading images with your comented component in the live demo code example. The component put inside the record params the file info with the upload function.
const newRecord = {...record} const [file] = files console.log('valor de record después del onChange', file) onChange({ ...newRecord, params: { ...newRecord.params, [`${property.name}.file`]: file, [`${property.name}.name`]: file.name, [`${property.name}.size`]: file.size, [`${property.name}.type`]: file.type, } }) event.preventDefault() }
but when you get the payload inthe upload.js uploadphoto.file is always empty and I don't now why... any suggestions? thank you!
take a look on the example app code. It's commented, but still it should work. https://github.com/SoftwareBrothers/admin-bro-example-app/blob/master/admin/components/upload-photo.tsx
Hi, @dmitryLagoda I'm using this component too... Into the component I have the file info, but when it arrives to the file "upload.js" the file info is empty inside the payload... I put everything like the code example, and I got a file write into the folder that I want, but the file is empty, because the file info into the payload is empty. I don't now why! Have you use the example and does it work for you? Thank you!
@MariaRoblesSpin these are my files, and file uploading work fine for me. Also, please ensure you use the latest AdminBro version, they fixed file uploading in 1.6.3
ImageUpload.jsx
import React, { useState } from 'react'
import { DropArea, PropertyInEdit, BasePropertyProps } from 'admin-bro'
import { unflatten } from 'flat'
const TJImageUpload = (props) => {
const { property, record, onChange } = props
const fileObject = unflatten(record.params)[property.name]
const onUpload = (files) => {
const newRecord = {...record}
const [file] = files
onChange({
...newRecord,
params: {
...newRecord.params,
file: file,
name: file.name,
size: file.size,
type: file.type,
}
})
event.preventDefault()
}
return (
<PropertyInEdit property={property}>
<DropArea
fileObject={fileObject}
onUpload={onUpload}
propertyName={property.name}
/>
</PropertyInEdit>
)
}
export default TJImageUpload;
handler for uploaded image
actions: {
new: {
after: uploadImageHandler
},
}
const uploadImageHandler = async (response, request, context) => {
const { record } = context;
const { payload } = request;
const recordData = flat.unflatten(payload);
// console.log(recordData)
if (!(record.isValid() && recordData && recordData.image && recordData.image.file)) {
return response;
}
const { file } = recordData.image;
console.log(file)
};
@dmitryLagoda thank you very much! I have to download the latest version! What a silly thing!
ReferenceError: flat is not defined
backend | at Object.uploadImageHandler [as after] (/app/adminbro.js:16:21)
backend | at ActionDecorator.handler (/app/node_modules/admin-bro/lib/backend/decorators/action-decorator.js:69:31)
backend | at processTicksAndRejections (internal/process/task_queues.js:97:5)
backend | at async handler (/app/node_modules/admin-bro-expressjs/plugin.js:56:22)
This is what I get from the above code
made some progress. https://www.npmjs.com/package/flat
Is there a way i can upload images while working with express? And i'm not using any frame work, just the ejs templating engine
take a look at this screencast: https://www.youtube.com/watch?v=7WtKcFqJHho it shows you how to add file upload to AdminBro with expressjs
How do upload image & send that image (in email via sendgrid) from a custom resource?
I dont see any option to do that as there is not record there, its just a custom page.
How do upload multiple images in adminbro and save them?
How do upload multiple images in adminbro and save them?
I also try to modify for upload multiple files...
take a look at @admin-bro/upload feature
Using @admin-bro/upload, I was only able to upload single images. The file-picker that opens after clicking on the DropZone forces me to select one image only. Is there any guide to select multi images?
@mohamed-nazmi
https://github.com/SoftwareBrothers/admin-bro-upload/blob/beta/src/index.doc.md
this is the latest beta with multi upload - but you have tot have it installed with the latest beta of admin-bro
Although I have installed
And added the following upload feature:
features: [
uploadFeature({
provider: {
aws: {
bucket: config.s3.bucket,
accessKeyId: config.s3.accessKeyId,
secretAccessKey: config.s3.secretAccessKey,
region: config.s3.region
}
},
properties: {
key: 'path',
filePath: 'imagePaths'
},
validation: {
mimeTypes: ['image/png', 'image/jpg', 'image/jpeg']
},
multiple: true
})
]
But still the DropZone allows me to select only one image!
And when I try to customize uploading images in the old way, the array of images fails to be passed to the request's payload. Here is a sample of my customized React component:
import React, { FC } from 'react';
import { BasePropertyProps, Box, DropZone, Label, OnDropZoneChange } from 'admin-bro';
const Image: FC<BasePropertyProps> = (props) => {
const { property, record, onChange } = props;
const onUpload: OnDropZoneChange = (files: File[]) => {
const newRecord = { ...record };
onChange({
...newRecord,
params: {
...newRecord.params,
[property.name]: files
}
});
event.preventDefault();
};
return (
<Box>
<Label>{property.label}</Label>
<DropZone
multiple
onChange={onUpload}
validate={{ mimeTypes: ['image/png', 'image/jpg', 'image/jpeg'] }}/>
</Box>
);
};
export default Image;
latest upload is "@admin-bro/upload": "^1.2.0-beta.3",
Using
And with the following code:
features: [
uploadFeature({
provider: {
aws: {
bucket: config.s3.bucket,
accessKeyId: config.s3.accessKeyId,
secretAccessKey: config.s3.secretAccessKey,
region: config.s3.region
}
},
properties: {
key: 'keys',
filePath: 'imagePaths'
},
validation: {
mimeTypes: ['image/png', 'image/jpg', 'image/jpeg']
},
multiple: true
})
]
I get the following error:
Error: You cannot upload file for not persisted record. Save record first
at Object.exports.buildRemotePath (C:\Users\Mohamed\Desktop\Self\Identity\Projects\alexengsyndicate-backend\node_modules\@admin-bro\upload\build\features\upload-file\utils\build-remote-path.js:22:15)
at Promise.all.uploadedFiles.map (C:\Users\Mohamed\Desktop\Self\Identity\Projects\alexengsyndicate-backend\node_modules\@admin-bro\upload\build\features\upload-file\factories\update-record-factory.js:36:53)
at Array.map (<anonymous>)
at updateRecord (C:\Users\Mohamed\Desktop\Self\Identity\Projects\alexengsyndicate-backend\node_modules\@admin-bro\upload\build\features\upload-file\factories\update-record-factory.js:35:62)
at prevPromise.then.modifiedResponse (C:\Users\Mohamed\Desktop\Self\Identity\Projects\alexengsyndicate-backend\node_modules\admin-bro\lib\backend\decorators\action\action-decorator.js:147:99)
at process._tickCallback (internal/process/next_tick.js:68:7)
Can you please give a full example for a multiple upload?
do you have some db validations - maybe they fail - like required name
field or whatever????
No, the error is still found even when I remove all model validations. Anyway, my model is here:
const NewsSchema: Schema = new Schema({
title: {
type: String,
required: true
},
content: {
type: String,
required: true
},
keys: [{
type: String
}],
imagePaths: [{
type: String
}]
}, { timestamps: true });
Do the "key" and "filePath" in the properties of the upload feature should have values that are attribute names in the model?
yes - in your case keys
and filePaths
. But it, you know it is still in beta, and we tested it a lot on typeorm and sequelize, but haven't on mongoose. There was an error in mongoose where it didn't update a record after update and this might cause the error. Can you bump up it to the latest version?
also, the error is triggered here: https://github.com/SoftwareBrothers/admin-bro-upload/blob/a68bfa23f85d1d6ecfd22e225d76191237d0b88e/src/features/upload-file/factories/update-record-factory.ts#L67-L67
it is thrown because reocrd.id() returns null for some reason. Can you debug why this happens (you can put console.log(record.params)
Hey @wojtek-krysiak ,
I've got the same error using NestJS with TypeORM and Admin-Bro.
"@admin-bro/typeorm": "^1.4.0-beta.1",
"@admin-bro/upload": "^1.2.0-beta.8",
"admin-bro": "^3.3.0-beta.33",
The model looks like this:
@Entity({
name: 'product'
})
export class Product extends BaseEntity {
@ObjectIdColumn()
_id: ObjectID
@Column()
keys: string[]
@Column()
imagePaths: string[]
}
The output of console.log(record.params) is:
{ '_id._bsontype': 'ObjectID',
'_id.id': <Buffer 5f 96 bb de b7 72 6d 17 92 50 66 72> }
Adding an additional @PrimaryColumn() to the MongoDB Entity doesn't help.
Are there any news on this bug?
Friendly Regards Nico :)
@Nico205 this is a @admin-bro/typeorm issue related to mongodb - can you post this error in https://github.com/SoftwareBrothers/admin-bro-typeorm?
so custom componenet dont work for me "....undefined"... so i try to do uploadFeature but why its not give me a dropzone fieldd ?
`const options = { image: { options: { listProperties: ["image", "mimeType"], },
features: [
uploadFeature({
provider: {
aws: {
accessKeyId: process.env.S3_ACCESS_KEY,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
region: "EU (London) eu-west-2",
bucket: "battttkol",
},
},
properties: {
key: "image", // to this db field feature will safe S3 key,
mimeType: "mimeType", // this property is important because allows to have previews,
},
validation: {
mimeTypes: ["image/png", "image/jpg", "image/jpeg"],
},
multiple: true,
}),
],
},
}; `
hello friends please help me I am fresh for node and adminbro I have developed front end application using ejs, and now I would like to write a code for backend using node js. which one is good ......admin panel templet or just coding from scratch? When I am using adminbro their is a lot of errors for uploading images.
How to upload to cloudinary ? Do we have plan for it ? Thanks.
Is there no way to upload files like images in the admin panel?