Skip to content
This repository was archived by the owner on Nov 25, 2022. It is now read-only.

Group export #64

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 27 additions & 160 deletions admin/src/containers/ExportPage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,108 +3,20 @@
* ExportPage
*
*/

import React, { memo, useState, useMemo } from "react";
import React, { memo, useState } from "react";
import PropTypes from "prop-types";

import { Loader, Block, Row } from "../../components/common";
import { Select, Label, Button } from "@buffetjs/core";
import DataViewer from "../../components/DataViewer";

import FORMATS from "../../constants/formats";

import pluginId from "../../pluginId";
import { request } from "strapi-helper-plugin";
import { downloadFile, copyClipboard } from "../../utils/exportUtils";

import { Collapse } from "reactstrap";
import { FilterIcon } from "strapi-helper-plugin";
import BASE_OPTIONS from "../../constants/options";
import OptionsExport from "../../components/OptionsExport";

const exportFormatsOptions = FORMATS.map(({ name, mimeType }) => ({
label: name,
value: mimeType,
}));

function ImportPage({ contentTypes }) {
const [target, setTarget] = useState(null);
const [sourceExports, setSourceExports] = useState("");
const [exportFormat, setExportFormat] = useState("application/json");
const [contentToExport, setContentToExport] = useState("");

const sourceOptions = useMemo(
() =>
[{ label: "Select Export Source", value: "" }].concat(
contentTypes.map(({ uid, info, apiID }) => ({
label: info.label || apiID,
value: uid,
}))
),
[contentTypes]
);

// Source Options Handler
const handleSelectSourceExports = ({ target: { value } }) => {
setSourceExports(value);
setTarget(contentTypes.find(({ uid }) => uid === value));
setContentToExport("");
};

// Source Options Handler
const handleSelectExportFormat = ({ target: { value } }) => {
setExportFormat(value);
setContentToExport("");
};
import { Select, Label } from "@buffetjs/core";

// Options to exporting
const [isOptionsOpen, setIsOptionsOpen] = useState(false);
const [options, setOptions] = useState(
BASE_OPTIONS.reduce((acc, { name, defaultValue }) => {
acc[name] = defaultValue;
return acc;
}, {})
);
import SingleExport from "../SingleExport";
import GroupExport from "../GroupExport";

const handleChangeOptions = (option, value) => {
setOptions({
...options,
[option]: value,
});
};
function ExportPage({ contentTypes }) {
const [isLoading, setIsLoading] = useState(false);
const [exportType, setExportType] = useState("single");

// Request to Get Available Content
const [isLoading, setIsLoadig] = useState(false);
const getContent = async () => {
if (sourceExports === "")
return strapi.notification.toggle({
type: "warning",
message: "export.source.empty",
});

try {
setIsLoadig(true);
const { data } = await request(`/${pluginId}/export`, {
method: "POST",
body: { target, type: exportFormat, options },
});

setContentToExport(data);
} catch (error) {
strapi.notification.toggle({
type: "warning",
message: `export.items.error`,
});
}

setIsLoadig(false);
};

// Export Options
const handleDownload = () => {
downloadFile(target.info.name, contentToExport, exportFormat);
};
const handleCopy = () => copyClipboard(contentToExport);
const handleSelectExportType = ({ target: { value } }) => setExportType(value);

return (
<Block
Expand All @@ -113,83 +25,38 @@ function ImportPage({ contentTypes }) {
style={{ marginBottom: 12 }}
>
{isLoading && <Loader />}

<Row>
<div className="pt-3 col-sm-6 col-md-5">
<Label htmlFor="exportSource">Export Source</Label>
<Label htmlFor="exportSource">Export Type</Label>
<Select
name="exportSource"
options={sourceOptions}
value={sourceExports}
onChange={handleSelectSourceExports}
/>
</div>
<div className="pt-3 col-sm-6 col-md-5">
<Label htmlFor="exportFormat">Export Format</Label>
<Select
name="exportFormat"
options={exportFormatsOptions}
value={exportFormat}
onChange={handleSelectExportFormat}
/>
</div>
<div className="pt-3 col-md-2 d-flex flex-column-reverse">
<Button
onClick={() => setIsOptionsOpen((v) => !v)}
className="w-100"
icon={<FilterIcon />}
label="Options"
color="cancel"
/>
</div>
</Row>
<Row>
<div className="col-12">
<Collapse isOpen={isOptionsOpen}>
<OptionsExport values={options} onChange={handleChangeOptions} />
</Collapse>
</div>
</Row>
<Row>
<div className="col-12">
<DataViewer data={contentToExport} type={exportFormat} />
</div>
<div className="mt-3 col-md-4">
<Button
onClick={getContent}
className="w-100"
label="Get Data"
color="primary"
/>
</div>
<div className="mt-3 col-md-3 col-lg-2">
<Button
label="Download"
className="w-100"
color="success"
disabled={!contentToExport}
onClick={handleDownload}
/>
</div>
<div className="mt-3 col-md-3 col-lg-2">
<Button
className="w-100"
label="Copy to Clipboard"
color="secondary"
disabled={!contentToExport}
onClick={handleCopy}
options={[
{ label: "Single", value: 'single' },
{ label: "Group", value: 'group' },
]}
value={exportType}
onChange={handleSelectExportType}
/>
</div>
</Row>

{exportType === 'single' && (
<SingleExport contentTypes={contentTypes} setIsLoading={setIsLoading} />
)}
{exportType === 'group' && (
<GroupExport contentTypes={contentTypes} setIsLoading={setIsLoading} />
)}
</Block>
);
)
}

ImportPage.defaultProps = {
ExportPage.defaultProps = {
contentTypes: [],
};

ImportPage.propTypes = {
ExportPage.propTypes = {
contentTypes: PropTypes.array,
};

export default memo(ImportPage);
export default memo(ExportPage);
171 changes: 171 additions & 0 deletions admin/src/containers/GroupExport/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/*
*
* GroupExport
*
*/

import React, { memo, useState, useMemo } from "react";
import PropTypes from "prop-types";

import { Row } from "../../components/common";
import { Select, Label, Button, Checkbox } from "@buffetjs/core";

import pluginId from "../../pluginId";
import { request, auth } from "strapi-helper-plugin";

import { Collapse } from "reactstrap";
import { FilterIcon } from "strapi-helper-plugin";
import OptionsExport from "../../components/OptionsExport";
import useExportFormats from "../../hooks/useExportFormat";
import useExportOptions from "../../hooks/useExportOptions";

function GroupExport({ contentTypes, setIsLoading }) {
const [targets, setTargets] = useState(
contentTypes.reduce((acc, type) => ({
...acc, [type.uid]: {
enabled: true,
label: type.info.label || apiID,
}
}), {})
);

const {
exportFormat,
setExportFormat,
exportFormatsOptions,
} = useExportFormats();

const {
options,
isOptionsOpen,
setIsOptionsOpen,
updateOption,
} = useExportOptions();

const handleSelectExportFormat = ({ target: { value } }) => {
setExportFormat(value);
};

const getContent = async () => {
if (Object.keys(targets).every(uid => !targets[uid].enabled))
return strapi.notification.toggle({
type: "warning",
message: "export.source.empty",
});

try {
setIsLoading(true);

const token = auth.getToken();

const response = await fetch(`/${pluginId}/export-multi`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
targets: contentTypes.filter(({ uid }) => !!targets[uid].enabled),
type: exportFormat,
options
}),
});

if (response.status === 200) {
const blob = await response.blob();

const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `export.zip`;
document.body.appendChild(a);
a.click();
a.remove();
}
} catch (error) {
strapi.notification.toggle({
type: "warning",
message: `export.items.error`,
});
}

setIsLoading(false);
};

return (
<>
<Row>
<div className="pt-3 col-sm-12 col-md-12">
<Label htmlFor="exportSource">Export Source</Label>
{Object.keys(targets).map(current => {
return (
<div key={current} style={{ padding: "8px 8px 0px 8px" }}>
<Checkbox
name={current}
message={targets[current].label}
value={targets[current].enabled}
onChange={({ target: { value } }) => {
setTargets(prevState => ({
...prevState,
[current]: {
...targets[current],
enabled: value,
},
}));
}}
/>
</div>
);
})}
</div>
</Row>
<Row>
<div className="pt-3 col-sm-6 col-md-5">
<Label htmlFor="exportFormat">Export Format</Label>
<Select
name="exportFormat"
options={exportFormatsOptions}
value={exportFormat}
onChange={handleSelectExportFormat}
/>
</div>
<div className="pt-3 col-md-2 d-flex flex-column-reverse">
<Button
onClick={() => setIsOptionsOpen((v) => !v)}
className="w-100"
icon={<FilterIcon />}
label="Options"
color="cancel"
/>
</div>
</Row>
<Row>
<div className="col-12">
<Collapse isOpen={isOptionsOpen}>
<OptionsExport values={options} onChange={updateOption} />
</Collapse>
</div>
</Row>
<Row>
<div className="mt-3 col-md-4">
<Button
onClick={getContent}
className="w-100"
label="Download"
color="primary"
/>
</div>
</Row>
</>
);
}

GroupExport.defaultProps = {
contentTypes: [],
};

GroupExport.propTypes = {
contentTypes: PropTypes.array,
setIsLoading: PropTypes.func,
};

export default memo(GroupExport);
Loading