feat: add umami analytics

This commit is contained in:
Samuel 2025-01-22 16:56:43 +01:00
parent 448dde62f7
commit 533866a1f2
7 changed files with 53 additions and 20 deletions

View file

@ -6,6 +6,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<!-- <link rel="shortcut icon" type="image/ico" href="/src/assets/favicon.ico" /> -->
<script defer src="https://umami.duskflower.dev/script.js" data-website-id="90772569-37b0-47af-9702-2ec2cfe0fe5f"
data-domains="signalstats.duskflower.dev"></script>
</head>
<body>

View file

@ -40,6 +40,7 @@
"@solidjs/router": "^0.15.3",
"@sqlite.org/sqlite-wasm": "3.48.0-build2",
"@tanstack/solid-table": "^8.20.5",
"@types/umami": "^2.10.0",
"chart.js": "^4.4.7",
"chartjs-chart-wordcloud": "^4.4.4",
"chartjs-plugin-deferred": "^2.0.0",

8
pnpm-lock.yaml generated
View file

@ -41,6 +41,9 @@ importers:
'@tanstack/solid-table':
specifier: ^8.20.5
version: 8.20.5(solid-js@1.9.4)
'@types/umami':
specifier: ^2.10.0
version: 2.10.0
chart.js:
specifier: ^4.4.7
version: 4.4.7
@ -800,6 +803,9 @@ packages:
'@types/node@22.10.7':
resolution: {integrity: sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==}
'@types/umami@2.10.0':
resolution: {integrity: sha512-iWcs1KkcO3ooIi2rR9M5drmpQzlsT+sFiyWElIGmVwjdGlp+vQmy/VYIChYnF5ETqx7KrL80JfSkroS6dm37Hg==}
JSONStream@1.3.5:
resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==}
hasBin: true
@ -2739,6 +2745,8 @@ snapshots:
dependencies:
undici-types: 6.20.0
'@types/umami@2.10.0': {}
JSONStream@1.3.5:
dependencies:
jsonparse: 1.3.1

View file

@ -42,7 +42,14 @@ if (root) {
There is currently no backup database loaded, but you can watch statistics that have been
cached, meaning only chats you already opened or chats that were preloaded.
<br />
<A href="/overview">Watch cached statistics</A>
<A
href="/overview"
onClick={() => {
umami.track("Watch cached statistics");
}}
>
Watch cached statistics
</A>
</Callout>
</Show>
}

View file

@ -37,7 +37,7 @@ export const Home: Component<RouteSectionProps> = () => {
const [loadingProgress, setLoadingProgress] = createSignal<number>();
// const [isLoadingDatabase, setIsLoadingDatabase] = createSignal(false);
const onSubmit: JSX.EventHandler<HTMLFormElement, SubmitEvent> = async (event) => {
const onSubmit: JSX.EventHandler<HTMLFormElement, SubmitEvent> = (event) => {
event.preventDefault();
const currentBackupFile = backupFile();
@ -53,22 +53,24 @@ export const Home: Component<RouteSectionProps> = () => {
// setDbHash(hash);
try {
const decrypted = await decryptBackup(currentBackupFile, currentPassphrase, setDecryptionProgress);
decryptBackup(currentBackupFile, currentPassphrase, setDecryptionProgress)
.then(async (decrypted) => {
umami.track("Decrypt backup");
setDecryptionProgress(undefined);
// setIsLoadingDatabase(true);
setLoadingProgress(0);
setDecryptionProgress(undefined);
// setIsLoadingDatabase(true);
setLoadingProgress(0);
await loadDb(decrypted.database_statements, setLoadingProgress);
umami.track("Load database");
await loadDb(decrypted.database_statements, setLoadingProgress);
// setIsLoadingDatabase(false);
setLoadingProgress(undefined);
// setIsLoadingDatabase(false);
setLoadingProgress(undefined);
navigate("/overview");
} catch (error) {
console.error("Decryption failed:", error);
}
navigate("/overview");
})
.catch((error) => {
console.error("Decryption failed:", error);
});
}
};

View file

@ -94,6 +94,7 @@ export const columns = [
<Button
variant="ghost"
onClick={() => {
umami.track("Sort overview table");
props.column.toggleSorting();
}}
>
@ -144,6 +145,7 @@ export const columns = [
<Button
variant="ghost"
onClick={() => {
umami.track("Sort overview table");
props.column.toggleSorting();
}}
>
@ -162,6 +164,7 @@ export const columns = [
<Button
variant="ghost"
onClick={() => {
umami.track("Sort overview table");
props.column.toggleSorting();
}}
>
@ -269,7 +272,10 @@ export const OverviewTable = (props: OverviewTableProps) => {
<div class="flex items-center py-4">
<TextField
value={(table.getColumn("name")?.getFilterValue() as string | undefined) ?? ""}
onChange={(value) => table.getColumn("name")?.setFilterValue(value)}
onChange={(value) => {
umami.track("Filter overview table");
table.getColumn("name")?.setFilterValue(value);
}}
>
<TextFieldInput placeholder="Filter by name..." class="max-w-sm" />
</TextField>
@ -278,7 +284,10 @@ export const OverviewTable = (props: OverviewTableProps) => {
<Checkbox
id="show-archived"
checked={(table.getColumn("archived")?.getFilterValue() as boolean | undefined) ?? false}
onChange={(value) => table.getColumn("archived")?.setFilterValue(value)}
onChange={(value) => {
umami.track("Filter overview table");
table.getColumn("archived")?.setFilterValue(value);
}}
/>
<div class="grid gap-1.5 leading-none">
<Label for="show-archived">Show archived chats</Label>
@ -288,7 +297,10 @@ export const OverviewTable = (props: OverviewTableProps) => {
<Checkbox
id="show-groups"
checked={(table.getColumn("isGroup")?.getFilterValue() as boolean | undefined) ?? false}
onChange={(value) => table.getColumn("isGroup")?.setFilterValue(value)}
onChange={(value) => {
umami.track("Filter overview table");
table.getColumn("isGroup")?.setFilterValue(value);
}}
/>
<div class="grid gap-1.5 leading-none">
<Label for="show-groups">Show group chats (detailed analysis not implemented)</Label>
@ -347,7 +359,7 @@ export const OverviewTable = (props: OverviewTableProps) => {
preload(`/${isGroup ? "group" : "dm"}/${threadId.toString()}`, {
preloadData: true,
});
}, 20);
}, 50);
event.currentTarget.addEventListener(
"pointerout",
@ -365,6 +377,7 @@ export const OverviewTable = (props: OverviewTableProps) => {
const isGroup = row.original.isGroup;
if (rowIsAvailable(threadId)) {
umami.track("Load chat statistics");
navigate(`/${isGroup ? "group" : "dm"}/${threadId.toString()}`);
}
}}

View file

@ -8,7 +8,7 @@
"esModuleInterop": true,
"jsx": "preserve",
"jsxImportSource": "solid-js",
"types": ["vite/client"],
"types": ["vite/client", "@types/umami"],
"noEmit": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,