diff --git a/.dockerignore b/.dockerignore index f925df8..3dd638e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,5 @@ node_modules/ dist/ -.git/ documentation/ *.log .env @@ -9,3 +8,8 @@ documentation/ # Lomitko na zacatku je nutne: bez nej by se vzorec shodl s KAZDOU # slozkou 'data', tedy i se src/data - a zdrojove soubory by tise chybely. /data/ + +# `.git/` se zamerne NEvylucuje. Build z nej cte cislo commitu do oznaceni +# verze - bez nej se na nasazene aplikaci pozna jen cas buildu, ne co v ni je. +# Do vysledneho image se nedostane: ten vznika z ciste zakladni image +# a kopiruje se do nej jen `dist`, `scripts` a migrace. diff --git a/documentation/02-appfactory-proxy.md b/documentation/02-appfactory-proxy.md index 04fa62d..480884d 100644 --- a/documentation/02-appfactory-proxy.md +++ b/documentation/02-appfactory-proxy.md @@ -104,6 +104,41 @@ Definici sestavuje `src/openapi.ts`. Pozn.: `/api/dashboard/stream` je Server-Sent Events. Swagger UI streamovanou odpoved rozumne nezobrazi, testuje se prohlizecem nebo curlem. +## Jak se pozna, ktera verze bezi + +Nasazena aplikace, ktera je o dva commity pozadu, funguje a vypada skoro +stejne jako nova. Bez oznaceni buildu se to nepozna a hleda se chyba tam, kde +zadna neni - presne to nas jednou stalo pul hodiny. + +Kazdy build proto nese svoje oznaceni. Sklada ho Vite pri buildu +(`vite.config.ts`, sekce `buildInfo`) a je videt na dvou mistech: + +| Kde | Jak se k tomu dostat | +| --------------------- | ------------------------------------------- | +| Pata postranniho menu | pod tlacitkem Odhlasit se, staci prihlaseni | +| Hlavicka stranky | `curl` na adresu aplikace, bez prihlaseni | + +```bash +curl -s https://services.csbot.cz/apps/csbot-prototype/ | grep app-build +# +``` + +Tri udaje a kazdy rika neco jineho: + +| Udaj | K cemu | +| ---------- | ------------------------------------------------------ | +| Verze | z `package.json`, meni se zridka | +| Cas buildu | **hlavni udaj.** Rika, jestli nasazeni vubec probehlo | +| Commit | rika, **co** v tom je. Bez nej se pozna jen kdy, ne co | + +Commit se cte z `.git`, takze se `.git/` **zamerne nevylucuje** +v `.dockerignore`. Do vysledneho image se nedostane: ten vznika z ciste +zakladni image a kopiruje se do nej jen `dist`, `scripts` a migrace. Kdyby +`.git` pri buildu chybelo, oznaceni se nerozbije, jen commit zustane prazdny. + +Ve vyvoji se misto casu pise "vyvoj". Cas buildu by tam byl pokazde jiny +a nikomu by nic nerekl. + ## Overeni po zmene ```bash diff --git a/documentation/99-zmeny.md b/documentation/99-zmeny.md index 947d2a4..e81cdcc 100644 --- a/documentation/99-zmeny.md +++ b/documentation/99-zmeny.md @@ -2,6 +2,30 @@ Nejnovejsi nahore. +## 2026-08-26 - na aplikaci je videt, ktery build to je + +Nasazena aplikace o dva commity pozadu funguje a vypada skoro stejne jako +nova. Bez oznaceni buildu se to nepozna a hleda se chyba tam, kde zadna neni. + +### Pridano + +- **Oznaceni buildu v pate postranniho menu**, pod tlacitkem Odhlasit se: + verze, cas buildu a cislo commitu. Text jde oznacit jednim kliknutim, aby + se dal poslat dal. +- **Totez jako `` v hlavicce stranky.** V JS balicku uz + to je, ale ten se musi stahnout a rozbalit. Meta znacka je videt na jeden + `curl` bez prihlaseni - a prave to clovek potrebuje, kdyz zjistuje, co bezi + na produkci. +- Hodnoty dosazuje Vite pri buildu (`define` a plugin `build-stamp` + ve `vite.config.ts`), takze neplati pro repozitar, ale pro ten konkretni + balicek. + +### Zmeneno + +- **`.dockerignore` uz nevylucuje `.git/`.** Build z nej cte cislo commitu; + bez nej by se poznal jen cas buildu, ne co v nem je. Do vysledneho image se + `.git` nedostane, ten se sklada z ciste zakladni image. + ## 2026-08-26 - rebrand na WorkNuke Prevzeti vizualniho smeru z predlohy. Popis, jak znacka funguje v kodu, je diff --git a/vite.config.ts b/vite.config.ts index c3c44a8..2acee19 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,11 +1,72 @@ import tailwindcss from '@tailwindcss/vite'; import react from '@vitejs/plugin-react'; +import { execSync } from 'node:child_process'; +import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; -import { defineConfig } from 'vite'; +import { defineConfig, type Plugin } from 'vite'; const here = path.dirname(fileURLToPath(import.meta.url)); +/** + * Oznaceni buildu. + * + * Bez nej se nasazena verze nepozna: aplikace bezi, jen je stara, a z venku + * to vypada stejne jako kdyz je nova. Prave to nas jednou stalo pul hodiny + * hadani, proc je na produkci porad stary vzhled. + * + * Cas buildu je hlavni udaj, protoze funguje vzdycky. Commit je bonus: do + * image se `.git` nekopiruje (`.dockerignore`), takze v produkcnim buildu + * chybi a zustane prazdny. + */ +const pkg: { version: string } = JSON.parse( + fs.readFileSync(path.resolve(here, 'package.json'), 'utf8'), +); + +function gitCommit(): string { + try { + return execSync('git rev-parse --short HEAD', { stdio: ['ignore', 'pipe', 'ignore'] }) + .toString() + .trim(); + } catch { + // V containeru `.git` neni. Neni to chyba, jen se commit nedozvime. + return ''; + } +} + +const buildInfo = { + version: pkg.version, + builtAt: new Date().toISOString(), + commit: gitCommit(), +}; + +/** + * Vlozi oznaceni buildu i do hlavicky stranky. + * + * V JS balicku uz je, ale ten se musi stahnout a rozbalit. Meta znacka je + * videt na jeden `curl` bez prihlaseni - a presne to clovek potrebuje, kdyz + * zjistuje, co vlastne bezi na produkci. + */ +function buildStamp(): Plugin { + return { + name: 'build-stamp', + transformIndexHtml() { + return [ + { + tag: 'meta', + attrs: { + name: 'app-build', + content: [buildInfo.version, buildInfo.builtAt, buildInfo.commit] + .filter(Boolean) + .join(' '), + }, + injectTo: 'head', + }, + ]; + }, + }; +} + export default defineConfig({ root: path.resolve(here, 'web'), /** @@ -14,7 +75,10 @@ export default defineConfig({ * podle ROOT_PATH a relativni odkazy se podle nej slozi spravne. */ base: './', - plugins: [react(), tailwindcss()], + plugins: [react(), tailwindcss(), buildStamp()], + define: { + __BUILD_INFO__: JSON.stringify(buildInfo), + }, resolve: { // Musi zustat v souladu s "paths" ve web/tsconfig.json alias: { diff --git a/web/src/components/dashboard/DashboardLayout.tsx b/web/src/components/dashboard/DashboardLayout.tsx index 1040979..7769b7a 100644 --- a/web/src/components/dashboard/DashboardLayout.tsx +++ b/web/src/components/dashboard/DashboardLayout.tsx @@ -27,6 +27,7 @@ import { EventToasts } from '@/components/dashboard/EventToasts'; import { LiveIndicator } from '@/components/dashboard/LiveIndicator'; import { Logo } from '@/components/layout/Logo'; import { cn } from '@/lib/cn'; +import { buildInfo, versionLabel } from '@/config/version'; import { setActiveTenant, useActiveTenant } from '@/lib/tenant'; import { useApiQuery } from '@/lib/useApiQuery'; import type { Access } from '@/types/dashboard'; @@ -247,6 +248,18 @@ function DashboardShell() { Odhlásit se + + {/* + Ktera verze zrovna bezi. Bez toho se nasazena aplikace nepozna od + stare: obojí funguje a vypada skoro stejne. Cas je z buildu, ne + z prohlizece. + */} +

+ {versionLabel()} +

diff --git a/web/src/config/version.ts b/web/src/config/version.ts new file mode 100644 index 0000000..c4b83d6 --- /dev/null +++ b/web/src/config/version.ts @@ -0,0 +1,46 @@ +/** + * Ktera verze zrovna bezi. + * + * Hodnoty dosazuje Vite pri buildu (`define` ve `vite.config.ts`), takze + * neplati pro repozitar, ale **pro tenhle konkretni balicek** - presne to, + * co clovek potrebuje vedet, kdyz se diva na nasazenou aplikaci. + * + * Cas buildu je hlavni udaj: rozliseni na sekundy staci, aby se poznalo, ze + * nasazeni probehlo nebo neprobehlo. Commit je nepovinny, do image se `.git` + * nekopiruje. + */ + +const info: { version: string; builtAt: string; commit: string } = + typeof __BUILD_INFO__ === 'undefined' + ? { version: '0.0.0', builtAt: '', commit: '' } + : __BUILD_INFO__; + +export const buildInfo = info; + +/** + * Kratky popis verze pro patu postranniho menu. + * + * Ve vyvoji se cas buildu nepise: mel by tam kazdou minutu jiny a nikomu nic + * nerekne. Na nasazene aplikaci je naopak to hlavni. + */ +export function versionLabel(): string { + const parts = [`v${info.version}`]; + + if (import.meta.env.DEV) { + parts.push('vývoj'); + } else if (info.builtAt) { + parts.push( + new Date(info.builtAt).toLocaleString('cs-CZ', { + day: 'numeric', + month: 'numeric', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + }), + ); + } + + if (info.commit) parts.push(info.commit); + + return parts.join(' · '); +} diff --git a/web/src/vite-env.d.ts b/web/src/vite-env.d.ts index 05dd671..591bd29 100644 --- a/web/src/vite-env.d.ts +++ b/web/src/vite-env.d.ts @@ -1,6 +1,12 @@ /// declare global { + /** + * Oznaceni buildu dosazene Vitem (`define` ve vite.config.ts). + * Ve vyvoji i v produkci existuje vzdy, jen s jinym obsahem. + */ + const __BUILD_INFO__: { version: string; builtAt: string; commit: string }; + interface Window { /** * Prefix reverse proxy vlozeny serverem do index.html podle ROOT_PATH.