From 738ed19e7fd6cbcc592a23977ce4ce66bb23484a Mon Sep 17 00:00:00 2001 From: Christoph Enne Date: Fri, 16 Dec 2022 23:48:06 +0100 Subject: [PATCH] feat: Trello board JSON import (#352) Closes #27, closes #105 --- client/src/api/boards.js | 5 + client/src/components/Boards/AddPopup.jsx | 70 -------- .../components/Boards/AddPopup.module.scss | 5 - .../components/Boards/AddPopup/AddPopup.jsx | 116 +++++++++++++ .../Boards/AddPopup/AddPopup.module.scss | 42 +++++ .../components/Boards/AddPopup/ImportStep.jsx | 51 ++++++ .../Boards/AddPopup/ImportStep.module.scss | 17 ++ .../src/components/Boards/AddPopup/index.js | 3 + client/src/entry-actions/boards.js | 3 +- client/src/locales/en/core.js | 3 + client/src/models/Board.js | 6 +- client/src/sagas/core/services/boards.js | 24 ++- client/src/sagas/core/watchers/boards.js | 4 +- client/src/sagas/core/watchers/socket.js | 4 +- client/src/selectors/boards.js | 7 + server/api/controllers/boards/create.js | 55 +++++++ server/api/helpers/boards/create-one.js | 16 ++ .../api/helpers/boards/import-from-trello.js | 152 ++++++++++++++++++ .../process-uploaded-trello-import-file.js | 38 +++++ server/api/models/Board.js | 5 + 20 files changed, 537 insertions(+), 89 deletions(-) delete mode 100755 client/src/components/Boards/AddPopup.jsx delete mode 100644 client/src/components/Boards/AddPopup.module.scss create mode 100755 client/src/components/Boards/AddPopup/AddPopup.jsx create mode 100644 client/src/components/Boards/AddPopup/AddPopup.module.scss create mode 100644 client/src/components/Boards/AddPopup/ImportStep.jsx create mode 100644 client/src/components/Boards/AddPopup/ImportStep.module.scss create mode 100644 client/src/components/Boards/AddPopup/index.js create mode 100644 server/api/helpers/boards/import-from-trello.js create mode 100644 server/api/helpers/boards/process-uploaded-trello-import-file.js diff --git a/client/src/api/boards.js b/client/src/api/boards.js index b605ed2e..c35b2e98 100755 --- a/client/src/api/boards.js +++ b/client/src/api/boards.js @@ -1,4 +1,5 @@ import socket from './socket'; +import http from './http'; import { transformCard } from './cards'; import { transformAttachment } from './attachments'; @@ -7,6 +8,9 @@ import { transformAttachment } from './attachments'; const createBoard = (projectId, data, headers) => socket.post(`/projects/${projectId}/boards`, data, headers); +const createBoardWithImport = (projectId, data, requestId, headers) => + http.post(`/projects/${projectId}/boards?requestId=${requestId}`, data, headers); + const getBoard = (id, headers) => socket.get(`/boards/${id}`, undefined, headers).then((body) => ({ ...body, @@ -23,6 +27,7 @@ const deleteBoard = (id, headers) => socket.delete(`/boards/${id}`, undefined, h export default { createBoard, + createBoardWithImport, getBoard, updateBoard, deleteBoard, diff --git a/client/src/components/Boards/AddPopup.jsx b/client/src/components/Boards/AddPopup.jsx deleted file mode 100755 index ff378ac5..00000000 --- a/client/src/components/Boards/AddPopup.jsx +++ /dev/null @@ -1,70 +0,0 @@ -import React, { useCallback, useEffect, useRef } from 'react'; -import PropTypes from 'prop-types'; -import { useTranslation } from 'react-i18next'; -import { Button, Form } from 'semantic-ui-react'; -import { withPopup } from '../../lib/popup'; -import { Input, Popup } from '../../lib/custom-ui'; - -import { useForm } from '../../hooks'; - -import styles from './AddPopup.module.scss'; - -const AddStep = React.memo(({ onCreate, onClose }) => { - const [t] = useTranslation(); - - const [data, handleFieldChange] = useForm({ - name: '', - }); - - const nameField = useRef(null); - - const handleSubmit = useCallback(() => { - const cleanData = { - ...data, - type: 'kanban', - name: data.name.trim(), - }; - - if (!cleanData.name) { - nameField.current.select(); - return; - } - - onCreate(cleanData); - onClose(); - }, [onCreate, onClose, data]); - - useEffect(() => { - nameField.current.focus(); - }, []); - - return ( - <> - - {t('common.createBoard', { - context: 'title', - })} - - -
- -
+ + +
+ + ); +}); + +AddStep.propTypes = { + onCreate: PropTypes.func.isRequired, + onClose: PropTypes.func.isRequired, +}; + +export default withPopup(AddStep); diff --git a/client/src/components/Boards/AddPopup/AddPopup.module.scss b/client/src/components/Boards/AddPopup/AddPopup.module.scss new file mode 100644 index 00000000..cda85c3c --- /dev/null +++ b/client/src/components/Boards/AddPopup/AddPopup.module.scss @@ -0,0 +1,42 @@ +:global(#app) { + .controls { + display: flex; + max-width: 280px; + + @media only screen and (max-width: 767px) { + max-width: 226px; + } + } + + .createButton { + white-space: nowrap; + } + + .field { + margin-bottom: 8px; + } + + .importButton { + background: transparent; + box-shadow: none; + color: #6b808c; + font-weight: normal; + margin-left: auto; + margin-right: 0; + overflow: hidden; + text-align: left; + text-decoration: underline; + text-overflow: ellipsis; + transition: none; + white-space: nowrap; + + &:hover { + background: rgba(9, 30, 66, 0.08); + color: #092d42; + } + } + + .importButtonIcon { + text-decoration: none; + } +} diff --git a/client/src/components/Boards/AddPopup/ImportStep.jsx b/client/src/components/Boards/AddPopup/ImportStep.jsx new file mode 100644 index 00000000..d56bf2a2 --- /dev/null +++ b/client/src/components/Boards/AddPopup/ImportStep.jsx @@ -0,0 +1,51 @@ +import React, { useCallback } from 'react'; +import PropTypes from 'prop-types'; +import { useTranslation } from 'react-i18next'; +import { Button } from 'semantic-ui-react'; +import { FilePicker, Popup } from '../../../lib/custom-ui'; + +import styles from './ImportStep.module.scss'; + +const ImportStep = React.memo(({ onSelect, onBack }) => { + const [t] = useTranslation(); + + const handleFileSelect = useCallback( + (type, file) => { + onSelect({ + type, + file, + }); + + onBack(); + }, + [onSelect, onBack], + ); + + return ( + <> + + {t('common.importBoard', { + context: 'title', + })} + + + handleFileSelect('trello', file)} accept=".json"> +