Skip to content

Instantly share code, notes, and snippets.

@Manoj-nathwani
Created March 24, 2021 14:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Manoj-nathwani/726615bcf0f3b9900b51cf14be618952 to your computer and use it in GitHub Desktop.
Save Manoj-nathwani/726615bcf0f3b9900b51cf14be618952 to your computer and use it in GitHub Desktop.
BulkFileUploaderComponent
import ReactDOM from 'react-dom';
import React from 'react';
import App from './src/App';
const componentElement =
document.getElementById('BulkFileUploaderComponent');
const getAttr = key => {
const val = componentElement.getAttribute(`data-${key}`);
return ['None', ''].includes(val) ? null : val;
};
const requiredString = str => {
console.assert(str.length);
return str;
}
const
lfsServer = requiredString(getAttr('lfsServer')),
orgId = requiredString(getAttr('orgId')),
datasetId = requiredString(getAttr('datasetId'));
// wait for ckan.i18n to load
window.addEventListener('load', function () {
ReactDOM.render(
<App {...{ lfsServer, orgId, datasetId }} />,
componentElement
);
})
import React, { useState, useEffect } from 'react';
import { Promise } from 'bluebird';
import axios from 'axios';
import FileUploader from './FileUploader';
export default function App({ lfsServer, orgId, datasetId }) {
const axiosHeaders = {
'Authorization': '<YOUR CKAN API KEY>'
};
const [authToken, setAuthToken] = useState();
useEffect(() => {
axios.post(
'/api/3/action/authz_authorize',
{ scopes: `obj:ckan/${datasetId}/*:write` },
{ withCredentials: true }
)
.then(res => setAuthToken(res.data.result.token))
.catch(error => {
console.log(`authz_authorize error: ${error}`);
setAuthToken('error')
})
}, []);
if (!authToken) return 'Loading...';
const handleFilesSelected = file => {
const files = [file];
// ckan can't handle concurrent resource uploads,
// so we're sequentially uploading each one
Promise.mapSeries(files, derp => (
axios({
method: 'POST',
url: 'http://dev-adr/api/3/action/resource_create',
data: {
package_id: datasetId,
url_type: 'upload',
name: file.name,
sha256: file.sha256,
size: file.size,
url: file.name,
lfs_prefix: `${orgId}/${datasetId}`,
},
headers: axiosHeaders
})
)).then(() => window.location.replace(window.location.pathname))
}
const handleDelete = () => {
axios({
method: 'GET',
url: 'http://dev-adr/api/3/action/package_show',
params: { id: datasetId },
headers: axiosHeaders
}).then(res => {
Promise.mapSeries(res.data.result.resources, resource => (
axios({
method: 'POST',
url: 'http://dev-adr/api/3/action/resource_delete',
data: { id: resource.id },
headers: axiosHeaders
})
)).then(() => window.location.replace(window.location.pathname));
});
}
return (
<>
<FileUploader {...{
lfsServer, orgId, datasetId, authToken,
handleFilesSelected
}} />
<button className="btn btn-default pull-right" onClick={handleDelete}>🔥 Delete all resources</button>
</>
);
}
import React from 'react';
import { useDropzone } from 'react-dropzone'
import { Client } from 'giftless-client';
export default function FileUploader({
lfsServer, orgId, datasetId, authToken, handleFilesSelected
}) {
const handleFileSelected = async inputFile => {
if (!inputFile) return;
const file = data.open(inputFile);
const client = new Client(lfsServer, authToken, ['basic']);
await client.upload(file, orgId, datasetId);
console.log(file);
handleFilesSelected({
name: file._descriptor.name,
sha256: file._computedHashes.sha256,
size: file._descriptor.size,
url: file._descriptor.name
})
}
const { getRootProps, getInputProps, open } = useDropzone({
multiple: false,
noClick: true,
onDrop: acceptedFiles =>
handleFileSelected(acceptedFiles[0]),
onDropRejected: rejectedFiles =>
handleFileSelected(rejectedFiles[0].file),
})
const uploadOptions = [
{
name: 'FileUploaderButton',
label: ckan.i18n._('Upload a file'),
icon: 'fa-cloud-upload',
onClick: e => {
open(e);
e.preventDefault();
}
}
]
return (
<div {...getRootProps({ className: 'dropzone' })} data-testid="FileUploaderComponent">
<input {...getInputProps()} data-testid="FileUploaderInput" />
<p>{ckan.i18n._('Drag a file into this box or')}</p>
<div className="btn-group">
{uploadOptions.map(option => (
<button
key={option.name}
data-testid={option.name}
className="btn btn-default"
onClick={option.onClick}
>
<i className={`fa ${option.icon}`}></i>
{option.label}
</button>
))}
</div>
</div>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment