Skip to content

Commit

Permalink
fix: add with lib
Browse files Browse the repository at this point in the history
  • Loading branch information
MenahemOwlytics authored and blake-r committed Apr 25, 2023
1 parent c4bf7b8 commit 2fb7f69
Show file tree
Hide file tree
Showing 22 changed files with 364 additions and 20 deletions.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,6 @@ dist
.DS_store

# build files
/build
/lib
/types
.adminjs
example-app/.adminjs
66 changes: 66 additions & 0 deletions lib/components/ExportComponent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getExportedFileName = exports.mimeTypes = void 0;
const tslib_1 = require("tslib");
const react_1 = tslib_1.__importStar(require("react"));
const adminjs_1 = require("adminjs");
const design_system_1 = require("@adminjs/design-system");
const file_saver_1 = require("file-saver");
const exporter_type_1 = require("../exporter.type");
const format_1 = tslib_1.__importDefault(require("date-fns/format"));
exports.mimeTypes = {
json: 'application/json',
csv: 'text/csv',
xml: 'text/xml',
};
const getExportedFileName = (extension) => `export-${(0, format_1.default)(Date.now(), 'yyyy-MM-dd_HH-mm')}.${extension}`;
exports.getExportedFileName = getExportedFileName;
const ExportComponent = ({ resource }) => {
const filter = {};
const query = new URLSearchParams(location.search);
for (const entry of query.entries()) {
const [key, value] = entry;
if (key.match('filters.')) {
filter[key.replace('filters.', '')] = value;
}
}
const [isFetching, setFetching] = (0, react_1.useState)();
const sendNotice = (0, adminjs_1.useNotice)();
const exportData = async (type) => {
setFetching(true);
try {
const { data: { exportedData }, } = await new adminjs_1.ApiClient().resourceAction({
method: 'post',
resourceId: resource.id,
actionName: 'export',
params: {
type,
filter
},
});
const blob = new Blob([exportedData], { type: exports.mimeTypes[type] });
(0, file_saver_1.saveAs)(blob, (0, exports.getExportedFileName)(type));
sendNotice({ message: 'Exported successfully', type: 'success' });
}
catch (e) {
sendNotice({ message: e.message, type: 'error' });
}
setFetching(false);
};
if (isFetching) {
return <design_system_1.Loader />;
}
return (<design_system_1.Box>
<design_system_1.Box display="flex" justifyContent="center">
<design_system_1.Text variant="lg">Choose export format:</design_system_1.Text>
</design_system_1.Box>
<design_system_1.Box display="flex" justifyContent="center">
{exporter_type_1.Exporters.map(parserType => (<design_system_1.Box key={parserType} m={2}>
<design_system_1.Button onClick={() => exportData(parserType)} disabled={isFetching}>
{parserType.toUpperCase()}
</design_system_1.Button>
</design_system_1.Box>))}
</design_system_1.Box>
</design_system_1.Box>);
};
exports.default = ExportComponent;
49 changes: 49 additions & 0 deletions lib/components/ImportComponent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const react_1 = tslib_1.__importStar(require("react"));
const adminjs_1 = require("adminjs");
const design_system_1 = require("@adminjs/design-system");
const ImportComponent = ({ resource }) => {
const [file, setFile] = (0, react_1.useState)(null);
const sendNotice = (0, adminjs_1.useNotice)();
const [isFetching, setFetching] = (0, react_1.useState)();
const onUpload = (uploadedFile) => {
var _a;
setFile((_a = uploadedFile === null || uploadedFile === void 0 ? void 0 : uploadedFile[0]) !== null && _a !== void 0 ? _a : null);
};
const onSubmit = async () => {
if (!file) {
return;
}
setFetching(true);
try {
const importData = new FormData();
importData.append('file', file, file === null || file === void 0 ? void 0 : file.name);
await new adminjs_1.ApiClient().resourceAction({
method: 'post',
resourceId: resource.id,
actionName: 'import',
data: importData,
});
sendNotice({ message: 'Imported successfully', type: 'success' });
}
catch (e) {
sendNotice({ message: e.message, type: 'error' });
}
setFetching(false);
};
if (isFetching) {
return <design_system_1.Loader />;
}
return (<design_system_1.Box margin="auto" maxWidth={600} display="flex" justifyContent="center" flexDirection="column">
<design_system_1.DropZone files={[]} onChange={onUpload} multiple={false}/>
{file && (<design_system_1.DropZoneItem file={file} filename={file.name} onRemove={() => setFile(null)}/>)}
<design_system_1.Box display="flex" justifyContent="center" m={10}>
<design_system_1.Button onClick={onSubmit} disabled={!file || isFetching}>
Upload
</design_system_1.Button>
</design_system_1.Box>
</design_system_1.Box>);
};
exports.default = ImportComponent;
11 changes: 11 additions & 0 deletions lib/components/bundleComponents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.bundleComponents = void 0;
const tslib_1 = require("tslib");
const adminjs_1 = tslib_1.__importDefault(require("adminjs"));
const bundleComponents = () => {
const EXPORT_COMPONENT = adminjs_1.default.bundle('../../src/components/ExportComponent');
const IMPORT_COMPONENT = adminjs_1.default.bundle('../../src/components/ImportComponent');
return { EXPORT_COMPONENT, IMPORT_COMPONENT };
};
exports.bundleComponents = bundleComponents;
15 changes: 15 additions & 0 deletions lib/export.handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.exportHandler = void 0;
const parsers_1 = require("./parsers");
const utils_1 = require("./utils");
const exportHandler = async (request, response, context) => {
var _a, _b;
const parser = parsers_1.Parsers[(_b = (_a = request.query) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : 'json'].export;
const records = await (0, utils_1.getRecords)(context, request);
const parsedData = parser(records);
return {
exportedData: parsedData,
};
};
exports.exportHandler = exportHandler;
4 changes: 4 additions & 0 deletions lib/exporter.type.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Exporters = void 0;
exports.Exporters = ['csv', 'json', 'xml'];
16 changes: 16 additions & 0 deletions lib/import.handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.importHandler = void 0;
const tslib_1 = require("tslib");
const fs_1 = tslib_1.__importDefault(require("fs"));
const util_1 = tslib_1.__importDefault(require("util"));
const utils_1 = require("./utils");
const readFile = util_1.default.promisify(fs_1.default.readFile);
const importHandler = async (request, response, context) => {
const file = (0, utils_1.getFileFromRequest)(request);
const importer = (0, utils_1.getImporterByFileName)(file.name);
const fileContent = await readFile(file.path);
await importer(fileContent.toString(), context.resource);
return {};
};
exports.importHandler = importHandler;
27 changes: 27 additions & 0 deletions lib/importExportFeature.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const adminjs_1 = require("adminjs");
const bundleComponents_1 = require("./components/bundleComponents");
const utils_1 = require("./utils");
const export_handler_1 = require("./export.handler");
const import_handler_1 = require("./import.handler");
const { EXPORT_COMPONENT, IMPORT_COMPONENT } = (0, bundleComponents_1.bundleComponents)();
const importExportFeature = () => {
return (0, adminjs_1.buildFeature)({
actions: {
export: {
handler: (0, utils_1.postActionHandler)(export_handler_1.exportHandler),
component: EXPORT_COMPONENT,
actionType: 'resource',
showFilter: true
},
import: {
handler: (0, utils_1.postActionHandler)(import_handler_1.importHandler),
component: IMPORT_COMPONENT,
actionType: 'resource',
showFilter: true
},
},
});
};
exports.default = importExportFeature;
11 changes: 11 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"use strict";
/**
* @module @adminjs/import-export
* @subcategory Features
* @section modules
*/
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const importExportFeature_1 = tslib_1.__importDefault(require("./importExportFeature"));
tslib_1.__exportStar(require("./components/bundleComponents"), exports);
exports.default = importExportFeature_1.default;
8 changes: 8 additions & 0 deletions lib/modules/csv/csv.exporter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.csvExporter = void 0;
const json2csv_1 = require("json2csv");
const csvExporter = (records) => {
return (0, json2csv_1.parse)(records.map(r => r.params));
};
exports.csvExporter = csvExporter;
11 changes: 11 additions & 0 deletions lib/modules/csv/csv.importer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.csvImporter = void 0;
const tslib_1 = require("tslib");
const csvtojson_1 = tslib_1.__importDefault(require("csvtojson"));
const utils_1 = require("../../utils");
const csvImporter = async (csvString, resource) => {
const records = await (0, csvtojson_1.default)().fromString(csvString);
return (0, utils_1.saveRecords)(records, resource);
};
exports.csvImporter = csvImporter;
7 changes: 7 additions & 0 deletions lib/modules/json/json.exporter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.jsonExporter = void 0;
const jsonExporter = (records) => {
return JSON.stringify(records.map(r => r.params));
};
exports.jsonExporter = jsonExporter;
9 changes: 9 additions & 0 deletions lib/modules/json/json.importer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.jsonImporter = void 0;
const utils_1 = require("../../utils");
const jsonImporter = async (jsonString, resource) => {
const records = JSON.parse(jsonString);
return (0, utils_1.saveRecords)(records, resource);
};
exports.jsonImporter = jsonImporter;
17 changes: 17 additions & 0 deletions lib/modules/xml/xml.exporter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.xmlExporter = void 0;
const tslib_1 = require("tslib");
const xml_1 = tslib_1.__importDefault(require("xml"));
const xmlExporter = (records) => {
const data = records.map(record => ({
record: Object.entries(record.params).map(([key, value]) => ({
[key]: value,
})),
}));
return (0, xml_1.default)({ records: data }, {
indent: '\t',
declaration: true,
});
};
exports.xmlExporter = xmlExporter;
12 changes: 12 additions & 0 deletions lib/modules/xml/xml.importer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.xmlImporter = void 0;
const tslib_1 = require("tslib");
const xml2js_1 = tslib_1.__importDefault(require("xml2js"));
const utils_1 = require("../../utils");
const xmlImporter = async (xmlString, resource) => {
const parser = new xml2js_1.default.Parser({ explicitArray: false });
const { records: { record }, } = await parser.parseStringPromise(xmlString);
return (0, utils_1.saveRecords)(record, resource);
};
exports.xmlImporter = xmlImporter;
14 changes: 14 additions & 0 deletions lib/parsers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Parsers = void 0;
const json_exporter_1 = require("./modules/json/json.exporter");
const json_importer_1 = require("./modules/json/json.importer");
const csv_exporter_1 = require("./modules/csv/csv.exporter");
const xml_exporter_1 = require("./modules/xml/xml.exporter");
const csv_importer_1 = require("./modules/csv/csv.importer");
const xml_importer_1 = require("./modules/xml/xml.importer");
exports.Parsers = {
json: { export: json_exporter_1.jsonExporter, import: json_importer_1.jsonImporter },
csv: { export: csv_exporter_1.csvExporter, import: csv_importer_1.csvImporter },
xml: { export: xml_exporter_1.xmlExporter, import: xml_importer_1.xmlImporter },
};
65 changes: 65 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRecords = exports.getFileFromRequest = exports.postActionHandler = exports.getImporterByFileName = exports.saveRecords = void 0;
const adminjs_1 = require("adminjs");
const csv_importer_1 = require("./modules/csv/csv.importer");
const json_importer_1 = require("./modules/json/json.importer");
const xml_importer_1 = require("./modules/xml/xml.importer");
const saveRecords = async (records, resource) => {
return Promise.all(records.map(async (record) => {
try {
return await resource.create(record);
}
catch (e) {
console.error(e);
return e;
}
}));
};
exports.saveRecords = saveRecords;
const getImporterByFileName = (fileName) => {
if (fileName.includes('.json')) {
return json_importer_1.jsonImporter;
}
if (fileName.includes('.csv')) {
return csv_importer_1.csvImporter;
}
if (fileName.includes('.xml')) {
return xml_importer_1.xmlImporter;
}
throw new Error('No parser found');
};
exports.getImporterByFileName = getImporterByFileName;
const postActionHandler = (handler) => async (request, response, context) => {
if (request.method !== 'post') {
return {};
}
return handler(request, response, context);
};
exports.postActionHandler = postActionHandler;
const getFileFromRequest = (request) => {
var _a;
const file = (_a = request.payload) === null || _a === void 0 ? void 0 : _a.file;
if (!(file === null || file === void 0 ? void 0 : file.path)) {
throw new adminjs_1.ValidationError({
file: { message: 'No file uploaded' },
});
}
return file;
};
exports.getFileFromRequest = getFileFromRequest;
const getRecords = async (context, request) => {
var _a, _b, _c, _d, _e, _f;
const idProperty = (_b = (_a = context.resource
.properties()
.find(p => p.isId())) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.call(_a);
const titleProperty = (_d = (_c = context.resource.decorate().titleProperty()) === null || _c === void 0 ? void 0 : _c.name) === null || _d === void 0 ? void 0 : _d.call(_c);
return context.resource.find(new adminjs_1.Filter(((_e = request === null || request === void 0 ? void 0 : request.query) === null || _e === void 0 ? void 0 : _e.filter) ? JSON.stringify((_f = request === null || request === void 0 ? void 0 : request.query) === null || _f === void 0 ? void 0 : _f.filter) : {}, context.resource), {
limit: Number.MAX_SAFE_INTEGER,
sort: {
sortBy: idProperty !== null && idProperty !== void 0 ? idProperty : titleProperty,
direction: 'asc',
},
});
};
exports.getRecords = getRecords;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
}
},
"private": false,
"repository": "[email protected]/MenahemOwlytics/adminjs-import-export.git",
"repository": "[email protected]:MenahemOwlytics/adminjs-import-export.git",
"license": "SEE LICENSE IN LICENSE",
"scripts": {
"release": "semantic-release",
Expand Down
Loading

0 comments on commit 2fb7f69

Please sign in to comment.