Repository navigation
feat(web-ui): claude local bridge, share command, session utilization & UI improvements #166
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
564d27b
a9e567a
7e13a4e
2701016
ae446ef
12b3038
b839fc4
3d896b2
4ca5164
707462f
cde92c3
c746613
9c3e6c9
55322e5
db99a4f
2bac697
3ea1e0d
b43af44
82123ea
dec373a
58999a5
75ad600
e3854bf
3f54c4b
f9011e0
6a5b08f
655b04e
32489f5
5b4ee20
dd28a6b
52d577f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,6 +27,18 @@ function formatCompactUsageSummaryNumber(value) { | |
| }).format(Math.floor(numeric)); | ||
| } | ||
|
|
||
| function formatSignedUsageSummaryNumber(value) { | ||
| const numeric = Number(value); | ||
| if (!Number.isFinite(numeric)) { | ||
| return '0'; | ||
| } | ||
| const abs = Math.floor(Math.abs(numeric)); | ||
| const formatted = abs.toLocaleString('en-US'); | ||
| if (numeric > 0) return `+${formatted}`; | ||
| if (numeric < 0) return `-${formatted}`; | ||
| return '0'; | ||
| } | ||
|
|
||
| function formatUsageRangeLabel(range, t) { | ||
| const normalized = typeof range === 'string' ? range.trim().toLowerCase() : '7d'; | ||
| if (typeof t === 'function') { | ||
|
|
@@ -571,6 +583,7 @@ export function createSessionComputed() { | |
| tokenPercent: maxTokens > 0 ? Math.round((row.tokenTotal / maxTokens) * 1000) / 10 : 0, | ||
| prevTokenPercent: row.compareEnabled && maxTokens > 0 ? Math.round(((row.prevTokenTotal || 0) / maxTokens) * 1000) / 10 : 0, | ||
| prevTokenTitle: row.compareEnabled ? formatUsageSummaryNumber(row.prevTokenTotal || 0) : '', | ||
| prevCostTitle: row.compareEnabled ? formatUsageSummaryNumber(row.prevTokenTotal || 0) : '', | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Description: Search for usage of prevCostTitle to understand its purpose
# Search for prevCostTitle usage in templates and code
rg -n 'prevCostTitle' --type=html --type=js --type=vue -C3Repository: SakuraByteCore/codexmate Length of output: 96 🏁 Script executed: #!/bin/bash
# Search for prevCostTitle without vue type
rg -n 'prevCostTitle' -C3
# Also search for the file to confirm path
find . -name "app.computed.session.mjs" -type fRepository: SakuraByteCore/codexmate Length of output: 1909 🏁 Script executed: #!/bin/bash
# Read the file around line 586 to see context
# First, get file info
file_path=$(find . -name "app.computed.session.mjs" -type f)
if [ -n "$file_path" ]; then
# Show lines 570-600 to get context
sed -n '570,600p' "$file_path" | cat -n
fiRepository: SakuraByteCore/codexmate Length of output: 1887 🏁 Script executed: #!/bin/bash
# Search for how prevCostTitle and prevTokenTitle are used in templates
rg -n 'prevToken|prevCost' -t html -t js -C2Repository: SakuraByteCore/codexmate Length of output: 2888 🏁 Script executed: #!/bin/bash
# Search for prevCostTitle in all files, especially templates
rg -n 'prevCostTitle' -C5
# Also search for cost-related fields to see if actual cost calculation exists
rg -n 'prevCost|costTotal|cost' --type=js --type=html -i | head -50Repository: SakuraByteCore/codexmate Length of output: 3298 🏁 Script executed: #!/bin/bash
# Search for tooltip usage patterns to understand how prevCostTitle is consumed
rg -n 'tooltip|title=' web-ui/partials/ -C2 | head -80Repository: SakuraByteCore/codexmate Length of output: 11257 🏁 Script executed: #!/bin/bash
# Search for where prevTokenTitle is referenced/used
rg -n 'prevTokenTitle|prevCostTitle' -t js -t html -A2 -B2
# Also search for usage of day.tokenTitle or similar to understand the pattern
rg -n '\.tokenTitle|day\.token' web-ui/partials/ -C3Repository: SakuraByteCore/codexmate Length of output: 2017 Remove or rename Line 586 defines
Either remove the field or correct the naming to 🤖 Prompt for AI Agents |
||
| })), | ||
| maxTokens, | ||
| }; | ||
|
|
@@ -688,6 +701,35 @@ export function createSessionComputed() { | |
| return Math.max(0, Math.floor(totalCount)); | ||
| } | ||
| return Array.isArray(this.sessionTrashItems) ? this.sessionTrashItems.length : 0; | ||
| }, | ||
|
|
||
| sessionContextUtilization() { | ||
| const list = Array.isArray(this.sessionsList) ? this.sessionsList : []; | ||
| const utilizationMap = {}; | ||
| for (const session of list) { | ||
| if (!session || typeof session !== 'object') continue; | ||
| const key = this.getSessionExportKey(session); | ||
| if (!key) continue; | ||
| const totalTokens = Number.isFinite(Number(session.totalTokens)) | ||
| ? Math.max(0, Math.floor(Number(session.totalTokens))) | ||
| : 0; | ||
| const contextWindow = Number.isFinite(Number(session.contextWindow)) | ||
| ? Math.max(0, Math.floor(Number(session.contextWindow))) | ||
| : 0; | ||
| if (contextWindow <= 0) { | ||
| utilizationMap[key] = { percent: 0, level: 'normal' }; | ||
| continue; | ||
| } | ||
| const percent = Math.min(100, Math.round((totalTokens / contextWindow) * 100)); | ||
| let level = 'normal'; | ||
| if (percent >= 95) { | ||
| level = 'critical'; | ||
| } else if (percent >= 80) { | ||
| level = 'warning'; | ||
| } | ||
| utilizationMap[key] = { percent, level }; | ||
| } | ||
| return utilizationMap; | ||
| } | ||
| }; | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -122,7 +122,7 @@ | |||||||||||||||||
| <button class="card-action-btn" @click="openCloneClaudeConfigModal(name, config)" :aria-label="t('claude.action.cloneAria', { name })" :title="t('claude.action.clone')"> | ||||||||||||||||||
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg> | ||||||||||||||||||
| </button> | ||||||||||||||||||
| <button class="card-action-btn" :class="{ loading: claudeShareLoading[name] }" @click="copyClaudeShareCommand(name)" disabled :title="t('claude.action.shareDisabled')" :aria-label="t('config.shareCommand.aria')"> | ||||||||||||||||||
| <button class="card-action-btn" :class="{ loading: claudeShareLoading[name] }" @click="copyClaudeShareCommand(name)" :title="t('config.shareCommand')" :aria-label="t('config.shareCommand.aria')"> | ||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Disable the share button while loading to prevent duplicate actions. Line 125 applies a loading class but still allows repeated clicks while Proposed fix-<button class="card-action-btn" :class="{ loading: claudeShareLoading[name] }" `@click`="copyClaudeShareCommand(name)" :title="t('config.shareCommand')" :aria-label="t('config.shareCommand.aria')">
+<button
+ class="card-action-btn"
+ :class="{ loading: claudeShareLoading[name] }"
+ :disabled="claudeShareLoading[name]"
+ `@click`="copyClaudeShareCommand(name)"
+ :title="t('config.shareCommand')"
+ :aria-label="t('config.shareCommand.aria')">📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 12v7a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-7"/><path d="M16 6l-4-4-4 4"/><path d="M12 2v14"/></svg> | ||||||||||||||||||
| </button> | ||||||||||||||||||
| <button class="card-action-btn delete" @click="deleteClaudeConfig(name)" :aria-label="t('claude.action.deleteAria', { name })" :title="t('claude.action.delete')"> | ||||||||||||||||||
|
|
||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strengthen this assertion to prove the button is actually enabled.
This regex still passes when
disabled/:disabledis present, so it doesn’t validate the PR’s core behavior (interactive share button). Add a targeted negative check on the matched markup (and ideally assert updated aria/title bindings too).Suggested test hardening
📝 Committable suggestion
🤖 Prompt for AI Agents