mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
feat: Added error message if admin password wrong
Improved looks of admin panel
This commit is contained in:
@@ -120,8 +120,7 @@ export class AudioManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//this.#socket = new WebSocket(`wss://${wsAddress}/${this.#endpoint}`);
|
this.#socket = new WebSocket(`wss://${wsAddress}/${this.#endpoint}`);
|
||||||
this.#socket = new WebSocket(`wss://refugees.dcsolympus.com/audio`);
|
|
||||||
if (!this.#socket) this.#socket = new WebSocket(`ws://${wsAddress}:${this.#port}`);
|
if (!this.#socket) this.#socket = new WebSocket(`ws://${wsAddress}:${this.#port}`);
|
||||||
|
|
||||||
if (!this.#socket) {
|
if (!this.#socket) {
|
||||||
|
|||||||
@@ -74,20 +74,38 @@ export function AdminModal(props: { open: boolean }) {
|
|||||||
});
|
});
|
||||||
}, [adminPassword, configs]);
|
}, [adminPassword, configs]);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal open={props.open} size={"full"}>
|
<Modal open={props.open} size={"full"}>
|
||||||
<div className="flex flex-col lg:flex-row w-full gap-4">
|
<h2 className="text-2xl font-bold text-gray-200">User admin panel</h2>
|
||||||
<div className="lg:w-[40%]">
|
<div
|
||||||
|
className={`
|
||||||
|
flex w-full flex-col gap-4 p-4
|
||||||
|
lg:flex-row
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={`
|
||||||
|
flex flex-col gap-2 rounded-lg border-2 border-gray-500
|
||||||
|
bg-olympus-600/50 p-4
|
||||||
|
lg:w-[40%]
|
||||||
|
`}
|
||||||
|
>
|
||||||
<div className="text-white">Groups:</div>
|
<div className="text-white">Groups:</div>
|
||||||
<div className="flex max-h-[calc(100vh-280px)] flex-col gap-1 overflow-auto p-2">
|
<div
|
||||||
|
className={`
|
||||||
|
flex h-[calc(100vh-450px)] flex-col gap-1 overflow-auto p-2
|
||||||
|
`}
|
||||||
|
>
|
||||||
{configs.groups &&
|
{configs.groups &&
|
||||||
Object.keys(configs.groups).map((group: any) => {
|
Object.keys(configs.groups).map((group: any, idx: number) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={group}
|
key={group}
|
||||||
className={`
|
className={`
|
||||||
flex justify-between gap-4 text-sm text-gray-200
|
flex justify-between gap-4 bg-white/5 p-2 text-sm
|
||||||
|
text-gray-200
|
||||||
|
${idx % 2 === 0 ? "bg-black/5" : ""}
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
<div className="my-auto">{group}</div>
|
<div className="my-auto">{group}</div>
|
||||||
@@ -121,7 +139,7 @@ export function AdminModal(props: { open: boolean }) {
|
|||||||
hover:bg-red-400
|
hover:bg-red-400
|
||||||
`}
|
`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
delete configs["users"][group];
|
delete configs["groups"][group];
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FaTrash className={`text-gray-50`}></FaTrash>
|
<FaTrash className={`text-gray-50`}></FaTrash>
|
||||||
@@ -173,75 +191,96 @@ export function AdminModal(props: { open: boolean }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex lg:w-[58%] flex-col gap-2">
|
<div
|
||||||
|
className={`
|
||||||
|
flex flex-col gap-2 rounded-lg border-2 border-gray-500
|
||||||
|
bg-olympus-600/50 p-4
|
||||||
|
lg:w-[58%]
|
||||||
|
`}
|
||||||
|
>
|
||||||
<div className="text-white">Users:</div>
|
<div className="text-white">Users:</div>
|
||||||
<div className={`flex max-h-[calc(100vh-280px)] flex-col gap-1 overflow-auto p-2`}>
|
<div
|
||||||
|
className={`
|
||||||
|
flex h-[calc(100vh-450px)] flex-col gap-1 overflow-auto p-2
|
||||||
|
`}
|
||||||
|
>
|
||||||
{configs.users &&
|
{configs.users &&
|
||||||
Object.keys(configs.users).map((user: any) => {
|
Object.keys(configs.users).map((user: any, idx: number) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={user.id}
|
key={user.id}
|
||||||
className={`
|
className={`
|
||||||
flex justify-between gap-2 text-sm text-gray-200
|
flex flex-col gap-2 bg-white/5 p-2 text-sm text-gray-200
|
||||||
|
lg:flex-row
|
||||||
|
${idx % 2 === 0 ? "bg-black/5" : ""}
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
<div className="my-auto">{user}</div>
|
|
||||||
|
|
||||||
<OlDropdown
|
|
||||||
label="Enabled roles"
|
|
||||||
className={`my-auto ml-auto min-w-48`}
|
|
||||||
disableAutoClose={true}
|
|
||||||
>
|
|
||||||
{["Game master", "Blue commander", "Red commander"].map((role: any) => {
|
|
||||||
return (
|
|
||||||
<div key={role} className="flex gap-2 p-2">
|
|
||||||
<OlCheckbox
|
|
||||||
checked={configs["users"][user].roles.includes(role)}
|
|
||||||
onChange={(ev) => {
|
|
||||||
if (ev.target.checked) {
|
|
||||||
configs["users"][user].roles.push(role);
|
|
||||||
} else {
|
|
||||||
configs["users"][user].roles = configs["users"][user].roles.filter((r: any) => r !== role);
|
|
||||||
}
|
|
||||||
setConfigs({ ...configs });
|
|
||||||
}}
|
|
||||||
></OlCheckbox>
|
|
||||||
{role}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</OlDropdown>
|
|
||||||
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
autoComplete="new-password"
|
|
||||||
onChange={(ev) => {
|
|
||||||
var hash = sha256.create();
|
|
||||||
configs["users"][user].password = hash.update(ev.currentTarget.value).hex();
|
|
||||||
setConfigs({ ...configs });
|
|
||||||
}}
|
|
||||||
className={`
|
|
||||||
max-w-44 rounded-lg border border-gray-300 bg-gray-50
|
|
||||||
p-2.5 text-sm text-gray-900
|
|
||||||
dark:border-gray-600 dark:bg-gray-700 dark:text-white
|
|
||||||
dark:placeholder-gray-400 dark:focus:border-blue-500
|
|
||||||
dark:focus:ring-blue-500
|
|
||||||
focus:border-blue-500 focus:ring-blue-500
|
|
||||||
`}
|
|
||||||
placeholder="Change password"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<div
|
<div
|
||||||
className={`
|
className={`
|
||||||
my-auto cursor-pointer rounded-md bg-red-600 p-2
|
flex w-full content-center justify-between gap-4
|
||||||
hover:bg-red-400
|
|
||||||
`}
|
`}
|
||||||
onClick={() => {
|
|
||||||
delete configs["users"][user];
|
|
||||||
setConfigs({ ...configs });
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<FaTrash className={`text-gray-50`}></FaTrash>
|
<div className="my-auto">{user}</div>
|
||||||
|
|
||||||
|
<OlDropdown
|
||||||
|
label="Enabled roles"
|
||||||
|
className={`my-auto ml-auto min-w-48`}
|
||||||
|
disableAutoClose={true}
|
||||||
|
>
|
||||||
|
{["Game master", "Blue commander", "Red commander"].map((role: any) => {
|
||||||
|
return (
|
||||||
|
<div key={role} className="flex gap-2 p-2">
|
||||||
|
<OlCheckbox
|
||||||
|
checked={configs["users"][user].roles.includes(role)}
|
||||||
|
onChange={(ev) => {
|
||||||
|
if (ev.target.checked) {
|
||||||
|
configs["users"][user].roles.push(role);
|
||||||
|
} else {
|
||||||
|
configs["users"][user].roles = configs["users"][user].roles.filter((r: any) => r !== role);
|
||||||
|
}
|
||||||
|
setConfigs({ ...configs });
|
||||||
|
}}
|
||||||
|
></OlCheckbox>
|
||||||
|
{role}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</OlDropdown>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex content-center justify-between gap-4">
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
autoComplete="new-password"
|
||||||
|
onChange={(ev) => {
|
||||||
|
var hash = sha256.create();
|
||||||
|
configs["users"][user].password = hash.update(ev.currentTarget.value).hex();
|
||||||
|
setConfigs({ ...configs });
|
||||||
|
}}
|
||||||
|
className={`
|
||||||
|
w-full rounded-lg border border-gray-300 bg-gray-50
|
||||||
|
p-2.5 text-sm text-gray-900
|
||||||
|
dark:border-gray-600 dark:bg-gray-700 dark:text-white
|
||||||
|
dark:placeholder-gray-400 dark:focus:border-blue-500
|
||||||
|
dark:focus:ring-blue-500
|
||||||
|
focus:border-blue-500 focus:ring-blue-500
|
||||||
|
lg:max-w-92
|
||||||
|
`}
|
||||||
|
placeholder="Change password"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className={`
|
||||||
|
my-auto cursor-pointer rounded-md bg-red-600 p-2
|
||||||
|
hover:bg-red-400
|
||||||
|
`}
|
||||||
|
onClick={() => {
|
||||||
|
delete configs["users"][user];
|
||||||
|
setConfigs({ ...configs });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FaTrash className={`text-gray-50`}></FaTrash>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -291,7 +330,12 @@ export function AdminModal(props: { open: boolean }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-auto flex justify-between">
|
<div
|
||||||
|
className={`
|
||||||
|
mt-auto flex flex-col justify-between gap-4
|
||||||
|
lg:flex-row
|
||||||
|
`}
|
||||||
|
>
|
||||||
<div className="my-auto flex gap-4 text-sm text-gray-400">
|
<div className="my-auto flex gap-4 text-sm text-gray-400">
|
||||||
<div className="my-auto">Reset all user preferences, use with caution</div>
|
<div className="my-auto">Reset all user preferences, use with caution</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -318,10 +362,10 @@ export function AdminModal(props: { open: boolean }) {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
uploadNewConfig();
|
uploadNewConfig();
|
||||||
getApp().setState(OlympusState.IDLE)}
|
getApp().setState(OlympusState.IDLE);
|
||||||
}
|
}}
|
||||||
className={`
|
className={`
|
||||||
my-auto flex content-center items-center gap-2 rounded-sm
|
my-auto ml-auto flex content-center items-center gap-2 rounded-sm
|
||||||
bg-blue-700 px-5 py-2.5 text-sm font-medium text-white
|
bg-blue-700 px-5 py-2.5 text-sm font-medium text-white
|
||||||
dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800
|
dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800
|
||||||
focus:outline-none focus:ring-4 focus:ring-blue-300
|
focus:outline-none focus:ring-4 focus:ring-blue-300
|
||||||
|
|||||||
@@ -27,9 +27,8 @@ export function Modal(props: {
|
|||||||
<div
|
<div
|
||||||
className={`
|
className={`
|
||||||
fixed left-[50%] top-[50%] z-40 inline-flex translate-x-[-50%]
|
fixed left-[50%] top-[50%] z-40 inline-flex translate-x-[-50%]
|
||||||
translate-y-[-50%] overflow-y-auto scroll-smooth rounded-xl
|
translate-y-[-50%] rounded-xl border-[1px] border-solid
|
||||||
border-[1px] border-solid border-gray-700 bg-olympus-800
|
border-gray-700 bg-olympus-800 drop-shadow-md
|
||||||
drop-shadow-md
|
|
||||||
max-md:rounded-none max-md:border-none
|
max-md:rounded-none max-md:border-none
|
||||||
${
|
${
|
||||||
props.size === "lg"
|
props.size === "lg"
|
||||||
@@ -77,9 +76,10 @@ export function Modal(props: {
|
|||||||
></div>
|
></div>
|
||||||
<div
|
<div
|
||||||
className={`
|
className={`
|
||||||
absolute flex h-full w-full flex-col gap-8 p-16
|
absolute flex h-full max-h-full w-full flex-col gap-8
|
||||||
|
overflow-y-auto scroll-smooth p-16
|
||||||
max-lg:p-8
|
max-lg:p-8
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
{!props.disableClose && (
|
{!props.disableClose && (
|
||||||
|
|||||||
@@ -51,7 +51,9 @@ export function WarningModal(props: { open: boolean }) {
|
|||||||
<span>Your connection to DCS Olympus is not secure.</span>
|
<span>Your connection to DCS Olympus is not secure.</span>
|
||||||
<span>To protect your personal data some advanced DCS Olympus features like the camera plugin or the audio backend have been disabled.</span>
|
<span>To protect your personal data some advanced DCS Olympus features like the camera plugin or the audio backend have been disabled.</span>
|
||||||
<span>
|
<span>
|
||||||
To solve this issue, DCS Olympus should be served using the <span className={`italic`}>https</span> protocol.
|
To solve this issue, DCS Olympus should be served using the <span className={`
|
||||||
|
italic
|
||||||
|
`}>https</span> protocol.
|
||||||
</span>
|
</span>
|
||||||
<span>To do so, we suggest using a dedicated server and a reverse proxy with SSL enabled.</span>
|
<span>To do so, we suggest using a dedicated server and a reverse proxy with SSL enabled.</span>
|
||||||
<div className="mt-5 flex gap-4">
|
<div className="mt-5 flex gap-4">
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ export function OptionsMenu(props: { open: boolean; onClose: () => void; childre
|
|||||||
getApp().setState(OlympusState.ADMIN);
|
getApp().setState(OlympusState.ADMIN);
|
||||||
return response.json();
|
return response.json();
|
||||||
} else {
|
} else {
|
||||||
|
getApp().addInfoMessage(`Admin password incorrect!`);
|
||||||
throw new Error("Admin password incorrect");
|
throw new Error("Admin password incorrect");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user