Separate JSON API backend (vm_api.py) + React+TanStack frontend scaffold
- vm_api.py: pure FastAPI JSON API on :8098 with CORS - vm-api.service: systemd unit for API (replaces inline HTML vm_web.py for frontend) - vm_web.py: kept intact as fallback; Apache now proxies /api/ -> :8098 - frontend/: Vite + React + TanStack Query scaffold - Apache vhost updated: DocumentRoot -> frontend/dist, /api/ proxy, SPA fallback - All original HTML pages still functional via :8099 during transition
This commit is contained in:
61
frontend/node_modules/@tanstack/react-store/src/index.ts
generated
vendored
Normal file
61
frontend/node_modules/@tanstack/react-store/src/index.ts
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
export * from '@tanstack/store'
|
||||
|
||||
export { useStore } from './useStore'
|
||||
|
||||
export function shallow<T>(objA: T, objB: T) {
|
||||
if (Object.is(objA, objB)) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (
|
||||
typeof objA !== 'object' ||
|
||||
objA === null ||
|
||||
typeof objB !== 'object' ||
|
||||
objB === null
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (objA instanceof Map && objB instanceof Map) {
|
||||
if (objA.size !== objB.size) return false
|
||||
for (const [k, v] of objA) {
|
||||
if (!objB.has(k) || !Object.is(v, objB.get(k))) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if (objA instanceof Set && objB instanceof Set) {
|
||||
if (objA.size !== objB.size) return false
|
||||
for (const v of objA) {
|
||||
if (!objB.has(v)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if (objA instanceof Date && objB instanceof Date) {
|
||||
if (objA.getTime() !== objB.getTime()) return false
|
||||
return true
|
||||
}
|
||||
|
||||
const keysA = getOwnKeys(objA)
|
||||
if (keysA.length !== getOwnKeys(objB).length) {
|
||||
return false
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
||||
for (let i = 0; i < keysA.length; i++) {
|
||||
if (
|
||||
!Object.prototype.hasOwnProperty.call(objB, keysA[i] as string) ||
|
||||
!Object.is(objA[keysA[i] as keyof T], objB[keysA[i] as keyof T])
|
||||
) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function getOwnKeys(obj: object): Array<string | symbol> {
|
||||
return (Object.keys(obj) as Array<string | symbol>).concat(
|
||||
Object.getOwnPropertySymbols(obj),
|
||||
)
|
||||
}
|
||||
44
frontend/node_modules/@tanstack/react-store/src/useStore.ts
generated
vendored
Normal file
44
frontend/node_modules/@tanstack/react-store/src/useStore.ts
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
import { useCallback } from 'react'
|
||||
import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector'
|
||||
import type { AnyAtom } from '@tanstack/store'
|
||||
|
||||
type SyncExternalStoreSubscribe = Parameters<
|
||||
typeof useSyncExternalStoreWithSelector
|
||||
>[0]
|
||||
|
||||
function defaultCompare<T>(a: T, b: T) {
|
||||
return a === b
|
||||
}
|
||||
|
||||
export function useStore<TAtom extends AnyAtom | undefined, T>(
|
||||
atom: TAtom,
|
||||
selector: (
|
||||
snapshot: TAtom extends { get: () => infer TSnapshot }
|
||||
? TSnapshot
|
||||
: undefined,
|
||||
) => T,
|
||||
compare: (a: T, b: T) => boolean = defaultCompare,
|
||||
): T {
|
||||
const subscribe: SyncExternalStoreSubscribe = useCallback(
|
||||
(handleStoreChange) => {
|
||||
if (!atom) {
|
||||
return () => {}
|
||||
}
|
||||
const { unsubscribe } = atom.subscribe(handleStoreChange)
|
||||
return unsubscribe
|
||||
},
|
||||
[atom],
|
||||
)
|
||||
|
||||
const boundGetSnapshot = useCallback(() => atom?.get(), [atom])
|
||||
|
||||
const selectedSnapshot = useSyncExternalStoreWithSelector(
|
||||
subscribe,
|
||||
boundGetSnapshot,
|
||||
boundGetSnapshot,
|
||||
selector,
|
||||
compare,
|
||||
)
|
||||
|
||||
return selectedSnapshot
|
||||
}
|
||||
Reference in New Issue
Block a user