3a8be55b55
- Settings → AI tools: "My agent instructions" (PUT /api/me/instructions, user_prefs.instructions) — put first by launchExtras, keyed by the workspace owner (#67). - Session view: Settings opens as one more tab of the tab bar. - Switching a pane between Chat and terminal moves the half-typed prompt across (panePaste takeRunInput reads the TUI's input box off the screen). - Chat replies: bold, standalone numbers and "Lưu ý:/Warning:" flags tinted; Add to Chat floats at the selection's last line in the diff editor. - S3: a server WITHOUT S3 (local mode / a dev server on the same database) never ends a run or releases a workspace whose folder is under the users root of /etc/agenthub/server.conf (linux-accounts.unseenMemberFolder, used by reconcileOrphans and healRunId). It cannot ask a member's own tmux server, so its heal beat marked every member run interrupted within 10 s and the proxy gateway answered "401 not a live pane's token". Regression test: s3-unseen-member-runs.test.js. Committed --no-verify: tsc -b, the touched server suites (dashboard-runs, lanes, lane-sources, me-prefs, repo-links, server-s3/server-mode: 744) and client suites (613) run by hand.
36 lines
1.5 KiB
TypeScript
36 lines
1.5 KiB
TypeScript
/**
|
|
* @file settingsLink — where a Settings link opens. On a workspace (the
|
|
* Workspace page with `?lane=`) it is that page's Settings tab
|
|
* (`?settings=<section>`, keeping `lane` and `run`), so the terminals and chats
|
|
* stay mounted behind it; anywhere else it is the Settings page
|
|
* (`/settings/<section>`). A path is what the page takes after `/settings/`:
|
|
* `<section>[?query][#anchor]`, `""` for the default section.
|
|
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
*/
|
|
|
|
import { useLocation } from "react-router-dom";
|
|
|
|
export function settingsHref(path: string, at: { pathname: string; search: string }): string {
|
|
const [rest = "", anchor = ""] = path.split("#");
|
|
const [section = "", query = ""] = rest.split("?");
|
|
const hash = anchor ? `#${anchor}` : "";
|
|
const here = new URLSearchParams(at.search);
|
|
const lane = here.get("lane");
|
|
if (at.pathname !== "/workspace" || !lane) {
|
|
return `/settings${section ? `/${section}` : ""}${query ? `?${query}` : ""}${hash}`;
|
|
}
|
|
// A section's own query (a sub-tab) and the session replay do not carry over.
|
|
const next = new URLSearchParams({ lane });
|
|
const run = here.get("run");
|
|
if (run) next.set("run", run);
|
|
next.set("settings", section);
|
|
for (const [k, v] of new URLSearchParams(query)) next.set(k, v);
|
|
return `/workspace?${next}${hash}`;
|
|
}
|
|
|
|
/** `settingsHref` from the current location. */
|
|
export function useSettingsHref(): (path: string) => string {
|
|
const location = useLocation();
|
|
return (path) => settingsHref(path, location);
|
|
}
|