Skip to content

Commit 267d002

Browse files
committed
feat(pi-config): add history panels, locale strings, and UI coverage
1 parent 948b8dc commit 267d002

8 files changed

Lines changed: 237 additions & 4 deletions

File tree

tests/unit/config-tabs-ui.test.mjs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import assert from 'assert';
2+
import { DICT } from '../../web-ui/modules/i18n.dict.mjs';
23
import {
34
readBundledWebUiCss,
45
readBundledWebUiHtml,
@@ -703,3 +704,27 @@ test('docs panel uses segmented package manager control and drops summary strip'
703704
/<div class="docs-toolbar-card">\s*<label class="form-label">\{\{ t\('common\.packageManager'\) \}\}<\/label>\s*<div class="install-action-tabs">/
704705
);
705706
});
707+
708+
test('pi config file-JSON sections expose history panels with locale copy in every language', () => {
709+
const piPanel = readProjectFile('web-ui/partials/index/panel-config-pi.html');
710+
711+
assert.match(piPanel, /@click="openPiConfigHistory\('settings'\)"/);
712+
assert.match(piPanel, /@click="openPiConfigHistory\('models'\)"/);
713+
assert.match(piPanel, /v-if="piHistoryTarget === 'settings'"/);
714+
assert.match(piPanel, /v-if="piHistoryTarget === 'models'"/);
715+
for (const section of ['settings', 'models']) {
716+
const historyPanel = piPanel.match(
717+
new RegExp(`<details v-if="piHistoryTarget === '${section}'"[\\s\\S]*?</details>`)
718+
)?.[0] || '';
719+
assert.ok(historyPanel, `pi ${section} history panel should exist`);
720+
assert.match(historyPanel, /@click="applyPiConfigHistory" :disabled="piHistoryApplying \|\| !isToolConfigWriteAllowed\('pi'\)"/);
721+
assert.match(historyPanel, /t\('pi\.history\.apply'\)/);
722+
}
723+
724+
for (const code of ['zh', 'zh-tw', 'en', 'ja', 'vi']) {
725+
for (const key of ['pi.history.apply', 'pi.history.applied', 'pi.history.applyFailed', 'pi.history.confirm']) {
726+
assert.strictEqual(typeof DICT[code][key], 'string', `${code} should define ${key}`);
727+
assert(DICT[code][key].trim(), `${code} ${key} should not be empty`);
728+
}
729+
}
730+
});

web-ui/modules/i18n/locales/en.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,10 @@ const en = Object.freeze({
13641364
'pi.files.desc': 'View and edit Pi settings.json and models.json in full; JSON validity is checked before saving and invalid content is never written.',
13651365
'pi.files.settingsTitle': 'settings.json (active settings)',
13661366
'pi.files.modelsTitle': 'models.json (providers and models)',
1367+
'pi.history.apply': 'Apply this record',
1368+
'pi.history.applied': 'History record applied',
1369+
'pi.history.applyFailed': 'Failed to apply history record',
1370+
'pi.history.confirm': 'Apply this history record to the file? The current file content will be snapshotted first.',
13671371
'pi.providers.models.remove': 'Remove',
13681372
'pi.providers.models.search': 'Search available models…',
13691373
'pi.providers.models.remoteCount': '{count} models available, click to add',

web-ui/modules/i18n/locales/ja.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,6 +1365,10 @@ const ja = Object.freeze({
13651365
'pi.files.desc': 'Pi の settings.json と models.json を全文表示して直接編集します。保存前に JSON の正当性を検証し、不正な内容は書き込みません。',
13661366
'pi.files.settingsTitle': 'settings.json(有効な設定)',
13671367
'pi.files.modelsTitle': 'models.json(プロバイダーとモデル)',
1368+
'pi.history.apply': 'この履歴を適用',
1369+
'pi.history.applied': '履歴を適用しました',
1370+
'pi.history.applyFailed': '履歴の適用に失敗しました',
1371+
'pi.history.confirm': 'この履歴をファイルに適用しますか?現在の内容は先にスナップショット保存されます。',
13681372
'pi.providers.models.remove': '削除',
13691373
'pi.providers.models.search': '利用可能なモデルを検索…',
13701374
'pi.providers.models.remoteCount': '{count} 個のモデルを取得しました。クリックで追加',

web-ui/modules/i18n/locales/vi.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,6 +1333,10 @@ const vi = Object.freeze({
13331333
'pi.files.desc': 'Hiển thị đầy đủ và chỉnh sửa trực tiếp settings.json và models.json của Pi; kiểm tra tính hợp lệ của JSON trước khi lưu, nội dung không hợp lệ sẽ không được ghi.',
13341334
'pi.files.settingsTitle': 'settings.json (cài đặt đang dùng)',
13351335
'pi.files.modelsTitle': 'models.json (nhà cung cấp và mô hình)',
1336+
'pi.history.apply': 'Áp dụng bản ghi này',
1337+
'pi.history.applied': 'Đã áp dụng lịch sử',
1338+
'pi.history.applyFailed': 'Áp dụng lịch sử thất bại',
1339+
'pi.history.confirm': 'Áp dụng bản ghi lịch sử này vào tệp? Nội dung hiện tại sẽ được chụp nhanh trước.',
13361340
'pi.providers.models.remove': 'Xóa',
13371341
'pi.providers.models.search': 'Tìm kiếm mô hình khả dụng…',
13381342
'pi.providers.models.remoteCount': 'Đã lấy {count} mô hình, bấm để thêm',

web-ui/modules/i18n/locales/zh-tw.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,6 +1362,10 @@ const zhTw = Object.freeze({
13621362
'pi.files.desc': '完整展示並直接編輯 Pi 的 settings.json 與 models.json;儲存前校驗 JSON 合法性,非法內容不會寫入。',
13631363
'pi.files.settingsTitle': 'settings.json(生效設定)',
13641364
'pi.files.modelsTitle': 'models.json(供應商與模型)',
1365+
'pi.history.apply': '套用此紀錄',
1366+
'pi.history.applied': '已套用歷史紀錄',
1367+
'pi.history.applyFailed': '套用歷史紀錄失敗',
1368+
'pi.history.confirm': '將此歷史紀錄套用到檔案?目前檔案內容會先被快照儲存。',
13651369
'pi.providers.models.remove': '刪除',
13661370
'pi.providers.models.search': '搜尋可用模型…',
13671371
'pi.providers.models.remoteCount': '已取得 {count} 個可用模型,點擊新增',

web-ui/modules/i18n/locales/zh.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,6 +1362,10 @@ const zh = Object.freeze({
13621362
'pi.files.desc': '完整展示并直接编辑 Pi 的 settings.json 与 models.json;保存前校验 JSON 合法性,非法内容不会写入。',
13631363
'pi.files.settingsTitle': 'settings.json(生效设置)',
13641364
'pi.files.modelsTitle': 'models.json(供应商与模型)',
1365+
'pi.history.apply': '应用此记录',
1366+
'pi.history.applied': '已应用历史记录',
1367+
'pi.history.applyFailed': '应用历史记录失败',
1368+
'pi.history.confirm': '将此历史记录应用到文件?当前文件内容会先被快照保存。',
13651369
'pi.providers.models.remove': '删除',
13661370
'pi.providers.models.search': '搜索可用模型…',
13671371
'pi.providers.models.remoteCount': '已拉取 {count} 个可用模型,点击添加',

web-ui/partials/index/panel-config-pi.html

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,29 @@
195195
<p v-if="piSettingsJsonError" class="config-template-hint error-text">{{ piSettingsJsonError }}</p>
196196
<div class="settings-tab-actions">
197197
<button type="button" class="btn-tool" @click="savePiSettingsJson" :disabled="!isToolConfigWriteAllowed('pi') || piSaving || piFileJsonSaving || !!piSettingsJsonError">{{ t('common.save') }}</button>
198+
<button type="button" class="btn-mini" @click="openPiConfigHistory('settings')" :disabled="piHistoryLoading">{{ t('common.history') }}</button>
198199
</div>
200+
<details v-if="piHistoryTarget === 'settings'" class="prompt-history-panel" open>
201+
<summary class="prompt-history-summary">
202+
<span>{{ t('common.history') }}</span>
203+
<button type="button" class="btn-mini prompt-history-close" @click="closePiConfigHistory" :title="t('common.close')"></button>
204+
</summary>
205+
<div class="prompt-history-body">
206+
<ul v-if="!piHistoryLoading && !piHistoryError && piHistoryItems.length" class="prompt-history-list">
207+
<li v-for="item in piHistoryItems" :key="item.id" :class="['prompt-history-item', { active: piHistoryPreviewId === item.id }]" @click="viewPiConfigHistoryItem(item)">
208+
<span class="prompt-history-time">{{ item.id }}</span>
209+
<span class="prompt-history-size">{{ Math.round(item.size / 1024 * 10) / 10 }} KB</span>
210+
</li>
211+
</ul>
212+
<div v-if="piHistoryLoading" class="state-message">{{ t('diff.generating') }}</div>
213+
<div v-else-if="piHistoryError" class="state-message error">{{ piHistoryError }}</div>
214+
<div v-else-if="!piHistoryItems.length" class="state-message">{{ t('toast.history.empty') }}</div>
215+
<div v-if="piHistoryPreviewContent" class="prompt-history-preview-wrap">
216+
<pre class="prompt-history-preview">{{ piHistoryPreviewContent }}</pre>
217+
<button type="button" class="btn-mini btn-confirm-mini" @click="applyPiConfigHistory" :disabled="piHistoryApplying || !isToolConfigWriteAllowed('pi')">{{ t('pi.history.apply') }}</button>
218+
</div>
219+
</div>
220+
</details>
199221
<label class="form-label">{{ t('pi.files.modelsTitle') }}</label>
200222
<textarea
201223
class="template-textarea config-json-editor"
@@ -208,7 +230,29 @@
208230
<p v-if="piModelsJsonError" class="config-template-hint error-text">{{ piModelsJsonError }}</p>
209231
<div class="settings-tab-actions">
210232
<button type="button" class="btn-tool" @click="savePiModelsJson" :disabled="!isToolConfigWriteAllowed('pi') || piSaving || piFileJsonSaving || !!piModelsJsonError">{{ t('common.save') }}</button>
233+
<button type="button" class="btn-mini" @click="openPiConfigHistory('models')" :disabled="piHistoryLoading">{{ t('common.history') }}</button>
211234
</div>
235+
<details v-if="piHistoryTarget === 'models'" class="prompt-history-panel" open>
236+
<summary class="prompt-history-summary">
237+
<span>{{ t('common.history') }}</span>
238+
<button type="button" class="btn-mini prompt-history-close" @click="closePiConfigHistory" :title="t('common.close')"></button>
239+
</summary>
240+
<div class="prompt-history-body">
241+
<ul v-if="!piHistoryLoading && !piHistoryError && piHistoryItems.length" class="prompt-history-list">
242+
<li v-for="item in piHistoryItems" :key="item.id" :class="['prompt-history-item', { active: piHistoryPreviewId === item.id }]" @click="viewPiConfigHistoryItem(item)">
243+
<span class="prompt-history-time">{{ item.id }}</span>
244+
<span class="prompt-history-size">{{ Math.round(item.size / 1024 * 10) / 10 }} KB</span>
245+
</li>
246+
</ul>
247+
<div v-if="piHistoryLoading" class="state-message">{{ t('diff.generating') }}</div>
248+
<div v-else-if="piHistoryError" class="state-message error">{{ piHistoryError }}</div>
249+
<div v-else-if="!piHistoryItems.length" class="state-message">{{ t('toast.history.empty') }}</div>
250+
<div v-if="piHistoryPreviewContent" class="prompt-history-preview-wrap">
251+
<pre class="prompt-history-preview">{{ piHistoryPreviewContent }}</pre>
252+
<button type="button" class="btn-mini btn-confirm-mini" @click="applyPiConfigHistory" :disabled="piHistoryApplying || !isToolConfigWriteAllowed('pi')">{{ t('pi.history.apply') }}</button>
253+
</div>
254+
</div>
255+
</details>
212256
</section>
213257
<div v-if="!isToolConfigWriteAllowed('pi')" class="tool-config-write-overlay">
214258
<div class="tool-config-write-overlay-card">

0 commit comments

Comments
 (0)