From 78120608d0026c85f2635dddf9f8a487c34377e2 Mon Sep 17 00:00:00 2001 From: lupusA Date: Sat, 6 Jan 2024 09:55:46 +0100 Subject: [PATCH 1/7] Added a modified directory selector --- src/components/SetupRepositoryFilesystem.jsx | 7 ++--- src/forms/RequiredDirectory.jsx | 31 ++++++++++++++++++++ src/utils/uiutil.jsx | 6 ++++ 3 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 src/forms/RequiredDirectory.jsx diff --git a/src/components/SetupRepositoryFilesystem.jsx b/src/components/SetupRepositoryFilesystem.jsx index f5915ae..9b1049b 100644 --- a/src/components/SetupRepositoryFilesystem.jsx +++ b/src/components/SetupRepositoryFilesystem.jsx @@ -1,7 +1,6 @@ import React, { Component } from 'react'; -import Row from 'react-bootstrap/Row'; import { handleChange, validateRequiredFields } from '../forms'; -import { RequiredField } from '../forms/RequiredField'; +import { RequiredDirectory } from '../forms/RequiredDirectory'; export class SetupRepositoryFilesystem extends Component { constructor(props) { @@ -19,9 +18,7 @@ export class SetupRepositoryFilesystem extends Component { render() { return <> - - {RequiredField(this, "Directory Path", "path", { autoFocus: true, placeholder: "enter directory path where you want to store repository files" })} - + {RequiredDirectory(this, "Directory Path", "path", { autoFocus: true, placeholder: "enter directory path where you want to store repository files"})} ; } } diff --git a/src/forms/RequiredDirectory.jsx b/src/forms/RequiredDirectory.jsx new file mode 100644 index 0000000..f3b2c45 --- /dev/null +++ b/src/forms/RequiredDirectory.jsx @@ -0,0 +1,31 @@ +import React from 'react'; +import Col from 'react-bootstrap/Col'; +import Button from 'react-bootstrap/Button'; +import Form from 'react-bootstrap/Form'; +import FormControl from 'react-bootstrap/FormControl'; +import InputGroup from 'react-bootstrap/InputGroup'; +import { faFolderOpen } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { stateProperty } from '.'; + +export function RequiredDirectory(component, label, name, props = {}, helpText = null) { + let { onDirectorySelected, ...inputProps } = props; + if (!window.kopiaUI) { + return + } + return + {label} + + + + {helpText && {helpText}} + Required field + +} \ No newline at end of file diff --git a/src/utils/uiutil.jsx b/src/utils/uiutil.jsx index ddcee21..e8c8e34 100644 --- a/src/utils/uiutil.jsx +++ b/src/utils/uiutil.jsx @@ -367,6 +367,12 @@ export function errorAlert(err, prefix) { } } +/** + * A selector that openes a file browser to select a directory. + * The selector checks, if the it is used in the context of the native or web-ui. + * @param {*} props + * @returns + */ export function DirectorySelector(props) { let { onDirectorySelected, ...inputProps } = props; From 2a888f2907cce32ad1b33b3e04105936e851f453 Mon Sep 17 00:00:00 2001 From: lupusA Date: Sat, 6 Jan 2024 11:19:27 +0100 Subject: [PATCH 2/7] First draft of directory selector --- src/components/SetupRepositoryFilesystem.jsx | 3 +- src/css/index.css | 2 - src/forms/RequiredDirectory.jsx | 39 ++++++++++++-------- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/components/SetupRepositoryFilesystem.jsx b/src/components/SetupRepositoryFilesystem.jsx index 9b1049b..ac7e99e 100644 --- a/src/components/SetupRepositoryFilesystem.jsx +++ b/src/components/SetupRepositoryFilesystem.jsx @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import { handleChange, validateRequiredFields } from '../forms'; import { RequiredDirectory } from '../forms/RequiredDirectory'; +import { Row } from 'react-bootstrap'; export class SetupRepositoryFilesystem extends Component { constructor(props) { @@ -18,7 +19,7 @@ export class SetupRepositoryFilesystem extends Component { render() { return <> - {RequiredDirectory(this, "Directory Path", "path", { autoFocus: true, placeholder: "enter directory path where you want to store repository files"})} + {RequiredDirectory(this, "Directory Path", "path", { autoFocus: true, placeholder: "enter directory path where you want to store repository files"})} ; } } diff --git a/src/css/index.css b/src/css/index.css index 4a1df4d..662dfda 100644 --- a/src/css/index.css +++ b/src/css/index.css @@ -3,8 +3,6 @@ body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; } code { diff --git a/src/forms/RequiredDirectory.jsx b/src/forms/RequiredDirectory.jsx index f3b2c45..92cc5e3 100644 --- a/src/forms/RequiredDirectory.jsx +++ b/src/forms/RequiredDirectory.jsx @@ -1,7 +1,7 @@ import React from 'react'; -import Col from 'react-bootstrap/Col'; import Button from 'react-bootstrap/Button'; import Form from 'react-bootstrap/Form'; +import { Col } from 'react-bootstrap'; import FormControl from 'react-bootstrap/FormControl'; import InputGroup from 'react-bootstrap/InputGroup'; import { faFolderOpen } from '@fortawesome/free-solid-svg-icons'; @@ -11,21 +11,28 @@ import { stateProperty } from '.'; export function RequiredDirectory(component, label, name, props = {}, helpText = null) { let { onDirectorySelected, ...inputProps } = props; if (!window.kopiaUI) { - return + return <> + {label} + + + } - return - {label} - - + return <> + {label} + + - {helpText && {helpText}} - Required field - + + + {helpText && {helpText}} + Required field + + } \ No newline at end of file From fc4bc40f997cddcc6034eed63bf72e6a4f1bb9a9 Mon Sep 17 00:00:00 2001 From: lupusA Date: Sat, 6 Jan 2024 13:15:41 +0100 Subject: [PATCH 3/7] Further working on the feature --- src/components/SetupRepositoryFilesystem.jsx | 1 - src/forms/OptionalDirectory.jsx | 27 ++++++++++++++++++++ src/forms/RequiredDirectory.jsx | 23 +++++------------ src/pages/Policies.jsx | 9 +++---- src/pages/SnapshotCreate.jsx | 13 ++++------ src/utils/uiutil.jsx | 24 +---------------- 6 files changed, 44 insertions(+), 53 deletions(-) create mode 100644 src/forms/OptionalDirectory.jsx diff --git a/src/components/SetupRepositoryFilesystem.jsx b/src/components/SetupRepositoryFilesystem.jsx index ac7e99e..6f3dbcd 100644 --- a/src/components/SetupRepositoryFilesystem.jsx +++ b/src/components/SetupRepositoryFilesystem.jsx @@ -1,7 +1,6 @@ import React, { Component } from 'react'; import { handleChange, validateRequiredFields } from '../forms'; import { RequiredDirectory } from '../forms/RequiredDirectory'; -import { Row } from 'react-bootstrap'; export class SetupRepositoryFilesystem extends Component { constructor(props) { diff --git a/src/forms/OptionalDirectory.jsx b/src/forms/OptionalDirectory.jsx new file mode 100644 index 0000000..267cc3c --- /dev/null +++ b/src/forms/OptionalDirectory.jsx @@ -0,0 +1,27 @@ +import React from 'react'; +import Button from 'react-bootstrap/Button'; +import Form from 'react-bootstrap/Form'; +import { Col, FormGroup } from 'react-bootstrap'; +import FormControl from 'react-bootstrap/FormControl'; +import InputGroup from 'react-bootstrap/InputGroup'; +import { faFolderOpen } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { stateProperty } from '.'; + +export function OptionalDirectory(component, label, name, props = {}, helpText = null) { + let { onDirectorySelected, ...inputProps } = props; + return + {label ? {label} : <>} + + component.setState({ name: p })} + onChange={component.handleChange}{...inputProps}> + {window.kopiaUI ? + : <>} + {helpText && {helpText}} + + +} \ No newline at end of file diff --git a/src/forms/RequiredDirectory.jsx b/src/forms/RequiredDirectory.jsx index 92cc5e3..03d547c 100644 --- a/src/forms/RequiredDirectory.jsx +++ b/src/forms/RequiredDirectory.jsx @@ -1,7 +1,7 @@ import React from 'react'; import Button from 'react-bootstrap/Button'; import Form from 'react-bootstrap/Form'; -import { Col } from 'react-bootstrap'; +import { Col, FormGroup } from 'react-bootstrap'; import FormControl from 'react-bootstrap/FormControl'; import InputGroup from 'react-bootstrap/InputGroup'; import { faFolderOpen } from '@fortawesome/free-solid-svg-icons'; @@ -10,29 +10,20 @@ import { stateProperty } from '.'; export function RequiredDirectory(component, label, name, props = {}, helpText = null) { let { onDirectorySelected, ...inputProps } = props; - if (!window.kopiaUI) { - return <> - {label} - - - - } - return <> - {label} + return + {label ? {label} : <>} component.setState({ name: p })} onChange={component.handleChange}{...inputProps}> - + {window.kopiaUI ? - + : <>} {helpText && {helpText}} Required field - + } \ No newline at end of file diff --git a/src/pages/Policies.jsx b/src/pages/Policies.jsx index 9f7ff37..56676d5 100644 --- a/src/pages/Policies.jsx +++ b/src/pages/Policies.jsx @@ -10,8 +10,9 @@ import Form from 'react-bootstrap/Form'; import Row from 'react-bootstrap/Row'; import { Link } from 'react-router-dom'; import { handleChange } from '../forms'; +import { OptionalDirectory } from '../forms/OptionalDirectory' import KopiaTable from '../utils/KopiaTable'; -import { CLIEquivalent, compare, DirectorySelector, isAbsolutePath, ownerName, policyEditorURL, redirect } from '../utils/uiutil'; +import { CLIEquivalent, compare, isAbsolutePath, ownerName, policyEditorURL, redirect } from '../utils/uiutil'; const applicablePolicies = "Applicable Policies" const localPolicies = "Local Path Policies" @@ -274,9 +275,7 @@ export class Policies extends Component { {(this.state.selectedOwner === localPolicies || this.state.selectedOwner === this.state.localSourceName || this.state.selectedOwner === applicablePolicies) ? <> - this.setState({ policyPath: p })} - placeholder="enter directory to find or set policy" - name="policyPath" value={this.state.policyPath} onChange={this.handleChange} /> + {OptionalDirectory(this, null, "policyPath", { autoFocus: true, placeholder: "enter directory to find or set policy" })} @@ -295,4 +294,4 @@ export class Policies extends Component { ; } -} +} \ No newline at end of file diff --git a/src/pages/SnapshotCreate.jsx b/src/pages/SnapshotCreate.jsx index 7a85f1b..1888e22 100644 --- a/src/pages/SnapshotCreate.jsx +++ b/src/pages/SnapshotCreate.jsx @@ -7,7 +7,8 @@ import Row from 'react-bootstrap/Row'; import { handleChange } from '../forms'; import { PolicyEditor } from '../components/policy-editor/PolicyEditor'; import { SnapshotEstimation } from '../components/SnapshotEstimation'; -import { CLIEquivalent, DirectorySelector, errorAlert, GoBackButton, redirect } from '../utils/uiutil'; +import { RequiredDirectory } from '../forms/RequiredDirectory'; +import { CLIEquivalent, errorAlert, GoBackButton, redirect } from '../utils/uiutil'; export class SnapshotCreate extends Component { constructor() { @@ -147,18 +148,15 @@ export class SnapshotCreate extends Component { render() { return <> - -    

New Snapshot

-
+
+

New Snapshot


- - this.setState({ path: p })} autoFocus placeholder="enter path to snapshot" name="path" value={this.state.path} onChange={this.handleChange} /> - + {RequiredDirectory(this, "Directory Path", "path", { autoFocus: true, placeholder: "enter path to snapshot" })} -   - ; -} - export function CLIEquivalent(props) { let [visible, setVisible] = useState(false); let [cliInfo, setCLIInfo] = useState({}); From 4b6712aceb5b19d8c932060900f51ab8f71dafbd Mon Sep 17 00:00:00 2001 From: lupusA Date: Sun, 7 Jan 2024 09:19:21 +0100 Subject: [PATCH 4/7] Further working on the feature --- src/forms/OptionalDirectory.jsx | 42 +++++++++++++++++++++--------- src/forms/OptionalField.jsx | 3 +-- src/forms/RequiredDirectory.jsx | 46 +++++++++++++++++++++++---------- src/pages/SnapshotCreate.jsx | 18 +++++-------- 4 files changed, 70 insertions(+), 39 deletions(-) diff --git a/src/forms/OptionalDirectory.jsx b/src/forms/OptionalDirectory.jsx index 267cc3c..9060477 100644 --- a/src/forms/OptionalDirectory.jsx +++ b/src/forms/OptionalDirectory.jsx @@ -1,27 +1,45 @@ import React from 'react'; import Button from 'react-bootstrap/Button'; import Form from 'react-bootstrap/Form'; -import { Col, FormGroup } from 'react-bootstrap'; -import FormControl from 'react-bootstrap/FormControl'; -import InputGroup from 'react-bootstrap/InputGroup'; +import { Col, FormGroup, FormControl, InputGroup } from 'react-bootstrap'; import { faFolderOpen } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { stateProperty } from '.'; +import { setDeepStateProperty } from '../utils/deepstate'; -export function OptionalDirectory(component, label, name, props = {}, helpText = null) { - let { onDirectorySelected, ...inputProps } = props; +/** + * This functions returns a directory selector that allows the user to select a directory. + * The selections is invoked using a button that calls a functions within the electron app. + * If the electron app is not present, the button is not visible. + * + * @param {The component that this function is called from} component + * @param {Label, that is added before the input field} label + * @param {Name of the variable in which the directory path is stored} name + * @param {Additional properties of the component} props + * @returns The form group with the components + */ +export function OptionalDirectory(component, label, name, props = {}) { + /** + * Saves the selected path as a deepstate variable within the component + * @param {The path that has been selected} path + */ + function onDirectorySelected(path) { + setDeepStateProperty(component, name, path) + } + return - {label ? {label} : <>} + {label && {label}} - component.setState({ name: p })} - onChange={component.handleChange}{...inputProps}> - {window.kopiaUI ? + onChange={component.handleChange}{...props}> + {window.kopiaUI && : <>} - {helpText && {helpText}} + } } \ No newline at end of file diff --git a/src/forms/OptionalField.jsx b/src/forms/OptionalField.jsx index 29ccda4..63b454c 100644 --- a/src/forms/OptionalField.jsx +++ b/src/forms/OptionalField.jsx @@ -3,7 +3,7 @@ import Form from 'react-bootstrap/Form'; import Col from 'react-bootstrap/Col'; import { stateProperty } from '.'; -export function OptionalField(component, label, name, props = {}, helpText = null, invalidFeedback = null) { +export function OptionalField(component, label, name, props = {}, helpText = null) { return {label} {helpText && {helpText}} - {invalidFeedback && {invalidFeedback}} ; } diff --git a/src/forms/RequiredDirectory.jsx b/src/forms/RequiredDirectory.jsx index 03d547c..d279681 100644 --- a/src/forms/RequiredDirectory.jsx +++ b/src/forms/RequiredDirectory.jsx @@ -1,28 +1,46 @@ import React from 'react'; import Button from 'react-bootstrap/Button'; import Form from 'react-bootstrap/Form'; -import { Col, FormGroup } from 'react-bootstrap'; -import FormControl from 'react-bootstrap/FormControl'; -import InputGroup from 'react-bootstrap/InputGroup'; +import { Col, FormGroup, FormControl, InputGroup } from 'react-bootstrap'; import { faFolderOpen } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { stateProperty } from '.'; +import { setDeepStateProperty } from '../utils/deepstate'; -export function RequiredDirectory(component, label, name, props = {}, helpText = null) { - let { onDirectorySelected, ...inputProps } = props; +/** + * This functions returns a directory selector that allows the user to select a directory. + * The selections is invoked using a button that calls a functions within the electron app. + * If the electron app is not present, the button is not visible. The path is required. + * + * @param {The component that this function is called from} component + * @param {Label, that is added before the input field} label + * @param {Name of the variable in which the directory path is stored} name + * @param {Additional properties of the component} props + * @returns The form group with the components + */ +export function RequiredDirectory(component, label, name, props = {}) { + /** + * Saves the selected path as a deepstate variable within the component + * @param {The path that has been selected} path + */ + function onDirectorySelected(path) { + setDeepStateProperty(component, name, path) + } + return - {label ? {label} : <>} + {label && {label}} - component.setState({ name: p })} - onChange={component.handleChange}{...inputProps}> - {window.kopiaUI ? - : <>} - {helpText && {helpText}} + onChange={component.handleChange}{...props}> + {window.kopiaUI && + } Required field diff --git a/src/pages/SnapshotCreate.jsx b/src/pages/SnapshotCreate.jsx index 1888e22..fbabf7a 100644 --- a/src/pages/SnapshotCreate.jsx +++ b/src/pages/SnapshotCreate.jsx @@ -148,15 +148,15 @@ export class SnapshotCreate extends Component { render() { return <> - - - -
-

New Snapshot

+ + + +
+

New Snapshot


- {RequiredDirectory(this, "Directory Path", "path", { autoFocus: true, placeholder: "enter path to snapshot" })} + {RequiredDirectory(this, null, "path", { autoFocus: true, placeholder: "enter path to snapshot" })}