UI: remove dead control UI modules
This commit is contained in:
parent
0385553918
commit
5eea523f39
18
pnpm-lock.yaml
generated
18
pnpm-lock.yaml
generated
@ -625,12 +625,6 @@ importers:
|
||||
|
||||
ui:
|
||||
dependencies:
|
||||
'@lit-labs/signals':
|
||||
specifier: ^0.2.0
|
||||
version: 0.2.0
|
||||
'@lit/context':
|
||||
specifier: ^1.1.6
|
||||
version: 1.1.6
|
||||
'@noble/ed25519':
|
||||
specifier: 3.0.1
|
||||
version: 3.0.1
|
||||
@ -643,15 +637,6 @@ importers:
|
||||
marked:
|
||||
specifier: ^17.0.4
|
||||
version: 17.0.4
|
||||
signal-polyfill:
|
||||
specifier: ^0.2.2
|
||||
version: 0.2.2
|
||||
signal-utils:
|
||||
specifier: ^0.21.1
|
||||
version: 0.21.1(signal-polyfill@0.2.2)
|
||||
vite:
|
||||
specifier: 8.0.0
|
||||
version: 8.0.0(@types/node@25.5.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)
|
||||
devDependencies:
|
||||
'@vitest/browser-playwright':
|
||||
specifier: 4.1.0
|
||||
@ -662,6 +647,9 @@ importers:
|
||||
playwright:
|
||||
specifier: ^1.58.2
|
||||
version: 1.58.2
|
||||
vite:
|
||||
specifier: 8.0.0
|
||||
version: 8.0.0(@types/node@25.5.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)
|
||||
vitest:
|
||||
specifier: 4.1.0
|
||||
version: 4.1.0(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(@vitest/browser-playwright@4.1.0)(jsdom@29.0.0(@noble/hashes@2.0.1))(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))
|
||||
|
||||
@ -9,20 +9,16 @@
|
||||
"test": "vitest run --config vitest.config.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@lit-labs/signals": "^0.2.0",
|
||||
"@lit/context": "^1.1.6",
|
||||
"@noble/ed25519": "3.0.1",
|
||||
"dompurify": "^3.3.3",
|
||||
"lit": "^3.3.2",
|
||||
"marked": "^17.0.4",
|
||||
"signal-polyfill": "^0.2.2",
|
||||
"signal-utils": "^0.21.1",
|
||||
"vite": "8.0.0"
|
||||
"marked": "^17.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitest/browser-playwright": "4.1.0",
|
||||
"jsdom": "^29.0.0",
|
||||
"playwright": "^1.58.2",
|
||||
"vite": "8.0.0",
|
||||
"vitest": "4.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -249,6 +249,7 @@
|
||||
|
||||
.topnav-shell__content {
|
||||
display: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.topbar-nav-toggle {
|
||||
@ -650,75 +651,3 @@
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===========================================
|
||||
Bottom Tabs (mobile navigation bar)
|
||||
=========================================== */
|
||||
|
||||
.bottom-tabs {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.bottom-tabs {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 60;
|
||||
background: var(--bg);
|
||||
border-top: 1px solid var(--border);
|
||||
padding: 4px 0 calc(4px + env(safe-area-inset-bottom, 0px));
|
||||
justify-content: space-around;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.bottom-tab {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
flex: 1;
|
||||
padding: 6px 4px;
|
||||
border: none;
|
||||
background: none;
|
||||
color: var(--muted);
|
||||
font-size: 10px;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
color var(--duration-fast) ease,
|
||||
opacity var(--duration-fast) ease;
|
||||
}
|
||||
|
||||
.bottom-tab__icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.bottom-tab__icon svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
stroke: currentColor;
|
||||
fill: none;
|
||||
stroke-width: 1.5px;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
.bottom-tab__label {
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
.bottom-tab--active {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.bottom-tab:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1 +0,0 @@
|
||||
export { exportChatMarkdown } from "./chat/export.ts";
|
||||
@ -1,45 +0,0 @@
|
||||
export const MOONSHOT_KIMI_K2_DEFAULT_ID = "kimi-k2.5";
|
||||
export const MOONSHOT_KIMI_K2_CONTEXT_WINDOW = 256000;
|
||||
export const MOONSHOT_KIMI_K2_MAX_TOKENS = 8192;
|
||||
export const MOONSHOT_KIMI_K2_INPUT = ["text"] as const;
|
||||
export const MOONSHOT_KIMI_K2_COST = {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
} as const;
|
||||
|
||||
export const MOONSHOT_KIMI_K2_MODELS = [
|
||||
{
|
||||
id: "kimi-k2.5",
|
||||
name: "Kimi K2.5",
|
||||
alias: "Kimi K2.5",
|
||||
reasoning: false,
|
||||
},
|
||||
{
|
||||
id: "kimi-k2-0905-preview",
|
||||
name: "Kimi K2 0905 Preview",
|
||||
alias: "Kimi K2",
|
||||
reasoning: false,
|
||||
},
|
||||
{
|
||||
id: "kimi-k2-turbo-preview",
|
||||
name: "Kimi K2 Turbo",
|
||||
alias: "Kimi K2 Turbo",
|
||||
reasoning: false,
|
||||
},
|
||||
{
|
||||
id: "kimi-k2-thinking",
|
||||
name: "Kimi K2 Thinking",
|
||||
alias: "Kimi K2 Thinking",
|
||||
reasoning: true,
|
||||
},
|
||||
{
|
||||
id: "kimi-k2-thinking-turbo",
|
||||
name: "Kimi K2 Thinking Turbo",
|
||||
alias: "Kimi K2 Thinking Turbo",
|
||||
reasoning: true,
|
||||
},
|
||||
] as const;
|
||||
|
||||
export type MoonshotKimiK2Model = (typeof MOONSHOT_KIMI_K2_MODELS)[number];
|
||||
@ -1,39 +0,0 @@
|
||||
/**
|
||||
* Map raw tool names to human-friendly labels for the chat UI.
|
||||
* Unknown tools are title-cased with underscores replaced by spaces.
|
||||
*/
|
||||
|
||||
export const TOOL_LABELS: Record<string, string> = {
|
||||
exec: "Run Command",
|
||||
bash: "Run Command",
|
||||
read: "Read File",
|
||||
write: "Write File",
|
||||
edit: "Edit File",
|
||||
apply_patch: "Apply Patch",
|
||||
web_search: "Web Search",
|
||||
web_fetch: "Fetch Page",
|
||||
browser: "Browser",
|
||||
message: "Send Message",
|
||||
image: "Generate Image",
|
||||
canvas: "Canvas",
|
||||
cron: "Cron",
|
||||
gateway: "Gateway",
|
||||
nodes: "Nodes",
|
||||
memory_search: "Search Memory",
|
||||
memory_get: "Get Memory",
|
||||
session_status: "Session Status",
|
||||
sessions_list: "List Sessions",
|
||||
sessions_history: "Session History",
|
||||
sessions_send: "Send to Session",
|
||||
sessions_spawn: "Spawn Session",
|
||||
agents_list: "List Agents",
|
||||
};
|
||||
|
||||
export function friendlyToolName(raw: string): string {
|
||||
const mapped = TOOL_LABELS[raw];
|
||||
if (mapped) {
|
||||
return mapped;
|
||||
}
|
||||
// Title-case fallback: "some_tool_name" → "Some Tool Name"
|
||||
return raw.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
import { html } from "lit";
|
||||
import { icons } from "../icons.ts";
|
||||
import type { Tab } from "../navigation.ts";
|
||||
|
||||
export type BottomTabsProps = {
|
||||
activeTab: Tab;
|
||||
onTabChange: (tab: Tab) => void;
|
||||
};
|
||||
|
||||
const BOTTOM_TABS: Array<{ id: Tab; label: string; icon: keyof typeof icons }> = [
|
||||
{ id: "overview", label: "Dashboard", icon: "barChart" },
|
||||
{ id: "chat", label: "Chat", icon: "messageSquare" },
|
||||
{ id: "sessions", label: "Sessions", icon: "fileText" },
|
||||
{ id: "config", label: "Settings", icon: "settings" },
|
||||
];
|
||||
|
||||
export function renderBottomTabs(props: BottomTabsProps) {
|
||||
return html`
|
||||
<nav class="bottom-tabs">
|
||||
${BOTTOM_TABS.map(
|
||||
(tab) => html`
|
||||
<button
|
||||
class="bottom-tab ${props.activeTab === tab.id ? "bottom-tab--active" : ""}"
|
||||
@click=${() => props.onTabChange(tab.id)}
|
||||
>
|
||||
<span class="bottom-tab__icon">${icons[tab.icon]}</span>
|
||||
<span class="bottom-tab__label">${tab.label}</span>
|
||||
</button>
|
||||
`,
|
||||
)}
|
||||
</nav>
|
||||
`;
|
||||
}
|
||||
@ -1,50 +0,0 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
appendTagFilter,
|
||||
getTagFilters,
|
||||
hasTagFilter,
|
||||
removeTagFilter,
|
||||
replaceTagFilters,
|
||||
toggleTagFilter,
|
||||
} from "./config-search.ts";
|
||||
|
||||
describe("config search tag helper", () => {
|
||||
it("adds a tag when query is empty", () => {
|
||||
expect(appendTagFilter("", "security")).toBe("tag:security");
|
||||
});
|
||||
|
||||
it("appends a tag to existing text query", () => {
|
||||
expect(appendTagFilter("token", "security")).toBe("token tag:security");
|
||||
});
|
||||
|
||||
it("deduplicates existing tag filters case-insensitively", () => {
|
||||
expect(appendTagFilter("token tag:Security", "security")).toBe("token tag:Security");
|
||||
});
|
||||
|
||||
it("detects exact tag terms", () => {
|
||||
expect(hasTagFilter("tag:security token", "security")).toBe(true);
|
||||
expect(hasTagFilter("tag:security-hard token", "security")).toBe(false);
|
||||
});
|
||||
|
||||
it("removes only the selected active tag", () => {
|
||||
expect(removeTagFilter("token tag:security tag:auth", "security")).toBe("token tag:auth");
|
||||
});
|
||||
|
||||
it("toggle removes active tag and keeps text", () => {
|
||||
expect(toggleTagFilter("token tag:security", "security")).toBe("token");
|
||||
});
|
||||
|
||||
it("toggle adds missing tag", () => {
|
||||
expect(toggleTagFilter("token", "channels")).toBe("token tag:channels");
|
||||
});
|
||||
|
||||
it("extracts unique normalized tags from query", () => {
|
||||
expect(getTagFilters("token tag:Security tag:auth tag:security")).toEqual(["security", "auth"]);
|
||||
});
|
||||
|
||||
it("replaces only tag filters and preserves free text", () => {
|
||||
expect(replaceTagFilters("token tag:security mode", ["auth", "channels"])).toBe(
|
||||
"token mode tag:auth tag:channels",
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -1,92 +0,0 @@
|
||||
function escapeRegExp(value: string): string {
|
||||
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
}
|
||||
|
||||
function normalizeTag(tag: string): string {
|
||||
return tag.trim().toLowerCase();
|
||||
}
|
||||
|
||||
export function getTagFilters(query: string): string[] {
|
||||
const seen = new Set<string>();
|
||||
const tags: string[] = [];
|
||||
const pattern = /(^|\s)tag:([^\s]+)/gi;
|
||||
const raw = query.trim();
|
||||
let match: RegExpExecArray | null = pattern.exec(raw);
|
||||
while (match) {
|
||||
const normalized = normalizeTag(match[2] ?? "");
|
||||
if (normalized && !seen.has(normalized)) {
|
||||
seen.add(normalized);
|
||||
tags.push(normalized);
|
||||
}
|
||||
match = pattern.exec(raw);
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
export function hasTagFilter(query: string, tag: string): boolean {
|
||||
const normalizedTag = normalizeTag(tag);
|
||||
if (!normalizedTag) {
|
||||
return false;
|
||||
}
|
||||
const pattern = new RegExp(`(^|\\s)tag:${escapeRegExp(normalizedTag)}(?=\\s|$)`, "i");
|
||||
return pattern.test(query.trim());
|
||||
}
|
||||
|
||||
export function appendTagFilter(query: string, tag: string): string {
|
||||
const normalizedTag = normalizeTag(tag);
|
||||
const trimmed = query.trim();
|
||||
if (!normalizedTag) {
|
||||
return trimmed;
|
||||
}
|
||||
if (!trimmed) {
|
||||
return `tag:${normalizedTag}`;
|
||||
}
|
||||
if (hasTagFilter(trimmed, normalizedTag)) {
|
||||
return trimmed;
|
||||
}
|
||||
return `${trimmed} tag:${normalizedTag}`;
|
||||
}
|
||||
|
||||
export function removeTagFilter(query: string, tag: string): string {
|
||||
const normalizedTag = normalizeTag(tag);
|
||||
const trimmed = query.trim();
|
||||
if (!normalizedTag || !trimmed) {
|
||||
return trimmed;
|
||||
}
|
||||
const pattern = new RegExp(`(^|\\s)tag:${escapeRegExp(normalizedTag)}(?=\\s|$)`, "ig");
|
||||
return trimmed.replace(pattern, " ").replace(/\s+/g, " ").trim();
|
||||
}
|
||||
|
||||
export function replaceTagFilters(query: string, tags: readonly string[]): string {
|
||||
const uniqueTags: string[] = [];
|
||||
const seen = new Set<string>();
|
||||
for (const tag of tags) {
|
||||
const normalized = normalizeTag(tag);
|
||||
if (!normalized || seen.has(normalized)) {
|
||||
continue;
|
||||
}
|
||||
seen.add(normalized);
|
||||
uniqueTags.push(normalized);
|
||||
}
|
||||
|
||||
const trimmed = query.trim();
|
||||
const withoutTags = trimmed
|
||||
.replace(/(^|\s)tag:([^\s]+)/gi, " ")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
const tagTokens = uniqueTags.map((tag) => `tag:${tag}`).join(" ");
|
||||
if (withoutTags && tagTokens) {
|
||||
return `${withoutTags} ${tagTokens}`;
|
||||
}
|
||||
if (withoutTags) {
|
||||
return withoutTags;
|
||||
}
|
||||
return tagTokens;
|
||||
}
|
||||
|
||||
export function toggleTagFilter(query: string, tag: string): string {
|
||||
if (hasTagFilter(query, tag)) {
|
||||
return removeTagFilter(query, tag);
|
||||
}
|
||||
return appendTagFilter(query, tag);
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
import { html } from "lit";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { icons } from "../icons.ts";
|
||||
|
||||
export type OverviewQuickActionsProps = {
|
||||
onNavigate: (tab: string) => void;
|
||||
onRefresh: () => void;
|
||||
};
|
||||
|
||||
export function renderOverviewQuickActions(props: OverviewQuickActionsProps) {
|
||||
return html`
|
||||
<section class="ov-quick-actions">
|
||||
<button class="btn ov-quick-action-btn" @click=${() => props.onNavigate("chat")}>
|
||||
<span class="nav-item__icon">${icons.messageSquare}</span>
|
||||
${t("overview.quickActions.newSession")}
|
||||
</button>
|
||||
<button class="btn ov-quick-action-btn" @click=${() => props.onNavigate("cron")}>
|
||||
<span class="nav-item__icon">${icons.zap}</span>
|
||||
${t("overview.quickActions.automation")}
|
||||
</button>
|
||||
<button class="btn ov-quick-action-btn" @click=${() => props.onRefresh()}>
|
||||
<span class="nav-item__icon">${icons.loader}</span>
|
||||
${t("overview.quickActions.refreshAll")}
|
||||
</button>
|
||||
<button class="btn ov-quick-action-btn" @click=${() => props.onNavigate("sessions")}>
|
||||
<span class="nav-item__icon">${icons.monitor}</span>
|
||||
${t("overview.quickActions.terminal")}
|
||||
</button>
|
||||
</section>
|
||||
`;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user