From 8fb6edac18b40fcfe766fbc10fcdbdcbedb2d711 Mon Sep 17 00:00:00 2001 From: Lan_zhijiang Date: Tue, 22 Sep 2026 20:31:46 +0800 Subject: [PATCH 01/30] =?UTF-8?q?docs(shared):=20=E5=90=8C=E6=AD=A5=20Peer?= =?UTF-8?q?=20=E8=BF=90=E8=A1=8C=E8=BA=AB=E4=BB=BD=E5=A5=91=E7=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/_shared | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_shared b/docs/_shared index 5aa97e6..d87049c 160000 --- a/docs/_shared +++ b/docs/_shared @@ -1 +1 @@ -Subproject commit 5aa97e6243dce02dd27c5f58eda345be2ba47297 +Subproject commit d87049c49ba10f0a710022dce23abcd316127b3c From 18ae924ae4454d30e440bcc2d5c432ce1786e1e2 Mon Sep 17 00:00:00 2001 From: Lan_zhijiang Date: Tue, 22 Sep 2026 21:12:56 +0800 Subject: [PATCH 02/30] =?UTF-8?q?feat(peer):=20=E5=88=86=E7=A6=BB=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0=E8=AE=BE=E7=BD=AE=E4=B8=8E=20Peer=20=E7=AE=A1?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client-web/AGENTS.md | 4 +- apps/client-web/src/components/AGENTS.md | 2 +- .../common/AppSidePanel/AppSidePanel.vue | 5 + .../extension/extensionCard/extensionCard.md | 2 +- .../src/components/peer/peerCard/peerCard.md | 2 +- .../components/peer/peerCard/peerCard.scss | 19 +++ .../src/components/peer/peerCard/peerCard.ts | 1 + .../src/components/peer/peerCard/peerCard.vue | 27 ++-- .../components/peer/peerList/peerList.scss | 20 +-- .../src/components/peer/peerList/peerList.vue | 66 ++++---- apps/client-web/src/core.ts | 39 ++++- apps/client-web/src/extension-peer-control.ts | 2 +- apps/client-web/src/locales/messages/en.json | 43 +++--- .../src/locales/messages/zh-CN.json | 44 +++--- apps/client-web/src/router.ts | 6 + .../src/views/extensions/extensions.vue | 15 +- apps/client-web/src/views/peers/peers.scss | 15 ++ apps/client-web/src/views/peers/peers.vue | 15 ++ .../src/views/settings/settings.scss | 3 - .../src/views/settings/settings.vue | 141 +++++------------- .../client-runtime-and-delegation.md | 13 +- docs/40-deployment/development-runtime.md | 7 +- .../memos/docs/module-federation/index.md | 2 +- extensions/memos/src/MemosSetup.vue | 18 ++- .../twitterSetupWizard/twitterSetupWizard.vue | 14 +- packages/core/src/config/store.ts | 8 +- .../core/src/database/database.generated.ts | 3 + .../database/runtime-contract.generated.json | 2 +- packages/core/src/peer/manager.ts | 14 -- packages/core/src/peer/peer.ts | 9 +- packages/core/src/peer/runtime.ts | 58 ++++--- tests/e2e/peer-database.spec.ts | 130 +++++++++++++++- 32 files changed, 450 insertions(+), 299 deletions(-) create mode 100644 apps/client-web/src/views/peers/peers.scss create mode 100644 apps/client-web/src/views/peers/peers.vue diff --git a/apps/client-web/AGENTS.md b/apps/client-web/AGENTS.md index 9961e17..b707bbc 100644 --- a/apps/client-web/AGENTS.md +++ b/apps/client-web/AGENTS.md @@ -13,8 +13,8 @@ Static Vue application and equal InKCre database Peer. ## Local Hazards - Keep deployable artifacts environment-neutral: no service origin, Peer identity, JWT secret, Worker runtime, or `/api/config` fallback. -- Browser-owned settings are runtime authority. Keep the JWT signing secret masked, memory-only after use, absent from logs, and excluded from portable exports. -- Use **Peer** in technical contracts; product-facing UI may say **client**. +- Browser-owned settings are runtime authority. Keep the JWT signing secret masked during ordinary display and absent from logs. The explicit full-browser export includes it so another browser can restore the same experience. +- Use **Peer** for InKCre runtime nodes in both technical contracts and product UI. Keep “client” only for actual application or protocol client roles. - Preserve exact capability delegation and typed unknown outcomes; do not replace them with a generic Core API path or automatic retry after ambiguous dispatch. - Start development through root commands so SVC and Portless preserve worktree identity. The sibling UI source lane is explicitly non-release evidence. diff --git a/apps/client-web/src/components/AGENTS.md b/apps/client-web/src/components/AGENTS.md index 9ce1590..f70bcdc 100644 --- a/apps/client-web/src/components/AGENTS.md +++ b/apps/client-web/src/components/AGENTS.md @@ -8,7 +8,7 @@ Scope: `apps/client-web/src/components/**`. component-local copy of a model merely to shape props or emits. - Solved-content renderer selection belongs to the core `Resolver` registration. Keep `SolvedContentRenderer` as a dynamic handoff; do not add a second resolver-to-component map here. -- Keep technical names under `peer/`; user-facing copy may use “client”. +- Keep InKCre runtime-node names under `peer/` and use “Peer” in user-facing copy. Use “client” only for actual application or protocol client roles. General component file guidance lives in [component.instructions.md](../../../../.github/instructions/component.instructions.md). Stable diff --git a/apps/client-web/src/components/common/AppSidePanel/AppSidePanel.vue b/apps/client-web/src/components/common/AppSidePanel/AppSidePanel.vue index 2ee2b5d..a44ccf6 100644 --- a/apps/client-web/src/components/common/AppSidePanel/AppSidePanel.vue +++ b/apps/client-web/src/components/common/AppSidePanel/AppSidePanel.vue @@ -24,6 +24,10 @@ const onSettingsClick = () => { router.push('/settings') } +const onPeersClick = () => { + router.push('/peers') +} + const onExploreClick = () => { router.push('/info-base/graph') } @@ -43,6 +47,7 @@ watch(

{{ t('sidePanel.managing') }}

+ diff --git a/apps/client-web/src/components/extension/extensionCard/extensionCard.md b/apps/client-web/src/components/extension/extensionCard/extensionCard.md index 9b1aafa..236aefd 100644 --- a/apps/client-web/src/components/extension/extensionCard/extensionCard.md +++ b/apps/client-web/src/components/extension/extensionCard/extensionCard.md @@ -5,7 +5,7 @@ A component that displays extension information and provides controls for toggli ## Props - `extension` (InstalledExtension, required): the canonical installed row -- `enabled` (boolean, required): whether the selected Client's Peer UUID is in `enabled[]` +- `enabled` (boolean, required): whether the selected Peer's UUID is in `enabled[]` - `controlsCurrentWebRuntime` (boolean, required): whether the switch owns this browser's runtime - `canChangeVersion` (boolean, required): whether the selected Host can validate a version change - `changeVersion` (function, required): application-level version change through the selected Host diff --git a/apps/client-web/src/components/peer/peerCard/peerCard.md b/apps/client-web/src/components/peer/peerCard/peerCard.md index b420f76..bd7bfc3 100644 --- a/apps/client-web/src/components/peer/peerCard/peerCard.md +++ b/apps/client-web/src/components/peer/peerCard/peerCard.md @@ -1,5 +1,5 @@ # peerCard -Displays one technical Peer while retaining the product-facing “client” language. Name and +Displays one Peer using the same product and technical language. Name and owner config are editable shared facts;online status comes from database-time lease filtering, not an ad-hoc health endpoint。 diff --git a/apps/client-web/src/components/peer/peerCard/peerCard.scss b/apps/client-web/src/components/peer/peerCard/peerCard.scss index 0383e50..918a27b 100644 --- a/apps/client-web/src/components/peer/peerCard/peerCard.scss +++ b/apps/client-web/src/components/peer/peerCard/peerCard.scss @@ -13,9 +13,28 @@ min-width: 0; display: flex; flex-direction: column; + align-items: flex-start; gap: sys-var(space, xs); } + &__heading { + display: flex; + align-items: center; + gap: sys-var(space, sm); + flex-wrap: wrap; + } + + &__version, + &__current { + @include apply-font(label-md); + color: sys-var(color, text, subtle); + } + + &__current { + padding-inline-start: sys-var(space, sm); + border-inline-start: 1px solid sys-var(color, border, base); + } + &__item-id { @include apply-font(label-md, $mono: true); color: sys-var(color, text, subtle); diff --git a/apps/client-web/src/components/peer/peerCard/peerCard.ts b/apps/client-web/src/components/peer/peerCard/peerCard.ts index aaa03bd..e1f6eb8 100644 --- a/apps/client-web/src/components/peer/peerCard/peerCard.ts +++ b/apps/client-web/src/components/peer/peerCard/peerCard.ts @@ -3,6 +3,7 @@ import { Peer } from '@inkcre/core' export const peerCardProps = { peer: { type: Object as PropType, required: true }, + current: { type: Boolean, default: false }, status: { type: String as PropType<'online' | 'offline' | 'unknown'>, required: true, diff --git a/apps/client-web/src/components/peer/peerCard/peerCard.vue b/apps/client-web/src/components/peer/peerCard/peerCard.vue index d5aac54..0561e67 100644 --- a/apps/client-web/src/components/peer/peerCard/peerCard.vue +++ b/apps/client-web/src/components/peer/peerCard/peerCard.vue @@ -8,7 +8,7 @@ import { InkJsonEditor, type JsonEditorValidation, } from '@inkcre/ui-web' -import { Peer } from '@inkcre/core' +import { configStore, Peer, PeerConfigSchema } from '@inkcre/core' import { peerCardEmits, peerCardProps } from './peerCard' const props = defineProps(peerCardProps) @@ -37,7 +37,7 @@ const savePeer = async () => { emit('updated') } catch (error) { console.error('Failed to update Peer:', error) - alert('Failed to update client') + alert(t('common.saveFailed')) } } @@ -49,6 +49,7 @@ const onConfirmConfig = async () => { const updated = Peer.parse({ ...props.peer, config: JSON.parse(configModel.value) }) await updated.saveConfig() props.peer.config = updated.config + if (props.current) configStore.peerConfig = PeerConfigSchema.parse(updated.config) emit('updated') configPopupOpen.value = false } catch (error) { @@ -60,9 +61,9 @@ const onConfirmConfig = async () => { const getStatusText = (status: 'online' | 'offline' | 'unknown') => { const statusMap = { - online: t('client.statusOnline'), - offline: t('client.statusOffline'), - unknown: t('client.statusUnknown'), + online: t('peer.statusOnline'), + offline: t('peer.statusOffline'), + unknown: t('peer.statusUnknown'), } return statusMap[status] } @@ -71,22 +72,28 @@ const getStatusText = (status: 'online' | 'offline' | 'unknown') => { diff --git a/apps/client-web/src/locales/messages/en.json b/apps/client-web/src/locales/messages/en.json index aa70d81..cc0b6b9 100644 --- a/apps/client-web/src/locales/messages/en.json +++ b/apps/client-web/src/locales/messages/en.json @@ -187,7 +187,11 @@ "statusUnknown": "Unknown", "empty": "No Peers registered", "listFailed": "Unable to load Peers", - "editConfig": "Edit Config" + "editConfig": "Edit Config", + "delete": "Delete Peer", + "deleteConfirm": "This removes the Peer and its extension enablement from this deployment. A running Peer may register again when it reconnects.", + "deleteOnline": "Stop this Peer and wait for it to go offline before deleting it.", + "deleteFailed": "Unable to delete this Peer. Please try again." }, "infoBase": { "list": { diff --git a/apps/client-web/src/locales/messages/zh-CN.json b/apps/client-web/src/locales/messages/zh-CN.json index 7b82e5d..8b30aba 100644 --- a/apps/client-web/src/locales/messages/zh-CN.json +++ b/apps/client-web/src/locales/messages/zh-CN.json @@ -188,7 +188,11 @@ "statusUnknown": "未知", "empty": "暂无已注册的 Peer", "listFailed": "无法加载 Peer", - "editConfig": "编辑配置" + "editConfig": "编辑配置", + "delete": "删除 Peer", + "deleteConfirm": "这会从当前部署中移除该 Peer 及其扩展启用记录。若它重新连接,可能会再次注册。", + "deleteOnline": "请先停止该 Peer,待它离线后再删除。", + "deleteFailed": "无法删除该 Peer,请重试。" }, "infoBase": { "list": { diff --git a/packages/core/src/peer/peer.ts b/packages/core/src/peer/peer.ts index 8b02089..ca279b1 100644 --- a/packages/core/src/peer/peer.ts +++ b/packages/core/src/peer/peer.ts @@ -61,4 +61,8 @@ export class Peer extends Z.class({ async saveConfig(): Promise { await Peer.dbApi.update({ config: this.config }).eq('id', this.id).throwOnError() } + + async delete(): Promise { + await Peer.dbApi.from().delete().eq('id', this.id).throwOnError() + } } diff --git a/tasks/peer-extension-experience/packet.md b/tasks/peer-extension-experience/packet.md index e47ca69..d9ee565 100644 --- a/tasks/peer-extension-experience/packet.md +++ b/tasks/peer-extension-experience/packet.md @@ -19,6 +19,8 @@ - **本轮验收结论(2026-09-23)**:五个 Web 消费者已统一升级到正式 UI 2.1.1,完整 `pnpm check` 与 PR #118 最新 head 的全部检查、Cloudflare preview 均通过。Web E2E 在真实隔离数据库上验证确认安装、取消无写入、两个离线 Peer 批量启停。公开 preview 连接 owner Heroku/Neon 部署,Core Eco dyno 休眠时 Peers 页和弹窗均显示离线;唤醒后均显示在线,在线 Core 启用、停用 RSS 成功。最后卸载 RSS,刷新后的最终 preview 显示未安装扩展。Registry #56 的独立 Web 预览在精确 PR head 上运行,但空目录尚不能完成版本页的跨站点击验收;本 PR 继续保持 Draft。另一个既有缺口是空浏览器 Settings 保存→刷新→Peers 的自动化回归,手工链路此前已通过。 - **链接颜色复核(2026-09-23)**:公开 preview 的原生 Browse Registry 链接使用浏览器默认蓝色,已访问的 Settings 链接变为默认紫色;应用未设置原生 `` 的颜色。用宿主一条继承规则保留 InkUI 文字色、下划线及组件自有样式,不增加链接组件。 - **Registry 预览发现(2026-09-23)**:`registry-preview.yml` 的工作流运行 35825019767 在 PR #56 head `d58bdcb` 上成功交付完整 CPython Web,`/livez` 返回相同修订号,首页 200,`/v1/extensions` 为空。预览 URL 记录于 GitHub Deployment 6607501622,但 `workflow_run` 的 Deployment ref 是 `main`,因此 PR #56 的 checks 不呈现预览地址;这是关联与可发现性缺口,不是预览环境缺失。 +- **Peer 删除新增需求(2026-09-23)**:Human 要求 Peers 页可删除 Peer,第二条待补。Web 当前可直接读写 `peers`,但没有删除入口;本浏览器删除后会再次注册,在线 Peer 的运行时亦可能重注册。`extensions.enabled[]` 以 UUID 存引用,若先删 Peer,将无法再通过现有 RPC 停用该 UUID,进而阻碍扩展卸载/换版。拟只允许删除离线的非当前 Peer,在确认后先逐个停用其扩展,再删除 Peer 行;失败时保留卡片并显示错误,已成功的停用不回滚,重试可继续。验收覆盖取消、在线/当前不可删、带扩展绑定的离线 Peer 删除后无残留 UUID。具体边界仍待复核。 +- **Peer 删除实现与验证(2026-09-23)**:按单用户 deployment 的 best-effort 模型,不引入新数据库 RPC 或通用删除框架。当前浏览器不显示删除;在线 Peer 禁用删除;确认时再次按服务端 lease 核对,先用现有 Extension RPC 清掉该 Peer 的每条 `enabled[]` 关系,再删除 Peer 行。失败保留卡片与错误,重试继续未完成的清理。`pnpm check` 全通过;使用临时 GHCR 凭据和本机隔离 Compose 的 `pnpm test:e2e:web` 8/8,通过取消、在线限制、当前身份限制及启用关系清理,测试资源与临时凭据已销毁。已咨询 advisor:其建议为并发启用/删除增加数据库事务和锁;鉴于既定单用户 best-effort 边界,本轮不承担这一跨仓库协议成本。 ## 工作地图 diff --git a/tests/e2e/peer-database.spec.ts b/tests/e2e/peer-database.spec.ts index c77ad29..421d34d 100644 --- a/tests/e2e/peer-database.spec.ts +++ b/tests/e2e/peer-database.spec.ts @@ -162,8 +162,25 @@ test('Registry install and multi-Peer enablement require explicit confirmation', await expect(dialog).toBeHidden() await expect.poll(readEnabled).toEqual(expect.arrayContaining(peerIds)) + await page.goto('/peers') + await expect( + page.locator('.peer-card', { hasText: 'This browser' }).getByRole('button', { + name: 'Delete Peer', + }) + ).toHaveCount(0) + const peerToDelete = page.locator('.peer-card', { hasText: peerIds[0] }) + await peerToDelete.getByRole('button', { name: 'Delete Peer' }).click() + const deleteDialog = page.getByRole('dialog', { name: 'Delete Peer' }) + await deleteDialog.getByRole('button', { name: 'Cancel' }).click() + await expect(peerToDelete).toBeVisible() + await expect.poll(readEnabled).toEqual(expect.arrayContaining(peerIds)) + await peerToDelete.getByRole('button', { name: 'Delete Peer' }).click() + await deleteDialog.getByRole('button', { name: 'Delete Peer' }).click() + await expect(peerToDelete).toBeHidden() + await expect.poll(readEnabled).toEqual([peerIds[1]]) + + await page.goto('/extensions') await page.getByRole('button', { name: 'Disable…' }).click() - await dialog.getByRole('checkbox', { name: /E2E Peer 1/ }).check() await dialog.getByRole('checkbox', { name: /E2E Peer 2/ }).check() await dialog.getByRole('button', { name: 'Disable selected' }).click() await expect(dialog).toBeHidden() @@ -343,6 +360,7 @@ test('Peer config keeps invalid and failed drafts and saves only once while pend expect(renewed.status).toBe(204) await page.getByRole('button', { name: 'Refresh', exact: true }).click() await expect(peer.getByText('Online', { exact: true })).toBeVisible() + await expect(peer.getByRole('button', { name: 'Delete Peer' })).toBeDisabled() await peer.getByRole('button', { name: 'Edit Config' }).click() const dialog = page.getByRole('dialog', { name: 'Edit Config' }) await dialog.getByRole('tab', { name: 'JSON' }).click() From 81f282280f42f6292a11c60ead6128ad116f2237 Mon Sep 17 00:00:00 2001 From: Lan_zhijiang Date: Wed, 23 Sep 2026 21:11:09 +0800 Subject: [PATCH 20/30] =?UTF-8?q?feat:=20=E6=94=B9=E5=96=84=E7=AC=AC?= =?UTF-8?q?=E5=9B=9B=E7=BB=84=E4=BA=A4=E4=BA=92=E5=8F=8D=E9=A6=88=E4=B8=8E?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E5=B1=82=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/interaction-quality.md | 6 + apps/client-web/src/App.vue | 40 +- .../extensionCard/extensionCard.scss | 12 + .../extension/extensionCard/extensionCard.vue | 129 +++++-- .../BlockInspectorPopup.scss | 7 + .../BlockInspectorPopup.vue | 27 +- .../RelationInspectorPopup.vue | 34 +- .../components/obsrv/LogsViewer/LogsViewer.md | 46 +-- .../obsrv/LogsViewer/LogsViewer.scss | 12 +- .../obsrv/LogsViewer/LogsViewer.vue | 68 ++-- .../components/peer/peerCard/peerCard.scss | 31 +- .../src/components/peer/peerCard/peerCard.vue | 14 +- .../components/peer/peerList/peerList.scss | 14 + .../src/components/peer/peerList/peerList.vue | 41 +- .../src/components/recall/RecallSearch.vue | 147 +++++--- .../source/sourceForm/sourceForm.vue | 3 +- .../src/composables/use-page-object-title.ts | 17 + apps/client-web/src/core.ts | 28 +- apps/client-web/src/locales/messages/en.json | 43 ++- .../src/locales/messages/zh-CN.json | 43 ++- apps/client-web/src/router.ts | 14 +- .../src/views/extensions/extensions.scss | 19 +- .../src/views/extensions/extensions.vue | 70 +++- .../src/views/info-base/list/list.scss | 25 +- .../src/views/info-base/list/list.vue | 52 ++- apps/client-web/src/views/jobs/job/job.scss | 11 +- apps/client-web/src/views/jobs/job/job.vue | 137 +++---- apps/client-web/src/views/peers/peers.scss | 6 - apps/client-web/src/views/peers/peers.vue | 3 +- .../src/views/settings/settings.scss | 41 +- .../src/views/settings/settings.vue | 124 ++++-- .../src/views/sources/source/source.scss | 7 +- .../src/views/sources/source/source.vue | 30 +- .../client-web/src/views/sources/sources.scss | 14 +- apps/client-web/src/views/sources/sources.vue | 41 +- packages/core/src/job/job.ts | 6 +- packages/core/src/obsrv/log.ts | 2 +- .../interaction-quality-study.html | 353 ++++++++++++++++++ tasks/peer-extension-experience/packet.md | 12 +- tasks/peer-extension-experience/task-map.md | 12 +- .../track-interaction-quality.md | 158 +++++++- tests/e2e/peer-database.spec.ts | 314 +++++++++++++++- 42 files changed, 1739 insertions(+), 474 deletions(-) create mode 100644 .changeset/interaction-quality.md create mode 100644 apps/client-web/src/composables/use-page-object-title.ts create mode 100644 tasks/peer-extension-experience/interaction-quality-study.html diff --git a/.changeset/interaction-quality.md b/.changeset/interaction-quality.md new file mode 100644 index 0000000..37df82c --- /dev/null +++ b/.changeset/interaction-quality.md @@ -0,0 +1,6 @@ +--- +'@inkcre/client-web': patch +'@inkcre/core': patch +--- + +按任务精简 Settings、Peer 与 Extension 界面,统一页面和浏览器标题,补齐场景化加载、刷新失败保留、保存与取消的动作反馈。修正重复检索、任务不存在及日志读取失败的可观察结果,保留失败后的恢复入口。 diff --git a/apps/client-web/src/App.vue b/apps/client-web/src/App.vue index 229ec0b..b77073c 100644 --- a/apps/client-web/src/App.vue +++ b/apps/client-web/src/App.vue @@ -1,5 +1,5 @@ diff --git a/apps/client-web/src/components/peer/peerCard/peerCard.scss b/apps/client-web/src/components/peer/peerCard/peerCard.scss index 5813ca5..3ceb882 100644 --- a/apps/client-web/src/components/peer/peerCard/peerCard.scss +++ b/apps/client-web/src/components/peer/peerCard/peerCard.scss @@ -51,24 +51,27 @@ gap: sys-var(space, xs); } + &__details { + @include apply-font(body-sm); + max-width: 100%; + summary { + cursor: pointer; + } + p { + margin: sys-var(space, xs) 0; + } + pre { + max-width: 100%; + overflow-x: auto; + } + } + &__item-status { @include apply-font(label-md); padding: sys-var(space, xs) sys-var(space, sm); border-radius: sys-var(radius, none); - &--online { - background-color: sys-var(color, surface, subtle); - color: sys-var(color, feedback, success); - } - - &--offline { - background-color: sys-var(color, surface, subtle); - color: sys-var(color, feedback, error); - } - - &--unknown { - background-color: sys-var(color, surface, subtle); - color: sys-var(color, text, subtle); - } + background-color: sys-var(color, surface, subtle); + color: sys-var(color, text, subtle); } } diff --git a/apps/client-web/src/components/peer/peerCard/peerCard.vue b/apps/client-web/src/components/peer/peerCard/peerCard.vue index 6eb75b2..c387d21 100644 --- a/apps/client-web/src/components/peer/peerCard/peerCard.vue +++ b/apps/client-web/src/components/peer/peerCard/peerCard.vue @@ -5,6 +5,7 @@ import { InkButton, InkDialog, InkInput, type JsonEditorValidation } from '@inkc import SchemaConfigEditor from '@/components/schemaConfigEditor/schemaConfigEditor.vue' import { configStore, ExtensionModel, Peer, PeerConfigSchema, PeerManager } from '@inkcre/core' import { peerCardEmits, peerCardProps } from './peerCard' +import { currentWebPeer } from '@/core' const props = defineProps(peerCardProps) const emit = defineEmits(peerCardEmits) @@ -36,6 +37,7 @@ function openConfig() { const savePeer = async () => { try { await props.peer.save() + if (props.current) currentWebPeer.value = { id: props.peer.id, name: props.peer.name } emit('updated') } catch (error) { console.error('Failed to update Peer:', error) @@ -106,10 +108,6 @@ const getStatusText = (status: 'online' | 'offline' | 'unknown') => { {{ t('peer.current') }} - {{ peer.id }} - - {{ t('peer.capabilities', { count: peer.capabilities.length }) }} -
{ size="sm" theme="danger" :disabled="status === 'online'" - :title="status === 'online' ? t('peer.deleteOnline') : undefined" @click="openDelete" />
+
+ {{ t('common.details') }} + {{ peer.id }} +

{{ t('peer.capabilities', { count: peer.capabilities.length }) }}

+
{{ JSON.stringify(peer.capabilities, null, 2) }}
+

{{ t('peer.deleteOnline') }}

+
{{ getStatusText(status) }} diff --git a/apps/client-web/src/components/peer/peerList/peerList.scss b/apps/client-web/src/components/peer/peerList/peerList.scss index 834b73e..6c63766 100644 --- a/apps/client-web/src/components/peer/peerList/peerList.scss +++ b/apps/client-web/src/components/peer/peerList/peerList.scss @@ -16,4 +16,18 @@ flex-direction: column; gap: sys-var(space, sm); } + &__skeleton { + display: grid; + gap: sys-var(space, md); + padding: sys-var(space, lg) sys-var(space, md); + border: 1px solid sys-var(color, border, subtle); + } + &__error { + display: grid; + justify-items: start; + gap: sys-var(space, sm); + p { + margin: 0; + } + } } diff --git a/apps/client-web/src/components/peer/peerList/peerList.vue b/apps/client-web/src/components/peer/peerList/peerList.vue index 6332a82..41ed8e0 100644 --- a/apps/client-web/src/components/peer/peerList/peerList.vue +++ b/apps/client-web/src/components/peer/peerList/peerList.vue @@ -1,7 +1,9 @@