mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-10-04 03:40:10 +00:00
404 hosts polish
This commit is contained in:
@@ -88,14 +88,6 @@ Sometimes this can take a little bit because of the entropy of keys.
|
|||||||
|
|
||||||
[http://127.0.0.1:81](http://127.0.0.1:81)
|
[http://127.0.0.1:81](http://127.0.0.1:81)
|
||||||
|
|
||||||
Default Admin User:
|
|
||||||
```
|
|
||||||
Email: admin@example.com
|
|
||||||
Password: changeme
|
|
||||||
```
|
|
||||||
|
|
||||||
Immediately after logging in with this default user you will be asked to modify your details and change your password.
|
|
||||||
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
@@ -63,7 +63,7 @@ const internalDeadHost = {
|
|||||||
action: "created",
|
action: "created",
|
||||||
object_type: "dead-host",
|
object_type: "dead-host",
|
||||||
object_id: row.id,
|
object_id: row.id,
|
||||||
meta: _.assign({}, data.meta || {}, row.meta),
|
meta: thisData,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (createCertificate) {
|
if (createCertificate) {
|
||||||
@@ -240,6 +240,7 @@ const internalDeadHost = {
|
|||||||
// Delete Nginx Config
|
// Delete Nginx Config
|
||||||
await internalNginx.deleteConfig("dead_host", row);
|
await internalNginx.deleteConfig("dead_host", row);
|
||||||
await internalNginx.reload();
|
await internalNginx.reload();
|
||||||
|
|
||||||
// Add to audit log
|
// Add to audit log
|
||||||
await internalAuditLog.add(access, {
|
await internalAuditLog.add(access, {
|
||||||
action: "deleted",
|
action: "deleted",
|
||||||
@@ -247,6 +248,7 @@ const internalDeadHost = {
|
|||||||
object_id: row.id,
|
object_id: row.id,
|
||||||
meta: _.omit(row, omissions()),
|
meta: _.omit(row, omissions()),
|
||||||
});
|
});
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -301,8 +301,11 @@ const internalNginx = {
|
|||||||
* @param {String} filename
|
* @param {String} filename
|
||||||
*/
|
*/
|
||||||
deleteFile: (filename) => {
|
deleteFile: (filename) => {
|
||||||
logger.debug(`Deleting file: ${filename}`);
|
if (!fs.existsSync(filename)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
|
logger.debug(`Deleting file: ${filename}`);
|
||||||
fs.unlinkSync(filename);
|
fs.unlinkSync(filename);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.debug("Could not delete file:", JSON.stringify(err, null, 2));
|
logger.debug("Could not delete file:", JSON.stringify(err, null, 2));
|
||||||
|
@@ -121,7 +121,7 @@ router
|
|||||||
/**
|
/**
|
||||||
* PUT /api/nginx/dead-hosts/123
|
* PUT /api/nginx/dead-hosts/123
|
||||||
*
|
*
|
||||||
* Update and existing dead-host
|
* Update an existing dead-host
|
||||||
*/
|
*/
|
||||||
.put(async (req, res, next) => {
|
.put(async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
@@ -138,7 +138,7 @@ router
|
|||||||
/**
|
/**
|
||||||
* DELETE /api/nginx/dead-hosts/123
|
* DELETE /api/nginx/dead-hosts/123
|
||||||
*
|
*
|
||||||
* Update and existing dead-host
|
* Delete a dead-host
|
||||||
*/
|
*/
|
||||||
.delete(async (req, res, next) => {
|
.delete(async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
|
@@ -4,14 +4,32 @@ interface Props {
|
|||||||
domains: string[];
|
domains: string[];
|
||||||
createdOn?: string;
|
createdOn?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DomainLink = ({ domain }: { domain: string }) => {
|
||||||
|
// when domain contains a wildcard, make the link go nowhere.
|
||||||
|
let onClick: ((e: React.MouseEvent) => void) | undefined;
|
||||||
|
if (domain.includes("*")) {
|
||||||
|
onClick = (e: React.MouseEvent) => e.preventDefault();
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
key={domain}
|
||||||
|
href={`http://${domain}`}
|
||||||
|
target="_blank"
|
||||||
|
onClick={onClick}
|
||||||
|
className="badge bg-yellow-lt domain-name me-2"
|
||||||
|
>
|
||||||
|
{domain}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export function DomainsFormatter({ domains, createdOn }: Props) {
|
export function DomainsFormatter({ domains, createdOn }: Props) {
|
||||||
return (
|
return (
|
||||||
<div className="flex-fill">
|
<div className="flex-fill">
|
||||||
<div className="font-weight-medium">
|
<div className="font-weight-medium">
|
||||||
{domains.map((domain: string) => (
|
{domains.map((domain: string) => (
|
||||||
<a key={domain} href={`http://${domain}`} className="badge bg-yellow-lt domain-name">
|
<DomainLink key={domain} domain={domain} />
|
||||||
{domain}
|
|
||||||
</a>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{createdOn ? (
|
{createdOn ? (
|
||||||
|
@@ -10,6 +10,8 @@ const getEventValue = (event: AuditLog) => {
|
|||||||
switch (event.objectType) {
|
switch (event.objectType) {
|
||||||
case "user":
|
case "user":
|
||||||
return event.meta?.name;
|
return event.meta?.name;
|
||||||
|
case "dead-host":
|
||||||
|
return event.meta?.domainNames?.join(", ") || "N/A";
|
||||||
default:
|
default:
|
||||||
return `UNKNOWN EVENT TYPE: ${event.objectType}`;
|
return `UNKNOWN EVENT TYPE: ${event.objectType}`;
|
||||||
}
|
}
|
||||||
|
@@ -41,6 +41,8 @@
|
|||||||
"column.status": "Status",
|
"column.status": "Status",
|
||||||
"created-on": "Created: {date}",
|
"created-on": "Created: {date}",
|
||||||
"dashboard.title": "Dashboard",
|
"dashboard.title": "Dashboard",
|
||||||
|
"dead-host.delete.content": "Are you sure you want to delete this 404 host?",
|
||||||
|
"dead-host.delete.title": "Delete 404 Host",
|
||||||
"dead-host.edit": "Edit 404 Host",
|
"dead-host.edit": "Edit 404 Host",
|
||||||
"dead-host.new": "New 404 Host",
|
"dead-host.new": "New 404 Host",
|
||||||
"dead-hosts.actions-title": "404 Host #{id}",
|
"dead-hosts.actions-title": "404 Host #{id}",
|
||||||
@@ -67,8 +69,11 @@
|
|||||||
"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-dead-host": "Created 404 Host",
|
||||||
"event.created-user": "Created User",
|
"event.created-user": "Created User",
|
||||||
"event.deleted-user": "Deleted User",
|
"event.deleted-user": "Deleted User",
|
||||||
|
"event.disabled-dead-host": "Disabled 404 Host",
|
||||||
|
"event.enabled-dead-host": "Enabled 404 Host",
|
||||||
"event.updated-user": "Updated User",
|
"event.updated-user": "Updated User",
|
||||||
"footer.github-fork": "Fork me on Github",
|
"footer.github-fork": "Fork me on Github",
|
||||||
"hosts.title": "Hosts",
|
"hosts.title": "Hosts",
|
||||||
@@ -84,6 +89,9 @@
|
|||||||
"notfound.title": "Oops… You just found an error page",
|
"notfound.title": "Oops… You just found an error page",
|
||||||
"notification.dead-host-saved": "404 Host has been saved",
|
"notification.dead-host-saved": "404 Host has been saved",
|
||||||
"notification.error": "Error",
|
"notification.error": "Error",
|
||||||
|
"notification.host-deleted": "Host has been deleted",
|
||||||
|
"notification.host-disabled": "Host has been disabled",
|
||||||
|
"notification.host-enabled": "Host has been enabled",
|
||||||
"notification.success": "Success",
|
"notification.success": "Success",
|
||||||
"notification.user-deleted": "User has been deleted",
|
"notification.user-deleted": "User has been deleted",
|
||||||
"notification.user-saved": "User has been saved",
|
"notification.user-saved": "User has been saved",
|
||||||
|
@@ -134,12 +134,18 @@
|
|||||||
"dead-hosts.count": {
|
"dead-hosts.count": {
|
||||||
"defaultMessage": "{count} 404 Hosts"
|
"defaultMessage": "{count} 404 Hosts"
|
||||||
},
|
},
|
||||||
"dead-host.edit": {
|
|
||||||
"defaultMessage": "Edit 404 Host"
|
|
||||||
},
|
|
||||||
"dead-hosts.empty": {
|
"dead-hosts.empty": {
|
||||||
"defaultMessage": "There are no 404 Hosts"
|
"defaultMessage": "There are no 404 Hosts"
|
||||||
},
|
},
|
||||||
|
"dead-host.delete.content": {
|
||||||
|
"defaultMessage": "Are you sure you want to delete this 404 host?"
|
||||||
|
},
|
||||||
|
"dead-host.delete.title": {
|
||||||
|
"defaultMessage": "Delete 404 Host"
|
||||||
|
},
|
||||||
|
"dead-host.edit": {
|
||||||
|
"defaultMessage": "Edit 404 Host"
|
||||||
|
},
|
||||||
"dead-host.new": {
|
"dead-host.new": {
|
||||||
"defaultMessage": "New 404 Host"
|
"defaultMessage": "New 404 Host"
|
||||||
},
|
},
|
||||||
@@ -200,12 +206,21 @@
|
|||||||
"error.required": {
|
"error.required": {
|
||||||
"defaultMessage": "This is required"
|
"defaultMessage": "This is required"
|
||||||
},
|
},
|
||||||
|
"event.created-dead-host": {
|
||||||
|
"defaultMessage": "Created 404 Host"
|
||||||
|
},
|
||||||
"event.created-user": {
|
"event.created-user": {
|
||||||
"defaultMessage": "Created User"
|
"defaultMessage": "Created User"
|
||||||
},
|
},
|
||||||
"event.deleted-user": {
|
"event.deleted-user": {
|
||||||
"defaultMessage": "Deleted User"
|
"defaultMessage": "Deleted User"
|
||||||
},
|
},
|
||||||
|
"event.disabled-dead-host": {
|
||||||
|
"defaultMessage": "Disabled 404 Host"
|
||||||
|
},
|
||||||
|
"event.enabled-dead-host": {
|
||||||
|
"defaultMessage": "Enabled 404 Host"
|
||||||
|
},
|
||||||
"event.updated-user": {
|
"event.updated-user": {
|
||||||
"defaultMessage": "Updated User"
|
"defaultMessage": "Updated User"
|
||||||
},
|
},
|
||||||
@@ -254,9 +269,18 @@
|
|||||||
"notification.error": {
|
"notification.error": {
|
||||||
"defaultMessage": "Error"
|
"defaultMessage": "Error"
|
||||||
},
|
},
|
||||||
|
"notification.host-deleted": {
|
||||||
|
"defaultMessage": "Host has been deleted"
|
||||||
|
},
|
||||||
"notification.user-deleted": {
|
"notification.user-deleted": {
|
||||||
"defaultMessage": "User has been deleted"
|
"defaultMessage": "User has been deleted"
|
||||||
},
|
},
|
||||||
|
"notification.host-disabled": {
|
||||||
|
"defaultMessage": "Host has been disabled"
|
||||||
|
},
|
||||||
|
"notification.host-enabled": {
|
||||||
|
"defaultMessage": "Host has been enabled"
|
||||||
|
},
|
||||||
"notification.user-saved": {
|
"notification.user-saved": {
|
||||||
"defaultMessage": "User has been saved"
|
"defaultMessage": "User has been saved"
|
||||||
},
|
},
|
||||||
|
@@ -12,9 +12,10 @@ interface Props {
|
|||||||
isFetching?: boolean;
|
isFetching?: boolean;
|
||||||
onEdit?: (id: number) => void;
|
onEdit?: (id: number) => void;
|
||||||
onDelete?: (id: number) => void;
|
onDelete?: (id: number) => void;
|
||||||
|
onDisableToggle?: (id: number, enabled: boolean) => void;
|
||||||
onNew?: () => void;
|
onNew?: () => void;
|
||||||
}
|
}
|
||||||
export default function Table({ data, isFetching, onEdit, onDelete, onNew }: Props) {
|
export default function Table({ data, isFetching, onEdit, onDelete, onDisableToggle, onNew }: Props) {
|
||||||
const columnHelper = createColumnHelper<DeadHost>();
|
const columnHelper = createColumnHelper<DeadHost>();
|
||||||
const columns = useMemo(
|
const columns = useMemo(
|
||||||
() => [
|
() => [
|
||||||
@@ -83,9 +84,18 @@ export default function Table({ data, isFetching, onEdit, onDelete, onNew }: Pro
|
|||||||
<IconEdit size={16} />
|
<IconEdit size={16} />
|
||||||
{intl.formatMessage({ id: "action.edit" })}
|
{intl.formatMessage({ id: "action.edit" })}
|
||||||
</a>
|
</a>
|
||||||
<a className="dropdown-item" href="#">
|
<a
|
||||||
|
className="dropdown-item"
|
||||||
|
href="#"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
onDisableToggle?.(info.row.original.id, !info.row.original.enabled);
|
||||||
|
}}
|
||||||
|
>
|
||||||
<IconPower size={16} />
|
<IconPower size={16} />
|
||||||
{intl.formatMessage({ id: "action.disable" })}
|
{intl.formatMessage({
|
||||||
|
id: info.row.original.enabled ? "action.disable" : "action.enable",
|
||||||
|
})}
|
||||||
</a>
|
</a>
|
||||||
<div className="dropdown-divider" />
|
<div className="dropdown-divider" />
|
||||||
<a
|
<a
|
||||||
@@ -108,7 +118,7 @@ export default function Table({ data, isFetching, onEdit, onDelete, onNew }: Pro
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
[columnHelper, onDelete, onEdit],
|
[columnHelper, onDelete, onEdit, onDisableToggle],
|
||||||
);
|
);
|
||||||
|
|
||||||
const tableInstance = useReactTable<DeadHost>({
|
const tableInstance = useReactTable<DeadHost>({
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
import { IconSearch } from "@tabler/icons-react";
|
import { IconSearch } from "@tabler/icons-react";
|
||||||
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import Alert from "react-bootstrap/Alert";
|
import Alert from "react-bootstrap/Alert";
|
||||||
|
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 } from "src/locale";
|
import { intl } from "src/locale";
|
||||||
@@ -9,6 +11,7 @@ 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 [deleteId, setDeleteId] = useState(0);
|
const [deleteId, setDeleteId] = useState(0);
|
||||||
const [editId, setEditId] = useState(0 as number | "new");
|
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"]);
|
||||||
@@ -22,10 +25,17 @@ export default function TableWrapper() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleDelete = async () => {
|
const handleDelete = async () => {
|
||||||
// await deleteUser(deleteId);
|
await deleteDeadHost(deleteId);
|
||||||
showSuccess(intl.formatMessage({ id: "notification.host-deleted" }));
|
showSuccess(intl.formatMessage({ id: "notification.host-deleted" }));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDisableToggle = async (id: number, enabled: boolean) => {
|
||||||
|
await toggleDeadHost(id, enabled);
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["dead-hosts"] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["dead-host", id] });
|
||||||
|
showSuccess(intl.formatMessage({ id: enabled ? "notification.host-enabled" : "notification.host-disabled" }));
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="card mt-4">
|
<div className="card mt-4">
|
||||||
<div className="card-status-top bg-red" />
|
<div className="card-status-top bg-red" />
|
||||||
@@ -60,17 +70,18 @@ export default function TableWrapper() {
|
|||||||
isFetching={isFetching}
|
isFetching={isFetching}
|
||||||
onEdit={(id: number) => setEditId(id)}
|
onEdit={(id: number) => setEditId(id)}
|
||||||
onDelete={(id: number) => setDeleteId(id)}
|
onDelete={(id: number) => setDeleteId(id)}
|
||||||
|
onDisableToggle={handleDisableToggle}
|
||||||
onNew={() => setEditId("new")}
|
onNew={() => setEditId("new")}
|
||||||
/>
|
/>
|
||||||
{editId ? <DeadHostModal id={editId} onClose={() => setEditId(0)} /> : null}
|
{editId ? <DeadHostModal id={editId} onClose={() => setEditId(0)} /> : null}
|
||||||
{deleteId ? (
|
{deleteId ? (
|
||||||
<DeleteConfirmModal
|
<DeleteConfirmModal
|
||||||
title={intl.formatMessage({ id: "user.delete.title" })}
|
title={intl.formatMessage({ id: "dead-host.delete.title" })}
|
||||||
onConfirm={handleDelete}
|
onConfirm={handleDelete}
|
||||||
onClose={() => setDeleteId(0)}
|
onClose={() => setDeleteId(0)}
|
||||||
invalidations={[["dead-hosts"], ["dead-host", deleteId]]}
|
invalidations={[["dead-hosts"], ["dead-host", deleteId]]}
|
||||||
>
|
>
|
||||||
{intl.formatMessage({ id: "user.delete.content" })}
|
{intl.formatMessage({ id: "dead-host.delete.content" })}
|
||||||
</DeleteConfirmModal>
|
</DeleteConfirmModal>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user