mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-10-23 03:43:33 +00:00
Use a modal manager
This commit is contained in:
@@ -24,6 +24,7 @@
|
|||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
"country-flag-icons": "^1.5.20",
|
"country-flag-icons": "^1.5.20",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
|
"ez-modal-react": "^1.0.5",
|
||||||
"formik": "^2.4.6",
|
"formik": "^2.4.6",
|
||||||
"generate-password-browser": "^1.1.0",
|
"generate-password-browser": "^1.1.0",
|
||||||
"humps": "^2.0.1",
|
"humps": "^2.0.1",
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
||||||
|
import EasyModal from "ez-modal-react";
|
||||||
import { RawIntlProvider } from "react-intl";
|
import { RawIntlProvider } from "react-intl";
|
||||||
import { ToastContainer } from "react-toastify";
|
import { ToastContainer } from "react-toastify";
|
||||||
import { AuthProvider, LocaleProvider, ThemeProvider } from "src/context";
|
import { AuthProvider, LocaleProvider, ThemeProvider } from "src/context";
|
||||||
@@ -16,7 +17,9 @@ function App() {
|
|||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
|
<EasyModal.Provider>
|
||||||
<Router />
|
<Router />
|
||||||
|
</EasyModal.Provider>
|
||||||
<ToastContainer
|
<ToastContainer
|
||||||
position="top-right"
|
position="top-right"
|
||||||
autoClose={5000}
|
autoClose={5000}
|
||||||
|
@@ -1,18 +1,15 @@
|
|||||||
import { IconLock, IconLogout, IconUser } from "@tabler/icons-react";
|
import { IconLock, IconLogout, IconUser } from "@tabler/icons-react";
|
||||||
import { useState } from "react";
|
|
||||||
import { LocalePicker, ThemeSwitcher } from "src/components";
|
import { LocalePicker, ThemeSwitcher } from "src/components";
|
||||||
import { useAuthState } from "src/context";
|
import { useAuthState } from "src/context";
|
||||||
import { useUser } from "src/hooks";
|
import { useUser } from "src/hooks";
|
||||||
import { T } from "src/locale";
|
import { T } from "src/locale";
|
||||||
import { ChangePasswordModal, UserModal } from "src/modals";
|
import { showChangePasswordModal, showUserModal } from "src/modals";
|
||||||
import styles from "./SiteHeader.module.css";
|
import styles from "./SiteHeader.module.css";
|
||||||
|
|
||||||
export function SiteHeader() {
|
export function SiteHeader() {
|
||||||
const { data: currentUser } = useUser("me");
|
const { data: currentUser } = useUser("me");
|
||||||
const isAdmin = currentUser?.roles.includes("admin");
|
const isAdmin = currentUser?.roles.includes("admin");
|
||||||
const { logout } = useAuthState();
|
const { logout } = useAuthState();
|
||||||
const [showProfileEdit, setShowProfileEdit] = useState(false);
|
|
||||||
const [showChangePassword, setShowChangePassword] = useState(false);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="navbar navbar-expand-md d-print-none">
|
<header className="navbar navbar-expand-md d-print-none">
|
||||||
@@ -76,7 +73,7 @@ export function SiteHeader() {
|
|||||||
className="dropdown-item"
|
className="dropdown-item"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setShowProfileEdit(true);
|
showUserModal("me");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconUser width={18} />
|
<IconUser width={18} />
|
||||||
@@ -87,7 +84,7 @@ export function SiteHeader() {
|
|||||||
className="dropdown-item"
|
className="dropdown-item"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setShowChangePassword(true);
|
showChangePasswordModal("me");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconLock width={18} />
|
<IconLock width={18} />
|
||||||
@@ -110,10 +107,6 @@ export function SiteHeader() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{showProfileEdit ? <UserModal userId="me" onClose={() => setShowProfileEdit(false)} /> : null}
|
|
||||||
{showChangePassword ? (
|
|
||||||
<ChangePasswordModal userId="me" onClose={() => setShowChangePassword(false)} />
|
|
||||||
) : null}
|
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
import { IconArrowsCross, IconBolt, IconBoltOff, IconDisc, IconUser } from "@tabler/icons-react";
|
import { IconArrowsCross, IconBolt, IconBoltOff, IconDisc, IconLock, IconUser } from "@tabler/icons-react";
|
||||||
import type { AuditLog } from "src/api/backend";
|
import type { AuditLog } from "src/api/backend";
|
||||||
import { DateTimeFormat, T } from "src/locale";
|
import { DateTimeFormat, T } from "src/locale";
|
||||||
|
|
||||||
const getEventValue = (event: AuditLog) => {
|
const getEventValue = (event: AuditLog) => {
|
||||||
switch (event.objectType) {
|
switch (event.objectType) {
|
||||||
|
case "access-list":
|
||||||
case "user":
|
case "user":
|
||||||
return event.meta?.name;
|
return event.meta?.name;
|
||||||
case "proxy-host":
|
case "proxy-host":
|
||||||
@@ -47,6 +48,9 @@ const getIcon = (row: AuditLog) => {
|
|||||||
case "stream":
|
case "stream":
|
||||||
ico = <IconDisc size={16} className={c} />;
|
ico = <IconDisc size={16} className={c} />;
|
||||||
break;
|
break;
|
||||||
|
case "access-list":
|
||||||
|
ico = <IconLock size={16} className={c} />;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ico;
|
return ico;
|
||||||
|
@@ -85,6 +85,7 @@
|
|||||||
"error.max-domains": "Too many domains, max is {max}",
|
"error.max-domains": "Too many domains, max is {max}",
|
||||||
"error.passwords-must-match": "Passwords must match",
|
"error.passwords-must-match": "Passwords must match",
|
||||||
"error.required": "This is required",
|
"error.required": "This is required",
|
||||||
|
"event.created-access-list": "Created Access List",
|
||||||
"event.created-dead-host": "Created 404 Host",
|
"event.created-dead-host": "Created 404 Host",
|
||||||
"event.created-redirection-host": "Created Redirection Host",
|
"event.created-redirection-host": "Created Redirection Host",
|
||||||
"event.created-stream": "Created Stream",
|
"event.created-stream": "Created Stream",
|
||||||
@@ -127,6 +128,7 @@
|
|||||||
"notification.host-deleted": "Host has been deleted",
|
"notification.host-deleted": "Host has been deleted",
|
||||||
"notification.host-disabled": "Host has been disabled",
|
"notification.host-disabled": "Host has been disabled",
|
||||||
"notification.host-enabled": "Host has been enabled",
|
"notification.host-enabled": "Host has been enabled",
|
||||||
|
"notification.proxy-host-saved": "Proxy Host has been saved",
|
||||||
"notification.redirection-host-saved": "Redirection Host has been saved",
|
"notification.redirection-host-saved": "Redirection Host has been saved",
|
||||||
"notification.stream-deleted": "Stream has been deleted",
|
"notification.stream-deleted": "Stream has been deleted",
|
||||||
"notification.stream-disabled": "Stream has been disabled",
|
"notification.stream-disabled": "Stream has been disabled",
|
||||||
@@ -148,6 +150,7 @@
|
|||||||
"permissions.visibility.all": "All Items",
|
"permissions.visibility.all": "All Items",
|
||||||
"permissions.visibility.title": "Item Visibility",
|
"permissions.visibility.title": "Item Visibility",
|
||||||
"permissions.visibility.user": "Created Items Only",
|
"permissions.visibility.user": "Created Items Only",
|
||||||
|
"proxy-host.edit": "Edit Proxy Host",
|
||||||
"proxy-host.forward-host": "Forward Hostname / IP",
|
"proxy-host.forward-host": "Forward Hostname / IP",
|
||||||
"proxy-host.new": "New Proxy Host",
|
"proxy-host.new": "New Proxy Host",
|
||||||
"proxy-hosts.actions-title": "Proxy Host #{id}",
|
"proxy-hosts.actions-title": "Proxy Host #{id}",
|
||||||
|
@@ -257,6 +257,9 @@
|
|||||||
"error.required": {
|
"error.required": {
|
||||||
"defaultMessage": "This is required"
|
"defaultMessage": "This is required"
|
||||||
},
|
},
|
||||||
|
"event.created-access-list": {
|
||||||
|
"defaultMessage": "Created Access List"
|
||||||
|
},
|
||||||
"event.created-dead-host": {
|
"event.created-dead-host": {
|
||||||
"defaultMessage": "Created 404 Host"
|
"defaultMessage": "Created 404 Host"
|
||||||
},
|
},
|
||||||
@@ -383,6 +386,9 @@
|
|||||||
"notification.host-enabled": {
|
"notification.host-enabled": {
|
||||||
"defaultMessage": "Host has been enabled"
|
"defaultMessage": "Host has been enabled"
|
||||||
},
|
},
|
||||||
|
"notification.proxy-host-saved": {
|
||||||
|
"defaultMessage": "Proxy Host has been saved"
|
||||||
|
},
|
||||||
"notification.redirection-host-saved": {
|
"notification.redirection-host-saved": {
|
||||||
"defaultMessage": "Redirection Host has been saved"
|
"defaultMessage": "Redirection Host has been saved"
|
||||||
},
|
},
|
||||||
@@ -446,6 +452,9 @@
|
|||||||
"permissions.visibility.user": {
|
"permissions.visibility.user": {
|
||||||
"defaultMessage": "Created Items Only"
|
"defaultMessage": "Created Items Only"
|
||||||
},
|
},
|
||||||
|
"proxy-host.edit": {
|
||||||
|
"defaultMessage": "Edit Proxy Host"
|
||||||
|
},
|
||||||
"proxy-host.forward-host": {
|
"proxy-host.forward-host": {
|
||||||
"defaultMessage": "Forward Hostname / IP"
|
"defaultMessage": "Forward Hostname / IP"
|
||||||
},
|
},
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import cn from "classnames";
|
import cn from "classnames";
|
||||||
|
import EasyModal, { type InnerModalProps } from "ez-modal-react";
|
||||||
import { Field, Form, Formik } from "formik";
|
import { Field, Form, Formik } from "formik";
|
||||||
import { type ReactNode, useState } from "react";
|
import { type ReactNode, useState } from "react";
|
||||||
import { Alert } from "react-bootstrap";
|
import { Alert } from "react-bootstrap";
|
||||||
@@ -10,11 +11,14 @@ import { intl, T } from "src/locale";
|
|||||||
import { validateString } from "src/modules/Validations";
|
import { validateString } from "src/modules/Validations";
|
||||||
import { showSuccess } from "src/notifications";
|
import { showSuccess } from "src/notifications";
|
||||||
|
|
||||||
interface Props {
|
const showAccessListModal = (id: number | "new") => {
|
||||||
|
EasyModal.show(AccessListModal, { id });
|
||||||
|
};
|
||||||
|
|
||||||
|
interface Props extends InnerModalProps {
|
||||||
id: number | "new";
|
id: number | "new";
|
||||||
onClose: () => void;
|
|
||||||
}
|
}
|
||||||
export function AccessListModal({ id, onClose }: Props) {
|
const AccessListModal = EasyModal.create(({ id, visible, remove }: Props) => {
|
||||||
const { data, isLoading, error } = useAccessList(id, ["items", "clients"]);
|
const { data, isLoading, error } = useAccessList(id, ["items", "clients"]);
|
||||||
const { mutate: setAccessList } = useSetAccessList();
|
const { mutate: setAccessList } = useSetAccessList();
|
||||||
const [errorMsg, setErrorMsg] = useState<ReactNode | null>(null);
|
const [errorMsg, setErrorMsg] = useState<ReactNode | null>(null);
|
||||||
@@ -69,7 +73,7 @@ export function AccessListModal({ id, onClose }: Props) {
|
|||||||
onError: (err: any) => setErrorMsg(<T id={err.message} />),
|
onError: (err: any) => setErrorMsg(<T id={err.message} />),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
showSuccess(intl.formatMessage({ id: "notification.access-saved" }));
|
showSuccess(intl.formatMessage({ id: "notification.access-saved" }));
|
||||||
onClose();
|
remove();
|
||||||
},
|
},
|
||||||
onSettled: () => {
|
onSettled: () => {
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
@@ -82,7 +86,7 @@ export function AccessListModal({ id, onClose }: Props) {
|
|||||||
const toggleEnabled = cn(toggleClasses, "bg-cyan");
|
const toggleEnabled = cn(toggleClasses, "bg-cyan");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal show onHide={onClose} animation={false}>
|
<Modal show={visible} onHide={remove}>
|
||||||
{!isLoading && error && (
|
{!isLoading && error && (
|
||||||
<Alert variant="danger" className="m-3">
|
<Alert variant="danger" className="m-3">
|
||||||
{error?.message || "Unknown error"}
|
{error?.message || "Unknown error"}
|
||||||
@@ -263,7 +267,7 @@ export function AccessListModal({ id, onClose }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<Button data-bs-dismiss="modal" onClick={onClose} disabled={isSubmitting}>
|
<Button data-bs-dismiss="modal" onClick={remove} disabled={isSubmitting}>
|
||||||
<T id="cancel" />
|
<T id="cancel" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -283,4 +287,6 @@ export function AccessListModal({ id, onClose }: Props) {
|
|||||||
)}
|
)}
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
export { showAccessListModal };
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import EasyModal, { type InnerModalProps } from "ez-modal-react";
|
||||||
import { Field, Form, Formik } from "formik";
|
import { Field, Form, Formik } from "formik";
|
||||||
import { type ReactNode, useState } from "react";
|
import { type ReactNode, useState } from "react";
|
||||||
import { Alert } from "react-bootstrap";
|
import { Alert } from "react-bootstrap";
|
||||||
@@ -7,11 +8,14 @@ import { Button } from "src/components";
|
|||||||
import { intl, T } from "src/locale";
|
import { intl, T } from "src/locale";
|
||||||
import { validateString } from "src/modules/Validations";
|
import { validateString } from "src/modules/Validations";
|
||||||
|
|
||||||
interface Props {
|
const showChangePasswordModal = (id: number | "me") => {
|
||||||
userId: number | "me";
|
EasyModal.show(ChangePasswordModal, { id });
|
||||||
onClose: () => void;
|
};
|
||||||
|
|
||||||
|
interface Props extends InnerModalProps {
|
||||||
|
id: number | "me";
|
||||||
}
|
}
|
||||||
export function ChangePasswordModal({ userId, onClose }: Props) {
|
const ChangePasswordModal = EasyModal.create(({ id, visible, remove }: Props) => {
|
||||||
const [error, setError] = useState<ReactNode | null>(null);
|
const [error, setError] = useState<ReactNode | null>(null);
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
|
||||||
@@ -27,8 +31,8 @@ export function ChangePasswordModal({ userId, onClose }: Props) {
|
|||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await updateAuth(userId, values.new, values.current);
|
await updateAuth(id, values.new, values.current);
|
||||||
onClose();
|
remove();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
setError(<T id={err.message} />);
|
setError(<T id={err.message} />);
|
||||||
}
|
}
|
||||||
@@ -37,7 +41,7 @@ export function ChangePasswordModal({ userId, onClose }: Props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal show onHide={onClose} animation={false}>
|
<Modal show={visible} onHide={remove}>
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={
|
initialValues={
|
||||||
{
|
{
|
||||||
@@ -142,7 +146,7 @@ export function ChangePasswordModal({ userId, onClose }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<Button data-bs-dismiss="modal" onClick={onClose} disabled={isSubmitting}>
|
<Button data-bs-dismiss="modal" onClick={remove} disabled={isSubmitting}>
|
||||||
<T id="cancel" />
|
<T id="cancel" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -161,4 +165,6 @@ export function ChangePasswordModal({ userId, onClose }: Props) {
|
|||||||
</Formik>
|
</Formik>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
export { showChangePasswordModal };
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import { IconSettings } from "@tabler/icons-react";
|
import { IconSettings } from "@tabler/icons-react";
|
||||||
|
import EasyModal, { type InnerModalProps } from "ez-modal-react";
|
||||||
import { Form, Formik } from "formik";
|
import { Form, Formik } from "formik";
|
||||||
import { type ReactNode, useState } from "react";
|
import { type ReactNode, useState } from "react";
|
||||||
import { Alert } from "react-bootstrap";
|
import { Alert } from "react-bootstrap";
|
||||||
@@ -15,11 +16,14 @@ import { useDeadHost, useSetDeadHost } from "src/hooks";
|
|||||||
import { intl, T } from "src/locale";
|
import { intl, T } from "src/locale";
|
||||||
import { showSuccess } from "src/notifications";
|
import { showSuccess } from "src/notifications";
|
||||||
|
|
||||||
interface Props {
|
const showDeadHostModal = (id: number | "new") => {
|
||||||
|
EasyModal.show(DeadHostModal, { id });
|
||||||
|
};
|
||||||
|
|
||||||
|
interface Props extends InnerModalProps {
|
||||||
id: number | "new";
|
id: number | "new";
|
||||||
onClose: () => void;
|
|
||||||
}
|
}
|
||||||
export function DeadHostModal({ id, onClose }: Props) {
|
const DeadHostModal = EasyModal.create(({ id, visible, remove }: Props) => {
|
||||||
const { data, isLoading, error } = useDeadHost(id);
|
const { data, isLoading, error } = useDeadHost(id);
|
||||||
const { mutate: setDeadHost } = useSetDeadHost();
|
const { mutate: setDeadHost } = useSetDeadHost();
|
||||||
const [errorMsg, setErrorMsg] = useState<ReactNode | null>(null);
|
const [errorMsg, setErrorMsg] = useState<ReactNode | null>(null);
|
||||||
@@ -39,7 +43,7 @@ export function DeadHostModal({ id, onClose }: Props) {
|
|||||||
onError: (err: any) => setErrorMsg(<T id={err.message} />),
|
onError: (err: any) => setErrorMsg(<T id={err.message} />),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
showSuccess(intl.formatMessage({ id: "notification.dead-host-saved" }));
|
showSuccess(intl.formatMessage({ id: "notification.dead-host-saved" }));
|
||||||
onClose();
|
remove();
|
||||||
},
|
},
|
||||||
onSettled: () => {
|
onSettled: () => {
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
@@ -49,7 +53,7 @@ export function DeadHostModal({ id, onClose }: Props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal show onHide={onClose} animation={false}>
|
<Modal show={visible} onHide={remove}>
|
||||||
{!isLoading && error && (
|
{!isLoading && error && (
|
||||||
<Alert variant="danger" className="m-3">
|
<Alert variant="danger" className="m-3">
|
||||||
{error?.message || "Unknown error"}
|
{error?.message || "Unknown error"}
|
||||||
@@ -145,7 +149,7 @@ export function DeadHostModal({ id, onClose }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<Button data-bs-dismiss="modal" onClick={onClose} disabled={isSubmitting}>
|
<Button data-bs-dismiss="modal" onClick={remove} disabled={isSubmitting}>
|
||||||
<T id="cancel" />
|
<T id="cancel" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -165,4 +169,6 @@ export function DeadHostModal({ id, onClose }: Props) {
|
|||||||
)}
|
)}
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
export { showDeadHostModal };
|
||||||
|
@@ -1,18 +1,25 @@
|
|||||||
import { useQueryClient } from "@tanstack/react-query";
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
|
import EasyModal, { type InnerModalProps } from "ez-modal-react";
|
||||||
import { type ReactNode, useState } from "react";
|
import { type ReactNode, useState } from "react";
|
||||||
import { Alert } from "react-bootstrap";
|
import { Alert } from "react-bootstrap";
|
||||||
import Modal from "react-bootstrap/Modal";
|
import Modal from "react-bootstrap/Modal";
|
||||||
import { Button } from "src/components";
|
import { Button } from "src/components";
|
||||||
import { T } from "src/locale";
|
import { T } from "src/locale";
|
||||||
|
|
||||||
interface Props {
|
interface ShowProps {
|
||||||
title: string;
|
title: string;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
onConfirm: () => Promise<void> | void;
|
onConfirm: () => Promise<void> | void;
|
||||||
onClose: () => void;
|
|
||||||
invalidations?: any[];
|
invalidations?: any[];
|
||||||
}
|
}
|
||||||
export function DeleteConfirmModal({ title, children, onConfirm, onClose, invalidations }: Props) {
|
|
||||||
|
interface Props extends InnerModalProps, ShowProps {}
|
||||||
|
|
||||||
|
const showDeleteConfirmModal = (props: ShowProps) => {
|
||||||
|
EasyModal.show(DeleteConfirmModal, props);
|
||||||
|
};
|
||||||
|
|
||||||
|
const DeleteConfirmModal = EasyModal.create(({ title, children, onConfirm, invalidations, visible, remove }: Props) => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const [error, setError] = useState<ReactNode | null>(null);
|
const [error, setError] = useState<ReactNode | null>(null);
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
@@ -23,7 +30,7 @@ export function DeleteConfirmModal({ title, children, onConfirm, onClose, invali
|
|||||||
setError(null);
|
setError(null);
|
||||||
try {
|
try {
|
||||||
await onConfirm();
|
await onConfirm();
|
||||||
onClose();
|
remove();
|
||||||
// invalidate caches as requested
|
// invalidate caches as requested
|
||||||
invalidations?.forEach((inv) => {
|
invalidations?.forEach((inv) => {
|
||||||
queryClient.invalidateQueries({ queryKey: inv });
|
queryClient.invalidateQueries({ queryKey: inv });
|
||||||
@@ -35,7 +42,7 @@ export function DeleteConfirmModal({ title, children, onConfirm, onClose, invali
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal show onHide={onClose} animation={false}>
|
<Modal show={visible} onHide={remove}>
|
||||||
<Modal.Header closeButton>
|
<Modal.Header closeButton>
|
||||||
<Modal.Title>
|
<Modal.Title>
|
||||||
<T id={title} />
|
<T id={title} />
|
||||||
@@ -48,7 +55,7 @@ export function DeleteConfirmModal({ title, children, onConfirm, onClose, invali
|
|||||||
{children}
|
{children}
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<Button data-bs-dismiss="modal" onClick={onClose} disabled={isSubmitting}>
|
<Button data-bs-dismiss="modal" onClick={remove} disabled={isSubmitting}>
|
||||||
<T id="cancel" />
|
<T id="cancel" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -65,4 +72,6 @@ export function DeleteConfirmModal({ title, children, onConfirm, onClose, invali
|
|||||||
</Modal.Footer>
|
</Modal.Footer>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
export { showDeleteConfirmModal };
|
||||||
|
@@ -1,18 +1,22 @@
|
|||||||
|
import EasyModal, { type InnerModalProps } from "ez-modal-react";
|
||||||
import { Alert } from "react-bootstrap";
|
import { Alert } from "react-bootstrap";
|
||||||
import Modal from "react-bootstrap/Modal";
|
import Modal from "react-bootstrap/Modal";
|
||||||
import { Button, EventFormatter, GravatarFormatter, Loading } from "src/components";
|
import { Button, EventFormatter, GravatarFormatter, Loading } from "src/components";
|
||||||
import { useAuditLog } from "src/hooks";
|
import { useAuditLog } from "src/hooks";
|
||||||
import { T } from "src/locale";
|
import { T } from "src/locale";
|
||||||
|
|
||||||
interface Props {
|
const showEventDetailsModal = (id: number) => {
|
||||||
|
EasyModal.show(EventDetailsModal, { id });
|
||||||
|
};
|
||||||
|
|
||||||
|
interface Props extends InnerModalProps {
|
||||||
id: number;
|
id: number;
|
||||||
onClose: () => void;
|
|
||||||
}
|
}
|
||||||
export function EventDetailsModal({ id, onClose }: Props) {
|
const EventDetailsModal = EasyModal.create(({ id, visible, remove }: Props) => {
|
||||||
const { data, isLoading, error } = useAuditLog(id);
|
const { data, isLoading, error } = useAuditLog(id);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal show onHide={onClose} animation={false}>
|
<Modal show={visible} onHide={remove}>
|
||||||
{!isLoading && error && (
|
{!isLoading && error && (
|
||||||
<Alert variant="danger" className="m-3">
|
<Alert variant="danger" className="m-3">
|
||||||
{error?.message || "Unknown error"}
|
{error?.message || "Unknown error"}
|
||||||
@@ -41,7 +45,7 @@ export function EventDetailsModal({ id, onClose }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<Button data-bs-dismiss="modal" onClick={onClose}>
|
<Button data-bs-dismiss="modal" onClick={remove}>
|
||||||
<T id="close" />
|
<T id="close" />
|
||||||
</Button>
|
</Button>
|
||||||
</Modal.Footer>
|
</Modal.Footer>
|
||||||
@@ -49,4 +53,6 @@ export function EventDetailsModal({ id, onClose }: Props) {
|
|||||||
)}
|
)}
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
export { showEventDetailsModal };
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import { useQueryClient } from "@tanstack/react-query";
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
import cn from "classnames";
|
import cn from "classnames";
|
||||||
|
import EasyModal, { type InnerModalProps } from "ez-modal-react";
|
||||||
import { Field, Form, Formik } from "formik";
|
import { Field, Form, Formik } from "formik";
|
||||||
import { type ReactNode, useState } from "react";
|
import { type ReactNode, useState } from "react";
|
||||||
import { Alert } from "react-bootstrap";
|
import { Alert } from "react-bootstrap";
|
||||||
@@ -9,14 +10,17 @@ import { Button, Loading } from "src/components";
|
|||||||
import { useUser } from "src/hooks";
|
import { useUser } from "src/hooks";
|
||||||
import { T } from "src/locale";
|
import { T } from "src/locale";
|
||||||
|
|
||||||
interface Props {
|
const showPermissionsModal = (id: number) => {
|
||||||
userId: number;
|
EasyModal.show(PermissionsModal, { id });
|
||||||
onClose: () => void;
|
};
|
||||||
|
|
||||||
|
interface Props extends InnerModalProps {
|
||||||
|
id: number;
|
||||||
}
|
}
|
||||||
export function PermissionsModal({ userId, onClose }: Props) {
|
const PermissionsModal = EasyModal.create(({ id, visible, remove }: Props) => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const [errorMsg, setErrorMsg] = useState<ReactNode | null>(null);
|
const [errorMsg, setErrorMsg] = useState<ReactNode | null>(null);
|
||||||
const { data, isLoading, error } = useUser(userId);
|
const { data, isLoading, error } = useUser(id);
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
|
||||||
const onSubmit = async (values: any, { setSubmitting }: any) => {
|
const onSubmit = async (values: any, { setSubmitting }: any) => {
|
||||||
@@ -24,8 +28,8 @@ export function PermissionsModal({ userId, onClose }: Props) {
|
|||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
setErrorMsg(null);
|
setErrorMsg(null);
|
||||||
try {
|
try {
|
||||||
await setPermissions(userId, values);
|
await setPermissions(id, values);
|
||||||
onClose();
|
remove();
|
||||||
queryClient.invalidateQueries({ queryKey: ["users"] });
|
queryClient.invalidateQueries({ queryKey: ["users"] });
|
||||||
queryClient.invalidateQueries({ queryKey: ["user"] });
|
queryClient.invalidateQueries({ queryKey: ["user"] });
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
@@ -86,7 +90,7 @@ export function PermissionsModal({ userId, onClose }: Props) {
|
|||||||
const isAdmin = data?.roles.indexOf("admin") !== -1;
|
const isAdmin = data?.roles.indexOf("admin") !== -1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal show onHide={onClose} animation={false}>
|
<Modal show={visible} onHide={remove}>
|
||||||
{!isLoading && error && (
|
{!isLoading && error && (
|
||||||
<Alert variant="danger" className="m-3">
|
<Alert variant="danger" className="m-3">
|
||||||
{error?.message || "Unknown error"}
|
{error?.message || "Unknown error"}
|
||||||
@@ -216,7 +220,7 @@ export function PermissionsModal({ userId, onClose }: Props) {
|
|||||||
)}
|
)}
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<Button data-bs-dismiss="modal" onClick={onClose} disabled={isSubmitting}>
|
<Button data-bs-dismiss="modal" onClick={remove} disabled={isSubmitting}>
|
||||||
<T id="cancel" />
|
<T id="cancel" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -236,4 +240,6 @@ export function PermissionsModal({ userId, onClose }: Props) {
|
|||||||
)}
|
)}
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
export { showPermissionsModal };
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import { IconSettings } from "@tabler/icons-react";
|
import { IconSettings } from "@tabler/icons-react";
|
||||||
import cn from "classnames";
|
import cn from "classnames";
|
||||||
|
import EasyModal, { type InnerModalProps } from "ez-modal-react";
|
||||||
import { Field, Form, Formik } from "formik";
|
import { Field, Form, Formik } from "formik";
|
||||||
import { type ReactNode, useState } from "react";
|
import { type ReactNode, useState } from "react";
|
||||||
import { Alert } from "react-bootstrap";
|
import { Alert } from "react-bootstrap";
|
||||||
@@ -18,11 +19,14 @@ import { intl, T } from "src/locale";
|
|||||||
import { validateNumber, validateString } from "src/modules/Validations";
|
import { validateNumber, validateString } from "src/modules/Validations";
|
||||||
import { showSuccess } from "src/notifications";
|
import { showSuccess } from "src/notifications";
|
||||||
|
|
||||||
interface Props {
|
const showProxyHostModal = (id: number | "new") => {
|
||||||
|
EasyModal.show(ProxyHostModal, { id });
|
||||||
|
};
|
||||||
|
|
||||||
|
interface Props extends InnerModalProps {
|
||||||
id: number | "new";
|
id: number | "new";
|
||||||
onClose: () => void;
|
|
||||||
}
|
}
|
||||||
export function ProxyHostModal({ id, onClose }: Props) {
|
const ProxyHostModal = EasyModal.create(({ id, visible, remove }: Props) => {
|
||||||
const { data, isLoading, error } = useProxyHost(id);
|
const { data, isLoading, error } = useProxyHost(id);
|
||||||
const { mutate: setProxyHost } = useSetProxyHost();
|
const { mutate: setProxyHost } = useSetProxyHost();
|
||||||
const [errorMsg, setErrorMsg] = useState<ReactNode | null>(null);
|
const [errorMsg, setErrorMsg] = useState<ReactNode | null>(null);
|
||||||
@@ -42,7 +46,7 @@ export function ProxyHostModal({ id, onClose }: Props) {
|
|||||||
onError: (err: any) => setErrorMsg(<T id={err.message} />),
|
onError: (err: any) => setErrorMsg(<T id={err.message} />),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
showSuccess(intl.formatMessage({ id: "notification.proxy-host-saved" }));
|
showSuccess(intl.formatMessage({ id: "notification.proxy-host-saved" }));
|
||||||
onClose();
|
remove();
|
||||||
},
|
},
|
||||||
onSettled: () => {
|
onSettled: () => {
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
@@ -52,7 +56,7 @@ export function ProxyHostModal({ id, onClose }: Props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal show onHide={onClose} animation={false}>
|
<Modal show={visible} onHide={remove}>
|
||||||
{!isLoading && error && (
|
{!isLoading && error && (
|
||||||
<Alert variant="danger" className="m-3">
|
<Alert variant="danger" className="m-3">
|
||||||
{error?.message || "Unknown error"}
|
{error?.message || "Unknown error"}
|
||||||
@@ -341,7 +345,7 @@ export function ProxyHostModal({ id, onClose }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<Button data-bs-dismiss="modal" onClick={onClose} disabled={isSubmitting}>
|
<Button data-bs-dismiss="modal" onClick={remove} disabled={isSubmitting}>
|
||||||
<T id="cancel" />
|
<T id="cancel" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -361,4 +365,6 @@ export function ProxyHostModal({ id, onClose }: Props) {
|
|||||||
)}
|
)}
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
export { showProxyHostModal };
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import { IconSettings } from "@tabler/icons-react";
|
import { IconSettings } from "@tabler/icons-react";
|
||||||
import cn from "classnames";
|
import cn from "classnames";
|
||||||
|
import EasyModal, { type InnerModalProps } from "ez-modal-react";
|
||||||
import { Field, Form, Formik } from "formik";
|
import { Field, Form, Formik } from "formik";
|
||||||
import { type ReactNode, useState } from "react";
|
import { type ReactNode, useState } from "react";
|
||||||
import { Alert } from "react-bootstrap";
|
import { Alert } from "react-bootstrap";
|
||||||
@@ -17,11 +18,14 @@ import { intl, T } from "src/locale";
|
|||||||
import { validateString } from "src/modules/Validations";
|
import { validateString } from "src/modules/Validations";
|
||||||
import { showSuccess } from "src/notifications";
|
import { showSuccess } from "src/notifications";
|
||||||
|
|
||||||
interface Props {
|
const showRedirectionHostModal = (id: number | "new") => {
|
||||||
|
EasyModal.show(RedirectionHostModal, { id });
|
||||||
|
};
|
||||||
|
|
||||||
|
interface Props extends InnerModalProps {
|
||||||
id: number | "new";
|
id: number | "new";
|
||||||
onClose: () => void;
|
|
||||||
}
|
}
|
||||||
export function RedirectionHostModal({ id, onClose }: Props) {
|
const RedirectionHostModal = EasyModal.create(({ id, visible, remove }: Props) => {
|
||||||
const { data, isLoading, error } = useRedirectionHost(id);
|
const { data, isLoading, error } = useRedirectionHost(id);
|
||||||
const { mutate: setRedirectionHost } = useSetRedirectionHost();
|
const { mutate: setRedirectionHost } = useSetRedirectionHost();
|
||||||
const [errorMsg, setErrorMsg] = useState<ReactNode | null>(null);
|
const [errorMsg, setErrorMsg] = useState<ReactNode | null>(null);
|
||||||
@@ -41,7 +45,7 @@ export function RedirectionHostModal({ id, onClose }: Props) {
|
|||||||
onError: (err: any) => setErrorMsg(<T id={err.message} />),
|
onError: (err: any) => setErrorMsg(<T id={err.message} />),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
showSuccess(intl.formatMessage({ id: "notification.redirection-host-saved" }));
|
showSuccess(intl.formatMessage({ id: "notification.redirection-host-saved" }));
|
||||||
onClose();
|
remove();
|
||||||
},
|
},
|
||||||
onSettled: () => {
|
onSettled: () => {
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
@@ -51,7 +55,7 @@ export function RedirectionHostModal({ id, onClose }: Props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal show onHide={onClose} animation={false}>
|
<Modal show={visible} onHide={remove}>
|
||||||
{!isLoading && error && (
|
{!isLoading && error && (
|
||||||
<Alert variant="danger" className="m-3">
|
<Alert variant="danger" className="m-3">
|
||||||
{error?.message || "Unknown error"}
|
{error?.message || "Unknown error"}
|
||||||
@@ -275,7 +279,7 @@ export function RedirectionHostModal({ id, onClose }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<Button data-bs-dismiss="modal" onClick={onClose} disabled={isSubmitting}>
|
<Button data-bs-dismiss="modal" onClick={remove} disabled={isSubmitting}>
|
||||||
<T id="cancel" />
|
<T id="cancel" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -295,4 +299,6 @@ export function RedirectionHostModal({ id, onClose }: Props) {
|
|||||||
)}
|
)}
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
export { showRedirectionHostModal };
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import EasyModal, { type InnerModalProps } from "ez-modal-react";
|
||||||
import { Field, Form, Formik } from "formik";
|
import { Field, Form, Formik } from "formik";
|
||||||
import { generate } from "generate-password-browser";
|
import { generate } from "generate-password-browser";
|
||||||
import { type ReactNode, useState } from "react";
|
import { type ReactNode, useState } from "react";
|
||||||
@@ -8,21 +9,24 @@ import { Button } from "src/components";
|
|||||||
import { intl, T } from "src/locale";
|
import { intl, T } from "src/locale";
|
||||||
import { validateString } from "src/modules/Validations";
|
import { validateString } from "src/modules/Validations";
|
||||||
|
|
||||||
interface Props {
|
const showSetPasswordModal = (id: number) => {
|
||||||
userId: number;
|
EasyModal.show(SetPasswordModal, { id });
|
||||||
onClose: () => void;
|
};
|
||||||
|
|
||||||
|
interface Props extends InnerModalProps {
|
||||||
|
id: number;
|
||||||
}
|
}
|
||||||
export function SetPasswordModal({ userId, onClose }: Props) {
|
const SetPasswordModal = EasyModal.create(({ id, visible, remove }: Props) => {
|
||||||
const [error, setError] = useState<ReactNode | null>(null);
|
const [error, setError] = useState<ReactNode | null>(null);
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
|
||||||
const _onSubmit = async (values: any, { setSubmitting }: any) => {
|
const onSubmit = async (values: any, { setSubmitting }: any) => {
|
||||||
if (isSubmitting) return;
|
if (isSubmitting) return;
|
||||||
setError(null);
|
setError(null);
|
||||||
try {
|
try {
|
||||||
await updateAuth(userId, values.new);
|
await updateAuth(id, values.new);
|
||||||
onClose();
|
remove();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
setError(<T id={err.message} />);
|
setError(<T id={err.message} />);
|
||||||
}
|
}
|
||||||
@@ -31,14 +35,14 @@ export function SetPasswordModal({ userId, onClose }: Props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal show onHide={onClose} animation={false}>
|
<Modal show={visible} onHide={remove}>
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={
|
initialValues={
|
||||||
{
|
{
|
||||||
new: "",
|
new: "",
|
||||||
} as any
|
} as any
|
||||||
}
|
}
|
||||||
onSubmit={_onSubmit}
|
onSubmit={onSubmit}
|
||||||
>
|
>
|
||||||
{() => (
|
{() => (
|
||||||
<Form>
|
<Form>
|
||||||
@@ -110,7 +114,7 @@ export function SetPasswordModal({ userId, onClose }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<Button data-bs-dismiss="modal" onClick={onClose} disabled={isSubmitting}>
|
<Button data-bs-dismiss="modal" onClick={remove} disabled={isSubmitting}>
|
||||||
<T id="cancel" />
|
<T id="cancel" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -129,4 +133,6 @@ export function SetPasswordModal({ userId, onClose }: Props) {
|
|||||||
</Formik>
|
</Formik>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
export { showSetPasswordModal };
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import EasyModal, { type InnerModalProps } from "ez-modal-react";
|
||||||
import { Field, Form, Formik } from "formik";
|
import { Field, Form, Formik } from "formik";
|
||||||
import { type ReactNode, useState } from "react";
|
import { type ReactNode, useState } from "react";
|
||||||
import { Alert } from "react-bootstrap";
|
import { Alert } from "react-bootstrap";
|
||||||
@@ -8,11 +9,14 @@ import { intl, T } from "src/locale";
|
|||||||
import { validateNumber, validateString } from "src/modules/Validations";
|
import { validateNumber, validateString } from "src/modules/Validations";
|
||||||
import { showSuccess } from "src/notifications";
|
import { showSuccess } from "src/notifications";
|
||||||
|
|
||||||
interface Props {
|
const showStreamModal = (id: number | "new") => {
|
||||||
|
EasyModal.show(StreamModal, { id });
|
||||||
|
};
|
||||||
|
|
||||||
|
interface Props extends InnerModalProps {
|
||||||
id: number | "new";
|
id: number | "new";
|
||||||
onClose: () => void;
|
|
||||||
}
|
}
|
||||||
export function StreamModal({ id, onClose }: Props) {
|
const StreamModal = EasyModal.create(({ id, visible, remove }: Props) => {
|
||||||
const { data, isLoading, error } = useStream(id);
|
const { data, isLoading, error } = useStream(id);
|
||||||
const { mutate: setStream } = useSetStream();
|
const { mutate: setStream } = useSetStream();
|
||||||
const [errorMsg, setErrorMsg] = useState<ReactNode | null>(null);
|
const [errorMsg, setErrorMsg] = useState<ReactNode | null>(null);
|
||||||
@@ -32,7 +36,7 @@ export function StreamModal({ id, onClose }: Props) {
|
|||||||
onError: (err: any) => setErrorMsg(<T id={err.message} />),
|
onError: (err: any) => setErrorMsg(<T id={err.message} />),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
showSuccess(intl.formatMessage({ id: "notification.stream-saved" }));
|
showSuccess(intl.formatMessage({ id: "notification.stream-saved" }));
|
||||||
onClose();
|
remove();
|
||||||
},
|
},
|
||||||
onSettled: () => {
|
onSettled: () => {
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
@@ -42,7 +46,7 @@ export function StreamModal({ id, onClose }: Props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal show onHide={onClose} animation={false}>
|
<Modal show={visible} onHide={remove}>
|
||||||
{!isLoading && error && (
|
{!isLoading && error && (
|
||||||
<Alert variant="danger" className="m-3">
|
<Alert variant="danger" className="m-3">
|
||||||
{error?.message || "Unknown error"}
|
{error?.message || "Unknown error"}
|
||||||
@@ -296,7 +300,7 @@ export function StreamModal({ id, onClose }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<Button data-bs-dismiss="modal" onClick={onClose} disabled={isSubmitting}>
|
<Button data-bs-dismiss="modal" onClick={remove} disabled={isSubmitting}>
|
||||||
<T id="cancel" />
|
<T id="cancel" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -316,4 +320,6 @@ export function StreamModal({ id, onClose }: Props) {
|
|||||||
)}
|
)}
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
export { showStreamModal };
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import EasyModal, { type InnerModalProps } from "ez-modal-react";
|
||||||
import { Field, Form, Formik } from "formik";
|
import { Field, Form, Formik } from "formik";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Alert } from "react-bootstrap";
|
import { Alert } from "react-bootstrap";
|
||||||
@@ -8,12 +9,15 @@ import { intl, T } from "src/locale";
|
|||||||
import { validateEmail, validateString } from "src/modules/Validations";
|
import { validateEmail, validateString } from "src/modules/Validations";
|
||||||
import { showSuccess } from "src/notifications";
|
import { showSuccess } from "src/notifications";
|
||||||
|
|
||||||
interface Props {
|
const showUserModal = (id: number | "me" | "new") => {
|
||||||
userId: number | "me" | "new";
|
EasyModal.show(UserModal, { id });
|
||||||
onClose: () => void;
|
};
|
||||||
|
|
||||||
|
interface Props extends InnerModalProps {
|
||||||
|
id: number | "me" | "new";
|
||||||
}
|
}
|
||||||
export function UserModal({ userId, onClose }: Props) {
|
const UserModal = EasyModal.create(({ id, visible, remove }: Props) => {
|
||||||
const { data, isLoading, error } = useUser(userId);
|
const { data, isLoading, error } = useUser(id);
|
||||||
const { data: currentUser, isLoading: currentIsLoading } = useUser("me");
|
const { data: currentUser, isLoading: currentIsLoading } = useUser("me");
|
||||||
const { mutate: setUser } = useSetUser();
|
const { mutate: setUser } = useSetUser();
|
||||||
const [errorMsg, setErrorMsg] = useState<string | null>(null);
|
const [errorMsg, setErrorMsg] = useState<string | null>(null);
|
||||||
@@ -25,7 +29,7 @@ export function UserModal({ userId, onClose }: Props) {
|
|||||||
setErrorMsg(null);
|
setErrorMsg(null);
|
||||||
|
|
||||||
const { ...payload } = {
|
const { ...payload } = {
|
||||||
id: userId === "new" ? undefined : userId,
|
id: id === "new" ? undefined : id,
|
||||||
roles: [],
|
roles: [],
|
||||||
...values,
|
...values,
|
||||||
};
|
};
|
||||||
@@ -45,7 +49,7 @@ export function UserModal({ userId, onClose }: Props) {
|
|||||||
onError: (err: any) => setErrorMsg(err.message),
|
onError: (err: any) => setErrorMsg(err.message),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
showSuccess(intl.formatMessage({ id: "notification.user-saved" }));
|
showSuccess(intl.formatMessage({ id: "notification.user-saved" }));
|
||||||
onClose();
|
remove();
|
||||||
},
|
},
|
||||||
onSettled: () => {
|
onSettled: () => {
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
@@ -55,7 +59,7 @@ export function UserModal({ userId, onClose }: Props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal show onHide={onClose} animation={false}>
|
<Modal show={visible} onHide={remove}>
|
||||||
{!isLoading && error && (
|
{!isLoading && error && (
|
||||||
<Alert variant="danger" className="m-3">
|
<Alert variant="danger" className="m-3">
|
||||||
{error?.message || "Unknown error"}
|
{error?.message || "Unknown error"}
|
||||||
@@ -218,7 +222,7 @@ export function UserModal({ userId, onClose }: Props) {
|
|||||||
) : null}
|
) : null}
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<Button data-bs-dismiss="modal" onClick={onClose} disabled={isSubmitting}>
|
<Button data-bs-dismiss="modal" onClick={remove} disabled={isSubmitting}>
|
||||||
<T id="cancel" />
|
<T id="cancel" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -238,4 +242,6 @@ export function UserModal({ userId, onClose }: Props) {
|
|||||||
)}
|
)}
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
export { showUserModal };
|
||||||
|
@@ -14,7 +14,7 @@ export default function Empty({ tableInstance, onNew, isFiltered }: Props) {
|
|||||||
<div className="text-center my-4">
|
<div className="text-center my-4">
|
||||||
{isFiltered ? (
|
{isFiltered ? (
|
||||||
<h2>
|
<h2>
|
||||||
<T id="empty.search" />
|
<T id="empty-search" />
|
||||||
</h2>
|
</h2>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
@@ -5,14 +5,12 @@ import { deleteAccessList } from "src/api/backend";
|
|||||||
import { Button, LoadingPage } from "src/components";
|
import { Button, LoadingPage } from "src/components";
|
||||||
import { useAccessLists } from "src/hooks";
|
import { useAccessLists } from "src/hooks";
|
||||||
import { intl, T } from "src/locale";
|
import { intl, T } from "src/locale";
|
||||||
import { AccessListModal, DeleteConfirmModal } from "src/modals";
|
import { showAccessListModal, showDeleteConfirmModal } from "src/modals";
|
||||||
import { showSuccess } from "src/notifications";
|
import { showSuccess } from "src/notifications";
|
||||||
import Table from "./Table";
|
import Table from "./Table";
|
||||||
|
|
||||||
export default function TableWrapper() {
|
export default function TableWrapper() {
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const [editId, setEditId] = useState(0 as number | "new");
|
|
||||||
const [deleteId, setDeleteId] = useState(0);
|
|
||||||
const { isFetching, isLoading, isError, error, data } = useAccessLists(["owner", "items", "clients"]);
|
const { isFetching, isLoading, isError, error, data } = useAccessLists(["owner", "items", "clients"]);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@@ -23,21 +21,15 @@ export default function TableWrapper() {
|
|||||||
return <Alert variant="danger">{error?.message || "Unknown error"}</Alert>;
|
return <Alert variant="danger">{error?.message || "Unknown error"}</Alert>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDelete = async () => {
|
const handleDelete = async (id: number) => {
|
||||||
await deleteAccessList(deleteId);
|
await deleteAccessList(id);
|
||||||
showSuccess(intl.formatMessage({ id: "notification.access-deleted" }));
|
showSuccess(intl.formatMessage({ id: "notification.access-deleted" }));
|
||||||
};
|
};
|
||||||
|
|
||||||
let filtered = null;
|
let filtered = null;
|
||||||
if (search && data) {
|
if (search && data) {
|
||||||
filtered = data?.filter((_item) => {
|
filtered = data?.filter((item) => {
|
||||||
return true;
|
return item.name.toLowerCase().includes(search);
|
||||||
// TODO
|
|
||||||
// return (
|
|
||||||
// `${item.incomingPort}`.includes(search) ||
|
|
||||||
// `${item.forwardingPort}`.includes(search) ||
|
|
||||||
// item.forwardingHost.includes(search)
|
|
||||||
// );
|
|
||||||
});
|
});
|
||||||
} else if (search !== "") {
|
} else if (search !== "") {
|
||||||
// this can happen if someone deletes the last item while searching
|
// this can happen if someone deletes the last item while searching
|
||||||
@@ -70,7 +62,7 @@ export default function TableWrapper() {
|
|||||||
onChange={(e: any) => setSearch(e.target.value.toLowerCase().trim())}
|
onChange={(e: any) => setSearch(e.target.value.toLowerCase().trim())}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button size="sm" className="btn-cyan" onClick={() => setEditId("new")}>
|
<Button size="sm" className="btn-cyan" onClick={() => showAccessListModal("new")}>
|
||||||
<T id="access.add" />
|
<T id="access.add" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -82,21 +74,17 @@ export default function TableWrapper() {
|
|||||||
data={filtered ?? data ?? []}
|
data={filtered ?? data ?? []}
|
||||||
isFetching={isFetching}
|
isFetching={isFetching}
|
||||||
isFiltered={!!filtered}
|
isFiltered={!!filtered}
|
||||||
onEdit={(id: number) => setEditId(id)}
|
onEdit={(id: number) => showAccessListModal(id)}
|
||||||
onDelete={(id: number) => setDeleteId(id)}
|
onDelete={(id: number) =>
|
||||||
onNew={() => setEditId("new")}
|
showDeleteConfirmModal({
|
||||||
|
title: "access.delete.title",
|
||||||
|
onConfirm: () => handleDelete(id),
|
||||||
|
invalidations: [["access-lists"], ["access-list", id]],
|
||||||
|
children: <T id="access.delete.content" />,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onNew={() => showAccessListModal("new")}
|
||||||
/>
|
/>
|
||||||
{editId ? <AccessListModal id={editId} onClose={() => setEditId(0)} /> : null}
|
|
||||||
{deleteId ? (
|
|
||||||
<DeleteConfirmModal
|
|
||||||
title="access.delete.title"
|
|
||||||
onConfirm={handleDelete}
|
|
||||||
onClose={() => setDeleteId(0)}
|
|
||||||
invalidations={[["access-lists"], ["access-list", deleteId]]}
|
|
||||||
>
|
|
||||||
<T id="access.delete.content" />
|
|
||||||
</DeleteConfirmModal>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@@ -1,13 +1,11 @@
|
|||||||
import { useState } from "react";
|
|
||||||
import Alert from "react-bootstrap/Alert";
|
import Alert from "react-bootstrap/Alert";
|
||||||
import { LoadingPage } from "src/components";
|
import { LoadingPage } from "src/components";
|
||||||
import { useAuditLogs } from "src/hooks";
|
import { useAuditLogs } from "src/hooks";
|
||||||
import { T } from "src/locale";
|
import { T } from "src/locale";
|
||||||
import { EventDetailsModal } from "src/modals";
|
import { showEventDetailsModal } from "src/modals";
|
||||||
import Table from "./Table";
|
import Table from "./Table";
|
||||||
|
|
||||||
export default function TableWrapper() {
|
export default function TableWrapper() {
|
||||||
const [eventId, setEventId] = useState(0);
|
|
||||||
const { isFetching, isLoading, isError, error, data } = useAuditLogs(["user"]);
|
const { isFetching, isLoading, isError, error, data } = useAuditLogs(["user"]);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@@ -31,8 +29,7 @@ export default function TableWrapper() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Table data={data ?? []} isFetching={isFetching} onSelectItem={setEventId} />
|
<Table data={data ?? []} isFetching={isFetching} onSelectItem={showEventDetailsModal} />
|
||||||
{eventId ? <EventDetailsModal id={eventId} onClose={() => setEventId(0)} /> : null}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@@ -14,7 +14,7 @@ export default function Empty({ tableInstance, onNew, onNewCustom, isFiltered }:
|
|||||||
<div className="text-center my-4">
|
<div className="text-center my-4">
|
||||||
{isFiltered ? (
|
{isFiltered ? (
|
||||||
<h2>
|
<h2>
|
||||||
<T id="empty.search" />
|
<T id="empty-search" />
|
||||||
</h2>
|
</h2>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
@@ -14,7 +14,7 @@ export default function Empty({ tableInstance, onNew, isFiltered }: Props) {
|
|||||||
<div className="text-center my-4">
|
<div className="text-center my-4">
|
||||||
{isFiltered ? (
|
{isFiltered ? (
|
||||||
<h2>
|
<h2>
|
||||||
<T id="empty.search" />
|
<T id="empty-search" />
|
||||||
</h2>
|
</h2>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
@@ -6,15 +6,13 @@ import { deleteDeadHost, toggleDeadHost } from "src/api/backend";
|
|||||||
import { Button, LoadingPage } from "src/components";
|
import { Button, LoadingPage } from "src/components";
|
||||||
import { useDeadHosts } from "src/hooks";
|
import { useDeadHosts } from "src/hooks";
|
||||||
import { intl, T } from "src/locale";
|
import { intl, T } from "src/locale";
|
||||||
import { DeadHostModal, DeleteConfirmModal } from "src/modals";
|
import { showDeadHostModal, showDeleteConfirmModal } from "src/modals";
|
||||||
import { showSuccess } from "src/notifications";
|
import { showSuccess } from "src/notifications";
|
||||||
import Table from "./Table";
|
import Table from "./Table";
|
||||||
|
|
||||||
export default function TableWrapper() {
|
export default function TableWrapper() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const [deleteId, setDeleteId] = useState(0);
|
|
||||||
const [editId, setEditId] = useState(0 as number | "new");
|
|
||||||
const { isFetching, isLoading, isError, error, data } = useDeadHosts(["owner", "certificate"]);
|
const { isFetching, isLoading, isError, error, data } = useDeadHosts(["owner", "certificate"]);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@@ -25,8 +23,8 @@ export default function TableWrapper() {
|
|||||||
return <Alert variant="danger">{error?.message || "Unknown error"}</Alert>;
|
return <Alert variant="danger">{error?.message || "Unknown error"}</Alert>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDelete = async () => {
|
const handleDelete = async (id: number) => {
|
||||||
await deleteDeadHost(deleteId);
|
await deleteDeadHost(id);
|
||||||
showSuccess(intl.formatMessage({ id: "notification.host-deleted" }));
|
showSuccess(intl.formatMessage({ id: "notification.host-deleted" }));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -73,7 +71,7 @@ export default function TableWrapper() {
|
|||||||
onChange={(e: any) => setSearch(e.target.value.toLowerCase().trim())}
|
onChange={(e: any) => setSearch(e.target.value.toLowerCase().trim())}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button size="sm" className="btn-red" onClick={() => setEditId("new")}>
|
<Button size="sm" className="btn-red" onClick={() => showDeadHostModal("new")}>
|
||||||
<T id="dead-hosts.add" />
|
<T id="dead-hosts.add" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -85,22 +83,18 @@ export default function TableWrapper() {
|
|||||||
data={filtered ?? data ?? []}
|
data={filtered ?? data ?? []}
|
||||||
isFiltered={!!search}
|
isFiltered={!!search}
|
||||||
isFetching={isFetching}
|
isFetching={isFetching}
|
||||||
onEdit={(id: number) => setEditId(id)}
|
onEdit={(id: number) => showDeadHostModal(id)}
|
||||||
onDelete={(id: number) => setDeleteId(id)}
|
onDelete={(id: number) =>
|
||||||
|
showDeleteConfirmModal({
|
||||||
|
title: "dead-host.delete.title",
|
||||||
|
onConfirm: () => handleDelete(id),
|
||||||
|
invalidations: [["dead-hosts"], ["dead-host", id]],
|
||||||
|
children: <T id="dead-host.delete.content" />,
|
||||||
|
})
|
||||||
|
}
|
||||||
onDisableToggle={handleDisableToggle}
|
onDisableToggle={handleDisableToggle}
|
||||||
onNew={() => setEditId("new")}
|
onNew={() => showDeadHostModal("new")}
|
||||||
/>
|
/>
|
||||||
{editId ? <DeadHostModal id={editId} onClose={() => setEditId(0)} /> : null}
|
|
||||||
{deleteId ? (
|
|
||||||
<DeleteConfirmModal
|
|
||||||
title="dead-host.delete.title"
|
|
||||||
onConfirm={handleDelete}
|
|
||||||
onClose={() => setDeleteId(0)}
|
|
||||||
invalidations={[["dead-hosts"], ["dead-host", deleteId]]}
|
|
||||||
>
|
|
||||||
<T id="dead-host.delete.content" />
|
|
||||||
</DeleteConfirmModal>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@@ -14,7 +14,7 @@ export default function Empty({ tableInstance, onNew, isFiltered }: Props) {
|
|||||||
<div className="text-center my-4">
|
<div className="text-center my-4">
|
||||||
{isFiltered ? (
|
{isFiltered ? (
|
||||||
<h2>
|
<h2>
|
||||||
<T id="empty.search" />
|
<T id="empty-search" />
|
||||||
</h2>
|
</h2>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
@@ -6,15 +6,13 @@ import { deleteProxyHost, toggleProxyHost } from "src/api/backend";
|
|||||||
import { Button, LoadingPage } from "src/components";
|
import { Button, LoadingPage } from "src/components";
|
||||||
import { useProxyHosts } from "src/hooks";
|
import { useProxyHosts } from "src/hooks";
|
||||||
import { intl, T } from "src/locale";
|
import { intl, T } from "src/locale";
|
||||||
import { DeleteConfirmModal, ProxyHostModal } from "src/modals";
|
import { showDeleteConfirmModal, showProxyHostModal } from "src/modals";
|
||||||
import { showSuccess } from "src/notifications";
|
import { showSuccess } from "src/notifications";
|
||||||
import Table from "./Table";
|
import Table from "./Table";
|
||||||
|
|
||||||
export default function TableWrapper() {
|
export default function TableWrapper() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const [deleteId, setDeleteId] = useState(0);
|
|
||||||
const [editId, setEditId] = useState(0 as number | "new");
|
|
||||||
const { isFetching, isLoading, isError, error, data } = useProxyHosts(["owner", "access_list", "certificate"]);
|
const { isFetching, isLoading, isError, error, data } = useProxyHosts(["owner", "access_list", "certificate"]);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@@ -25,8 +23,8 @@ export default function TableWrapper() {
|
|||||||
return <Alert variant="danger">{error?.message || "Unknown error"}</Alert>;
|
return <Alert variant="danger">{error?.message || "Unknown error"}</Alert>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDelete = async () => {
|
const handleDelete = async (id: number) => {
|
||||||
await deleteProxyHost(deleteId);
|
await deleteProxyHost(id);
|
||||||
showSuccess(intl.formatMessage({ id: "notification.host-deleted" }));
|
showSuccess(intl.formatMessage({ id: "notification.host-deleted" }));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -74,9 +72,10 @@ export default function TableWrapper() {
|
|||||||
type="text"
|
type="text"
|
||||||
className="form-control form-control-sm"
|
className="form-control form-control-sm"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
|
onChange={(e: any) => setSearch(e.target.value.toLowerCase().trim())}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button size="sm" className="btn-lime">
|
<Button size="sm" className="btn-lime" onClick={() => showProxyHostModal("new")}>
|
||||||
<T id="proxy-hosts.add" />
|
<T id="proxy-hosts.add" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -88,22 +87,18 @@ export default function TableWrapper() {
|
|||||||
data={filtered ?? data ?? []}
|
data={filtered ?? data ?? []}
|
||||||
isFiltered={!!search}
|
isFiltered={!!search}
|
||||||
isFetching={isFetching}
|
isFetching={isFetching}
|
||||||
onEdit={(id: number) => setEditId(id)}
|
onEdit={(id: number) => showProxyHostModal(id)}
|
||||||
onDelete={(id: number) => setDeleteId(id)}
|
onDelete={(id: number) =>
|
||||||
|
showDeleteConfirmModal({
|
||||||
|
title: "proxy-host.delete.title",
|
||||||
|
onConfirm: () => handleDelete(id),
|
||||||
|
invalidations: [["proxy-hosts"], ["proxy-host", id]],
|
||||||
|
children: <T id="proxy-host.delete.content" />,
|
||||||
|
})
|
||||||
|
}
|
||||||
onDisableToggle={handleDisableToggle}
|
onDisableToggle={handleDisableToggle}
|
||||||
onNew={() => setEditId("new")}
|
onNew={() => showProxyHostModal("new")}
|
||||||
/>
|
/>
|
||||||
{editId ? <ProxyHostModal id={editId} onClose={() => setEditId(0)} /> : null}
|
|
||||||
{deleteId ? (
|
|
||||||
<DeleteConfirmModal
|
|
||||||
title="proxy-host.delete.title"
|
|
||||||
onConfirm={handleDelete}
|
|
||||||
onClose={() => setDeleteId(0)}
|
|
||||||
invalidations={[["proxy-hosts"], ["proxy-host", deleteId]]}
|
|
||||||
>
|
|
||||||
<T id="proxy-host.delete.content" />
|
|
||||||
</DeleteConfirmModal>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@@ -14,7 +14,7 @@ export default function Empty({ tableInstance, onNew, isFiltered }: Props) {
|
|||||||
<div className="text-center my-4">
|
<div className="text-center my-4">
|
||||||
{isFiltered ? (
|
{isFiltered ? (
|
||||||
<h2>
|
<h2>
|
||||||
<T id="empty.search" />
|
<T id="empty-search" />
|
||||||
</h2>
|
</h2>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
@@ -6,15 +6,13 @@ import { deleteRedirectionHost, toggleRedirectionHost } from "src/api/backend";
|
|||||||
import { Button, LoadingPage } from "src/components";
|
import { Button, LoadingPage } from "src/components";
|
||||||
import { useRedirectionHosts } from "src/hooks";
|
import { useRedirectionHosts } from "src/hooks";
|
||||||
import { intl, T } from "src/locale";
|
import { intl, T } from "src/locale";
|
||||||
import { DeleteConfirmModal, RedirectionHostModal } from "src/modals";
|
import { showDeleteConfirmModal, showRedirectionHostModal } from "src/modals";
|
||||||
import { showSuccess } from "src/notifications";
|
import { showSuccess } from "src/notifications";
|
||||||
import Table from "./Table";
|
import Table from "./Table";
|
||||||
|
|
||||||
export default function TableWrapper() {
|
export default function TableWrapper() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const [deleteId, setDeleteId] = useState(0);
|
|
||||||
const [editId, setEditId] = useState(0 as number | "new");
|
|
||||||
const { isFetching, isLoading, isError, error, data } = useRedirectionHosts(["owner", "certificate"]);
|
const { isFetching, isLoading, isError, error, data } = useRedirectionHosts(["owner", "certificate"]);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@@ -25,8 +23,8 @@ export default function TableWrapper() {
|
|||||||
return <Alert variant="danger">{error?.message || "Unknown error"}</Alert>;
|
return <Alert variant="danger">{error?.message || "Unknown error"}</Alert>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDelete = async () => {
|
const handleDelete = async (id: number) => {
|
||||||
await deleteRedirectionHost(deleteId);
|
await deleteRedirectionHost(id);
|
||||||
showSuccess(intl.formatMessage({ id: "notification.host-deleted" }));
|
showSuccess(intl.formatMessage({ id: "notification.host-deleted" }));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -76,7 +74,11 @@ export default function TableWrapper() {
|
|||||||
onChange={(e: any) => setSearch(e.target.value.toLowerCase().trim())}
|
onChange={(e: any) => setSearch(e.target.value.toLowerCase().trim())}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button size="sm" className="btn-yellow" onClick={() => setEditId("new")}>
|
<Button
|
||||||
|
size="sm"
|
||||||
|
className="btn-yellow"
|
||||||
|
onClick={() => showRedirectionHostModal("new")}
|
||||||
|
>
|
||||||
<T id="redirection-hosts.add" />
|
<T id="redirection-hosts.add" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -88,22 +90,18 @@ export default function TableWrapper() {
|
|||||||
data={filtered ?? data ?? []}
|
data={filtered ?? data ?? []}
|
||||||
isFiltered={!!search}
|
isFiltered={!!search}
|
||||||
isFetching={isFetching}
|
isFetching={isFetching}
|
||||||
onEdit={(id: number) => setEditId(id)}
|
onEdit={(id: number) => showRedirectionHostModal(id)}
|
||||||
onDelete={(id: number) => setDeleteId(id)}
|
onDelete={(id: number) =>
|
||||||
|
showDeleteConfirmModal({
|
||||||
|
title: "redirection-host.delete.title",
|
||||||
|
onConfirm: () => handleDelete(id),
|
||||||
|
invalidations: [["redirection-hosts"], ["redirection-host", id]],
|
||||||
|
children: <T id="redirection-host.delete.content" />,
|
||||||
|
})
|
||||||
|
}
|
||||||
onDisableToggle={handleDisableToggle}
|
onDisableToggle={handleDisableToggle}
|
||||||
onNew={() => setEditId("new")}
|
onNew={() => showRedirectionHostModal("new")}
|
||||||
/>
|
/>
|
||||||
{editId ? <RedirectionHostModal id={editId} onClose={() => setEditId(0)} /> : null}
|
|
||||||
{deleteId ? (
|
|
||||||
<DeleteConfirmModal
|
|
||||||
title="redirection-host.delete.title"
|
|
||||||
onConfirm={handleDelete}
|
|
||||||
onClose={() => setDeleteId(0)}
|
|
||||||
invalidations={[["redirection-hosts"], ["redirection-host", deleteId]]}
|
|
||||||
>
|
|
||||||
<T id="redirection-host.delete.content" />
|
|
||||||
</DeleteConfirmModal>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@@ -14,7 +14,7 @@ export default function Empty({ tableInstance, onNew, isFiltered }: Props) {
|
|||||||
<div className="text-center my-4">
|
<div className="text-center my-4">
|
||||||
{isFiltered ? (
|
{isFiltered ? (
|
||||||
<h2>
|
<h2>
|
||||||
<T id="empty.search" />
|
<T id="empty-search" />
|
||||||
</h2>
|
</h2>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
@@ -6,15 +6,14 @@ import { deleteStream, toggleStream } from "src/api/backend";
|
|||||||
import { Button, LoadingPage } from "src/components";
|
import { Button, LoadingPage } from "src/components";
|
||||||
import { useStreams } from "src/hooks";
|
import { useStreams } from "src/hooks";
|
||||||
import { intl, T } from "src/locale";
|
import { intl, T } from "src/locale";
|
||||||
import { DeleteConfirmModal, StreamModal } from "src/modals";
|
import { showDeleteConfirmModal, showStreamModal } from "src/modals";
|
||||||
import { showSuccess } from "src/notifications";
|
import { showSuccess } from "src/notifications";
|
||||||
import Table from "./Table";
|
import Table from "./Table";
|
||||||
|
|
||||||
export default function TableWrapper() {
|
export default function TableWrapper() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const [editId, setEditId] = useState(0 as number | "new");
|
const [_deleteId, _setDeleteIdd] = useState(0);
|
||||||
const [deleteId, setDeleteId] = useState(0);
|
|
||||||
const { isFetching, isLoading, isError, error, data } = useStreams(["owner", "certificate"]);
|
const { isFetching, isLoading, isError, error, data } = useStreams(["owner", "certificate"]);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@@ -25,8 +24,8 @@ export default function TableWrapper() {
|
|||||||
return <Alert variant="danger">{error?.message || "Unknown error"}</Alert>;
|
return <Alert variant="danger">{error?.message || "Unknown error"}</Alert>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDelete = async () => {
|
const handleDelete = async (id: number) => {
|
||||||
await deleteStream(deleteId);
|
await deleteStream(id);
|
||||||
showSuccess(intl.formatMessage({ id: "notification.stream-deleted" }));
|
showSuccess(intl.formatMessage({ id: "notification.stream-deleted" }));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -79,7 +78,7 @@ export default function TableWrapper() {
|
|||||||
onChange={(e: any) => setSearch(e.target.value.toLowerCase().trim())}
|
onChange={(e: any) => setSearch(e.target.value.toLowerCase().trim())}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button size="sm" className="btn-blue" onClick={() => setEditId("new")}>
|
<Button size="sm" className="btn-blue" onClick={() => showStreamModal("new")}>
|
||||||
<T id="streams.add" />
|
<T id="streams.add" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -91,22 +90,18 @@ export default function TableWrapper() {
|
|||||||
data={filtered ?? data ?? []}
|
data={filtered ?? data ?? []}
|
||||||
isFetching={isFetching}
|
isFetching={isFetching}
|
||||||
isFiltered={!!filtered}
|
isFiltered={!!filtered}
|
||||||
onEdit={(id: number) => setEditId(id)}
|
onEdit={(id: number) => showStreamModal(id)}
|
||||||
onDelete={(id: number) => setDeleteId(id)}
|
onDelete={(id: number) =>
|
||||||
|
showDeleteConfirmModal({
|
||||||
|
title: "stream.delete.title",
|
||||||
|
onConfirm: () => handleDelete(id),
|
||||||
|
invalidations: [["streams"], ["stream", id]],
|
||||||
|
children: <T id="stream.delete.content" />,
|
||||||
|
})
|
||||||
|
}
|
||||||
onDisableToggle={handleDisableToggle}
|
onDisableToggle={handleDisableToggle}
|
||||||
onNew={() => setEditId("new")}
|
onNew={() => showStreamModal("new")}
|
||||||
/>
|
/>
|
||||||
{editId ? <StreamModal id={editId} onClose={() => setEditId(0)} /> : null}
|
|
||||||
{deleteId ? (
|
|
||||||
<DeleteConfirmModal
|
|
||||||
title="stream.delete.title"
|
|
||||||
onConfirm={handleDelete}
|
|
||||||
onClose={() => setDeleteId(0)}
|
|
||||||
invalidations={[["streams"], ["stream", deleteId]]}
|
|
||||||
>
|
|
||||||
<T id="stream.delete.content" />
|
|
||||||
</DeleteConfirmModal>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@@ -87,7 +87,7 @@ export default function Table({
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
columnHelper.display({
|
columnHelper.display({
|
||||||
id: "id", // todo: not needed for a display?
|
id: "id",
|
||||||
cell: (info: any) => {
|
cell: (info: any) => {
|
||||||
return (
|
return (
|
||||||
<span className="dropdown">
|
<span className="dropdown">
|
||||||
@@ -112,7 +112,7 @@ export default function Table({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconEdit size={16} />
|
<IconEdit size={16} />
|
||||||
<T id="users.edit" />
|
<T id="user.edit" />
|
||||||
</a>
|
</a>
|
||||||
{currentUserId !== info.row.original.id ? (
|
{currentUserId !== info.row.original.id ? (
|
||||||
<>
|
<>
|
||||||
|
@@ -6,17 +6,13 @@ import { deleteUser, toggleUser } from "src/api/backend";
|
|||||||
import { Button, LoadingPage } from "src/components";
|
import { Button, LoadingPage } from "src/components";
|
||||||
import { useUser, useUsers } from "src/hooks";
|
import { useUser, useUsers } from "src/hooks";
|
||||||
import { intl, T } from "src/locale";
|
import { intl, T } from "src/locale";
|
||||||
import { DeleteConfirmModal, PermissionsModal, SetPasswordModal, UserModal } from "src/modals";
|
import { showDeleteConfirmModal, showPermissionsModal, showSetPasswordModal, showUserModal } from "src/modals";
|
||||||
import { showSuccess } from "src/notifications";
|
import { showSuccess } from "src/notifications";
|
||||||
import Table from "./Table";
|
import Table from "./Table";
|
||||||
|
|
||||||
export default function TableWrapper() {
|
export default function TableWrapper() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const [editUserId, setEditUserId] = useState(0 as number | "new");
|
|
||||||
const [editUserPermissionsId, setEditUserPermissionsId] = useState(0);
|
|
||||||
const [editUserPasswordId, setEditUserPasswordId] = useState(0);
|
|
||||||
const [deleteUserId, setDeleteUserId] = useState(0);
|
|
||||||
const { isFetching, isLoading, isError, error, data } = useUsers(["permissions"]);
|
const { isFetching, isLoading, isError, error, data } = useUsers(["permissions"]);
|
||||||
const { data: currentUser } = useUser("me");
|
const { data: currentUser } = useUser("me");
|
||||||
|
|
||||||
@@ -28,8 +24,8 @@ export default function TableWrapper() {
|
|||||||
return <Alert variant="danger">{error?.message || "Unknown error"}</Alert>;
|
return <Alert variant="danger">{error?.message || "Unknown error"}</Alert>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDelete = async () => {
|
const handleDelete = async (id: number) => {
|
||||||
await deleteUser(deleteUserId);
|
await deleteUser(id);
|
||||||
showSuccess(intl.formatMessage({ id: "notification.user-deleted" }));
|
showSuccess(intl.formatMessage({ id: "notification.user-deleted" }));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -81,7 +77,7 @@ export default function TableWrapper() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button size="sm" className="btn-orange" onClick={() => setEditUserId("new")}>
|
<Button size="sm" className="btn-orange" onClick={() => showUserModal("new")}>
|
||||||
<T id="users.add" />
|
<T id="users.add" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -94,30 +90,20 @@ export default function TableWrapper() {
|
|||||||
isFiltered={!!search}
|
isFiltered={!!search}
|
||||||
isFetching={isFetching}
|
isFetching={isFetching}
|
||||||
currentUserId={currentUser?.id}
|
currentUserId={currentUser?.id}
|
||||||
onEditUser={(id: number) => setEditUserId(id)}
|
onEditUser={(id: number) => showUserModal(id)}
|
||||||
onEditPermissions={(id: number) => setEditUserPermissionsId(id)}
|
onEditPermissions={(id: number) => showPermissionsModal(id)}
|
||||||
onSetPassword={(id: number) => setEditUserPasswordId(id)}
|
onSetPassword={(id: number) => showSetPasswordModal(id)}
|
||||||
onDeleteUser={(id: number) => setDeleteUserId(id)}
|
onDeleteUser={(id: number) =>
|
||||||
|
showDeleteConfirmModal({
|
||||||
|
title: "user.delete.title",
|
||||||
|
onConfirm: () => handleDelete(id),
|
||||||
|
invalidations: [["users"], ["user", id]],
|
||||||
|
children: <T id="user.delete.content" />,
|
||||||
|
})
|
||||||
|
}
|
||||||
onDisableToggle={handleDisableToggle}
|
onDisableToggle={handleDisableToggle}
|
||||||
onNewUser={() => setEditUserId("new")}
|
onNewUser={() => showUserModal("new")}
|
||||||
/>
|
/>
|
||||||
{editUserId ? <UserModal userId={editUserId} onClose={() => setEditUserId(0)} /> : null}
|
|
||||||
{editUserPermissionsId ? (
|
|
||||||
<PermissionsModal userId={editUserPermissionsId} onClose={() => setEditUserPermissionsId(0)} />
|
|
||||||
) : null}
|
|
||||||
{deleteUserId ? (
|
|
||||||
<DeleteConfirmModal
|
|
||||||
title="user.delete.title"
|
|
||||||
onConfirm={handleDelete}
|
|
||||||
onClose={() => setDeleteUserId(0)}
|
|
||||||
invalidations={[["users"], ["user", deleteUserId]]}
|
|
||||||
>
|
|
||||||
<T id="user.delete.content" />
|
|
||||||
</DeleteConfirmModal>
|
|
||||||
) : null}
|
|
||||||
{editUserPasswordId ? (
|
|
||||||
<SetPasswordModal userId={editUserPasswordId} onClose={() => setEditUserPasswordId(0)} />
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@@ -1530,6 +1530,11 @@ extend@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||||
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
||||||
|
|
||||||
|
ez-modal-react@^1.0.5:
|
||||||
|
version "1.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/ez-modal-react/-/ez-modal-react-1.0.5.tgz#38d36c5e31f54f6b7cb7afa0cc79a8d1190c2805"
|
||||||
|
integrity sha512-/A8yLK54tpmWCMkW8Pwqc2xxspmimGOOw/m+1Y+tNtUIheuDHhLynHP1Q0utciJEGDAK849aQcd+6DrJ88hggQ==
|
||||||
|
|
||||||
fast-deep-equal@^3.1.3:
|
fast-deep-equal@^3.1.3:
|
||||||
version "3.1.3"
|
version "3.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||||
|
Reference in New Issue
Block a user