You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
5.0 KiB

<script lang="ts">
import { navigate } from "svelte-routing";
import { getUnixTime, sub } from "date-fns";
import { buildQueryParams, fromUnixTimeSafe } from "../api/util";
import { getLogs, getStats, LogPayload, StatSearchKey } from "../api";
import type { Stat, Log } from "../api";
import PageContainer from "./PageContainer.svelte";
import SearchOptions from "../components/SearchOptions.svelte";
import TimeChart from "../components/TimeChart.svelte";
import LogViewer from "../components/LogViewer.svelte";
export let location: Location;
const { search } = location;
let params = new URLSearchParams(search.substring(1));
const aggKey = params.get("key");
const fixed = aggKey
? aggKey[0].toUpperCase() + aggKey.substr(1)
: "Domain";
let start: Date =
fromUnixTimeSafe(params.get("start")) || sub(new Date(), { hours: 24 });
let end: Date = fromUnixTimeSafe(params.get("end")) || null;
let filter: string = params.get("filter") || "";
let chartKey: StatSearchKey = StatSearchKey[fixed] || StatSearchKey.Domain;
let chartInterval: number = 30;
let page: number = Number(params.get("page") || 0);
let chartData: Stat = null;
let chartErrorMsg: string = null;
let chartDataLoading: Boolean = false;
let logs: Log[] = [];
let logErrorMsg: string = null;
let logDataLoading: Boolean = false;
let pageSize: number = Number(params.get("pageSize") || 25);
let pageCount: number = 0;
let logCount: number = 0;
const fetchLogs = async () => {
if (logDataLoading) {
console.warn("tried loading logs while already loading");
return;
}
logErrorMsg = null;
logDataLoading = true;
const { error, payload } = await getLogs({
start,
end,
page,
pageSize,
filter,
});
logDataLoading = false;
if (error) {
logErrorMsg = error;
return new LogPayload();
}
return payload;
};
const fetchStats = async (): Promise<Stat> => {
if (chartDataLoading) {
console.warn("tried loading stats while already loading");
return;
}
chartErrorMsg = null;
chartDataLoading = true;
const { error, payload } = await getStats({
start,
end,
key: chartKey,
interval: chartInterval,
});
chartDataLoading = false;
if (error) {
chartErrorMsg = error;
return null;
}
return payload;
};
let done = true;
const updateData = async (evt) => {
if (chartDataLoading || logDataLoading || !done) {
console.debug("SKIPPED DATA FETCH");
return;
}
console.groupCollapsed("Stats Data Update");
const {
filter: eFilter,
start: eStart,
end: eEnd,
key: eKey,
page: ePage,
pageSize: eps,
} = evt;
console.debug("handled search, fetching new data:", evt);
console.groupEnd();
let truePage =
logCount <= pageSize * page ? 0 : ePage === 0 ? null : ePage;
if (logCount <= pageSize * page) {
console.warn(
"adjusting log page because logCount is too small for current settings"
);
page = 0;
}
navigate(
`${location?.pathname}${buildQueryParams({
start: eStart ? getUnixTime(eStart) : null,
end: eEnd ? getUnixTime(eEnd) : null,
filter: eFilter === "" ? eFilter : null,
key: eKey !== "domain" ? eKey : null,
page: truePage,
pageSize: eps && eps !== 25 ? eps : null,
})}`,
{ replace: true }
);
[{ page, total: logCount, pageCount, pageSize, logs }, chartData] =
await Promise.all([fetchLogs(), fetchStats()]);
done = true;
};
$: updateData({ start, end, key: chartKey, filter, pageSize, page });
</script>
<PageContainer
{location}
header="Stats"
description="Server performance stats and activity log"
>
<SearchOptions bind:start bind:end bind:filter bind:key={chartKey} />
<section style="height: 384px;" class="my-5">
{#if chartDataLoading}
<p>Loading chart</p>
{:else if chartErrorMsg}
<p>{chartErrorMsg}</p>
{:else}
<TimeChart stats={chartData} column={chartKey} />
{/if}
</section>
<section class="my-5">
{#if logDataLoading}
<p>Loading logs</p>
{:else if logErrorMsg}
<p>{logErrorMsg}</p>
{:else}
<LogViewer
pages={pageCount}
total={logCount}
{logs}
bind:page
bind:pageSize
/>
{/if}
</section>
</PageContainer>