🔨 Refactor: Add SessionV2 page and features

- Add a new page for sessionv2 with features to load session data, deltas, list of files, prerender flag, and navigation to previous and next session
- Add a sticky header for the timeline and a list of files and entries for the timeline
- Add a link to the v2 page for project session page

[src/routes/projects/[projectId]/sessionv2/[sessionId]/+page.svelte]
- Add a new file for the session page
- Add a function to convert timestamp to column index
- Add a sticky header for the timeline
- Add a list of files for the timeline
- Add a list of entries for the timeline
[src/routes/projects/[projectId]/sessionv2/[sessionId]/+page.ts]
- Add a new page for sessionv2 with the following features:
    - Load session data
    - Load deltas from the backend
    - Load list of files from the backend
    - Add a prerender flag
    - Add a navigation to the previous and next session if available
[src/routes/projects/[projectId]/sessions/[sessionId]/+page.svelte]
- Add link to v2 page for project session page
This commit is contained in:
Kiril Videlov 2023-02-21 00:44:30 +01:00
parent b7677ca75f
commit 1d1c500c63
3 changed files with 230 additions and 0 deletions

View File

@ -73,6 +73,7 @@
nextSession={$nextSession}
previousSesssion={$previousSesssion}
/>
<a href="/projects/{$project?.id}/sessionv2/{$session?.id}">v2</a>
</div>
<div class="overflow-auto h-2/3 mx-4">

View File

@ -0,0 +1,178 @@
<script lang="ts">
import MdKeyboardArrowLeft from "svelte-icons/md/MdKeyboardArrowLeft.svelte";
import MdKeyboardArrowRight from "svelte-icons/md/MdKeyboardArrowRight.svelte";
import type { PageData } from "./$types";
import { add, format, differenceInSeconds } from "date-fns";
import { page } from "$app/stores";
import { fi } from "date-fns/esm/locale";
export let data: PageData;
$: session = data.session;
$: previousSesssion = data.previousSesssion;
$: nextSession = data.nextSession;
$: deltas = data.deltas;
$: start = new Date($session.meta.startTimestampMs);
$: end = new Date($session.meta.lastTimestampMs);
$: midpoint = add(start, {
seconds: differenceInSeconds(end, start) * 0.5,
});
$: quarter = add(start, {
seconds: differenceInSeconds(end, start) * 0.25,
});
$: threequarters = add(start, {
seconds: differenceInSeconds(end, start) * 0.75,
});
const timeStampToCol = (deltaTimestamp: Date) => {
if (deltaTimestamp < start || deltaTimestamp > end) {
console.error(
`Delta timestamp out of session range. Delta timestamp: ${deltaTimestamp}, Session start: ${start}, Session end: ${end}`
);
}
// there are 88 columns
// start is column 17
const totalDiff = differenceInSeconds(end, start);
const eventDiff = differenceInSeconds(deltaTimestamp, start);
const rat = eventDiff / totalDiff;
const col = Math.floor(rat * 63 + 17);
return col;
};
</script>
<div class="flex flex-col h-full text-zinc-400">
<header
class="flex items-center justify-between flex-none px-6 py-4 border-b border-zinc-700"
>
<div class="flex items-center justify-start w-72">
<a
href="/projects/{$page.params
.projectId}/sessionv2/{$previousSesssion?.id}"
class="w-8 h-8 hover:text-zinc-200 {$previousSesssion
? ''
: 'opacity-50 pointer-events-none cursor-not-allowed'}"
>
<MdKeyboardArrowLeft />
</a>
<a
href="/projects/{$page.params
.projectId}/sessionv2/{$nextSession?.id}"
class="w-8 h-8 hover:text-zinc-200 {$nextSession
? ''
: 'opacity-50 pointer-events-none cursor-not-allowed'}"
>
<MdKeyboardArrowRight />
</a>
</div>
</header>
<!-- main part -->
<div class="flex flex-col flex-none max-w-full">
<div class="flex flex-col flex-none max-w-full">
<!-- sticky header -->
<div
class="overflow-hidden sticky top-0 z-30 bg-zinc-800 flex-none shadow shadow-zinc-700 ring-1 ring-zinc-700 ring-opacity-5"
>
<div
class="grid-cols-11 -mr-px text-sm leading-6 border-zinc-700 grid"
>
<div />
<div
class="col-span-2 flex items-center justify-center py-3"
>
<span>{format(start, "hh:mm")}</span>
</div>
<div
class="col-span-2 flex items-center justify-center py-3"
>
<span>{format(quarter, "hh:mm")}</span>
</div>
<div
class="col-span-2 flex items-center justify-center py-3"
>
<span>{format(midpoint, "hh:mm")}</span>
</div>
<div
class="col-span-2 flex items-center justify-center py-3"
>
<span>{format(threequarters, "hh:mm")}</span>
</div>
<div
class="col-span-2 flex items-center justify-center py-3"
>
<span>{format(end, "hh:mm")}</span>
</div>
</div>
</div>
<div class="flex flex-auto">
<!-- <div
class="sticky left-0 z-10 w-14 flex-none ring-1 ring-zinc-700"
/> -->
<div class="grid flex-auto grid-cols-1 grid-rows-1">
<!-- file names list -->
<div
class="col-start-1 col-end-2 row-start-1 grid divide-y divide-zinc-700/20"
style="grid-template-rows: repeat({Object.keys($deltas)
.length}, minmax(2rem, 1fr));"
>
<!-- <div class="row-end-1 h-7" /> -->
{#each Object.keys($deltas) as filePath}
<div
class="flex justify-end items-center overflow-hidden sticky left-0 z-20 w-1/6 pr-4 text-xs leading-5 text-zinc-300"
title={filePath}
>
{filePath.split("/").pop()}
</div>
{/each}
</div>
<!-- time vertical lines -->
<div
class="col-start-1 col-end-2 row-start-1 grid-rows-1 divide-x divide-zinc-700/50 grid grid-cols-11"
>
<div class="col-span-2 row-span-full" />
<div class="col-span-2 row-span-full" />
<div class="col-span-2 row-span-full" />
<div class="col-span-2 row-span-full" />
<div class="col-span-2 row-span-full" />
<div class="col-span-2 row-span-full" />
</div>
<!-- actual entries -->
<ol
class="col-start-1 col-end-2 row-start-1 grid"
style="
grid-template-columns: repeat(88, minmax(0, 1fr));
grid-template-rows: 2rem repeat({Object.keys($deltas)
.length}, minmax(0px, 1fr)) auto;"
>
{#each Object.entries($deltas) as [filePath, fileDeltas], idx}
{#each fileDeltas as delta}
<li
class="relative mt-px flex items-center"
style="
grid-row: {idx + 1} / span 1;
grid-column: {timeStampToCol(
new Date(delta.timestampMs)
)} / span 2;"
>
<a
href="/"
class="group absolute inset-1 flex flex-col items-center justify-center rounded bg-zinc-300 p-px text-xs leading-5 hover:bg-zinc-200 shadow"
>
<p
class="order-1 font-semibold text-zinc-800"
>
<!-- foo -->
</p>
</a>
</li>
{/each}
{/each}
</ol>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,51 @@
import type { PageLoad } from "./$types";
import { derived, readable } from "svelte/store";
import { building } from "$app/environment";
import type { Delta } from "$lib/deltas";
export const prerender = false;
export const load: PageLoad = async ({ parent, params }) => {
const { sessions } = await parent();
const deltas = building
? readable({} as Record<string, Delta[]>)
: (await import("$lib/deltas")).default({
projectId: params.projectId,
sessionId: params.sessionId,
});
const files = building
? ({} as Record<string, string>)
: (await import("$lib/sessions")).listFiles({
projectId: params.projectId,
sessionId: params.sessionId,
});
return {
session: derived(sessions, (sessions) => {
const result = sessions.find(
(session) => session.id === params.sessionId
);
return result ? result : sessions[0];
}),
previousSesssion: derived(sessions, (sessions) => {
const currentSessionIndex = sessions.findIndex(
(session) => session.id === params.sessionId
);
if (currentSessionIndex - 1 < sessions.length) {
return sessions[currentSessionIndex - 1];
} else {
return undefined;
}
}),
nextSession: derived(sessions, (sessions) => {
const currentSessionIndex = sessions.findIndex(
(session) => session.id === params.sessionId
);
if (currentSessionIndex + 1 < sessions.length) {
return sessions[currentSessionIndex + 1];
} else {
return undefined;
}
}),
files: files,
deltas: deltas,
}
}