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>
  );
}