📝 Abstracted connection form into a component
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
import React, { ReactElement, useCallback, useContext } from "react";
|
import React, { ReactElement, useCallback, useContext } from "react";
|
||||||
import { Form, Field } from "react-final-form";
|
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import {
|
import {
|
||||||
saveSettings,
|
saveSettings,
|
||||||
@@ -7,8 +6,8 @@ import {
|
|||||||
} from "../../../actions/settings.actions";
|
} from "../../../actions/settings.actions";
|
||||||
import { AirDCPPSettingsConfirmation } from "./AirDCPPSettingsConfirmation";
|
import { AirDCPPSettingsConfirmation } from "./AirDCPPSettingsConfirmation";
|
||||||
import { AirDCPPSocketContext } from "../../../context/AirDCPPSocket";
|
import { AirDCPPSocketContext } from "../../../context/AirDCPPSocket";
|
||||||
import { isUndefined, isEmpty, isNil } from "lodash";
|
import { isUndefined, isEmpty } from "lodash";
|
||||||
import { hostNameValidator } from "../../../shared/utils/validator.utils";
|
import { ConnectionForm } from "../../shared/ConnectionForm/ConnectionForm";
|
||||||
|
|
||||||
export const AirDCPPSettingsForm = (): ReactElement => {
|
export const AirDCPPSettingsForm = (): ReactElement => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@@ -26,7 +25,7 @@ export const AirDCPPSettingsForm = (): ReactElement => {
|
|||||||
airDCPPSettings.setSettings({});
|
airDCPPSettings.setSettings({});
|
||||||
dispatch(deleteSettings());
|
dispatch(deleteSettings());
|
||||||
}, []);
|
}, []);
|
||||||
const validate = async () => { };
|
|
||||||
const initFormData = !isUndefined(
|
const initFormData = !isUndefined(
|
||||||
airDCPPSettings.airDCPPState.settings.directConnect,
|
airDCPPSettings.airDCPPState.settings.directConnect,
|
||||||
)
|
)
|
||||||
@@ -35,94 +34,8 @@ export const AirDCPPSettingsForm = (): ReactElement => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Form
|
<ConnectionForm initialData={initFormData} submitHandler={onSubmit} />
|
||||||
onSubmit={onSubmit}
|
|
||||||
validate={validate}
|
|
||||||
initialValues={initFormData}
|
|
||||||
render={({ handleSubmit }) => (
|
|
||||||
<form onSubmit={handleSubmit}>
|
|
||||||
<h2>Configure AirDC++</h2>
|
|
||||||
<label className="label">AirDC++ Hostname</label>
|
|
||||||
<div className="field has-addons">
|
|
||||||
<p className="control">
|
|
||||||
<span className="select">
|
|
||||||
<Field name="protocol" component="select">
|
|
||||||
<option>Protocol</option>
|
|
||||||
<option value="http">http://</option>
|
|
||||||
<option value="https">https://</option>
|
|
||||||
</Field>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<div className="control is-expanded">
|
|
||||||
<Field name="hostname" validate={hostNameValidator}>
|
|
||||||
{({ input, meta }) => (
|
|
||||||
<div>
|
|
||||||
<input
|
|
||||||
{...input}
|
|
||||||
type="text"
|
|
||||||
placeholder="AirDC++ hostname"
|
|
||||||
className="input"
|
|
||||||
/>
|
|
||||||
{meta.error && meta.touched && (
|
|
||||||
<span className="is-size-7 has-text-danger">
|
|
||||||
{meta.error}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
</div>
|
|
||||||
<p className="control">
|
|
||||||
<Field
|
|
||||||
name="port"
|
|
||||||
component="input"
|
|
||||||
className="input"
|
|
||||||
placeholder="AirDC++ port"
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="field">
|
|
||||||
<label className="label">Credentials</label>
|
|
||||||
<div className="field-body">
|
|
||||||
<div className="field">
|
|
||||||
<p className="control is-expanded has-icons-left">
|
|
||||||
<Field
|
|
||||||
name="username"
|
|
||||||
component="input"
|
|
||||||
className="input"
|
|
||||||
placeholder="Username"
|
|
||||||
/>
|
|
||||||
<span className="icon is-small is-left">
|
|
||||||
<i className="fa-solid fa-user-ninja"></i>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="field">
|
|
||||||
<p className="control is-expanded has-icons-left has-icons-right">
|
|
||||||
<Field
|
|
||||||
name="password"
|
|
||||||
component="input"
|
|
||||||
type="password"
|
|
||||||
className="input"
|
|
||||||
placeholder="Password"
|
|
||||||
/>
|
|
||||||
<span className="icon is-small is-left">
|
|
||||||
<i className="fa-solid fa-lock"></i>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="field is-grouped">
|
|
||||||
<p className="control">
|
|
||||||
<button type="submit" className="button is-primary">
|
|
||||||
{!isEmpty(initFormData) ? "Update" : "Save"}
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
{!isEmpty(airDCPPSettings.airDCPPState.socketConnectionInformation) ? (
|
{!isEmpty(airDCPPSettings.airDCPPState.socketConnectionInformation) ? (
|
||||||
<AirDCPPSettingsConfirmation
|
<AirDCPPSettingsConfirmation
|
||||||
settings={airDCPPSettings.airDCPPState.socketConnectionInformation}
|
settings={airDCPPSettings.airDCPPState.socketConnectionInformation}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import React, { ReactElement, useCallback, useEffect } from "react";
|
import React, { ReactElement, useCallback, useEffect } from "react";
|
||||||
import { Form, Field } from "react-final-form";
|
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { getQBitTorrentClientInfo } from "../../../actions/settings.actions";
|
import { getQBitTorrentClientInfo } from "../../../actions/settings.actions";
|
||||||
import { hostNameValidator } from "../../../shared/utils/validator.utils";
|
|
||||||
import { saveSettings } from "../../../actions/settings.actions";
|
import { saveSettings } from "../../../actions/settings.actions";
|
||||||
|
import { ConnectionForm } from "../../shared/ConnectionForm/ConnectionForm";
|
||||||
import { isUndefined } from "lodash";
|
import { isUndefined } from "lodash";
|
||||||
|
|
||||||
export const QbittorrentConnectionForm = (): ReactElement => {
|
export const QbittorrentConnectionForm = (): ReactElement => {
|
||||||
@@ -34,98 +33,11 @@ export const QbittorrentConnectionForm = (): ReactElement => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<ConnectionForm
|
||||||
<Form
|
initialData={qBittorrentSettings}
|
||||||
onSubmit={onSubmit}
|
submitHandler={onSubmit}
|
||||||
// validate={}
|
|
||||||
initialValues={qBittorrentSettings}
|
|
||||||
render={({ handleSubmit }) => (
|
|
||||||
<form className="content" onSubmit={handleSubmit}>
|
|
||||||
<h2>Configure Qbittorrent</h2>
|
|
||||||
<label className="label">Qbittorrent Hostname</label>
|
|
||||||
<div className="field has-addons">
|
|
||||||
<p className="control">
|
|
||||||
<span className="select">
|
|
||||||
<Field name="protocol" component="select">
|
|
||||||
<option>Protocol</option>
|
|
||||||
<option value="http">http://</option>
|
|
||||||
<option value="https">https://</option>
|
|
||||||
</Field>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<div className="control is-expanded">
|
|
||||||
<Field name="hostname" validate={hostNameValidator}>
|
|
||||||
{({ input, meta }) => (
|
|
||||||
<div>
|
|
||||||
<input
|
|
||||||
{...input}
|
|
||||||
type="text"
|
|
||||||
placeholder="Qbittorrent hostname"
|
|
||||||
className="input"
|
|
||||||
/>
|
|
||||||
{meta.error && meta.touched && (
|
|
||||||
<span className="is-size-7 has-text-danger">
|
|
||||||
{meta.error}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
</div>
|
|
||||||
<p className="control">
|
|
||||||
<Field
|
|
||||||
name="port"
|
|
||||||
component="input"
|
|
||||||
className="input"
|
|
||||||
placeholder="Qbittorrent port"
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="field">
|
|
||||||
<label className="label">Credentials</label>
|
|
||||||
<div className="field-body">
|
|
||||||
<div className="field">
|
|
||||||
<p className="control is-expanded has-icons-left">
|
|
||||||
<Field
|
|
||||||
name="username"
|
|
||||||
component="input"
|
|
||||||
className="input"
|
|
||||||
placeholder="Username"
|
|
||||||
/>
|
|
||||||
<span className="icon is-small is-left">
|
|
||||||
<i className="fa-solid fa-user-ninja"></i>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="field">
|
|
||||||
<p className="control is-expanded has-icons-left has-icons-right">
|
|
||||||
<Field
|
|
||||||
name="password"
|
|
||||||
component="input"
|
|
||||||
type="password"
|
|
||||||
className="input"
|
|
||||||
placeholder="Password"
|
|
||||||
/>
|
|
||||||
<span className="icon is-small is-left">
|
|
||||||
<i className="fa-solid fa-lock"></i>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="field is-grouped">
|
|
||||||
<p className="control">
|
|
||||||
<button type="submit" className="button is-primary">
|
|
||||||
Connect
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
<pre> {JSON.stringify(torrents, null, 4)} </pre>
|
<pre> {torrents && JSON.stringify(torrents, null, 4)} </pre>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
101
src/client/components/shared/ConnectionForm/ConnectionForm.tsx
Normal file
101
src/client/components/shared/ConnectionForm/ConnectionForm.tsx
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import React, { ReactElement } from "react";
|
||||||
|
import { Form, Field } from "react-final-form";
|
||||||
|
import { hostNameValidator } from "../../../shared/utils/validator.utils";
|
||||||
|
import { isEmpty } from "lodash";
|
||||||
|
|
||||||
|
export const ConnectionForm = ({
|
||||||
|
initialData,
|
||||||
|
submitHandler,
|
||||||
|
}): ReactElement => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Form
|
||||||
|
onSubmit={submitHandler}
|
||||||
|
initialValues={initialData}
|
||||||
|
render={({ handleSubmit }) => (
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<h2>Configure AirDC++</h2>
|
||||||
|
<label className="label">AirDC++ Hostname</label>
|
||||||
|
<div className="field has-addons">
|
||||||
|
<p className="control">
|
||||||
|
<span className="select">
|
||||||
|
<Field name="protocol" component="select">
|
||||||
|
<option>Protocol</option>
|
||||||
|
<option value="http">http://</option>
|
||||||
|
<option value="https">https://</option>
|
||||||
|
</Field>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<div className="control is-expanded">
|
||||||
|
<Field name="hostname" validate={hostNameValidator}>
|
||||||
|
{({ input, meta }) => (
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
{...input}
|
||||||
|
type="text"
|
||||||
|
placeholder="hostname"
|
||||||
|
className="input"
|
||||||
|
/>
|
||||||
|
{meta.error && meta.touched && (
|
||||||
|
<span className="is-size-7 has-text-danger">
|
||||||
|
{meta.error}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
<p className="control">
|
||||||
|
<Field
|
||||||
|
name="port"
|
||||||
|
component="input"
|
||||||
|
className="input"
|
||||||
|
placeholder="port"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="field">
|
||||||
|
<label className="label">Credentials</label>
|
||||||
|
<div className="field-body">
|
||||||
|
<div className="field">
|
||||||
|
<p className="control is-expanded has-icons-left">
|
||||||
|
<Field
|
||||||
|
name="username"
|
||||||
|
component="input"
|
||||||
|
className="input"
|
||||||
|
placeholder="Username"
|
||||||
|
/>
|
||||||
|
<span className="icon is-small is-left">
|
||||||
|
<i className="fa-solid fa-user-ninja"></i>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="field">
|
||||||
|
<p className="control is-expanded has-icons-left has-icons-right">
|
||||||
|
<Field
|
||||||
|
name="password"
|
||||||
|
component="input"
|
||||||
|
type="password"
|
||||||
|
className="input"
|
||||||
|
placeholder="Password"
|
||||||
|
/>
|
||||||
|
<span className="icon is-small is-left">
|
||||||
|
<i className="fa-solid fa-lock"></i>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="field is-grouped">
|
||||||
|
<p className="control">
|
||||||
|
<button type="submit" className="button is-primary">
|
||||||
|
{!isEmpty(initialData) ? "Update" : "Save"}
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -17,6 +17,9 @@ const Navbar: React.FunctionComponent = (props) => {
|
|||||||
const airDCPPSessionInfo = useSelector(
|
const airDCPPSessionInfo = useSelector(
|
||||||
(state: RootState) => state.airdcpp.airDCPPSessionInfo,
|
(state: RootState) => state.airdcpp.airDCPPSessionInfo,
|
||||||
);
|
);
|
||||||
|
const qBittorrentConnectionInfo = useSelector(
|
||||||
|
(state: RootState) => state.settings.data,
|
||||||
|
);
|
||||||
const socketDisconnectionReason = useSelector(
|
const socketDisconnectionReason = useSelector(
|
||||||
(state: RootState) => state.airdcpp.socketDisconnectionReason,
|
(state: RootState) => state.airdcpp.socketDisconnectionReason,
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user