Table.tsx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. import { IconDotsVertical, IconDownload, IconRefresh, IconTrash } from "@tabler/icons-react";
  2. import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table";
  3. import { useMemo } from "react";
  4. import type { Certificate } from "src/api/backend";
  5. import {
  6. CertificateInUseFormatter,
  7. DateFormatter,
  8. DomainsFormatter,
  9. EmptyData,
  10. GravatarFormatter,
  11. } from "src/components";
  12. import { TableLayout } from "src/components/Table/TableLayout";
  13. import { intl, T } from "src/locale";
  14. import { showCustomCertificateModal, showDNSCertificateModal, showHTTPCertificateModal } from "src/modals";
  15. interface Props {
  16. data: Certificate[];
  17. isFiltered?: boolean;
  18. isFetching?: boolean;
  19. onDelete?: (id: number) => void;
  20. onRenew?: (id: number) => void;
  21. onDownload?: (id: number) => void;
  22. }
  23. export default function Table({ data, isFetching, onDelete, onRenew, onDownload, isFiltered }: Props) {
  24. const columnHelper = createColumnHelper<Certificate>();
  25. const columns = useMemo(
  26. () => [
  27. columnHelper.accessor((row: any) => row.owner, {
  28. id: "owner",
  29. cell: (info: any) => {
  30. const value = info.getValue();
  31. return <GravatarFormatter url={value.avatar} name={value.name} />;
  32. },
  33. meta: {
  34. className: "w-1",
  35. },
  36. }),
  37. columnHelper.accessor((row: any) => row, {
  38. id: "domainNames",
  39. header: intl.formatMessage({ id: "column.name" }),
  40. cell: (info: any) => {
  41. const value = info.getValue();
  42. return <DomainsFormatter domains={value.domainNames} createdOn={value.createdOn} />;
  43. },
  44. }),
  45. columnHelper.accessor((row: any) => row.provider, {
  46. id: "provider",
  47. header: intl.formatMessage({ id: "column.provider" }),
  48. cell: (info: any) => {
  49. if (info.getValue() === "letsencrypt") {
  50. return <T id="lets-encrypt" />;
  51. }
  52. return <T id={info.getValue()} />;
  53. },
  54. }),
  55. columnHelper.accessor((row: any) => row.expiresOn, {
  56. id: "expiresOn",
  57. header: intl.formatMessage({ id: "column.expires" }),
  58. cell: (info: any) => {
  59. return <DateFormatter value={info.getValue()} highlightPast />;
  60. },
  61. }),
  62. columnHelper.accessor((row: any) => row, {
  63. id: "proxyHosts",
  64. header: intl.formatMessage({ id: "column.status" }),
  65. cell: (info: any) => {
  66. const r = info.getValue();
  67. return (
  68. <CertificateInUseFormatter
  69. proxyHosts={r.proxyHosts}
  70. redirectionHosts={r.redirectionHosts}
  71. deadHosts={r.deadHosts}
  72. />
  73. );
  74. },
  75. }),
  76. columnHelper.display({
  77. id: "id",
  78. cell: (info: any) => {
  79. return (
  80. <span className="dropdown">
  81. <button
  82. type="button"
  83. className="btn dropdown-toggle btn-action btn-sm px-1"
  84. data-bs-boundary="viewport"
  85. data-bs-toggle="dropdown"
  86. >
  87. <IconDotsVertical />
  88. </button>
  89. <div className="dropdown-menu dropdown-menu-end">
  90. <span className="dropdown-header">
  91. <T
  92. id="object.actions-title"
  93. tData={{ object: "certificate" }}
  94. data={{ id: info.row.original.id }}
  95. />
  96. </span>
  97. <a
  98. className="dropdown-item"
  99. href="#"
  100. onClick={(e) => {
  101. e.preventDefault();
  102. onRenew?.(info.row.original.id);
  103. }}
  104. >
  105. <IconRefresh size={16} />
  106. <T id="action.renew" />
  107. </a>
  108. <a
  109. className="dropdown-item"
  110. href="#"
  111. onClick={(e) => {
  112. e.preventDefault();
  113. onDownload?.(info.row.original.id);
  114. }}
  115. >
  116. <IconDownload size={16} />
  117. <T id="action.download" />
  118. </a>
  119. <div className="dropdown-divider" />
  120. <a
  121. className="dropdown-item"
  122. href="#"
  123. onClick={(e) => {
  124. e.preventDefault();
  125. onDelete?.(info.row.original.id);
  126. }}
  127. >
  128. <IconTrash size={16} />
  129. <T id="action.delete" />
  130. </a>
  131. </div>
  132. </span>
  133. );
  134. },
  135. meta: {
  136. className: "text-end w-1",
  137. },
  138. }),
  139. ],
  140. [columnHelper, onDelete, onRenew, onDownload],
  141. );
  142. const tableInstance = useReactTable<Certificate>({
  143. columns,
  144. data,
  145. getCoreRowModel: getCoreRowModel(),
  146. rowCount: data.length,
  147. meta: {
  148. isFetching,
  149. },
  150. enableSortingRemoval: false,
  151. });
  152. const customAddBtn = (
  153. <div className="dropdown">
  154. <button type="button" className="btn dropdown-toggle btn-pink my-3" data-bs-toggle="dropdown">
  155. <T id="object.add" tData={{ object: "certificate" }} />
  156. </button>
  157. <div className="dropdown-menu">
  158. <a
  159. className="dropdown-item"
  160. href="#"
  161. onClick={(e) => {
  162. e.preventDefault();
  163. showHTTPCertificateModal();
  164. }}
  165. >
  166. <T id="lets-encrypt-via-http" />
  167. </a>
  168. <a
  169. className="dropdown-item"
  170. href="#"
  171. onClick={(e) => {
  172. e.preventDefault();
  173. showDNSCertificateModal();
  174. }}
  175. >
  176. <T id="lets-encrypt-via-dns" />
  177. </a>
  178. <div className="dropdown-divider" />
  179. <a
  180. className="dropdown-item"
  181. href="#"
  182. onClick={(e) => {
  183. e.preventDefault();
  184. showCustomCertificateModal();
  185. }}
  186. >
  187. <T id="certificates.custom" />
  188. </a>
  189. </div>
  190. </div>
  191. );
  192. return (
  193. <TableLayout
  194. tableInstance={tableInstance}
  195. emptyState={
  196. <EmptyData
  197. object="certificate"
  198. objects="certificates"
  199. tableInstance={tableInstance}
  200. isFiltered={isFiltered}
  201. color="pink"
  202. customAddBtn={customAddBtn}
  203. />
  204. }
  205. />
  206. );
  207. }