fixed warnings from eslint
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
import type { NextRequest } from 'next/server'
|
import type { NextRequest } from 'next/server'
|
||||||
import { NextResponse } from 'next/server'
|
import { NextResponse } from 'next/server'
|
||||||
|
|
||||||
/// Resend request to backend.
|
/**
|
||||||
/// Body is being sent as stream.
|
* Resend request to backend.
|
||||||
|
* Body is being sent as stream.
|
||||||
|
*/
|
||||||
export async function redirectRequest(
|
export async function redirectRequest(
|
||||||
req: NextRequest,
|
req: NextRequest,
|
||||||
proxyUrl: string,
|
proxyUrl: string,
|
||||||
@@ -26,8 +28,7 @@ export async function redirectRequest(
|
|||||||
method: req.method,
|
method: req.method,
|
||||||
headers: req.headers,
|
headers: req.headers,
|
||||||
body: req.body,
|
body: req.body,
|
||||||
// @ts-ignore
|
duplex: 'half', // required by nodejs when the body is a stream, see src/types/fetch.d.ts
|
||||||
duplex: 'half', // some property required by nodejs but not defined in @types/node
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return new NextResponse(backendRes.body, {
|
return new NextResponse(backendRes.body, {
|
||||||
@@ -41,9 +42,14 @@ export async function redirectRequest(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Browsers send OPTIONS request sometimes to check webserver's allowed headers and methods.
|
/**
|
||||||
/// My C# backend doesn't support OPTIONS, so the proxy answer to OPTIONS request that all headers and methods are allowed.
|
* Browsers send OPTIONS request sometimes to check webserver's allowed
|
||||||
export async function responseToOPTIONS(
|
* headers and methods.
|
||||||
|
* My C# backend doesn't support OPTIONS, so the proxy answer to OPTIONS
|
||||||
|
* request that all headers and methods are allowed.
|
||||||
|
*/
|
||||||
|
export async function respondToOPTIONS(
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- required by the nextjs route handler signature
|
||||||
req: NextRequest
|
req: NextRequest
|
||||||
): Promise<NextResponse> {
|
): Promise<NextResponse> {
|
||||||
// console.log('proxy responding to CORS OPTIONS', req.url)
|
// console.log('proxy responding to CORS OPTIONS', req.url)
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
import type { NextRequest } from 'next/server'
|
import type { NextRequest } from 'next/server'
|
||||||
import { NextResponse } from 'next/server'
|
import { NextResponse } from 'next/server'
|
||||||
import {
|
import { redirectRequest, respondToOPTIONS } from '@/app/api/proxy/functions'
|
||||||
redirectRequest,
|
|
||||||
responseToOPTIONS as respondToOPTIONS,
|
|
||||||
} from '@/app/api/proxy/functions'
|
|
||||||
import { PROXY_PATHS } from '@/app/api/proxy/paths'
|
import { PROXY_PATHS } from '@/app/api/proxy/paths'
|
||||||
import { appConfig } from '@/lib/configLoader'
|
import { appConfig } from '@/lib/configLoader'
|
||||||
|
|
||||||
|
|||||||
+35
-26
@@ -6,38 +6,47 @@ import {
|
|||||||
themeQuartz,
|
themeQuartz,
|
||||||
colorSchemeDark,
|
colorSchemeDark,
|
||||||
} from 'ag-grid-community'
|
} from 'ag-grid-community'
|
||||||
import { useState, useEffect } from 'react'
|
import { useSyncExternalStore } from 'react'
|
||||||
|
|
||||||
|
const DARK_SCHEME_QUERY = '(prefers-color-scheme: dark)'
|
||||||
|
|
||||||
|
// add the vertical lines between cells
|
||||||
|
const BASE_THEME = themeQuartz.withParams({
|
||||||
|
columnBorder: true,
|
||||||
|
headerColumnBorder: true,
|
||||||
|
})
|
||||||
|
// Built once, so the grid keeps seeing the same theme object between renders.
|
||||||
|
const LIGHT_THEME = BASE_THEME
|
||||||
|
const DARK_THEME = BASE_THEME.withPart(colorSchemeDark)
|
||||||
|
|
||||||
|
// Notifies React whenever the browser's light/dark color scheme changes.
|
||||||
|
function subscribeToColorScheme(onChange: () => void) {
|
||||||
|
const mediaQuery = window.matchMedia(DARK_SCHEME_QUERY)
|
||||||
|
mediaQuery.addEventListener('change', onChange)
|
||||||
|
return () => mediaQuery.removeEventListener('change', onChange)
|
||||||
|
}
|
||||||
|
|
||||||
|
function isDarkSchemePreferred() {
|
||||||
|
return window.matchMedia(DARK_SCHEME_QUERY).matches
|
||||||
|
}
|
||||||
|
|
||||||
|
// The server has no color scheme, so it always prerenders the light theme.
|
||||||
|
function isDarkSchemePreferredOnServer() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: create tabs with general info, tables, plots
|
// TODO: create tabs with general info, tables, plots
|
||||||
|
|
||||||
// Page that shows a save file's parsed data in a grid.
|
// Page that shows a save file's parsed data in a grid.
|
||||||
export default function BrowseSaveDataPage() {
|
export default function BrowseSaveDataPage() {
|
||||||
const [agTheme, setAgTheme] = useState(themeQuartz)
|
// Read the color scheme straight from the browser instead of mirroring it
|
||||||
|
// into state, which would need an extra render to catch up.
|
||||||
// Keep the grid theme in sync with the browser's light/dark color scheme.
|
const prefersDark = useSyncExternalStore(
|
||||||
useEffect(() => {
|
subscribeToColorScheme,
|
||||||
const prefersDark = window.matchMedia(
|
isDarkSchemePreferred,
|
||||||
'(prefers-color-scheme: dark)'
|
isDarkSchemePreferredOnServer
|
||||||
).matches
|
|
||||||
setAgTheme(
|
|
||||||
prefersDark ? themeQuartz.withPart(colorSchemeDark) : themeQuartz
|
|
||||||
)
|
)
|
||||||
|
const agTheme = prefersDark ? DARK_THEME : LIGHT_THEME
|
||||||
const listener = (e: MediaQueryListEvent) => {
|
|
||||||
setAgTheme(
|
|
||||||
e.matches ? themeQuartz.withPart(colorSchemeDark) : themeQuartz
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
window
|
|
||||||
.matchMedia('(prefers-color-scheme: dark)')
|
|
||||||
.addEventListener('change', listener)
|
|
||||||
return () => {
|
|
||||||
window
|
|
||||||
.matchMedia('(prefers-color-scheme: dark)')
|
|
||||||
.removeEventListener('change', listener)
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ height: '500px' }}>
|
<div style={{ height: '500px' }}>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { authService } from '@/services/AuthService'
|
import { authService } from '@/services/AuthService'
|
||||||
import FormError from '@/components/FormError'
|
import FormError from '@/components/FormError'
|
||||||
|
import { getMsgFromError } from '@/lib/errors'
|
||||||
|
|
||||||
// Page with the login form.
|
// Page with the login form.
|
||||||
export default function LoginPage() {
|
export default function LoginPage() {
|
||||||
@@ -35,9 +36,10 @@ export default function LoginPage() {
|
|||||||
formData.password
|
formData.password
|
||||||
)
|
)
|
||||||
console.log('Logged in:', result)
|
console.log('Logged in:', result)
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
console.error(err.message)
|
const errMsg = getMsgFromError(err)
|
||||||
setError(err.message)
|
console.error(errMsg)
|
||||||
|
setError(errMsg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useState } from 'react'
|
|||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import { authService } from '@/services/AuthService'
|
import { authService } from '@/services/AuthService'
|
||||||
import FormError from '@/components/FormError'
|
import FormError from '@/components/FormError'
|
||||||
|
import { getMsgFromError } from '@/lib/errors'
|
||||||
|
|
||||||
// Page with the registration form.
|
// Page with the registration form.
|
||||||
export default function RegisterPage() {
|
export default function RegisterPage() {
|
||||||
@@ -43,9 +44,10 @@ export default function RegisterPage() {
|
|||||||
)
|
)
|
||||||
console.log('Registered:', result)
|
console.log('Registered:', result)
|
||||||
router.push('/login') // Redirect after success
|
router.push('/login') // Redirect after success
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
console.error(err.message)
|
const errMsg = getMsgFromError(err)
|
||||||
setError(err.message)
|
console.error(errMsg)
|
||||||
|
setError(errMsg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
} from '@/services/SaveParserBackendService'
|
} from '@/services/SaveParserBackendService'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import FormError from './FormError'
|
import FormError from './FormError'
|
||||||
|
import { getMsgFromError } from '@/lib/errors'
|
||||||
|
|
||||||
export enum GameEnum {
|
export enum GameEnum {
|
||||||
EU4 = 'eu4',
|
EU4 = 'eu4',
|
||||||
@@ -71,16 +72,18 @@ export default function SaveFileUploadingDialog() {
|
|||||||
clearInterval(intervalId)
|
clearInterval(intervalId)
|
||||||
setUploadDisabled(false)
|
setUploadDisabled(false)
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
console.error('Error while polling status:', err)
|
const errMsg = getMsgFromError(err)
|
||||||
|
console.error('Error while polling status:', errMsg)
|
||||||
clearInterval(intervalId)
|
clearInterval(intervalId)
|
||||||
setError(err.message)
|
setError(errMsg)
|
||||||
setUploadDisabled(false)
|
setUploadDisabled(false)
|
||||||
}
|
}
|
||||||
}, pollInterval)
|
}, pollInterval)
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
console.error(err.message)
|
const errMsg = getMsgFromError(err)
|
||||||
setError(err.message)
|
console.error(errMsg)
|
||||||
|
setError(errMsg)
|
||||||
setUploadDisabled(false)
|
setUploadDisabled(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,7 +148,7 @@ export default function SaveFileUploadingDialog() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* add link to <ConditionalView cond={done}> /browse?id=${saveStatus.id} */}
|
{/* TODO: add link to <ConditionalView cond={done}> /browse?id=${saveStatus.id} */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,5 +4,10 @@
|
|||||||
export async function register() {
|
export async function register() {
|
||||||
console.log('hello from instrumentation.ts!')
|
console.log('hello from instrumentation.ts!')
|
||||||
await import('@/lib/customConsoleLog') // replaces console.log
|
await import('@/lib/customConsoleLog') // replaces console.log
|
||||||
|
|
||||||
|
// Importing configLoader outside of this block will produce warning.
|
||||||
|
// Next.js compiles this file for some "edge runtime", where no fs and path modules exist.
|
||||||
|
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
||||||
await import('@/lib/configLoader') // forces loadConfig() to run at server startup
|
await import('@/lib/configLoader') // forces loadConfig() to run at server startup
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
function injectConsoleLog() {
|
function injectConsoleLog() {
|
||||||
const originalLog = console.log
|
const originalLog = console.log
|
||||||
|
|
||||||
function customLog(message?: any, ...optionalParams: any[]) {
|
function customLog(message?: unknown, ...optionalParams: unknown[]) {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const timestamp = now.toTimeString().split(' ')[0] // hh:mm:ss
|
const timestamp = now.toTimeString().split(' ')[0] // hh:mm:ss
|
||||||
originalLog(`[${timestamp}] ${message}`, ...optionalParams)
|
originalLog(`[${timestamp}] ${message}`, ...optionalParams)
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* Extracts a readable message from an unknown thrown value, since anything
|
||||||
|
* (not just an Error) can be thrown and caught.
|
||||||
|
*/
|
||||||
|
export function getMsgFromError(err: unknown): string {
|
||||||
|
return err instanceof Error ? err.message : String(err)
|
||||||
|
}
|
||||||
@@ -61,7 +61,7 @@ export class SaveParserBackendService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fetches the fully parsed data for a save once its parsing is done.
|
// Fetches the fully parsed data for a save once its parsing is done.
|
||||||
async getParsedSave(id: string): Promise<Record<string, any>> {
|
async getParsedSave(id: string): Promise<Record<string, unknown>> {
|
||||||
const url = `${this.API_BASE}/getParsedSave?id=${encodeURIComponent(id)}`
|
const url = `${this.API_BASE}/getParsedSave?id=${encodeURIComponent(id)}`
|
||||||
const response = await fetch(url)
|
const response = await fetch(url)
|
||||||
|
|
||||||
|
|||||||
Vendored
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// Node's fetch needs `duplex: 'half'` for stream bodies,
|
||||||
|
// but lib.dom's RequestInit doesn't declare it.
|
||||||
|
// This interface is automatically merged with RequestInit from lib.dom.d.ts
|
||||||
|
interface RequestInit {
|
||||||
|
duplex?: 'half'
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user