mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 13:21:46 +00:00
feat: prerelease workflow with major version support and version propagation
- Add docker-dev.yml: prerelease CI for dev branch with minor/major bump inputs; auto-continues in-flight major line via existing pre tags; publishes floating major-pre Docker tag (e.g. 2-pre) - Rewrite docker.yml version-bump: tag-based versioning, manual bump inputs (auto/patch/minor/major), major guarded by confirm_major=MAJOR, auto-finalizes in-flight prereleases; publishes floating major tag (e.g. 2) - Inject APP_VERSION build-arg through Dockerfile so the running container knows its real version instead of reading package.json - Server reads APP_VERSION env in authService/adminService; exposes is_prerelease in app config and update-check response; prerelease builds compare against GitHub prerelease releases rather than latest stable - Client stores isPrerelease from config; navbar shows amber version badge on prerelease builds (left of dark-mode toggle); GitHubPanel filters out prerelease releases unless the running build is itself a prerelease
This commit is contained in:
+3
-2
@@ -88,16 +88,17 @@ function RootRedirect() {
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
const { loadUser, isAuthenticated, demoMode, setDemoMode, setDevMode, setHasMapsKey, setServerTimezone, setAppRequireMfa, setTripRemindersEnabled } = useAuthStore()
|
||||
const { loadUser, isAuthenticated, demoMode, setDemoMode, setDevMode, setIsPrerelease, setHasMapsKey, setServerTimezone, setAppRequireMfa, setTripRemindersEnabled } = useAuthStore()
|
||||
const { loadSettings } = useSettingsStore()
|
||||
|
||||
useEffect(() => {
|
||||
if (!location.pathname.startsWith('/shared/') && !location.pathname.startsWith('/public/') && !location.pathname.startsWith('/login')) {
|
||||
loadUser()
|
||||
}
|
||||
authApi.getAppConfig().then(async (config: { demo_mode?: boolean; dev_mode?: boolean; has_maps_key?: boolean; version?: string; timezone?: string; require_mfa?: boolean; trip_reminders_enabled?: boolean; permissions?: Record<string, PermissionLevel> }) => {
|
||||
authApi.getAppConfig().then(async (config: { demo_mode?: boolean; dev_mode?: boolean; is_prerelease?: boolean; has_maps_key?: boolean; version?: string; timezone?: string; require_mfa?: boolean; trip_reminders_enabled?: boolean; permissions?: Record<string, PermissionLevel> }) => {
|
||||
if (config?.demo_mode) setDemoMode(true)
|
||||
if (config?.dev_mode) setDevMode(true)
|
||||
if (config?.is_prerelease !== undefined) setIsPrerelease(config.is_prerelease)
|
||||
if (config?.has_maps_key !== undefined) setHasMapsKey(config.has_maps_key)
|
||||
if (config?.timezone) setServerTimezone(config.timezone)
|
||||
if (config?.require_mfa !== undefined) setAppRequireMfa(!!config.require_mfa)
|
||||
|
||||
@@ -6,7 +6,7 @@ import apiClient from '../../api/client'
|
||||
const REPO = 'mauriceboe/TREK'
|
||||
const PER_PAGE = 10
|
||||
|
||||
export default function GitHubPanel() {
|
||||
export default function GitHubPanel({ isPrerelease = false }: { isPrerelease?: boolean }) {
|
||||
const { t, language } = useTranslation()
|
||||
const [releases, setReleases] = useState([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
@@ -273,7 +273,7 @@ export default function GitHubPanel() {
|
||||
<div className="absolute left-[11px] top-3 bottom-3 w-px" style={{ background: 'var(--border-primary)' }} />
|
||||
|
||||
<div className="space-y-0">
|
||||
{releases.map((release, idx) => {
|
||||
{(isPrerelease ? releases : releases.filter((r: any) => !r.prerelease)).map((release, idx) => {
|
||||
const isLatest = idx === 0
|
||||
const isExpanded = expanded[release.id]
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ interface Addon {
|
||||
}
|
||||
|
||||
export default function Navbar({ tripTitle, tripId, onBack, showBack, onShare }: NavbarProps): React.ReactElement {
|
||||
const { user, logout } = useAuthStore()
|
||||
const { user, logout, isPrerelease } = useAuthStore()
|
||||
const { settings, updateSetting } = useSettingsStore()
|
||||
const { addons: allAddons, loadAddons } = useAddonStore()
|
||||
const { t, locale } = useTranslation()
|
||||
@@ -155,6 +155,17 @@ export default function Navbar({ tripTitle, tripId, onBack, showBack, onShare }:
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* Prerelease badge */}
|
||||
{isPrerelease && appVersion && (
|
||||
<span
|
||||
className="hidden sm:flex items-center gap-1.5 px-2.5 py-1 rounded-full text-[11px] font-semibold flex-shrink-0"
|
||||
style={{ background: 'rgba(245,158,11,0.15)', color: '#d97706', border: '1px solid rgba(245,158,11,0.3)' }}
|
||||
>
|
||||
<span className="w-1.5 h-1.5 rounded-full flex-shrink-0" style={{ background: '#f59e0b' }} />
|
||||
{appVersion}
|
||||
</span>
|
||||
)}
|
||||
|
||||
{/* Dark mode toggle (light ↔ dark, overrides auto) — hidden on mobile */}
|
||||
<button onClick={toggleDarkMode} title={dark ? t('nav.lightMode') : t('nav.darkMode')}
|
||||
className="p-2 rounded-lg transition-colors flex-shrink-0 hidden sm:flex"
|
||||
|
||||
@@ -55,6 +55,7 @@ interface UpdateInfo {
|
||||
current: string
|
||||
release_url?: string
|
||||
is_docker?: boolean
|
||||
is_prerelease?: boolean
|
||||
}
|
||||
|
||||
const ADMIN_EVENT_LABEL_KEYS: Record<string, string> = {
|
||||
@@ -1370,7 +1371,7 @@ export default function AdminPage(): React.ReactElement {
|
||||
|
||||
{activeTab === 'mcp-tokens' && <AdminMcpTokensPanel />}
|
||||
|
||||
{activeTab === 'github' && <GitHubPanel />}
|
||||
{activeTab === 'github' && <GitHubPanel isPrerelease={updateInfo?.is_prerelease ?? false} />}
|
||||
|
||||
{activeTab === 'dev-notifications' && <DevNotificationsPanel />}
|
||||
</div>
|
||||
|
||||
@@ -22,6 +22,7 @@ interface AuthState {
|
||||
error: string | null
|
||||
demoMode: boolean
|
||||
devMode: boolean
|
||||
isPrerelease: boolean
|
||||
hasMapsKey: boolean
|
||||
serverTimezone: string
|
||||
/** Server policy: all users must enable MFA */
|
||||
@@ -41,6 +42,7 @@ interface AuthState {
|
||||
deleteAvatar: () => Promise<void>
|
||||
setDemoMode: (val: boolean) => void
|
||||
setDevMode: (val: boolean) => void
|
||||
setIsPrerelease: (val: boolean) => void
|
||||
setHasMapsKey: (val: boolean) => void
|
||||
setServerTimezone: (tz: string) => void
|
||||
setAppRequireMfa: (val: boolean) => void
|
||||
@@ -58,6 +60,7 @@ export const useAuthStore = create<AuthState>((set, get) => ({
|
||||
error: null,
|
||||
demoMode: localStorage.getItem('demo_mode') === 'true',
|
||||
devMode: false,
|
||||
isPrerelease: false,
|
||||
hasMapsKey: false,
|
||||
serverTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
appRequireMfa: false,
|
||||
@@ -222,6 +225,7 @@ export const useAuthStore = create<AuthState>((set, get) => ({
|
||||
},
|
||||
|
||||
setDevMode: (val: boolean) => set({ devMode: val }),
|
||||
setIsPrerelease: (val: boolean) => set({ isPrerelease: val }),
|
||||
setHasMapsKey: (val: boolean) => set({ hasMapsKey: val }),
|
||||
setServerTimezone: (tz: string) => set({ serverTimezone: tz }),
|
||||
setAppRequireMfa: (val: boolean) => set({ appRequireMfa: val }),
|
||||
|
||||
Reference in New Issue
Block a user