From 563b327007432f0d2a85f34945ca5dbd82b2d51a Mon Sep 17 00:00:00 2001 From: Trung Dang Date: Fri, 2 May 2025 23:16:26 +0700 Subject: [PATCH] chore: marketplace wordings, cleanup, and document refresh (#6) * chore: reword all `PackageManager` => `Marketplace` * chore: document refresh, `mcp-server` => `mcp` * chore: correct word * chore: remove unnecessary condition * chore: remove unnecessary bits * chore: add note for failed test --- cline_docs/marketplace/README.md | 10 +- .../implementation/01-architecture.md | 69 +- .../implementation/02-core-components.md | 221 +----- .../implementation/03-data-structures.md | 341 +-------- .../implementation/04-search-and-filter.md | 258 +------ .../implementation/05-ui-components.md | 710 +----------------- .../implementation/06-testing-strategy.md | 100 +-- .../implementation/07-extending.md | 62 +- .../marketplace/user-guide/01-introduction.md | 8 +- ...wsing-packages.md => 02-browsing-items.md} | 2 +- .../user-guide/03-searching-and-filtering.md | 2 +- .../user-guide/04-working-with-details.md | 2 +- .../user-guide/05-adding-packages.md | 39 +- .../user-guide/06-adding-custom-sources.md | 4 +- knip.json | 1 - marketplace-template/README.md | 46 -- .../data-processor/metadata.en.yml | 7 - .../mcp servers/data-processor/server.js | 143 ---- .../groups/data-engineering/metadata.en.yml | 6 - .../modes/data-engineer-mode/metadata.en.yml | 7 - .../modes/data-engineer-mode/mode.md | 56 -- .../example-server/metadata.en.yml | 6 - .../mcp servers/file-analyzer/metadata.en.yml | 8 - .../mcp servers/file-analyzer/server.js | 134 ---- marketplace-template/metadata.en.yml | 5 - .../modes/developer-mode/metadata.en.yml | 8 - .../modes/developer-mode/mode.md | 51 -- .../data-validator/metadata.en.yml | 8 - .../mcp servers/data-validator/server.js | 124 --- .../packages/data-platform/metadata.en.yml | 7 - .../packages/data-platform/metadata.es.yml | 5 - .../packages/data-platform/metadata.ja.yml | 5 - .../modes/platform-admin-mode/metadata.en.yml | 8 - .../modes/platform-admin-mode/mode.md | 129 ---- .../packages/test-source-url/metadata.en.yml | 8 - src/core/webview/marketplaceMessageHandler.ts | 8 +- src/i18n/locales/ca/marketplace.json | 4 +- src/i18n/locales/de/marketplace.json | 4 +- src/i18n/locales/en/marketplace.json | 4 +- src/i18n/locales/es/marketplace.json | 4 +- src/i18n/locales/fr/marketplace.json | 4 +- src/i18n/locales/hi/marketplace.json | 4 +- src/i18n/locales/it/marketplace.json | 4 +- src/i18n/locales/ja/marketplace.json | 4 +- src/i18n/locales/ko/marketplace.json | 4 +- src/i18n/locales/pl/marketplace.json | 4 +- src/i18n/locales/pt-BR/marketplace.json | 4 +- src/i18n/locales/tr/marketplace.json | 4 +- src/i18n/locales/vi/marketplace.json | 4 +- src/i18n/locales/zh-CN/marketplace.json | 4 +- src/i18n/locales/zh-TW/marketplace.json | 4 +- src/services/marketplace/GitFetcher.ts | 4 +- .../marketplace/MarketplaceManager.ts | 14 +- src/services/marketplace/MetadataScanner.ts | 20 +- .../__tests__/MarketplaceManager.test.ts | 91 +-- .../MetadataScanner.external.test.ts | 6 +- .../__tests__/MetadataScanner.test.ts | 8 +- .../marketplace/__tests__/schemas.test.ts | 8 +- src/services/marketplace/schemas.ts | 8 +- src/services/marketplace/types.ts | 14 +- .../parseSourceCodeDefinitions.tsx.test.ts | 2 +- webview-ui/src/App.tsx | 4 +- .../marketplace/MarketplaceView.tsx | 4 +- .../MarketplaceViewStateManager.test.ts | 4 +- .../components/MarketplaceItemCard.tsx | 6 +- .../marketplace/components/TypeGroup.tsx | 4 +- .../__tests__/MarketplaceItemCard.test.tsx | 8 +- .../components/__tests__/TypeGroup.test.tsx | 4 +- .../utils/__tests__/grouping.test.ts | 16 +- .../src/i18n/locales/ca/marketplace.json | 4 +- .../src/i18n/locales/de/marketplace.json | 4 +- .../src/i18n/locales/en/marketplace.json | 4 +- .../src/i18n/locales/es/marketplace.json | 4 +- .../src/i18n/locales/fr/marketplace.json | 4 +- .../src/i18n/locales/hi/marketplace.json | 4 +- .../src/i18n/locales/it/marketplace.json | 4 +- .../src/i18n/locales/ja/marketplace.json | 4 +- .../src/i18n/locales/ko/marketplace.json | 4 +- .../src/i18n/locales/pl/marketplace.json | 4 +- .../src/i18n/locales/pt-BR/marketplace.json | 4 +- .../src/i18n/locales/tr/marketplace.json | 4 +- .../src/i18n/locales/vi/marketplace.json | 4 +- .../src/i18n/locales/zh-CN/marketplace.json | 4 +- .../src/i18n/locales/zh-TW/marketplace.json | 4 +- webview-ui/src/test/test-utils.tsx | 4 +- 85 files changed, 379 insertions(+), 2578 deletions(-) rename cline_docs/marketplace/user-guide/{02-browsing-packages.md => 02-browsing-items.md} (98%) delete mode 100644 marketplace-template/README.md delete mode 100644 marketplace-template/groups/data-engineering/mcp servers/data-processor/metadata.en.yml delete mode 100644 marketplace-template/groups/data-engineering/mcp servers/data-processor/server.js delete mode 100644 marketplace-template/groups/data-engineering/metadata.en.yml delete mode 100644 marketplace-template/groups/data-engineering/modes/data-engineer-mode/metadata.en.yml delete mode 100644 marketplace-template/groups/data-engineering/modes/data-engineer-mode/mode.md delete mode 100644 marketplace-template/mcp servers/example-server/metadata.en.yml delete mode 100644 marketplace-template/mcp servers/file-analyzer/metadata.en.yml delete mode 100644 marketplace-template/mcp servers/file-analyzer/server.js delete mode 100644 marketplace-template/metadata.en.yml delete mode 100644 marketplace-template/modes/developer-mode/metadata.en.yml delete mode 100644 marketplace-template/modes/developer-mode/mode.md delete mode 100644 marketplace-template/packages/data-platform/mcp servers/data-validator/metadata.en.yml delete mode 100644 marketplace-template/packages/data-platform/mcp servers/data-validator/server.js delete mode 100644 marketplace-template/packages/data-platform/metadata.en.yml delete mode 100644 marketplace-template/packages/data-platform/metadata.es.yml delete mode 100644 marketplace-template/packages/data-platform/metadata.ja.yml delete mode 100644 marketplace-template/packages/data-platform/modes/platform-admin-mode/metadata.en.yml delete mode 100644 marketplace-template/packages/data-platform/modes/platform-admin-mode/mode.md delete mode 100644 marketplace-template/packages/test-source-url/metadata.en.yml diff --git a/cline_docs/marketplace/README.md b/cline_docs/marketplace/README.md index 2c78fe3440..6e43e25723 100644 --- a/cline_docs/marketplace/README.md +++ b/cline_docs/marketplace/README.md @@ -9,10 +9,10 @@ This directory contains comprehensive documentation for the Roo Code Marketplace The user guide provides end-user documentation for using the Marketplace: 1. [Introduction to Marketplace](./user-guide/01-introduction.md) - Overview and purpose of the Marketplace -2. [Browsing Packages](./user-guide/02-browsing-packages.md) - Understanding the interface and navigating items +2. [Browsing Items](./user-guide/02-browsing-items.md) - Understanding the interface and navigating items 3. [Searching and Filtering](./user-guide/03-searching-and-filtering.md) - Using search and filters to find items -4. [Working with Package Details](./user-guide/04-working-with-details.md) - Exploring package details and subcomponents -5. [Adding Packages](./user-guide/05-adding-packages.md) - Creating and contributing your own items and package +4. [Working with Package Details](./user-guide/04-working-with-details.md) - Exploring package details and items +5. [Adding Packages](./user-guide/05-adding-packages.md) - Creating and contributing your own items 6. [Adding Custom Sources](./user-guide/06-adding-custom-sources.md) - Setting up and managing custom sources ### Implementation Documentation @@ -29,10 +29,10 @@ The implementation documentation provides technical details for developers: The Marketplace provides the following key features: - **Component Discovery**: Browse and search for items -- **Package Management**: Add packages of items to your environment +- **Item Management**: Add/update/remove items to your environment - **Custom Sources**: Add your own repositories of team or private Marketplaces - **Localization Support**: View items in your preferred language -- **Filtering**: Filter components by type, search term, and tags +- **Filtering**: Filter items by type, search term, and tags ## Default Marketplace Repository diff --git a/cline_docs/marketplace/implementation/01-architecture.md b/cline_docs/marketplace/implementation/01-architecture.md index e74433c1b5..61100f06c7 100644 --- a/cline_docs/marketplace/implementation/01-architecture.md +++ b/cline_docs/marketplace/implementation/01-architecture.md @@ -4,7 +4,7 @@ This document provides a comprehensive overview of the Marketplace's architectur ## System Overview -The Marketplace is built on a modular architecture that separates concerns between data management, UI rendering, and user interactions. The system consists of several key components that work together to provide a seamless experience for discovering, browsing, and managing packages. +The Marketplace is built on a modular architecture that separates concerns between data management, UI rendering, and user interactions. The system consists of several key components that work together to provide a seamless experience for discovering, browsing, and managing items. ### High-Level Architecture @@ -12,8 +12,8 @@ The Marketplace is built on a modular architecture that separates concerns betwe graph TD User[User] -->|Interacts with| UI[Marketplace UI] UI -->|Sends messages| MH[Message Handler] - MH -->|Processes requests| PM[PackageManagerManager] - PM -->|Validates sources| PSV[PackageManagerSourceValidation] + MH -->|Processes requests| PM[MarketplaceManager] + PM -->|Validates sources| PSV[MarketplaceSourceValidation] PM -->|Fetches repos| GF[GitFetcher] GF -->|Scans metadata| MS[MetadataScanner] MS -->|Reads| FS[File System / Git Repositories] @@ -38,20 +38,20 @@ The Marketplace components interact through a well-defined message flow: 1. **Data Loading**: - GitFetcher handles repository cloning and updates - - MetadataScanner loads package data from repositories - - PackageManagerManager manages caching and concurrency + - MetadataScanner loads item data from repositories + - MarketplaceManager manages caching and concurrency - UI requests data through the message handler 2. **Filtering and Search**: - UI sends filter/search criteria to the backend - - PackageManagerManager applies filters with match info + - MarketplaceManager applies filters with match info - Filtered results are returned to the UI - State manager handles view-level filtering 3. **Source Management**: - UI sends source management commands - - PackageManagerManager coordinates with GitFetcher + - MarketplaceManager coordinates with GitFetcher - Cache is managed with timeout protection - Sources are processed with concurrency control @@ -69,7 +69,7 @@ graph LR subgraph Backend GF[GitFetcher] MS[MetadataScanner] - PM[PackageManagerManager] + PM[MarketplaceManager] MH[Message Handler] end @@ -92,16 +92,16 @@ graph LR ## Sequence Diagrams -### Package Loading Sequence +### Item Loading Sequence -The following sequence diagram shows how packages are loaded from sources: +The following sequence diagram shows how items are loaded from sources: ```mermaid sequenceDiagram participant User participant UI as UI Components participant MH as Message Handler - participant PM as PackageManagerManager + participant PM as MarketplaceManager participant GF as GitFetcher participant MS as MetadataScanner participant FS as File System/Git @@ -118,7 +118,7 @@ sequenceDiagram GF-->>PM: Return repository data PM-->>MH: Return initial items MH-->>UI: Update with items - UI-->>User: Display packages + UI-->>User: Display items ``` ### Search and Filter Sequence @@ -131,7 +131,7 @@ sequenceDiagram participant UI as UI Components participant State as State Manager participant MH as Message Handler - participant PM as PackageManagerManager + participant PM as MarketplaceManager User->>UI: Enter search term UI->>State: Update filters @@ -162,20 +162,20 @@ The following class diagram shows the main classes in the Marketplace system: ```mermaid classDiagram - class PackageManagerManager { - -currentItems: PackageManagerItem[] + class MarketplaceManager { + -currentItems: MarketplaceItem[] -cache: Map -gitFetcher: GitFetcher -activeSourceOperations: Set - +getPackageManagerItems(): PackageManagerItem[] - +filterItems(filters): PackageManagerItem[] - +sortItems(sortBy, order): PackageManagerItem[] + +getMarketplaceItems(): MarketplaceItem[] + +filterItems(filters): MarketplaceItem[] + +sortItems(sortBy, order): MarketplaceItem[] +refreshRepository(url): void -queueOperation(operation): void -validateSources(sources): ValidationError[] } - class PackageManagerSourceValidation { + class MarketplaceSourceValidation { +validateSourceUrl(url): ValidationError[] +validateSourceName(name): ValidationError[] +validateSourceDuplicates(sources): ValidationError[] @@ -187,7 +187,7 @@ classDiagram class GitFetcher { -cacheDir: string -metadataScanner: MetadataScanner - +fetchRepository(url): PackageManagerRepository + +fetchRepository(url): MarketplaceRepository -cloneOrPullRepository(url): void -validateRepositoryStructure(dir): void -parseRepositoryMetadata(dir): RepositoryMetadata @@ -195,12 +195,12 @@ classDiagram class MetadataScanner { -git: SimpleGit - +scanDirectory(path): PackageManagerItem[] + +scanDirectory(path): MarketplaceItem[] +parseMetadata(file): ComponentMetadata - -buildComponentHierarchy(items): PackageManagerItem[] + -buildComponentHierarchy(items): MarketplaceItem[] } - class PackageManagerViewStateManager { + class MarketplaceViewStateManager { -state: ViewState -stateChangeHandlers: Set -fetchTimeoutId: NodeJS.Timeout @@ -213,15 +213,15 @@ classDiagram -notifyStateChange(): void -clearFetchTimeout(): void -isFilterActive(): boolean - -filterItems(items): PackageManagerItem[] - -sortItems(items): PackageManagerItem[] + -filterItems(items): MarketplaceItem[] + -sortItems(items): MarketplaceItem[] +handleMessage(message): Promise } - PackageManagerManager --> GitFetcher: uses - PackageManagerManager --> PackageManagerSourceValidation: uses + MarketplaceManager --> GitFetcher: uses + MarketplaceManager --> MarketplaceSourceValidation: uses GitFetcher --> MetadataScanner: uses - PackageManagerManager --> PackageManagerViewStateManager: updates + MarketplaceManager --> MarketplaceViewStateManager: updates ``` ## Component Responsibilities @@ -242,7 +242,7 @@ classDiagram - Builds component hierarchies - Handles file system operations -3. **PackageManagerManager** +3. **MarketplaceManager** - Manages concurrent operations - Handles caching with timeout protection @@ -257,7 +257,7 @@ classDiagram ### Frontend Components -1. **PackageManagerViewStateManager** +1. **MarketplaceViewStateManager** - Manages frontend state and backend synchronization - Handles state transitions and message processing @@ -267,7 +267,7 @@ classDiagram - Manages source modification tracking - Provides state change subscriptions -2. **PackageManagerSourceValidation** +2. **MarketplaceSourceValidation** - Validates Git repository URLs for any domain - Validates source names and configurations @@ -275,12 +275,13 @@ classDiagram - Provides structured validation errors - Supports multiple Git protocols (HTTPS, SSH, Git) -3. **PackageManagerItemCard** +3. **MarketplaceItemCard** - - Displays package information + - Displays item information - Handles tag interactions - Manages expandable sections - Shows match highlights + - Handle item actions. 4. **ExpandableSection** @@ -369,4 +370,4 @@ The Marketplace architecture is designed for extensibility: --- -**Previous**: [Adding Custom Package Sources](../user-guide/06-adding-custom-sources.md) | **Next**: [Core Components](./02-core-components.md) +**Previous**: [Adding Custom Item Sources](../user-guide/06-adding-custom-sources.md) | **Next**: [Core Components](./02-core-components.md) diff --git a/cline_docs/marketplace/implementation/02-core-components.md b/cline_docs/marketplace/implementation/02-core-components.md index e12a05043a..3aa8d96726 100644 --- a/cline_docs/marketplace/implementation/02-core-components.md +++ b/cline_docs/marketplace/implementation/02-core-components.md @@ -16,46 +16,7 @@ The GitFetcher is responsible for managing Git repository operations, including ### Implementation Details -```typescript -class GitFetcher { - private readonly cacheDir: string - private metadataScanner: MetadataScanner - private git?: SimpleGit - - /** - * Fetch repository data - * @param repoUrl Repository URL - * @param forceRefresh Whether to bypass cache - * @param sourceName Optional source name - * @returns Repository data - */ - public async fetchRepository( - repoUrl: string, - forceRefresh = false, - sourceName?: string, - ): Promise { - // Implementation details - } - - /** - * Clone or pull repository - * @param repoUrl Repository URL - * @param repoDir Repository directory - * @param forceRefresh Whether to force refresh - */ - private async cloneOrPullRepository(repoUrl: string, repoDir: string, forceRefresh: boolean): Promise { - // Implementation details - } - - /** - * Clean up git locks - * @param repoDir Repository directory - */ - private async cleanupGitLocks(repoDir: string): Promise { - // Implementation details - } -} -``` +[/src/services/marketplace/GitFetcher.ts](/src/services/marketplace/GitFetcher.ts) ### Key Algorithms @@ -85,11 +46,11 @@ The repository management process includes: ## MetadataScanner -The MetadataScanner is responsible for reading and parsing package metadata from repositories. +The MetadataScanner is responsible for reading and parsing item metadata from repositories. ### Responsibilities -- Scanning directories for package metadata files +- Scanning directories for item metadata files - Parsing YAML metadata into structured objects - Building component hierarchies - Supporting localized metadata @@ -97,40 +58,11 @@ The MetadataScanner is responsible for reading and parsing package metadata from ### Implementation Details -```typescript -class MetadataScanner { - private git: SimpleGit - private localizationOptions: LocalizationOptions +[/src/services/marketplace/MetadataScanner.ts](/src/services/marketplace/MetadataScanner.ts) - /** - * Scan directory for package metadata - * @param directoryPath Directory to scan - * @param baseUrl Base repository URL - * @param sourceName Source repository name - * @returns Array of package items - */ - public async scanDirectory( - directoryPath: string, - baseUrl?: string, - sourceName?: string, - ): Promise { - // Implementation details - } +## MarketplaceManager - /** - * Parse metadata file - * @param filePath Path to metadata file - * @returns Parsed metadata - */ - private async parseMetadataFile(filePath: string): Promise { - // Implementation details - } -} -``` - -## PackageManagerManager - -The PackageManagerManager is the central component that manages marketplace data, caching, and operations. +The MarketplaceManager is the central component that manages marketplace data, caching, and operations. ### Responsibilities @@ -138,58 +70,11 @@ The PackageManagerManager is the central component that manages marketplace data - Handling repository caching - Coordinating with GitFetcher - Applying filters and sorting -- Managing package sources +- Managing registry sources ### Implementation Details -```typescript -class PackageManagerManager { - private currentItems: PackageManagerItem[] = [] - private cache: Map - private gitFetcher: GitFetcher - private activeSourceOperations = new Set() - private isMetadataScanActive = false - private pendingOperations: Array<() => Promise> = [] - - /** - * Queue an operation to run when no metadata scan is active - */ - private async queueOperation(operation: () => Promise): Promise { - // Implementation details - } - - /** - * Get marketplace items from sources - */ - public async getPackageManagerItems( - sources: PackageManagerSource[], - ): Promise<{ items: PackageManagerItem[]; errors?: string[] }> { - // Implementation details - } - - /** - * Filter items based on criteria - */ - public filterItems( - items: PackageManagerItem[], - filters: { type?: ComponentType; search?: string; tags?: string[] }, - ): PackageManagerItem[] { - // Implementation details - } - - /** - * Sort items by field - */ - public sortItems( - items: PackageManagerItem[], - sortBy: keyof Pick, - sortOrder: "asc" | "desc", - sortSubcomponents: boolean = false, - ): PackageManagerItem[] { - // Implementation details - } -} -``` +[/src/services/marketplace/MarketplaceManager.ts](/src/services/marketplace/MarketplaceManager.ts) ### Key Algorithms @@ -225,7 +110,7 @@ The filtering system provides rich functionality: - Filter parent items - Filter subcomponents - - Handle package-specific logic + - Handle item-specific logic - Track match information 2. **Match Information**: @@ -234,9 +119,9 @@ The filtering system provides rich functionality: - Support highlighting - Maintain match context -## PackageManagerSourceValidation +## MarketplaceValidation -The PackageManagerSourceValidation component handles validation of marketplace sources and their configurations. +The MarketplaceValidation component handles validation of marketplace sources and their configurations. ### Responsibilities @@ -248,40 +133,7 @@ The PackageManagerSourceValidation component handles validation of marketplace s ### Implementation Details -```typescript -export class PackageManagerSourceValidation { - /** - * Validates a marketplace source URL - */ - public static validateSourceUrl(url: string): ValidationError[] { - // Implementation details - } - - /** - * Validates a marketplace source name - */ - public static validateSourceName(name?: string): ValidationError[] { - // Implementation details - } - - /** - * Validates sources for duplicates - */ - public static validateSourceDuplicates( - sources: PackageManagerSource[], - newSource?: PackageManagerSource, - ): ValidationError[] { - // Implementation details - } - - /** - * Checks if a URL is a valid Git repository URL - */ - private static isValidGitRepositoryUrl(url: string): boolean { - // Implementation details - } -} -``` +[/src/shared/MarketplaceValidation.ts](/src/shared/MarketplaceValidation.ts) ### Key Algorithms @@ -309,9 +161,9 @@ The URL validation system supports: - Optional .git suffix - Subpath support -## PackageManagerViewStateManager +## MarketplaceViewStateManager -The PackageManagerViewStateManager manages frontend state and synchronization with the backend. +The MarketplaceViewStateManager manages frontend state and synchronization with the backend. ### Responsibilities @@ -325,42 +177,7 @@ The PackageManagerViewStateManager manages frontend state and synchronization wi ### Implementation Details -```typescript -class PackageManagerViewStateManager { - private state: ViewState - private stateChangeHandlers: Set - private fetchTimeoutId?: NodeJS.Timeout - private sourcesModified: boolean - - /** - * Initialize state manager - */ - public initialize(): void { - // Implementation details - } - - /** - * Subscribe to state changes - */ - public onStateChange(handler: StateChangeHandler): () => void { - // Implementation details - } - - /** - * Process state transitions - */ - public async transition(transition: ViewStateTransition): Promise { - // Implementation details - } - - /** - * Handle incoming messages - */ - public async handleMessage(message: any): Promise { - // Implementation details - } -} -``` +[/webview-ui/src/components/marketplace/MarketplaceViewStateManager.ts](/webview-ui/src/components/marketplace/MarketplaceViewStateManager.ts) ## Component Integration @@ -370,15 +187,15 @@ The components work together through well-defined interfaces: 1. **Repository Operations**: - - PackageManagerManager validates sources with PackageManagerSourceValidation - - PackageManagerManager coordinates with GitFetcher + - MarketplaceManager validates sources with MarketplaceValidation + - MarketplaceManager coordinates with GitFetcher - GitFetcher manages repository state - MetadataScanner processes repository content - - Results flow back to PackageManagerManager + - Results flow back to MarketplaceManager 2. **State Management**: - - PackageManagerManager maintains backend state + - MarketplaceManager maintains backend state - ViewStateManager handles UI state transitions - ViewStateManager processes messages - State changes notify subscribers diff --git a/cline_docs/marketplace/implementation/03-data-structures.md b/cline_docs/marketplace/implementation/03-data-structures.md index 8e103e6ddf..f1db63a498 100644 --- a/cline_docs/marketplace/implementation/03-data-structures.md +++ b/cline_docs/marketplace/implementation/03-data-structures.md @@ -2,37 +2,32 @@ This document details the key data structures used in the Marketplace, including their definitions, relationships, and usage patterns. -## Package and Component Types +## Item Types -The Marketplace uses a type system to categorize different kinds of components: +The Marketplace uses a type system to categorize different kinds of items: -### ComponentType Enumeration +### MarketplaceItemType Enumeration -```typescript -/** - * Supported component types - */ -export type ComponentType = "mode" | "prompt" | "package" | "mcp server" -``` +[/src/services/marketplace/types.ts](/src/services/marketplace/types.ts) These types represent the different kinds of components that can be managed by the Marketplace: 1. **mode**: AI assistant personalities with specialized capabilities 2. **prompt**: Pre-configured instructions for specific tasks -3. **package**: Collections of related components -4. **mcp server**: Model Context Protocol servers that provide additional functionality +3. **mcp**: Model Context Protocol servers that provide additional functionality +4. **package**: Collections of items (multiple modes, mcps,..., like `roo-commander`) ## Core Data Structures -### PackageManagerRepository +### MarketplaceRepository ```typescript /** * Represents a repository with its metadata and items */ -export interface PackageManagerRepository { +export interface MarketplaceRepository { metadata: RepositoryMetadata - items: PackageManagerItem[] + items: MarketplaceItem[] url: string defaultBranch: string error?: string @@ -47,35 +42,9 @@ This interface represents a complete repository: - **defaultBranch**: The default Git branch (e.g., "main") - **error**: Optional error message if there was a problem -### PackageManagerItem +### MarketplaceItem -```typescript -/** - * Represents an individual marketplace item - */ -export interface PackageManagerItem { - name: string - description: string - type: ComponentType - url: string - repoUrl: string - sourceName?: string - author?: string - tags?: string[] - version?: string - lastUpdated?: string - sourceUrl?: string - defaultBranch?: string - items?: { - type: ComponentType - path: string - metadata?: ComponentMetadata - lastUpdated?: string - matchInfo?: MatchInfo - }[] - matchInfo?: MatchInfo -} -``` +[/src/services/marketplace/types.ts](/src/services/marketplace/types.ts) Key changes: @@ -85,21 +54,7 @@ Key changes: ### MatchInfo -```typescript -/** - * Information about why an item matched search/filter criteria - */ -export interface MatchInfo { - matched: boolean - matchReason?: { - nameMatch?: boolean - descriptionMatch?: boolean - typeMatch?: boolean - tagMatch?: boolean - hasMatchingSubcomponents?: boolean - } -} -``` +[/src/services/marketplace/types.ts](/src/services/marketplace/types.ts) Enhanced match tracking: @@ -111,15 +66,7 @@ Enhanced match tracking: ### ValidationError -```typescript -/** - * Error type for marketplace source validation - */ -export interface ValidationError { - field: string - message: string -} -``` +[/src/shared/MarketplaceValidation.ts](/src/shared/MarketplaceValidation.ts) Used for structured validation errors: @@ -128,24 +75,7 @@ Used for structured validation errors: ### ViewState -```typescript -/** - * View-level state management - */ -interface ViewState { - allItems: PackageManagerItem[] - displayItems?: PackageManagerItem[] - isFetching: boolean - activeTab: "browse" | "sources" - refreshingUrls: string[] - sources: PackageManagerSource[] - filters: Filters - sortConfig: { - by: "name" | "author" | "lastUpdated" - order: "asc" | "desc" - } -} -``` +[/webview-ui/src/components/marketplace/MarketplaceViewStateManager.ts](/webview-ui/src/components/marketplace/MarketplaceViewStateManager.ts) Manages UI state: @@ -160,31 +90,7 @@ Manages UI state: ### ViewStateTransition -```typescript -/** - * State transition types and payloads - */ -type ViewStateTransition = { - type: - | "FETCH_ITEMS" - | "FETCH_COMPLETE" - | "FETCH_ERROR" - | "SET_ACTIVE_TAB" - | "UPDATE_FILTERS" - | "UPDATE_SORT" - | "REFRESH_SOURCE" - | "REFRESH_SOURCE_COMPLETE" - | "UPDATE_SOURCES" - payload?: { - items?: PackageManagerItem[] - tab?: "browse" | "sources" - filters?: Partial - sortConfig?: Partial - url?: string - sources?: PackageManagerSource[] - } -} -``` +[/webview-ui/src/components/marketplace/MarketplaceViewStateManager.ts](/webview-ui/src/components/marketplace/MarketplaceViewStateManager.ts) Defines state transitions: @@ -194,16 +100,7 @@ Defines state transitions: ### Filters -```typescript -/** - * Filter criteria - */ -interface Filters { - type: string - search: string - tags: string[] -} -``` +[/webview-ui/src/components/marketplace/MarketplaceViewStateManager.ts](/webview-ui/src/components/marketplace/MarketplaceViewStateManager.ts) Enhanced filtering: @@ -215,17 +112,7 @@ Enhanced filtering: ### BaseMetadata -```typescript -/** - * Base metadata interface - */ -export interface BaseMetadata { - name: string - description: string - version: string - tags?: string[] -} -``` +[/src/services/marketplace/types.ts](/src/services/marketplace/types.ts) Common metadata properties: @@ -236,211 +123,39 @@ Common metadata properties: ### ComponentMetadata -```typescript -/** - * Component metadata with type - */ -export interface ComponentMetadata extends BaseMetadata { - type: ComponentType - lastUpdated?: string -} -``` +[/src/services/marketplace/types.ts](/src/services/marketplace/types.ts) Added: -- **lastUpdated** field for tracking changes +- **type** field for item component type ### PackageMetadata -```typescript -/** - * Package metadata with subcomponents - */ -export interface PackageMetadata extends ComponentMetadata { - type: "package" - items?: { - type: ComponentType - path: string - metadata?: ComponentMetadata - lastUpdated?: string - }[] -} -``` +[/src/services/marketplace/types.ts](/src/services/marketplace/types.ts) Enhanced with: - Subcomponent tracking -- Last update timestamps ## Source Management -### PackageManagerSource +### MarketplaceSource -```typescript -/** - * Git repository source - */ -export interface PackageManagerSource { - url: string - name?: string - enabled: boolean -} -``` - -Repository source configuration: - -- **url**: Git repository URL -- **name**: Optional display name -- **enabled**: Source status - -### SourceOperation - -```typescript -/** - * Source operation tracking - */ -interface SourceOperation { - url: string - type: "clone" | "pull" | "refresh" - timestamp: number -} -``` - -Tracks repository operations: - -- Operation type -- Timestamp -- Source URL - -## Cache Management - -### CacheEntry - -```typescript -/** - * Cache entry structure - */ -interface CacheEntry { - data: T - timestamp: number -} -``` - -Generic cache structure: - -- Cached data -- Timestamp for expiry - -### RepositoryCache - -```typescript -/** - * Repository cache management - */ -type RepositoryCache = Map> -``` - -Specialized for repositories: - -- URL-based lookup -- Timestamp-based expiry -- Full repository data +[/src/services/marketplace/types.ts](/src/services/marketplace/types.ts) ## Message Structures -### Input Messages - -```typescript -type PackageManagerMessage = - | { type: "getItems" } - | { - type: "search" - search: string - typeFilter: string - tagFilters: string[] - } - | { - type: "addSource" - url: string - name?: string - } - | { - type: "removeSource" - url: string - } - | { type: "refreshSources" } -``` - -### Output Messages - -```typescript -type PackageManagerResponse = - | { - type: "items" - data: PackageManagerItem[] - } - | { - type: "searchResults" - data: PackageManagerItem[] - filters: Filters - } - | { - type: "sourceAdded" | "sourceRemoved" - data: { success: boolean } - } - | { - type: "error" - error: string - } -``` - -Enhanced with: - -- Filter state in search results -- Operation success tracking -- Detailed error reporting +> TBA ## Data Validation ### Metadata Validation -```typescript -/** - * Validate component metadata - */ -function validateMetadata(metadata: unknown): metadata is ComponentMetadata { - if (!isObject(metadata)) return false - - return ( - typeof metadata.name === "string" && - typeof metadata.description === "string" && - typeof metadata.version === "string" && - (metadata.tags === undefined || Array.isArray(metadata.tags)) && - isValidComponentType(metadata.type) - ) -} -``` +[/src/services/marketplace/schemas.ts](/src/services/marketplace/schemas.ts) ### URL Validation -```typescript -/** - * Validate Git repository URL - */ -function isValidGitRepositoryUrl(url: string): boolean { - // HTTPS pattern (any domain) - const httpsPattern = - /^https?:\/\/[a-zA-Z0-9_.-]+(\.[a-zA-Z0-9_.-]+)*\/[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+(\/.+)*(\.git)?$/ - - // SSH pattern (any domain) - const sshPattern = /^git@[a-zA-Z0-9_.-]+(\.[a-zA-Z0-9_.-]+)*:([a-zA-Z0-9_.-]+)\/([a-zA-Z0-9_.-]+)(\.git)?$/ - - // Git protocol pattern (any domain) - const gitProtocolPattern = /^git:\/\/[a-zA-Z0-9_.-]+(\.[a-zA-Z0-9_.-]+)*\/[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+(\.git)?$/ - - return httpsPattern.test(url) || sshPattern.test(url) || gitProtocolPattern.test(url) -} -``` +[/src/shared/MarketplaceValidation.ts](/src/shared/MarketplaceValidation.ts) Supports: @@ -481,15 +196,15 @@ Repository └── Items ├── Package │ ├── Mode - │ ├── MCP Server + │ ├── MCP │ └── Prompt - └── Standalone Components + └── Standalone Components (Modes, MCP, Prompts) ``` ### State Flow ``` -Git Repository → Cache → PackageManager → ViewState → UI +Git Repository → Cache → Marketplace → ViewState → UI ``` ### Filter Chain diff --git a/cline_docs/marketplace/implementation/04-search-and-filter.md b/cline_docs/marketplace/implementation/04-search-and-filter.md index d6c9bf3cf2..9d06976eee 100644 --- a/cline_docs/marketplace/implementation/04-search-and-filter.md +++ b/cline_docs/marketplace/implementation/04-search-and-filter.md @@ -8,271 +8,25 @@ The Marketplace implements a comprehensive filtering system that handles multipl ### Filter Implementation -```typescript -/** - * Filter items based on criteria with match tracking - */ -export function filterItems( - items: PackageManagerItem[], - filters: { - type?: ComponentType - search?: string - tags?: string[] - }, -): PackageManagerItem[] { - // Helper function to normalize text for case-insensitive comparison - const normalizeText = (text: string) => text.toLowerCase().replace(/\s+/g, " ").trim() - - // Normalize search term once - const searchTerm = filters.search ? normalizeText(filters.search) : "" - - // Create a deep clone of items - const clonedItems = items.map((item) => JSON.parse(JSON.stringify(item)) as PackageManagerItem) - - return clonedItems - .filter((item) => { - // Check parent item matches - const itemMatches = { - type: !filters.type || item.type === filters.type, - search: - !searchTerm || - containsSearchTerm(item.name, searchTerm) || - containsSearchTerm(item.description, searchTerm), - tags: !filters.tags?.length || (item.tags && filters.tags.some((tag) => item.tags!.includes(tag))), - } - - // Check subcomponent matches - const subcomponentMatches = - item.items?.some((subItem) => { - const subMatches = { - type: !filters.type || subItem.type === filters.type, - search: - !searchTerm || - (subItem.metadata && - (containsSearchTerm(subItem.metadata.name, searchTerm) || - containsSearchTerm(subItem.metadata.description, searchTerm))), - tags: - !filters.tags?.length || - (subItem.metadata?.tags && - filters.tags.some((tag) => subItem.metadata!.tags!.includes(tag))), - } - - return ( - subMatches.type && - (!searchTerm || subMatches.search) && - (!filters.tags?.length || subMatches.tags) - ) - }) ?? false - - // Include item if either parent matches or has matching subcomponents - const hasActiveFilters = filters.type || searchTerm || filters.tags?.length - if (!hasActiveFilters) return true - - const parentMatchesAll = itemMatches.type && itemMatches.search && itemMatches.tags - const isPackageWithMatchingSubcomponent = item.type === "package" && subcomponentMatches - - return parentMatchesAll || isPackageWithMatchingSubcomponent - }) - .map((item) => addMatchInfo(item, filters)) -} -``` - -### Match Tracking - -The system tracks detailed match information: - -```typescript -/** - * Add match information to items - */ -function addMatchInfo(item: PackageManagerItem, filters: Filters): PackageManagerItem { - const matchReason: Record = { - nameMatch: filters.search ? containsSearchTerm(item.name, filters.search) : true, - descriptionMatch: filters.search ? containsSearchTerm(item.description, filters.search) : true, - typeMatch: filters.type ? item.type === filters.type : true, - tagMatch: filters.tags?.length ? hasMatchingTags(item.tags, filters.tags) : true, - } - - // Process subcomponents - if (item.items) { - item.items = item.items.map((subItem) => { - const subMatches = { - type: !filters.type || subItem.type === filters.type, - search: - !filters.search || - (subItem.metadata && - (containsSearchTerm(subItem.metadata.name, filters.search) || - containsSearchTerm(subItem.metadata.description, filters.search))), - tags: - !filters.tags?.length || - (subItem.metadata?.tags && filters.tags.some((tag) => subItem.metadata!.tags!.includes(tag))), - } - - subItem.matchInfo = { - matched: subMatches.type && subMatches.search && subMatches.tags, - matchReason: { - typeMatch: subMatches.type, - nameMatch: subMatches.search, - tagMatch: subMatches.tags, - }, - } - - return subItem - }) - } - - return { - ...item, - matchInfo: { - matched: Object.values(matchReason).every(Boolean), - matchReason, - }, - } -} -``` +[/src/services/marketplace/MarketplaceManager.ts](/src/services/marketplace/MarketplaceManager.ts) ## Sort System The Marketplace implements flexible sorting with subcomponent support: -```typescript -/** - * Sort items with subcomponent support - */ -export function sortItems( - items: PackageManagerItem[], - sortBy: "name" | "lastUpdated" | "author", - sortOrder: "asc" | "desc", - sortSubcomponents: boolean = false, -): PackageManagerItem[] { - return [...items] - .map((item) => { - const clonedItem = { ...item } - - if (clonedItem.items && sortSubcomponents) { - clonedItem.items = [...clonedItem.items].sort((a, b) => { - const aValue = getSortValue(a, sortBy) - const bValue = getSortValue(b, sortBy) - return compareValues(aValue, bValue, sortOrder) - }) - } - - return clonedItem - }) - .sort((a, b) => { - const aValue = getSortValue(a, sortBy) - const bValue = getSortValue(b, sortBy) - return compareValues(aValue, bValue, sortOrder) - }) -} -``` +[/src/services/marketplace/MarketplaceManager.ts](/src/services/marketplace/MarketplaceManager.ts) ## State Management Integration The filtering system integrates with the state management through state transitions: -```typescript -export class PackageManagerViewStateManager { - private state: ViewState - private stateChangeHandlers: Set - - /** - * Process state transitions - */ - public async transition(transition: ViewStateTransition): Promise { - switch (transition.type) { - case "UPDATE_FILTERS": { - const { filters = {} } = transition.payload || {} - - // Update filters while preserving existing ones - const updatedFilters = { - type: filters.type ?? this.state.filters.type, - search: filters.search ?? this.state.filters.search, - tags: filters.tags ?? this.state.filters.tags, - } - - // Update state - this.state = { - ...this.state, - filters: updatedFilters, - } - - // Notify subscribers - this.notifyStateChange() - - // Request filtered items from backend - vscode.postMessage({ - type: "filterPackageManagerItems", - filters: updatedFilters, - }) - break - } - - case "FETCH_COMPLETE": { - const { items } = transition.payload as { items: PackageManagerItem[] } - - // Update both all items and display items - this.state = { - ...this.state, - allItems: items, - displayItems: items, - isFetching: false, - } - - this.notifyStateChange() - break - } - } - } - - /** - * Subscribe to state changes - */ - public onStateChange(handler: StateChangeHandler): () => void { - this.stateChangeHandlers.add(handler) - return () => this.stateChangeHandlers.delete(handler) - } -} -``` - -```` +[/webview-ui/src/components/marketplace/MarketplaceViewStateManager.ts](/webview-ui/src/components/marketplace/MarketplaceViewStateManager.ts) ## Performance Optimizations ### Concurrent Operation Handling -```typescript -export class PackageManagerManager { - private isMetadataScanActive = false - private pendingOperations: Array<() => Promise> = [] - - /** - * Queue filter operations during active scans - */ - private async queueOperation(operation: () => Promise): Promise { - if (this.isMetadataScanActive) { - return new Promise((resolve) => { - this.pendingOperations.push(async () => { - await operation() - resolve() - }) - }) - } - - try { - this.isMetadataScanActive = true - await operation() - } finally { - this.isMetadataScanActive = false - - const nextOperation = this.pendingOperations.shift() - if (nextOperation) { - void this.queueOperation(nextOperation) - } - } - } -} -```` +[/src/services/marketplace/MarketplaceManager.ts](/src/services/marketplace/MarketplaceManager.ts) ### Filter Optimizations @@ -307,7 +61,7 @@ describe("Filter System", () => { }) it("should track subcomponent matches", () => { - const result = filterItems([testPackage], { search: "test" }) + const result = filterItems([testPack], { search: "test" }) const subItem = result[0].items![0] expect(subItem.matchInfo.matched).toBe(true) }) @@ -315,7 +69,7 @@ describe("Filter System", () => { describe("Sort System", () => { it("should sort subcomponents", () => { - const result = sortItems([testPackage], "name", "asc", true) + const result = sortItems([testPack], "name", "asc", true) expect(result[0].items).toBeSorted((a, b) => a.metadata.name.localeCompare(b.metadata.name)) }) }) diff --git a/cline_docs/marketplace/implementation/05-ui-components.md b/cline_docs/marketplace/implementation/05-ui-components.md index fad89ae3f0..435c2f77ce 100644 --- a/cline_docs/marketplace/implementation/05-ui-components.md +++ b/cline_docs/marketplace/implementation/05-ui-components.md @@ -2,92 +2,17 @@ This document details the design and implementation of the Marketplace's UI components, including their structure, styling, interactions, and accessibility features. -## PackageManagerView +## MarketplaceView -The PackageManagerView is the main container component that manages the overall marketplace interface. +The MarketplaceView is the main container component that manages the overall marketplace interface. ### Component Structure -```tsx -const PackageManagerView: React.FC = ({ onDone }) => { - const [state, manager] = useStateManager() - const [tagSearch, setTagSearch] = useState("") - const [isTagInputActive, setIsTagInputActive] = useState(false) - - // Fetch items on mount - useEffect(() => { - manager.transition({ type: "FETCH_ITEMS" }) - }, [manager]) - - return ( - - -
-

Marketplace

-
- - -
-
-
- - - {state.activeTab === "browse" ? ( - - manager.transition({ - type: "UPDATE_FILTERS", - payload: { filters }, - }) - } - /> - ) : ( - - manager.transition({ - type: "REFRESH_SOURCE", - payload: { url }, - }) - } - onSourcesChange={(sources) => - manager.transition({ - type: "UPDATE_SOURCES", - payload: { sources }, - }) - } - /> - )} - -
- ) -} -``` +[/webview-ui/src/components/marketplace/MarketplaceView.tsx](/webview-ui/src/components/marketplace/MarketplaceView.tsx) ### State Management Integration -The component uses the PackageManagerViewStateManager through the useStateManager hook: +The component uses the MarketplaceViewStateManager through the useStateManager hook: ```tsx const [state, manager] = useStateManager() @@ -101,200 +26,13 @@ Key features: - Manages loading states - Handles source validation -## PackageManagerItemCard +## MarketplaceItemCard -The PackageManagerItemCard is the primary component for displaying package information in the UI. +The MarketplaceItemCard is the primary component for displaying item information in the UI. ### Component Structure -```tsx -export const PackageManagerItemCard: React.FC = ({ - item, - filters, - setFilters, - activeTab, - setActiveTab, -}) => { - // URL validation helper - const isValidUrl = (urlString: string): boolean => { - try { - new URL(urlString) - return true - } catch (e) { - return false - } - } - - // Type label and color helpers - const getTypeLabel = (type: string) => { - switch (type) { - case "mode": - return "Mode" - case "mcp server": - return "MCP Server" - case "prompt": - return "Prompt" - case "package": - return "Package" - default: - return "Other" - } - } - - const getTypeColor = (type: string) => { - switch (type) { - case "mode": - return "bg-blue-600" - case "mcp server": - return "bg-green-600" - case "prompt": - return "bg-purple-600" - case "package": - return "bg-orange-600" - default: - return "bg-gray-600" - } - } - - // URL opening handler - const handleOpenUrl = () => { - const urlToOpen = item.sourceUrl && isValidUrl(item.sourceUrl) ? item.sourceUrl : item.repoUrl - vscode.postMessage({ - type: "openExternal", - url: urlToOpen, - }) - } - - // Group items by type - const groupedItems = useMemo(() => { - if (!item.items?.length) { - return null - } - return groupItemsByType(item.items) - }, [item.items]) as GroupedItems | null - - return ( -
- {/* Header section with name, author, and type badge */} -
-
-

{item.name}

- {item.author &&

{`by ${item.author}`}

} -
- - {getTypeLabel(item.type)} - -
- - {/* Description */} -

{item.description}

- - {/* Tags section */} - {item.tags && item.tags.length > 0 && ( -
- {item.tags.map((tag) => ( - - ))} -
- )} - - {/* Footer section with metadata and action button */} -
-
- {item.version && ( - - - {item.version} - - )} - {item.lastUpdated && ( - - - {new Date(item.lastUpdated).toLocaleDateString(undefined, { - year: "numeric", - month: "short", - day: "numeric", - })} - - )} -
- - -
- - {/* Details section with subcomponents */} - {groupedItems && ( - { - const matchCount = - item.items?.filter( - (subItem) => - (subItem.metadata?.name || "") - .toLowerCase() - .includes(filters.search.toLowerCase()) || - (subItem.metadata?.description || "") - .toLowerCase() - .includes(filters.search.toLowerCase()), - ).length || 0 - return matchCount > 0 - ? `${matchCount} match${matchCount !== 1 ? "es" : ""}` - : undefined - })() - : undefined - } - defaultExpanded={ - !!filters.search && - (item.items?.some( - (subItem) => - (subItem.metadata?.name || "").toLowerCase().includes(filters.search.toLowerCase()) || - (subItem.metadata?.description || "") - .toLowerCase() - .includes(filters.search.toLowerCase()), - ) || - false) - }> -
- {Object.entries(groupedItems).map(([type, group]) => ( - - ))} -
-
- )} -
- ) -} -``` +[/webview-ui/src/components/marketplace/components/MarketplaceItemCard.tsx](/webview-ui/src/components/marketplace/components/MarketplaceItemCard.tsx) ### Design Considerations @@ -327,56 +65,7 @@ The ExpandableSection component provides a collapsible container for content tha ### Component Structure -```tsx -export const ExpandableSection: React.FC = ({ - title, - children, - className, - defaultExpanded = false, - badge, -}) => { - const [isExpanded, setIsExpanded] = useState(defaultExpanded) - - return ( -
- -
-
{children}
-
-
- ) -} -``` +[/webview-ui/src/components/marketplace/components/ExpandableSection.tsx](/webview-ui/src/components/marketplace/components/ExpandableSection.tsx) ### Design Considerations @@ -409,67 +98,7 @@ The TypeGroup component displays a collection of items of the same type, with sp ### Component Structure -```tsx -export const TypeGroup: React.FC = ({ type, items, className, searchTerm }) => { - const getTypeLabel = (type: string) => { - switch (type) { - case "mode": - return "Modes" - case "mcp server": - return "MCP Servers" - case "prompt": - return "Prompts" - case "package": - return "Packages" - default: - return `${type.charAt(0).toUpperCase()}${type.slice(1)}s` - } - } - - if (!items?.length) { - return null - } - - // Check if an item matches the search term - const itemMatchesSearch = (item: { name: string; description?: string }) => { - if (!searchTerm) return false - const term = searchTerm.toLowerCase() - return item.name.toLowerCase().includes(term) || (item.description || "").toLowerCase().includes(term) - } - - return ( -
-

{getTypeLabel(type)}

-
    - {items.map((item, index) => { - const matches = itemMatchesSearch(item) - return ( -
  1. - - {item.name} - - {item.description && ( - - {item.description} - )} - {matches && ( - - match - - )} -
  2. - ) - })} -
-
- ) -} -``` +[/webview-ui/src/components/marketplace/components/TypeGroup.tsx](/webview-ui/src/components/marketplace/components/TypeGroup.tsx) ### Design Considerations @@ -498,300 +127,32 @@ export const TypeGroup: React.FC = ({ type, items, className, se ## Source Configuration Components -The Marketplace includes components for managing package sources. +The Marketplace includes components for managing item sources. -### SourcesView - -```tsx -const SourcesView: React.FC = ({ sources, refreshingUrls, onRefreshSource, onSourcesChange }) => { - const [newSourceUrl, setNewSourceUrl] = useState("") - const [newSourceName, setNewSourceName] = useState("") - const [error, setError] = useState("") - - const handleAddSource = () => { - // Validate source URL and name - const errors = [ - ...validateSourceUrl(newSourceUrl), - ...validateSourceName(newSourceName), - ...validateSourceDuplicates(sources, { - url: newSourceUrl, - name: newSourceName, - enabled: true, - }), - ] - - if (errors.length > 0) { - setError(errors[0].message) - return - } - - // Add new source - onSourcesChange([ - ...sources, - { - url: newSourceUrl, - name: newSourceName || undefined, - enabled: true, - }, - ]) - - // Clear form - setNewSourceUrl("") - setNewSourceName("") - setError("") - } - - return ( -
-

Configure Marketplace Sources

-

Add Git repositories containing marketplace items.

- - {/* Source form */} -
- setNewSourceUrl(e.target.value)} - /> - setNewSourceName(e.target.value)} - /> - {error &&

{error}

} - -
- - {/* Source list */} -
- {sources.map((source) => ( - onRefreshSource(source.url)} - onToggle={() => { - const updatedSources = sources.map((s) => - s.url === source.url ? { ...s, enabled: !s.enabled } : s, - ) - onSourcesChange(updatedSources) - }} - onRemove={() => { - const updatedSources = sources.filter((s) => s.url !== source.url) - onSourcesChange(updatedSources) - }} - /> - ))} -
-
- ) -} -``` +[/webview-ui/src/components/marketplace/MarketplaceView.tsx](/webview-ui/src/components/marketplace/MarketplaceView.tsx) ## Filter Components The Marketplace includes components for filtering and searching. -### SearchInput - -```tsx -const SearchInput: React.FC<{ - value: string - onChange: (value: string) => void -}> = ({ value, onChange }) => { - // Debounce search input to avoid excessive filtering - const debouncedOnChange = useDebounce(onChange, 300) - - return ( -
- - debouncedOnChange(e.target.value)} - placeholder="Search packages..." - className="search-input" - aria-label="Search packages" - /> - {value && ( - - )} -
- ) -} -``` +[/webview-ui/src/components/marketplace/MarketplaceView.tsx](/webview-ui/src/components/marketplace/MarketplaceView.tsx) ### TypeFilterGroup -```tsx -const TypeFilterGroup: React.FC<{ - selectedType: string - onChange: (type: string) => void - availableTypes: string[] -}> = ({ selectedType, onChange, availableTypes }) => { - return ( -
-

Filter by Type

-
- - - {availableTypes.map((type) => ( - - ))} -
-
- ) -} -``` +[/webview-ui/src/components/marketplace/MarketplaceView.tsx](/webview-ui/src/components/marketplace/MarketplaceView.tsx) ### TagFilterGroup -```tsx -const TagFilterGroup: React.FC<{ - selectedTags: string[] - onChange: (tags: string[]) => void - availableTags: string[] -}> = ({ selectedTags, onChange, availableTags }) => { - const toggleTag = (tag: string) => { - if (selectedTags.includes(tag)) { - onChange(selectedTags.filter((t) => t !== tag)) - } else { - onChange([...selectedTags, tag]) - } - } - - return ( -
-

Filter by Tags

-
- {availableTags.map((tag) => ( - - ))} -
-
- ) -} -``` +[/webview-ui/src/components/marketplace/MarketplaceView.tsx](/webview-ui/src/components/marketplace/MarketplaceView.tsx) ## Styling Approach The Marketplace UI uses a combination of Tailwind CSS and VSCode theme variables for styling. -### VSCode Theme Integration - -The components use VSCode theme variables to ensure they match the user's selected theme: - -```css -/* Example of VSCode theme variable usage */ -.package-card { - background-color: var(--vscode-panel-background); - border-color: var(--vscode-panel-border); - color: var(--vscode-foreground); -} - -.package-description { - color: var(--vscode-descriptionForeground); -} - -.package-link { - color: var(--vscode-textLink-foreground); -} - -.package-link:hover { - color: var(--vscode-textLink-activeForeground); -} -``` - -### Tailwind CSS Usage - -Tailwind CSS is used for utility-based styling: - -```tsx -// Example of Tailwind CSS usage -
-

{item.name}

- {getTypeLabel(item.type)} -
-``` - -### Custom Utility Functions - -The UI uses utility functions for class name composition: - -```typescript -// cn utility for conditional class names -import { clsx, type ClassValue } from "clsx" -import { twMerge } from "tailwind-merge" - -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) -} -``` - ## Responsive Design The Marketplace UI is designed to work across different viewport sizes: -### Layout Adjustments - -```tsx -// Example of responsive layout -
- {items.map((item) => ( - - ))} -
-``` - -### Mobile Considerations - -For smaller screens: - -1. **Stacked Layout**: - - - Cards stack vertically on small screens - - Filter panel collapses to a dropdown - - Full-width elements for better touch targets - -2. **Touch Optimization**: - - - Larger touch targets for mobile users - - Swipe gestures for common actions - - Simplified interactions for touch devices - -3. **Content Prioritization**: - - Critical information shown first - - Less important details hidden behind expandable sections - - Reduced information density on small screens - ## Accessibility Features The Marketplace UI includes several accessibility features: @@ -820,7 +181,7 @@ The Marketplace UI includes several accessibility features: ```tsx // Example of screen reader support -
+
@@ -889,7 +250,7 @@ The Marketplace UI uses subtle animations to enhance the user experience: // Example of loading state animation
- Loading packages... + Loading items...
``` @@ -906,7 +267,7 @@ const ErrorDisplay: React.FC<{ error: string; retry: () => void }> = ({ error, r
-

Error loading packages

+

Error loading items

{error}