codexmate 0.1.4 → 0.1.6
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 +2 -2
- package/README.vi.md +2 -2
- package/README.zh.md +2 -2
- package/cli/analytics-export-args.js +2 -2
- package/cli/session-usage.js +5 -2
- package/cli.js +424 -54
- package/lib/cli-sessions.js +19 -0
- package/package.json +1 -1
- package/web-ui/logic.sessions.mjs +5 -5
- package/web-ui/modules/app.computed.session.mjs +2 -1
- package/web-ui/modules/app.methods.session-actions.mjs +13 -5
- package/web-ui/modules/app.methods.session-browser.mjs +8 -4
- package/web-ui/modules/app.methods.session-trash.mjs +2 -2
- package/web-ui/modules/i18n/locales/en.mjs +1 -0
- package/web-ui/modules/i18n/locales/ja.mjs +1 -0
- package/web-ui/modules/i18n/locales/vi.mjs +1 -0
- package/web-ui/modules/i18n/locales/zh-tw.mjs +1 -0
- package/web-ui/modules/i18n/locales/zh.mjs +1 -0
- package/web-ui/partials/index/panel-sessions.html +8 -12
- package/web-ui/res/web-ui-render.precompiled.js +12 -29
- package/web-ui/styles/responsive.css +12 -0
- package/web-ui/styles/sessions-toolbar-trash.css +23 -1
package/lib/cli-sessions.js
CHANGED
|
@@ -204,6 +204,17 @@ function extractMessageFromRecord(record, source) {
|
|
|
204
204
|
}
|
|
205
205
|
return null;
|
|
206
206
|
}
|
|
207
|
+
if (source === 'pi') {
|
|
208
|
+
if (record.type === 'message' && record.message && typeof record.message === 'object') {
|
|
209
|
+
const role = normalizeRole(record.message.role);
|
|
210
|
+
const text = extractMessageText(record.message.content);
|
|
211
|
+
if (!role || !text) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
return { role, text };
|
|
215
|
+
}
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
207
218
|
|
|
208
219
|
const role = normalizeRole(record.type);
|
|
209
220
|
if (!role) {
|
|
@@ -271,6 +282,14 @@ function applySessionDetailRecordMetadata(record, source, state) {
|
|
|
271
282
|
return;
|
|
272
283
|
}
|
|
273
284
|
|
|
285
|
+
if (source === 'pi') {
|
|
286
|
+
if (record.type === 'session') {
|
|
287
|
+
state.sessionId = record.id || state.sessionId;
|
|
288
|
+
state.cwd = record.cwd || state.cwd;
|
|
289
|
+
}
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
274
293
|
if (!state.sessionId && record.sessionId) {
|
|
275
294
|
state.sessionId = record.sessionId;
|
|
276
295
|
}
|
package/package.json
CHANGED
|
@@ -29,14 +29,14 @@ function shouldUseFastSessionBrowseLimit(options = {}) {
|
|
|
29
29
|
|
|
30
30
|
export function isSessionQueryEnabled(source) {
|
|
31
31
|
const normalized = normalizeSessionSource(source, '');
|
|
32
|
-
return normalized === 'codex' || normalized === 'claude' || normalized === 'gemini' || normalized === 'codebuddy' || normalized === 'all';
|
|
32
|
+
return normalized === 'codex' || normalized === 'claude' || normalized === 'gemini' || normalized === 'codebuddy' || normalized === 'pi' || normalized === 'all';
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export function normalizeSessionSource(source, fallback = 'all') {
|
|
36
36
|
const normalized = typeof source === 'string'
|
|
37
37
|
? source.trim().toLowerCase()
|
|
38
38
|
: '';
|
|
39
|
-
if (normalized === 'codex' || normalized === 'claude' || normalized === 'gemini' || normalized === 'codebuddy' || normalized === 'all') {
|
|
39
|
+
if (normalized === 'codex' || normalized === 'claude' || normalized === 'gemini' || normalized === 'codebuddy' || normalized === 'pi' || normalized === 'all') {
|
|
40
40
|
return normalized;
|
|
41
41
|
}
|
|
42
42
|
return fallback;
|
|
@@ -209,7 +209,7 @@ export function buildUsageHeatmap(sessions = [], options = {}) {
|
|
|
209
209
|
for (const session of list) {
|
|
210
210
|
if (!session || typeof session !== 'object') continue;
|
|
211
211
|
const source = normalizeSessionSource(session.source, '');
|
|
212
|
-
if (source !== 'codex' && source !== 'claude') continue;
|
|
212
|
+
if (source !== 'codex' && source !== 'claude' && source !== 'pi') continue;
|
|
213
213
|
const updatedAtMs = Date.parse(session.updatedAt || '');
|
|
214
214
|
if (!Number.isFinite(updatedAtMs)) continue;
|
|
215
215
|
normalized.push({
|
|
@@ -309,7 +309,7 @@ export function buildUsageHourlyHeatmap(sessions = [], options = {}) {
|
|
|
309
309
|
for (const session of list) {
|
|
310
310
|
if (!session || typeof session !== 'object') continue;
|
|
311
311
|
const source = normalizeSessionSource(session.source, '');
|
|
312
|
-
if (source !== 'codex' && source !== 'claude') continue;
|
|
312
|
+
if (source !== 'codex' && source !== 'claude' && source !== 'pi') continue;
|
|
313
313
|
const updatedAtMs = Date.parse(session.updatedAt || '');
|
|
314
314
|
if (!Number.isFinite(updatedAtMs)) continue;
|
|
315
315
|
const dayStart = toUtcDayStartMs(updatedAtMs);
|
|
@@ -402,7 +402,7 @@ export function buildUsageChartGroups(sessions = [], options = {}) {
|
|
|
402
402
|
for (const [sessionIndex, session] of list.entries()) {
|
|
403
403
|
if (!session || typeof session !== 'object') continue;
|
|
404
404
|
const source = normalizeSessionSource(session.source, '');
|
|
405
|
-
if (source !== 'codex' && source !== 'claude') continue;
|
|
405
|
+
if (source !== 'codex' && source !== 'claude' && source !== 'pi') continue;
|
|
406
406
|
const updatedAtMs = Date.parse(session.updatedAt || '');
|
|
407
407
|
if (!Number.isFinite(updatedAtMs)) continue;
|
|
408
408
|
const createdAtMs = Date.parse(session.createdAt || '');
|
|
@@ -307,7 +307,8 @@ export function createSessionComputed() {
|
|
|
307
307
|
{ value: "codex", label: this.t("sessions.source.codex") },
|
|
308
308
|
{ value: "claude", label: this.t("sessions.source.claudeCode") },
|
|
309
309
|
{ value: "gemini", label: this.t("sessions.source.gemini") },
|
|
310
|
-
{ value: "codebuddy", label: this.t("sessions.source.codebuddy") }
|
|
310
|
+
{ value: "codebuddy", label: this.t("sessions.source.codebuddy") },
|
|
311
|
+
{ value: "pi", label: this.t("sessions.source.pi") }
|
|
311
312
|
];
|
|
312
313
|
},
|
|
313
314
|
activeSessionExportKey() {
|
|
@@ -28,8 +28,8 @@ export function createSessionActionMethods(options = {}) {
|
|
|
28
28
|
let error = '';
|
|
29
29
|
if (!source) {
|
|
30
30
|
error = '缺少 source 参数';
|
|
31
|
-
} else if (source !== 'codex' && source !== 'claude') {
|
|
32
|
-
error = 'source 仅支持 codex 或
|
|
31
|
+
} else if (source !== 'codex' && source !== 'claude' && source !== 'gemini' && source !== 'codebuddy' && source !== 'pi') {
|
|
32
|
+
error = 'source 仅支持 codex、claude、gemini、codebuddy 或 pi';
|
|
33
33
|
}
|
|
34
34
|
if (!sessionId && !filePath) {
|
|
35
35
|
error = error ? `${error},还缺少 sessionId 或 filePath` : '缺少 sessionId 或 filePath 参数';
|
|
@@ -67,7 +67,15 @@ export function createSessionActionMethods(options = {}) {
|
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
const sourceLabel = context.params.source === 'codex'
|
|
70
|
+
const sourceLabel = context.params.source === 'codex'
|
|
71
|
+
? 'Codex'
|
|
72
|
+
: (context.params.source === 'claude'
|
|
73
|
+
? 'Claude Code'
|
|
74
|
+
: (context.params.source === 'gemini'
|
|
75
|
+
? 'Gemini CLI'
|
|
76
|
+
: (context.params.source === 'pi'
|
|
77
|
+
? 'Pi'
|
|
78
|
+
: (context.params.source === 'codebuddy' ? 'CodeBuddy Code' : context.params.source))));
|
|
71
79
|
this.activeSession = {
|
|
72
80
|
source: context.params.source,
|
|
73
81
|
sourceLabel,
|
|
@@ -96,7 +104,7 @@ export function createSessionActionMethods(options = {}) {
|
|
|
96
104
|
buildSessionStandaloneUrl(session) {
|
|
97
105
|
if (!session) return '';
|
|
98
106
|
const source = typeof session.source === 'string' ? session.source.trim().toLowerCase() : '';
|
|
99
|
-
if (!source || (source !== 'codex' && source !== 'claude')) return '';
|
|
107
|
+
if (!source || (source !== 'codex' && source !== 'claude' && source !== 'gemini' && source !== 'codebuddy' && source !== 'pi')) return '';
|
|
100
108
|
const sessionId = typeof session.sessionId === 'string' ? session.sessionId.trim() : '';
|
|
101
109
|
const filePath = typeof session.filePath === 'string' ? session.filePath.trim() : '';
|
|
102
110
|
if (!sessionId && !filePath) return '';
|
|
@@ -217,7 +225,7 @@ export function createSessionActionMethods(options = {}) {
|
|
|
217
225
|
isDeleteAvailable(session) {
|
|
218
226
|
if (!session) return false;
|
|
219
227
|
const source = String(session.source || '').trim().toLowerCase();
|
|
220
|
-
if (source !== 'codex' && source !== 'claude') return false;
|
|
228
|
+
if (source !== 'codex' && source !== 'claude' && source !== 'pi') return false;
|
|
221
229
|
const sessionId = typeof session.sessionId === 'string' ? session.sessionId.trim() : '';
|
|
222
230
|
const filePath = typeof session.filePath === 'string' ? session.filePath.trim() : '';
|
|
223
231
|
return !!sessionId || !!filePath;
|
|
@@ -120,7 +120,7 @@ export function createSessionBrowserMethods(options = {}) {
|
|
|
120
120
|
syncSessionPathOptionsForSource(source, nextOptions, mergeWithExisting = false) {
|
|
121
121
|
const targetSource = source === 'claude'
|
|
122
122
|
? 'claude'
|
|
123
|
-
: (source === 'gemini' ? 'gemini' : (source === 'all' ? 'all' : 'codex'));
|
|
123
|
+
: (source === 'gemini' ? 'gemini' : (source === 'pi' ? 'pi' : (source === 'all' ? 'all' : 'codex')));
|
|
124
124
|
const current = Array.isArray(this.sessionPathOptionsMap[targetSource])
|
|
125
125
|
? this.sessionPathOptionsMap[targetSource]
|
|
126
126
|
: [];
|
|
@@ -137,7 +137,7 @@ export function createSessionBrowserMethods(options = {}) {
|
|
|
137
137
|
refreshSessionPathOptions(source) {
|
|
138
138
|
const targetSource = source === 'claude'
|
|
139
139
|
? 'claude'
|
|
140
|
-
: (source === 'gemini' ? 'gemini' : (source === 'all' ? 'all' : 'codex'));
|
|
140
|
+
: (source === 'gemini' ? 'gemini' : (source === 'pi' ? 'pi' : (source === 'all' ? 'all' : 'codex')));
|
|
141
141
|
const base = Array.isArray(this.sessionPathOptionsMap[targetSource])
|
|
142
142
|
? [...this.sessionPathOptionsMap[targetSource]]
|
|
143
143
|
: [];
|
|
@@ -161,7 +161,7 @@ export function createSessionBrowserMethods(options = {}) {
|
|
|
161
161
|
async loadSessionPathOptions(options = {}) {
|
|
162
162
|
const source = options.source === 'claude'
|
|
163
163
|
? 'claude'
|
|
164
|
-
: (options.source === 'gemini' ? 'gemini' : (options.source === 'all' ? 'all' : 'codex'));
|
|
164
|
+
: (options.source === 'gemini' ? 'gemini' : (options.source === 'pi' ? 'pi' : (options.source === 'all' ? 'all' : 'codex')));
|
|
165
165
|
const forceRefresh = !!options.forceRefresh;
|
|
166
166
|
const loaded = !!this.sessionPathOptionsLoadedMap[source];
|
|
167
167
|
if (!forceRefresh && loaded) {
|
|
@@ -507,7 +507,11 @@ export function createSessionBrowserMethods(options = {}) {
|
|
|
507
507
|
? this.t('sessions.source.claudeCode')
|
|
508
508
|
: (this.sessionFilterSource === 'gemini'
|
|
509
509
|
? this.t('sessions.source.gemini')
|
|
510
|
-
: (this.sessionFilterSource === 'codebuddy'
|
|
510
|
+
: (this.sessionFilterSource === 'codebuddy'
|
|
511
|
+
? this.t('sessions.source.codebuddy')
|
|
512
|
+
: (this.sessionFilterSource === 'pi'
|
|
513
|
+
? this.t('sessions.source.pi')
|
|
514
|
+
: this.sessionFilterSource))));
|
|
511
515
|
chips.push({ key: 'source', title: this.t('sessions.filters.source'), value: label });
|
|
512
516
|
}
|
|
513
517
|
if (this.sessionPathFilter) {
|
|
@@ -10,7 +10,7 @@ export function createSessionTrashMethods(options = {}) {
|
|
|
10
10
|
const deletedAt = typeof result.deletedAt === 'string' && result.deletedAt
|
|
11
11
|
? result.deletedAt
|
|
12
12
|
: new Date().toISOString();
|
|
13
|
-
const source = session && (session.source === 'claude' || session.source === 'gemini')
|
|
13
|
+
const source = session && (session.source === 'claude' || session.source === 'gemini' || session.source === 'codebuddy' || session.source === 'pi')
|
|
14
14
|
? session.source
|
|
15
15
|
: 'codex';
|
|
16
16
|
return {
|
|
@@ -18,7 +18,7 @@ export function createSessionTrashMethods(options = {}) {
|
|
|
18
18
|
source,
|
|
19
19
|
sourceLabel: session && typeof session.sourceLabel === 'string' && session.sourceLabel
|
|
20
20
|
? session.sourceLabel
|
|
21
|
-
: (source === 'claude' ? 'Claude Code' : (source === 'gemini' ? 'Gemini CLI' : 'Codex')),
|
|
21
|
+
: (source === 'claude' ? 'Claude Code' : (source === 'gemini' ? 'Gemini CLI' : (source === 'pi' ? 'Pi' : (source === 'codebuddy' ? 'CodeBuddy Code' : 'Codex')))),
|
|
22
22
|
sessionId: session && typeof session.sessionId === 'string' ? session.sessionId : '',
|
|
23
23
|
title: session && typeof session.title === 'string' && session.title
|
|
24
24
|
? session.title
|
|
@@ -645,6 +645,7 @@ const en = Object.freeze({
|
|
|
645
645
|
'sessions.source.claudeCode': 'Claude Code',
|
|
646
646
|
'sessions.source.gemini': 'Gemini CLI',
|
|
647
647
|
'sessions.source.codebuddy': 'CodeBuddy Code',
|
|
648
|
+
'sessions.source.pi': 'Pi',
|
|
648
649
|
'sessions.loadingList': 'Loading sessions...',
|
|
649
650
|
'sessions.empty': 'No sessions found',
|
|
650
651
|
'sessions.unknownTime': 'unknown time',
|
|
@@ -647,6 +647,7 @@ const ja = Object.freeze({
|
|
|
647
647
|
'sessions.source.claudeCode': 'Claude Code',
|
|
648
648
|
'sessions.source.gemini': 'Gemini',
|
|
649
649
|
'sessions.source.codebuddy': 'CodeBuddy',
|
|
650
|
+
'sessions.source.pi': 'Pi',
|
|
650
651
|
'sessions.loadingList': 'セッション一覧を読み込み中...',
|
|
651
652
|
'sessions.empty': 'セッションがありません',
|
|
652
653
|
'sessions.unknownTime': '不明な時間',
|
|
@@ -850,6 +850,7 @@ const vi = Object.freeze({
|
|
|
850
850
|
'sessions.source.claudeCode': 'Claude Code',
|
|
851
851
|
'sessions.source.gemini': 'Gemini CLI',
|
|
852
852
|
'sessions.source.codebuddy': 'CodeBuddy Code',
|
|
853
|
+
'sessions.source.pi': 'Pi',
|
|
853
854
|
'sessions.loadingList': 'Đang tải phiên làm việc...',
|
|
854
855
|
'sessions.empty': 'Không tìm thấy phiên nào',
|
|
855
856
|
'sessions.unknownTime': 'thời gian không rõ',
|
|
@@ -645,6 +645,7 @@ const zhTw = Object.freeze({
|
|
|
645
645
|
'sessions.source.claudeCode': 'Claude Code',
|
|
646
646
|
'sessions.source.gemini': 'Gemini CLI',
|
|
647
647
|
'sessions.source.codebuddy': 'CodeBuddy Code',
|
|
648
|
+
'sessions.source.pi': 'Pi',
|
|
648
649
|
'sessions.loadingList': '會話載入中...',
|
|
649
650
|
'sessions.empty': '暫無可用會話記錄',
|
|
650
651
|
'sessions.unknownTime': '未知時間',
|
|
@@ -645,6 +645,7 @@ const zh = Object.freeze({
|
|
|
645
645
|
'sessions.source.claudeCode': 'Claude Code',
|
|
646
646
|
'sessions.source.gemini': 'Gemini CLI',
|
|
647
647
|
'sessions.source.codebuddy': 'CodeBuddy Code',
|
|
648
|
+
'sessions.source.pi': 'Pi',
|
|
648
649
|
'sessions.loadingList': '会话加载中...',
|
|
649
650
|
'sessions.empty': '暂无可用会话记录',
|
|
650
651
|
'sessions.unknownTime': '未知时间',
|
|
@@ -220,35 +220,30 @@
|
|
|
220
220
|
</div>
|
|
221
221
|
</div>
|
|
222
222
|
<div class="session-actions">
|
|
223
|
-
<button class="btn-session-refresh" @click="loadActiveSessionDetail" :disabled="sessionDetailLoading || !activeSession"
|
|
223
|
+
<button class="btn-session-refresh has-label" @click="loadActiveSessionDetail" :disabled="sessionDetailLoading || !activeSession"
|
|
224
224
|
:title="sessionDetailLoading ? t('sessions.preview.loading') : t('sessions.preview.refresh')"
|
|
225
225
|
:aria-label="sessionDetailLoading ? t('sessions.preview.loading') : t('sessions.preview.refresh')">
|
|
226
226
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M2.5 8a5.5 5.5 0 0 1 9.4-3.8"/><path d="M13.5 8a5.5 5.5 0 0 1-9.4 3.8"/><polyline points="2.5 2 2.5 5 5.5 5"/><polyline points="13.5 14 13.5 11 10.5 11"/></svg>
|
|
227
|
+
<span class="session-action-label">{{ t('sessions.preview.refresh') }}</span>
|
|
227
228
|
</button>
|
|
228
229
|
<button
|
|
229
230
|
v-if="isDeleteAvailable(activeSession)"
|
|
230
|
-
class="btn-session-delete"
|
|
231
|
+
class="btn-session-delete has-label"
|
|
231
232
|
@click="deleteSession(activeSession)"
|
|
232
233
|
:disabled="!activeSession || sessionsLoading || sessionDeleting[getSessionExportKey(activeSession)]"
|
|
233
234
|
:title="(activeSession && sessionDeleting[getSessionExportKey(activeSession)]) ? (sessionTrashEnabled === false ? t('sessions.preview.deleting') : t('sessions.preview.moving')) : (sessionTrashEnabled === false ? t('sessions.preview.deleteHard') : t('sessions.preview.moveToTrash'))"
|
|
234
235
|
:aria-label="(activeSession && sessionDeleting[getSessionExportKey(activeSession)]) ? (sessionTrashEnabled === false ? t('sessions.preview.deleting') : t('sessions.preview.moving')) : (sessionTrashEnabled === false ? t('sessions.preview.deleteHard') : t('sessions.preview.moveToTrash'))">
|
|
235
236
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 4 4 4 13 4"/><path d="M5.5 4V2.5a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1V4"/><path d="M12 4v9.5a1.5 1.5 0 0 1-1.5 1.5h-5A1.5 1.5 0 0 1 4 13.5V4"/></svg>
|
|
237
|
+
<span class="session-action-label">{{ (activeSession && sessionDeleting[getSessionExportKey(activeSession)]) ? (sessionTrashEnabled === false ? t('sessions.preview.deleting') : t('sessions.preview.moving')) : (sessionTrashEnabled === false ? t('sessions.preview.deleteHard') : t('sessions.preview.moveToTrash')) }}</span>
|
|
236
238
|
</button>
|
|
237
239
|
<button
|
|
238
|
-
class="btn-session-export"
|
|
240
|
+
class="btn-session-export has-label"
|
|
239
241
|
@click="exportSession(activeSession)"
|
|
240
242
|
:disabled="!activeSession || sessionExporting[getSessionExportKey(activeSession)]"
|
|
241
243
|
:title="(activeSession && sessionExporting[getSessionExportKey(activeSession)]) ? t('sessions.preview.exporting') : t('sessions.preview.export')"
|
|
242
244
|
:aria-label="(activeSession && sessionExporting[getSessionExportKey(activeSession)]) ? t('sessions.preview.exporting') : t('sessions.preview.export')">
|
|
243
245
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2v8"/><polyline points="4 7 8 10.5 12 7"/><path d="M2.5 12v1.5a1 1 0 0 0 1 1h9a1 1 0 0 0 1-1V12"/></svg>
|
|
244
|
-
|
|
245
|
-
<button
|
|
246
|
-
class="btn-session-open session-brief-copy"
|
|
247
|
-
@click="copySessionWorkspaceBrief"
|
|
248
|
-
:disabled="!activeSessionWorkspaceSummary.available"
|
|
249
|
-
:title="t('sessions.workspace.copy')"
|
|
250
|
-
:aria-label="t('sessions.workspace.copy')">
|
|
251
|
-
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 2.5h6.5L13 5v8.5H4z"/><path d="M10.5 2.5V5H13"/><path d="M6 8h5"/><path d="M6 10.5h5"/></svg>
|
|
246
|
+
<span class="session-action-label">{{ (activeSession && sessionExporting[getSessionExportKey(activeSession)]) ? t('sessions.preview.exporting') : t('sessions.preview.export') }}</span>
|
|
252
247
|
</button>
|
|
253
248
|
<div class="session-link-group">
|
|
254
249
|
<button
|
|
@@ -269,12 +264,13 @@
|
|
|
269
264
|
</button>
|
|
270
265
|
</div>
|
|
271
266
|
<button
|
|
272
|
-
class="btn-session-open"
|
|
267
|
+
class="btn-session-open has-label"
|
|
273
268
|
@click="copySessionPath(activeSession)"
|
|
274
269
|
:disabled="!activeSession || !getSessionFilePath(activeSession)"
|
|
275
270
|
:title="t('sessions.preview.copyPath')"
|
|
276
271
|
:aria-label="t('sessions.preview.copyPath')">
|
|
277
272
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M2 5.5V12.5a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V7.5a1 1 0 0 0-1-1H8L6.5 5H3a1 1 0 0 0-1 1z"/></svg>
|
|
273
|
+
<span class="session-action-label">{{ t('sessions.preview.copyPath') }}</span>
|
|
278
274
|
</button>
|
|
279
275
|
</div>
|
|
280
276
|
</div>
|
|
@@ -3512,7 +3512,7 @@ return function render(_ctx, _cache) {
|
|
|
3512
3512
|
]),
|
|
3513
3513
|
_createElementVNode("div", { class: "session-actions" }, [
|
|
3514
3514
|
_createElementVNode("button", {
|
|
3515
|
-
class: "btn-session-refresh",
|
|
3515
|
+
class: "btn-session-refresh has-label",
|
|
3516
3516
|
onClick: _ctx.loadActiveSessionDetail,
|
|
3517
3517
|
disabled: _ctx.sessionDetailLoading || !_ctx.activeSession,
|
|
3518
3518
|
title: _ctx.sessionDetailLoading ? _ctx.t('sessions.preview.loading') : _ctx.t('sessions.preview.refresh'),
|
|
@@ -3530,12 +3530,13 @@ return function render(_ctx, _cache) {
|
|
|
3530
3530
|
_createElementVNode("path", { d: "M13.5 8a5.5 5.5 0 0 1-9.4 3.8" }),
|
|
3531
3531
|
_createElementVNode("polyline", { points: "2.5 2 2.5 5 5.5 5" }),
|
|
3532
3532
|
_createElementVNode("polyline", { points: "13.5 14 13.5 11 10.5 11" })
|
|
3533
|
-
]))
|
|
3533
|
+
])),
|
|
3534
|
+
_createElementVNode("span", { class: "session-action-label" }, _toDisplayString(_ctx.t('sessions.preview.refresh')), 1 /* TEXT */)
|
|
3534
3535
|
], 8 /* PROPS */, ["onClick", "disabled", "title", "aria-label"]),
|
|
3535
3536
|
(_ctx.isDeleteAvailable(_ctx.activeSession))
|
|
3536
3537
|
? (_openBlock(), _createElementBlock("button", {
|
|
3537
3538
|
key: 0,
|
|
3538
|
-
class: "btn-session-delete",
|
|
3539
|
+
class: "btn-session-delete has-label",
|
|
3539
3540
|
onClick: $event => (_ctx.deleteSession(_ctx.activeSession)),
|
|
3540
3541
|
disabled: !_ctx.activeSession || _ctx.sessionsLoading || _ctx.sessionDeleting[_ctx.getSessionExportKey(_ctx.activeSession)],
|
|
3541
3542
|
title: (_ctx.activeSession && _ctx.sessionDeleting[_ctx.getSessionExportKey(_ctx.activeSession)]) ? (_ctx.sessionTrashEnabled === false ? _ctx.t('sessions.preview.deleting') : _ctx.t('sessions.preview.moving')) : (_ctx.sessionTrashEnabled === false ? _ctx.t('sessions.preview.deleteHard') : _ctx.t('sessions.preview.moveToTrash')),
|
|
@@ -3552,11 +3553,12 @@ return function render(_ctx, _cache) {
|
|
|
3552
3553
|
_createElementVNode("polyline", { points: "3 4 4 4 13 4" }),
|
|
3553
3554
|
_createElementVNode("path", { d: "M5.5 4V2.5a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1V4" }),
|
|
3554
3555
|
_createElementVNode("path", { d: "M12 4v9.5a1.5 1.5 0 0 1-1.5 1.5h-5A1.5 1.5 0 0 1 4 13.5V4" })
|
|
3555
|
-
]))
|
|
3556
|
+
])),
|
|
3557
|
+
_createElementVNode("span", { class: "session-action-label" }, _toDisplayString((_ctx.activeSession && _ctx.sessionDeleting[_ctx.getSessionExportKey(_ctx.activeSession)]) ? (_ctx.sessionTrashEnabled === false ? _ctx.t('sessions.preview.deleting') : _ctx.t('sessions.preview.moving')) : (_ctx.sessionTrashEnabled === false ? _ctx.t('sessions.preview.deleteHard') : _ctx.t('sessions.preview.moveToTrash'))), 1 /* TEXT */)
|
|
3556
3558
|
], 8 /* PROPS */, ["onClick", "disabled", "title", "aria-label"]))
|
|
3557
3559
|
: _createCommentVNode("v-if", true),
|
|
3558
3560
|
_createElementVNode("button", {
|
|
3559
|
-
class: "btn-session-export",
|
|
3561
|
+
class: "btn-session-export has-label",
|
|
3560
3562
|
onClick: $event => (_ctx.exportSession(_ctx.activeSession)),
|
|
3561
3563
|
disabled: !_ctx.activeSession || _ctx.sessionExporting[_ctx.getSessionExportKey(_ctx.activeSession)],
|
|
3562
3564
|
title: (_ctx.activeSession && _ctx.sessionExporting[_ctx.getSessionExportKey(_ctx.activeSession)]) ? _ctx.t('sessions.preview.exporting') : _ctx.t('sessions.preview.export'),
|
|
@@ -3573,28 +3575,8 @@ return function render(_ctx, _cache) {
|
|
|
3573
3575
|
_createElementVNode("path", { d: "M8 2v8" }),
|
|
3574
3576
|
_createElementVNode("polyline", { points: "4 7 8 10.5 12 7" }),
|
|
3575
3577
|
_createElementVNode("path", { d: "M2.5 12v1.5a1 1 0 0 0 1 1h9a1 1 0 0 0 1-1V12" })
|
|
3576
|
-
]))
|
|
3577
|
-
|
|
3578
|
-
_createElementVNode("button", {
|
|
3579
|
-
class: "btn-session-open session-brief-copy",
|
|
3580
|
-
onClick: _ctx.copySessionWorkspaceBrief,
|
|
3581
|
-
disabled: !_ctx.activeSessionWorkspaceSummary.available,
|
|
3582
|
-
title: _ctx.t('sessions.workspace.copy'),
|
|
3583
|
-
"aria-label": _ctx.t('sessions.workspace.copy')
|
|
3584
|
-
}, [
|
|
3585
|
-
(_openBlock(), _createElementBlock("svg", {
|
|
3586
|
-
viewBox: "0 0 16 16",
|
|
3587
|
-
fill: "none",
|
|
3588
|
-
stroke: "currentColor",
|
|
3589
|
-
"stroke-width": "1.8",
|
|
3590
|
-
"stroke-linecap": "round",
|
|
3591
|
-
"stroke-linejoin": "round"
|
|
3592
|
-
}, [
|
|
3593
|
-
_createElementVNode("path", { d: "M4 2.5h6.5L13 5v8.5H4z" }),
|
|
3594
|
-
_createElementVNode("path", { d: "M10.5 2.5V5H13" }),
|
|
3595
|
-
_createElementVNode("path", { d: "M6 8h5" }),
|
|
3596
|
-
_createElementVNode("path", { d: "M6 10.5h5" })
|
|
3597
|
-
]))
|
|
3578
|
+
])),
|
|
3579
|
+
_createElementVNode("span", { class: "session-action-label" }, _toDisplayString((_ctx.activeSession && _ctx.sessionExporting[_ctx.getSessionExportKey(_ctx.activeSession)]) ? _ctx.t('sessions.preview.exporting') : _ctx.t('sessions.preview.export')), 1 /* TEXT */)
|
|
3598
3580
|
], 8 /* PROPS */, ["onClick", "disabled", "title", "aria-label"]),
|
|
3599
3581
|
_createElementVNode("div", { class: "session-link-group" }, [
|
|
3600
3582
|
_createElementVNode("button", {
|
|
@@ -3638,7 +3620,7 @@ return function render(_ctx, _cache) {
|
|
|
3638
3620
|
], 8 /* PROPS */, ["onClick", "disabled", "title", "aria-label"])
|
|
3639
3621
|
]),
|
|
3640
3622
|
_createElementVNode("button", {
|
|
3641
|
-
class: "btn-session-open",
|
|
3623
|
+
class: "btn-session-open has-label",
|
|
3642
3624
|
onClick: $event => (_ctx.copySessionPath(_ctx.activeSession)),
|
|
3643
3625
|
disabled: !_ctx.activeSession || !_ctx.getSessionFilePath(_ctx.activeSession),
|
|
3644
3626
|
title: _ctx.t('sessions.preview.copyPath'),
|
|
@@ -3653,7 +3635,8 @@ return function render(_ctx, _cache) {
|
|
|
3653
3635
|
"stroke-linejoin": "round"
|
|
3654
3636
|
}, [
|
|
3655
3637
|
_createElementVNode("path", { d: "M2 5.5V12.5a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V7.5a1 1 0 0 0-1-1H8L6.5 5H3a1 1 0 0 0-1 1z" })
|
|
3656
|
-
]))
|
|
3638
|
+
])),
|
|
3639
|
+
_createElementVNode("span", { class: "session-action-label" }, _toDisplayString(_ctx.t('sessions.preview.copyPath')), 1 /* TEXT */)
|
|
3657
3640
|
], 8 /* PROPS */, ["onClick", "disabled", "title", "aria-label"])
|
|
3658
3641
|
])
|
|
3659
3642
|
], 512 /* NEED_PATCH */),
|
|
@@ -366,6 +366,14 @@ textarea:focus-visible {
|
|
|
366
366
|
height: 44px;
|
|
367
367
|
}
|
|
368
368
|
|
|
369
|
+
.btn-session-export.has-label,
|
|
370
|
+
.btn-session-open.has-label,
|
|
371
|
+
.btn-session-refresh.has-label,
|
|
372
|
+
.btn-session-delete.has-label {
|
|
373
|
+
width: auto;
|
|
374
|
+
height: 44px;
|
|
375
|
+
padding: 0 14px;
|
|
376
|
+
}
|
|
369
377
|
.session-link-group .btn-session-open {
|
|
370
378
|
width: 44px;
|
|
371
379
|
height: 44px;
|
|
@@ -585,6 +593,10 @@ textarea:focus-visible {
|
|
|
585
593
|
height: 40px;
|
|
586
594
|
}
|
|
587
595
|
|
|
596
|
+
.session-actions .session-action-label {
|
|
597
|
+
display: none;
|
|
598
|
+
}
|
|
599
|
+
|
|
588
600
|
.session-preview-body {
|
|
589
601
|
padding: 12px;
|
|
590
602
|
}
|
|
@@ -544,12 +544,34 @@
|
|
|
544
544
|
transform: none;
|
|
545
545
|
}
|
|
546
546
|
|
|
547
|
+
.btn-session-export.has-label,
|
|
548
|
+
.btn-session-open.has-label,
|
|
549
|
+
.btn-session-clone.has-label,
|
|
550
|
+
.btn-session-refresh.has-label,
|
|
551
|
+
.btn-session-delete.has-label {
|
|
552
|
+
width: auto;
|
|
553
|
+
min-width: 32px;
|
|
554
|
+
height: 32px;
|
|
555
|
+
padding: 0 var(--spacing-sm);
|
|
556
|
+
gap: 6px;
|
|
557
|
+
font-size: var(--font-size-caption);
|
|
558
|
+
font-weight: var(--font-weight-secondary);
|
|
559
|
+
line-height: 1;
|
|
560
|
+
white-space: nowrap;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
.session-action-label {
|
|
564
|
+
font-size: inherit;
|
|
565
|
+
line-height: 1;
|
|
566
|
+
letter-spacing: 0.01em;
|
|
567
|
+
white-space: nowrap;
|
|
568
|
+
}
|
|
569
|
+
|
|
547
570
|
.btn-icon-sm {
|
|
548
571
|
width: 16px;
|
|
549
572
|
height: 16px;
|
|
550
573
|
flex-shrink: 0;
|
|
551
574
|
}
|
|
552
|
-
|
|
553
575
|
/* ===== Session match badges ===== */
|
|
554
576
|
.session-match-badge {
|
|
555
577
|
display: inline-flex;
|