Ignore generated OpenAPI types

This commit is contained in:
PnePnePne
2026-02-12 18:58:48 +01:00
parent 13f8899b19
commit 51c16e77d8
41 changed files with 3015 additions and 22 deletions

33
frontend/src/App.vue Normal file
View File

@@ -0,0 +1,33 @@
<script setup lang="ts">
import { ref, onMounted } from "vue"
import { checkBackendHealth } from "./features/health/health.service"
const health = ref<any>(null)
onMounted(async () => {
health.value = await checkBackendHealth()
})
</script>
<template>
<main style="padding: 16px">
<h1>Frontend</h1>
<pre>{{ health }}</pre>
</main>
</template>
<style scoped>
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

View File

@@ -0,0 +1,37 @@
// src/api/assets.api.ts
import type { paths } from "../generated/api"
import { http, apiUrl } from "./http"
// Request bodies
export type AssetCreateIn =
paths["/api/assets"]["post"]["requestBody"]["content"]["application/json"]
export type AssetTransitionIn =
paths["/api/assets/{asset_id}/transition"]["post"]["requestBody"]["content"]["application/json"]
// Responses
export type AssetOut =
paths["/api/assets/{asset_id}"]["get"]["responses"]["200"]["content"]["application/json"]
export type AssetEventsOut =
paths["/api/assets/{asset_id}/events"]["get"]["responses"]["200"]["content"]["application/json"]
export async function createAsset(payload: AssetCreateIn): Promise<AssetOut> {
const r = await http.post<AssetOut>(apiUrl("/assets"), payload)
return r.data
}
export async function getAsset(assetId: string): Promise<AssetOut> {
const r = await http.get<AssetOut>(apiUrl(`/assets/${assetId}`))
return r.data
}
export async function transitionAsset(assetId: string, payload: AssetTransitionIn): Promise<AssetOut> {
const r = await http.post<AssetOut>(apiUrl(`/assets/${assetId}/transition`), payload)
return r.data
}
export async function listAssetEvents(assetId: string): Promise<AssetEventsOut> {
const r = await http.get<AssetEventsOut>(apiUrl(`/assets/${assetId}/events`))
return r.data
}

View File

@@ -0,0 +1,11 @@
// src/api/health.api.ts
import type { paths } from "../generated/api"
import { http, apiUrl } from "./http"
type HealthOk =
paths["/api/health"]["get"]["responses"]["200"]["content"]["application/json"]
export async function getHealth(): Promise<HealthOk> {
const r = await http.get<HealthOk>(apiUrl("/health"))
return r.data
}

14
frontend/src/api/http.ts Normal file
View File

@@ -0,0 +1,14 @@
// src/api/http.ts
import axios from "axios"
export const API_BASE = (import.meta.env.VITE_API_BASE ?? "/api").replace(/\/$/, "")
export const http = axios.create({
baseURL: "", // same-origin (Vite Proxy übernimmt /api)
timeout: 10_000,
})
export function apiUrl(path: string): string {
const p = path.startsWith("/") ? path : `/${path}`
return `${API_BASE}${p}`
}

View File

@@ -0,0 +1,41 @@
<script setup lang="ts">
import { ref } from 'vue'
defineProps<{ msg: string }>()
const count = ref(0)
</script>
<template>
<h1>{{ msg }}</h1>
<div class="card">
<button type="button" @click="count++">count is {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test HMR
</p>
</div>
<p>
Check out
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
>create-vue</a
>, the official Vue + Vite starter
</p>
<p>
Learn more about IDE Support for Vue in the
<a
href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
target="_blank"
>Vue Docs Scaling up Guide</a
>.
</p>
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
</template>
<style scoped>
.read-the-docs {
color: #888;
}
</style>

View File

@@ -0,0 +1,18 @@
// src/features/assets/assets.service.ts
import { createAsset, getAsset, listAssetEvents, transitionAsset } from "../../api/assets.api"
import type { AssetCreateIn, AssetTransitionIn } from "../../api/assets.api"
export const AssetsService = {
create(payload: AssetCreateIn) {
return createAsset(payload)
},
get(assetId: string) {
return getAsset(assetId)
},
transition(assetId: string, payload: AssetTransitionIn) {
return transitionAsset(assetId, payload)
},
events(assetId: string) {
return listAssetEvents(assetId)
},
}

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

After

Width:  |  Height:  |  Size: 496 B

View File

@@ -0,0 +1,6 @@
// src/features/health/health.service.ts
import { getHealth } from "../../api/health.api"
export async function checkBackendHealth() {
return getHealth()
}

330
frontend/src/generated/api.d.ts vendored Normal file
View File

@@ -0,0 +1,330 @@
/**
* This file was auto-generated by openapi-typescript.
* Do not make direct changes to the file.
*/
export interface paths {
"/api/health": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** Health */
get: operations["health_api_health_get"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/assets": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/** Create Asset */
post: operations["create_asset_api_assets_post"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/assets/{asset_id}": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** Get Asset */
get: operations["get_asset_api_assets__asset_id__get"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/assets/{asset_id}/transition": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/** Transition Asset */
post: operations["transition_asset_api_assets__asset_id__transition_post"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/assets/{asset_id}/events": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** List Events */
get: operations["list_events_api_assets__asset_id__events_get"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
}
export type webhooks = Record<string, never>;
export interface components {
schemas: {
/** AssetCreate */
AssetCreate: {
/** Name */
name: string;
/** Serial */
serial?: string | null;
};
/** AssetEventOut */
AssetEventOut: {
/**
* Asset Id
* Format: uuid
*/
asset_id: string;
from_status: components["schemas"]["AssetStatus"];
to_status: components["schemas"]["AssetStatus"];
/**
* At
* Format: date-time
*/
at: string;
/** Note */
note?: string | null;
};
/** AssetOut */
AssetOut: {
/**
* Id
* Format: uuid
*/
id: string;
/** Name */
name: string;
/** Serial */
serial: string | null;
status: components["schemas"]["AssetStatus"];
/** Revision */
revision: number;
/**
* Updated At
* Format: date-time
*/
updated_at: string;
};
/**
* AssetStatus
* @enum {string}
*/
AssetStatus: "WARENEINGANG" | "SICHTPRUEFUNG" | "WARTESCHLANGE" | "IN_BEARBEITUNG" | "QUALITAETSKONTROLLE" | "WARENAUSGANG";
/** AssetTransitionIn */
AssetTransitionIn: {
to_status: components["schemas"]["AssetStatus"];
/** Expected Revision */
expected_revision: number;
/** Note */
note?: string | null;
};
/** HTTPValidationError */
HTTPValidationError: {
/** Detail */
detail?: components["schemas"]["ValidationError"][];
};
/** ValidationError */
ValidationError: {
/** Location */
loc: (string | number)[];
/** Message */
msg: string;
/** Error Type */
type: string;
/** Input */
input?: unknown;
/** Context */
ctx?: Record<string, never>;
};
};
responses: never;
parameters: never;
requestBodies: never;
headers: never;
pathItems: never;
}
export type $defs = Record<string, never>;
export interface operations {
health_api_health_get: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": unknown;
};
};
};
};
create_asset_api_assets_post: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["AssetCreate"];
};
};
responses: {
/** @description Successful Response */
201: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["AssetOut"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
get_asset_api_assets__asset_id__get: {
parameters: {
query?: never;
header?: never;
path: {
asset_id: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["AssetOut"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
transition_asset_api_assets__asset_id__transition_post: {
parameters: {
query?: never;
header?: never;
path: {
asset_id: string;
};
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["AssetTransitionIn"];
};
};
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["AssetOut"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
list_events_api_assets__asset_id__events_get: {
parameters: {
query?: never;
header?: never;
path: {
asset_id: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["AssetEventOut"][];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
}

5
frontend/src/lib/api.ts Normal file
View File

@@ -0,0 +1,5 @@
import axios from "axios"
export const api = axios.create({
baseURL: "/api",
})

5
frontend/src/main.ts Normal file
View File

@@ -0,0 +1,5 @@
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
createApp(App).mount('#app')

79
frontend/src/style.css Normal file
View File

@@ -0,0 +1,79 @@
:root {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
.card {
padding: 2em;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}