This commit is contained in:
2025-03-27 13:26:28 +00:00
parent 2037953000
commit 77cb64b260
1973 changed files with 3529 additions and 10479 deletions

40
frontend/src/App.svelte Normal file
View File

@@ -0,0 +1,40 @@
<script lang="ts">
import { metricCall } from "./config"
import { location } from "./lib/store"
export let url = ""
if (url) {
// ssr
let l = url.split("?")
$location = {
path: l[0],
search: l.length > 1 ? l[1] : "",
hash: "",
push: false,
pop: false,
}
}
// metrics
let oldPath: string
$: if (metricCall && typeof window !== "undefined" && oldPath !== $location.path) {
const ref = oldPath ? document.location.protocol + "//" + document.location.host + oldPath : document.referrer
oldPath = $location.path
const fetchPath = oldPath + (oldPath.includes("?") ? "&" : "?") + "metrics"
fetch(fetchPath, {
headers: {
"x-ssr-skip": "204",
"x-ssr-ref": ref,
"x-ssr-res": `${window.innerWidth}x${window.innerHeight}`,
// no cache
"cache-control": "no-cache, no-store, must-revalidate",
},
})
}
</script>
<h1>Tibi Svelte Starter</h1>
<style lang="less" global>
@import "./css/style.less";
</style>

14
frontend/src/config.ts Normal file
View File

@@ -0,0 +1,14 @@
// @ts-ignore
import * as sentry from "./sentry"
import configClient from "../../api/hooks/config-client"
export const apiBaseURL = configClient.apiClientBaseURL
export const release = configClient.release
export const sentryDSN = ""
export const sentryTracingOrigins = ["localhost", "project-domain.tld", /^\//]
export const sentryEnvironment: string = "local"
// need to execute early for fetch wrapping
// sentry.init(sentryDSN, sentryTracingOrigins, sentryEnvironment, release)
export const metricCall = false

View File

14
frontend/src/index.ts Normal file
View File

@@ -0,0 +1,14 @@
import App from "./App.svelte"
let appContainer = document?.getElementById("appContainer")
const hydrate = true //import.meta?.env?.MODE !== "development"
console.log("Features: ", { hydrate })
const app = new App({
target: appContainer,
props: {},
hydrate,
})
export default app

84
frontend/src/lib/store.ts Normal file
View File

@@ -0,0 +1,84 @@
import { get, writable } from "svelte/store"
/*********** location **************************/
const initLoc = {
path: (typeof window !== "undefined" && window.location?.pathname) || "/",
search: (typeof window !== "undefined" && window.location?.search) || "",
hash: (typeof window !== "undefined" && window.location?.hash) || "",
push: false,
pop: false,
}
export const location = writable<LocationStore>(initLoc)
const publishLocation = (_p?: string) => {
let _s: string
let _h: string
if (_p) {
const parts = _p.split("#")
_p = parts.shift()
_h = parts.join()
if (_h) _h = "#" + _h
const parts2 = _p.split("?")
_p = parts2.shift()
_s = parts2.join()
if (_s) _s = "?" + _s
}
const newLocation: LocationStore = {
path: _p || (typeof window !== "undefined" && window.location?.pathname),
search: _p ? _s : typeof window !== "undefined" && window.location?.search,
hash: _p ? _h : typeof window !== "undefined" && window.location?.hash,
push: !!_p,
pop: !_p,
previousLocation: get(location),
}
location.set(newLocation)
}
if (typeof history !== "undefined") {
if (typeof Proxy !== "undefined") {
// modern browser
const historyApply = (
target: (this: any, ...args: readonly any[]) => unknown,
thisArg: any,
argumentsList: string | readonly any[]
) => {
publishLocation(argumentsList && argumentsList.length >= 2 && argumentsList[2])
Reflect.apply(target, thisArg, argumentsList)
}
history.pushState = new Proxy(history.pushState, {
apply: historyApply,
})
history.replaceState = new Proxy(history.replaceState, {
apply: historyApply,
})
} else {
// ie11
const pushStateFn = history.pushState
const replaceStateFn = history.replaceState
history.pushState = function (data: any, title: string, url?: string) {
publishLocation(url)
// @ts-ignore
return pushStateFn.apply(history, arguments)
}
history.replaceState = function (data: any, title: string, url?: string) {
publishLocation(url)
// @ts-ignore
return replaceStateFn.apply(history, arguments)
}
}
} // else ssr -> no history handling
typeof window !== "undefined" &&
window.addEventListener("popstate", (event) => {
publishLocation()
})
/********************** override for admin ui *****************/
export const apiBaseOverride = writable<string | null>(null)

52
frontend/src/sentry.ts Normal file
View File

@@ -0,0 +1,52 @@
import * as Sentry from "@sentry/svelte"
let initialized = false
export const init = (dsn: string, tracingOrigins: (string | RegExp)[], environment: string, release: string) => {
if (typeof window !== "undefined") {
Sentry.init({
dsn: dsn,
tunnel: "/_s",
tracePropagationTargets: tracingOrigins,
integrations: [
Sentry.browserTracingIntegration(),
Sentry.replayIntegration({
maskAllText: false,
maskAllInputs: false,
blockAllMedia: false,
networkDetailAllowUrls: [/\/api\//],
mutationLimit: 99999,
mutationBreadcrumbLimit: 2000,
}),
],
environment: environment,
tracesSampleRate: 1.0,
debug: false,
release: release,
replaysSessionSampleRate: 1.0,
replaysOnErrorSampleRate: 1.0,
})
console.log("Sentry initialized")
initialized = true
}
}
// export const startSpan = (opt: { name: string; op: string }) => {
// if (typeof window !== "undefined" && initialized) {
// return Sentry.startInactiveSpan(opt)
// }
// }
export const currentTransaction = () => {
const activeSpan = Sentry.getActiveSpan()
if (activeSpan && activeSpan) {
return activeSpan
}
return null
}
export const setUser = (user: Sentry.User) => {
if (typeof window !== "undefined" && initialized) {
user.ip_address = "{{auto}}"
Sentry.setUser(user)
}
}

3
frontend/src/ssr.ts Normal file
View File

@@ -0,0 +1,3 @@
import App from "./App.svelte"
export default App