Compare commits

...

3 commits

Author SHA1 Message Date
duskflower
5a49648e64 fmt: sort imports 2025-01-24 18:10:10 +01:00
duskflower
12094316ee feat: add new progress display for parallel loading 2025-01-24 18:10:00 +01:00
duskflower
33d6c6b3ed perf: load database parallel to decrypting 2025-01-24 17:40:16 +01:00
23 changed files with 87 additions and 110 deletions

View file

@ -1,6 +1,7 @@
{ {
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"quickfix.biome": "explicit" "quickfix.biome": "explicit",
"source.organizeImports.biome": "explicit"
}, },
"typescript.inlayHints.parameterNames.enabled": "all", "typescript.inlayHints.parameterNames.enabled": "all",
"[typescript]": { "[typescript]": {

View file

@ -4,11 +4,11 @@
"": { "": {
"name": "signalstats", "name": "signalstats",
"dependencies": { "dependencies": {
"@duskflower/signal-decrypt-backup-wasm": "^0.2.1", "@duskflower/signal-decrypt-backup-wasm": "^0.3.0",
"@kobalte/core": "^0.13.7", "@kobalte/core": "^0.13.7",
"@kobalte/tailwindcss": "^0.9.0", "@kobalte/tailwindcss": "^0.9.0",
"@solid-primitives/refs": "^1.1.0", "@solid-primitives/refs": "^1.1.0",
"@solid-primitives/storage": "^4.3.0", "@solid-primitives/storage": "^4.3.1",
"@solid-primitives/upload": "^0.1.0", "@solid-primitives/upload": "^0.1.0",
"@solid-primitives/workers": "^0.4.0", "@solid-primitives/workers": "^0.4.0",
"@solidjs/meta": "^0.29.4", "@solidjs/meta": "^0.29.4",
@ -37,7 +37,7 @@
"@commitlint/cli": "^19.6.1", "@commitlint/cli": "^19.6.1",
"@commitlint/config-conventional": "^19.6.0", "@commitlint/config-conventional": "^19.6.0",
"@tailwindcss/vite": "^4.0.0", "@tailwindcss/vite": "^4.0.0",
"@types/node": "^22.10.9", "@types/node": "^22.10.10",
"better-sqlite3": "^11.8.1", "better-sqlite3": "^11.8.1",
"husky": "^9.1.7", "husky": "^9.1.7",
"kysely-codegen": "^0.17.0", "kysely-codegen": "^0.17.0",
@ -141,7 +141,7 @@
"@corvu/utils": ["@corvu/utils@0.4.2", "", { "dependencies": { "@floating-ui/dom": "^1.6.11" }, "peerDependencies": { "solid-js": "^1.8" } }, "sha512-Ox2kYyxy7NoXdKWdHeDEjZxClwzO4SKM8plAaVwmAJPxHMqA0rLOoAsa+hBDwRLpctf+ZRnAd/ykguuJidnaTA=="], "@corvu/utils": ["@corvu/utils@0.4.2", "", { "dependencies": { "@floating-ui/dom": "^1.6.11" }, "peerDependencies": { "solid-js": "^1.8" } }, "sha512-Ox2kYyxy7NoXdKWdHeDEjZxClwzO4SKM8plAaVwmAJPxHMqA0rLOoAsa+hBDwRLpctf+ZRnAd/ykguuJidnaTA=="],
"@duskflower/signal-decrypt-backup-wasm": ["@duskflower/signal-decrypt-backup-wasm@0.2.1", "https://git.duskflower.dev/api/packages/duskflower/npm/%40duskflower%2Fsignal-decrypt-backup-wasm/-/0.2.1/signal-decrypt-backup-wasm-0.2.1.tgz", {}, "sha512-lYwtubVOUU4kuJNw28Ns8N9Gh2nZB4j6BJz/vLpxF0Vc7zww3VIGnMCQToFWWSAwCs5+cABadeZMkv87SGfyQg=="], "@duskflower/signal-decrypt-backup-wasm": ["@duskflower/signal-decrypt-backup-wasm@0.3.0", "https://git.duskflower.dev/api/packages/duskflower/npm/%40duskflower%2Fsignal-decrypt-backup-wasm/-/0.3.0/signal-decrypt-backup-wasm-0.3.0.tgz", {}, "sha512-1IMNFGz4bV4o29eXVelNbancqovsljmM0iZRrtau81gSy8bFE1lgwGFN05NAOFWlX/aZYzeUEeZVBrjUYIM0/w=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.24.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA=="], "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.24.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA=="],

View file

@ -16,7 +16,7 @@
"@commitlint/cli": "^19.6.1", "@commitlint/cli": "^19.6.1",
"@commitlint/config-conventional": "^19.6.0", "@commitlint/config-conventional": "^19.6.0",
"@tailwindcss/vite": "^4.0.0", "@tailwindcss/vite": "^4.0.0",
"@types/node": "^22.10.9", "@types/node": "^22.10.10",
"better-sqlite3": "^11.8.1", "better-sqlite3": "^11.8.1",
"husky": "^9.1.7", "husky": "^9.1.7",
"kysely-codegen": "^0.17.0", "kysely-codegen": "^0.17.0",
@ -28,11 +28,11 @@
"vite-plugin-wasm": "^3.4.1" "vite-plugin-wasm": "^3.4.1"
}, },
"dependencies": { "dependencies": {
"@duskflower/signal-decrypt-backup-wasm": "^0.2.1", "@duskflower/signal-decrypt-backup-wasm": "^0.3.0",
"@kobalte/core": "^0.13.7", "@kobalte/core": "^0.13.7",
"@kobalte/tailwindcss": "^0.9.0", "@kobalte/tailwindcss": "^0.9.0",
"@solid-primitives/refs": "^1.1.0", "@solid-primitives/refs": "^1.1.0",
"@solid-primitives/storage": "^4.3.0", "@solid-primitives/storage": "^4.3.1",
"@solid-primitives/upload": "^0.1.0", "@solid-primitives/upload": "^0.1.0",
"@solid-primitives/workers": "^0.4.0", "@solid-primitives/workers": "^0.4.0",
"@solidjs/meta": "^0.29.4", "@solidjs/meta": "^0.29.4",

View file

@ -1,16 +1,15 @@
import { A, Route, Router, useNavigate } from "@solidjs/router"; import { A, Route, Router, useNavigate } from "@solidjs/router";
import { createEffect, Show, Suspense, type Component } from "solid-js"; import { type Component, Show, Suspense, createEffect } from "solid-js";
import { DmId, GroupId, Home, Overview, preloadDmId, Privacy } from "./pages"; import { DmId, GroupId, Home, Overview, Privacy, preloadDmId } from "./pages";
import "./app.css"; import "./app.css";
import { ColorModeProvider, ColorModeScript, createLocalStorageManager } from "@kobalte/core";
import { MetaProvider } from "@solidjs/meta"; import { MetaProvider } from "@solidjs/meta";
import { Portal } from "solid-js/web"; import { Portal } from "solid-js/web";
import { Callout, CalloutTitle, CalloutContent } from "./components/ui/callout"; import { Callout, CalloutContent, CalloutTitle } from "./components/ui/callout";
import { ModeToggle } from "./components/ui/mode-toggle";
import { dbLoaded } from "./db"; import { dbLoaded } from "./db";
import { hasCashedData } from "./lib/db-cache"; import { hasCashedData } from "./lib/db-cache";
import { isWasmSupported } from "./lib/utils"; import { isWasmSupported } from "./lib/utils";
import { ColorModeProvider, ColorModeScript, createLocalStorageManager } from "@kobalte/core";
import { ModeToggle } from "./components/ui/mode-toggle";
const NO_DATA_NEEDED_PAGES = ["/", "/privacy"]; const NO_DATA_NEEDED_PAGES = ["/", "/privacy"];

View file

@ -1,7 +1,7 @@
import { sql, type NotNull } from "kysely"; import { type NotNull, sql } from "kysely";
import { worker, kyselyDb, SELF_ID, DB_FILENAME, setDbLoaded } from "./db";
import { cached, clearDbCache } from "../lib/db-cache";
import type { MainToWorkerMsg, WorkerToMainMsg } from "~/lib/kysely-official-wasm-worker/type"; import type { MainToWorkerMsg, WorkerToMainMsg } from "~/lib/kysely-official-wasm-worker/type";
import { cached, clearDbCache } from "../lib/db-cache";
import { DB_FILENAME, SELF_ID, kyselyDb, setDbLoaded, worker } from "./db";
export const loadDb = async (statements: string[], progressCallback?: (percentage: number) => void): Promise<void> => { export const loadDb = async (statements: string[], progressCallback?: (percentage: number) => void): Promise<void> => {
// try to persist storage, https://web.dev/articles/persistent-storage#request_persistent_storage // try to persist storage, https://web.dev/articles/persistent-storage#request_persistent_storage

View file

@ -1,8 +1,8 @@
import { Kysely } from "kysely"; import { Kysely } from "kysely";
import type { DB } from "./db-schema";
import { OfficialWasmWorkerDialect } from "~/lib/kysely-official-wasm-worker";
import WasmWorker from "./db-worker?worker";
import { createSignal } from "solid-js"; import { createSignal } from "solid-js";
import { OfficialWasmWorkerDialect } from "~/lib/kysely-official-wasm-worker";
import type { DB } from "./db-schema";
import WasmWorker from "./db-worker?worker";
export const SELF_ID = 2; export const SELF_ID = 2;

View file

@ -1,7 +1,4 @@
import { import { BackupDecryptor } from "@duskflower/signal-decrypt-backup-wasm";
BackupDecryptor,
type DecryptionResult,
} from "@duskflower/signal-decrypt-backup-wasm";
const CHUNK_SIZE = 1024 * 1024 * 40; // 40MB chunks const CHUNK_SIZE = 1024 * 1024 * 40; // 40MB chunks
@ -9,7 +6,8 @@ export async function decryptBackup(
file: File, file: File,
passphrase: string, passphrase: string,
progressCallback: (progress: number) => void, progressCallback: (progress: number) => void,
): Promise<DecryptionResult> { statementsCallback?: (statements: string[]) => void | Promise<void>,
): Promise<string[]> {
const fileSize = file.size; const fileSize = file.size;
const decryptor = new BackupDecryptor(); const decryptor = new BackupDecryptor();
decryptor.set_progress_callback(fileSize, progressCallback); decryptor.set_progress_callback(fileSize, progressCallback);
@ -34,6 +32,8 @@ export async function decryptBackup(
} }
} }
await statementsCallback?.(decryptor.get_new_decrypted_statements());
offset += CHUNK_SIZE; offset += CHUNK_SIZE;
} }

View file

@ -1,11 +1,4 @@
import type { import type { DatabaseIntrospector, Dialect, DialectAdapter, Driver, Kysely, QueryCompiler } from "kysely";
DatabaseIntrospector,
Dialect,
DialectAdapter,
Driver,
Kysely,
QueryCompiler,
} from "kysely";
import { SqliteAdapter, SqliteIntrospector, SqliteQueryCompiler } from "kysely"; import { SqliteAdapter, SqliteIntrospector, SqliteQueryCompiler } from "kysely";
import { OfficialWasmWorkerDriver } from "./driver"; import { OfficialWasmWorkerDriver } from "./driver";
import type { OfficialWasmWorkerDialectConfig } from "./type"; import type { OfficialWasmWorkerDialectConfig } from "./type";

View file

@ -1,5 +1,5 @@
import { getHourList, getMonthList, getWeekdayList } from "./date";
import type { MessageOverview, MessageStats, Recipients } from "~/types"; import type { MessageOverview, MessageStats, Recipients } from "~/types";
import { getHourList, getMonthList, getWeekdayList } from "./date";
const hourNames = getHourList(); const hourNames = getHourList();

View file

@ -1,6 +1,6 @@
import type { MessageOverview, MessageStats, Recipients } from "~/types"; import type { MessageOverview, MessageStats, Recipients } from "~/types";
import { cached } from "./db-cache";
import { getHourList, getMonthList, getWeekdayList } from "./date"; import { getHourList, getMonthList, getWeekdayList } from "./date";
import { cached } from "./db-cache";
import MessageStatsWorker from "./messages-worker?worker"; import MessageStatsWorker from "./messages-worker?worker";
export const hourNames = getHourList(); export const hourNames = getHourList();

View file

@ -1,21 +1,20 @@
import { Suspense, type Component } from "solid-js";
import { createAsync, type RoutePreloadFunc, type RouteSectionProps } from "@solidjs/router";
import { dmPartnerRecipientQuery, threadMostUsedWordsQuery, threadSentMessagesOverviewQuery, SELF_ID } from "~/db";
import { getNameFromRecipient } from "~/lib/get-name-from-recipient";
import { Heading } from "~/components/ui/heading";
import { Grid } from "~/components/ui/grid";
import { Title } from "@solidjs/meta"; import { Title } from "@solidjs/meta";
import { type RoutePreloadFunc, type RouteSectionProps, createAsync } from "@solidjs/router";
import { type Component, Suspense } from "solid-js";
import { Flex } from "~/components/ui/flex";
import { Grid } from "~/components/ui/grid";
import { Heading } from "~/components/ui/heading";
import { SELF_ID, dmPartnerRecipientQuery, threadMostUsedWordsQuery, threadSentMessagesOverviewQuery } from "~/db";
import { getNameFromRecipient } from "~/lib/get-name-from-recipient";
import { createMessageStatsSources } from "~/lib/messages";
import type { MessageOverview } from "~/types";
import { DmMessagesPerDate } from "./dm-messages-per-date"; import { DmMessagesPerDate } from "./dm-messages-per-date";
import { DmOverview } from "./dm-overview";
import { DmWordCloud } from "./dm-wordcloud";
import { DmMessagesPerMonth } from "./dm-messages-per-month";
import { DmMessagesPerDaytime } from "./dm-messages-per-daytime"; import { DmMessagesPerDaytime } from "./dm-messages-per-daytime";
import { DmMessagesPerMonth } from "./dm-messages-per-month";
import { DmMessagesPerRecipient } from "./dm-messages-per-recipients"; import { DmMessagesPerRecipient } from "./dm-messages-per-recipients";
import { DmMessagesPerWeekday } from "./dm-messages-per-weekday"; import { DmMessagesPerWeekday } from "./dm-messages-per-weekday";
import type { MessageOverview } from "~/types"; import { DmOverview } from "./dm-overview";
import { createMessageStatsSources } from "~/lib/messages"; import { DmWordCloud } from "./dm-wordcloud";
import { Flex } from "~/components/ui/flex";
const getDmIdData = (dmId: number) => { const getDmIdData = (dmId: number) => {
// the other person in the chat with name and id // the other person in the chat with name and id

View file

@ -1,5 +1,5 @@
import { Show, type Accessor, type Component } from "solid-js";
import type { ChartData } from "chart.js"; import type { ChartData } from "chart.js";
import { type Accessor, type Component, Show } from "solid-js";
import { LineChart } from "~/components/ui/charts"; import { LineChart } from "~/components/ui/charts";
import type { MessageStats, Recipients } from "~/types"; import type { MessageStats, Recipients } from "~/types";

View file

@ -1,8 +1,8 @@
import { Show, type Accessor, type Component } from "solid-js";
import type { ChartData } from "chart.js"; import type { ChartData } from "chart.js";
import { type Accessor, type Component, Show } from "solid-js";
import { BarChart } from "~/components/ui/charts"; import { BarChart } from "~/components/ui/charts";
import type { MessageStats, Recipients } from "~/types";
import { hourNames } from "~/lib/messages"; import { hourNames } from "~/lib/messages";
import type { MessageStats, Recipients } from "~/types";
export const DmMessagesPerDaytime: Component<{ export const DmMessagesPerDaytime: Component<{
daytimeStats: MessageStats["daytime"] | undefined; daytimeStats: MessageStats["daytime"] | undefined;

View file

@ -1,5 +1,5 @@
import { Show, type Accessor, type Component } from "solid-js";
import type { ChartData } from "chart.js"; import type { ChartData } from "chart.js";
import { type Accessor, type Component, Show } from "solid-js";
import { RadarChart } from "~/components/ui/charts"; import { RadarChart } from "~/components/ui/charts";
import { monthNames } from "~/lib/messages"; import { monthNames } from "~/lib/messages";
import type { MessageStats, Recipients } from "~/types"; import type { MessageStats, Recipients } from "~/types";

View file

@ -1,5 +1,5 @@
import { Show, type Accessor, type Component } from "solid-js";
import type { ChartData } from "chart.js"; import type { ChartData } from "chart.js";
import { type Accessor, type Component, Show } from "solid-js";
import { PieChart } from "~/components/ui/charts"; import { PieChart } from "~/components/ui/charts";
import type { MessageStats, Recipients } from "~/types"; import type { MessageStats, Recipients } from "~/types";

View file

@ -1,5 +1,5 @@
import { Show, type Accessor, type Component } from "solid-js";
import type { ChartData } from "chart.js"; import type { ChartData } from "chart.js";
import { type Accessor, type Component, Show } from "solid-js";
import { RadarChart } from "~/components/ui/charts"; import { RadarChart } from "~/components/ui/charts";
import { weekdayNames } from "~/lib/messages"; import { weekdayNames } from "~/lib/messages";
import type { MessageStats, Recipients } from "~/types"; import type { MessageStats, Recipients } from "~/types";

View file

@ -1,7 +1,7 @@
import { Show, type Component } from "solid-js"; import { CalendarArrowDown, CalendarArrowUp, CalendarClock, MessagesSquare } from "lucide-solid";
import { type Component, Show } from "solid-js";
import { Flex } from "~/components/ui/flex"; import { Flex } from "~/components/ui/flex";
import { Grid } from "~/components/ui/grid"; import { Grid } from "~/components/ui/grid";
import { CalendarArrowDown, CalendarArrowUp, CalendarClock, MessagesSquare } from "lucide-solid";
import { getDistanceBetweenDatesInDays } from "~/lib/date"; import { getDistanceBetweenDatesInDays } from "~/lib/date";
import type { MessageOverview } from "~/types"; import type { MessageOverview } from "~/types";

View file

@ -1,5 +1,5 @@
import type { ChartData } from "chart.js"; import type { ChartData } from "chart.js";
import { Show, type Accessor, type Component } from "solid-js"; import { type Accessor, type Component, Show } from "solid-js";
import { WordCloudChart } from "~/components/ui/charts"; import { WordCloudChart } from "~/components/ui/charts";
import type { threadMostUsedWordsQuery } from "~/db"; import type { threadMostUsedWordsQuery } from "~/db";

View file

@ -1,5 +1,5 @@
import type { Component } from "solid-js";
import type { RouteSectionProps } from "@solidjs/router"; import type { RouteSectionProps } from "@solidjs/router";
import type { Component } from "solid-js";
export const GroupId: Component<RouteSectionProps> = (props) => { export const GroupId: Component<RouteSectionProps> = (props) => {
const groupId = () => Number(props.params.groupid); const groupId = () => Number(props.params.groupid);

View file

@ -1,16 +1,14 @@
import { useNavigate, type RouteSectionProps } from "@solidjs/router";
import { createSignal, type JSX, Show, type Component } from "solid-js";
import { Title } from "@solidjs/meta";
import { Portal } from "solid-js/web";
import { Flex } from "~/components/ui/flex";
import { Progress, ProgressLabel, ProgressValueLabel } from "~/components/ui/progress";
import { loadDb } from "~/db";
import { decryptBackup } from "~/lib/decryptor";
import { createDropzone, createFileUploader } from "@solid-primitives/upload"; import { createDropzone, createFileUploader } from "@solid-primitives/upload";
import { Title } from "@solidjs/meta";
import { type RouteSectionProps, useNavigate } from "@solidjs/router";
import { type Component, type JSX, Show, createSignal } from "solid-js";
import { Portal } from "solid-js/web";
import { Button } from "~/components/ui/button"; import { Button } from "~/components/ui/button";
import { Flex } from "~/components/ui/flex";
import { Progress, ProgressLabel, ProgressValueLabel } from "~/components/ui/progress";
import { TextField, TextFieldInput, TextFieldLabel } from "~/components/ui/text-field"; import { TextField, TextFieldInput, TextFieldLabel } from "~/components/ui/text-field";
import { loadDb } from "~/db";
import { decryptBackup } from "~/lib/backup-decryptor";
export const Home: Component<RouteSectionProps> = () => { export const Home: Component<RouteSectionProps> = () => {
const navigate = useNavigate(); const navigate = useNavigate();
@ -34,8 +32,8 @@ export const Home: Component<RouteSectionProps> = () => {
const [backupFile, setBackupFile] = createSignal<File>(); const [backupFile, setBackupFile] = createSignal<File>();
const [decryptionProgress, setDecryptionProgress] = createSignal<number>(); const [decryptionProgress, setDecryptionProgress] = createSignal<number>();
const [loadingProgress, setLoadingProgress] = createSignal<number>(); const [totalStatements, setTotalStatements] = createSignal(0);
// const [isLoadingDatabase, setIsLoadingDatabase] = createSignal(false); const [executedStatements, setExecutedStatements] = createSignal(0);
const onSubmit: JSX.EventHandler<HTMLFormElement, SubmitEvent> = (event) => { const onSubmit: JSX.EventHandler<HTMLFormElement, SubmitEvent> = (event) => {
event.preventDefault(); event.preventDefault();
@ -44,28 +42,22 @@ export const Home: Component<RouteSectionProps> = () => {
const currentPassphrase = passphrase(); const currentPassphrase = passphrase();
if (currentBackupFile && currentPassphrase) { if (currentBackupFile && currentPassphrase) {
// const hashChunk = await currentBackupFile.slice(-1000).text(); console.time();
// const hash = hashString(hashChunk); decryptBackup(currentBackupFile, currentPassphrase, setDecryptionProgress, async (statements) => {
const length = statements.length;
setTotalStatements((oldValue) => oldValue + length);
// if (hash === dbHash()) { await loadDb(statements, (progress) => {
// return; setExecutedStatements((oldValue) => Math.round(oldValue + (progress / 100) * length));
// } });
// setDbHash(hash); setExecutedStatements((oldValue) => oldValue + length);
})
decryptBackup(currentBackupFile, currentPassphrase, setDecryptionProgress) .then(() => {
.then(async (decrypted) => {
umami.track("Decrypt backup"); umami.track("Decrypt backup");
setDecryptionProgress(undefined);
// setIsLoadingDatabase(true);
setLoadingProgress(0);
await loadDb(decrypted.database_statements, setLoadingProgress);
umami.track("Load database"); umami.track("Load database");
// setIsLoadingDatabase(false); console.timeEnd();
setLoadingProgress(undefined);
navigate("/overview"); navigate("/overview");
}) })
.catch((error) => { .catch((error) => {
@ -84,7 +76,7 @@ export const Home: Component<RouteSectionProps> = () => {
class="fixed inset-0 gap-y-8 backdrop-blur-lg backdrop-filter" class="fixed inset-0 gap-y-8 backdrop-blur-lg backdrop-filter"
classList={{ classList={{
// hidden: decryptionProgress() === undefined && !isLoadingDatabase(), // hidden: decryptionProgress() === undefined && !isLoadingDatabase(),
hidden: decryptionProgress() === undefined && loadingProgress() === undefined, hidden: decryptionProgress() === undefined && totalStatements() === 0,
}} }}
> >
<Show when={decryptionProgress() !== undefined}> <Show when={decryptionProgress() !== undefined}>
@ -97,20 +89,18 @@ export const Home: Component<RouteSectionProps> = () => {
class="w-[300px] space-y-1" class="w-[300px] space-y-1"
> >
<div class="flex justify-between"> <div class="flex justify-between">
<ProgressLabel>Processing...</ProgressLabel> <ProgressLabel>Decrypting...</ProgressLabel>
<ProgressValueLabel /> <ProgressValueLabel />
</div> </div>
</Progress> </Progress>
</Show> </Show>
<Show when={loadingProgress() !== undefined}> <Show when={totalStatements() !== 0}>
{/* <p class="font-bold text-2xl">Loading database</p>
<p class="text-muted-foreground">This can take some time</p> */}
<p class="font-bold text-2xl">Loading database</p> <p class="font-bold text-2xl">Loading database</p>
<Progress <Progress
value={loadingProgress()} value={executedStatements()}
minValue={0} minValue={0}
maxValue={100} maxValue={totalStatements()}
getValueLabel={({ value }) => `${value}%`} getValueLabel={({ value, max }) => `${value} of ${max}`}
class="w-[300px] space-y-1" class="w-[300px] space-y-1"
> >
<div class="flex justify-between"> <div class="flex justify-between">

View file

@ -1,9 +1,7 @@
import type { RouteSectionProps } from "@solidjs/router";
import { type Component, createResource, Show } from "solid-js";
import { allThreadsOverviewQuery, overallSentMessagesQuery, SELF_ID } from "~/db";
import { Title } from "@solidjs/meta"; import { Title } from "@solidjs/meta";
import type { RouteSectionProps } from "@solidjs/router";
import { type Component, Show, createResource } from "solid-js";
import { SELF_ID, allThreadsOverviewQuery, overallSentMessagesQuery } from "~/db";
import { getNameFromRecipient } from "~/lib/get-name-from-recipient"; import { getNameFromRecipient } from "~/lib/get-name-from-recipient";
import { OverviewTable, type RoomOverview } from "./overview-table"; import { OverviewTable, type RoomOverview } from "./overview-table";

View file

@ -1,32 +1,29 @@
import { type Component, createSignal, For, Match, Show, Switch } from "solid-js";
import { useNavigate, usePreloadRoute } from "@solidjs/router"; import { useNavigate, usePreloadRoute } from "@solidjs/router";
import { import {
type ColumnFiltersState, type ColumnFiltersState,
type FilterFn,
type SortDirection,
type SortingState,
createColumnHelper, createColumnHelper,
createSolidTable, createSolidTable,
type FilterFn,
flexRender, flexRender,
getCoreRowModel, getCoreRowModel,
getFilteredRowModel, getFilteredRowModel,
getPaginationRowModel, getPaginationRowModel,
getSortedRowModel, getSortedRowModel,
type SortDirection,
type SortingState,
} from "@tanstack/solid-table"; } from "@tanstack/solid-table";
import { intlFormatDistance } from "date-fns"; import { intlFormatDistance } from "date-fns";
import { ArrowDown, ArrowUp, ArrowUpDown } from "lucide-solid"; import { ArrowDown, ArrowUp, ArrowUpDown } from "lucide-solid";
import { type Component, For, Match, Show, Switch, createSignal } from "solid-js";
import { Badge } from "~/components/ui/badge"; import { Badge } from "~/components/ui/badge";
import { Button } from "~/components/ui/button"; import { Button } from "~/components/ui/button";
import { Checkbox } from "~/components/ui/checkbox"; import { Checkbox } from "~/components/ui/checkbox";
import { Flex } from "~/components/ui/flex";
import { Label } from "~/components/ui/label"; import { Label } from "~/components/ui/label";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "~/components/ui/table"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "~/components/ui/table";
import { TextField, TextFieldInput } from "~/components/ui/text-field"; import { TextField, TextFieldInput } from "~/components/ui/text-field";
import { cn } from "~/lib/utils";
import { Flex } from "~/components/ui/flex";
import { dbLoaded, threadSentMessagesOverviewQuery } from "~/db"; import { dbLoaded, threadSentMessagesOverviewQuery } from "~/db";
import { cn } from "~/lib/utils";
export interface RoomOverview { export interface RoomOverview {
threadId: number; threadId: number;

View file

@ -1,8 +1,8 @@
import path from "path"; import path from "path";
import tailwind from "@tailwindcss/vite";
import { defineConfig } from "vite"; import { defineConfig } from "vite";
import solidPlugin from "vite-plugin-solid"; import solidPlugin from "vite-plugin-solid";
import wasm from "vite-plugin-wasm"; import wasm from "vite-plugin-wasm";
import tailwind from "@tailwindcss/vite";
export default defineConfig({ export default defineConfig({
plugins: [solidPlugin(), wasm(), tailwind()], plugins: [solidPlugin(), wasm(), tailwind()],