Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d92b5edaa | ||
|
|
4a6a8592e0 |
@@ -1,5 +1,9 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v0.40.0 — 2026-09-21 13:06
|
||||||
|
- **Top-bar version link (ISS-080).** The header's version tag (`components/Map.tsx`) is now an anchor to the repo's `CHANGELOG.md` on Gitea (`app-version` testid, opens in a new tab); one small CSS rule keeps it subtle against the dark header. E2E: `e2e/map.spec.ts` pins the exact href
|
||||||
|
- **On-board ICAO tags (ISS-081).** The on-board package row in the fleet list (`components/LeftPane.tsx`) shows 4-char ICAO tags instead of full airport names — both the route span (new `onboard-route-{id}` testid) and the "Fly to …" button label + title. Other name displays (in-flight leg, plane location, map popup, open-package rows, toasts) are unchanged. E2E: one new assertion in `e2e/actions.spec.ts` pins the ICAO route on a loaded package
|
||||||
|
|
||||||
## v0.39.0 — 2026-09-21 12:02
|
## v0.39.0 — 2026-09-21 12:02
|
||||||
- **Maintenance (ISS-069).** Planes wear out and can be repaired: distance-based health, a broken state that burns more fuel, and a repair action that grounds the plane for 3 sim days. New balance constants in `lib/game/catalog.ts` (all ponytail-tunable): `WEAR_PER_KM = 0.005`, `BROKEN_BURN_MULTIPLIER = 1.5`, `REPAIR_COST = 1_500` (flat), `REPAIR_DURATION_MS = 3 × 86_400_000`, plus the pure helper `conditionBurnMultiplier(health)` — exactly 1 above zero health, ×1.5 at/below it
|
- **Maintenance (ISS-069).** Planes wear out and can be repaired: distance-based health, a broken state that burns more fuel, and a repair action that grounds the plane for 3 sim days. New balance constants in `lib/game/catalog.ts` (all ponytail-tunable): `WEAR_PER_KM = 0.005`, `BROKEN_BURN_MULTIPLIER = 1.5`, `REPAIR_COST = 1_500` (flat), `REPAIR_DURATION_MS = 3 × 86_400_000`, plus the pure helper `conditionBurnMultiplier(health)` — exactly 1 above zero health, ×1.5 at/below it
|
||||||
- **Schema.** Two new `planes` columns in all four places: Drizzle schema (`lib/db/schema.ts`), raw DDL + guarded `ALTER TABLE … ADD COLUMN` migrations in `migrateColumns()` (pre-existing rows backfill to full health / NULL gate, mirroring the weight_kg/special precedent), and the seed insert path — starter plane in `buildSeed` (`lib/game/seed.ts`) and every `buyPlane` delivery start at `health: 100`. New plane status `'repairing'` added to the three pinned unions (schema enum, `PlaneState`, OpenAPI) plus `mapData.ts`'s feature props
|
- **Schema.** Two new `planes` columns in all four places: Drizzle schema (`lib/db/schema.ts`), raw DDL + guarded `ALTER TABLE … ADD COLUMN` migrations in `migrateColumns()` (pre-existing rows backfill to full health / NULL gate, mirroring the weight_kg/special precedent), and the seed insert path — starter plane in `buildSeed` (`lib/game/seed.ts`) and every `buyPlane` delivery start at `health: 100`. New plane status `'repairing'` added to the three pinned unions (schema enum, `PlaneState`, OpenAPI) plus `mapData.ts`'s feature props
|
||||||
|
|||||||
@@ -48,6 +48,16 @@ body {
|
|||||||
color: #94a3b8;
|
color: #94a3b8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ISS-080 (v0.40.0): the version tag links to the repo's CHANGELOG.md — keep it subtle, like the rest of the header. */
|
||||||
|
.app-header a {
|
||||||
|
color: #7dd3fc;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-header a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
/* Style switcher — kept subtle, like the version tag. */
|
/* Style switcher — kept subtle, like the version tag. */
|
||||||
.style-switch {
|
.style-switch {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|||||||
@@ -429,8 +429,9 @@ export default function LeftPane({ state, loading, error, onRefresh, applySnapsh
|
|||||||
// so "Fly to …" works from any state and the queue needs no dedicated input.
|
// so "Fly to …" works from any state and the queue needs no dedicated input.
|
||||||
onClick={() => void runAction(`/api/planes/${p.id}/${p.status === 'flying' ? 'queue' : 'fly'}`, { destIcao: pkg.destIcao })}
|
onClick={() => void runAction(`/api/planes/${p.id}/${p.status === 'flying' ? 'queue' : 'fly'}`, { destIcao: pkg.destIcao })}
|
||||||
>
|
>
|
||||||
<span className="onboard-fly-label" title={`Fly to ${pkg.destName}`}>
|
{/* ISS-081 (v0.40.0): ICAO tags instead of full airport names. */}
|
||||||
Fly to {pkg.destName}
|
<span className="onboard-fly-label" title={`Fly to ${pkg.destIcao}`}>
|
||||||
|
Fly to {pkg.destIcao}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<div className="onboard-actions">
|
<div className="onboard-actions">
|
||||||
@@ -455,7 +456,10 @@ export default function LeftPane({ state, loading, error, onRefresh, applySnapsh
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="contract-sub">
|
<div className="contract-sub">
|
||||||
<span className="contract-route">{pkg.originName} → {pkg.destName}</span>
|
{/* ISS-081 (v0.40.0): ICAO tags instead of full airport names. */}
|
||||||
|
<span data-testid={`onboard-route-${pkg.id}`} className="contract-route">
|
||||||
|
{pkg.originIcao} → {pkg.destIcao}
|
||||||
|
</span>
|
||||||
{/* v0.37.0 (ISS-073): special-status badge — rendered only when the package has one. */}
|
{/* v0.37.0 (ISS-073): special-status badge — rendered only when the package has one. */}
|
||||||
{pkg.special && (
|
{pkg.special && (
|
||||||
<span data-testid={`package-special-${pkg.id}`} className="special-badge">
|
<span data-testid={`package-special-${pkg.id}`} className="special-badge">
|
||||||
|
|||||||
+3
-1
@@ -537,7 +537,9 @@ export default function FlightMap({ state, hovered, applySnapshot }: MapProps) {
|
|||||||
<div className="map-wrap">
|
<div className="map-wrap">
|
||||||
<header data-testid="app-header" className="app-header">
|
<header data-testid="app-header" className="app-header">
|
||||||
<h1>Flight Ops</h1>
|
<h1>Flight Ops</h1>
|
||||||
<small>v{pkg.version}</small>
|
<a data-testid="app-version" href="https://git.kkhost.pl/OpenCode/Flight-Ops/src/branch/master/CHANGELOG.md" target="_blank" rel="noreferrer">
|
||||||
|
<small>v{pkg.version}</small>
|
||||||
|
</a>
|
||||||
<select
|
<select
|
||||||
data-testid="style-switch"
|
data-testid="style-switch"
|
||||||
className="style-switch"
|
className="style-switch"
|
||||||
|
|||||||
+3
-1
@@ -192,8 +192,10 @@ test('full core loop via UI: load → fly to destination → exact reward + rep
|
|||||||
// package shows as loaded on the starter in the on-board section.
|
// package shows as loaded on the starter in the on-board section.
|
||||||
const onboardRow = page.getByTestId(`onboard-package-${pkg.id}`);
|
const onboardRow = page.getByTestId(`onboard-package-${pkg.id}`);
|
||||||
await expect(onboardRow, 'loaded package appears in the on-board list').toBeVisible();
|
await expect(onboardRow, 'loaded package appears in the on-board list').toBeVisible();
|
||||||
|
// ISS-081 (v0.40.0): the on-board route shows ICAO tags, not full airport names.
|
||||||
|
await expect(page.getByTestId(`onboard-route-${pkg.id}`)).toContainText(`${HUB} → ${nearest.icao}`);
|
||||||
|
|
||||||
// FLY via the UI: click the destination name button in the on-board list.
|
// FLY via the UI: click the fly-to button in the on-board list (ISS-081: ICAO label).
|
||||||
const flyBtn = page.getByTestId(`fly-to-${pkg.id}`);
|
const flyBtn = page.getByTestId(`fly-to-${pkg.id}`);
|
||||||
await expect(flyBtn).toBeEnabled();
|
await expect(flyBtn).toBeEnabled();
|
||||||
await flyBtn.click();
|
await flyBtn.click();
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ test('header shows the app version sourced from package.json', async ({ page })
|
|||||||
await page.goto(APP_URL);
|
await page.goto(APP_URL);
|
||||||
const header = page.getByTestId('app-header');
|
const header = page.getByTestId('app-header');
|
||||||
await expect(header).toContainText(`v${pkg.version}`);
|
await expect(header).toContainText(`v${pkg.version}`);
|
||||||
|
// ISS-080 (v0.40.0): the version links to the repo's CHANGELOG.md.
|
||||||
|
await expect(page.getByTestId('app-version')).toHaveAttribute(
|
||||||
|
'href',
|
||||||
|
'https://git.kkhost.pl/OpenCode/Flight-Ops/src/branch/master/CHANGELOG.md',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('clicking an airport marker opens a popup with name and ICAO', async ({ page }) => {
|
test('clicking an airport marker opens a popup with name and ICAO', async ({ page }) => {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "flight-ops",
|
"name": "flight-ops",
|
||||||
"version": "0.39.0",
|
"version": "0.40.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev -p 3000",
|
"dev": "next dev -p 3000",
|
||||||
|
|||||||
Reference in New Issue
Block a user