diff --git a/Dockerfile b/Dockerfile index f22f31a..29ce319 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,15 @@ # Stage 1: Build frontend FROM node:20-slim AS frontend-builder +ARG COMMIT_HASH=unknown + WORKDIR /build COPY frontend/package*.json ./ RUN npm ci COPY frontend/ ./ -RUN npm run build +RUN VITE_COMMIT_HASH=${COMMIT_HASH} npm run build # Stage 2: Python runtime diff --git a/frontend/AGENTS.md b/frontend/AGENTS.md index 45896f9..52854e1 100644 --- a/frontend/AGENTS.md +++ b/frontend/AGENTS.md @@ -80,7 +80,8 @@ frontend/src/ │ │ ├── SettingsMqttSection.tsx # MQTT broker config, TLS, publish toggles │ │ ├── SettingsDatabaseSection.tsx # DB size, cleanup, auto-decrypt, local label │ │ ├── SettingsBotSection.tsx # Bot list, code editor, add/delete/reset -│ │ └── SettingsStatisticsSection.tsx # Read-only mesh network stats +│ │ ├── SettingsStatisticsSection.tsx # Read-only mesh network stats +│ │ └── SettingsAboutSection.tsx # Version, author, license, links │ ├── repeater/ │ │ ├── repeaterPaneShared.tsx # Shared: RepeaterPane, KvRow, format helpers │ │ ├── RepeaterTelemetryPane.tsx # Battery, airtime, packet counts diff --git a/frontend/src/components/SettingsModal.tsx b/frontend/src/components/SettingsModal.tsx index 989fbb3..3059946 100644 --- a/frontend/src/components/SettingsModal.tsx +++ b/frontend/src/components/SettingsModal.tsx @@ -16,6 +16,7 @@ import { SettingsMqttSection } from './settings/SettingsMqttSection'; import { SettingsDatabaseSection } from './settings/SettingsDatabaseSection'; import { SettingsBotSection } from './settings/SettingsBotSection'; import { SettingsStatisticsSection } from './settings/SettingsStatisticsSection'; +import { SettingsAboutSection } from './settings/SettingsAboutSection'; interface SettingsModalBaseProps { open: boolean; @@ -77,6 +78,7 @@ export function SettingsModal(props: SettingsModalProps) { database: false, bot: false, statistics: false, + about: false, }; }); @@ -267,6 +269,13 @@ export function SettingsModal(props: SettingsModalProps) { )} )} + + {shouldRenderSection('about') && ( +
+ {renderSectionHeader('about')} + {isSectionVisible('about') && } +
+ )} ); } diff --git a/frontend/src/components/settings/SettingsAboutSection.tsx b/frontend/src/components/settings/SettingsAboutSection.tsx new file mode 100644 index 0000000..a7e182a --- /dev/null +++ b/frontend/src/components/settings/SettingsAboutSection.tsx @@ -0,0 +1,108 @@ +import { Separator } from '../ui/separator'; + +const GITHUB_URL = 'https://github.com/jkingsman/Remote-Terminal-for-MeshCore'; + +export function SettingsAboutSection({ className }: { className?: string }) { + const version = __APP_VERSION__; + const commit = __COMMIT_HASH__; + + return ( +
+
+ {/* Version */} +
+

RemoteTerm for MeshCore

+
+ v{version} + · + {commit} +
+
+ + + + {/* Author & License */} +
+

+ Made with love and open source by{' '} + + Jack Kingsman + +

+

+ Licensed under the{' '} + + MIT License + +

+
+ + + + {/* Links */} +
+ + GitHub + + + Report a Bug + + + Changelog + +
+ + + + {/* Acknowledgements */} +
+

With great appreciation to those who have made the tools upon which this is built:

+

+ + MeshCore + + · + + meshcore_py + +

+
+
+
+ ); +} diff --git a/frontend/src/components/settings/settingsConstants.ts b/frontend/src/components/settings/settingsConstants.ts index e6e43b8..8fe66c4 100644 --- a/frontend/src/components/settings/settingsConstants.ts +++ b/frontend/src/components/settings/settingsConstants.ts @@ -5,7 +5,8 @@ export type SettingsSection = | 'mqtt' | 'database' | 'bot' - | 'statistics'; + | 'statistics' + | 'about'; export const SETTINGS_SECTION_ORDER: SettingsSection[] = [ 'radio', @@ -15,6 +16,7 @@ export const SETTINGS_SECTION_ORDER: SettingsSection[] = [ 'database', 'bot', 'statistics', + 'about', ]; export const SETTINGS_SECTION_LABELS: Record = { @@ -25,4 +27,5 @@ export const SETTINGS_SECTION_LABELS: Record = { database: '🗄️ Database & Interface', bot: '🤖 Bot', statistics: '📊 Statistics', + about: 'About', }; diff --git a/frontend/src/types/globals.d.ts b/frontend/src/types/globals.d.ts new file mode 100644 index 0000000..11311eb --- /dev/null +++ b/frontend/src/types/globals.d.ts @@ -0,0 +1,2 @@ +declare const __APP_VERSION__: string; +declare const __COMMIT_HASH__: string; diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index ede2da3..10b4892 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,9 +1,24 @@ import path from "path" +import { execSync } from "child_process" import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' +function getCommitHash(): string { + // Docker builds pass VITE_COMMIT_HASH as an env var + if (process.env.VITE_COMMIT_HASH) return process.env.VITE_COMMIT_HASH; + try { + return execSync('git rev-parse --short HEAD', { encoding: 'utf-8' }).trim(); + } catch { + return 'unknown'; + } +} + export default defineConfig({ plugins: [react()], + define: { + __APP_VERSION__: JSON.stringify(process.env.npm_package_version ?? 'unknown'), + __COMMIT_HASH__: JSON.stringify(getCommitHash()), + }, resolve: { alias: { "@": path.resolve(__dirname, "./src"), diff --git a/scripts/publish.sh b/scripts/publish.sh index 6e0b264..e979d09 100644 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -153,7 +153,8 @@ GIT_HASH=$(git rev-parse --short HEAD) # Build docker image echo -e "${YELLOW}Building Docker image...${NC}" -docker build -t jkingsman/remoteterm-meshcore:latest \ +docker build --build-arg COMMIT_HASH=$GIT_HASH \ + -t jkingsman/remoteterm-meshcore:latest \ -t jkingsman/remoteterm-meshcore:$VERSION \ -t jkingsman/remoteterm-meshcore:$GIT_HASH . echo -e "${GREEN}Docker build complete!${NC}"