From 378ff3cc6210a43958def293b7c76f4a823cdf1f Mon Sep 17 00:00:00 2001 From: MaximEdogawa Date: Mon, 20 Apr 2026 09:27:48 +0200 Subject: [PATCH] update: removed dashboard and setting from web app --- package.json | 1 + playwright.config.ts | 3 +- src/App.tsx | 14 ++- src/pages/LandingPage.tsx | 45 +++++++-- src/pages/SettingsPage.tsx | 128 +----------------------- src/shared/about/AboutLegalContent.tsx | 131 +++++++++++++++++++++++++ src/shared/runtimeTarget.ts | 19 ++++ src/shared/ui/TopMenu.tsx | 25 +++-- src/vite-env.d.ts | 2 + 9 files changed, 220 insertions(+), 148 deletions(-) create mode 100644 src/shared/about/AboutLegalContent.tsx create mode 100644 src/shared/runtimeTarget.ts diff --git a/package.json b/package.json index cfcf53c..baed7f7 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "type": "module", "scripts": { "dev": "vite", + "dev:app": "VITE_ENABLE_APP_ROUTES_IN_BROWSER=true vite", "build:web": "tsc && vite build", "build": "bun run build:web", "preview": "vite preview", diff --git a/playwright.config.ts b/playwright.config.ts index ed87abd..3537198 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -18,7 +18,8 @@ export default defineConfig({ }, ], webServer: { - command: "npm run dev -- --host 127.0.0.1 --port 1420", + command: + "VITE_ENABLE_APP_ROUTES_IN_BROWSER=true npm run dev -- --host 127.0.0.1 --port 1420", url: "http://127.0.0.1:1420", reuseExistingServer: !process.env.CI, timeout: 120000, diff --git a/src/App.tsx b/src/App.tsx index 68db654..e07d4d0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,6 +2,7 @@ import { lazy, Suspense, useEffect, useRef, useState } from "react"; import { Navigate, Route, Routes, useNavigate } from "react-router-dom"; import { getPengineHealth } from "./modules/bot/api"; import { useAppSessionStore } from "./modules/bot/store/appSessionStore"; +import { isMarketingWebsite } from "./shared/runtimeTarget"; const LandingPage = lazy(() => import("./pages/LandingPage").then((m) => ({ default: m.LandingPage })), @@ -70,6 +71,7 @@ function StartupDashboardRedirect() { function App() { const [sessionReady, setSessionReady] = useState(false); + const marketingSite = isMarketingWebsite(); useEffect(() => { if (useAppSessionStore.persist.hasHydrated()) { @@ -94,13 +96,17 @@ function App() { return (
- + {!marketingSite && } }> } /> - } /> - } /> - } /> + {!marketingSite && ( + <> + } /> + } /> + } /> + + )} } /> diff --git a/src/pages/LandingPage.tsx b/src/pages/LandingPage.tsx index b06bccc..cb756ba 100644 --- a/src/pages/LandingPage.tsx +++ b/src/pages/LandingPage.tsx @@ -1,6 +1,8 @@ import { Link } from "react-router-dom"; import { TerminalPreview } from "../modules/bot/components/TerminalPreview"; import { DownloadLatestButton } from "../modules/updater"; +import { AboutLegalContent } from "../shared/about/AboutLegalContent"; +import { isMarketingWebsite } from "../shared/runtimeTarget"; import { PhoneMockup } from "../shared/ui/PhoneMockup"; import { SpecMockup } from "../shared/ui/SpecMockup"; import { TopMenu } from "../shared/ui/TopMenu"; @@ -106,6 +108,8 @@ const specCards = [ ]; export function LandingPage() { + const marketingSite = isMarketingWebsite(); + return (
@@ -128,10 +132,14 @@ export function LandingPage() { tools become new abilities on demand.

- - Scan and connect - - + {marketingSite ? ( + + ) : ( + + Scan and connect + + )} + {!marketingSite && } Read the spec @@ -438,10 +446,14 @@ export function LandingPage() { Your AI. Your machine. Your rules.
- - Open setup wizard - - + {marketingSite ? ( + + ) : ( + + Open setup wizard + + )} + {!marketingSite && }
+ + {marketingSite && ( +
+

About

+
+

+ Contact, privacy, and project +

+

+ Links and compliance information for the open source app. +

+
+
+ +
+
+ )}
); diff --git a/src/pages/SettingsPage.tsx b/src/pages/SettingsPage.tsx index ecf85d4..764b2d1 100644 --- a/src/pages/SettingsPage.tsx +++ b/src/pages/SettingsPage.tsx @@ -2,15 +2,11 @@ import { useCallback, useEffect, useState } from "react"; import { Link } from "react-router-dom"; import { getPengineHealth } from "../modules/bot/api"; import { useAppSessionStore } from "../modules/bot/store/appSessionStore"; +import { AboutLegalContent } from "../shared/about/AboutLegalContent"; import { TopMenu } from "../shared/ui/TopMenu"; type SettingsTab = "preferences" | "about"; -const CONTACT = { - x: { label: "X (Twitter)", href: "https://x.com/PengineAI" }, - github: { label: "GitHub", href: "https://github.com/pengine-ai/pengine" }, -} as const; - export function SettingsPage() { const isDeviceConnected = useAppSessionStore((s) => s.isDeviceConnected); const botUsername = useAppSessionStore((s) => s.botUsername); @@ -128,127 +124,7 @@ export function SettingsPage() { {tab === "about" && (
-
-

Contact info

-

- Project links and maintainer contact on social platforms. -

-
-
- -
-

Privacy info

-
-
-

- Privacy Policy -

-

- Pengine is a{" "} - desktop app that - runs an agent loop on your machine. There is no Pengine-hosted account or - cloud database for your chats: ordinary use keeps configuration and skills on - your device, while the bot and tools you enable determine what leaves it. -

-
-
-

- Analytics and telemetry -

-

- The app does not include first-party analytics or behavioral tracking, and it - does not phone home to a Pengine telemetry service. The dashboard may{" "} - - check GitHub’s public API - {" "} - for new releases (version metadata only), which is subject to GitHub’s own - policies and your network path. -

-
-
-

- What stays on your device -

-

- Pengine stores app data under your OS app-data location: connection metadata, - skills, MCP configuration, and UI-related settings files. Sensitive values - such as your{" "} - Telegram bot token{" "} - and MCP secrets you configure are kept in the{" "} - - platform secure store - {" "} - (for example Keychain on macOS), not in a Pengine cloud. -

-
-
-

- Network, Telegram, and inference -

-

- When your bot is connected, message traffic uses{" "} - Telegram’s services{" "} - per Telegram’s terms. The app sends prompts and tool activity to{" "} - - Ollama (or another endpoint you configure) - - — typically on your LAN or localhost, but cloud or remote models are possible - if you point the stack there. Any{" "} - - MCP servers, containers, or custom tools - {" "} - you add can read or forward data according to their own configuration; treat - them like any other software you install. -

-
-
-

- Responsibility -

-

- You choose the bot, models, skills, and tools. This policy describes how - Pengine is designed to run locally; it does not replace Telegram’s, your host - OS’s, or your inference provider’s policies. For exact storage and startup - behavior, see the project documentation in the repository. -

-
-
-
- -
-

About the app

-

- Pengine is a local AI agent runtime: it connects your Telegram bot to Ollama (or - compatible inference) so conversations and tools run on your hardware. The project - is open source; see the GitHub repository above for license and source code. -

- {appVersion && ( -

- Reported app version: v{appVersion} -

- )} -
+
)}
diff --git a/src/shared/about/AboutLegalContent.tsx b/src/shared/about/AboutLegalContent.tsx new file mode 100644 index 0000000..4c1a6f3 --- /dev/null +++ b/src/shared/about/AboutLegalContent.tsx @@ -0,0 +1,131 @@ +const CONTACT = { + x: { label: "X (Twitter)", href: "https://x.com/PengineAI" }, + github: { label: "GitHub", href: "https://github.com/pengine-ai/pengine" }, +} as const; + +type Props = { + /** Shown on the Settings page when the local app reports a version. */ + appVersion?: string | null; +}; + +export function AboutLegalContent({ appVersion }: Props) { + return ( +
+
+

Contact info

+

+ Project links and maintainer contact on social platforms. +

+ +
+ +
+

Privacy info

+
+
+

+ Privacy Policy +

+

+ Pengine is a desktop app{" "} + that runs an agent loop on your machine. There is no Pengine-hosted account or cloud + database for your chats: ordinary use keeps configuration and skills on your device, + while the bot and tools you enable determine what leaves it. +

+
+
+

+ Analytics and telemetry +

+

+ The app does not include first-party analytics or behavioral tracking, and it does not + phone home to a Pengine telemetry service. The dashboard may{" "} + check GitHub’s public API{" "} + for new releases (version metadata only), which is subject to GitHub’s own policies + and your network path. +

+
+
+

+ What stays on your device +

+

+ Pengine stores app data under your OS app-data location: connection metadata, skills, + MCP configuration, and UI-related settings files. Sensitive values such as your{" "} + Telegram bot token and MCP + secrets you configure are kept in the{" "} + platform secure store (for + example Keychain on macOS), not in a Pengine cloud. +

+
+
+

+ Network, Telegram, and inference +

+

+ When your bot is connected, message traffic uses{" "} + Telegram’s services per + Telegram’s terms. The app sends prompts and tool activity to{" "} + + Ollama (or another endpoint you configure) + + — typically on your LAN or localhost, but cloud or remote models are possible if you + point the stack there. Any{" "} + + MCP servers, containers, or custom tools + {" "} + you add can read or forward data according to their own configuration; treat them like + any other software you install. +

+
+
+

+ Responsibility +

+

+ You choose the bot, models, skills, and tools. This policy describes how Pengine is + designed to run locally; it does not replace Telegram’s, your host OS’s, or your + inference provider’s policies. For exact storage and startup behavior, see the project + documentation in the repository. +

+
+
+
+ +
+

About the app

+

+ Pengine is a local AI agent runtime: it connects your Telegram bot to Ollama (or + compatible inference) so conversations and tools run on your hardware. The project is open + source; see the GitHub repository above for license and source code. +

+ {appVersion ? ( +

+ Reported app version: v{appVersion} +

+ ) : null} +
+
+ ); +} diff --git a/src/shared/runtimeTarget.ts b/src/shared/runtimeTarget.ts new file mode 100644 index 0000000..7e53a1d --- /dev/null +++ b/src/shared/runtimeTarget.ts @@ -0,0 +1,19 @@ +/** + * Detect the Tauri desktop/webview shell. Static marketing builds (e.g. Docker) run in a normal + * browser with no Tauri globals. + */ +export function isTauriApp(): boolean { + if (typeof window === "undefined") return false; + const w = window as Window & { __TAURI_INTERNALS__?: object; isTauri?: boolean }; + return Boolean(w.__TAURI_INTERNALS__ ?? w.isTauri); +} + +/** + * “Marketing” shell: any normal browser (dev or prod) without Tauri — only landing + about. + * Set `VITE_ENABLE_APP_ROUTES_IN_BROWSER=true` to expose setup/dashboard/settings in a browser + * (used by Playwright; optional for local UI testing without the desktop shell). + */ +export function isMarketingWebsite(): boolean { + if (isTauriApp()) return false; + return import.meta.env.VITE_ENABLE_APP_ROUTES_IN_BROWSER !== "true"; +} diff --git a/src/shared/ui/TopMenu.tsx b/src/shared/ui/TopMenu.tsx index 7689f2d..5969efe 100644 --- a/src/shared/ui/TopMenu.tsx +++ b/src/shared/ui/TopMenu.tsx @@ -2,17 +2,22 @@ import * as Menubar from "@radix-ui/react-menubar"; import { useState } from "react"; import { Link, useLocation } from "react-router-dom"; import { useAppSessionStore } from "../../modules/bot/store/appSessionStore"; +import { isMarketingWebsite } from "../runtimeTarget"; -const navLinks = [ +const appNavLinks = [ { label: "Home", to: "/" }, { label: "Dashboard", to: "/dashboard" }, { label: "Settings", to: "/settings" }, ]; +const marketingNavLinks = [{ label: "Home", to: "/" }]; + export function TopMenu() { const location = useLocation(); + const marketingSite = isMarketingWebsite(); + const navLinks = marketingSite ? marketingNavLinks : appNavLinks; const isDeviceConnected = useAppSessionStore((s) => s.isDeviceConnected); - const showOpenSetup = !isDeviceConnected && location.pathname !== "/setup"; + const showOpenSetup = !marketingSite && !isDeviceConnected && location.pathname !== "/setup"; const [mobileOpen, setMobileOpen] = useState(false); const isOnSetup = location.pathname === "/setup"; @@ -118,13 +123,15 @@ export function TopMenu() { })} -

- {isOnSetup ? "Setup in progress" : "Runtime dashboard"} -

+ {!marketingSite && ( +

+ {isOnSetup ? "Setup in progress" : "Runtime dashboard"} +

+ )}
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 5252099..08aab1b 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -3,6 +3,8 @@ interface ImportMetaEnv { /** Production site URL (see `.env.production`). */ readonly VITE_APP_ORIGIN?: string; + /** When `"true"`, allow /setup, /dashboard, /settings in a normal browser (e.g. E2E). */ + readonly VITE_ENABLE_APP_ROUTES_IN_BROWSER?: string; } interface ImportMeta {