checkpoint ISAC registries and system monitoring
This commit is contained in:
@@ -5,7 +5,7 @@ import { requireDataView, requirePermission } from '$lib/server/auth/authorizati
|
||||
import { getSessionUser } from '$lib/server/auth/session';
|
||||
import { getDatabase } from '$lib/server/database';
|
||||
import { recordIsacAudit } from '$lib/server/audit';
|
||||
import { getPagination, getRegistrySearch } from '$lib/server/pagination';
|
||||
import { getPagination, getRegistrySearch, getRegistrySort } from '$lib/server/pagination';
|
||||
import { parseLoadoutDraft } from '$lib/builder/loadout';
|
||||
|
||||
const operators = new Set([
|
||||
@@ -62,6 +62,24 @@ export const load: PageServerLoad = async ({ cookies, url }) => {
|
||||
await requireDataView(await getSessionUser(cookies));
|
||||
const database = await getDatabase();
|
||||
const { search, pattern } = getRegistrySearch(url);
|
||||
const observationCount = `((calibration.body_hit IS NOT NULL) + (calibration.critical_body_hit IS NOT NULL)
|
||||
+ (calibration.headshot IS NOT NULL) + (calibration.critical_headshot IS NOT NULL)
|
||||
+ (calibration.magazine_seconds IS NOT NULL) + (calibration.reload_seconds IS NOT NULL))`;
|
||||
const sort = getRegistrySort(url, {
|
||||
name: { asc: 'calibration.name COLLATE NOCASE ASC', desc: 'calibration.name COLLATE NOCASE DESC' },
|
||||
weapon: { asc: 'calibration.selected_weapon ASC', desc: 'calibration.selected_weapon DESC' },
|
||||
observations: {
|
||||
asc: `${observationCount} ASC`,
|
||||
desc: `${observationCount} DESC`,
|
||||
defaultDirection: 'desc'
|
||||
},
|
||||
prediction: {
|
||||
asc: '(calibration.predicted_json IS NOT NULL) ASC',
|
||||
desc: '(calibration.predicted_json IS NOT NULL) DESC',
|
||||
defaultDirection: 'desc'
|
||||
},
|
||||
state: { asc: 'calibration.status COLLATE NOCASE ASC', desc: 'calibration.status COLLATE NOCASE DESC' }
|
||||
}, 'name');
|
||||
const where = search ? "WHERE calibration.name LIKE ? ESCAPE '\\' COLLATE NOCASE" : '';
|
||||
const args = search ? [pattern] : [];
|
||||
const total = Number((await (await database.prepare(
|
||||
@@ -77,7 +95,7 @@ export const load: PageServerLoad = async ({ cookies, url }) => {
|
||||
FROM calculation_calibration_cases calibration
|
||||
LEFT JOIN users user ON user.id=calibration.created_by
|
||||
LEFT JOIN user_profiles profile ON profile.user_id=user.id
|
||||
${where} ORDER BY calibration.updated_at DESC LIMIT ? OFFSET ?`
|
||||
${where} ORDER BY ${sort.orderBy},calibration.name COLLATE NOCASE,calibration.id LIMIT ? OFFSET ?`
|
||||
)).all(...args, pagination.perPage, pagination.offset),
|
||||
(await database.prepare(`SELECT COUNT(*) AS total,
|
||||
SUM(CASE WHEN status='ready' THEN 1 ELSE 0 END) AS ready,
|
||||
@@ -95,7 +113,8 @@ export const load: PageServerLoad = async ({ cookies, url }) => {
|
||||
calibrationCases,
|
||||
calibrationSummary,
|
||||
pagination,
|
||||
search
|
||||
search,
|
||||
sort
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<script lang="ts">
|
||||
import PendingForm from '$lib/components/PendingForm.svelte';
|
||||
import RegistryInlineEditor from '$lib/components/RegistryInlineEditor.svelte';
|
||||
import RegistryPagination from '$lib/components/RegistryPagination.svelte';
|
||||
import SortableColumnHeader from '$lib/components/SortableColumnHeader.svelte';
|
||||
import SearchableAssignment from '$lib/components/SearchableAssignment.svelte';
|
||||
import SegmentedChoice from '$lib/components/SegmentedChoice.svelte';
|
||||
import { createDraft } from '$lib/builder/loadout';
|
||||
@@ -186,6 +188,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#snippet calibrationEditor()}
|
||||
{#if calibrationEditing}
|
||||
<div class="dashboard-editor calibration-editor">
|
||||
<div class="editor-title"><div><p class="eyebrow">{calibrationEditing.id ? 'MODIFY CALIBRATION CASE' : 'NEW CALIBRATION CASE'}</p><h3>{calibrationEditing.name || 'FIELD OBSERVATION'}</h3></div><button aria-label="Close calibration editor" onclick={() => calibrationEditing = null}>×</button></div>
|
||||
@@ -209,6 +212,11 @@
|
||||
</PendingForm>
|
||||
</div>
|
||||
{/if}
|
||||
{/snippet}
|
||||
|
||||
{#if calibrationEditing && !calibrationEditing.id}
|
||||
{@render calibrationEditor()}
|
||||
{/if}
|
||||
|
||||
<div class="calculation-revision-registry">
|
||||
<div class="selection-head"><div><span>CALCULATION REVISIONS</span><small>SAVED BUILDS USE THE ACTIVE REVISION</small></div><PendingForm action="?/suggestRevision">{#snippet children(pending)}<button class="secondary" disabled={pending}>{pending ? 'ANALYZING…' : 'GENERATE ASSISTED SUGGESTION'}</button>{/snippet}</PendingForm></div>
|
||||
@@ -232,9 +240,14 @@
|
||||
<div class="selection-head"><div><span>CALIBRATION REGISTRY</span><small>OBSERVED GAME VALUES + MODEL COMPARISON</small></div><b>{Number(data.calibrationSummary?.total ?? 0)} CASES</b></div>
|
||||
<RegistryPagination pagination={data.pagination} search={data.search}/>
|
||||
<div class="dashboard-table">
|
||||
<div class="dashboard-row calibration-row table-heading"><span>CASE</span><span>WEAPON</span><span>OBSERVATIONS</span><span>PREDICTION</span><span>STATE</span><span></span></div>
|
||||
<div class="dashboard-row calibration-row table-heading"><SortableColumnHeader label="CASE" column="name" sort={data.sort}/><SortableColumnHeader label="WEAPON" column="weapon" sort={data.sort}/><SortableColumnHeader label="OBSERVATIONS" column="observations" sort={data.sort} defaultDirection="desc"/><SortableColumnHeader label="PREDICTION" column="prediction" sort={data.sort} defaultDirection="desc"/><SortableColumnHeader label="STATE" column="state" sort={data.sort}/><span></span></div>
|
||||
{#each data.calibrationCases as item}
|
||||
<div class="dashboard-row calibration-row"><div><strong>{item.name}</strong><small>{item.game_version || 'GAME VERSION NOT RECORDED'} · {item.creator_name}</small></div><span>{Number(item.selected_weapon) === 0 ? 'PRIMARY' : 'SECONDARY'}</span><span>{[item.body_hit,item.critical_body_hit,item.headshot,item.critical_headshot,item.magazine_seconds,item.reload_seconds].filter((value) => value !== null).length} / 6 CORE</span><span>{item.predicted_json ? 'AVAILABLE' : 'INSUFFICIENT DATA'}</span><b class:configured={item.status === 'ready'} class="state-dot">{item.status.toUpperCase()}</b><button onclick={() => calibrationEditing = calibrationFrom(item)}>EDIT →</button></div>
|
||||
<div class="dashboard-row calibration-row" class:registry-row-editing={String(calibrationEditing?.id ?? '') === String(item.id)}><div><strong>{item.name}</strong><small>{item.game_version || 'GAME VERSION NOT RECORDED'} · {item.creator_name}</small></div><span>{Number(item.selected_weapon) === 0 ? 'PRIMARY' : 'SECONDARY'}</span><span>{[item.body_hit,item.critical_body_hit,item.headshot,item.critical_headshot,item.magazine_seconds,item.reload_seconds].filter((value) => value !== null).length} / 6 CORE</span><span>{item.predicted_json ? 'AVAILABLE' : 'INSUFFICIENT DATA'}</span><b class:configured={item.status === 'ready'} class="state-dot">{item.status.toUpperCase()}</b><button aria-expanded={String(calibrationEditing?.id ?? '') === String(item.id)} aria-controls={`calibration-editor-${item.id}`} onclick={() => calibrationEditing = calibrationFrom(item)}>EDIT →</button></div>
|
||||
{#if String(calibrationEditing?.id ?? '') === String(item.id)}
|
||||
<RegistryInlineEditor id={`calibration-editor-${item.id}`} label={`Edit ${item.name}`}>
|
||||
{@render calibrationEditor()}
|
||||
</RegistryInlineEditor>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user