codexmate 0.0.20 → 0.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +289 -152
- package/README.zh.md +321 -0
- package/cli/agents-files.js +224 -0
- package/cli/archive-helpers.js +446 -0
- package/cli/auth-profiles.js +359 -0
- package/cli/builtin-proxy.js +1044 -0
- package/cli/claude-proxy.js +998 -0
- package/cli/config-bootstrap.js +384 -0
- package/cli/openai-bridge.js +950 -0
- package/cli/openclaw-config.js +629 -0
- package/cli/session-usage.concurrent.js +28 -0
- package/cli/session-usage.js +112 -0
- package/cli/session-usage.models.js +176 -0
- package/cli/skills.js +1141 -0
- package/cli/zip-commands.js +510 -0
- package/cli.js +9408 -9719
- package/lib/cli-models-utils.js +109 -1
- package/lib/cli-path-utils.js +69 -0
- package/lib/cli-sessions.js +386 -0
- package/lib/download-artifacts.js +77 -0
- package/lib/task-orchestrator.js +869 -0
- package/package.json +14 -10
- package/res/logo.png +0 -0
- package/res/vue.global.prod.js +13 -0
- package/web-ui/app.js +193 -15
- package/web-ui/index.html +5 -1
- package/web-ui/logic.agents-diff.mjs +1 -1
- package/web-ui/logic.claude.mjs +60 -0
- package/web-ui/logic.runtime.mjs +11 -7
- package/web-ui/logic.sessions.mjs +372 -21
- package/web-ui/modules/api.mjs +22 -1
- package/web-ui/modules/app.computed.dashboard.mjs +23 -10
- package/web-ui/modules/app.computed.index.mjs +4 -0
- package/web-ui/modules/app.computed.main-tabs.mjs +198 -0
- package/web-ui/modules/app.computed.session.mjs +521 -9
- package/web-ui/modules/app.methods.agents.mjs +62 -11
- package/web-ui/modules/app.methods.codex-config.mjs +189 -34
- package/web-ui/modules/app.methods.index.mjs +7 -1
- package/web-ui/modules/app.methods.install.mjs +24 -20
- package/web-ui/modules/app.methods.navigation.mjs +142 -1
- package/web-ui/modules/app.methods.openclaw-core.mjs +339 -39
- package/web-ui/modules/app.methods.openclaw-editing.mjs +39 -4
- package/web-ui/modules/app.methods.openclaw-persist.mjs +122 -4
- package/web-ui/modules/app.methods.providers.mjs +192 -53
- package/web-ui/modules/app.methods.session-actions.mjs +99 -19
- package/web-ui/modules/app.methods.session-browser.mjs +196 -5
- package/web-ui/modules/app.methods.session-timeline.mjs +22 -15
- package/web-ui/modules/app.methods.session-trash.mjs +3 -0
- package/web-ui/modules/app.methods.startup-claude.mjs +70 -71
- package/web-ui/modules/app.methods.task-orchestration.mjs +471 -0
- package/web-ui/modules/config-mode.computed.mjs +2 -0
- package/web-ui/modules/config-template-confirm-pref.mjs +33 -0
- package/web-ui/modules/i18n.mjs +1609 -0
- package/web-ui/modules/plugins.computed.mjs +220 -0
- package/web-ui/modules/plugins.methods.mjs +620 -0
- package/web-ui/modules/plugins.storage.mjs +37 -0
- package/web-ui/partials/index/layout-footer.html +1 -57
- package/web-ui/partials/index/layout-header.html +299 -175
- package/web-ui/partials/index/modal-config-template-agents.html +79 -29
- package/web-ui/partials/index/modal-confirm-toast.html +1 -1
- package/web-ui/partials/index/modal-health-check.html +14 -14
- package/web-ui/partials/index/modal-openclaw-config.html +47 -42
- package/web-ui/partials/index/modal-skills.html +130 -114
- package/web-ui/partials/index/modals-basic.html +71 -102
- package/web-ui/partials/index/panel-config-claude.html +50 -12
- package/web-ui/partials/index/panel-config-codex.html +34 -37
- package/web-ui/partials/index/panel-config-openclaw.html +10 -16
- package/web-ui/partials/index/panel-docs.html +147 -0
- package/web-ui/partials/index/panel-market.html +38 -38
- package/web-ui/partials/index/panel-orchestration.html +397 -0
- package/web-ui/partials/index/panel-plugins.html +243 -0
- package/web-ui/partials/index/panel-sessions.html +51 -146
- package/web-ui/partials/index/panel-settings.html +188 -96
- package/web-ui/partials/index/panel-usage.html +353 -0
- package/web-ui/session-helpers.mjs +221 -10
- package/web-ui/styles/base-theme.css +120 -229
- package/web-ui/styles/controls-forms.css +59 -51
- package/web-ui/styles/docs-panel.css +247 -0
- package/web-ui/styles/layout-shell.css +394 -128
- package/web-ui/styles/modals-core.css +18 -3
- package/web-ui/styles/navigation-panels.css +184 -183
- package/web-ui/styles/plugins-panel.css +518 -0
- package/web-ui/styles/responsive.css +102 -62
- package/web-ui/styles/sessions-list.css +13 -27
- package/web-ui/styles/sessions-preview.css +13 -7
- package/web-ui/styles/sessions-toolbar-trash.css +25 -0
- package/web-ui/styles/sessions-usage.css +581 -6
- package/web-ui/styles/settings-panel.css +166 -0
- package/web-ui/styles/skills-list.css +16 -11
- package/web-ui/styles/skills-market.css +63 -2
- package/web-ui/styles/task-orchestration.css +776 -0
- package/web-ui/styles/titles-cards.css +67 -66
- package/web-ui/styles.css +4 -0
- package/README.en.md +0 -259
- package/res/screenshot.png +0 -0
- package/res/vue.global.js +0 -18552
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
:aria-labelledby="'tab-sessions'">
|
|
8
8
|
<div v-if="sessionStandalone" class="session-standalone-page">
|
|
9
9
|
<div v-if="sessionStandaloneLoading" class="state-message">
|
|
10
|
-
|
|
10
|
+
{{ t('sessions.loading') }}
|
|
11
11
|
</div>
|
|
12
12
|
<div v-else-if="sessionStandaloneError" class="state-message error">
|
|
13
13
|
{{ sessionStandaloneError }}
|
|
@@ -20,128 +20,30 @@
|
|
|
20
20
|
<pre class="session-standalone-text">{{ sessionStandaloneText }}</pre>
|
|
21
21
|
</div>
|
|
22
22
|
</div>
|
|
23
|
-
|
|
24
23
|
<div v-else>
|
|
25
|
-
<div class="sessions-subtabs" role="tablist" aria-label="会话视图切换">
|
|
26
|
-
<button
|
|
27
|
-
class="sessions-subtab"
|
|
28
|
-
:class="{ active: sessionsViewMode === 'browser' }"
|
|
29
|
-
type="button"
|
|
30
|
-
role="tab"
|
|
31
|
-
:aria-selected="sessionsViewMode === 'browser'"
|
|
32
|
-
@click="sessionsViewMode = 'browser'">
|
|
33
|
-
Sessions
|
|
34
|
-
</button>
|
|
35
|
-
<button
|
|
36
|
-
class="sessions-subtab"
|
|
37
|
-
:class="{ active: sessionsViewMode === 'usage' }"
|
|
38
|
-
type="button"
|
|
39
|
-
role="tab"
|
|
40
|
-
:aria-selected="sessionsViewMode === 'usage'"
|
|
41
|
-
@click="sessionsViewMode = 'usage'">
|
|
42
|
-
Usage
|
|
43
|
-
</button>
|
|
44
|
-
</div>
|
|
45
|
-
|
|
46
|
-
<div v-if="sessionsViewMode === 'usage'">
|
|
47
|
-
<div class="usage-toolbar">
|
|
48
|
-
<div class="selector-header" style="padding:0;border:0;background:none;">
|
|
49
|
-
<span class="selector-title">本地使用概览</span>
|
|
50
|
-
</div>
|
|
51
|
-
<div class="usage-range-group" role="group" aria-label="Usage 时间范围">
|
|
52
|
-
<button type="button" class="usage-range-btn" :class="{ active: sessionsUsageTimeRange === '7d' }" @click="sessionsUsageTimeRange = '7d'">近 7 天</button>
|
|
53
|
-
<button type="button" class="usage-range-btn" :class="{ active: sessionsUsageTimeRange === '30d' }" @click="sessionsUsageTimeRange = '30d'">近 30 天</button>
|
|
54
|
-
</div>
|
|
55
|
-
</div>
|
|
56
|
-
|
|
57
|
-
<div v-if="!sessionsList.length" class="usage-empty">暂无可用于统计的会话数据</div>
|
|
58
|
-
<template v-else>
|
|
59
|
-
<div class="usage-summary-grid">
|
|
60
|
-
<div v-for="card in sessionUsageSummaryCards" :key="card.key" class="usage-summary-card">
|
|
61
|
-
<div class="usage-summary-label">{{ card.label }}</div>
|
|
62
|
-
<div class="usage-summary-value">{{ card.value }}</div>
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
65
|
-
|
|
66
|
-
<div class="usage-chart-grid">
|
|
67
|
-
<section class="usage-card">
|
|
68
|
-
<div class="usage-card-title">会话趋势</div>
|
|
69
|
-
<div class="usage-legend">
|
|
70
|
-
<span><span class="usage-legend-dot" style="background:#4f8cff"></span>Codex</span>
|
|
71
|
-
<span><span class="usage-legend-dot" style="background:#b277ff"></span>Claude</span>
|
|
72
|
-
</div>
|
|
73
|
-
<div class="usage-bars">
|
|
74
|
-
<div v-for="bucket in sessionUsageCharts.buckets" :key="bucket.key" class="usage-bar-group">
|
|
75
|
-
<div class="usage-bar-stack">
|
|
76
|
-
<div class="usage-bar codex" :style="{ height: ((bucket.codex / Math.max(sessionUsageCharts.maxSessionBucket, 1)) * 100) + '%' }" :title="`Codex ${bucket.codex}`"></div>
|
|
77
|
-
<div class="usage-bar claude" :style="{ height: ((bucket.claude / Math.max(sessionUsageCharts.maxSessionBucket, 1)) * 100) + '%' }" :title="`Claude ${bucket.claude}`"></div>
|
|
78
|
-
</div>
|
|
79
|
-
<div class="usage-bar-label">{{ bucket.label }}</div>
|
|
80
|
-
</div>
|
|
81
|
-
</div>
|
|
82
|
-
</section>
|
|
83
|
-
|
|
84
|
-
<section class="usage-card">
|
|
85
|
-
<div class="usage-card-title">来源占比</div>
|
|
86
|
-
<div class="usage-list">
|
|
87
|
-
<div v-for="item in sessionUsageCharts.sourceShare" :key="item.key" class="usage-list-row">
|
|
88
|
-
<div class="usage-list-label">{{ item.label }}</div>
|
|
89
|
-
<div class="usage-progress"><div class="usage-progress-fill" :style="{ width: item.percent + '%' }"></div></div>
|
|
90
|
-
<div class="usage-list-value">{{ item.percent }}%</div>
|
|
91
|
-
</div>
|
|
92
|
-
</div>
|
|
93
|
-
</section>
|
|
94
|
-
|
|
95
|
-
<section class="usage-card">
|
|
96
|
-
<div class="usage-card-title">消息趋势</div>
|
|
97
|
-
<div class="usage-bars">
|
|
98
|
-
<div v-for="bucket in sessionUsageCharts.buckets" :key="bucket.key + '-messages'" class="usage-bar-group">
|
|
99
|
-
<div class="usage-bar-stack">
|
|
100
|
-
<div class="usage-bar codex" style="width:100%" :style="{ height: ((bucket.totalMessages / Math.max(sessionUsageCharts.maxMessageBucket, 1)) * 100) + '%' }" :title="`${bucket.totalMessages} messages`"></div>
|
|
101
|
-
</div>
|
|
102
|
-
<div class="usage-bar-label">{{ bucket.label }}</div>
|
|
103
|
-
</div>
|
|
104
|
-
</div>
|
|
105
|
-
</section>
|
|
106
|
-
|
|
107
|
-
<section class="usage-card">
|
|
108
|
-
<div class="usage-card-title">高频路径</div>
|
|
109
|
-
<div v-if="!sessionUsageCharts.topPaths.length" class="usage-list-value">暂无路径数据</div>
|
|
110
|
-
<div v-else class="usage-list">
|
|
111
|
-
<div v-for="item in sessionUsageCharts.topPaths" :key="item.path" class="usage-list-row">
|
|
112
|
-
<div class="usage-list-label">{{ item.count }} 次</div>
|
|
113
|
-
<div class="usage-progress"><div class="usage-progress-fill" :style="{ width: ((item.count / Math.max(sessionUsageCharts.topPaths[0]?.count || 1, 1)) * 100) + '%' }"></div></div>
|
|
114
|
-
<div class="usage-list-value" :title="item.path">{{ item.path }}</div>
|
|
115
|
-
</div>
|
|
116
|
-
</div>
|
|
117
|
-
</section>
|
|
118
|
-
</div>
|
|
119
|
-
</template>
|
|
120
|
-
</div>
|
|
121
|
-
|
|
122
|
-
<template v-else>
|
|
123
24
|
<div class="selector-section">
|
|
124
25
|
<div class="selector-header">
|
|
125
|
-
<span class="selector-title"
|
|
26
|
+
<span class="selector-title">{{ t('sessions.sourceTitle') }}</span>
|
|
126
27
|
<div class="selector-actions">
|
|
127
|
-
<button class="btn-tool btn-tool-compact" @click="loadSessions" :disabled="sessionsLoading">
|
|
128
|
-
{{ sessionsLoading ? '
|
|
28
|
+
<button class="btn-tool btn-tool-compact" @click="loadSessions({ forceRefresh: true })" :disabled="sessionsLoading">
|
|
29
|
+
{{ sessionsLoading ? t('sessions.refreshing') : t('sessions.refresh') }}
|
|
129
30
|
</button>
|
|
130
31
|
</div>
|
|
131
32
|
</div>
|
|
132
33
|
<div class="session-toolbar">
|
|
133
|
-
<div class="session-toolbar-group">
|
|
34
|
+
<div class="session-toolbar-group session-toolbar-primary">
|
|
134
35
|
<select class="session-source-select" v-model="sessionFilterSource" @change="onSessionSourceChange" :disabled="sessionsLoading">
|
|
135
|
-
<option value="all"
|
|
136
|
-
<option value="codex">
|
|
137
|
-
<option value="claude">
|
|
36
|
+
<option value="all">{{ t('common.all') }}</option>
|
|
37
|
+
<option value="codex">{{ t('sessions.source.codex') }}</option>
|
|
38
|
+
<option value="claude">{{ t('sessions.source.claudeCode') }}</option>
|
|
138
39
|
</select>
|
|
139
40
|
<select
|
|
140
41
|
class="session-path-select"
|
|
141
42
|
v-model="sessionPathFilter"
|
|
142
43
|
@change="onSessionPathFilterChange"
|
|
44
|
+
@focus="loadSessionPathOptions({ source: sessionFilterSource })"
|
|
143
45
|
:disabled="sessionsLoading">
|
|
144
|
-
<option value=""
|
|
46
|
+
<option value="">{{ t('sessions.allPaths') }}</option>
|
|
145
47
|
<option v-for="cwd in sessionPathOptions" :key="cwd" :value="cwd">{{ cwd }}</option>
|
|
146
48
|
</select>
|
|
147
49
|
</div>
|
|
@@ -153,26 +55,26 @@
|
|
|
153
55
|
:disabled="sessionsLoading || !isSessionQueryEnabled"
|
|
154
56
|
:placeholder="sessionQueryPlaceholder">
|
|
155
57
|
</div>
|
|
156
|
-
<div class="session-toolbar-group">
|
|
58
|
+
<div class="session-toolbar-group session-toolbar-secondary">
|
|
157
59
|
<select
|
|
158
60
|
class="session-role-select"
|
|
159
61
|
v-model="sessionRoleFilter"
|
|
160
62
|
@change="onSessionFilterChange"
|
|
161
63
|
disabled>
|
|
162
|
-
<option value="all"
|
|
163
|
-
<option value="user"
|
|
164
|
-
<option value="assistant"
|
|
165
|
-
<option value="system"
|
|
64
|
+
<option value="all">{{ t('sessions.role.all') }}</option>
|
|
65
|
+
<option value="user">{{ t('sessions.role.user') }}</option>
|
|
66
|
+
<option value="assistant">{{ t('sessions.role.assistant') }}</option>
|
|
67
|
+
<option value="system">{{ t('sessions.role.system') }}</option>
|
|
166
68
|
</select>
|
|
167
69
|
<select
|
|
168
70
|
class="session-time-select"
|
|
169
71
|
v-model="sessionTimePreset"
|
|
170
72
|
@change="onSessionFilterChange"
|
|
171
73
|
disabled>
|
|
172
|
-
<option value="all"
|
|
173
|
-
<option value="7d"
|
|
174
|
-
<option value="30d"
|
|
175
|
-
<option value="90d"
|
|
74
|
+
<option value="all">{{ t('sessions.time.all') }}</option>
|
|
75
|
+
<option value="7d">{{ t('sessions.time.7d') }}</option>
|
|
76
|
+
<option value="30d">{{ t('sessions.time.30d') }}</option>
|
|
77
|
+
<option value="90d">{{ t('sessions.time.90d') }}</option>
|
|
176
78
|
</select>
|
|
177
79
|
</div>
|
|
178
80
|
</div>
|
|
@@ -183,23 +85,27 @@
|
|
|
183
85
|
v-model="sessionResumeWithYolo"
|
|
184
86
|
@change="onSessionResumeYoloChange"
|
|
185
87
|
>
|
|
186
|
-
|
|
88
|
+
{{ t('sessions.resumeYolo') }}
|
|
187
89
|
</label>
|
|
188
90
|
</div>
|
|
189
91
|
</div>
|
|
190
92
|
|
|
191
93
|
<div v-if="sessionsLoading" class="state-message">
|
|
192
|
-
|
|
94
|
+
{{ t('sessions.loadingList') }}
|
|
193
95
|
</div>
|
|
194
96
|
|
|
195
97
|
<div v-else-if="sessionsList.length === 0" class="session-empty">
|
|
196
|
-
|
|
98
|
+
{{ t('sessions.empty') }}
|
|
197
99
|
</div>
|
|
198
100
|
|
|
199
101
|
<div v-else class="session-layout">
|
|
200
|
-
<div
|
|
102
|
+
<div
|
|
103
|
+
v-if="sessionListRenderEnabled"
|
|
104
|
+
class="session-list"
|
|
105
|
+
:ref="setSessionListRef"
|
|
106
|
+
@scroll.passive="onSessionListScroll">
|
|
201
107
|
<div
|
|
202
|
-
v-for="session in
|
|
108
|
+
v-for="session in visibleSessionsList"
|
|
203
109
|
:key="session.source + '-' + session.sessionId + '-' + session.filePath"
|
|
204
110
|
v-memo="[activeSessionExportKey === getSessionExportKey(session), session.messageCount, session.updatedAt, session.title, session.sourceLabel, isSessionPinned(session), sessionsLoading]"
|
|
205
111
|
:class="[
|
|
@@ -218,15 +124,15 @@
|
|
|
218
124
|
<div class="session-item-header">
|
|
219
125
|
<div class="session-item-main">
|
|
220
126
|
<div class="session-item-title">{{ session.title || session.sessionId }}</div>
|
|
221
|
-
<span class="session-count-badge">{{ session.messageCount
|
|
127
|
+
<span class="session-count-badge">{{ session.messageCount == null ? 0 : session.messageCount }}</span>
|
|
222
128
|
</div>
|
|
223
129
|
<div class="session-item-actions">
|
|
224
130
|
<button
|
|
225
131
|
class="session-item-copy session-item-pin"
|
|
226
132
|
@click.stop="toggleSessionPin(session)"
|
|
227
133
|
:disabled="sessionsLoading"
|
|
228
|
-
:aria-label="isSessionPinned(session) ? '
|
|
229
|
-
:title="isSessionPinned(session) ? '
|
|
134
|
+
:aria-label="isSessionPinned(session) ? t('sessions.unpin') : t('sessions.pin')"
|
|
135
|
+
:title="isSessionPinned(session) ? t('sessions.unpin') : t('sessions.pin')"
|
|
230
136
|
:aria-pressed="isSessionPinned(session)">
|
|
231
137
|
<svg v-if="isSessionPinned(session)" class="pin-icon" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="1.6">
|
|
232
138
|
<path d="M12 22s8-6 8-12a8 8 0 1 0-16 0c0 6 8 12 8 12z"></path>
|
|
@@ -240,8 +146,8 @@
|
|
|
240
146
|
class="session-item-copy"
|
|
241
147
|
@click.stop="copyResumeCommand(session)"
|
|
242
148
|
:disabled="sessionsLoading"
|
|
243
|
-
aria-label="
|
|
244
|
-
title="
|
|
149
|
+
:aria-label="t('sessions.copyResume')"
|
|
150
|
+
:title="t('sessions.copyResume')">
|
|
245
151
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
246
152
|
<rect x="8" y="8" width="12" height="12" rx="2"></rect>
|
|
247
153
|
<path d="M16 8V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2"></path>
|
|
@@ -251,7 +157,7 @@
|
|
|
251
157
|
</div>
|
|
252
158
|
<div class="session-item-meta">
|
|
253
159
|
<span class="session-source">{{ session.sourceLabel }}</span>
|
|
254
|
-
<span class="session-item-time">{{ session.updatedAt || '
|
|
160
|
+
<span class="session-item-time">{{ session.updatedAt || t('sessions.unknownTime') }}</span>
|
|
255
161
|
</div>
|
|
256
162
|
</div>
|
|
257
163
|
</div>
|
|
@@ -265,7 +171,7 @@
|
|
|
265
171
|
<div class="session-preview-title">{{ activeSession.title || activeSession.sessionId }}</div>
|
|
266
172
|
<div class="session-preview-meta">
|
|
267
173
|
<span class="session-preview-meta-item">{{ activeSession.sourceLabel }}</span>
|
|
268
|
-
<span class="session-preview-meta-item">{{ activeSession.updatedAt || '
|
|
174
|
+
<span class="session-preview-meta-item">{{ activeSession.updatedAt || t('sessions.unknownTime') }}</span>
|
|
269
175
|
</div>
|
|
270
176
|
<div class="session-preview-meta" v-if="activeSession.cwd">
|
|
271
177
|
<span class="session-preview-meta-item">{{ activeSession.cwd }}</span>
|
|
@@ -273,32 +179,32 @@
|
|
|
273
179
|
</div>
|
|
274
180
|
<div class="session-actions">
|
|
275
181
|
<button class="btn-session-refresh" @click="loadActiveSessionDetail" :disabled="sessionDetailLoading || !activeSession">
|
|
276
|
-
{{ sessionDetailLoading ? '
|
|
182
|
+
{{ sessionDetailLoading ? t('sessions.preview.loading') : t('sessions.preview.refresh') }}
|
|
277
183
|
</button>
|
|
278
184
|
<button
|
|
279
185
|
v-if="isDeleteAvailable(activeSession)"
|
|
280
186
|
class="btn-session-delete"
|
|
281
187
|
@click="deleteSession(activeSession)"
|
|
282
188
|
:disabled="!activeSession || sessionsLoading || sessionDeleting[getSessionExportKey(activeSession)]">
|
|
283
|
-
{{ (activeSession && sessionDeleting[getSessionExportKey(activeSession)]) ? '
|
|
189
|
+
{{ (activeSession && sessionDeleting[getSessionExportKey(activeSession)]) ? (sessionTrashEnabled === false ? t('sessions.preview.deleting') : t('sessions.preview.moving')) : (sessionTrashEnabled === false ? t('sessions.preview.deleteHard') : t('sessions.preview.moveToTrash')) }}
|
|
284
190
|
</button>
|
|
285
191
|
<button
|
|
286
192
|
class="btn-session-export"
|
|
287
193
|
@click="exportSession(activeSession)"
|
|
288
194
|
:disabled="!activeSession || sessionExporting[getSessionExportKey(activeSession)]">
|
|
289
|
-
{{ (activeSession && sessionExporting[getSessionExportKey(activeSession)]) ? '
|
|
195
|
+
{{ (activeSession && sessionExporting[getSessionExportKey(activeSession)]) ? t('sessions.preview.exporting') : t('sessions.preview.export') }}
|
|
290
196
|
</button>
|
|
291
197
|
<button
|
|
292
198
|
class="btn-session-open"
|
|
293
199
|
@click="openSessionStandalone(activeSession)"
|
|
294
200
|
:disabled="!activeSession">
|
|
295
|
-
|
|
201
|
+
{{ t('sessions.preview.openStandalone') }}
|
|
296
202
|
</button>
|
|
297
203
|
</div>
|
|
298
204
|
</div>
|
|
299
205
|
|
|
300
206
|
<div v-if="sessionDetailLoading && !sessionPreviewLoadingMore" class="session-preview-empty">
|
|
301
|
-
|
|
207
|
+
{{ t('sessions.preview.loadingBody') }}
|
|
302
208
|
</div>
|
|
303
209
|
|
|
304
210
|
<div v-else-if="activeSessionDetailError" class="session-preview-empty">
|
|
@@ -306,38 +212,38 @@
|
|
|
306
212
|
</div>
|
|
307
213
|
|
|
308
214
|
<div v-else-if="!activeSessionMessages.length" class="session-preview-empty">
|
|
309
|
-
|
|
215
|
+
{{ t('sessions.preview.emptyMsgs') }}
|
|
310
216
|
</div>
|
|
311
217
|
|
|
312
218
|
<div v-else-if="sessionPreviewRenderEnabled && !activeSessionVisibleMessages.length" class="session-preview-empty">
|
|
313
|
-
<span
|
|
219
|
+
<span>{{ t('sessions.preview.rendering') }}</span>
|
|
314
220
|
<button class="btn-session-refresh" @click="primeSessionPreviewMessageRender" :disabled="sessionDetailLoading">
|
|
315
|
-
|
|
221
|
+
{{ t('sessions.preview.rerender') }}
|
|
316
222
|
</button>
|
|
317
223
|
</div>
|
|
318
224
|
|
|
319
225
|
<div v-else-if="!sessionPreviewRenderEnabled" class="session-preview-empty">
|
|
320
|
-
|
|
226
|
+
{{ t('sessions.preview.preparing') }}
|
|
321
227
|
</div>
|
|
322
228
|
|
|
323
229
|
<div v-else class="session-preview-body">
|
|
324
230
|
<div class="session-preview-messages">
|
|
325
231
|
<div v-if="activeSessionDetailClipped" class="session-item-sub session-item-wrap">
|
|
326
|
-
|
|
232
|
+
{{ t('sessions.preview.clipped', { count: activeSessionMessages.length }) }}
|
|
327
233
|
</div>
|
|
328
234
|
<div
|
|
329
235
|
v-if="canLoadMoreSessionMessages"
|
|
330
236
|
class="session-item-sub session-item-wrap"
|
|
331
237
|
style="display:flex;align-items:center;justify-content:space-between;gap:8px;">
|
|
332
|
-
<span
|
|
238
|
+
<span>{{ t('sessions.preview.shownCount', { shown: activeSessionVisibleMessages.length, total: activeSessionMessages.length }) }}</span>
|
|
333
239
|
<button class="btn-session-refresh" @click="loadMoreSessionMessages()" :disabled="sessionDetailLoading || sessionPreviewLoadingMore">
|
|
334
|
-
{{ sessionPreviewLoadingMore ? '
|
|
240
|
+
{{ sessionPreviewLoadingMore ? t('sessions.preview.loading') : t('sessions.preview.loadMore', { remain: sessionPreviewRemainingCount }) }}
|
|
335
241
|
</button>
|
|
336
242
|
</div>
|
|
337
243
|
<div
|
|
338
244
|
v-if="sessionPreviewLoadingMore"
|
|
339
245
|
class="session-item-sub session-item-wrap">
|
|
340
|
-
|
|
246
|
+
{{ t('sessions.preview.loadingMore') }}
|
|
341
247
|
</div>
|
|
342
248
|
<div
|
|
343
249
|
v-for="(msg, idx) in activeSessionVisibleMessages"
|
|
@@ -348,7 +254,7 @@
|
|
|
348
254
|
:class="['session-msg', msg.normalizedRole === 'user' ? 'user' : (msg.normalizedRole === 'system' ? 'system' : 'assistant')]">
|
|
349
255
|
<div class="session-msg-header">
|
|
350
256
|
<div class="session-msg-meta">
|
|
351
|
-
<span class="session-msg-role">{{ msg.roleLabel || (msg.normalizedRole === 'user' ? '
|
|
257
|
+
<span class="session-msg-role">{{ msg.roleLabel || (msg.normalizedRole === 'user' ? t('sessions.roleLabel.user') : (msg.normalizedRole === 'system' ? t('sessions.roleLabel.system') : t('sessions.roleLabel.assistant'))) }}</span>
|
|
352
258
|
<span class="session-msg-time">{{ msg.timestamp || '' }}</span>
|
|
353
259
|
</div>
|
|
354
260
|
</div>
|
|
@@ -357,7 +263,7 @@
|
|
|
357
263
|
</div>
|
|
358
264
|
</div>
|
|
359
265
|
</div>
|
|
360
|
-
<aside v-if="sessionPreviewRenderEnabled && sessionTimelineNodes.length" class="session-timeline" aria-label="
|
|
266
|
+
<aside v-if="sessionPreviewRenderEnabled && sessionTimelineNodes.length" class="session-timeline" :aria-label="t('sessions.timeline.aria')">
|
|
361
267
|
<div class="session-timeline-track"></div>
|
|
362
268
|
<button
|
|
363
269
|
v-for="node in sessionTimelineNodes"
|
|
@@ -378,10 +284,9 @@
|
|
|
378
284
|
</template>
|
|
379
285
|
|
|
380
286
|
<div v-else class="session-preview-empty">
|
|
381
|
-
<span
|
|
287
|
+
<span>{{ t('sessions.selectHint') }}</span>
|
|
382
288
|
</div>
|
|
383
289
|
</div>
|
|
384
290
|
</div>
|
|
385
|
-
</template>
|
|
386
291
|
</div>
|
|
387
292
|
</div>
|