Spaces:
Running
Running
File size: 3,976 Bytes
6e29063 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
import {
Alert,
Button,
Center,
CloseButton,
Group,
Modal,
Pagination,
Table,
TextInput,
Tooltip,
} from "@mantine/core";
import { IconInfoCircle, IconSearch } from "@tabler/icons-react";
import { usePubSub } from "create-pubsub/react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { logEntriesPubSub } from "../../modules/logEntries";
export default function LogsModal({
opened,
onClose,
}: {
opened: boolean;
onClose: () => void;
}) {
const [logEntries] = usePubSub(logEntriesPubSub);
const [page, setPage] = useState(1);
const [filterText, setFilterText] = useState("");
const logEntriesPerPage = 5;
const filteredLogEntries = useMemo(() => {
if (!filterText) return logEntries;
const lowerCaseFilter = filterText.toLowerCase();
return logEntries.filter((entry) =>
entry.message.toLowerCase().includes(lowerCaseFilter),
);
}, [logEntries, filterText]);
const logEntriesFromCurrentPage = useMemo(
() =>
filteredLogEntries.slice(
(page - 1) * logEntriesPerPage,
page * logEntriesPerPage,
),
[filteredLogEntries, page],
);
useEffect(() => {
void filterText;
setPage(1);
}, [filterText]);
const downloadLogsAsJson = useCallback(() => {
const jsonString = JSON.stringify(logEntries, null, 2);
const blob = new Blob([jsonString], { type: "application/json" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = "logs.json";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}, [logEntries]);
return (
<Modal opened={opened} onClose={onClose} size="xl" title="Logs">
<Alert variant="light" color="blue" icon={<IconInfoCircle />} mb="md">
<Group justify="space-between" align="center">
<span>
This information is stored solely in your browser for personal use.
It isn't sent automatically and is retained for debugging purposes
should you need to{" "}
<a
href="https://github.com/felladrin/MiniSearch/issues/new?labels=bug&template=bug_report.yml"
target="_blank"
rel="noopener noreferrer"
>
report a bug
</a>
.
</span>
<Button onClick={downloadLogsAsJson} size="xs" data-autofocus>
Download Logs
</Button>
</Group>
</Alert>
<TextInput
placeholder="Filter logs..."
mb="md"
leftSection={<IconSearch size={16} />}
value={filterText}
onChange={(event) => setFilterText(event.currentTarget.value)}
rightSection={
filterText ? (
<Tooltip label="Clear filter" withArrow>
<CloseButton
size="sm"
onClick={() => setFilterText("")}
aria-label="Clear filter"
/>
</Tooltip>
) : null
}
/>
<Table striped highlightOnHover withTableBorder>
<Table.Thead>
<Table.Tr>
<Table.Th style={{ width: 80 }}>Time</Table.Th>
<Table.Th>Message</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>
{logEntriesFromCurrentPage.map((entry, index) => (
<Table.Tr key={`${entry.timestamp}-${index}`}>
<Table.Td>
{new Date(entry.timestamp).toLocaleTimeString()}
</Table.Td>
<Table.Td>{entry.message}</Table.Td>
</Table.Tr>
))}
</Table.Tbody>
</Table>
<Center>
<Pagination
total={Math.ceil(filteredLogEntries.length / logEntriesPerPage)}
value={page}
onChange={setPage}
size="sm"
mt="md"
/>
</Center>
</Modal>
);
}
|