mirror of
https://github.com/C9Glax/tranga-website.git
synced 2025-04-18 22:33:20 +02:00
Add all types of Notification Connectors to settings
This commit is contained in:
parent
60f957ede2
commit
ecd76712d8
@ -16,18 +16,16 @@ export default function App(){
|
|||||||
const [updateInterval, setUpdateInterval] = React.useState<number | undefined>(undefined);
|
const [updateInterval, setUpdateInterval] = React.useState<number | undefined>(undefined);
|
||||||
const checkConnectedInterval = 1000;
|
const checkConnectedInterval = 1000;
|
||||||
|
|
||||||
const apiUri = frontendSettings.apiUri;
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCookie('apiUri', frontendSettings.apiUri);
|
setCookie('apiUri', frontendSettings.apiUri);
|
||||||
setCookie('jobInterval', frontendSettings.jobInterval);
|
setCookie('jobInterval', frontendSettings.jobInterval);
|
||||||
updateConnected(apiUri, connected, setConnected);
|
updateConnected(frontendSettings.apiUri, connected, setConnected);
|
||||||
}, [frontendSettings]);
|
}, [frontendSettings]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(updateInterval === undefined){
|
if(updateInterval === undefined){
|
||||||
setUpdateInterval(setInterval(() => {
|
setUpdateInterval(setInterval(() => {
|
||||||
updateConnected(apiUri, connected, setConnected);
|
updateConnected(frontendSettings.apiUri, connected, setConnected);
|
||||||
}, checkConnectedInterval));
|
}, checkConnectedInterval));
|
||||||
}else{
|
}else{
|
||||||
clearInterval(updateInterval);
|
clearInterval(updateInterval);
|
||||||
@ -36,23 +34,23 @@ export default function App(){
|
|||||||
}, [connected]);
|
}, [connected]);
|
||||||
|
|
||||||
return(<div>
|
return(<div>
|
||||||
<Header apiUri={apiUri} backendConnected={connected} settings={frontendSettings} setFrontendSettings={setFrontendSettings} />
|
<Header apiUri={frontendSettings.apiUri} backendConnected={connected} settings={frontendSettings} setFrontendSettings={setFrontendSettings} />
|
||||||
{connected
|
{connected
|
||||||
? <>
|
? <>
|
||||||
{showSearch
|
{showSearch
|
||||||
? <>
|
? <>
|
||||||
<Search apiUri={apiUri} jobInterval={frontendSettings.jobInterval} closeSearch={() => setShowSearch(false)} />
|
<Search apiUri={frontendSettings.apiUri} jobInterval={frontendSettings.jobInterval} closeSearch={() => setShowSearch(false)} />
|
||||||
<hr/>
|
<hr/>
|
||||||
</>
|
</>
|
||||||
: <></>}
|
: <></>}
|
||||||
<MonitorJobsList apiUri={apiUri} onStartSearch={() => setShowSearch(true)} connectedToBackend={connected} checkConnectedInterval={checkConnectedInterval} />
|
<MonitorJobsList apiUri={frontendSettings.apiUri} onStartSearch={() => setShowSearch(true)} connectedToBackend={connected} checkConnectedInterval={checkConnectedInterval} />
|
||||||
</>
|
</>
|
||||||
: <>
|
: <>
|
||||||
<h1>No connection to the Backend.</h1>
|
<h1>No connection to the Backend.</h1>
|
||||||
<h3>Check the Settings ApiUri.</h3>
|
<h3>Check the Settings ApiUri.</h3>
|
||||||
<Loader loading={true} />
|
<Loader loading={true} />
|
||||||
</>}
|
</>}
|
||||||
<Footer apiUri={apiUri} connectedToBackend={connected} checkConnectedInterval={checkConnectedInterval} />
|
<Footer apiUri={frontendSettings.apiUri} connectedToBackend={connected} checkConnectedInterval={checkConnectedInterval} />
|
||||||
</div>)
|
</div>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,12 @@ export default function Settings({backendConnected, apiUri, frontendSettings, se
|
|||||||
NotificationConnectorFunctions.GetNotificationConnectors(apiUri).then(setNotificationConnectors);
|
NotificationConnectorFunctions.GetNotificationConnectors(apiUri).then(setNotificationConnectors);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const dateToStr = (x: Date) => {
|
||||||
|
const ret = (x.getHours() < 10 ? "0" + x.getHours() : x.getHours())
|
||||||
|
+ ":" +
|
||||||
|
(x.getMinutes() < 10 ? "0" + x.getMinutes() : x.getMinutes());
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="Settings">
|
<div id="Settings">
|
||||||
@ -30,20 +36,11 @@ export default function Settings({backendConnected, apiUri, frontendSettings, se
|
|||||||
<div id="SettingsPopUpBody" className="popupBody">
|
<div id="SettingsPopUpBody" className="popupBody">
|
||||||
<div className="settings-apiuri">
|
<div className="settings-apiuri">
|
||||||
<label>ApiUri</label>
|
<label>ApiUri</label>
|
||||||
<input type="url" defaultValue={frontendSettings.apiUri} onChange={(e) => {
|
<input type="url" defaultValue={frontendSettings.apiUri} onChange={(e) => setFrontendSettings({...frontendSettings, apiUri:e.currentTarget.value})} id="ApiUri" />
|
||||||
let newSettings = frontendSettings;
|
|
||||||
newSettings.apiUri = e.currentTarget.value;
|
|
||||||
setFrontendSettings(newSettings);
|
|
||||||
}} id="ApiUri" />
|
|
||||||
</div>
|
</div>
|
||||||
<div className="settings-apiuri">
|
<div className="settings-apiuri">
|
||||||
<label>Default Job-Interval</label>
|
<label>Default Job-Interval</label>
|
||||||
<input type="time" defaultValue={new Date(frontendSettings.jobInterval).getTime()} onChange={(e) => {
|
<input type="time" min="00:30" max="23:59" defaultValue={dateToStr(new Date(frontendSettings.jobInterval))} onChange={(e) => setFrontendSettings({...frontendSettings, jobInterval: new Date(e.currentTarget.valueAsNumber-60*60*1000) ?? frontendSettings.jobInterval})}/>
|
||||||
let newSettings = frontendSettings;
|
|
||||||
newSettings.jobInterval = e.currentTarget.valueAsDate ?? frontendSettings.jobInterval;
|
|
||||||
setFrontendSettings(newSettings);
|
|
||||||
console.log(frontendSettings);
|
|
||||||
}}/>
|
|
||||||
</div>
|
</div>
|
||||||
{notificationConnectors.map(c => <NotificationConnectorItem apiUri={apiUri} notificationConnector={c} />)}
|
{notificationConnectors.map(c => <NotificationConnectorItem apiUri={apiUri} notificationConnector={c} />)}
|
||||||
<NotificationConnectorItem apiUri={apiUri} notificationConnector={null} />
|
<NotificationConnectorItem apiUri={apiUri} notificationConnector={null} />
|
||||||
|
@ -2,6 +2,9 @@ import {ReactElement, ReactEventHandler, useState} from "react";
|
|||||||
import "../../styles/notificationConnector.css";
|
import "../../styles/notificationConnector.css";
|
||||||
import Loader from "../Loader";
|
import Loader from "../Loader";
|
||||||
import NotificationConnectorFunctions from "../NotificationConnectorFunctions";
|
import NotificationConnectorFunctions from "../NotificationConnectorFunctions";
|
||||||
|
import {LunaseaItem} from "./records/ILunaseaRecord";
|
||||||
|
import {GotifyItem} from "./records/IGotifyRecord";
|
||||||
|
import {NtfyItem} from "./records/INtfyRecord";
|
||||||
|
|
||||||
export default interface INotificationConnector {
|
export default interface INotificationConnector {
|
||||||
name: string;
|
name: string;
|
||||||
@ -12,7 +15,32 @@ export default interface INotificationConnector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function NotificationConnectorItem({apiUri, notificationConnector} : {apiUri: string, notificationConnector: INotificationConnector | null}) : ReactElement {
|
export function NotificationConnectorItem({apiUri, notificationConnector} : {apiUri: string, notificationConnector: INotificationConnector | null}) : ReactElement {
|
||||||
const AddHeader : ReactEventHandler<HTMLButtonElement> = (e) => {
|
if(notificationConnector != null)
|
||||||
|
return <DefaultItem apiUri={apiUri} notificationConnector={notificationConnector} />
|
||||||
|
|
||||||
|
const [selectedConnectorElement, setSelectedConnectorElement] = useState<ReactElement>(<DefaultItem apiUri={apiUri} notificationConnector={null} />);
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<p>New Notification Connector</p>
|
||||||
|
<select defaultValue="default" onChange={(e) => {
|
||||||
|
switch (e.currentTarget.value){
|
||||||
|
case "default": setSelectedConnectorElement(<DefaultItem apiUri={apiUri} notificationConnector={null} />); break;
|
||||||
|
case "gotify": setSelectedConnectorElement(<GotifyItem apiUri={apiUri} />); break;
|
||||||
|
case "ntfy": setSelectedConnectorElement(<NtfyItem apiUri={apiUri} />); break;
|
||||||
|
case "lunasea": setSelectedConnectorElement(<LunaseaItem apiUri={apiUri} />); break;
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<option value="default">Generic REST</option>
|
||||||
|
<option value="gotify">Gotify</option>
|
||||||
|
<option value="ntfy">Ntfy</option>
|
||||||
|
<option value="lunasea">Lunasea</option>
|
||||||
|
</select>
|
||||||
|
{selectedConnectorElement}
|
||||||
|
</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function DefaultItem({apiUri, notificationConnector}:{apiUri: string, notificationConnector: INotificationConnector | null}) : ReactElement {
|
||||||
|
const AddHeader : ReactEventHandler<HTMLButtonElement> = () => {
|
||||||
let header : Record<string, string> = {};
|
let header : Record<string, string> = {};
|
||||||
let x = info;
|
let x = info;
|
||||||
x.headers = [header, ...x.headers];
|
x.headers = [header, ...x.headers];
|
||||||
@ -20,7 +48,6 @@ export function NotificationConnectorItem({apiUri, notificationConnector} : {api
|
|||||||
setHeaderElements([...headerElements, <HeaderElement record={header} />])
|
setHeaderElements([...headerElements, <HeaderElement record={header} />])
|
||||||
}
|
}
|
||||||
const [headerElements, setHeaderElements] = useState<ReactElement[]>([]);
|
const [headerElements, setHeaderElements] = useState<ReactElement[]>([]);
|
||||||
const [loading, setLoading] = useState<boolean>(false);
|
|
||||||
const [info, setInfo] = useState<INotificationConnector>({
|
const [info, setInfo] = useState<INotificationConnector>({
|
||||||
name: "",
|
name: "",
|
||||||
url: "",
|
url: "",
|
||||||
@ -28,30 +55,22 @@ export function NotificationConnectorItem({apiUri, notificationConnector} : {api
|
|||||||
httpMethod: "",
|
httpMethod: "",
|
||||||
body: ""
|
body: ""
|
||||||
});
|
});
|
||||||
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
return (<div className="NotificationConnectorItem" key={notificationConnector ? notificationConnector.name : "new"}>
|
return <div className="NotificationConnectorItem">
|
||||||
<p className="NotificationConnectorItem-Name">{notificationConnector ? notificationConnector.name : "New Notification Connector"}</p>
|
<input className="NotificationConnectorItem-Name" placeholder="Name" defaultValue={notificationConnector ? notificationConnector.name : ""}
|
||||||
|
disabled={notificationConnector != null} onChange={(e) => setInfo({...info, name: e.currentTarget.value})} />
|
||||||
<div className="NotificationConnectorItem-Url">
|
<div className="NotificationConnectorItem-Url">
|
||||||
<select className="NotificationConnectorItem-RequestMethod" defaultValue={notificationConnector ? notificationConnector.httpMethod : ""} disabled={notificationConnector != null} onChange={(e) => {
|
<select className="NotificationConnectorItem-RequestMethod" defaultValue={notificationConnector ? notificationConnector.httpMethod : ""}
|
||||||
let x = info;
|
disabled={notificationConnector != null} onChange={(e)=> setInfo({...info, httpMethod: e.currentTarget.value})} >
|
||||||
x.httpMethod = e.currentTarget.value;
|
|
||||||
setInfo(x);
|
|
||||||
}}>
|
|
||||||
<option value="" disabled hidden>Request Method</option>
|
<option value="" disabled hidden>Request Method</option>
|
||||||
<option value="GET">GET</option>
|
<option value="GET">GET</option>
|
||||||
<option value="POST">POST</option>
|
<option value="POST">POST</option>
|
||||||
</select>
|
</select>
|
||||||
<input type="url" className="NotificationConnectorItem-RequestUrl" placeholder="URL" defaultValue={notificationConnector ? notificationConnector.url : ""} disabled={notificationConnector != null} onChange={(e) => {
|
<input type="url" className="NotificationConnectorItem-RequestUrl" placeholder="URL" defaultValue={notificationConnector ? notificationConnector.url : ""}
|
||||||
let x = info;
|
disabled={notificationConnector != null} onChange={(e) => setInfo({...info, url: e.currentTarget.value})} />
|
||||||
x.url = e.currentTarget.value;
|
|
||||||
setInfo(x);
|
|
||||||
}} />
|
|
||||||
</div>
|
</div>
|
||||||
<textarea className="NotificationConnectorItem-Body" placeholder="Request-Body" defaultValue={notificationConnector ? notificationConnector.body : ""} disabled={notificationConnector != null} onChange={(e) => {
|
<textarea className="NotificationConnectorItem-Body" placeholder="Request-Body" defaultValue={notificationConnector ? notificationConnector.body : ""}
|
||||||
let x = info;
|
disabled={notificationConnector != null} onChange={(e)=> setInfo({...info, body: e.currentTarget.value})} />
|
||||||
x.body = e.currentTarget.value;
|
|
||||||
setInfo(x);
|
|
||||||
}} />
|
|
||||||
{notificationConnector != null ? null :
|
{notificationConnector != null ? null :
|
||||||
(
|
(
|
||||||
<p className="NotificationConnectorItem-Explanation">Explanation Text</p>
|
<p className="NotificationConnectorItem-Explanation">Explanation Text</p>
|
||||||
@ -67,17 +86,15 @@ export function NotificationConnectorItem({apiUri, notificationConnector} : {api
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
{notificationConnector != null ? null : (
|
<>
|
||||||
<>
|
<button className="NotificationConnectorItem-Save" onClick={(e) => {
|
||||||
<button className="NotificationConnectorItem-Save" onClick={(e) => {
|
setLoading(true);
|
||||||
setLoading(true);
|
NotificationConnectorFunctions.CreateNotificationConnector(apiUri, info)
|
||||||
NotificationConnectorFunctions.CreateNotificationConnector(apiUri, info)
|
.finally(() => setLoading(false));
|
||||||
.finally(() => setLoading(false));
|
}}>Add</button>
|
||||||
}}>Add</button>
|
<Loader loading={loading} style={{width:"40px",height:"40px",margin:"calc(sin(70)*(50% - 40px))"}}/>
|
||||||
<Loader loading={loading} style={{width:"40px",height:"40px",margin:"calc(sin(70)*(50% - 40px))"}}/>
|
</>
|
||||||
</>
|
</div>
|
||||||
)}
|
|
||||||
</div>);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function HeaderElement({record, disabled} : {record: Record<string, string>, disabled?: boolean | null}) : ReactElement {
|
function HeaderElement({record, disabled} : {record: Record<string, string>, disabled?: boolean | null}) : ReactElement {
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
export default interface IGotifyRecord {
|
|
||||||
endpoint: string;
|
|
||||||
appToken: string;
|
|
||||||
priority: number;
|
|
||||||
}
|
|
51
Website/modules/interfaces/records/IGotifyRecord.tsx
Normal file
51
Website/modules/interfaces/records/IGotifyRecord.tsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import {ReactElement, useState} from "react";
|
||||||
|
import NotificationConnectorFunctions from "../../NotificationConnectorFunctions";
|
||||||
|
import Loader from "../../Loader";
|
||||||
|
import "../../../styles/notificationConnector.css";
|
||||||
|
import {isValidUri} from "../../../App";
|
||||||
|
|
||||||
|
export default interface IGotifyRecord {
|
||||||
|
endpoint: string;
|
||||||
|
appToken: string;
|
||||||
|
priority: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Validate(record: IGotifyRecord) : boolean {
|
||||||
|
if(!isValidUri(record.endpoint))
|
||||||
|
return false;
|
||||||
|
if(record.appToken.length < 1)
|
||||||
|
return false;
|
||||||
|
if(record.priority < 1 || record.priority > 5)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GotifyItem ({apiUri} : {apiUri: string}) : ReactElement{
|
||||||
|
const [record, setRecord] = useState<IGotifyRecord>({
|
||||||
|
endpoint: "",
|
||||||
|
appToken: "",
|
||||||
|
priority: 3
|
||||||
|
});
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
return <div className="NotificationConnectorItem">
|
||||||
|
<input className="NotificationConnectorItem-Name" value="Gotify" disabled={true} />
|
||||||
|
<div className="NotificationConnectorItem-Url">
|
||||||
|
<input type="text" className="NotificationConnectorItem-RequestUrl" placeholder="URL" onChange={(e) => setRecord({...record, endpoint: e.currentTarget.value})} />
|
||||||
|
<input type="text" className="NotificationConnectorItem-AppToken" placeholder="Apptoken" onChange={(e) => setRecord({...record, appToken: e.currentTarget.value})} />
|
||||||
|
</div>
|
||||||
|
<div className="NotificationConnectorItem-Priority">
|
||||||
|
<label htmlFor="NotificationConnectorItem-Priority">Priority</label>
|
||||||
|
<input id="NotificationConnectorItem-Priority-Value" type="number" className="NotificationConnectorItem-Priority-Value" min={1} max={5} defaultValue={3} onChange={(e) => setRecord({...record, priority: e.currentTarget.valueAsNumber})} />
|
||||||
|
</div>
|
||||||
|
<>
|
||||||
|
<button className="NotificationConnectorItem-Save" onClick={(e) => {
|
||||||
|
if(record === null || Validate(record) === false)
|
||||||
|
return;
|
||||||
|
setLoading(true);
|
||||||
|
NotificationConnectorFunctions.CreateGotify(apiUri, record)
|
||||||
|
.finally(() => setLoading(false));
|
||||||
|
}}>Add</button>
|
||||||
|
<Loader loading={loading} style={{width:"40px",height:"40px",margin:"calc(sin(70)*(50% - 40px))"}}/>
|
||||||
|
</>
|
||||||
|
</div>;
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
export default interface ILunaseaRecord {
|
|
||||||
id: string;
|
|
||||||
}
|
|
36
Website/modules/interfaces/records/ILunaseaRecord.tsx
Normal file
36
Website/modules/interfaces/records/ILunaseaRecord.tsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import {ReactElement, useState} from "react";
|
||||||
|
import NotificationConnectorFunctions from "../../NotificationConnectorFunctions";
|
||||||
|
import Loader from "../../Loader";
|
||||||
|
import "../../../styles/notificationConnector.css";
|
||||||
|
|
||||||
|
export default interface ILunaseaRecord {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const regex = new RegExp("(?:device|user)\/[0-9a-zA-Z\-]+");
|
||||||
|
function Validate(record: ILunaseaRecord) : boolean {
|
||||||
|
return regex.test(record.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LunaseaItem ({apiUri} : {apiUri: string}) : ReactElement{
|
||||||
|
const [record, setRecord] = useState<ILunaseaRecord>({
|
||||||
|
id: ""
|
||||||
|
});
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
return <div className="NotificationConnectorItem">
|
||||||
|
<input className="NotificationConnectorItem-Name" value="LunaSea" disabled={true} />
|
||||||
|
<div className="NotificationConnectorItem-Url">
|
||||||
|
<input type="text" className="NotificationConnectorItem-RequestUrl" placeholder="device/:device_id or user/:user_id" onChange={(e) => setRecord({...record, id: e.currentTarget.value})} />
|
||||||
|
</div>
|
||||||
|
<>
|
||||||
|
<button className="NotificationConnectorItem-Save" onClick={(e) => {
|
||||||
|
if(record === null || Validate(record) === false)
|
||||||
|
return;
|
||||||
|
setLoading(true);
|
||||||
|
NotificationConnectorFunctions.CreateLunasea(apiUri, record)
|
||||||
|
.finally(() => setLoading(false));
|
||||||
|
}}>Add</button>
|
||||||
|
<Loader loading={loading} style={{width:"40px",height:"40px",margin:"calc(sin(70)*(50% - 40px))"}}/>
|
||||||
|
</>
|
||||||
|
</div>;
|
||||||
|
}
|
@ -1,7 +0,0 @@
|
|||||||
export default interface INtfyRecord {
|
|
||||||
endpoint: string;
|
|
||||||
username: string;
|
|
||||||
password: string;
|
|
||||||
topic: string;
|
|
||||||
priority: number;
|
|
||||||
}
|
|
62
Website/modules/interfaces/records/INtfyRecord.tsx
Normal file
62
Website/modules/interfaces/records/INtfyRecord.tsx
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import {ReactElement, useState} from "react";
|
||||||
|
import NotificationConnectorFunctions from "../../NotificationConnectorFunctions";
|
||||||
|
import Loader from "../../Loader";
|
||||||
|
import "../../../styles/notificationConnector.css";
|
||||||
|
import {isValidUri} from "../../../App";
|
||||||
|
|
||||||
|
export default interface INtfyRecord {
|
||||||
|
endpoint: string;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
topic: string;
|
||||||
|
priority: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Validate(record: INtfyRecord) : boolean {
|
||||||
|
if(!isValidUri(record.endpoint))
|
||||||
|
return false;
|
||||||
|
if(record.username.length < 1)
|
||||||
|
return false;
|
||||||
|
if(record.password.length < 1)
|
||||||
|
return false;
|
||||||
|
if(record.topic.length < 1)
|
||||||
|
return false;
|
||||||
|
if(record.priority < 1 || record.priority > 5)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function NtfyItem ({apiUri} : {apiUri: string}) : ReactElement{
|
||||||
|
const [info, setInfo] = useState<INtfyRecord>({
|
||||||
|
endpoint: "",
|
||||||
|
username: "",
|
||||||
|
password: "",
|
||||||
|
topic: "",
|
||||||
|
priority: 0
|
||||||
|
});
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
return <div className="NotificationConnectorItem">
|
||||||
|
<input className="NotificationConnectorItem-Name" value="Ntfy" disabled={true} />
|
||||||
|
<div className="NotificationConnectorItem-Url">
|
||||||
|
<input type="text" className="NotificationConnectorItem-RequestUrl" placeholder="URL" onChange={(e) => setInfo({...info, endpoint: e.currentTarget.value})} />
|
||||||
|
<input type="text" className="NotificationConnectorItem-Topic" placeholder="Topic" onChange={(e) => setInfo({...info, topic: e.currentTarget.value})} />
|
||||||
|
</div>
|
||||||
|
<div className="NotificationConnectorItem-Ident">
|
||||||
|
<input type="text" className="NotificationConnectorItem-Username" placeholder="Username" onChange={(e) => setInfo({...info, username: e.currentTarget.value})} />
|
||||||
|
<input type="password" className="NotificationConnectorItem-Password" placeholder="***" onChange={(e) => setInfo({...info, password: e.currentTarget.value})} />
|
||||||
|
</div>
|
||||||
|
<div className="NotificationConnectorItem-Priority">
|
||||||
|
<label htmlFor="NotificationConnectorItem-Priority">Priority</label>
|
||||||
|
<input id="NotificationConnectorItem-Priority-Value" type="number" className="NotificationConnectorItem-Priority-Value" min={1} max={5} defaultValue={3} onChange={(e) => setInfo({...info, priority: e.currentTarget.valueAsNumber})} />
|
||||||
|
</div><>
|
||||||
|
<button className="NotificationConnectorItem-Save" onClick={(e) => {
|
||||||
|
if(info === null || Validate(info) === false)
|
||||||
|
return;
|
||||||
|
setLoading(true);
|
||||||
|
NotificationConnectorFunctions.CreateNtfy(apiUri, info)
|
||||||
|
.finally(() => setLoading(false));
|
||||||
|
}}>Add</button>
|
||||||
|
<Loader loading={loading} style={{width:"40px",height:"40px",margin:"calc(sin(70)*(50% - 40px))"}}/>
|
||||||
|
</>
|
||||||
|
</div>;
|
||||||
|
}
|
@ -6,7 +6,7 @@
|
|||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
grid-template-rows: 30px 30px auto 30px;
|
grid-template-rows: 30px auto auto 30px;
|
||||||
column-gap: 4px;
|
column-gap: 4px;
|
||||||
row-gap: 4px;
|
row-gap: 4px;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
@ -25,6 +25,13 @@
|
|||||||
.NotificationConnectorItem-Name{
|
.NotificationConnectorItem-Name{
|
||||||
grid-area: name;
|
grid-area: name;
|
||||||
justify-self: flex-start;
|
justify-self: flex-start;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.NotificationConnectorItem-Name::before {
|
||||||
|
content: "Connector-Name";
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.NotificationConnectorItem-Url{
|
.NotificationConnectorItem-Url{
|
||||||
@ -46,6 +53,14 @@
|
|||||||
align-self: flex-end;
|
align-self: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.NotificationConnectorItem-Priority {
|
||||||
|
grid-area: explanation;
|
||||||
|
}
|
||||||
|
|
||||||
|
.NotificationConnectorItem-Ident {
|
||||||
|
grid-area: body;
|
||||||
|
}
|
||||||
|
|
||||||
.NotificationConnectorItem-Headers{
|
.NotificationConnectorItem-Headers{
|
||||||
grid-area: headers;
|
grid-area: headers;
|
||||||
justify-self: flex-end;
|
justify-self: flex-end;
|
||||||
|
@ -22,4 +22,13 @@
|
|||||||
|
|
||||||
#SettingsPopUpBody > * {
|
#SettingsPopUpBody > * {
|
||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#SettingsPopUpBody label {
|
||||||
|
width: max-content;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#SettingsPopUpBody label::after {
|
||||||
|
content: ':';
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user