@@ -26,7 +26,9 @@ export interface ViewState {
2626 type : string
2727 search : string
2828 tags : string [ ]
29+ installed : boolean // New filter to show only installed items
2930 }
31+ installedMetadata ?: any // Store installed metadata for filtering
3032}
3133
3234type TransitionPayloads = {
@@ -65,6 +67,7 @@ export class MarketplaceViewStateManager {
6567 type : "" ,
6668 search : "" ,
6769 tags : [ ] ,
70+ installed : false ,
6871 } ,
6972 }
7073 }
@@ -189,8 +192,11 @@ export class MarketplaceViewStateManager {
189192 let newDisplayItems : MarketplaceItem [ ]
190193 let newDisplayOrganizationMcps : MarketplaceItem [ ]
191194 if ( this . isFilterActive ( ) ) {
192- newDisplayItems = this . filterItems ( [ ...items ] )
193- newDisplayOrganizationMcps = this . filterItems ( [ ...this . state . organizationMcps ] )
195+ newDisplayItems = this . filterItems ( [ ...items ] , this . state . installedMetadata )
196+ newDisplayOrganizationMcps = this . filterItems (
197+ [ ...this . state . organizationMcps ] ,
198+ this . state . installedMetadata ,
199+ )
194200 } else {
195201 // No filters active - show all items
196202 newDisplayItems = [ ...items ]
@@ -251,6 +257,7 @@ export class MarketplaceViewStateManager {
251257 type : filters . type !== undefined ? filters . type : this . state . filters . type ,
252258 search : filters . search !== undefined ? filters . search : this . state . filters . search ,
253259 tags : filters . tags !== undefined ? filters . tags : this . state . filters . tags ,
260+ installed : filters . installed !== undefined ? filters . installed : this . state . filters . installed ,
254261 }
255262
256263 // Update filters first
@@ -260,8 +267,11 @@ export class MarketplaceViewStateManager {
260267 }
261268
262269 // Apply filters to displayItems and displayOrganizationMcps with the updated filters
263- const newDisplayItems = this . filterItems ( this . state . allItems )
264- const newDisplayOrganizationMcps = this . filterItems ( this . state . organizationMcps )
270+ const newDisplayItems = this . filterItems ( this . state . allItems , this . state . installedMetadata )
271+ const newDisplayOrganizationMcps = this . filterItems (
272+ this . state . organizationMcps ,
273+ this . state . installedMetadata ,
274+ )
265275
266276 // Update state with filtered items
267277 this . state = {
@@ -284,11 +294,16 @@ export class MarketplaceViewStateManager {
284294 }
285295
286296 public isFilterActive ( ) : boolean {
287- return ! ! ( this . state . filters . type || this . state . filters . search || this . state . filters . tags . length > 0 )
297+ return ! ! (
298+ this . state . filters . type ||
299+ this . state . filters . search ||
300+ this . state . filters . tags . length > 0 ||
301+ this . state . filters . installed
302+ )
288303 }
289304
290- public filterItems ( items : MarketplaceItem [ ] ) : MarketplaceItem [ ] {
291- const { type, search, tags } = this . state . filters
305+ public filterItems ( items : MarketplaceItem [ ] , installedMetadata ?: any ) : MarketplaceItem [ ] {
306+ const { type, search, tags, installed } = this . state . filters
292307
293308 return items
294309 . map ( ( item ) => {
@@ -303,9 +318,20 @@ export class MarketplaceViewStateManager {
303318 : false
304319 const tagMatch = tags . length > 0 ? item . tags ?. some ( ( tag ) => tags . includes ( tag ) ) : false
305320
321+ // Check installed status if filter is active
322+ let installedMatch = true
323+ if ( installed && installedMetadata ) {
324+ const isInstalledGlobally = ! ! installedMetadata ?. global ?. [ item . id ]
325+ const isInstalledInProject = ! ! installedMetadata ?. project ?. [ item . id ]
326+ installedMatch = isInstalledGlobally || isInstalledInProject
327+ }
328+
306329 // Determine if the main item matches all filters
307330 const mainItemMatches =
308- typeMatch && ( ! search || nameMatch || descriptionMatch ) && ( ! tags . length || tagMatch )
331+ typeMatch &&
332+ ( ! search || nameMatch || descriptionMatch ) &&
333+ ( ! tags . length || tagMatch ) &&
334+ installedMatch
309335
310336 const hasMatchingSubcomponents = false
311337
@@ -343,20 +369,29 @@ export class MarketplaceViewStateManager {
343369 // Handle state updates for marketplace items
344370 // The state.marketplaceItems come from ClineProvider, see the file src/core/webview/ClineProvider.ts
345371 const marketplaceItems = message . state . marketplaceItems
372+ const marketplaceInstalledMetadata = message . state . marketplaceInstalledMetadata
346373
347374 if ( marketplaceItems !== undefined ) {
348375 // Always use the marketplace items from the extension when they're provided
349376 // This ensures fresh data is always displayed
350377 const items = [ ...marketplaceItems ]
351378
379+ // Update installed metadata if provided
380+ if ( marketplaceInstalledMetadata !== undefined ) {
381+ this . state . installedMetadata = marketplaceInstalledMetadata
382+ }
383+
352384 // Calculate display items based on current filters
353385 // If no filters are active, show all items
354386 // If filters are active, apply filtering
355387 let newDisplayItems : MarketplaceItem [ ]
356388 let newDisplayOrganizationMcps : MarketplaceItem [ ]
357389 if ( this . isFilterActive ( ) ) {
358- newDisplayItems = this . filterItems ( items )
359- newDisplayOrganizationMcps = this . filterItems ( this . state . organizationMcps )
390+ newDisplayItems = this . filterItems ( items , this . state . installedMetadata )
391+ newDisplayOrganizationMcps = this . filterItems (
392+ this . state . organizationMcps ,
393+ this . state . installedMetadata ,
394+ )
360395 } else {
361396 // No filters active - show all items
362397 newDisplayItems = items
@@ -370,6 +405,7 @@ export class MarketplaceViewStateManager {
370405 allItems : items ,
371406 displayItems : newDisplayItems ,
372407 displayOrganizationMcps : newDisplayOrganizationMcps ,
408+ installedMetadata : marketplaceInstalledMetadata || this . state . installedMetadata ,
373409 }
374410 // Notification is handled below after all state parts are processed
375411 }
@@ -411,14 +447,25 @@ export class MarketplaceViewStateManager {
411447 if ( message . type === "marketplaceData" ) {
412448 const marketplaceItems = message . marketplaceItems
413449 const organizationMcps = message . organizationMcps || [ ]
450+ const marketplaceInstalledMetadata = message . marketplaceInstalledMetadata
414451
415452 if ( marketplaceItems !== undefined ) {
416453 // Always use the marketplace items from the extension when they're provided
417454 // This ensures fresh data is always displayed
418455 const items = [ ...marketplaceItems ]
419456 const orgMcps = [ ...organizationMcps ]
420- const newDisplayItems = this . isFilterActive ( ) ? this . filterItems ( items ) : items
421- const newDisplayOrganizationMcps = this . isFilterActive ( ) ? this . filterItems ( orgMcps ) : orgMcps
457+
458+ // Update installed metadata if provided
459+ if ( marketplaceInstalledMetadata !== undefined ) {
460+ this . state . installedMetadata = marketplaceInstalledMetadata
461+ }
462+
463+ const newDisplayItems = this . isFilterActive ( )
464+ ? this . filterItems ( items , this . state . installedMetadata )
465+ : items
466+ const newDisplayOrganizationMcps = this . isFilterActive ( )
467+ ? this . filterItems ( orgMcps , this . state . installedMetadata )
468+ : orgMcps
422469
423470 // Update state in a single operation
424471 this . state = {
@@ -428,6 +475,7 @@ export class MarketplaceViewStateManager {
428475 organizationMcps : orgMcps ,
429476 displayItems : newDisplayItems ,
430477 displayOrganizationMcps : newDisplayOrganizationMcps ,
478+ installedMetadata : marketplaceInstalledMetadata || this . state . installedMetadata ,
431479 }
432480 }
433481
0 commit comments