Add frontend boot diagnostics
This commit is contained in:
@@ -53,6 +53,7 @@ export interface SpootyWorkspaceTabsState {
|
||||
const WORKSPACE_STORAGE_KEY = 'jarri_spooty_workspace_state_v1';
|
||||
const WORKSPACE_TABS_STORAGE_KEY = 'jarri_spooty_workspace_tabs_v1';
|
||||
const ARCHIVE_DESTINATION_KEY = 'jarri_spooty_archive_destination_v1';
|
||||
const AUTH_TOKEN_STORAGE_KEY = 'spooty_auth_token';
|
||||
const GRID_SIZE = 12;
|
||||
const MIN_PANEL_WIDTH = 260;
|
||||
const MIN_PANEL_HEIGHT = 160;
|
||||
@@ -176,9 +177,26 @@ export function defaultWorkspaceTabsState(): SpootyWorkspaceTabsState {
|
||||
};
|
||||
}
|
||||
|
||||
function getStorageItem(key: string): string | null {
|
||||
try {
|
||||
return localStorage.getItem(key);
|
||||
} catch (error) {
|
||||
console.error(`Failed to read localStorage key "${key}"`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function setStorageItem(key: string, value: string): void {
|
||||
try {
|
||||
localStorage.setItem(key, value);
|
||||
} catch (error) {
|
||||
console.error(`Failed to write localStorage key "${key}"`, error);
|
||||
}
|
||||
}
|
||||
|
||||
export function loadWorkspaceState(): SpootyWorkspaceState {
|
||||
try {
|
||||
const raw = localStorage.getItem(WORKSPACE_STORAGE_KEY);
|
||||
const raw = getStorageItem(WORKSPACE_STORAGE_KEY);
|
||||
|
||||
if (!raw) {
|
||||
return defaultWorkspaceState();
|
||||
@@ -204,7 +222,7 @@ export function loadWorkspaceState(): SpootyWorkspaceState {
|
||||
|
||||
export function loadWorkspaceTabsState(): SpootyWorkspaceTabsState {
|
||||
try {
|
||||
const raw = localStorage.getItem(WORKSPACE_TABS_STORAGE_KEY);
|
||||
const raw = getStorageItem(WORKSPACE_TABS_STORAGE_KEY);
|
||||
|
||||
if (raw) {
|
||||
const parsed = JSON.parse(raw) as SpootyWorkspaceTabsState;
|
||||
@@ -318,8 +336,8 @@ export class AppComponent implements OnDestroy {
|
||||
selectedTrack$ = this.trackService.selectedTrack$;
|
||||
version = this.versionService.getVersion();
|
||||
spotifyConnected = false;
|
||||
authTokenPresent = Boolean(localStorage.getItem('spooty_auth_token'));
|
||||
archiveDestination = localStorage.getItem(ARCHIVE_DESTINATION_KEY) || '';
|
||||
authTokenPresent = Boolean(getStorageItem(AUTH_TOKEN_STORAGE_KEY));
|
||||
archiveDestination = getStorageItem(ARCHIVE_DESTINATION_KEY) || '';
|
||||
archiveListing?: ArchiveListing;
|
||||
archiveLoading = false;
|
||||
archiveError = '';
|
||||
@@ -370,7 +388,7 @@ export class AppComponent implements OnDestroy {
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem('spooty_auth_token', token);
|
||||
setStorageItem(AUTH_TOKEN_STORAGE_KEY, token);
|
||||
this.authTokenPresent = true;
|
||||
url.searchParams.delete('token');
|
||||
window.history.replaceState({}, document.title, url.toString());
|
||||
@@ -411,7 +429,7 @@ export class AppComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
saveArchiveDestination(): void {
|
||||
localStorage.setItem(ARCHIVE_DESTINATION_KEY, this.archiveDestination);
|
||||
setStorageItem(ARCHIVE_DESTINATION_KEY, this.archiveDestination);
|
||||
}
|
||||
|
||||
refreshArchive(): void {
|
||||
@@ -769,7 +787,7 @@ export class AppComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
private saveWorkspaceState(): void {
|
||||
localStorage.setItem(
|
||||
setStorageItem(
|
||||
WORKSPACE_TABS_STORAGE_KEY,
|
||||
JSON.stringify(this.workspaceTabsState),
|
||||
);
|
||||
|
||||
@@ -3,7 +3,13 @@ import { HttpInterceptorFn } from '@angular/common/http';
|
||||
const TOKEN_STORAGE_KEY = 'spooty_auth_token';
|
||||
|
||||
export const authTokenInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
const token = localStorage.getItem(TOKEN_STORAGE_KEY);
|
||||
let token: string | null = null;
|
||||
|
||||
try {
|
||||
token = localStorage.getItem(TOKEN_STORAGE_KEY);
|
||||
} catch (error) {
|
||||
console.error('Failed to read auth token from localStorage', error);
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
return next(req);
|
||||
|
||||
@@ -8,6 +8,21 @@
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<div id="boot-status">Loading Jarri Spooty...</div>
|
||||
<app-root></app-root>
|
||||
<script>
|
||||
window.addEventListener('error', function (event) {
|
||||
var boot = document.getElementById('boot-status');
|
||||
if (boot) {
|
||||
boot.textContent = 'Frontend error: ' + (event.message || 'unknown');
|
||||
}
|
||||
});
|
||||
window.addEventListener('unhandledrejection', function (event) {
|
||||
var boot = document.getElementById('boot-status');
|
||||
if (boot) {
|
||||
boot.textContent = 'Frontend rejection: ' + String(event.reason || 'unknown');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -5,6 +5,9 @@ import { AppComponent } from './app/app.component';
|
||||
import { devTools } from '@ngneat/elf-devtools';
|
||||
|
||||
bootstrapApplication(AppComponent, appConfig)
|
||||
.then(() => {
|
||||
document.getElementById('boot-status')?.remove();
|
||||
})
|
||||
.catch((err) => console.error(err));
|
||||
|
||||
if (isDevMode()) {
|
||||
|
||||
Reference in New Issue
Block a user