codexmate 0.0.38 → 0.0.40
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/cli/builtin-proxy.js +626 -207
- package/cli/config-bootstrap.js +6 -1
- package/cli/openai-bridge.js +541 -210
- package/cli.js +189 -4
- package/package.json +1 -1
- package/plugins/prompt-templates/computed.mjs +61 -3
- package/plugins/prompt-templates/manifest.mjs +3 -0
- package/web-ui/app.js +14 -3
- package/web-ui/modules/app.computed.main-tabs.mjs +39 -30
- package/web-ui/modules/app.methods.claude-config.mjs +111 -9
- package/web-ui/modules/app.methods.index.mjs +2 -0
- package/web-ui/modules/app.methods.openclaw-editing.mjs +48 -0
- package/web-ui/modules/app.methods.openclaw-persist.mjs +13 -7
- package/web-ui/modules/app.methods.providers.mjs +36 -10
- package/web-ui/modules/app.methods.runtime.mjs +76 -1
- package/web-ui/modules/app.methods.startup-claude.mjs +7 -0
- package/web-ui/modules/app.methods.tool-config-permissions.mjs +87 -0
- package/web-ui/modules/config-mode.computed.mjs +3 -3
- package/web-ui/modules/i18n/locales/en.mjs +1140 -0
- package/web-ui/modules/i18n/locales/ja.mjs +1130 -0
- package/web-ui/modules/i18n/locales/vi.mjs +239 -0
- package/web-ui/modules/i18n/locales/zh.mjs +1143 -0
- package/web-ui/modules/i18n.dict.mjs +9 -3195
- package/web-ui/modules/i18n.mjs +65 -16
- package/web-ui/partials/index/layout-header.html +16 -46
- package/web-ui/partials/index/modal-openclaw-config.html +135 -71
- package/web-ui/partials/index/modal-webhook.html +8 -8
- package/web-ui/partials/index/modals-basic.html +56 -16
- package/web-ui/partials/index/panel-config-claude.html +51 -21
- package/web-ui/partials/index/panel-config-codex.html +34 -5
- package/web-ui/partials/index/panel-config-openclaw.html +70 -64
- package/web-ui/partials/index/panel-dashboard.html +62 -77
- package/web-ui/partials/index/panel-settings.html +28 -7
- package/web-ui/partials/index/panel-trash.html +14 -14
- package/web-ui/res/web-ui-render.precompiled.js +1783 -1386
- package/web-ui/styles/controls-forms.css +99 -0
- package/web-ui/styles/dashboard.css +46 -14
- package/web-ui/styles/layout-shell.css +45 -0
- package/web-ui/styles/navigation-panels.css +3 -3
- package/web-ui/styles/openclaw-structured.css +383 -33
- package/web-ui/styles/responsive.css +68 -0
- package/web-ui/styles/sessions-usage.css +105 -9
- package/web-ui/styles/settings-panel.css +4 -0
|
@@ -16,6 +16,68 @@
|
|
|
16
16
|
</button>
|
|
17
17
|
</div>
|
|
18
18
|
</div>
|
|
19
|
+
<div class="doctor-status-row">
|
|
20
|
+
<div class="doctor-status-chip" :class="inspectorHealthTone">
|
|
21
|
+
<span>{{ t('dashboard.status.health') }}</span>
|
|
22
|
+
<strong>{{ inspectorHealthStatus }}</strong>
|
|
23
|
+
</div>
|
|
24
|
+
<div class="doctor-status-chip">
|
|
25
|
+
<span>{{ t('dashboard.status.busy') }}</span>
|
|
26
|
+
<strong>{{ inspectorBusyStatus }}</strong>
|
|
27
|
+
</div>
|
|
28
|
+
<div class="doctor-status-chip">
|
|
29
|
+
<span>{{ t('dashboard.status.models') }}</span>
|
|
30
|
+
<strong>{{ inspectorModelLoadStatus }}</strong>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
<div v-if="healthCheckResult" class="doctor-health-result" :class="healthCheckResult.ok ? 'ok' : 'error'">
|
|
34
|
+
<div class="doctor-health-title">
|
|
35
|
+
{{ healthCheckResult.ok ? t('dashboard.health.ok') : t('dashboard.health.fail') }}
|
|
36
|
+
<span v-if="healthCheckResult.issues && healthCheckResult.issues.length">({{ t('dashboard.health.issues', { count: healthCheckResult.issues.length }) }})</span>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
<div v-if="healthCheckResult && healthCheckResult.report" class="doctor-action-list">
|
|
40
|
+
<template v-if="healthCheckResult.report.issues && healthCheckResult.report.issues.length">
|
|
41
|
+
<div v-for="issue in healthCheckResult.report.issues" :key="issue.id" class="doctor-action-card">
|
|
42
|
+
<div class="doctor-action-head">
|
|
43
|
+
<div class="doctor-action-title">{{ issue.problem || (issue.problemKey ? t(issue.problemKey, issue.problemParams) : '') }}</div>
|
|
44
|
+
<div :class="['doctor-action-severity', issue.severity]">{{ issue.severityLabel || issue.severity }}</div>
|
|
45
|
+
</div>
|
|
46
|
+
<div class="doctor-action-impact">{{ issue.impact || (issue.impactKey ? t(issue.impactKey, issue.impactParams) : '') }}</div>
|
|
47
|
+
<div
|
|
48
|
+
v-if="issue.actions && issue.actions.some(action => action && action.type === 'navigate' && action.target)"
|
|
49
|
+
class="doctor-action-buttons">
|
|
50
|
+
<template v-for="(action, index) in issue.actions" :key="issue.id + '-action-' + index">
|
|
51
|
+
<button
|
|
52
|
+
v-if="action.type === 'navigate' && action.target"
|
|
53
|
+
type="button"
|
|
54
|
+
class="btn-tool btn-tool-compact"
|
|
55
|
+
@click="action.target ? switchMainTab(action.target) : null">
|
|
56
|
+
{{ action.label || (action.labelKey ? t(action.labelKey, action.labelParams) : t('dashboard.doctor.open')) }}
|
|
57
|
+
</button>
|
|
58
|
+
</template>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</template>
|
|
62
|
+
<div class="doctor-action-footer">
|
|
63
|
+
<button
|
|
64
|
+
type="button"
|
|
65
|
+
class="btn-tool btn-tool-compact"
|
|
66
|
+
@click="healthCheckResult && healthCheckResult.report
|
|
67
|
+
? downloadTextFile('codexmate-doctor.json', JSON.stringify(healthCheckResult.report, null, 2), 'application/json;charset=utf-8')
|
|
68
|
+
: null">
|
|
69
|
+
{{ t('dashboard.doctor.export.json') }}
|
|
70
|
+
</button>
|
|
71
|
+
<button
|
|
72
|
+
type="button"
|
|
73
|
+
class="btn-tool btn-tool-compact"
|
|
74
|
+
@click="healthCheckResult && healthCheckResult.report
|
|
75
|
+
? downloadTextFile('codexmate-doctor.md', String(healthCheckResult.markdown || ''), 'text/markdown;charset=utf-8')
|
|
76
|
+
: null">
|
|
77
|
+
{{ t('dashboard.doctor.export.md') }}
|
|
78
|
+
</button>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
19
81
|
<div class="doctor-grid">
|
|
20
82
|
<button type="button" class="doctor-card" @click="switchMainTab('config')" :disabled="loading || !!initError">
|
|
21
83
|
<div class="doctor-card-title">{{ t('dashboard.card.config') }}</div>
|
|
@@ -105,82 +167,5 @@
|
|
|
105
167
|
</div>
|
|
106
168
|
</button>
|
|
107
169
|
</div>
|
|
108
|
-
<div class="doctor-status-row">
|
|
109
|
-
<div class="doctor-status-chip" :class="inspectorHealthTone">
|
|
110
|
-
<span>{{ t('dashboard.status.health') }}</span>
|
|
111
|
-
<strong>{{ inspectorHealthStatus }}</strong>
|
|
112
|
-
</div>
|
|
113
|
-
<div class="doctor-status-chip">
|
|
114
|
-
<span>{{ t('dashboard.status.busy') }}</span>
|
|
115
|
-
<strong>{{ inspectorBusyStatus }}</strong>
|
|
116
|
-
</div>
|
|
117
|
-
<div class="doctor-status-chip">
|
|
118
|
-
<span>{{ t('dashboard.status.models') }}</span>
|
|
119
|
-
<strong>{{ inspectorModelLoadStatus }}</strong>
|
|
120
|
-
</div>
|
|
121
|
-
</div>
|
|
122
|
-
<div v-if="healthCheckResult" class="doctor-health-result" :class="healthCheckResult.ok ? 'ok' : 'error'">
|
|
123
|
-
<div class="doctor-health-title">
|
|
124
|
-
{{ healthCheckResult.ok ? t('dashboard.health.ok') : t('dashboard.health.fail') }}
|
|
125
|
-
<span v-if="healthCheckResult.issues && healthCheckResult.issues.length">({{ t('dashboard.health.issues', { count: healthCheckResult.issues.length }) }})</span>
|
|
126
|
-
</div>
|
|
127
|
-
</div>
|
|
128
|
-
<div v-if="healthCheckResult && healthCheckResult.report && healthCheckResult.report.issues && healthCheckResult.report.issues.length" class="doctor-action-list">
|
|
129
|
-
<div v-for="issue in healthCheckResult.report.issues" :key="issue.id" class="doctor-action-card">
|
|
130
|
-
<div class="doctor-action-head">
|
|
131
|
-
<div class="doctor-action-title">{{ issue.problem || (issue.problemKey ? t(issue.problemKey, issue.problemParams) : '') }}</div>
|
|
132
|
-
<div :class="['doctor-action-severity', issue.severity]">{{ issue.severityLabel || issue.severity }}</div>
|
|
133
|
-
</div>
|
|
134
|
-
<div class="doctor-action-impact">{{ issue.impact || (issue.impactKey ? t(issue.impactKey, issue.impactParams) : '') }}</div>
|
|
135
|
-
<div v-if="issue.actions && issue.actions.length" class="doctor-action-buttons">
|
|
136
|
-
<template v-for="(action, index) in issue.actions" :key="issue.id + '-action-' + index">
|
|
137
|
-
<button
|
|
138
|
-
v-if="action.type === 'navigate'"
|
|
139
|
-
type="button"
|
|
140
|
-
class="btn-tool btn-tool-compact"
|
|
141
|
-
@click="switchMainTab(action.target)">
|
|
142
|
-
{{ action.label || (action.labelKey ? t(action.labelKey, action.labelParams) : t('dashboard.doctor.open')) }}
|
|
143
|
-
</button>
|
|
144
|
-
<button
|
|
145
|
-
v-else-if="action.type === 'run-check'"
|
|
146
|
-
type="button"
|
|
147
|
-
class="btn-tool btn-tool-compact"
|
|
148
|
-
@click="runHealthCheck({ doctor: true, forceRefresh: true })"
|
|
149
|
-
:disabled="healthCheckLoading">
|
|
150
|
-
{{ t('dashboard.doctor.runChecks') }}
|
|
151
|
-
</button>
|
|
152
|
-
<button
|
|
153
|
-
v-else-if="action.type === 'export'"
|
|
154
|
-
type="button"
|
|
155
|
-
class="btn-tool btn-tool-compact"
|
|
156
|
-
@click="healthCheckResult && healthCheckResult.report
|
|
157
|
-
? (action.format === 'md'
|
|
158
|
-
? downloadTextFile('codexmate-doctor.md', String(healthCheckResult.markdown || ''), 'text/markdown;charset=utf-8')
|
|
159
|
-
: downloadTextFile('codexmate-doctor.json', JSON.stringify(healthCheckResult.report, null, 2), 'application/json;charset=utf-8'))
|
|
160
|
-
: null">
|
|
161
|
-
{{ action.format === 'md' ? t('dashboard.doctor.export.md') : t('dashboard.doctor.export.json') }}
|
|
162
|
-
</button>
|
|
163
|
-
</template>
|
|
164
|
-
</div>
|
|
165
|
-
</div>
|
|
166
|
-
<div class="doctor-action-footer">
|
|
167
|
-
<button
|
|
168
|
-
type="button"
|
|
169
|
-
class="btn-tool btn-tool-compact"
|
|
170
|
-
@click="healthCheckResult && healthCheckResult.report
|
|
171
|
-
? downloadTextFile('codexmate-doctor.json', JSON.stringify(healthCheckResult.report, null, 2), 'application/json;charset=utf-8')
|
|
172
|
-
: null">
|
|
173
|
-
{{ t('dashboard.doctor.export.json') }}
|
|
174
|
-
</button>
|
|
175
|
-
<button
|
|
176
|
-
type="button"
|
|
177
|
-
class="btn-tool btn-tool-compact"
|
|
178
|
-
@click="healthCheckResult && healthCheckResult.report
|
|
179
|
-
? downloadTextFile('codexmate-doctor.md', String(healthCheckResult.markdown || ''), 'text/markdown;charset=utf-8')
|
|
180
|
-
: null">
|
|
181
|
-
{{ t('dashboard.doctor.export.md') }}
|
|
182
|
-
</button>
|
|
183
|
-
</div>
|
|
184
|
-
</div>
|
|
185
170
|
</div>
|
|
186
171
|
</div>
|
|
@@ -40,6 +40,27 @@
|
|
|
40
40
|
role="tabpanel"
|
|
41
41
|
aria-labelledby="settings-tab-general">
|
|
42
42
|
<div class="settings-grid">
|
|
43
|
+
<section id="settings-language" class="settings-card" :aria-label="t('settings.language.title')">
|
|
44
|
+
<div class="settings-card-main">
|
|
45
|
+
<div class="settings-card-content">
|
|
46
|
+
<div class="settings-card-title">{{ t('settings.language.title') }}</div>
|
|
47
|
+
<p class="settings-card-desc">{{ t('settings.language.meta') }}</p>
|
|
48
|
+
<label class="selector-label" for="settings-language-select">{{ t('settings.language.label') }}</label>
|
|
49
|
+
<select
|
|
50
|
+
id="settings-language-select"
|
|
51
|
+
class="model-select settings-language-select"
|
|
52
|
+
:value="lang"
|
|
53
|
+
@change="setLang($event.target.value)">
|
|
54
|
+
<option
|
|
55
|
+
v-for="option in languageOptions()"
|
|
56
|
+
:key="option.code"
|
|
57
|
+
:value="option.code">{{ option.nativeName }} · {{ option.englishName }}</option>
|
|
58
|
+
</select>
|
|
59
|
+
<p class="settings-card-hint">{{ t('settings.language.hint') }}</p>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</section>
|
|
63
|
+
|
|
43
64
|
<section class="settings-card" :aria-label="t('settings.sharePrefix.title')">
|
|
44
65
|
<div class="settings-card-main">
|
|
45
66
|
<div class="settings-card-content">
|
|
@@ -76,21 +97,21 @@
|
|
|
76
97
|
</div>
|
|
77
98
|
</section>
|
|
78
99
|
|
|
79
|
-
<section class="settings-card" :aria-label="'
|
|
100
|
+
<section class="settings-card" :aria-label="t('settings.webhook.title')">
|
|
80
101
|
<div class="settings-card-main">
|
|
81
102
|
<div class="settings-card-content">
|
|
82
|
-
<div class="settings-card-title">
|
|
83
|
-
<p class="settings-card-desc"
|
|
103
|
+
<div class="settings-card-title">{{ t('settings.webhook.title') }}</div>
|
|
104
|
+
<p class="settings-card-desc">{{ t('settings.webhook.meta') }}</p>
|
|
84
105
|
<div class="webhook-status">
|
|
85
106
|
<span class="webhook-status-dot" :class="{ active: webhookConfig.enabled }"></span>
|
|
86
|
-
<span class="webhook-status-label">{{ webhookConfig.enabled ? '
|
|
107
|
+
<span class="webhook-status-label">{{ webhookConfig.enabled ? t('settings.webhook.enabled') : t('settings.webhook.disabled') }}</span>
|
|
87
108
|
<code v-if="webhookConfig.url" class="webhook-url">{{ webhookConfig.url }}</code>
|
|
88
109
|
</div>
|
|
89
110
|
</div>
|
|
90
111
|
</div>
|
|
91
112
|
<button class="settings-card-action" @click="openWebhookModal" :class="{ 'settings-card-action--active': webhookConfig.enabled }">
|
|
92
|
-
<span v-if="webhookConfig.enabled">{{ webhookConfig.url ? '
|
|
93
|
-
<span v-else
|
|
113
|
+
<span v-if="webhookConfig.enabled">{{ webhookConfig.url ? t('settings.webhook.edit') : t('settings.webhook.configure') }}</span>
|
|
114
|
+
<span v-else>{{ t('settings.webhook.enable') }}</span>
|
|
94
115
|
</button>
|
|
95
116
|
</section>
|
|
96
117
|
</div>
|
|
@@ -136,7 +157,7 @@
|
|
|
136
157
|
<div class="settings-retention">
|
|
137
158
|
<label for="settings-trash-retention-days">{{ t('settings.trash.retentionLabel') }}</label>
|
|
138
159
|
<input id="settings-trash-retention-days" type="number" min="1" max="365" :value="sessionTrashRetentionDays" @change="setSessionTrashRetentionDays(Number($event.target.value))" class="settings-retention-input" />
|
|
139
|
-
<span
|
|
160
|
+
<span>{{ t('settings.trash.retentionUnit') }}</span>
|
|
140
161
|
</div>
|
|
141
162
|
<p class="settings-card-hint">{{ t('settings.trash.retentionHint') }}</p>
|
|
142
163
|
</div>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!--
|
|
1
|
+
<!-- Trash panel -->
|
|
2
2
|
<div
|
|
3
3
|
v-show="mainTab === 'trash'"
|
|
4
4
|
class="mode-content"
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
role="tabpanel"
|
|
7
7
|
aria-labelledby="tab-trash">
|
|
8
8
|
<div v-if="!loading" class="trash-panel-shell">
|
|
9
|
-
<!--
|
|
9
|
+
<!-- Empty state -->
|
|
10
10
|
<div v-if="getSessionTrashViewState() === 'empty'" class="trash-empty-state">
|
|
11
11
|
<svg class="trash-empty-svg" viewBox="0 0 64 64" fill="none" stroke="currentColor" stroke-width="1.2">
|
|
12
12
|
<path d="M20 22l4 32h16l4-32"/>
|
|
@@ -15,38 +15,38 @@
|
|
|
15
15
|
<path d="M28 30v16M36 30v16" stroke-width="1.6" stroke-linecap="round"/>
|
|
16
16
|
</svg>
|
|
17
17
|
<div class="trash-empty-title">{{ t('settings.trash.empty') }}</div>
|
|
18
|
-
<div class="trash-empty-hint"
|
|
18
|
+
<div class="trash-empty-hint">{{ t('settings.trash.emptyHint', { days: sessionTrashRetentionDays }) }}</div>
|
|
19
19
|
</div>
|
|
20
20
|
|
|
21
|
-
<!--
|
|
21
|
+
<!-- Loading state -->
|
|
22
22
|
<div v-else-if="getSessionTrashViewState() === 'loading'" class="trash-empty-state">
|
|
23
23
|
<div class="trash-spinner"></div>
|
|
24
24
|
<div class="trash-empty-title">{{ t('settings.trash.loading') }}</div>
|
|
25
25
|
</div>
|
|
26
26
|
|
|
27
|
-
<!--
|
|
27
|
+
<!-- Error state -->
|
|
28
28
|
<div v-else-if="getSessionTrashViewState() === 'retry'" class="trash-empty-state">
|
|
29
29
|
<svg class="trash-empty-svg" viewBox="0 0 64 64" fill="none" stroke="currentColor" stroke-width="1.2">
|
|
30
30
|
<circle cx="32" cy="32" r="22"/>
|
|
31
31
|
<path d="M32 20v16M32 44v2" stroke-width="2" stroke-linecap="round"/>
|
|
32
32
|
</svg>
|
|
33
33
|
<div class="trash-empty-title">{{ t('settings.trash.retry') }}</div>
|
|
34
|
-
<button class="btn-tool" @click="loadSessionTrash({ forceRefresh: true })"
|
|
34
|
+
<button class="btn-tool" @click="loadSessionTrash({ forceRefresh: true })">{{ t('common.retry') }}</button>
|
|
35
35
|
</div>
|
|
36
36
|
|
|
37
|
-
<!--
|
|
37
|
+
<!-- List state -->
|
|
38
38
|
<template v-else>
|
|
39
39
|
<div class="trash-toolbar">
|
|
40
40
|
<div class="trash-toolbar-left">
|
|
41
|
-
<span class="trash-toolbar-count">{{ sessionTrashCount }}
|
|
42
|
-
<span class="trash-toolbar-retention">{{ sessionTrashRetentionDays }}
|
|
41
|
+
<span class="trash-toolbar-count">{{ t('settings.trash.count', { count: sessionTrashCount }) }}</span>
|
|
42
|
+
<span class="trash-toolbar-retention">{{ t('settings.trash.retentionShort', { days: sessionTrashRetentionDays }) }}</span>
|
|
43
43
|
</div>
|
|
44
44
|
<div class="trash-toolbar-right">
|
|
45
|
-
<button class="btn-mini" @click="loadSessionTrash({ forceRefresh: true })" :disabled="sessionTrashLoading" :title="t('sessions.refresh')">
|
|
45
|
+
<button class="btn-mini" @click="loadSessionTrash({ forceRefresh: true })" :disabled="sessionTrashLoading" :aria-label="t('sessions.refresh')" :title="t('sessions.refresh')">
|
|
46
46
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="btn-icon-sm"><path d="M21 2v6h-6M3 12a9 9 0 0115-6.7L21 8M3 22v-6h6M21 12a9 9 0 01-15 6.7L3 16"/></svg>
|
|
47
47
|
</button>
|
|
48
48
|
<button class="btn-mini delete" @click="clearSessionTrash" :disabled="sessionTrashClearing || sessionTrashLoading || !(Number(sessionTrashCount) > 0)">
|
|
49
|
-
{{ sessionTrashClearing ? '
|
|
49
|
+
{{ sessionTrashClearing ? t('settings.trash.clearing') : t('settings.trash.clearShort') }}
|
|
50
50
|
</button>
|
|
51
51
|
</div>
|
|
52
52
|
</div>
|
|
@@ -63,10 +63,10 @@
|
|
|
63
63
|
</div>
|
|
64
64
|
</div>
|
|
65
65
|
<div class="trash-item-actions">
|
|
66
|
-
<button class="trash-action-btn restore" @click="restoreSessionTrash(item)" :disabled="sessionTrashLoading || sessionTrashClearing || isSessionTrashActionBusy(item)" :title="sessionTrashRestoring[getSessionTrashActionKey(item)] ? '
|
|
66
|
+
<button class="trash-action-btn restore" @click="restoreSessionTrash(item)" :disabled="sessionTrashLoading || sessionTrashClearing || isSessionTrashActionBusy(item)" :aria-label="sessionTrashRestoring[getSessionTrashActionKey(item)] ? t('settings.trash.restoring') : t('settings.trash.restore')" :title="sessionTrashRestoring[getSessionTrashActionKey(item)] ? t('settings.trash.restoring') : t('settings.trash.restore')">
|
|
67
67
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 12a9 9 0 119 9"/><path d="M3 4v6h6"/></svg>
|
|
68
68
|
</button>
|
|
69
|
-
<button class="trash-action-btn delete" @click="purgeSessionTrash(item)" :disabled="sessionTrashLoading || sessionTrashClearing || isSessionTrashActionBusy(item)" :title="sessionTrashPurging[getSessionTrashActionKey(item)] ? '
|
|
69
|
+
<button class="trash-action-btn delete" @click="purgeSessionTrash(item)" :disabled="sessionTrashLoading || sessionTrashClearing || isSessionTrashActionBusy(item)" :aria-label="sessionTrashPurging[getSessionTrashActionKey(item)] ? t('settings.trash.purging') : t('settings.trash.purge')" :title="sessionTrashPurging[getSessionTrashActionKey(item)] ? t('settings.trash.purging') : t('settings.trash.purge')">
|
|
70
70
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2M19 6l-1 14a2 2 0 01-2 2H8a2 2 0 01-2-2L5 6M10 11v6M14 11v6"/></svg>
|
|
71
71
|
</button>
|
|
72
72
|
</div>
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
</div>
|
|
75
75
|
<div v-if="sessionTrashHasMoreItems" class="trash-list-footer">
|
|
76
76
|
<button class="btn-tool btn-tool-compact" @click="loadMoreSessionTrashItems" :disabled="sessionTrashLoading || sessionTrashClearing">
|
|
77
|
-
|
|
77
|
+
{{ t('settings.trash.loadMoreItems', { count: sessionTrashHiddenCount }) }}
|
|
78
78
|
</button>
|
|
79
79
|
</div>
|
|
80
80
|
</div>
|