TableWrapper.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import { IconHelp, IconSearch } from "@tabler/icons-react";
  2. import { useQueryClient } from "@tanstack/react-query";
  3. import { useState } from "react";
  4. import Alert from "react-bootstrap/Alert";
  5. import { deleteProxyHost, toggleProxyHost } from "src/api/backend";
  6. import { Button, LoadingPage } from "src/components";
  7. import { useProxyHosts } from "src/hooks";
  8. import { T } from "src/locale";
  9. import { showDeleteConfirmModal, showHelpModal, showProxyHostModal } from "src/modals";
  10. import { showObjectSuccess } from "src/notifications";
  11. import Table from "./Table";
  12. export default function TableWrapper() {
  13. const queryClient = useQueryClient();
  14. const [search, setSearch] = useState("");
  15. const { isFetching, isLoading, isError, error, data } = useProxyHosts(["owner", "access_list", "certificate"]);
  16. if (isLoading) {
  17. return <LoadingPage />;
  18. }
  19. if (isError) {
  20. return <Alert variant="danger">{error?.message || "Unknown error"}</Alert>;
  21. }
  22. const handleDelete = async (id: number) => {
  23. await deleteProxyHost(id);
  24. showObjectSuccess("proxy-host", "deleted");
  25. };
  26. const handleDisableToggle = async (id: number, enabled: boolean) => {
  27. await toggleProxyHost(id, enabled);
  28. queryClient.invalidateQueries({ queryKey: ["proxy-hosts"] });
  29. queryClient.invalidateQueries({ queryKey: ["proxy-host", id] });
  30. showObjectSuccess("proxy-host", enabled ? "enabled" : "disabled");
  31. };
  32. let filtered = null;
  33. if (search && data) {
  34. filtered = data?.filter(
  35. (item) =>
  36. item.domainNames.some((domain: string) => domain.toLowerCase().includes(search)) ||
  37. item.forwardHost.toLowerCase().includes(search) ||
  38. `${item.forwardPort}`.includes(search),
  39. );
  40. } else if (search !== "") {
  41. // this can happen if someone deletes the last item while searching
  42. setSearch("");
  43. }
  44. return (
  45. <div className="card mt-4">
  46. <div className="card-status-top bg-lime" />
  47. <div className="card-table">
  48. <div className="card-header">
  49. <div className="row w-full">
  50. <div className="col">
  51. <h2 className="mt-1 mb-0">
  52. <T id="proxy-hosts" />
  53. </h2>
  54. </div>
  55. <div className="col-md-auto col-sm-12">
  56. <div className="ms-auto d-flex flex-wrap btn-list">
  57. {data?.length ? (
  58. <div className="input-group input-group-flat w-auto">
  59. <span className="input-group-text input-group-text-sm">
  60. <IconSearch size={16} />
  61. </span>
  62. <input
  63. id="advanced-table-search"
  64. type="text"
  65. className="form-control form-control-sm"
  66. autoComplete="off"
  67. onChange={(e: any) => setSearch(e.target.value.toLowerCase().trim())}
  68. />
  69. </div>
  70. ) : null}
  71. <Button size="sm" onClick={() => showHelpModal("ProxyHosts", "lime")}>
  72. <IconHelp size={20} />
  73. </Button>
  74. {data?.length ? (
  75. <Button size="sm" className="btn-lime" onClick={() => showProxyHostModal("new")}>
  76. <T id="object.add" tData={{ object: "proxy-host" }} />
  77. </Button>
  78. ) : null}
  79. </div>
  80. </div>
  81. </div>
  82. </div>
  83. <Table
  84. data={filtered ?? data ?? []}
  85. isFiltered={!!search}
  86. isFetching={isFetching}
  87. onEdit={(id: number) => showProxyHostModal(id)}
  88. onDelete={(id: number) =>
  89. showDeleteConfirmModal({
  90. title: <T id="object.delete" tData={{ object: "proxy-host" }} />,
  91. onConfirm: () => handleDelete(id),
  92. invalidations: [["proxy-hosts"], ["proxy-host", id]],
  93. children: <T id="object.delete.content" tData={{ object: "proxy-host" }} />,
  94. })
  95. }
  96. onDisableToggle={handleDisableToggle}
  97. onNew={() => showProxyHostModal("new")}
  98. />
  99. </div>
  100. </div>
  101. );
  102. }