codexmate 0.1.28 → 0.1.29
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 +53 -44
- package/README.vi.md +45 -36
- package/README.zh.md +51 -42
- package/cli/session-usage.js +2 -2
- package/cli.js +369 -15
- package/package.json +1 -1
- package/web-ui/app.js +3 -0
- package/web-ui/index.html +3 -2
- package/web-ui/logic.sessions.mjs +6 -4
- package/web-ui/modules/app.computed.session.mjs +52 -33
- package/web-ui/modules/app.methods.agents.mjs +36 -0
- package/web-ui/modules/app.methods.codex-config.mjs +3 -1
- package/web-ui/modules/app.methods.providers.mjs +12 -4
- package/web-ui/modules/app.methods.session-actions.mjs +10 -8
- package/web-ui/modules/app.methods.session-browser.mjs +3 -1
- package/web-ui/modules/app.methods.session-trash.mjs +16 -16
- package/web-ui/modules/app.methods.theme.mjs +5 -4
- package/web-ui/modules/i18n/locales/en.mjs +74 -1
- package/web-ui/modules/i18n/locales/ja.mjs +74 -1
- package/web-ui/modules/i18n/locales/vi.mjs +74 -1
- package/web-ui/modules/i18n/locales/zh-tw.mjs +74 -1
- package/web-ui/modules/i18n/locales/zh.mjs +74 -1
- package/web-ui/modules/i18n.mjs +7 -0
- package/web-ui/partials/index/modal-config-template-agents.html +1 -1
- package/web-ui/partials/index/modal-health-check.html +1 -1
- package/web-ui/partials/index/modal-openclaw-config.html +50 -50
- package/web-ui/partials/index/panel-dashboard.html +1 -1
- package/web-ui/partials/index/panel-prompts.html +2 -2
- package/web-ui/partials/index/panel-sessions.html +45 -28
- package/web-ui/partials/index/panel-settings.html +6 -0
- package/web-ui/res/web-ui-render.precompiled.js +219 -156
- package/web-ui/session-helpers.mjs +3 -0
- package/web-ui/styles/base-theme.css +2 -2
- package/web-ui/styles/bridge-pool.css +1 -1
- package/web-ui/styles/layout-shell.css +0 -1
- package/web-ui/styles/sessions-preview.css +77 -0
- package/web-ui/styles/theme-dark-tokens.css +2 -2
- package/web-ui/styles/theme-dark.css +2 -2
- package/web-ui/styles/theme-ocean-tokens.css +88 -0
- package/web-ui/styles/theme-ocean.css +920 -0
- package/web-ui/styles.css +1 -0
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<div class="form-hint">
|
|
13
13
|
{{ openclawConfigPath || t('common.notLoaded') }}
|
|
14
14
|
<span v-if="openclawConfigPath">
|
|
15
|
-
|
|
15
|
+
{{ paren(openclawConfigExists ? t('common.exists') : t('common.notExistsWillCreateOnApply')) }}
|
|
16
16
|
</span>
|
|
17
17
|
</div>
|
|
18
18
|
<div class="btn-group" style="justify-content:flex-start;">
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
<div class="accordion-content" v-show="openclawAccordionStep === 1">
|
|
53
53
|
<div class="form-group">
|
|
54
54
|
<label class="form-label">{{ t('field.providerName') }}</label>
|
|
55
|
-
<input v-model="openclawQuick.providerName" class="form-input" placeholder="
|
|
55
|
+
<input v-model="openclawQuick.providerName" class="form-input" :placeholder="t('modal.openclaw.quick.providerNamePlaceholder')" @input="validateProviderName">
|
|
56
56
|
<div class="form-hint" :class="{ 'hint-error': !openclawValidation.providerName.valid }">
|
|
57
57
|
{{ openclawValidation.providerName.message || t('modal.openclaw.quick.providerHint') }}
|
|
58
58
|
</div>
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
</div>
|
|
88
88
|
<div class="accordion-actions">
|
|
89
89
|
<button class="btn btn-confirm btn-sm" @click="nextAccordionStep" :disabled="!openclawQuick.providerName">
|
|
90
|
-
|
|
90
|
+
{{ t('modal.openclaw.next') }}
|
|
91
91
|
</button>
|
|
92
92
|
</div>
|
|
93
93
|
</div>
|
|
@@ -111,13 +111,13 @@
|
|
|
111
111
|
<label class="form-label">{{ t('field.modelId') }}</label>
|
|
112
112
|
<input v-model="openclawQuick.modelId" class="form-input" :placeholder="t('placeholder.modelIdExample')" @input="validateModelId">
|
|
113
113
|
<div class="form-hint" :class="{ 'hint-error': !openclawValidation.modelId.valid }">
|
|
114
|
-
{{ openclawValidation.modelId.message || '
|
|
114
|
+
{{ openclawValidation.modelId.message || t('modal.openclaw.quick.modelIdHint') }}
|
|
115
115
|
</div>
|
|
116
116
|
</div>
|
|
117
117
|
<div class="form-group">
|
|
118
118
|
<label class="form-label">{{ t('field.displayName') }}</label>
|
|
119
119
|
<input v-model="openclawQuick.modelName" class="form-input" :placeholder="t('placeholder.modelNameOptional')">
|
|
120
|
-
<div class="form-hint"
|
|
120
|
+
<div class="form-hint">{{ t('modal.openclaw.quick.modelNameHint') }}</div>
|
|
121
121
|
</div>
|
|
122
122
|
<div class="form-group">
|
|
123
123
|
<label class="form-label">{{ t('field.contextAndMaxOutput') }}</label>
|
|
@@ -129,10 +129,10 @@
|
|
|
129
129
|
</div>
|
|
130
130
|
<div class="accordion-actions">
|
|
131
131
|
<button class="btn btn-cancel btn-sm" @click="prevAccordionStep">
|
|
132
|
-
|
|
132
|
+
{{ t('modal.openclaw.prev') }}
|
|
133
133
|
</button>
|
|
134
134
|
<button class="btn btn-confirm btn-sm" @click="nextAccordionStep" :disabled="!openclawQuick.modelId">
|
|
135
|
-
|
|
135
|
+
{{ t('modal.openclaw.next') }}
|
|
136
136
|
</button>
|
|
137
137
|
</div>
|
|
138
138
|
</div>
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
<template v-else>3</template>
|
|
147
147
|
</span>
|
|
148
148
|
<span class="accordion-title">{{ t('modal.openclaw.quick.optionsTitle') }}</span>
|
|
149
|
-
<span class="accordion-status"
|
|
149
|
+
<span class="accordion-status">{{ t('modal.openclaw.quick.advancedOptions') }}</span>
|
|
150
150
|
<svg class="accordion-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
151
151
|
<path d="M6 9l6 6 6-6"/>
|
|
152
152
|
</svg>
|
|
@@ -167,10 +167,10 @@
|
|
|
167
167
|
<div class="form-hint">{{ t('modal.openclaw.quick.optionsHint') }}</div>
|
|
168
168
|
<div class="accordion-actions">
|
|
169
169
|
<button class="btn btn-cancel btn-sm" @click="prevAccordionStep">
|
|
170
|
-
|
|
170
|
+
{{ t('modal.openclaw.prev') }}
|
|
171
171
|
</button>
|
|
172
172
|
<button class="btn btn-confirm btn-sm" @click="finishAccordionStep">
|
|
173
|
-
|
|
173
|
+
{{ t('modal.openclaw.finish') }}
|
|
174
174
|
</button>
|
|
175
175
|
</div>
|
|
176
176
|
</div>
|
|
@@ -184,55 +184,55 @@
|
|
|
184
184
|
|
|
185
185
|
<div class="structured-section">
|
|
186
186
|
<div class="structured-header">
|
|
187
|
-
<span class="structured-title"
|
|
187
|
+
<span class="structured-title">{{ t('modal.openclaw.structured.title') }}</span>
|
|
188
188
|
<span class="form-hint">{{ t('modal.openclaw.structured.writeHint') }}</span>
|
|
189
189
|
</div>
|
|
190
190
|
<div class="structured-grid">
|
|
191
191
|
<div class="structured-card">
|
|
192
192
|
<div class="structured-card-title">Agents Defaults</div>
|
|
193
193
|
<div class="form-group">
|
|
194
|
-
<label class="form-label"
|
|
195
|
-
<input v-model="openclawStructured.agentPrimary" class="form-input" placeholder="
|
|
194
|
+
<label class="form-label">{{ t('modal.openclaw.structured.primaryModel') }}</label>
|
|
195
|
+
<input v-model="openclawStructured.agentPrimary" class="form-input" :placeholder="t('modal.openclaw.structured.providerModelPlaceholder')">
|
|
196
196
|
</div>
|
|
197
197
|
<div class="form-group">
|
|
198
|
-
<label class="form-label"
|
|
198
|
+
<label class="form-label">{{ t('modal.openclaw.structured.fallbackModels') }}</label>
|
|
199
199
|
<div class="list-row" v-for="(item, index) in openclawStructured.agentFallbacks" :key="'fallback-' + index">
|
|
200
|
-
<input v-model="openclawStructured.agentFallbacks[index]" class="form-input" placeholder="
|
|
201
|
-
<button class="btn-mini delete" @click="removeOpenclawFallback(index)"
|
|
200
|
+
<input v-model="openclawStructured.agentFallbacks[index]" class="form-input" :placeholder="t('modal.openclaw.structured.providerModelPlaceholder')">
|
|
201
|
+
<button class="btn-mini delete" @click="removeOpenclawFallback(index)">{{ t('common.delete') }}</button>
|
|
202
202
|
</div>
|
|
203
|
-
<button class="btn-mini" @click="addOpenclawFallback"
|
|
203
|
+
<button class="btn-mini" @click="addOpenclawFallback">{{ t('modal.openclaw.structured.addFallback') }}</button>
|
|
204
204
|
</div>
|
|
205
205
|
<div class="form-group">
|
|
206
206
|
<label class="form-label">Workspace</label>
|
|
207
|
-
<input v-model="openclawStructured.workspace" class="form-input" placeholder="
|
|
207
|
+
<input v-model="openclawStructured.workspace" class="form-input" :placeholder="t('modal.openclaw.structured.workspacePlaceholder')">
|
|
208
208
|
</div>
|
|
209
209
|
<div class="form-group">
|
|
210
210
|
<label class="form-label">Timeout(s)</label>
|
|
211
|
-
<input v-model="openclawStructured.timeout" class="form-input" placeholder="
|
|
211
|
+
<input v-model="openclawStructured.timeout" class="form-input" :placeholder="t('modal.openclaw.structured.timeoutPlaceholder')">
|
|
212
212
|
</div>
|
|
213
213
|
<div class="form-group">
|
|
214
214
|
<label class="form-label">Context Tokens</label>
|
|
215
|
-
<input v-model="openclawStructured.contextTokens" class="form-input" placeholder="
|
|
215
|
+
<input v-model="openclawStructured.contextTokens" class="form-input" :placeholder="t('modal.openclaw.structured.contextTokensPlaceholder')">
|
|
216
216
|
</div>
|
|
217
217
|
<div class="form-group">
|
|
218
218
|
<label class="form-label">Max Concurrent</label>
|
|
219
|
-
<input v-model="openclawStructured.maxConcurrent" class="form-input" placeholder="
|
|
219
|
+
<input v-model="openclawStructured.maxConcurrent" class="form-input" :placeholder="t('modal.openclaw.structured.maxConcurrentPlaceholder')">
|
|
220
220
|
</div>
|
|
221
221
|
</div>
|
|
222
222
|
|
|
223
223
|
<div class="structured-card">
|
|
224
224
|
<div class="structured-card-title">Env</div>
|
|
225
225
|
<div class="form-group">
|
|
226
|
-
<label class="form-label"
|
|
226
|
+
<label class="form-label">{{ t('modal.openclaw.structured.envVars') }}</label>
|
|
227
227
|
<div class="list-row" v-for="(item, index) in openclawStructured.envItems" :key="'env-' + index">
|
|
228
228
|
<input v-model="item.key" class="form-input" placeholder="KEY">
|
|
229
229
|
<input v-model="item.value" class="form-input" :type="item.show ? 'text' : 'password'" placeholder="VALUE">
|
|
230
230
|
<button class="btn-mini" @click="toggleOpenclawEnvItem(index)">
|
|
231
|
-
{{ item.show ? '
|
|
231
|
+
{{ item.show ? t('common.hide') : t('common.show') }}
|
|
232
232
|
</button>
|
|
233
|
-
<button class="btn-mini delete" @click="removeOpenclawEnvItem(index)"
|
|
233
|
+
<button class="btn-mini delete" @click="removeOpenclawEnvItem(index)">{{ t('common.delete') }}</button>
|
|
234
234
|
</div>
|
|
235
|
-
<button class="btn-mini" @click="addOpenclawEnvItem"
|
|
235
|
+
<button class="btn-mini" @click="addOpenclawEnvItem">{{ t('modal.openclaw.structured.addEnvVar') }}</button>
|
|
236
236
|
</div>
|
|
237
237
|
</div>
|
|
238
238
|
|
|
@@ -250,34 +250,34 @@
|
|
|
250
250
|
<div class="form-group">
|
|
251
251
|
<label class="form-label">Allow</label>
|
|
252
252
|
<div class="list-row" v-for="(item, index) in openclawStructured.toolsAllow" :key="'allow-' + index">
|
|
253
|
-
<input v-model="openclawStructured.toolsAllow[index]" class="form-input" placeholder="
|
|
254
|
-
<button class="btn-mini delete" @click="removeOpenclawToolsAllow(index)"
|
|
253
|
+
<input v-model="openclawStructured.toolsAllow[index]" class="form-input" :placeholder="t('modal.openclaw.structured.allowPlaceholder')">
|
|
254
|
+
<button class="btn-mini delete" @click="removeOpenclawToolsAllow(index)">{{ t('common.delete') }}</button>
|
|
255
255
|
</div>
|
|
256
|
-
<button class="btn-mini" @click="addOpenclawToolsAllow"
|
|
256
|
+
<button class="btn-mini" @click="addOpenclawToolsAllow">{{ t('modal.openclaw.structured.addAllow') }}</button>
|
|
257
257
|
</div>
|
|
258
258
|
<div class="form-group">
|
|
259
259
|
<label class="form-label">Deny</label>
|
|
260
260
|
<div class="list-row" v-for="(item, index) in openclawStructured.toolsDeny" :key="'deny-' + index">
|
|
261
|
-
<input v-model="openclawStructured.toolsDeny[index]" class="form-input" placeholder="
|
|
262
|
-
<button class="btn-mini delete" @click="removeOpenclawToolsDeny(index)"
|
|
261
|
+
<input v-model="openclawStructured.toolsDeny[index]" class="form-input" :placeholder="t('modal.openclaw.structured.denyPlaceholder')">
|
|
262
|
+
<button class="btn-mini delete" @click="removeOpenclawToolsDeny(index)">{{ t('common.delete') }}</button>
|
|
263
263
|
</div>
|
|
264
|
-
<button class="btn-mini" @click="addOpenclawToolsDeny"
|
|
264
|
+
<button class="btn-mini" @click="addOpenclawToolsDeny">{{ t('modal.openclaw.structured.addDeny') }}</button>
|
|
265
265
|
</div>
|
|
266
266
|
</div>
|
|
267
267
|
|
|
268
268
|
<div class="structured-card">
|
|
269
|
-
<div class="structured-card-title">
|
|
269
|
+
<div class="structured-card-title">{{ t('modal.openclaw.structured.providersTitle') }}</div>
|
|
270
270
|
<div v-if="openclawProviders.length === 0" class="form-hint">
|
|
271
|
-
|
|
271
|
+
{{ t('modal.openclaw.structured.noProviders') }}
|
|
272
272
|
</div>
|
|
273
273
|
<div v-else class="provider-list">
|
|
274
274
|
<div class="provider-item" v-for="(provider, index) in openclawProviders" :key="provider.key + '-' + provider.source + '-' + index">
|
|
275
275
|
<div class="provider-header">
|
|
276
276
|
<span class="provider-name">{{ provider.key }}</span>
|
|
277
|
-
<span class="provider-source"
|
|
278
|
-
<span v-if="provider.isActive" class="pill configured"
|
|
277
|
+
<span class="provider-source">{{ t('modal.openclaw.structured.sourceLabel') }}: {{ provider.source }}</span>
|
|
278
|
+
<span v-if="provider.isActive" class="pill configured">{{ t('modal.openclaw.structured.active') }}</span>
|
|
279
279
|
</div>
|
|
280
|
-
<div v-if="provider.fields.length === 0" class="form-hint"
|
|
280
|
+
<div v-if="provider.fields.length === 0" class="form-hint">{{ t('modal.openclaw.structured.noFields') }}</div>
|
|
281
281
|
<div v-else class="provider-fields">
|
|
282
282
|
<div class="provider-field" v-for="field in provider.fields" :key="provider.key + '-' + field.key">
|
|
283
283
|
<span class="provider-field-key">{{ field.key }}</span>
|
|
@@ -287,14 +287,14 @@
|
|
|
287
287
|
</div>
|
|
288
288
|
</div>
|
|
289
289
|
<div v-if="openclawMissingProviders.length" class="form-hint">
|
|
290
|
-
|
|
290
|
+
{{ t('modal.openclaw.structured.missingProviders', { list: openclawMissingProviders.join(', ') }) }}
|
|
291
291
|
</div>
|
|
292
292
|
</div>
|
|
293
293
|
|
|
294
294
|
<div class="structured-card">
|
|
295
|
-
<div class="structured-card-title">
|
|
295
|
+
<div class="structured-card-title">{{ t('modal.openclaw.structured.agentsTitle') }}</div>
|
|
296
296
|
<div v-if="openclawAgentsList.length === 0" class="form-hint">
|
|
297
|
-
|
|
297
|
+
{{ t('modal.openclaw.structured.noAgents') }}
|
|
298
298
|
</div>
|
|
299
299
|
<div v-else class="agent-list">
|
|
300
300
|
<div class="agent-item" v-for="(agent, index) in openclawAgentsList" :key="agent.key + '-' + index">
|
|
@@ -303,41 +303,41 @@
|
|
|
303
303
|
<span class="agent-id">ID: {{ agent.id }}</span>
|
|
304
304
|
</div>
|
|
305
305
|
<div class="agent-meta" v-if="agent.theme || agent.emoji || agent.avatar">
|
|
306
|
-
<span v-if="agent.theme"
|
|
307
|
-
<span v-if="agent.emoji"
|
|
308
|
-
<span v-if="agent.avatar"
|
|
306
|
+
<span v-if="agent.theme">{{ t('modal.openclaw.structured.themeLabel') }}: {{ agent.theme }}</span>
|
|
307
|
+
<span v-if="agent.emoji">{{ t('modal.openclaw.structured.emojiLabel') }}: {{ agent.emoji }}</span>
|
|
308
|
+
<span v-if="agent.avatar">{{ t('modal.openclaw.structured.avatarLabel') }}: {{ agent.avatar }}</span>
|
|
309
309
|
</div>
|
|
310
310
|
</div>
|
|
311
311
|
</div>
|
|
312
312
|
</div>
|
|
313
313
|
</div>
|
|
314
314
|
<div class="btn-group">
|
|
315
|
-
<button class="btn btn-confirm secondary" @click="syncOpenclawStructuredFromText"
|
|
315
|
+
<button class="btn btn-confirm secondary" @click="syncOpenclawStructuredFromText">{{ t('common.refreshFromText') }}</button>
|
|
316
316
|
<button class="btn btn-confirm" @click="applyOpenclawStructuredToText">{{ t('common.writeToEditor') }}</button>
|
|
317
317
|
</div>
|
|
318
318
|
</div>
|
|
319
319
|
|
|
320
320
|
<div class="form-group">
|
|
321
|
-
<label class="form-label">
|
|
321
|
+
<label class="form-label">{{ t('modal.openclaw.editorLabel') }}</label>
|
|
322
322
|
<textarea
|
|
323
323
|
v-model="openclawEditing.content"
|
|
324
324
|
class="form-input template-editor"
|
|
325
325
|
spellcheck="false"
|
|
326
326
|
:readonly="openclawSaving || openclawApplying"
|
|
327
|
-
placeholder="
|
|
327
|
+
:placeholder="t('modal.openclaw.editorPlaceholder')"></textarea>
|
|
328
328
|
<div class="template-editor-warning">
|
|
329
|
-
<span v-if="openclawEditing.lockName && isDefaultOpenclawConfig(openclawEditing.name)"
|
|
330
|
-
<span v-else
|
|
329
|
+
<span v-if="openclawEditing.lockName && isDefaultOpenclawConfig(openclawEditing.name)">{{ t('modal.openclaw.defaultConfigHint') }}</span>
|
|
330
|
+
<span v-else>{{ t('modal.openclaw.saveOnlyHint') }}</span>
|
|
331
331
|
</div>
|
|
332
332
|
</div>
|
|
333
333
|
|
|
334
334
|
<div class="btn-group">
|
|
335
|
-
<button class="btn btn-cancel" @click="closeOpenclawConfigModal" :disabled="openclawSaving || openclawApplying"
|
|
335
|
+
<button class="btn btn-cancel" @click="closeOpenclawConfigModal" :disabled="openclawSaving || openclawApplying">{{ t('common.cancel') }}</button>
|
|
336
336
|
<button class="btn btn-confirm" @click="saveOpenclawConfig" :disabled="openclawSaving || openclawApplying || (openclawEditing.lockName && isDefaultOpenclawConfig(openclawEditing.name))">
|
|
337
|
-
{{ openclawSaving ? '
|
|
337
|
+
{{ openclawSaving ? t('common.saving') : t('common.save') }}
|
|
338
338
|
</button>
|
|
339
339
|
<button class="btn btn-confirm secondary" @click="saveAndApplyOpenclawConfig" :disabled="openclawSaving || openclawApplying">
|
|
340
|
-
{{ openclawApplying ? '
|
|
340
|
+
{{ openclawApplying ? t('common.applying') : t('common.saveApply') }}
|
|
341
341
|
</button>
|
|
342
342
|
</div>
|
|
343
343
|
</div>
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
<div class="doctor-health-result" :class="healthCheckResult.ok ? 'ok' : 'error'">
|
|
36
36
|
<div class="doctor-health-title">
|
|
37
37
|
{{ healthCheckResult.ok ? t('dashboard.health.ok') : t('dashboard.health.fail') }}
|
|
38
|
-
<span v-if="healthCheckResult.issues && healthCheckResult.issues.length"
|
|
38
|
+
<span v-if="healthCheckResult.issues && healthCheckResult.issues.length">{{ paren(t('dashboard.health.issues', { count: healthCheckResult.issues.length })) }}</span>
|
|
39
39
|
</div>
|
|
40
40
|
</div>
|
|
41
41
|
<div v-if="healthCheckResult.report" class="doctor-action-list">
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
<div class="form-hint">
|
|
41
41
|
{{ agentsPath || t('common.notLoaded') }}
|
|
42
42
|
<span v-if="agentsPath">
|
|
43
|
-
|
|
43
|
+
{{ paren(agentsExists ? t('common.exists') : t('common.notExistsWillCreateOnSave')) }}
|
|
44
44
|
</span>
|
|
45
45
|
<span v-if="agentsPath" class="prompts-token-hint">· {{ t('prompts.tokenCount.hint', { count: agentsTokenCount }) }}</span>
|
|
46
46
|
</div>
|
|
@@ -279,7 +279,7 @@
|
|
|
279
279
|
<div class="form-hint">
|
|
280
280
|
{{ sysPromptPath || t('common.notLoaded') }}
|
|
281
281
|
<span v-if="sysPromptPath">
|
|
282
|
-
|
|
282
|
+
{{ paren(sysPromptExists ? t('common.exists') : t('common.notExistsWillCreateOnSave')) }}
|
|
283
283
|
</span>
|
|
284
284
|
<span v-if="sysPromptPath" class="prompts-token-hint">· {{ t('prompts.tokenCount.hint', { count: sysPromptTokenCount }) }}</span>
|
|
285
285
|
</div>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- 会话浏览模式 -->
|
|
2
2
|
<div
|
|
3
3
|
v-show="mainTab === 'sessions'"
|
|
4
|
-
class="mode-content"
|
|
4
|
+
class="mode-content session-browser-refined"
|
|
5
5
|
id="panel-sessions"
|
|
6
6
|
role="tabpanel"
|
|
7
7
|
:aria-labelledby="'tab-sessions'">
|
|
@@ -133,12 +133,19 @@
|
|
|
133
133
|
</div>
|
|
134
134
|
</div>
|
|
135
135
|
|
|
136
|
+
<div v-if="sessionSearchInfo && !sessionsLoading" class="session-search-status" role="status">
|
|
137
|
+
<span class="session-search-count">{{ t('sessions.search.coverage', { scanned: sessionSearchInfo.scanned, candidates: sessionSearchInfo.candidates }) }}</span>
|
|
138
|
+
<span v-if="!sessionSearchInfo.complete" class="session-search-partial">{{ t('sessions.search.partial') }}</span>
|
|
139
|
+
<small class="session-search-scope">{{ t('sessions.search.scopeHint') }}</small>
|
|
140
|
+
</div>
|
|
141
|
+
|
|
136
142
|
<div v-if="sessionsLoading && sessionsList.length === 0" class="state-message">
|
|
137
143
|
{{ t('sessions.loadingList') }}
|
|
138
144
|
</div>
|
|
139
145
|
|
|
140
|
-
<div v-else-if="!sessionsLoading && sessionsList.length === 0" class="session-empty">
|
|
141
|
-
{{ t('sessions.empty') }}
|
|
146
|
+
<div v-else-if="!sessionsLoading && sessionsList.length === 0" class="session-empty session-empty-refined">
|
|
147
|
+
<p>{{ t(hasActiveSessionFilters() ? 'sessions.empty.filtered' : 'sessions.empty.source') }}</p>
|
|
148
|
+
<button v-if="hasActiveSessionFilters()" class="btn-tool btn-tool-compact" type="button" @click="clearSessionFilters">{{ t('sessions.empty.clearFilters') }}</button>
|
|
142
149
|
</div>
|
|
143
150
|
|
|
144
151
|
<div v-else class="session-layout">
|
|
@@ -244,24 +251,13 @@
|
|
|
244
251
|
<span class="session-preview-meta-item">{{ activeSession.cwd }}</span>
|
|
245
252
|
</div>
|
|
246
253
|
</div>
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
<button
|
|
255
|
-
v-if="isDeleteAvailable(activeSession)"
|
|
256
|
-
class="btn-session-delete has-label"
|
|
257
|
-
@click="deleteSession(activeSession)"
|
|
258
|
-
:disabled="!activeSession || sessionsLoading || sessionDeleting[getSessionExportKey(activeSession)]"
|
|
259
|
-
: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'))"
|
|
260
|
-
: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'))">
|
|
261
|
-
<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>
|
|
262
|
-
<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>
|
|
263
|
-
</button>
|
|
264
|
-
<button
|
|
254
|
+
<div class="session-export-control">
|
|
255
|
+
<label class="session-export-label" for="session-export-range">{{ t('sessions.export.range') }}</label>
|
|
256
|
+
<select id="session-export-range" v-model="sessionExportRange" :disabled="sessionExporting[getSessionExportKey(activeSession)]" aria-describedby="session-export-scope">
|
|
257
|
+
<option value="default">{{ t('sessions.export.default') }}</option>
|
|
258
|
+
<option value="all">{{ t('sessions.export.all') }}</option>
|
|
259
|
+
</select>
|
|
260
|
+
<button
|
|
265
261
|
class="btn-session-export has-label"
|
|
266
262
|
@click="exportSession(activeSession)"
|
|
267
263
|
:disabled="!activeSession || sessionExporting[getSessionExportKey(activeSession)]"
|
|
@@ -270,25 +266,31 @@
|
|
|
270
266
|
<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>
|
|
271
267
|
<span class="session-action-label">{{ (activeSession && sessionExporting[getSessionExportKey(activeSession)]) ? t('sessions.preview.exporting') : t('sessions.preview.export') }}</span>
|
|
272
268
|
</button>
|
|
273
|
-
|
|
274
|
-
|
|
269
|
+
</div>
|
|
270
|
+
<div class="session-actions session-preview-actions">
|
|
271
|
+
<div class="session-secondary-actions">
|
|
272
|
+
<button class="btn-session-refresh has-label" @click="loadActiveSessionDetail" :disabled="sessionDetailLoading || !activeSession"
|
|
273
|
+
:title="sessionDetailLoading ? t('sessions.preview.loading') : t('sessions.preview.refresh')"
|
|
274
|
+
:aria-label="sessionDetailLoading ? t('sessions.preview.loading') : t('sessions.preview.refresh')">
|
|
275
|
+
<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>
|
|
276
|
+
<span class="session-action-label">{{ t('sessions.preview.refresh') }}</span>
|
|
277
|
+
</button>
|
|
278
|
+
<div class="session-link-group"><button
|
|
275
279
|
class="btn-session-open"
|
|
276
280
|
@click="copySessionLink(activeSession)"
|
|
277
281
|
:disabled="!activeSession || !canBuildStandaloneUrl(activeSession)"
|
|
278
282
|
:title="t('sessions.preview.copyLink')"
|
|
279
283
|
:aria-label="t('sessions.preview.copyLink')">
|
|
280
284
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6.5 9.5a3.5 3.5 0 0 0 5 0l2-2a3.5 3.5 0 0 0-5-5l-1 1"/><path d="M9.5 6.5a3.5 3.5 0 0 0-5 0l-2 2a3.5 3.5 0 0 0 5 5l1-1"/></svg>
|
|
281
|
-
</button>
|
|
282
|
-
<button
|
|
285
|
+
</button> <button
|
|
283
286
|
class="btn-session-open"
|
|
284
287
|
@click="openSessionLink(activeSession)"
|
|
285
288
|
:disabled="!activeSession || !canBuildStandaloneUrl(activeSession)"
|
|
286
289
|
:title="t('sessions.preview.openLink')"
|
|
287
290
|
:aria-label="t('sessions.preview.openLink')">
|
|
288
291
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2h-8.5A1.5 1.5 0 0 0 2 3.5v8A1.5 1.5 0 0 0 3.5 13h8a1.5 1.5 0 0 0 1.5-1.5v-3"/><path d="M13 2v4h-4"/><path d="M13 2L7 8"/></svg>
|
|
289
|
-
</button>
|
|
290
|
-
|
|
291
|
-
<button
|
|
292
|
+
</button></div>
|
|
293
|
+
<button
|
|
292
294
|
class="btn-session-open has-label"
|
|
293
295
|
@click="copySessionPath(activeSession)"
|
|
294
296
|
:disabled="!activeSession || !getSessionFilePath(activeSession)"
|
|
@@ -297,8 +299,23 @@
|
|
|
297
299
|
<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>
|
|
298
300
|
<span class="session-action-label">{{ t('sessions.preview.copyPath') }}</span>
|
|
299
301
|
</button>
|
|
302
|
+
</div>
|
|
303
|
+
<div class="session-danger-action"><button
|
|
304
|
+
v-if="isDeleteAvailable(activeSession)"
|
|
305
|
+
class="btn-session-delete has-label"
|
|
306
|
+
@click="deleteSession(activeSession)"
|
|
307
|
+
:disabled="!activeSession || sessionsLoading || sessionDeleting[getSessionExportKey(activeSession)]"
|
|
308
|
+
: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'))"
|
|
309
|
+
: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'))">
|
|
310
|
+
<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>
|
|
311
|
+
<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>
|
|
312
|
+
</button></div>
|
|
300
313
|
</div>
|
|
301
314
|
</div>
|
|
315
|
+
<div class="session-export-feedback">
|
|
316
|
+
<small id="session-export-scope">{{ t('sessions.export.scopeHint') }}</small>
|
|
317
|
+
<p v-if="sessionExportNotice && sessionExportNotice.key === getSessionExportKey(activeSession)" class="session-export-notice" role="status">{{ t('sessions.export.truncated') }}</p>
|
|
318
|
+
</div>
|
|
302
319
|
|
|
303
320
|
<div v-if="sessionDetailLoading && !sessionPreviewLoadingMore" class="session-preview-empty">
|
|
304
321
|
{{ t('sessions.preview.loadingBody') }}
|
|
@@ -79,6 +79,12 @@
|
|
|
79
79
|
@click="setTheme('dark')">
|
|
80
80
|
{{ t('settings.theme.dark') }}
|
|
81
81
|
</button>
|
|
82
|
+
<button
|
|
83
|
+
type="button"
|
|
84
|
+
:class="['toggle-btn', { active: theme === 'ocean' }]"
|
|
85
|
+
@click="setTheme('ocean')">
|
|
86
|
+
{{ t('settings.theme.ocean') }}
|
|
87
|
+
</button>
|
|
82
88
|
</div>
|
|
83
89
|
<p class="settings-card-hint">{{ t('settings.theme.hint') }}</p>
|
|
84
90
|
</div>
|