🔧 Genericized AirDC++ settings
1. You can now enter your AirDC++ client settings in the settings menu and the UI will read from them 2. Hubs can also be selected for search
This commit is contained in:
98
src/client/components/AirDCPPSettings/AirDCPPHubsForm.tsx
Normal file
98
src/client/components/AirDCPPSettings/AirDCPPHubsForm.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
import React, { ReactElement, useEffect, useState } from "react";
|
||||
import { Form, Field } from "react-final-form";
|
||||
import axios from "axios";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { isEmpty, isUndefined } from "lodash";
|
||||
import Select from "react-select";
|
||||
import { saveSettings } from "../../actions/settings.actions";
|
||||
|
||||
export const AirDCPPHubsForm = (airDCPPClientUserSettings): ReactElement => {
|
||||
const { settings } = airDCPPClientUserSettings;
|
||||
const dispatch = useDispatch();
|
||||
const [hubList, setHubList] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isEmpty(settings)) {
|
||||
axios({
|
||||
url: `${settings.directConnect.client.host.protocol}://${settings.directConnect.client.host.hostname}/api/v1/hubs`,
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: `${settings.directConnect.client.airDCPPUserSettings.auth_token}`,
|
||||
},
|
||||
}).then((hubs) => {
|
||||
const hubSelectionOptions = hubs.data.map(({ hub_url, identity }) => ({
|
||||
value: hub_url,
|
||||
label: identity.name,
|
||||
}));
|
||||
|
||||
setHubList(hubSelectionOptions);
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onSubmit = (values) => {
|
||||
if (!isUndefined(values.hubs)) {
|
||||
dispatch(saveSettings({ hubs: values.hubs }, settings._id));
|
||||
}
|
||||
};
|
||||
|
||||
const validate = async () => {};
|
||||
|
||||
const SelectAdapter = ({ input, ...rest }) => {
|
||||
return <Select {...input} {...rest} isClearable isMulti />;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form
|
||||
onSubmit={onSubmit}
|
||||
validate={validate}
|
||||
render={({ handleSubmit }) => (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div>
|
||||
<h3 className="title">Hubs</h3>
|
||||
<h6 className="subtitle has-text-grey-light">
|
||||
Select the hubs you want to perform searches against.
|
||||
</h6>
|
||||
</div>
|
||||
<div className="field">
|
||||
<label className="label">AirDC++ Host</label>
|
||||
<div className="control">
|
||||
<Field
|
||||
name="hubs"
|
||||
component={SelectAdapter}
|
||||
className="basic-multi-select"
|
||||
placeholder="Select Hubs to Search Against"
|
||||
options={hubList}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" className="button is-primary">
|
||||
Submit
|
||||
</button>
|
||||
</form>
|
||||
)}
|
||||
/>
|
||||
<div className="mt-4">
|
||||
<article className="message is-warning">
|
||||
<div className="message-body is-size-6 is-family-secondary">
|
||||
Your selection in the dropdown <strong>will replace</strong> the
|
||||
existing selection.
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<div className="box mt-3">
|
||||
<h6>Selected hubs</h6>
|
||||
{settings.directConnect.client.hubs.map(({ value, label }) => (
|
||||
<div key={value}>
|
||||
<div>{label}</div>
|
||||
<span className="is-size-7">{value}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AirDCPPHubsForm;
|
||||
@@ -2,6 +2,7 @@ import React, { ReactElement } from "react";
|
||||
|
||||
export const AirDCPPSettingsConfirmation = (settingsObject): ReactElement => {
|
||||
const { settings } = settingsObject;
|
||||
|
||||
return (
|
||||
<div className="mt-4 is-clearfix">
|
||||
<div className="card">
|
||||
@@ -15,21 +16,21 @@ export const AirDCPPSettingsConfirmation = (settingsObject): ReactElement => {
|
||||
<dt>
|
||||
Client version:{" "}
|
||||
{
|
||||
settings.directConnect.client.airdcppUserSettings.system_info
|
||||
settings.directConnect.client.airDCPPUserSettings.system_info
|
||||
.client_version
|
||||
}
|
||||
</dt>
|
||||
<dt>
|
||||
Hostname:{" "}
|
||||
{
|
||||
settings.directConnect.client.airdcppUserSettings.system_info
|
||||
settings.directConnect.client.airDCPPUserSettings.system_info
|
||||
.hostname
|
||||
}
|
||||
</dt>
|
||||
<dt>
|
||||
Platform:{" "}
|
||||
{
|
||||
settings.directConnect.client.airdcppUserSettings.system_info
|
||||
settings.directConnect.client.airDCPPUserSettings.system_info
|
||||
.platform
|
||||
}
|
||||
</dt>
|
||||
@@ -37,7 +38,7 @@ export const AirDCPPSettingsConfirmation = (settingsObject): ReactElement => {
|
||||
<dt>
|
||||
Username:{" "}
|
||||
{
|
||||
settings.directConnect.client.airdcppUserSettings.user
|
||||
settings.directConnect.client.airDCPPUserSettings.user
|
||||
.username
|
||||
}
|
||||
</dt>
|
||||
@@ -45,7 +46,7 @@ export const AirDCPPSettingsConfirmation = (settingsObject): ReactElement => {
|
||||
<dt>
|
||||
Active Sessions:{" "}
|
||||
{
|
||||
settings.directConnect.client.airdcppUserSettings.user
|
||||
settings.directConnect.client.airDCPPUserSettings.user
|
||||
.active_sessions
|
||||
}
|
||||
</dt>
|
||||
@@ -53,7 +54,7 @@ export const AirDCPPSettingsConfirmation = (settingsObject): ReactElement => {
|
||||
Permissions:{" "}
|
||||
<pre>
|
||||
{JSON.stringify(
|
||||
settings.directConnect.client.airdcppUserSettings.user
|
||||
settings.directConnect.client.airDCPPUserSettings.user
|
||||
.permissions,
|
||||
undefined,
|
||||
2,
|
||||
|
||||
145
src/client/components/AirDCPPSettings/AirDCPPSettingsForm.tsx
Normal file
145
src/client/components/AirDCPPSettings/AirDCPPSettingsForm.tsx
Normal file
@@ -0,0 +1,145 @@
|
||||
import React, { ReactElement, useCallback, useContext, useEffect } from "react";
|
||||
import { Form, Field } from "react-final-form";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { saveSettings, deleteSettings } from "../../actions/settings.actions";
|
||||
import { AirDCPPSettingsConfirmation } from "./AirDCPPSettingsConfirmation";
|
||||
import axios from "axios";
|
||||
import { AirDCPPSocketContext } from "../../context/AirDCPPSocket";
|
||||
import AirDCPPSocket from "../../services/DcppSearchService";
|
||||
import { isUndefined, isEmpty } from "lodash";
|
||||
|
||||
export const AirDCPPSettingsForm = (airDCPPClientSettings): ReactElement => {
|
||||
const { settings } = airDCPPClientSettings;
|
||||
const dispatch = useDispatch();
|
||||
const { setADCPPSocket } = useContext(AirDCPPSocketContext);
|
||||
|
||||
const onSubmit = async (values) => {
|
||||
try {
|
||||
const airDCPPResponse = await axios({
|
||||
url: `${values.protocol}://${values.hostname}/api/v1/sessions/authorize`,
|
||||
method: "POST",
|
||||
data: {
|
||||
username: values.username,
|
||||
password: values.password,
|
||||
},
|
||||
});
|
||||
if (airDCPPResponse.status === 200) {
|
||||
dispatch(
|
||||
saveSettings({
|
||||
host: values,
|
||||
airDCPPUserSettings: airDCPPResponse.data,
|
||||
}),
|
||||
);
|
||||
setADCPPSocket(
|
||||
new AirDCPPSocket({
|
||||
hostname: `${values.hostname}`,
|
||||
}),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
const removeSettings = useCallback(async () => {
|
||||
dispatch(deleteSettings());
|
||||
setADCPPSocket({});
|
||||
}, []);
|
||||
|
||||
const validate = async () => {};
|
||||
const initFormData =
|
||||
!isEmpty(settings.directConnect) || !isUndefined(settings.directConnect)
|
||||
? settings.directConnect.client.host
|
||||
: {};
|
||||
return (
|
||||
<>
|
||||
<Form
|
||||
onSubmit={onSubmit}
|
||||
validate={validate}
|
||||
initialValues={initFormData}
|
||||
render={({ handleSubmit }) => (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<h2>AirDC++ Connection Information</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>
|
||||
<p className="control is-expanded">
|
||||
<Field
|
||||
name="hostname"
|
||||
component="input"
|
||||
className="input"
|
||||
placeholder="AirDC++ host IP / hostname"
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
<div className="field">
|
||||
<div className="is-clearfix">
|
||||
<label className="label">Credentials</label>
|
||||
</div>
|
||||
<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>
|
||||
<span className="icon is-small is-right">
|
||||
<i className="fas fa-check"></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(settings) ? (
|
||||
<AirDCPPSettingsConfirmation settings={settings} />
|
||||
) : null}
|
||||
|
||||
{!isEmpty(settings) ? (
|
||||
<p className="control mt-4">
|
||||
<button className="button is-danger" onClick={removeSettings}>
|
||||
Delete
|
||||
</button>
|
||||
</p>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AirDCPPSettingsForm;
|
||||
Reference in New Issue
Block a user