From b507c13b3b8f4fbdf76661f14bd3719ac54ca02a Mon Sep 17 00:00:00 2001 From: TuTiDore Date: Tue, 16 Dec 2025 18:54:08 -0800 Subject: [PATCH 1/5] feat: add shocker logs page fix: wording Co-authored-by: LucHeart Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../ClassicControlModule.svelte | 8 ++- .../ControlModules/impl/ShockerMenu.svelte | 31 +++++++++ src/lib/stores/ShockerLogStore.ts | 33 +++++++++ .../logs/[shockerId=guid]/+page.svelte | 68 +++++++++++++++++++ 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 src/lib/components/ControlModules/impl/ShockerMenu.svelte create mode 100644 src/lib/stores/ShockerLogStore.ts create mode 100644 src/routes/(authenticated)/shockers/logs/[shockerId=guid]/+page.svelte diff --git a/src/lib/components/ControlModules/ClassicControlModule.svelte b/src/lib/components/ControlModules/ClassicControlModule.svelte index 38063731..78d38a19 100644 --- a/src/lib/components/ControlModules/ClassicControlModule.svelte +++ b/src/lib/components/ControlModules/ClassicControlModule.svelte @@ -12,6 +12,7 @@ import ControlListener from './ControlListener.svelte'; import ActionButtons from './impl/ActionButtons.svelte'; import CircleSlider from './impl/CircleSlider.svelte'; + import ShockerMenu from './impl/ShockerMenu.svelte'; interface Props { shocker: ShockerResponse; @@ -36,7 +37,12 @@ class="border-surface-400-500-token flex flex-col items-center justify-center gap-2 overflow-hidden rounded-md border p-2" > -

{shocker.name}

+

+ + {shocker.name} + + +

diff --git a/src/lib/components/ControlModules/impl/ShockerMenu.svelte b/src/lib/components/ControlModules/impl/ShockerMenu.svelte new file mode 100644 index 00000000..7c2ecce5 --- /dev/null +++ b/src/lib/components/ControlModules/impl/ShockerMenu.svelte @@ -0,0 +1,31 @@ + + + + + {#snippet child({ props })} + + {/snippet} + + + View Logs + + diff --git a/src/lib/stores/ShockerLogStore.ts b/src/lib/stores/ShockerLogStore.ts new file mode 100644 index 00000000..784cce71 --- /dev/null +++ b/src/lib/stores/ShockerLogStore.ts @@ -0,0 +1,33 @@ +import { shockersV1Api } from '$lib/api'; +import { type LogEntry } from '$lib/api/internal/v1'; +import { handleApiError } from '$lib/errorhandling/apiErrorHandling'; +import { writable } from 'svelte/store'; + +export const ShockerLogStore = writable>(new Map()); + +export function fetchLogsForShocker(shockerId: string) { + shockersV1Api + .shockerGetShockerLogs(shockerId) + .then((response) => { + if (!response.data) { + throw new Error(`Failed to fetch logs: ${response.message}`); + } + + const grouped = response.data.reduce((acc, entry) => { + if (!acc.has(entry.id)) { + acc.set(entry.id, []); + } + acc.get(entry.id)!.push({ + id: entry.id, + createdOn: new Date(entry.createdOn), + type: entry.type, + controlledBy: entry.controlledBy, + intensity: entry.intensity, + duration: entry.duration, + }); + return acc; + }, new Map()); + ShockerLogStore.set(grouped); + }) + .catch(handleApiError); +} diff --git a/src/routes/(authenticated)/shockers/logs/[shockerId=guid]/+page.svelte b/src/routes/(authenticated)/shockers/logs/[shockerId=guid]/+page.svelte new file mode 100644 index 00000000..eb3ab20a --- /dev/null +++ b/src/routes/(authenticated)/shockers/logs/[shockerId=guid]/+page.svelte @@ -0,0 +1,68 @@ + + + + + +
+ Shocker Logs +
+
+ +
+
+ These are the logs for the specified shocker. +
+
+ +
+
From 8ee8a8dabd483fad6b73e8babb28d0f09cf7722f Mon Sep 17 00:00:00 2001 From: TuTiDore Date: Sat, 20 Dec 2025 15:25:06 -0800 Subject: [PATCH 2/5] fix: remove store, use load function --- .../ClassicControlModule.svelte | 2 +- src/lib/stores/ShockerLogStore.ts | 33 ----------------- .../logs/[shockerId=guid]/+page.svelte | 37 +++---------------- .../shockers/logs/[shockerId=guid]/+page.ts | 15 ++++++++ 4 files changed, 21 insertions(+), 66 deletions(-) delete mode 100644 src/lib/stores/ShockerLogStore.ts create mode 100644 src/routes/(authenticated)/shockers/logs/[shockerId=guid]/+page.ts diff --git a/src/lib/components/ControlModules/ClassicControlModule.svelte b/src/lib/components/ControlModules/ClassicControlModule.svelte index 78d38a19..d99517aa 100644 --- a/src/lib/components/ControlModules/ClassicControlModule.svelte +++ b/src/lib/components/ControlModules/ClassicControlModule.svelte @@ -37,7 +37,7 @@ class="border-surface-400-500-token flex flex-col items-center justify-center gap-2 overflow-hidden rounded-md border p-2" > -

+

{shocker.name} diff --git a/src/lib/stores/ShockerLogStore.ts b/src/lib/stores/ShockerLogStore.ts deleted file mode 100644 index 784cce71..00000000 --- a/src/lib/stores/ShockerLogStore.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { shockersV1Api } from '$lib/api'; -import { type LogEntry } from '$lib/api/internal/v1'; -import { handleApiError } from '$lib/errorhandling/apiErrorHandling'; -import { writable } from 'svelte/store'; - -export const ShockerLogStore = writable>(new Map()); - -export function fetchLogsForShocker(shockerId: string) { - shockersV1Api - .shockerGetShockerLogs(shockerId) - .then((response) => { - if (!response.data) { - throw new Error(`Failed to fetch logs: ${response.message}`); - } - - const grouped = response.data.reduce((acc, entry) => { - if (!acc.has(entry.id)) { - acc.set(entry.id, []); - } - acc.get(entry.id)!.push({ - id: entry.id, - createdOn: new Date(entry.createdOn), - type: entry.type, - controlledBy: entry.controlledBy, - intensity: entry.intensity, - duration: entry.duration, - }); - return acc; - }, new Map()); - ShockerLogStore.set(grouped); - }) - .catch(handleApiError); -} diff --git a/src/routes/(authenticated)/shockers/logs/[shockerId=guid]/+page.svelte b/src/routes/(authenticated)/shockers/logs/[shockerId=guid]/+page.svelte index eb3ab20a..43f67d58 100644 --- a/src/routes/(authenticated)/shockers/logs/[shockerId=guid]/+page.svelte +++ b/src/routes/(authenticated)/shockers/logs/[shockerId=guid]/+page.svelte @@ -1,30 +1,17 @@ @@ -54,15 +30,12 @@
Shocker Logs
-
- -
- These are the logs for the specified shocker. + + These are the logs for {data.shocker?.name}. +
- +
diff --git a/src/routes/(authenticated)/shockers/logs/[shockerId=guid]/+page.ts b/src/routes/(authenticated)/shockers/logs/[shockerId=guid]/+page.ts new file mode 100644 index 00000000..8ef7d414 --- /dev/null +++ b/src/routes/(authenticated)/shockers/logs/[shockerId=guid]/+page.ts @@ -0,0 +1,15 @@ +import { shockersV1Api } from '$lib/api'; +import { handleApiError } from '$lib/errorhandling/apiErrorHandling.js'; + +export async function load({ params }) { + try { + const shockerId = params.shockerId; + const logsPromise = shockersV1Api.shockerGetShockerLogs(shockerId); + const shockerPromise = shockersV1Api.shockerGetShockerById(shockerId); + const [logsRes, shockerRes] = await Promise.all([logsPromise, shockerPromise]); + return { logs: logsRes.data ?? [], shocker: shockerRes.data }; + } catch (err) { + handleApiError(err); + return { logs: [] }; + } +} From cf2b94cb83d62e9ff55feca783e9068e8282ca80 Mon Sep 17 00:00:00 2001 From: TuTiDore Date: Sat, 20 Dec 2025 15:26:51 -0800 Subject: [PATCH 3/5] feat: add /shockers/logs page --- .../(authenticated)/shockers/+page.svelte | 5 ++- .../shockers/logs/+page.svelte | 41 +++++++++++++++++++ .../(authenticated)/shockers/logs/+page.ts | 34 +++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 src/routes/(authenticated)/shockers/logs/+page.svelte create mode 100644 src/routes/(authenticated)/shockers/logs/+page.ts diff --git a/src/routes/(authenticated)/shockers/+page.svelte b/src/routes/(authenticated)/shockers/+page.svelte index c9897e91..a29122fc 100644 --- a/src/routes/(authenticated)/shockers/+page.svelte +++ b/src/routes/(authenticated)/shockers/+page.svelte @@ -1,5 +1,5 @@ + + + + +
+ Shocker Logs +
+
+ These are the logs for all shockers. +
+
+ +
+
diff --git a/src/routes/(authenticated)/shockers/logs/+page.ts b/src/routes/(authenticated)/shockers/logs/+page.ts new file mode 100644 index 00000000..94dac408 --- /dev/null +++ b/src/routes/(authenticated)/shockers/logs/+page.ts @@ -0,0 +1,34 @@ +import { shockersV1Api } from '$lib/api'; +import type { LogEntry } from '$lib/api/internal/v1'; +import { handleApiError } from '$lib/errorhandling/apiErrorHandling.js'; + +export type ShockerLogEntry = LogEntry & { + hubName: string; + shockerName: string; +}; + +export async function load(): Promise<{ logs: ShockerLogEntry[] }> { + try { + // TODO create a V2 endpoint that gets logs for all shockers in one call + const { data: hubs } = await shockersV1Api.shockerListShockers(); + if (!hubs) { + return { logs: [] }; + } + const logPromises = + hubs.flatMap((hub) => + hub.shockers?.map((shocker) => + shockersV1Api + .shockerGetShockerLogs(shocker.id!) + .then((res) => ({ hubName: hub.name, shockerName: shocker.name, data: res.data ?? [] })) + ) + ) ?? []; + const logResponses = await Promise.all(logPromises); + const allLogs = logResponses.flatMap((res) => + res.data.map((log) => ({ ...log, hubName: res.hubName, shockerName: res.shockerName })) + ); + return { logs: allLogs ?? [] }; + } catch (err) { + handleApiError(err); + return { logs: [] }; + } +} From 7ea7534ad7594080fb25e59907a376d9196af109 Mon Sep 17 00:00:00 2001 From: TuTiDore Date: Sun, 21 Dec 2025 19:43:33 -0800 Subject: [PATCH 4/5] chore: update OpenApi client --- .../api/internal/v1/.openapi-generator/FILES | 2 + src/lib/api/internal/v1/apis/ShockersApi.ts | 65 +++++++ .../api/internal/v1/models/LogEntryWithHub.ts | 164 ++++++++++++++++++ .../internal/v1/models/ShockerLogsResponse.ts | 74 ++++++++ src/lib/api/internal/v1/models/index.ts | 2 + 5 files changed, 307 insertions(+) create mode 100644 src/lib/api/internal/v1/models/LogEntryWithHub.ts create mode 100644 src/lib/api/internal/v1/models/ShockerLogsResponse.ts diff --git a/src/lib/api/internal/v1/.openapi-generator/FILES b/src/lib/api/internal/v1/.openapi-generator/FILES index cd594153..e69d8dbd 100644 --- a/src/lib/api/internal/v1/.openapi-generator/FILES +++ b/src/lib/api/internal/v1/.openapi-generator/FILES @@ -47,6 +47,7 @@ models/LcgResponseLegacyDataResponse.ts models/LegacyEmptyResponse.ts models/LogEntry.ts models/LogEntryArrayLegacyDataResponse.ts +models/LogEntryWithHub.ts models/Login.ts models/LoginSessionResponse.ts models/MatchTypeEnum.ts @@ -89,6 +90,7 @@ models/ShareInfoArrayLegacyDataResponse.ts models/SharedDevice.ts models/SharedShocker.ts models/ShockerLimits.ts +models/ShockerLogsResponse.ts models/ShockerModelType.ts models/ShockerPermLimitPair.ts models/ShockerPermissions.ts diff --git a/src/lib/api/internal/v1/apis/ShockersApi.ts b/src/lib/api/internal/v1/apis/ShockersApi.ts index c653f108..d507eed6 100644 --- a/src/lib/api/internal/v1/apis/ShockersApi.ts +++ b/src/lib/api/internal/v1/apis/ShockersApi.ts @@ -27,6 +27,7 @@ import type { ResponseDeviceWithShockersArrayLegacyDataResponse, ShareCodeInfoArrayLegacyDataResponse, ShareInfoArrayLegacyDataResponse, + ShockerLogsResponse, ShockerPermLimitPair, ShockerWithDeviceLegacyDataResponse, } from '../models/index'; @@ -55,6 +56,8 @@ import { ShareCodeInfoArrayLegacyDataResponseToJSON, ShareInfoArrayLegacyDataResponseFromJSON, ShareInfoArrayLegacyDataResponseToJSON, + ShockerLogsResponseFromJSON, + ShockerLogsResponseToJSON, ShockerPermLimitPairFromJSON, ShockerPermLimitPairToJSON, ShockerWithDeviceLegacyDataResponseFromJSON, @@ -66,6 +69,11 @@ export interface ShockerEditShockerRequest { newShocker?: NewShocker; } +export interface ShockerGetAllShockerLogsRequest { + offset?: number; + limit?: number; +} + export interface ShockerGetShockerByIdRequest { shockerId: string; } @@ -146,6 +154,22 @@ export interface ShockersApiInterface { */ shockerEditShocker(shockerId: string, newShocker?: NewShocker, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise; + /** + * + * @summary Get the logs for all shockers + * @param {number} [offset] + * @param {number} [limit] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ShockersApiInterface + */ + shockerGetAllShockerLogsRaw(requestParameters: ShockerGetAllShockerLogsRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise>; + + /** + * Get the logs for all shockers + */ + shockerGetAllShockerLogs(offset?: number, limit?: number, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise; + /** * * @summary Get information about a shocker. @@ -414,6 +438,47 @@ export class ShockersApi extends runtime.BaseAPI implements ShockersApiInterface return await response.value(); } + /** + * Get the logs for all shockers + */ + async shockerGetAllShockerLogsRaw(requestParameters: ShockerGetAllShockerLogsRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { + const queryParameters: any = {}; + + if (requestParameters['offset'] != null) { + queryParameters['offset'] = requestParameters['offset']; + } + + if (requestParameters['limit'] != null) { + queryParameters['limit'] = requestParameters['limit']; + } + + const headerParameters: runtime.HTTPHeaders = {}; + + if (this.configuration && this.configuration.apiKey) { + headerParameters["OpenShockToken"] = await this.configuration.apiKey("OpenShockToken"); // ApiToken authentication + } + + + let urlPath = `/1/shockers/logs`; + + const response = await this.request({ + path: urlPath, + method: 'GET', + headers: headerParameters, + query: queryParameters, + }, initOverrides); + + return new runtime.JSONApiResponse(response, (jsonValue) => ShockerLogsResponseFromJSON(jsonValue)); + } + + /** + * Get the logs for all shockers + */ + async shockerGetAllShockerLogs(offset?: number, limit?: number, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { + const response = await this.shockerGetAllShockerLogsRaw({ offset: offset, limit: limit }, initOverrides); + return await response.value(); + } + /** * Get information about a shocker. */ diff --git a/src/lib/api/internal/v1/models/LogEntryWithHub.ts b/src/lib/api/internal/v1/models/LogEntryWithHub.ts new file mode 100644 index 00000000..94e80491 --- /dev/null +++ b/src/lib/api/internal/v1/models/LogEntryWithHub.ts @@ -0,0 +1,164 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * OpenShock.API + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { ControlType } from './ControlType'; +import { + ControlTypeFromJSON, + ControlTypeFromJSONTyped, + ControlTypeToJSON, + ControlTypeToJSONTyped, +} from './ControlType'; +import type { ControlLogSenderLight } from './ControlLogSenderLight'; +import { + ControlLogSenderLightFromJSON, + ControlLogSenderLightFromJSONTyped, + ControlLogSenderLightToJSON, + ControlLogSenderLightToJSONTyped, +} from './ControlLogSenderLight'; + +/** + * + * @export + * @interface LogEntryWithHub + */ +export interface LogEntryWithHub { + /** + * + * @type {string} + * @memberof LogEntryWithHub + */ + id: string; + /** + * + * @type {string} + * @memberof LogEntryWithHub + */ + hubId: string; + /** + * + * @type {string} + * @memberof LogEntryWithHub + */ + hubName: string; + /** + * + * @type {string} + * @memberof LogEntryWithHub + */ + shockerId: string; + /** + * + * @type {string} + * @memberof LogEntryWithHub + */ + shockerName: string; + /** + * + * @type {Date} + * @memberof LogEntryWithHub + */ + createdOn: Date; + /** + * + * @type {ControlType} + * @memberof LogEntryWithHub + */ + type: ControlType; + /** + * + * @type {ControlLogSenderLight} + * @memberof LogEntryWithHub + */ + controlledBy: ControlLogSenderLight; + /** + * + * @type {number} + * @memberof LogEntryWithHub + */ + intensity: number; + /** + * + * @type {number} + * @memberof LogEntryWithHub + */ + duration: number; +} + + + +/** + * Check if a given object implements the LogEntryWithHub interface. + */ +export function instanceOfLogEntryWithHub(value: object): value is LogEntryWithHub { + if (!('id' in value) || value['id'] === undefined) return false; + if (!('hubId' in value) || value['hubId'] === undefined) return false; + if (!('hubName' in value) || value['hubName'] === undefined) return false; + if (!('shockerId' in value) || value['shockerId'] === undefined) return false; + if (!('shockerName' in value) || value['shockerName'] === undefined) return false; + if (!('createdOn' in value) || value['createdOn'] === undefined) return false; + if (!('type' in value) || value['type'] === undefined) return false; + if (!('controlledBy' in value) || value['controlledBy'] === undefined) return false; + if (!('intensity' in value) || value['intensity'] === undefined) return false; + if (!('duration' in value) || value['duration'] === undefined) return false; + return true; +} + +export function LogEntryWithHubFromJSON(json: any): LogEntryWithHub { + return LogEntryWithHubFromJSONTyped(json, false); +} + +export function LogEntryWithHubFromJSONTyped(json: any, ignoreDiscriminator: boolean): LogEntryWithHub { + if (json == null) { + return json; + } + return { + + 'id': json['id'], + 'hubId': json['hubId'], + 'hubName': json['hubName'], + 'shockerId': json['shockerId'], + 'shockerName': json['shockerName'], + 'createdOn': (new Date(json['createdOn'])), + 'type': ControlTypeFromJSON(json['type']), + 'controlledBy': ControlLogSenderLightFromJSON(json['controlledBy']), + 'intensity': json['intensity'], + 'duration': json['duration'], + }; +} + +export function LogEntryWithHubToJSON(json: any): LogEntryWithHub { + return LogEntryWithHubToJSONTyped(json, false); +} + +export function LogEntryWithHubToJSONTyped(value?: LogEntryWithHub | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + + 'id': value['id'], + 'hubId': value['hubId'], + 'hubName': value['hubName'], + 'shockerId': value['shockerId'], + 'shockerName': value['shockerName'], + 'createdOn': value['createdOn'].toISOString(), + 'type': ControlTypeToJSON(value['type']), + 'controlledBy': ControlLogSenderLightToJSON(value['controlledBy']), + 'intensity': value['intensity'], + 'duration': value['duration'], + }; +} + diff --git a/src/lib/api/internal/v1/models/ShockerLogsResponse.ts b/src/lib/api/internal/v1/models/ShockerLogsResponse.ts new file mode 100644 index 00000000..b7f712bb --- /dev/null +++ b/src/lib/api/internal/v1/models/ShockerLogsResponse.ts @@ -0,0 +1,74 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * OpenShock.API + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { LogEntryWithHub } from './LogEntryWithHub'; +import { + LogEntryWithHubFromJSON, + LogEntryWithHubFromJSONTyped, + LogEntryWithHubToJSON, + LogEntryWithHubToJSONTyped, +} from './LogEntryWithHub'; + +/** + * + * @export + * @interface ShockerLogsResponse + */ +export interface ShockerLogsResponse { + /** + * + * @type {Array} + * @memberof ShockerLogsResponse + */ + logs: Array; +} + +/** + * Check if a given object implements the ShockerLogsResponse interface. + */ +export function instanceOfShockerLogsResponse(value: object): value is ShockerLogsResponse { + if (!('logs' in value) || value['logs'] === undefined) return false; + return true; +} + +export function ShockerLogsResponseFromJSON(json: any): ShockerLogsResponse { + return ShockerLogsResponseFromJSONTyped(json, false); +} + +export function ShockerLogsResponseFromJSONTyped(json: any, ignoreDiscriminator: boolean): ShockerLogsResponse { + if (json == null) { + return json; + } + return { + + 'logs': ((json['logs'] as Array).map(LogEntryWithHubFromJSON)), + }; +} + +export function ShockerLogsResponseToJSON(json: any): ShockerLogsResponse { + return ShockerLogsResponseToJSONTyped(json, false); +} + +export function ShockerLogsResponseToJSONTyped(value?: ShockerLogsResponse | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + + 'logs': ((value['logs'] as Array).map(LogEntryWithHubToJSON)), + }; +} + diff --git a/src/lib/api/internal/v1/models/index.ts b/src/lib/api/internal/v1/models/index.ts index fb535bf4..5bc5ee12 100644 --- a/src/lib/api/internal/v1/models/index.ts +++ b/src/lib/api/internal/v1/models/index.ts @@ -35,6 +35,7 @@ export * from './LcgResponseLegacyDataResponse'; export * from './LegacyEmptyResponse'; export * from './LogEntry'; export * from './LogEntryArrayLegacyDataResponse'; +export * from './LogEntryWithHub'; export * from './Login'; export * from './LoginSessionResponse'; export * from './MatchTypeEnum'; @@ -77,6 +78,7 @@ export * from './ShareInfoArrayLegacyDataResponse'; export * from './SharedDevice'; export * from './SharedShocker'; export * from './ShockerLimits'; +export * from './ShockerLogsResponse'; export * from './ShockerModelType'; export * from './ShockerPermLimitPair'; export * from './ShockerPermissions'; From 10805593fccf9b46e39f826adfdab0404f0f0e9f Mon Sep 17 00:00:00 2001 From: TuTiDore Date: Sun, 21 Dec 2025 19:44:19 -0800 Subject: [PATCH 5/5] fix: use new v1 /shockers/logs endpoint --- .../shockers/logs/+page.svelte | 4 +-- .../(authenticated)/shockers/logs/+page.ts | 28 ++----------------- 2 files changed, 5 insertions(+), 27 deletions(-) diff --git a/src/routes/(authenticated)/shockers/logs/+page.svelte b/src/routes/(authenticated)/shockers/logs/+page.svelte index cf357542..a5acf4f9 100644 --- a/src/routes/(authenticated)/shockers/logs/+page.svelte +++ b/src/routes/(authenticated)/shockers/logs/+page.svelte @@ -1,5 +1,6 @@