feat: add Web App Port management alongside API Server Port and fix square 512x512 app launcher icon

This commit is contained in:
Schwitzz
2026-10-30 14:23:12 -05:00
parent 1d209fedd2
commit 29dbc27c41
6 changed files with 161 additions and 18 deletions
+9 -9
View File
@@ -1,4 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 112 512 288" width="512" height="288" role="img" aria-label="PubScript">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512" preserveAspectRatio="xMidYMid meet" role="img" aria-label="PubScript">
<defs>
<linearGradient id="ps-gold" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#f9edc4"/>
@@ -19,18 +19,18 @@
<g filter="url(#ps-shadow)">
<!-- P tile -->
<circle cx="126" cy="256" r="120" fill="url(#ps-gold)"/>
<circle cx="126" cy="256" r="104" fill="url(#ps-ivory)"/>
<circle cx="126" cy="256" r="104" fill="none" stroke="#8a6d1c" stroke-width="1.5" opacity="0.5"/>
<text x="126" y="256" text-anchor="middle" dominant-baseline="central"
<circle cx="132" cy="256" r="120" fill="url(#ps-gold)"/>
<circle cx="132" cy="256" r="104" fill="url(#ps-ivory)"/>
<circle cx="132" cy="256" r="104" fill="none" stroke="#8a6d1c" stroke-width="1.5" opacity="0.5"/>
<text x="132" y="256" text-anchor="middle" dominant-baseline="central"
font-family="Georgia, 'Times New Roman', serif" font-size="152" font-weight="600"
fill="#21242c">P</text>
<!-- S tile -->
<circle cx="386" cy="256" r="120" fill="url(#ps-gold)"/>
<circle cx="386" cy="256" r="104" fill="url(#ps-ivory)"/>
<circle cx="386" cy="256" r="104" fill="none" stroke="#8a6d1c" stroke-width="1.5" opacity="0.5"/>
<text x="386" y="256" text-anchor="middle" dominant-baseline="central"
<circle cx="380" cy="256" r="120" fill="url(#ps-gold)"/>
<circle cx="380" cy="256" r="104" fill="url(#ps-ivory)"/>
<circle cx="380" cy="256" r="104" fill="none" stroke="#8a6d1c" stroke-width="1.5" opacity="0.5"/>
<text x="380" y="256" text-anchor="middle" dominant-baseline="central"
font-family="Georgia, 'Times New Roman', serif" font-size="152" font-weight="600"
fill="#21242c">S</text>
</g>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

+15
View File
@@ -372,6 +372,8 @@ export const api = {
enabled: boolean;
port: number;
activePort?: number;
webPort?: number;
activeWebPort?: number;
startOnBoot: boolean;
projectDirectory?: string;
}> => {
@@ -388,6 +390,8 @@ export const api = {
enabled: boolean;
port: number;
activePort?: number;
webPort?: number;
activeWebPort?: number;
startOnBoot: boolean;
projectDirectory?: string;
};
@@ -396,6 +400,8 @@ export const api = {
enabled: data.enabled,
port: data.port,
...(data.activePort !== undefined ? { activePort: data.activePort } : {}),
...(data.webPort !== undefined ? { webPort: data.webPort } : {}),
...(data.activeWebPort !== undefined ? { activeWebPort: data.activeWebPort } : {}),
startOnBoot: data.startOnBoot,
...(data.projectDirectory ? { projectDirectory: data.projectDirectory } : {}),
};
@@ -408,6 +414,7 @@ export const api = {
online: false,
enabled: true,
port: portHint ?? 8081,
webPort: 5173,
startOnBoot: false,
};
},
@@ -416,6 +423,7 @@ export const api = {
patch: {
enabled?: boolean;
port?: number;
webPort?: number;
startOnBoot?: boolean;
projectDirectory?: string;
},
@@ -425,6 +433,8 @@ export const api = {
enabled: boolean;
port: number;
activePort?: number;
webPort?: number;
activeWebPort?: number;
startOnBoot: boolean;
projectDirectory?: string;
}> => {
@@ -446,6 +456,8 @@ export const api = {
enabled: boolean;
port: number;
activePort?: number;
webPort?: number;
activeWebPort?: number;
startOnBoot: boolean;
projectDirectory?: string;
};
@@ -454,6 +466,8 @@ export const api = {
enabled: data.enabled,
port: data.port,
...(data.activePort !== undefined ? { activePort: data.activePort } : {}),
...(data.webPort !== undefined ? { webPort: data.webPort } : {}),
...(data.activeWebPort !== undefined ? { activeWebPort: data.activeWebPort } : {}),
startOnBoot: data.startOnBoot,
...(data.projectDirectory ? { projectDirectory: data.projectDirectory } : {}),
};
@@ -466,6 +480,7 @@ export const api = {
online: false,
enabled: patch.enabled ?? true,
port: patch.port ?? portHint ?? 8081,
...(patch.webPort !== undefined ? { webPort: patch.webPort } : {}),
startOnBoot: patch.startOnBoot ?? false,
...(patch.projectDirectory ? { projectDirectory: patch.projectDirectory } : {}),
};
+70 -6
View File
@@ -67,6 +67,7 @@ export function Settings() {
const [probing, setProbing] = useState(false);
// Server & Project Directory state
const [webPortDraft, setWebPortDraft] = useState<string>(String(s.webPort || 5173));
const [portDraft, setPortDraft] = useState<string>(String(s.serverPort));
const [projectDirDraft, setProjectDirDraft] = useState<string>(
s.projectDirectory || "~/Documents/PubScript",
@@ -74,6 +75,7 @@ export function Settings() {
const [browseProjectDirOpen, setBrowseProjectDirOpen] = useState<boolean>(false);
const [serverOnline, setServerOnline] = useState<boolean>(false);
const [activeRunningPort, setActiveRunningPort] = useState<number | null>(null);
const [activeRunningWebPort, setActiveRunningWebPort] = useState<number | null>(null);
const [savingServerCfg, setSavingServerCfg] = useState<boolean>(false);
useEffect(() => {
@@ -82,14 +84,19 @@ export function Settings() {
if (cancelled) return;
setServerOnline(res.online);
setActiveRunningPort(res.activePort ?? res.port);
setActiveRunningWebPort(res.activeWebPort ?? res.webPort ?? s.webPort);
if (res.online) {
setPortDraft(String(res.port));
if (res.webPort) {
setWebPortDraft(String(res.webPort));
}
if (res.projectDirectory) {
setProjectDirDraft(res.projectDirectory);
}
set({
serverEnabled: res.enabled,
serverPort: res.port,
...(res.webPort ? { webPort: res.webPort } : {}),
serverStartOnBoot: res.startOnBoot,
...(res.projectDirectory ? { projectDirectory: res.projectDirectory } : {}),
});
@@ -139,10 +146,28 @@ export function Settings() {
}
};
const handleApplyWebPort = async () => {
const parsed = parseInt(webPortDraft.trim(), 10);
if (Number.isNaN(parsed) || parsed < 1024 || parsed > 65535) {
toast.error("Please enter a valid web app port between 1024 and 65535");
return;
}
set({ webPort: parsed });
setSavingServerCfg(true);
try {
const res = await api.updateServerConfig({ webPort: parsed }, s.serverPort);
setServerOnline(res.online);
setActiveRunningWebPort(res.activeWebPort ?? parsed);
toast.success(`Web App port saved and active on http://localhost:${parsed}`);
} finally {
setSavingServerCfg(false);
}
};
const handleApplyServerPort = async () => {
const parsed = parseInt(portDraft.trim(), 10);
if (Number.isNaN(parsed) || parsed < 1024 || parsed > 65535) {
toast.error("Please enter a valid port between 1024 and 65535");
toast.error("Please enter a valid API server port between 1024 and 65535");
return;
}
set({ serverPort: parsed });
@@ -151,7 +176,7 @@ export function Settings() {
const res = await api.updateServerConfig({ port: parsed }, s.serverPort);
setServerOnline(res.online);
setActiveRunningPort(res.activePort ?? parsed);
toast.success(`Server port saved (${parsed})`);
toast.success(`API Server port saved (${parsed})`);
} finally {
setSavingServerCfg(false);
}
@@ -1004,9 +1029,48 @@ export function Settings() {
<div className="ps-settings-row">
<div>
<div className="ps-settings-label">Server port</div>
<div className="ps-settings-label" style={{ display: "flex", alignItems: "center", gap: 8 }}>
<span>Web App Port</span>
<Badge variant={!s.serverEnabled ? "neutral" : "accent"}>
{`http://localhost:${activeRunningWebPort ?? s.webPort}`}
</Badge>
</div>
<div className="ps-settings-desc">
TCP port for the local/self-hosted PubScript server (1024–65535). Default: 8081 (web) / 18081 (desktop).
TCP port where the PubScript Web App UI is served (1024–65535). Default: 5173. Changing this immediately binds the web UI on the selected port.
</div>
</div>
<div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
<input
type="number"
className="ps-input"
min={1024}
max={65535}
style={{ width: 110 }}
value={webPortDraft}
onChange={(e) => setWebPortDraft(e.target.value)}
aria-label="Web app port"
/>
<Button
variant="secondary"
size="sm"
disabled={savingServerCfg}
onClick={() => void handleApplyWebPort()}
>
Apply Web Port
</Button>
</div>
</div>
<div className="ps-settings-row">
<div>
<div className="ps-settings-label" style={{ display: "flex", alignItems: "center", gap: 8 }}>
<span>API Server Port</span>
<Badge variant={!s.serverEnabled ? "neutral" : serverOnline ? "success" : "warning"}>
{`Port ${activeRunningPort ?? s.serverPort}`}
</Badge>
</div>
<div className="ps-settings-desc">
TCP port for the PubScript API &amp; SQLite server (1024–65535). Default: 8081 (web) / 18081 (desktop).
</div>
</div>
<div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
@@ -1018,7 +1082,7 @@ export function Settings() {
style={{ width: 110 }}
value={portDraft}
onChange={(e) => setPortDraft(e.target.value)}
aria-label="Server port"
aria-label="API server port"
/>
<Button
variant="secondary"
@@ -1026,7 +1090,7 @@ export function Settings() {
disabled={savingServerCfg}
onClick={() => void handleApplyServerPort()}
>
Apply Port
Apply API Port
</Button>
</div>
</div>
+2
View File
@@ -274,6 +274,7 @@ export interface AppSettings {
activeAgentId: string;
// Local / Self-Hosted Server & Startup Settings
serverEnabled: boolean;
webPort: number;
serverPort: number;
serverStartOnBoot: boolean;
}
@@ -309,6 +310,7 @@ export const DEFAULT_SETTINGS: AppSettings = {
activeAgentId: DEFAULT_AI_AGENTS[0]!.id,
// Local / Self-Hosted Server & Startup Settings
serverEnabled: true,
webPort: 5173,
serverPort: 8081,
serverStartOnBoot: false,
};