diff --git a/desktop/src/i18n/locales/en.ts b/desktop/src/i18n/locales/en.ts index 210e20db..dfeae4a8 100644 --- a/desktop/src/i18n/locales/en.ts +++ b/desktop/src/i18n/locales/en.ts @@ -2086,6 +2086,7 @@ export const en = { 'skillCenter.marketplace.drawer.metadata': 'Metadata', 'skillCenter.marketplace.drawer.links': 'Links', 'skillCenter.marketplace.loadingCard': 'Loading marketplace skills', + 'skillCenter.marketplace.loadingDetail': 'Loading skill detail', 'skillCenter.marketplace.previewTruncated': 'Truncated', 'skillCenter.marketplace.previewUnavailable': 'Preview unavailable', 'skillCenter.marketplace.previewUnavailable.skillhub': 'SkillHub does not expose a safe raw file preview endpoint yet.', diff --git a/desktop/src/i18n/locales/jp.ts b/desktop/src/i18n/locales/jp.ts index ea66d1b2..51fab328 100644 --- a/desktop/src/i18n/locales/jp.ts +++ b/desktop/src/i18n/locales/jp.ts @@ -2088,6 +2088,7 @@ export const jp: Record = { 'skillCenter.marketplace.drawer.metadata': 'メタデータ', 'skillCenter.marketplace.drawer.links': 'リンク', 'skillCenter.marketplace.loadingCard': 'マーケットスキルを読み込み中', + 'skillCenter.marketplace.loadingDetail': 'スキル詳細を読み込み中', 'skillCenter.marketplace.previewTruncated': '切り詰め済み', 'skillCenter.marketplace.previewUnavailable': 'プレビュー不可', 'skillCenter.marketplace.previewUnavailable.skillhub': 'SkillHub はまだ安全な raw ファイルプレビュー API を提供していません。', diff --git a/desktop/src/i18n/locales/kr.ts b/desktop/src/i18n/locales/kr.ts index 37ec10c6..ad4379d2 100644 --- a/desktop/src/i18n/locales/kr.ts +++ b/desktop/src/i18n/locales/kr.ts @@ -2088,6 +2088,7 @@ export const kr: Record = { 'skillCenter.marketplace.drawer.metadata': '메타데이터', 'skillCenter.marketplace.drawer.links': '링크', 'skillCenter.marketplace.loadingCard': '마켓 스킬 로드 중', + 'skillCenter.marketplace.loadingDetail': '스킬 상세 로드 중', 'skillCenter.marketplace.previewTruncated': '잘림', 'skillCenter.marketplace.previewUnavailable': '미리보기 불가', 'skillCenter.marketplace.previewUnavailable.skillhub': 'SkillHub는 아직 안전한 원본 파일 미리보기 API를 제공하지 않습니다.', diff --git a/desktop/src/i18n/locales/zh-TW.ts b/desktop/src/i18n/locales/zh-TW.ts index 0bf1c781..bb198dcb 100644 --- a/desktop/src/i18n/locales/zh-TW.ts +++ b/desktop/src/i18n/locales/zh-TW.ts @@ -2088,6 +2088,7 @@ export const zh: Record = { 'skillCenter.marketplace.drawer.metadata': '中繼資料', 'skillCenter.marketplace.drawer.links': '連結', 'skillCenter.marketplace.loadingCard': '正在載入市場技能', + 'skillCenter.marketplace.loadingDetail': '正在載入技能詳情', 'skillCenter.marketplace.previewTruncated': '已截斷', 'skillCenter.marketplace.previewUnavailable': '暫時無法預覽', 'skillCenter.marketplace.previewUnavailable.skillhub': 'SkillHub 目前尚未提供安全的原始檔案預覽介面。', diff --git a/desktop/src/i18n/locales/zh.ts b/desktop/src/i18n/locales/zh.ts index 27640350..bb9e95f9 100644 --- a/desktop/src/i18n/locales/zh.ts +++ b/desktop/src/i18n/locales/zh.ts @@ -2088,6 +2088,7 @@ export const zh: Record = { 'skillCenter.marketplace.drawer.metadata': '元数据', 'skillCenter.marketplace.drawer.links': '链接', 'skillCenter.marketplace.loadingCard': '正在加载市场技能', + 'skillCenter.marketplace.loadingDetail': '正在加载技能详情', 'skillCenter.marketplace.previewTruncated': '已截断', 'skillCenter.marketplace.previewUnavailable': '暂时无法预览', 'skillCenter.marketplace.previewUnavailable.skillhub': 'SkillHub 目前还没有提供安全的原始文件预览接口。', diff --git a/desktop/src/pages/SkillCenter.test.tsx b/desktop/src/pages/SkillCenter.test.tsx index b3f7a4c2..d25b8f74 100644 --- a/desktop/src/pages/SkillCenter.test.tsx +++ b/desktop/src/pages/SkillCenter.test.tsx @@ -245,10 +245,36 @@ describe('SkillCenter', () => { render() - expect(screen.getByTestId('skill-marketplace-loading')).toBeInTheDocument() + const loadingRegion = screen.getByTestId('skill-marketplace-loading') + expect(loadingRegion).toBeInTheDocument() + expect(loadingRegion).toHaveAttribute('role', 'status') + expect(loadingRegion).toHaveAttribute('aria-busy', 'true') + expect(screen.getByRole('status', { name: 'Loading marketplace skills' })).toBe(loadingRegion) expect(screen.getAllByTestId('skill-card-skeleton')).toHaveLength(8) }) + it('keeps the detail drawer in the body modal layer for uniform theme masking', async () => { + render() + fireEvent.click(await screen.findByRole('button', { name: 'PPT Generator' })) + + const detailLayer = await screen.findByTestId('skill-market-detail-layer') + expect(detailLayer.parentElement).toBe(document.body) + expect(detailLayer).toHaveClass('fixed', 'inset-0', 'z-50') + expect(detailLayer.querySelector('.skill-market-detail-scrim')).not.toBeNull() + }) + + it('announces detail drawer skeleton loading without visible copy', async () => { + mockedSkillMarketApi.detail.mockReturnValue(new Promise(() => {})) + + render() + fireEvent.click(await screen.findByRole('button', { name: 'PPT Generator' })) + + const detailLayer = screen.getByTestId('skill-market-detail-layer') + const detailLoading = within(detailLayer).getByRole('status', { name: 'Loading skill detail' }) + expect(detailLoading).toHaveAttribute('aria-busy', 'true') + expect(within(detailLoading).getByText('Loading skill detail')).toHaveClass('sr-only') + }) + it('places install decision, blocking reason, and file preview in the drawer decision area', async () => { mockedSkillMarketApi.detail.mockResolvedValue({ detail: makeDetail({ @@ -267,6 +293,7 @@ describe('SkillCenter', () => { fireEvent.click(await screen.findByRole('button', { name: 'PPT Generator' })) const dialog = await screen.findByRole('dialog', { name: 'PPT Generator' }) + expect(within(dialog).getByRole('heading', { name: 'Install decision' })).toBeInTheDocument() expect(within(dialog).getByRole('button', { name: 'Blocked' })).toBeDisabled() expect(within(dialog).getByText(/full package safety scan/i)).toBeInTheDocument() expect(within(dialog).getByText('File preview')).toBeInTheDocument() diff --git a/desktop/src/pages/SkillCenter.tsx b/desktop/src/pages/SkillCenter.tsx index 9ba28923..5f444f2e 100644 --- a/desktop/src/pages/SkillCenter.tsx +++ b/desktop/src/pages/SkillCenter.tsx @@ -787,7 +787,13 @@ function SkillMarketDetailPanel({ -
+
+

+ {t('skillCenter.marketplace.drawer.decision')} +