From 28065506741bf2d74a916377857a5781b3bbd4e7 Mon Sep 17 00:00:00 2001 From: Benjamin Morali Date: Wed, 17 Feb 2021 11:07:45 +0100 Subject: [PATCH] feat(export): add select all in export modal (#1192) --- .../export-modal/export-category-options.tsx | 7 +- .../modals/export-modal/export-checkbox.tsx | 4 +- .../modals/export-modal/export-controls.tsx | 79 +++++++++++++++++++ .../modals/export-modal/export-input.tsx | 15 ++-- .../export-modal/export-modal-content.tsx | 8 +- .../modals/export-modal/export-options.tsx | 38 ++++++--- .../export-modal/export-type-option.tsx | 19 +++-- src/translations/en.json | 5 +- src/translations/fr.json | 5 +- 9 files changed, 150 insertions(+), 30 deletions(-) create mode 100644 src/components/modals/export-modal/export-controls.tsx diff --git a/src/components/modals/export-modal/export-category-options.tsx b/src/components/modals/export-modal/export-category-options.tsx index 4f7d1528f..c4675895d 100644 --- a/src/components/modals/export-modal/export-category-options.tsx +++ b/src/components/modals/export-modal/export-category-options.tsx @@ -14,6 +14,7 @@ type ExportCategoryOptionsProps = { enabledExports: ExportTypesMap; exportPaths: ExportTypesMap; isValidPaths: ExportTypesMap; + activeExports: ExportTypesMap; setActiveExportValue: (exportType: ExportType, value: boolean) => void; setExportsPathsValue: (exportType: ExportType, value: string) => void; }; @@ -21,9 +22,10 @@ type ExportCategoryOptionsProps = { const ExportCategoryOptions: FC = ({ exportCategory, enabledExports, - setActiveExportValue, - isValidPaths, exportPaths, + isValidPaths, + activeExports, + setActiveExportValue, setExportsPathsValue, }) => { const { t } = useTranslation(); @@ -46,6 +48,7 @@ const ExportCategoryOptions: FC = ({ setActiveExportValue={setActiveExportValue} exportPaths={exportPaths} setExportsPathsValue={setExportsPathsValue} + activeExports={activeExports} /> ))} diff --git a/src/components/modals/export-modal/export-checkbox.tsx b/src/components/modals/export-modal/export-checkbox.tsx index 3105b1e1e..fb0193d1b 100644 --- a/src/components/modals/export-modal/export-checkbox.tsx +++ b/src/components/modals/export-modal/export-checkbox.tsx @@ -7,6 +7,7 @@ type ExportOptionProps = { label: string; isActive: boolean; disabledExplanation: string; + checked: boolean; }; const ExportCheckbox: FC = ({ @@ -14,6 +15,7 @@ const ExportCheckbox: FC = ({ label, isActive, disabledExplanation, + checked, }) => { const onChange = useCallback( (event) => { @@ -25,7 +27,7 @@ const ExportCheckbox: FC = ({ return ( } + control={} label={`${label}${ !isActive && disabledExplanation ? ` (${disabledExplanation})` : "" }`} diff --git a/src/components/modals/export-modal/export-controls.tsx b/src/components/modals/export-modal/export-controls.tsx new file mode 100644 index 000000000..1b9f73924 --- /dev/null +++ b/src/components/modals/export-modal/export-controls.tsx @@ -0,0 +1,79 @@ +import React, { FC } from "react"; +import Box from "@material-ui/core/Box"; +import { Button } from "@material-ui/core"; +import { FaFolderOpen } from "react-icons/fa"; +import { ExportType } from "./export-config"; +import { useTranslation } from "react-i18next"; +import { ExportTypesMap } from "./export-options"; +import { remote } from "electron"; +import path from "path"; +import Checkbox from "@material-ui/core/Checkbox"; +import FormControlLabel from "@material-ui/core/FormControlLabel"; + +type ExportControlsProps = { + setActiveExportValue: (exportType: ExportType, value: boolean) => void; + setExportsPathsValue: (exportType: ExportType, value: string) => void; + activeExports: ExportTypesMap; + exportPaths: ExportTypesMap; + enabledExports: ExportTypesMap; +}; + +const ExportControls: FC = ({ + setActiveExportValue, + setExportsPathsValue, + activeExports, + exportPaths, + enabledExports, +}) => { + const { t } = useTranslation(); + + const areAllBoxesChecked = Object.values(ExportType).every( + (exportType) => activeExports[exportType] + ); + + const setAllBoxes = (checked: boolean) => { + Object.values(ExportType) + .filter((exportType) => enabledExports[exportType]) + .forEach((exportType) => { + setActiveExportValue(exportType, checked); + }); + }; + + const toggleAllBoxes = () => { + setAllBoxes(!areAllBoxesChecked); + }; + + const browseForAll = async () => { + const filePath = await remote.dialog.showOpenDialog({ + properties: ["openDirectory"], + }); + + Object.values(ExportType).forEach((exportType) => { + if (filePath.filePaths.length > 0) { + const folderPath = filePath.filePaths[0]; + const filename = path.basename(exportPaths[exportType]); + setExportsPathsValue(exportType, `${folderPath}/${filename}`); + } + }); + }; + + return ( + + + } + label={ + areAllBoxesChecked + ? t("exportModal.unselectAll") + : t("exportModal.selectAll") + } + /> + + + ); +}; + +export default ExportControls; diff --git a/src/components/modals/export-modal/export-input.tsx b/src/components/modals/export-modal/export-input.tsx index d94498cb2..543e4ed2e 100644 --- a/src/components/modals/export-modal/export-input.tsx +++ b/src/components/modals/export-modal/export-input.tsx @@ -1,4 +1,4 @@ -import Button from "@material-ui/core/Button"; +import IconButton from "@material-ui/core/IconButton"; import Tooltip from "@material-ui/core/Tooltip"; import Box from "@material-ui/core/Box"; import React, { FC, useCallback } from "react"; @@ -56,11 +56,16 @@ const ExportInput: FC = ({ title={browseTitle} isvisible={(!isFilePickerDisabled).toString()} > -
- -
+ + ); diff --git a/src/components/modals/export-modal/export-modal-content.tsx b/src/components/modals/export-modal/export-modal-content.tsx index 80aa4f67a..dc6ff54c6 100644 --- a/src/components/modals/export-modal/export-modal-content.tsx +++ b/src/components/modals/export-modal/export-modal-content.tsx @@ -96,10 +96,13 @@ const ExportModalContent: FC = ({ }, [exportPaths, setValidPaths]); const setActiveExportValue = (exportType: ExportType, value: boolean) => - setActiveExports({ ...activeExports, [exportType]: value }); + setActiveExports((activeExports) => ({ + ...activeExports, + [exportType]: value, + })); const setExportsPathsValue = (exportType: ExportType, value: string) => - setExportsPaths({ ...exportPaths, [exportType]: value }); + setExportsPaths((exportPaths) => ({ ...exportPaths, [exportType]: value })); return ( <> @@ -110,6 +113,7 @@ const ExportModalContent: FC = ({ isValidPaths={validPaths} setActiveExportValue={setActiveExportValue} setExportsPathsValue={setExportsPathsValue} + activeExports={activeExports} /> diff --git a/src/components/modals/export-modal/export-options.tsx b/src/components/modals/export-modal/export-options.tsx index c3147d5ec..6bb33826c 100644 --- a/src/components/modals/export-modal/export-options.tsx +++ b/src/components/modals/export-modal/export-options.tsx @@ -1,6 +1,8 @@ import ExportCategoryOptions from "components/modals/export-modal/export-category-options"; import React, { FC } from "react"; import { ExportCategory, ExportType } from "./export-config"; +import Box from "@material-ui/core/Box"; +import ExportControls from "./export-controls"; export type ExportTypesMap = { [exportType in ExportType]: ValueType; @@ -10,6 +12,7 @@ type ExportOptionsProps = { enabledExports: ExportTypesMap; exportPaths: ExportTypesMap; isValidPaths: ExportTypesMap; + activeExports: ExportTypesMap; setActiveExportValue: (exportType: ExportType, value: boolean) => void; setExportsPathsValue: (exportType: ExportType, value: string) => void; }; @@ -18,22 +21,33 @@ const ExportOptions: FC = ({ enabledExports, exportPaths, isValidPaths, + activeExports, setActiveExportValue, setExportsPathsValue, -}) => ( - <> - {Object.values(ExportCategory).map((exportCategory) => ( - { + return ( + + - ))} - -); + {Object.values(ExportCategory).map((exportCategory) => ( + + ))} + + ); +}; export default ExportOptions; diff --git a/src/components/modals/export-modal/export-type-option.tsx b/src/components/modals/export-modal/export-type-option.tsx index cdd34d251..258f35b74 100644 --- a/src/components/modals/export-modal/export-type-option.tsx +++ b/src/components/modals/export-modal/export-type-option.tsx @@ -1,9 +1,13 @@ import ExportCheckbox from "components/modals/export-modal/export-checkbox"; -import { exportConfig } from "components/modals/export-modal/export-config"; +import { + exportConfig, + ExportType, +} from "components/modals/export-modal/export-config"; import ExportInput from "components/modals/export-modal/export-input"; import React, { FC } from "react"; import { useTranslation } from "react-i18next"; import styled from "styled-components"; +import { ExportTypesMap } from "./export-options"; const ExportContainer = styled.div` display: flex; @@ -12,12 +16,13 @@ const ExportContainer = styled.div` `; type ExportTypeOptionProps = { - exportType; - enabledExports; + exportType: ExportType; + enabledExports: ExportTypesMap; isPathValid: boolean; - setActiveExportValue; - exportPaths; - setExportsPathsValue; + exportPaths: ExportTypesMap; + setActiveExportValue: (exportType: ExportType, value: boolean) => void; + setExportsPathsValue: (exportType: ExportType, value: string) => void; + activeExports: ExportTypesMap; }; const ExportTypeOption: FC = ({ @@ -27,6 +32,7 @@ const ExportTypeOption: FC = ({ setActiveExportValue, exportPaths, setExportsPathsValue, + activeExports, }) => { const { t } = useTranslation(); @@ -41,6 +47,7 @@ const ExportTypeOption: FC = ({ disabledExplanation={t( exportConfig[exportType].disabledExplanation || "" )} + checked={activeExports[exportType]} />