问题描述
我正在为Keystonejs Adminui(React应用程序)中的自定义字段中使用Tinymce.我想将图像从React Front上传到KeystoneJS GraphQl后面.我可以使用我添加到Keystone服务器的休息端点上传图像 - 传递Tinymce and images_upload_handler回调 - 但是我想利用Keystone的图像列表/类型IE HEE IMENGEN创建.
const getGQL = (theFile) => { const query = gql` mutation upload($file: Upload!) { createImage(file: $file) { id file { path filename } } } `; // The operation contains the mutation itself as "query" // and the variables that are associated with the arguments // The file variable is null because we can only pass text // in operation variables const operation = { query, variables: { file: null } }; // This map is used to associate the file saved in the body // of the request under "0" with the operation variable "variables.file" const map = { '0': ['variables.file'] }; // This is the body of the request // the FormData constructor builds a multipart/form-data request body // Here we add the operation, map, and file to upload const body = new FormData(); body.append('operations', JSON.stringify(operation)); body.append('map', JSON.stringify(map)); body.append('0', theFile); // Create the options of our POST request const opts = { method: 'post', url: 'http://localhost:4545/admin/api', body }; // @ts-ignore return axios(opts); };
但我不确定要通过theFile - tinymce的images_upload_handler,我需要从中调用图像上传,接受blobInfo对象,该对象包含函数以给我
文件名不起作用,斑点也没有 - 两者都给我服务器错误500-错误消息不是更具体的.
我更喜欢使用GraphQl客户端上传图像 - 又是另一篇文章A>建议使用 apollo-upload-client .但是,我在Keystonejs环境中运行,Apollo-Upload-Client说
阿波罗客户端只能有1个"终止" Apollo链接 GraphQL请求;如果已经设置了诸如Apollo-link-HTTP之类的人, 删除它.
我相信Keystone已经设置了Apollo-link-http(在搜索时多次出现),所以我认为我不能使用Apollo-upload-client.
推荐答案
UploadLink只是HttpLink的倒入替换.没有理由您不应该使用它.有一个Demo Keystonejs App 在这里
Looking at the 源代码,您应该能够使用自定义图像处理程序并在提供的blobInfo对象上调用blob.这样的东西: 我曾经有相同的问题,并使用Apollo上传链接解决了它.现在,当该应用进入生产阶段时,我意识到Apollo客户端拿了1/3个GZPICTED构建的文件,并且我创建了最小的GraphQl客户端,仅用于使用自动图像上传的Keystone使用.该软件包可在NPM中找到: https://www.npmjs.com//软件包/@sylchi/keystone-graphql-client 用法示例,如果有AVATAR字段设置为文件: 整个软件包仅为50loc,具有1个依赖关系:) 对我来说,轻松的方式是使用graphql-request.优势是您无需手动设置任何标头道具,并且它使用images_upload_handler的变量,例如de docs 描述. 我这样做了: 对于Keystone 5 EditorConfig会划分功能,因此我克隆了字段并将函数设置在views/Field.js文件中. 祝你好运( ^_ ^)/*tinymce.init({
images_upload_handler: async function (blobInfo, success, failure) {
const image = blobInfo.blob()
try {
await apolloClient.mutate(
gql` mutation($image: Upload!) { ... } `,
{
variables: { image }
}
)
success()
} catch (e) {
failure(e)
}
}
})
其他推荐答案
import { mutate } from '@sylchi/keystone-graphql-client'
const getFile = () => fetch('https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png',
{
mode: "cors",
cache: "no-cache"
})
.then(response => response.blob())
.then(blob => {
return new File([blob], "file.png", { type: "image/png" })
});
getFile().then(file => {
const options = {
mutation: `
mutation($id: ID!, $data: UserUpdateInput!){
updateUser(id: $id, data: $data){
id
}
}
`,
variables: {
id: "5f5a7f712a64d9db72b30602", //replace with user id
data: {
avatar: file
}
}
}
mutate(options).then(result => console.log(result));
});
其他推荐答案
const { request, gql} = require('graphql-request')
const query = gql`
mutation IMAGE ($file: Upload!) {
createImage (data:
file: $file,
}) {
id
file {
publicUrl
}
}
}
`
images_upload_handler = (blobInfo, success) => {
// ^ ^ varibles you get from tinymce
const variables = {
file: blobInfo.blob()
}
request(GRAPHQL_API_URL, query, variables)
.then( data => {
console.log(data)
success(data.createImage.fileRemote.publicUrl)
})
}
问题描述
I'm using TinyMCE in a custom field for the KeystoneJS AdminUI, which is a React app. I'd like to upload images from the React front to the KeystoneJS GraphQL back. I can upload the images using a REST endpoint I added to the Keystone server -- passing TinyMCE an images_upload_handler callback -- but I'd like to take advantage of Keystone's already-built GraphQL endpoint for an Image list/type I've created.
I first tried to use the approach detailed in this article, using axios to upload the image
const getGQL = (theFile) => { const query = gql` mutation upload($file: Upload!) { createImage(file: $file) { id file { path filename } } } `; // The operation contains the mutation itself as "query" // and the variables that are associated with the arguments // The file variable is null because we can only pass text // in operation variables const operation = { query, variables: { file: null } }; // This map is used to associate the file saved in the body // of the request under "0" with the operation variable "variables.file" const map = { '0': ['variables.file'] }; // This is the body of the request // the FormData constructor builds a multipart/form-data request body // Here we add the operation, map, and file to upload const body = new FormData(); body.append('operations', JSON.stringify(operation)); body.append('map', JSON.stringify(map)); body.append('0', theFile); // Create the options of our POST request const opts = { method: 'post', url: 'http://localhost:4545/admin/api', body }; // @ts-ignore return axios(opts); };
but I'm not sure what to pass as theFile -- TinyMCE's images_upload_handler, from which I need to call the image upload, accepts a blobInfo object which contains functions to give me
The file name doesn't work, neither does the blob -- both give me server errors 500 -- the error message isn't more specific.
I would prefer to use a GraphQL client to upload the image -- another SO article suggests using apollo-upload-client. However, I'm operating within the KeystoneJS environment, and Apollo-upload-client says
Apollo Client can only have 1 “terminating” Apollo Link that sends the GraphQL requests; if one such as apollo-link-http is already setup, remove it.
I believe Keystone has already set up Apollo-link-http (it comes up multiple times on search), so I don't think I can use Apollo-upload-client.
推荐答案
The UploadLink is just a drop-in replacement for HttpLink. There's no reason you shouldn't be able to use it. There's a demo KeystoneJS app here that shows the Apollo Client configuration, including using createUploadLink.
Actual usage of the mutation with the Upload scalar is shown here.
Looking at the source code, you should be able to use a custom image handler and call blob on the provided blobInfo object. Something like this:
tinymce.init({ images_upload_handler: async function (blobInfo, success, failure) { const image = blobInfo.blob() try { await apolloClient.mutate( gql` mutation($image: Upload!) { ... } `, { variables: { image } } ) success() } catch (e) { failure(e) } } })
其他推荐答案
I used to have the same problem and solved it with Apollo upload link. Now when the app got into the production phase I realized that Apollo client took 1/3rd of the gzipped built files and I created minimal graphql client just for keystone use with automatic image upload. The package is available in npm: https://www.npmjs.com/package/@sylchi/keystone-graphql-client
Usage example that will upload github logo to user profile if there is an user with avatar field set as file:
import { mutate } from '@sylchi/keystone-graphql-client' const getFile = () => fetch('https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png', { mode: "cors", cache: "no-cache" }) .then(response => response.blob()) .then(blob => { return new File([blob], "file.png", { type: "image/png" }) }); getFile().then(file => { const options = { mutation: ` mutation($id: ID!, $data: UserUpdateInput!){ updateUser(id: $id, data: $data){ id } } `, variables: { id: "5f5a7f712a64d9db72b30602", //replace with user id data: { avatar: file } } } mutate(options).then(result => console.log(result)); });
The whole package is just 50loc with 1 dependency :)
其他推荐答案
The easies way for me was to use graphql-request. The advantage is that you don't need to set manually any header prop and it uses the variables you need from the images_upload_handler as de docs describe.
I did it this way:
const { request, gql} = require('graphql-request') const query = gql` mutation IMAGE ($file: Upload!) { createImage (data: file: $file, }) { id file { publicUrl } } } ` images_upload_handler = (blobInfo, success) => { // ^ ^ varibles you get from tinymce const variables = { file: blobInfo.blob() } request(GRAPHQL_API_URL, query, variables) .then( data => { console.log(data) success(data.createImage.fileRemote.publicUrl) }) }
For Keystone 5 editorConfig would stripe out functions, so I clone the field and set the function in the views/Field.js file.
Good luck ( ^_^)/*