惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
V2EX
J
Java Code Geeks
月光博客
月光博客
博客园_首页
The GitHub Blog
The GitHub Blog
Vercel News
Vercel News
B
Blog RSS Feed
博客园 - 聂微东
宝玉的分享
宝玉的分享
T
Tailwind CSS Blog
Jina AI
Jina AI
S
SegmentFault 最新的问题
B
Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
有赞技术团队
有赞技术团队
Hugging Face - Blog
Hugging Face - Blog
Google DeepMind News
Google DeepMind News
阮一峰的网络日志
阮一峰的网络日志
The Cloudflare Blog
量子位
Martin Fowler
Martin Fowler
博客园 - Franky
大猫的无限游戏
大猫的无限游戏
博客园 - 叶小钗

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
refactor(ui): dedupe usage menu close handler · openclaw/...
vincentkoc · 2026-06-18 · via Recent Commits to openclaw:main
Original file line numberDiff line numberDiff line change

@@ -135,6 +135,21 @@ function renderUsageEmptyState(onRefresh: () => void) {

135135

`;

136136

}

137137
138+

function closeDetailsOnOutsideClick(e: Event) {

139+

const el = e.currentTarget as HTMLDetailsElement;

140+

if (!el.open) {

141+

return;

142+

}

143+

const onClick = (ev: MouseEvent) => {

144+

const path = ev.composedPath();

145+

if (!path.includes(el)) {

146+

el.open = false;

147+

window.removeEventListener("click", onClick, true);

148+

}

149+

};

150+

window.addEventListener("click", onClick, true);

151+

}

152+
138153

export function renderUsage(props: UsageProps) {

139154

const { data, filters, display, detail, callbacks } = props;

140155

const filterActions = callbacks.filters;

@@ -368,23 +383,7 @@ export function renderUsage(props: UsageProps) {

368383

options.length > 0 && options.every((value) => selectedSet.has(normalizeQueryText(value)));

369384

const selectedCount = selected.length;

370385

return html`

371-

<details

372-

class="usage-filter-select"

373-

@toggle=${(e: Event) => {

374-

const el = e.currentTarget as HTMLDetailsElement;

375-

if (!el.open) {

376-

return;

377-

}

378-

const onClick = (ev: MouseEvent) => {

379-

const path = ev.composedPath();

380-

if (!path.includes(el)) {

381-

el.open = false;

382-

window.removeEventListener("click", onClick, true);

383-

}

384-

};

385-

window.addEventListener("click", onClick, true);

386-

}}

387-

>

386+

<details class="usage-filter-select" @toggle=${closeDetailsOnOutsideClick}>

388387

<summary>

389388

<span>${label}</span>

390389

${selectedCount > 0

@@ -517,23 +516,7 @@ export function renderUsage(props: UsageProps) {

517516

>

518517

${display.headerPinned ? t("usage.filters.pinned") : t("usage.filters.pin")}

519518

</button>

520-

<details

521-

class="usage-export-menu"

522-

@toggle=${(e: Event) => {

523-

const el = e.currentTarget as HTMLDetailsElement;

524-

if (!el.open) {

525-

return;

526-

}

527-

const onClick = (ev: MouseEvent) => {

528-

const path = ev.composedPath();

529-

if (!path.includes(el)) {

530-

el.open = false;

531-

window.removeEventListener("click", onClick, true);

532-

}

533-

};

534-

window.addEventListener("click", onClick, true);

535-

}}

536-

>

519+

<details class="usage-export-menu" @toggle=${closeDetailsOnOutsideClick}>

537520

<summary class="btn btn--sm">${t("usage.export.label")}</summary>

538521

<div class="usage-export-popover">

539522

<div class="usage-export-list">