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

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
EdisonPeM committed Apr 10, 2021
2 parents 3f09797 + 69b3753 commit 0f915f9
Show file tree
Hide file tree
Showing 39 changed files with 1,817 additions and 40 deletions.
47 changes: 47 additions & 0 deletions admin/src/components/DataMapper/DataBody.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React, { memo } from "react";
import PropTypes from "prop-types";

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faTrashAlt } from "@fortawesome/free-solid-svg-icons";

function DataBody({ rows, headers, onDeleteItem, onlyFistRow }) {
return (
<tbody className={onlyFistRow ? "fist-row-selected" : ""}>
{rows.map((row, i) => (
<tr key={i}>
{headers.map((header, j) => {
const cell = row[header];

if (cell === undefined || cell === null) return <td key={j}>-</td>;

if (typeof cell === "object")
return <td key={j}>{JSON.stringify(cell)}</td>;

return <td key={j}>{`${cell}`}</td>;
})}
<td>
<button onClick={onDeleteItem(row)}>
<FontAwesomeIcon icon={faTrashAlt} />
</button>
</td>
</tr>
))}
</tbody>
);
}

DataBody.defaultProps = {
rows: [],
headers: [],
onDeleteItem: () => {},
onlyFistRow: false,
};

DataBody.propTypes = {
rows: PropTypes.array,
headers: PropTypes.array,
onDeleteItem: PropTypes.func,
onlyFistRow: PropTypes.bool,
};

export default memo(DataBody);
52 changes: 52 additions & 0 deletions admin/src/components/DataMapper/DataHeader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React, { memo } from "react";
import PropTypes from "prop-types";
import { Label, Select } from "@buffetjs/core";

function DataHeader({
headers,
headersOptions,
headersValues,
onSelectHeader,
}) {
return (
<thead>
<tr>
{headers.map((header) => (
<th key={header}>{header}</th>
))}
<th></th>
</tr>
<tr>
{headers.map((header) => (
<th key={header}>
<Label htmlFor={`map-${header}`}>
<Select
name={`map-${header}`}
options={headersOptions}
value={headersValues[header]}
onChange={onSelectHeader(header)}
/>
</Label>
</th>
))}
<th>Del</th>
</tr>
</thead>
);
}

DataHeader.defaultProps = {
headers: [],
headersOptions: [],
headersValues: {},
onSelectHeader: () => {},
};

DataHeader.propTypes = {
headers: PropTypes.array,
headersOptions: PropTypes.array,
headersValues: PropTypes.object,
onSelectHeader: PropTypes.func,
};

export default memo(DataHeader);
132 changes: 132 additions & 0 deletions admin/src/components/DataMapper/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import React, { useState, useMemo, memo } from "react";
import PropTypes from "prop-types";
import { Prompt } from "react-router-dom";

import { Row } from "../common";
import { TableWrapper } from "./styles";
import { Button } from "@buffetjs/core";

import DataHeader from "./DataHeader";
import DataBody from "./DataBody";

// FORMATS
// import {
// Bool as BoolIcon,
// Json as JsonIcon,
// Text as TextIcon,
// NumberIcon,
// Email as EmailIcon,
// Calendar as DateIcon,
// RichText as RichTextIcon,
// } from "@buffetjs/icons";

const filterIgnoreFields = (fieldName) =>
![
"id",
"created_at",
"created_by",
"updated_at",
"updated_by",
"published_at",
].includes(fieldName);

// TODO: Support Relations
const filterIgnoreTypes = (type) => !["relation", "dynamiczone"].includes(type);

function DataMapper({ data, mapper, onSuccess, onCancel }) {
const { fieldsInfo, parsedData } = data;
const { kind, attributes } = mapper;

const filteredAttributes = useMemo(
() =>
Object.keys(attributes)
.filter(filterIgnoreFields)
.filter((field) => filterIgnoreTypes(attributes[field].type)),
[attributes]
);

// Manipulation over maping columns
const [mappedFields, setMappedFields] = useState(
fieldsInfo.reduce((mappedFields, { fieldName }) => {
mappedFields[fieldName] = filteredAttributes.includes(fieldName)
? fieldName
: "none";
return mappedFields;
}, {})
);

const selectDestinationField = (source) => ({ target: { value } }) => {
setMappedFields({ ...mappedFields, [source]: value });
};

const destinationOptions = [{ label: "None", value: "none" }].concat(
filteredAttributes.map((field) => ({ label: field, value: field }))
);

// Manipulation over Rows
const [importItems, setImportItems] = useState(parsedData);
const deleteItem = (item) => () => {
const importItemsFiltered = importItems.filter(
(importItems) => importItems !== item
);
setImportItems(importItemsFiltered);
};

// UploadData
const handleUploadItems = () =>
onSuccess({ fields: mappedFields, items: importItems });

return (
<div className="pt-3 col-12">
<Prompt message="import.mapper.unsaved" />
<Row>
<h2>Map the Import Data to Destination Field</h2>
<TableWrapper>
<table>
<DataHeader
headers={fieldsInfo.map(({ fieldName }) => fieldName)}
headersOptions={destinationOptions}
headersValues={mappedFields}
onSelectHeader={selectDestinationField}
/>
<DataBody
onlyFistRow={kind === "singleType"}
rows={importItems}
headers={fieldsInfo.map(({ fieldName }) => fieldName)}
onDeleteItem={deleteItem}
/>
</table>
</TableWrapper>
</Row>
<Row>
Count of Items to Import:{" "}
<strong>{kind === "singleType" ? 1 : importItems.length}</strong>
</Row>
<Row>
<Button label="Import Data" onClick={handleUploadItems} />
<Button
className="ml-3"
label="Cancel"
color="delete"
onClick={onCancel}
/>
</Row>
</div>
);
}

DataMapper.defaultProps = {
data: {},
mapper: {},
onSuccess: () => {},
onCancel: () => {},
};

DataMapper.propTypes = {
data: PropTypes.any,
mapper: PropTypes.any,
onSuccess: PropTypes.func,
onCancel: PropTypes.func,
};

export default memo(DataMapper);
77 changes: 77 additions & 0 deletions admin/src/components/DataMapper/styles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import styled from "styled-components";

const TableWrapper = styled.div`
width: 100%;
overflow: auto;
background: white;
margin-top: 1rem;
border-radius: 4px;
border: 1px solid #e3e9f3;
max-height: 300px;
table {
width: 100%;
text-align: center;
th {
min-width: 15ch;
background-color: #f3f3f4;
font-weight: bold;
padding: 10px;
}
th:last-child {
min-width: 50px;
width: 50px;
}
td:last-child {
border-left: 1px solid #ccc;
max-width: 50px;
padding: 0;
button {
border: none;
outline: none;
padding: 15px;
background: transparent;
font-size: 1.2rem;
opacity: 0.5;
cursor: pointer;
&:hover {
opacity: 1;
}
}
}
tbody {
&.fist-row-selected {
tr:not(:first-child) {
color: #999;
}
}
tr {
&:nth-child(even) {
background-color: #fafafa;
}
&:hover {
background-color: #efefef;
}
}
td {
padding: 15px;
cursor: auto;
max-width: 15ch;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
`;

export { TableWrapper };
26 changes: 26 additions & 0 deletions admin/src/components/DataViewer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from "react";
import PropTypes from "prop-types";
import { Code } from "./styles";

import formatFileContent from "../../utils/formatFileContent";

function DataViewer({ data, type }) {
const content = formatFileContent({
content: data,
mimeType: type,
});

return <Code>{content}</Code>;
}

DataViewer.defaultProps = {
data: "",
type: "",
};

DataViewer.propTypes = {
data: PropTypes.string,
type: PropTypes.string,
};

export default DataViewer;
18 changes: 18 additions & 0 deletions admin/src/components/DataViewer/styles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import styled from "styled-components";

export const Code = styled.pre`
height: 200px;
width: 100%;
border-radius: 4px;
background: #1e1e1e;
color: #fafafa;
margin: 0;
padding: 1.2rem;
overflow: auto;
line-height: 2rem;
white-space: wrap;
cursor: auto;
`;
Loading

0 comments on commit 0f915f9

Please sign in to comment.