@nextclaw/ui 0.12.23 → 0.12.25
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/CHANGELOG.md +136 -0
- package/dist/assets/api-DGD9_Bg4.js +15 -0
- package/dist/assets/app-manager-provider-oYdeYPSv.js +1 -0
- package/dist/assets/{book-open-DDlN5MvX.js → book-open-BcnAiKde.js} +1 -1
- package/dist/assets/channels-list-page-FJDuPwU6.js +8 -0
- package/dist/assets/chat-page-D1fMNBrT.js +1 -0
- package/dist/assets/config-split-page-CcrEUtwu.js +1 -0
- package/dist/assets/cpu-DPPwMzoC.js +3 -0
- package/dist/assets/{createLucideIcon-BLMK3QUd.js → createLucideIcon-DzY6wN61.js} +1 -1
- package/dist/assets/desktop-kk7qvZ-v.js +3 -0
- package/dist/assets/desktop-update-config-CP8dFYXK.js +1 -0
- package/dist/assets/{dialog-dxsKz7jJ.js → dialog-BKo0RItd.js} +1 -1
- package/dist/assets/{dist-DsYTOyq7.js → dist-CFiwgaLs.js} +1 -1
- package/dist/assets/doc-browser-CAhfnm0D.js +1 -0
- package/dist/assets/{doc-browser-context-BJuMaI3o.js → doc-browser-context-FukQHvyo.js} +1 -1
- package/dist/assets/doc-browser-p9DDNPWB.js +1 -0
- package/dist/assets/doc-browser-rZIQIjuw.js +1 -0
- package/dist/assets/download-CMM8po31.js +1 -0
- package/dist/assets/{es2015-V75WQJ2s.js → es2015-BhznEEyJ.js} +1 -1
- package/dist/assets/{external-link-DwfSfTLB.js → external-link-CpEvG65F.js} +1 -1
- package/dist/assets/i18n-D1144VAA.js +1 -0
- package/dist/assets/index-D-AAMKCt.js +103 -0
- package/dist/assets/index-DnBeV2Xm.css +1 -0
- package/dist/assets/{key-round-CJ5gDAAG.js → key-round-DUq47t0P.js} +1 -1
- package/dist/assets/marketplace-page-BrCLRIc4.js +105 -0
- package/dist/assets/marketplace-page-odDpPYEs.js +1 -0
- package/dist/assets/mcp-marketplace-page-CfbOBgKK.js +1 -0
- package/dist/assets/mcp-marketplace-page-DIq_SpMe.js +40 -0
- package/dist/assets/model-config-Bc6VVnxy.js +1 -0
- package/dist/assets/{notice-card-D1RNsTn_.js → notice-card-Dr6xCwva.js} +1 -1
- package/dist/assets/play-AqrNslHI.js +1 -0
- package/dist/assets/plus-B-YHtTNC.js +1 -0
- package/dist/assets/{popover-BMyiifTA.js → popover-BDFNiLlg.js} +1 -1
- package/dist/assets/provider-scoped-model-input-BMTp4BEH.js +1 -0
- package/dist/assets/providers-list-DN0tvISH.js +1 -0
- package/dist/assets/refresh-cw-CrbD8EkT.js +1 -0
- package/dist/assets/remote-Dr3jcfWP.js +1 -0
- package/dist/assets/{rotate-cw-BZ2JObNs.js → rotate-cw-BN9yjccP.js} +1 -1
- package/dist/assets/runtime-config-page-CRWOwBbl.js +1 -0
- package/dist/assets/{save-euRxl8pI.js → save-CO_4qf6b.js} +1 -1
- package/dist/assets/{search-CLd7m0M7.js → search-CRtQwr-h.js} +1 -1
- package/dist/assets/search-config-C4c1yZSP.js +1 -0
- package/dist/assets/secrets-config-zAF30YfO.js +3 -0
- package/dist/assets/{select-DTdzR8j8.js → select-BUTwE_lC.js} +1 -1
- package/dist/assets/{setting-row-CvKngoNI.js → setting-row-BavcnXw1.js} +1 -1
- package/dist/assets/settings-MWL2SMyk.js +1 -0
- package/dist/assets/{sparkles-DVfeSVJQ.js → sparkles-BmgOD4nY.js} +1 -1
- package/dist/assets/{status-dot-ChvPCib9.js → status-dot-l3kPFdq_.js} +1 -1
- package/dist/assets/{tabs-custom-Hia_ong0.js → tabs-custom-D48zdZoc.js} +1 -1
- package/dist/assets/{tag-chip-BywQeHJj.js → tag-chip-Dm2Lqnpu.js} +1 -1
- package/dist/assets/use-config-Cyv5IuSt.js +1 -0
- package/dist/assets/use-infinite-scroll-loader-Cvz8ZteY.js +1 -0
- package/dist/assets/x-BeyYA_h6.js +1 -0
- package/dist/index.html +29 -40
- package/package.json +9 -9
- package/src/app/components/layout/sidebar.layout.test.tsx +2 -4
- package/src/app/components/theme-provider.tsx +1 -0
- package/src/app/configs/app-navigation.config.ts +0 -6
- package/src/app/index.tsx +4 -7
- package/src/features/agents/components/agents-page.test.tsx +25 -15
- package/src/features/agents/components/agents-page.tsx +133 -172
- package/src/features/channels/components/config/channel-form.test.tsx +1 -0
- package/src/features/channels/components/config/channel-form.tsx +4 -3
- package/src/features/channels/components/config/weixin-channel-auth-section.test.tsx +38 -1
- package/src/features/channels/components/config/weixin-channel-auth-section.tsx +137 -40
- package/src/features/channels/index.ts +1 -1
- package/src/features/channels/utils/channel-form-fields.utils.test.ts +26 -0
- package/src/features/channels/utils/channel-form-fields.utils.ts +32 -18
- package/src/features/chat/components/chat-session-workspace-panel-nav.tsx +23 -4
- package/src/features/chat/components/chat-session-workspace-panel.tsx +34 -2
- package/src/features/chat/components/chat-sidebar-session-item.tsx +9 -3
- package/src/features/chat/components/conversation/chat-conversation-header.test.tsx +71 -0
- package/src/features/chat/components/conversation/chat-conversation-header.tsx +6 -0
- package/src/features/chat/components/conversation/chat-conversation-panel.test.tsx +181 -61
- package/src/features/chat/components/conversation/chat-conversation-panel.tsx +56 -25
- package/src/features/chat/components/conversation/session-header/chat-session-header-actions.test.tsx +24 -0
- package/src/features/chat/components/conversation/session-header/chat-session-header-actions.tsx +26 -5
- package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +174 -0
- package/src/features/chat/components/layout/chat-sidebar.test.tsx +119 -8
- package/src/features/chat/components/layout/chat-sidebar.tsx +57 -75
- package/src/features/chat/components/providers/chat-presenter.provider.tsx +2 -0
- package/src/features/chat/components/workspace/session-cron-job-content.tsx +103 -0
- package/src/features/chat/hooks/use-hydrated-ncp-agent.test.tsx +6 -0
- package/src/features/chat/hooks/use-ncp-agent-runtime.test.tsx +172 -69
- package/src/features/chat/hooks/use-ncp-chat-derived-state.ts +2 -2
- package/src/features/chat/hooks/use-ncp-chat-page-data.test.tsx +70 -0
- package/src/features/chat/hooks/use-ncp-chat-page-data.ts +7 -7
- package/src/features/chat/hooks/use-ncp-child-session-tabs-view.ts +2 -8
- package/src/features/chat/hooks/use-ncp-session-conversation.test.tsx +10 -0
- package/src/features/chat/hooks/use-ncp-session-conversation.ts +2 -1
- package/src/features/chat/hooks/use-ncp-session-list-view.ts +1 -2
- package/src/features/chat/hooks/use-selected-session-context-window-indicator.ts +2 -4
- package/src/features/chat/managers/chat-session-list.manager.test.ts +21 -20
- package/src/features/chat/managers/chat-session-list.manager.ts +15 -24
- package/src/features/chat/managers/ncp-chat-input.manager.test.ts +22 -13
- package/src/features/chat/managers/ncp-chat-input.manager.ts +4 -2
- package/src/features/chat/managers/ncp-chat-presenter.manager.ts +6 -0
- package/src/features/chat/managers/ncp-chat-thread.manager.test.ts +52 -1
- package/src/features/chat/managers/ncp-chat-thread.manager.ts +21 -0
- package/src/features/chat/pages/ncp-chat-page.tsx +28 -17
- package/src/features/chat/stores/chat-session-list.store.ts +0 -3
- package/src/features/chat/stores/chat-thread.store.ts +4 -0
- package/src/features/chat/types/chat-stream.types.ts +1 -1
- package/src/features/chat/utils/chat-session-display.utils.test.ts +83 -1
- package/src/features/chat/utils/chat-session-display.utils.ts +73 -0
- package/src/features/chat/utils/ncp-session-adapter.utils.test.ts +22 -0
- package/src/features/chat/utils/ncp-session-adapter.utils.ts +33 -1
- package/src/features/marketplace/components/curated-shelves/marketplace-curated-scene-route.test.tsx +235 -0
- package/src/features/marketplace/components/curated-shelves/marketplace-curated-shelves.config.ts +162 -0
- package/src/features/marketplace/components/curated-shelves/marketplace-curated-shelves.tsx +355 -0
- package/src/features/marketplace/components/curated-shelves/marketplace-shelf-card.tsx +118 -0
- package/src/features/marketplace/components/detail-doc/marketplace-detail-doc-renderer.ts +201 -0
- package/src/features/marketplace/components/detail-doc/marketplace-detail-doc.test.ts +40 -0
- package/src/features/marketplace/components/marketplace-catalog-grid.tsx +114 -0
- package/src/features/marketplace/components/marketplace-detail-doc.ts +73 -24
- package/src/features/marketplace/components/marketplace-item-icon.tsx +45 -0
- package/src/features/marketplace/components/marketplace-list-card.tsx +177 -93
- package/src/features/marketplace/components/marketplace-page-detail.test.tsx +9 -2
- package/src/features/marketplace/components/marketplace-page-parts.tsx +1 -1
- package/src/features/marketplace/components/marketplace-page.test.tsx +25 -6
- package/src/features/marketplace/components/marketplace-page.tsx +154 -132
- package/src/features/marketplace/hooks/use-marketplace-curated-scene-route.ts +97 -0
- package/src/features/marketplace/hooks/use-marketplace.ts +59 -3
- package/src/features/system-status/components/config/runtime-agent-list-card.tsx +4 -8
- package/src/features/system-status/components/config/runtime-binding-list-card.tsx +5 -7
- package/src/features/system-status/components/config/runtime-config-editor.tsx +1 -19
- package/src/features/system-status/components/config/runtime-entry-list-card.tsx +10 -11
- package/src/features/system-status/components/config/runtime-settings-card.tsx +15 -23
- package/src/features/system-status/components/runtime-control-card.test.tsx +8 -6
- package/src/features/system-status/components/runtime-control-card.tsx +7 -6
- package/src/features/system-status/pages/runtime-config-page.test.tsx +19 -9
- package/src/features/system-status/pages/runtime-config-page.tsx +2 -3
- package/src/features/system-status/utils/runtime-config-agent.utils.ts +4 -4
- package/src/features/system-status/utils/system-status.utils.ts +31 -6
- package/src/index.css +8 -0
- package/src/platforms/desktop/components/desktop-app-shell.test.tsx +67 -0
- package/src/platforms/desktop/components/desktop-app-shell.tsx +46 -18
- package/src/platforms/desktop/components/desktop-window-chrome.tsx +30 -0
- package/src/platforms/desktop/index.ts +6 -0
- package/src/platforms/desktop/types/desktop-update.types.ts +3 -0
- package/src/platforms/desktop/utils/desktop-host.utils.ts +56 -0
- package/src/shared/components/common/brand-header.tsx +36 -16
- package/src/shared/components/config/provider-form-support.ts +2 -22
- package/src/shared/components/cron-config.tsx +12 -58
- package/src/shared/components/doc-browser/doc-browser.tsx +4 -4
- package/src/shared/components/ui/select.tsx +19 -7
- package/src/shared/lib/api/channel-auth.types.ts +1 -0
- package/src/shared/lib/api/ncp-session-query-cache.test.ts +26 -1
- package/src/shared/lib/api/ncp-session-query-cache.ts +5 -1
- package/src/shared/lib/api/ncp-session.types.ts +9 -0
- package/src/shared/lib/api/types.ts +12 -1
- package/src/shared/lib/api/utils/marketplace.utils.ts +7 -1
- package/src/shared/lib/cron/cron-job-view.utils.ts +59 -0
- package/src/shared/lib/cron/index.ts +1 -0
- package/src/shared/lib/i18n/{channel-auth.ts → channel-auth.constants.ts} +31 -0
- package/src/shared/lib/i18n/chat-labels.utils.ts +3 -2
- package/src/shared/lib/i18n/index.ts +20 -59
- package/src/shared/lib/i18n/{runtime-control.ts → runtime-control-labels.utils.ts} +30 -1
- package/src/shared/lib/provider-models/index.test.ts +39 -0
- package/src/shared/lib/provider-models/index.ts +1 -3
- package/src/shared/lib/ui-document-title/index.ts +0 -1
- package/tsconfig.json +1 -0
- package/vite.config.ts +1 -1
- package/vitest.config.ts +1 -1
- package/dist/assets/api-BGd3rgv_.js +0 -15
- package/dist/assets/app-manager-provider-BuJ_U9eC.js +0 -1
- package/dist/assets/app-navigation.config-BTdUuqXS.js +0 -1
- package/dist/assets/channels-list-page-BrwymXPe.js +0 -8
- package/dist/assets/chat-DGM6K3Qs.js +0 -61
- package/dist/assets/chat-page-DpmXMWNS.js +0 -1
- package/dist/assets/chunk-JZWAC4HX-Kydj4yEz.js +0 -3
- package/dist/assets/config-split-page-DIOCjj2Q.js +0 -1
- package/dist/assets/desktop-update-config-BGKiqc6q.js +0 -1
- package/dist/assets/doc-browser-C8FM5fC0.js +0 -1
- package/dist/assets/doc-browser-RJUOL_GO.js +0 -1
- package/dist/assets/doc-browser-p82AdNO-.js +0 -1
- package/dist/assets/folder-CeJKPx5P.js +0 -1
- package/dist/assets/hash-BqxRTZW5.js +0 -1
- package/dist/assets/i18n-DnTGDIRw.js +0 -1
- package/dist/assets/index-BrEdR78s.js +0 -2
- package/dist/assets/index-D8MKmXtO.css +0 -1
- package/dist/assets/loader-circle-fd-vQKtW.js +0 -1
- package/dist/assets/logo-badge-KAe-7d8c.js +0 -1
- package/dist/assets/logos-C4sYP1Vl.js +0 -1
- package/dist/assets/marketplace-page-B2Pm2RDJ.js +0 -1
- package/dist/assets/marketplace-page-CPHxlYL8.js +0 -49
- package/dist/assets/mcp-marketplace-page-BcjVmw36.js +0 -1
- package/dist/assets/mcp-marketplace-page-CswPXSjf.js +0 -40
- package/dist/assets/message-square-z_osm9c0.js +0 -1
- package/dist/assets/model-config-Cmruiqdx.js +0 -1
- package/dist/assets/play-Dv6Nr1Ew.js +0 -1
- package/dist/assets/plus-D8eKFY7h.js +0 -1
- package/dist/assets/provider-scoped-model-input-D7ACiMAO.js +0 -1
- package/dist/assets/providers-list-gg7LrfuB.js +0 -1
- package/dist/assets/refresh-ccw-ByVwmnN_.js +0 -1
- package/dist/assets/refresh-cw-PcqoYB3K.js +0 -1
- package/dist/assets/remote-Db2M39Cv.js +0 -1
- package/dist/assets/runtime-config-page-BT_VV41p.js +0 -1
- package/dist/assets/search-config-0VTPpz-w.js +0 -1
- package/dist/assets/secrets-config-DwQbLLEy.js +0 -3
- package/dist/assets/sessions-config-page-CAG7Zevv.js +0 -2
- package/dist/assets/settings-drbWqzA4.js +0 -1
- package/dist/assets/skeleton-BK1SOSRA.js +0 -1
- package/dist/assets/theme-provider-COAwWFv8.js +0 -2
- package/dist/assets/tooltip-BOYp8Ue7.js +0 -1
- package/dist/assets/trash-2-CBsHCfqq.js +0 -1
- package/dist/assets/use-config-DTwhNDQE.js +0 -1
- package/dist/assets/use-confirm-dialog-oeSqhmrx.js +0 -1
- package/dist/assets/use-infinite-scroll-loader-X3KGuME8.js +0 -1
- package/dist/assets/use-viewport-layout-C0NJAVXs.js +0 -1
- package/dist/assets/x-CM-XDMpk.js +0 -1
- package/src/features/chat/components/config/sessions-config-detail-pane.tsx +0 -244
- package/src/features/chat/pages/sessions-config-page.test.tsx +0 -152
- package/src/features/chat/pages/sessions-config-page.tsx +0 -192
- /package/dist/assets/{config-hints-MogHYQ8G.js → config-hints-BNfpOL4J.js} +0 -0
|
@@ -63,6 +63,11 @@ vi.mock("@/shared/hooks/use-confirm-dialog", () => ({
|
|
|
63
63
|
vi.mock("@/features/marketplace/hooks/use-marketplace", () => ({
|
|
64
64
|
useMarketplaceItems: () => mocks.itemsQuery,
|
|
65
65
|
useMarketplaceInstalled: () => mocks.installedQuery,
|
|
66
|
+
useMarketplaceSkillScenes: () => ({
|
|
67
|
+
data: { scenes: [] },
|
|
68
|
+
isLoading: false,
|
|
69
|
+
}),
|
|
70
|
+
useMarketplaceSkillSceneCounts: () => new Map(),
|
|
66
71
|
useInstallMarketplaceItem: () => ({
|
|
67
72
|
mutateAsync: vi.fn(),
|
|
68
73
|
isPending: false,
|
|
@@ -103,7 +108,7 @@ function createItemsQuery(items: MarketplaceItemSummary[]): ItemsQueryState {
|
|
|
103
108
|
data: {
|
|
104
109
|
total: items.length,
|
|
105
110
|
page: 1,
|
|
106
|
-
pageSize:
|
|
111
|
+
pageSize: 20,
|
|
107
112
|
totalPages: 1,
|
|
108
113
|
sort: "relevance",
|
|
109
114
|
items,
|
|
@@ -162,7 +167,9 @@ describe("MarketplacePage detail loading", () => {
|
|
|
162
167
|
await user.click(screen.getByText("Web Search"));
|
|
163
168
|
|
|
164
169
|
expect(mocks.docOpen).toHaveBeenCalledTimes(1);
|
|
165
|
-
|
|
170
|
+
const loadingDetailHtml = decodeURIComponent(String(mocks.docOpen.mock.calls[0]?.[0]));
|
|
171
|
+
expect(loadingDetailHtml).toContain('aria-busy="true"');
|
|
172
|
+
expect(loadingDetailHtml).not.toContain("Loading");
|
|
166
173
|
expect(mocks.docOpen.mock.calls[0]?.[1]).toMatchObject({
|
|
167
174
|
dedupeKey: "marketplace:skill:web-search",
|
|
168
175
|
kind: "content",
|
|
@@ -70,7 +70,7 @@ export function MarketplaceListSkeleton({ count }: {
|
|
|
70
70
|
{Array.from({ length: count }, (_, index) => (
|
|
71
71
|
<article
|
|
72
72
|
key={`marketplace-skeleton-${index}`}
|
|
73
|
-
className="rounded-2xl border border-gray-200/40 bg-white px-5 py-4 shadow-sm"
|
|
73
|
+
className="h-full rounded-2xl border border-gray-200/40 bg-white px-5 py-4 shadow-sm"
|
|
74
74
|
>
|
|
75
75
|
<div className="flex items-start justify-between gap-3.5">
|
|
76
76
|
<div className="flex min-w-0 flex-1 gap-3">
|
|
@@ -28,6 +28,7 @@ const mocks = vi.hoisted(() => ({
|
|
|
28
28
|
navigate: vi.fn(),
|
|
29
29
|
docOpen: vi.fn(),
|
|
30
30
|
confirm: vi.fn(),
|
|
31
|
+
routeParams: {} as { type?: string; scene?: string },
|
|
31
32
|
itemsQuery: null as unknown as ItemsQueryState,
|
|
32
33
|
installedQuery: null as unknown as InstalledQueryState,
|
|
33
34
|
installMutation: {
|
|
@@ -48,7 +49,7 @@ vi.mock("react-router-dom", async () => {
|
|
|
48
49
|
return {
|
|
49
50
|
...(actual as object),
|
|
50
51
|
useNavigate: () => mocks.navigate,
|
|
51
|
-
useParams: () =>
|
|
52
|
+
useParams: () => mocks.routeParams,
|
|
52
53
|
};
|
|
53
54
|
});
|
|
54
55
|
|
|
@@ -73,6 +74,23 @@ vi.mock("@/shared/hooks/use-confirm-dialog", () => ({
|
|
|
73
74
|
|
|
74
75
|
vi.mock("@/features/marketplace/hooks/use-marketplace", () => ({
|
|
75
76
|
useMarketplaceItems: () => mocks.itemsQuery,
|
|
77
|
+
useMarketplaceSkillScenes: () => ({
|
|
78
|
+
data: {
|
|
79
|
+
scenes: [
|
|
80
|
+
{
|
|
81
|
+
scene: "development-debugging",
|
|
82
|
+
title: "Development",
|
|
83
|
+
description: "Review, debug, analyze, and verify delivery work.",
|
|
84
|
+
count: 2,
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
isLoading: false,
|
|
89
|
+
isFetching: false,
|
|
90
|
+
isError: false,
|
|
91
|
+
error: null,
|
|
92
|
+
}),
|
|
93
|
+
useMarketplaceSkillSceneCounts: () => new Map([["development-debugging", 2]]),
|
|
76
94
|
useMarketplaceInstalled: () => mocks.installedQuery,
|
|
77
95
|
useInstallMarketplaceItem: () => mocks.installMutation,
|
|
78
96
|
useManageMarketplaceItem: () => mocks.manageMutation,
|
|
@@ -169,6 +187,7 @@ describe("MarketplacePage", () => {
|
|
|
169
187
|
mocks.navigate.mockReset();
|
|
170
188
|
mocks.docOpen.mockReset();
|
|
171
189
|
mocks.confirm.mockReset();
|
|
190
|
+
mocks.routeParams = {};
|
|
172
191
|
mocks.installMutation.mutateAsync.mockReset();
|
|
173
192
|
mocks.manageMutation.mutate.mockReset();
|
|
174
193
|
mocks.manageMutation.mutateAsync.mockReset();
|
|
@@ -193,7 +212,7 @@ describe("MarketplacePage", () => {
|
|
|
193
212
|
container.querySelectorAll(
|
|
194
213
|
'[data-testid="marketplace-list-skeleton"] > article',
|
|
195
214
|
),
|
|
196
|
-
).toHaveLength(
|
|
215
|
+
).toHaveLength(36);
|
|
197
216
|
});
|
|
198
217
|
|
|
199
218
|
it("keeps loaded cards visible during background refresh", () => {
|
|
@@ -201,7 +220,7 @@ describe("MarketplacePage", () => {
|
|
|
201
220
|
data: {
|
|
202
221
|
total: 1,
|
|
203
222
|
page: 1,
|
|
204
|
-
pageSize:
|
|
223
|
+
pageSize: 20,
|
|
205
224
|
totalPages: 1,
|
|
206
225
|
sort: "relevance",
|
|
207
226
|
items: [createMarketplaceItem()],
|
|
@@ -220,7 +239,7 @@ describe("MarketplacePage", () => {
|
|
|
220
239
|
data: {
|
|
221
240
|
total: 1,
|
|
222
241
|
page: 1,
|
|
223
|
-
pageSize:
|
|
242
|
+
pageSize: 20,
|
|
224
243
|
totalPages: 1,
|
|
225
244
|
sort: "relevance",
|
|
226
245
|
items: [
|
|
@@ -256,7 +275,7 @@ describe("MarketplacePage", () => {
|
|
|
256
275
|
data: {
|
|
257
276
|
total: 1,
|
|
258
277
|
page: 1,
|
|
259
|
-
pageSize:
|
|
278
|
+
pageSize: 20,
|
|
260
279
|
totalPages: 1,
|
|
261
280
|
sort: "relevance",
|
|
262
281
|
items: [createPluginMarketplaceItem()],
|
|
@@ -277,7 +296,7 @@ describe("MarketplacePage", () => {
|
|
|
277
296
|
data: {
|
|
278
297
|
total: 2,
|
|
279
298
|
page: 1,
|
|
280
|
-
pageSize:
|
|
299
|
+
pageSize: 20,
|
|
281
300
|
totalPages: 1,
|
|
282
301
|
sort: "relevance",
|
|
283
302
|
items: [
|
|
@@ -23,7 +23,6 @@ import {
|
|
|
23
23
|
} from "@/features/marketplace/hooks/use-marketplace";
|
|
24
24
|
import {
|
|
25
25
|
FilterPanel,
|
|
26
|
-
MarketplaceListSkeleton,
|
|
27
26
|
MarketplaceInfiniteScrollStatus,
|
|
28
27
|
} from "@/features/marketplace/components/marketplace-page-parts";
|
|
29
28
|
import {
|
|
@@ -34,25 +33,29 @@ import {
|
|
|
34
33
|
buildCatalogLookup,
|
|
35
34
|
buildInstalledRecordLookup,
|
|
36
35
|
findCatalogItemForRecord,
|
|
37
|
-
findInstalledRecordForItem,
|
|
38
36
|
matchInstalledSearch,
|
|
39
37
|
type InstalledRenderEntry,
|
|
40
38
|
} from "@/features/marketplace/components/marketplace-page-data";
|
|
41
39
|
import { buildGenericDetailDataUrl } from "@/features/marketplace/components/marketplace-detail-doc";
|
|
42
|
-
import {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
type ManageState,
|
|
40
|
+
import type {
|
|
41
|
+
InstallState,
|
|
42
|
+
ManageState,
|
|
46
43
|
} from "@/features/marketplace/components/marketplace-list-card";
|
|
44
|
+
import { MarketplaceCatalogGrid } from "@/features/marketplace/components/marketplace-catalog-grid";
|
|
45
|
+
import {
|
|
46
|
+
MarketplaceCuratedSceneView,
|
|
47
|
+
MarketplaceCuratedShelves,
|
|
48
|
+
} from "@/features/marketplace/components/curated-shelves/marketplace-curated-shelves";
|
|
49
|
+
import { useMarketplaceCuratedSceneRoute } from "@/features/marketplace/hooks/use-marketplace-curated-scene-route";
|
|
47
50
|
import { t } from "@/shared/lib/i18n";
|
|
48
|
-
import {
|
|
51
|
+
import { PageLayout } from "@/app/components/layout/page-layout";
|
|
49
52
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
50
53
|
import { useNavigate, useParams } from "react-router-dom";
|
|
51
54
|
import { useInfiniteScrollLoader } from "@/shared/hooks/use-infinite-scroll-loader";
|
|
52
55
|
import { Tabs } from "@/shared/components/ui/tabs-custom";
|
|
53
56
|
|
|
54
|
-
const PAGE_SIZE =
|
|
55
|
-
const SKELETON_CARD_COUNT =
|
|
57
|
+
const PAGE_SIZE = 20;
|
|
58
|
+
const SKELETON_CARD_COUNT = 36;
|
|
56
59
|
|
|
57
60
|
type ScopeType = "all" | "installed";
|
|
58
61
|
|
|
@@ -61,10 +64,43 @@ type MarketplacePageProps = {
|
|
|
61
64
|
forcedType?: MarketplaceRouteType;
|
|
62
65
|
};
|
|
63
66
|
|
|
67
|
+
function getMarketplaceCopyKeys(typeFilter: MarketplaceItemType) {
|
|
68
|
+
if (typeFilter === "plugin") {
|
|
69
|
+
return {
|
|
70
|
+
pageTitle: "marketplacePluginsPageTitle",
|
|
71
|
+
pageDescription: "marketplacePluginsPageDescription",
|
|
72
|
+
tabMarketplace: "marketplaceTabMarketplacePlugins",
|
|
73
|
+
tabInstalled: "marketplaceTabInstalledPlugins",
|
|
74
|
+
searchPlaceholder: "marketplaceSearchPlaceholderPlugins",
|
|
75
|
+
sectionCatalog: "marketplaceSectionPlugins",
|
|
76
|
+
sectionInstalled: "marketplaceSectionInstalledPlugins",
|
|
77
|
+
errorLoadData: "marketplaceErrorLoadingPluginsData",
|
|
78
|
+
errorLoadInstalled: "marketplaceErrorLoadingInstalledPlugins",
|
|
79
|
+
emptyData: "marketplaceNoPlugins",
|
|
80
|
+
emptyInstalled: "marketplaceNoInstalledPlugins",
|
|
81
|
+
installedCountSuffix: "marketplaceInstalledPluginsCountSuffix",
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
pageTitle: "marketplaceSkillsPageTitle",
|
|
86
|
+
pageDescription: "marketplaceSkillsPageDescription",
|
|
87
|
+
tabMarketplace: "marketplaceTabMarketplaceSkills",
|
|
88
|
+
tabInstalled: "marketplaceTabInstalledSkills",
|
|
89
|
+
searchPlaceholder: "marketplaceSearchPlaceholderSkills",
|
|
90
|
+
sectionCatalog: "marketplaceSectionSkills",
|
|
91
|
+
sectionInstalled: "marketplaceSectionInstalledSkills",
|
|
92
|
+
errorLoadData: "marketplaceErrorLoadingSkillsData",
|
|
93
|
+
errorLoadInstalled: "marketplaceErrorLoadingInstalledSkills",
|
|
94
|
+
emptyData: "marketplaceNoSkills",
|
|
95
|
+
emptyInstalled: "marketplaceNoInstalledSkills",
|
|
96
|
+
installedCountSuffix: "marketplaceInstalledSkillsCountSuffix",
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
64
100
|
export function MarketplacePage(props: MarketplacePageProps = {}) {
|
|
65
101
|
const { forcedType } = props;
|
|
66
102
|
const navigate = useNavigate();
|
|
67
|
-
const params = useParams<{ type?: string }>();
|
|
103
|
+
const params = useParams<{ type?: string; scene?: string }>();
|
|
68
104
|
const { language } = useI18n();
|
|
69
105
|
const docBrowser = useDocBrowser();
|
|
70
106
|
|
|
@@ -94,36 +130,7 @@ export function MarketplacePage(props: MarketplacePageProps = {}) {
|
|
|
94
130
|
[language],
|
|
95
131
|
);
|
|
96
132
|
|
|
97
|
-
const
|
|
98
|
-
const copyKeys = isPluginModule
|
|
99
|
-
? {
|
|
100
|
-
pageTitle: "marketplacePluginsPageTitle",
|
|
101
|
-
pageDescription: "marketplacePluginsPageDescription",
|
|
102
|
-
tabMarketplace: "marketplaceTabMarketplacePlugins",
|
|
103
|
-
tabInstalled: "marketplaceTabInstalledPlugins",
|
|
104
|
-
searchPlaceholder: "marketplaceSearchPlaceholderPlugins",
|
|
105
|
-
sectionCatalog: "marketplaceSectionPlugins",
|
|
106
|
-
sectionInstalled: "marketplaceSectionInstalledPlugins",
|
|
107
|
-
errorLoadData: "marketplaceErrorLoadingPluginsData",
|
|
108
|
-
errorLoadInstalled: "marketplaceErrorLoadingInstalledPlugins",
|
|
109
|
-
emptyData: "marketplaceNoPlugins",
|
|
110
|
-
emptyInstalled: "marketplaceNoInstalledPlugins",
|
|
111
|
-
installedCountSuffix: "marketplaceInstalledPluginsCountSuffix",
|
|
112
|
-
}
|
|
113
|
-
: {
|
|
114
|
-
pageTitle: "marketplaceSkillsPageTitle",
|
|
115
|
-
pageDescription: "marketplaceSkillsPageDescription",
|
|
116
|
-
tabMarketplace: "marketplaceTabMarketplaceSkills",
|
|
117
|
-
tabInstalled: "marketplaceTabInstalledSkills",
|
|
118
|
-
searchPlaceholder: "marketplaceSearchPlaceholderSkills",
|
|
119
|
-
sectionCatalog: "marketplaceSectionSkills",
|
|
120
|
-
sectionInstalled: "marketplaceSectionInstalledSkills",
|
|
121
|
-
errorLoadData: "marketplaceErrorLoadingSkillsData",
|
|
122
|
-
errorLoadInstalled: "marketplaceErrorLoadingInstalledSkills",
|
|
123
|
-
emptyData: "marketplaceNoSkills",
|
|
124
|
-
emptyInstalled: "marketplaceNoInstalledSkills",
|
|
125
|
-
installedCountSuffix: "marketplaceInstalledSkillsCountSuffix",
|
|
126
|
-
};
|
|
133
|
+
const copyKeys = getMarketplaceCopyKeys(typeFilter);
|
|
127
134
|
|
|
128
135
|
const [searchText, setSearchText] = useState("");
|
|
129
136
|
const [query, setQuery] = useState("");
|
|
@@ -145,9 +152,11 @@ export function MarketplacePage(props: MarketplacePageProps = {}) {
|
|
|
145
152
|
}, [searchText]);
|
|
146
153
|
|
|
147
154
|
const installedQuery = useMarketplaceInstalled(typeFilter);
|
|
155
|
+
const sceneParam = typeFilter === "skill" ? params.scene?.trim() : undefined;
|
|
148
156
|
|
|
149
157
|
const itemsQuery = useMarketplaceItems({
|
|
150
|
-
q: query || undefined,
|
|
158
|
+
q: sceneParam ? undefined : query || undefined,
|
|
159
|
+
scene: sceneParam,
|
|
151
160
|
type: typeFilter,
|
|
152
161
|
sort,
|
|
153
162
|
pageSize: PAGE_SIZE,
|
|
@@ -160,7 +169,7 @@ export function MarketplacePage(props: MarketplacePageProps = {}) {
|
|
|
160
169
|
!itemsQuery.hasNextPage ||
|
|
161
170
|
itemsQuery.isFetchingNextPage,
|
|
162
171
|
onLoadMore: () => itemsQuery.fetchNextPage(),
|
|
163
|
-
watchValue: `${typeFilter}:${scope}:${query}:${sort}:${itemsQuery.data?.loadedItems ?? 0}:${itemsQuery.data?.loadedPages ?? 0}`,
|
|
172
|
+
watchValue: `${typeFilter}:${scope}:${query}:${sceneParam ?? ""}:${sort}:${itemsQuery.data?.loadedItems ?? 0}:${itemsQuery.data?.loadedPages ?? 0}`,
|
|
164
173
|
});
|
|
165
174
|
|
|
166
175
|
useEffect(() => {
|
|
@@ -168,7 +177,7 @@ export function MarketplacePage(props: MarketplacePageProps = {}) {
|
|
|
168
177
|
if (container && typeof container.scrollTo === "function") {
|
|
169
178
|
container.scrollTo({ top: 0 });
|
|
170
179
|
}
|
|
171
|
-
}, [infiniteScroll.containerRef, query, scope, sort, typeFilter]);
|
|
180
|
+
}, [infiniteScroll.containerRef, query, sceneParam, scope, sort, typeFilter]);
|
|
172
181
|
|
|
173
182
|
const installMutation = useInstallMarketplaceItem();
|
|
174
183
|
const manageMutation = useManageMarketplaceItem();
|
|
@@ -263,15 +272,18 @@ export function MarketplacePage(props: MarketplacePageProps = {}) {
|
|
|
263
272
|
const manageState: ManageState = {
|
|
264
273
|
actionsByTarget: managingTargets,
|
|
265
274
|
};
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
+
const curatedSceneRoute = useMarketplaceCuratedSceneRoute({
|
|
276
|
+
items: allItems,
|
|
277
|
+
installedRecordLookup,
|
|
278
|
+
scene: sceneParam,
|
|
279
|
+
forcedType,
|
|
280
|
+
typeFilter,
|
|
281
|
+
scope,
|
|
282
|
+
searchText,
|
|
283
|
+
query,
|
|
284
|
+
showListSkeleton,
|
|
285
|
+
hasCatalogError: itemsQuery.isError,
|
|
286
|
+
});
|
|
275
287
|
|
|
276
288
|
const handleInstall = async (item: MarketplaceItemSummary) => {
|
|
277
289
|
const installSpec = item.install.spec;
|
|
@@ -419,11 +431,7 @@ export function MarketplacePage(props: MarketplacePageProps = {}) {
|
|
|
419
431
|
title,
|
|
420
432
|
typeLabel: detailConfig.typeLabel,
|
|
421
433
|
spec: item.install.spec,
|
|
422
|
-
|
|
423
|
-
metadataRaw: t("loading"),
|
|
424
|
-
contentRaw: t("loading"),
|
|
425
|
-
tags: item.tags,
|
|
426
|
-
author: item.author,
|
|
434
|
+
loading: true,
|
|
427
435
|
}),
|
|
428
436
|
openOptions,
|
|
429
437
|
);
|
|
@@ -468,36 +476,44 @@ export function MarketplacePage(props: MarketplacePageProps = {}) {
|
|
|
468
476
|
|
|
469
477
|
return (
|
|
470
478
|
<PageLayout className="flex h-full min-h-0 flex-col pb-0">
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
479
|
+
{!curatedSceneRoute.isSceneRoute && (
|
|
480
|
+
<>
|
|
481
|
+
<Tabs
|
|
482
|
+
tabs={[
|
|
483
|
+
{ id: "all", label: t(copyKeys.tabMarketplace) },
|
|
484
|
+
{
|
|
485
|
+
id: "installed",
|
|
486
|
+
label: t(copyKeys.tabInstalled),
|
|
487
|
+
count: installedQuery.data?.total ?? 0,
|
|
488
|
+
},
|
|
489
|
+
]}
|
|
490
|
+
activeTab={scope}
|
|
491
|
+
onChange={(value) => setScope(value as ScopeType)}
|
|
492
|
+
className="mb-3"
|
|
493
|
+
/>
|
|
494
|
+
|
|
495
|
+
<FilterPanel
|
|
496
|
+
scope={scope}
|
|
497
|
+
searchText={searchText}
|
|
498
|
+
searchPlaceholder={t(copyKeys.searchPlaceholder)}
|
|
499
|
+
sort={sort}
|
|
500
|
+
onSearchTextChange={setSearchText}
|
|
501
|
+
onSortChange={setSort}
|
|
502
|
+
/>
|
|
503
|
+
</>
|
|
504
|
+
)}
|
|
491
505
|
|
|
492
506
|
<section className="flex min-h-0 flex-1 flex-col">
|
|
493
|
-
|
|
494
|
-
<
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
507
|
+
{!curatedSceneRoute.isSceneRoute && !curatedSceneRoute.showShelves && (
|
|
508
|
+
<div className="mb-3 flex items-center justify-between">
|
|
509
|
+
<h3 className="text-[14px] font-semibold text-gray-900">
|
|
510
|
+
{scope === "installed"
|
|
511
|
+
? t(copyKeys.sectionInstalled)
|
|
512
|
+
: t(copyKeys.sectionCatalog)}
|
|
513
|
+
</h3>
|
|
514
|
+
<span className="text-[12px] text-gray-500">{listSummary}</span>
|
|
515
|
+
</div>
|
|
516
|
+
)}
|
|
501
517
|
|
|
502
518
|
{scope === "all" && itemsQuery.isError && (
|
|
503
519
|
<div className="rounded-xl border border-rose-200 bg-rose-50 p-4 text-sm text-rose-700">
|
|
@@ -515,55 +531,60 @@ export function MarketplacePage(props: MarketplacePageProps = {}) {
|
|
|
515
531
|
className="min-h-0 flex-1 overflow-y-auto custom-scrollbar pr-1"
|
|
516
532
|
aria-busy={showListSkeleton || itemsQuery.isFetchingNextPage}
|
|
517
533
|
>
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
534
|
+
{curatedSceneRoute.isSceneRoute && curatedSceneRoute.selectedScene && (
|
|
535
|
+
<MarketplaceCuratedSceneView
|
|
536
|
+
scene={curatedSceneRoute.selectedScene}
|
|
537
|
+
entries={curatedSceneRoute.sceneEntries}
|
|
538
|
+
isLoading={showListSkeleton}
|
|
539
|
+
language={language}
|
|
540
|
+
localeFallbacks={localeFallbacks}
|
|
541
|
+
installState={installState}
|
|
542
|
+
onBack={() => navigate(curatedSceneRoute.backPath)}
|
|
543
|
+
onOpen={(entry) => void openItemDetail(entry.item, entry.record)}
|
|
544
|
+
onInstall={handleInstall}
|
|
545
|
+
/>
|
|
546
|
+
)}
|
|
547
|
+
|
|
548
|
+
{curatedSceneRoute.showShelves && (
|
|
549
|
+
<MarketplaceCuratedShelves
|
|
550
|
+
entries={curatedSceneRoute.entries}
|
|
551
|
+
scenes={curatedSceneRoute.scenes}
|
|
552
|
+
language={language}
|
|
553
|
+
installState={installState}
|
|
554
|
+
onOpen={(entry) => void openItemDetail(entry.item, entry.record)}
|
|
555
|
+
onInstall={handleInstall}
|
|
556
|
+
onOpenScene={(scene) =>
|
|
557
|
+
navigate(`${curatedSceneRoute.pathPrefix}/${scene}`)
|
|
558
|
+
}
|
|
559
|
+
/>
|
|
560
|
+
)}
|
|
561
|
+
|
|
562
|
+
{!curatedSceneRoute.isSceneRoute && (
|
|
563
|
+
<MarketplaceCatalogGrid
|
|
564
|
+
scope={scope}
|
|
565
|
+
title={
|
|
566
|
+
scope === "installed"
|
|
567
|
+
? t(copyKeys.sectionInstalled)
|
|
568
|
+
: t(copyKeys.sectionCatalog)
|
|
569
|
+
}
|
|
570
|
+
summary={listSummary}
|
|
571
|
+
showTitle={curatedSceneRoute.showShelves}
|
|
572
|
+
showListSkeleton={showListSkeleton}
|
|
573
|
+
skeletonCardCount={SKELETON_CARD_COUNT}
|
|
574
|
+
allItems={allItems}
|
|
575
|
+
installedEntries={installedEntries}
|
|
576
|
+
installedRecordLookup={installedRecordLookup}
|
|
577
|
+
language={language}
|
|
578
|
+
installState={installState}
|
|
579
|
+
manageState={manageState}
|
|
580
|
+
onOpen={(item, record) => void openItemDetail(item, record)}
|
|
581
|
+
onInstall={handleInstall}
|
|
582
|
+
onManage={handleManage}
|
|
583
|
+
/>
|
|
584
|
+
)}
|
|
565
585
|
|
|
566
586
|
{scope === "all" &&
|
|
587
|
+
!curatedSceneRoute.isSceneRoute &&
|
|
567
588
|
!showListSkeleton &&
|
|
568
589
|
!itemsQuery.isError &&
|
|
569
590
|
allItems.length === 0 && (
|
|
@@ -572,6 +593,7 @@ export function MarketplacePage(props: MarketplacePageProps = {}) {
|
|
|
572
593
|
</div>
|
|
573
594
|
)}
|
|
574
595
|
{scope === "installed" &&
|
|
596
|
+
!curatedSceneRoute.isSceneRoute &&
|
|
575
597
|
!showListSkeleton &&
|
|
576
598
|
!installedQuery.isError &&
|
|
577
599
|
installedEntries.length === 0 && (
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
MarketplaceInstalledRecord,
|
|
3
|
+
MarketplaceItemSummary,
|
|
4
|
+
MarketplaceItemType,
|
|
5
|
+
} from "@/shared/lib/api";
|
|
6
|
+
import { findInstalledRecordForItem } from "@/features/marketplace/components/marketplace-page-data";
|
|
7
|
+
import {
|
|
8
|
+
useMarketplaceSkillSceneCounts,
|
|
9
|
+
useMarketplaceSkillScenes,
|
|
10
|
+
} from "@/features/marketplace/hooks/use-marketplace";
|
|
11
|
+
import { useMemo } from "react";
|
|
12
|
+
|
|
13
|
+
type MarketplaceCuratedSceneRouteParams = {
|
|
14
|
+
items: MarketplaceItemSummary[];
|
|
15
|
+
installedRecordLookup: Map<string, MarketplaceInstalledRecord>;
|
|
16
|
+
scene?: string;
|
|
17
|
+
forcedType?: "plugins" | "skills";
|
|
18
|
+
typeFilter: MarketplaceItemType;
|
|
19
|
+
scope: "all" | "installed";
|
|
20
|
+
searchText: string;
|
|
21
|
+
query: string;
|
|
22
|
+
showListSkeleton: boolean;
|
|
23
|
+
hasCatalogError: boolean;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export function useMarketplaceCuratedSceneRoute(
|
|
27
|
+
params: MarketplaceCuratedSceneRouteParams,
|
|
28
|
+
) {
|
|
29
|
+
const {
|
|
30
|
+
items,
|
|
31
|
+
installedRecordLookup,
|
|
32
|
+
scene,
|
|
33
|
+
forcedType,
|
|
34
|
+
typeFilter,
|
|
35
|
+
scope,
|
|
36
|
+
searchText,
|
|
37
|
+
query,
|
|
38
|
+
showListSkeleton,
|
|
39
|
+
hasCatalogError,
|
|
40
|
+
} = params;
|
|
41
|
+
const scenesQuery = useMarketplaceSkillScenes(typeFilter === "skill");
|
|
42
|
+
const rawScenes = useMemo(
|
|
43
|
+
() => scenesQuery.data?.scenes ?? [],
|
|
44
|
+
[scenesQuery.data?.scenes],
|
|
45
|
+
);
|
|
46
|
+
const fallbackCounts = useMarketplaceSkillSceneCounts(rawScenes, typeFilter === "skill");
|
|
47
|
+
const scenes = useMemo(
|
|
48
|
+
() =>
|
|
49
|
+
rawScenes.map((entry) => ({
|
|
50
|
+
...entry,
|
|
51
|
+
count: typeof entry.count === "number"
|
|
52
|
+
? entry.count
|
|
53
|
+
: fallbackCounts.get(entry.scene),
|
|
54
|
+
})),
|
|
55
|
+
[fallbackCounts, rawScenes],
|
|
56
|
+
);
|
|
57
|
+
const entries = useMemo(
|
|
58
|
+
() =>
|
|
59
|
+
items.map((item) => ({
|
|
60
|
+
item,
|
|
61
|
+
record: findInstalledRecordForItem(item, installedRecordLookup),
|
|
62
|
+
})),
|
|
63
|
+
[items, installedRecordLookup],
|
|
64
|
+
);
|
|
65
|
+
const selectedScene = useMemo(() => {
|
|
66
|
+
const normalizedScene = scene?.trim();
|
|
67
|
+
if (!normalizedScene) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
return scenes.find((entry) => entry.scene === normalizedScene) ?? {
|
|
71
|
+
scene: normalizedScene,
|
|
72
|
+
title: normalizedScene,
|
|
73
|
+
};
|
|
74
|
+
}, [scene, scenes]);
|
|
75
|
+
const isSceneRoute = typeFilter === "skill" && Boolean(scene?.trim());
|
|
76
|
+
const showShelves =
|
|
77
|
+
typeFilter === "skill" &&
|
|
78
|
+
scope === "all" &&
|
|
79
|
+
!searchText.trim() &&
|
|
80
|
+
!query &&
|
|
81
|
+
!showListSkeleton &&
|
|
82
|
+
!hasCatalogError &&
|
|
83
|
+
scenes.length > 0 &&
|
|
84
|
+
items.length >= 4 &&
|
|
85
|
+
!isSceneRoute;
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
entries,
|
|
89
|
+
scenes,
|
|
90
|
+
selectedScene,
|
|
91
|
+
sceneEntries: entries,
|
|
92
|
+
isSceneRoute,
|
|
93
|
+
showShelves,
|
|
94
|
+
backPath: forcedType ? "/skills" : "/marketplace/skills",
|
|
95
|
+
pathPrefix: forcedType ? "/skills/scenes" : "/marketplace/skills/scenes",
|
|
96
|
+
};
|
|
97
|
+
}
|