Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55a9cbdc6e | ||
|
|
a6fc9daab9 | ||
|
|
8b3bff7df0 | ||
|
|
2b2ddc1b1b | ||
|
|
0d5986b81a |
@@ -59,10 +59,8 @@ This project uses version-tag-based CI/CD. Releases trigger automated Docker bui
|
||||
3. Commit changes: `git commit -m "chore: release vX.X.X"`
|
||||
4. Create git tag: `git tag vX.X.X`
|
||||
5. Push with tags: `git push origin master --tags`
|
||||
6. Create release in Gitea UI (git.schweitz.net → Releases → New Release)
|
||||
* Select the tag
|
||||
* Add release notes (can copy from CHANGELOG)
|
||||
* **Publish** the release (this triggers CI/CD)
|
||||
|
||||
CI/CD auto-triggers when a tag starting with `v` is pushed.
|
||||
|
||||
**What happens on release:**
|
||||
|
||||
|
||||
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.1.10] - 2026-01-04
|
||||
|
||||
### Changed
|
||||
- Removed page swipe transitions - all navigation is now instant (NoTransitionPage)
|
||||
|
||||
## [1.1.9] - 2026-01-04
|
||||
|
||||
### Changed
|
||||
- Moved health check to `/health` directory - URL is now `/health` instead of `/health.html`
|
||||
- Enables NPM forward auth path exclusion for health endpoint
|
||||
|
||||
## [1.1.8] - 2026-01-04
|
||||
|
||||
### Changed
|
||||
- Dark background (`#1a1a2e`) on web/index.html to prevent white flash during auth redirects
|
||||
|
||||
## [1.1.7] - 2026-01-04
|
||||
|
||||
### Removed
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:tatlock_ui/features/control_room/presentation/pages/control_room_page.dart';
|
||||
import 'package:tatlock_ui/routing/app_router.dart';
|
||||
import 'package:tatlock_ui/shared/layouts/widgets/nav_panel.dart';
|
||||
|
||||
/// Route paths for Control Room.
|
||||
@@ -66,7 +67,8 @@ List<RouteBase> controlRoomRoutes() {
|
||||
GoRoute(
|
||||
path: nav.path,
|
||||
name: 'controlRoom${_capitalize(nav.id.replaceAll('-', '_'))}',
|
||||
builder: (context, state) => ControlRoomPage(nav: nav),
|
||||
pageBuilder: (context, state) =>
|
||||
noTransitionPage(context, state, ControlRoomPage(nav: nav)),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:tatlock_ui/features/security/presentation/pages/security_page.dart';
|
||||
import 'package:tatlock_ui/routing/app_router.dart';
|
||||
import 'package:tatlock_ui/shared/layouts/widgets/nav_panel.dart';
|
||||
|
||||
/// Route paths for Security room.
|
||||
@@ -60,7 +61,8 @@ List<RouteBase> securityRoutes() {
|
||||
GoRoute(
|
||||
path: nav.path,
|
||||
name: 'security${_capitalize(nav.id.replaceAll('-', '_'))}',
|
||||
builder: (context, state) => SecurityPage(nav: nav),
|
||||
pageBuilder: (context, state) =>
|
||||
noTransitionPage(context, state, SecurityPage(nav: nav)),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -8,6 +8,14 @@ import 'package:tatlock_ui/shared/layouts/app_scaffold.dart';
|
||||
|
||||
part 'app_router.g.dart';
|
||||
|
||||
/// No-animation page builder for instant transitions
|
||||
Page<void> noTransitionPage(BuildContext context, GoRouterState state, Widget child) {
|
||||
return NoTransitionPage<void>(
|
||||
key: state.pageKey,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
/// Route paths as constants.
|
||||
abstract class AppRoutes {
|
||||
static const frontHall = '/';
|
||||
@@ -29,21 +37,22 @@ GoRouter appRouter(Ref ref) {
|
||||
GoRoute(
|
||||
path: AppRoutes.frontHall,
|
||||
name: 'frontHall',
|
||||
builder: (context, state) => const FrontHallPage(),
|
||||
pageBuilder: (context, state) =>
|
||||
noTransitionPage(context, state, const FrontHallPage()),
|
||||
),
|
||||
...controlRoomRoutes(),
|
||||
...securityRoutes(),
|
||||
GoRoute(
|
||||
path: AppRoutes.parlor,
|
||||
name: 'parlor',
|
||||
builder: (context, state) =>
|
||||
const _PlaceholderPage(title: 'Parlor'),
|
||||
pageBuilder: (context, state) =>
|
||||
noTransitionPage(context, state, const _PlaceholderPage(title: 'Parlor')),
|
||||
),
|
||||
GoRoute(
|
||||
path: AppRoutes.settings,
|
||||
name: 'settings',
|
||||
builder: (context, state) =>
|
||||
const _PlaceholderPage(title: 'Settings'),
|
||||
pageBuilder: (context, state) =>
|
||||
noTransitionPage(context, state, const _PlaceholderPage(title: 'Settings')),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
# Increase buffer size for large headers from Authentik
|
||||
proxy_buffers 8 16k;
|
||||
proxy_buffer_size 32k;
|
||||
|
||||
# Exclude static assets from forward auth
|
||||
# These paths bypass auth_request but still proxy to upstream
|
||||
location ~ ^/(manifest\.json|favicon\.(ico|png)|health|icons|assets) {
|
||||
auth_request off;
|
||||
proxy_pass $forward_scheme://$server:$port;
|
||||
}
|
||||
|
||||
# Forward authentication via standalone outpost
|
||||
auth_request /outpost.goauthentik.io/auth/nginx;
|
||||
error_page 401 = @goauthentik_proxy_signin;
|
||||
|
||||
# Capture auth response headers
|
||||
auth_request_set $auth_cookie $upstream_http_set_cookie;
|
||||
auth_request_set $authentik_username $upstream_http_x_authentik_username;
|
||||
auth_request_set $authentik_groups $upstream_http_x_authentik_groups;
|
||||
auth_request_set $authentik_email $upstream_http_x_authentik_email;
|
||||
auth_request_set $authentik_name $upstream_http_x_authentik_name;
|
||||
auth_request_set $authentik_uid $upstream_http_x_authentik_uid;
|
||||
|
||||
# Forward auth headers to application
|
||||
add_header Set-Cookie $auth_cookie;
|
||||
proxy_set_header X-authentik-username $authentik_username;
|
||||
proxy_set_header X-authentik-groups $authentik_groups;
|
||||
proxy_set_header X-authentik-email $authentik_email;
|
||||
proxy_set_header X-authentik-name $authentik_name;
|
||||
proxy_set_header X-authentik-uid $authentik_uid;
|
||||
|
||||
# Outpost proxy location
|
||||
location /outpost.goauthentik.io {
|
||||
proxy_pass https://localhost:9444/outpost.goauthentik.io;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $http_host;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_pass_request_body off;
|
||||
proxy_set_header Content-Length "";
|
||||
|
||||
# WebSocket support
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
}
|
||||
|
||||
# Signin redirect handler
|
||||
location @goauthentik_proxy_signin {
|
||||
internal;
|
||||
return 302 /outpost.goauthentik.io/start?rd=$request_uri;
|
||||
}
|
||||
+1
-1
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
# In Windows, build-name is used as the major, minor, and patch parts
|
||||
# of the product and file versions while build-number is used as the build suffix.
|
||||
version: 1.1.7+1
|
||||
version: 1.1.10+1
|
||||
|
||||
environment:
|
||||
sdk: ^3.10.4
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env dart
|
||||
// Generates web/health.json from pubspec.yaml
|
||||
// Generates web/health/health.json from pubspec.yaml
|
||||
// Run: dart run tool/generate_health_json.dart
|
||||
|
||||
// ignore_for_file: avoid_print
|
||||
@@ -37,15 +37,15 @@ void main() {
|
||||
'fullVersion': '$version+$buildNumber',
|
||||
};
|
||||
|
||||
final webDir = Directory('web');
|
||||
if (!webDir.existsSync()) {
|
||||
webDir.createSync(recursive: true);
|
||||
final healthDir = Directory('web/health');
|
||||
if (!healthDir.existsSync()) {
|
||||
healthDir.createSync(recursive: true);
|
||||
}
|
||||
|
||||
final healthFile = File('web/health.json');
|
||||
final healthFile = File('web/health/health.json');
|
||||
healthFile.writeAsStringSync(
|
||||
const JsonEncoder.withIndent(' ').convert(health),
|
||||
);
|
||||
|
||||
print('Generated web/health.json with version $version+$buildNumber');
|
||||
print('Generated web/health/health.json with version $version+$buildNumber');
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"status": "healthy",
|
||||
"name": "tatlock_ui",
|
||||
"title": "Tatlock - a Home Lab AI",
|
||||
"version": "1.0.4",
|
||||
"buildNumber": 1,
|
||||
"fullVersion": "1.0.4+1"
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
<h1 id="status">Loading...</h1>
|
||||
<pre id="data"></pre>
|
||||
<script>
|
||||
fetch('/health.json')
|
||||
fetch('./health.json')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
document.getElementById('status').textContent = data.status?.toUpperCase() || 'OK';
|
||||
@@ -32,6 +32,13 @@
|
||||
|
||||
<title>Tatlock</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #1a1a2e;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script src="flutter_bootstrap.js" async></script>
|
||||
|
||||
Reference in New Issue
Block a user