update documentation

This commit is contained in:
Smartsheet-JB-Brown 2025-04-16 19:28:39 -07:00
parent 9a24ed46a2
commit 6e299c73f5
6 changed files with 537 additions and 58 deletions

View file

@ -13,6 +13,7 @@ graph TD
User[User] -->|Interacts with| UI[Package Manager UI]
UI -->|Sends messages| MH[Message Handler]
MH -->|Processes requests| PM[PackageManagerManager]
PM -->|Validates sources| PSV[PackageManagerSourceValidation]
PM -->|Fetches repos| GF[GitFetcher]
GF -->|Scans metadata| MS[MetadataScanner]
MS -->|Reads| FS[File System / Git Repositories]
@ -171,6 +172,16 @@ classDiagram
+sortItems(sortBy, order): PackageManagerItem[]
+refreshRepository(url): void
-queueOperation(operation): void
-validateSources(sources): ValidationError[]
}
class PackageManagerSourceValidation {
+validateSourceUrl(url): ValidationError[]
+validateSourceName(name): ValidationError[]
+validateSourceDuplicates(sources): ValidationError[]
+validateSource(source): ValidationError[]
+validateSources(sources): ValidationError[]
-isValidGitRepositoryUrl(url): boolean
}
class GitFetcher {
@ -190,16 +201,25 @@ classDiagram
}
class PackageManagerViewStateManager {
-items: PackageManagerItem[]
-filters: Filters
-sortBy: string
-sortOrder: string
+setFilters(filters): void
+getFilteredAndSortedItems(): PackageManagerItem[]
-itemMatchesFilters(item): boolean
-state: ViewState
-stateChangeHandlers: Set
-fetchTimeoutId: NodeJS.Timeout
-sourcesModified: boolean
+initialize(): void
+onStateChange(handler): () => void
+cleanup(): void
+getState(): ViewState
+transition(transition): Promise<void>
-notifyStateChange(): void
-clearFetchTimeout(): void
-isFilterActive(): boolean
-filterItems(items): PackageManagerItem[]
-sortItems(items): PackageManagerItem[]
+handleMessage(message): Promise<void>
}
PackageManagerManager --> GitFetcher: uses
PackageManagerManager --> PackageManagerSourceValidation: uses
GitFetcher --> MetadataScanner: uses
PackageManagerManager --> PackageManagerViewStateManager: updates
```
@ -239,26 +259,37 @@ classDiagram
1. **PackageManagerViewStateManager**
- Manages view-level state
- Handles filtering and sorting
- Maintains UI preferences
- Manages frontend state and backend synchronization
- Handles state transitions and message processing
- Manages filtering, sorting, and view preferences
- Coordinates with backend state
- Handles timeout protection for operations
- Manages source modification tracking
- Provides state change subscriptions
2. **PackageManagerItemCard**
2. **PackageManagerSourceValidation**
- Validates Git repository URLs for any domain
- Validates source names and configurations
- Detects duplicate sources (case-insensitive)
- Provides structured validation errors
- Supports multiple Git protocols (HTTPS, SSH, Git)
3. **PackageManagerItemCard**
- Displays package information
- Handles tag interactions
- Manages expandable sections
- Shows match highlights
3. **ExpandableSection**
4. **ExpandableSection**
- Provides collapsible sections
- Manages expand/collapse state
- Handles animations
- Shows section metadata
4. **TypeGroup**
5. **TypeGroup**
- Groups items by type
- Formats item lists
- Highlights search matches

View file

@ -234,37 +234,129 @@ The filtering system provides rich functionality:
- Support highlighting
- Maintain match context
## PackageManagerViewStateManager
## PackageManagerSourceValidation
The PackageManagerViewStateManager handles UI state and view-level operations.
The PackageManagerSourceValidation component handles validation of package manager sources and their configurations.
### Responsibilities
- Managing view-level state
- Handling UI filters
- Coordinating sorting
- Managing item visibility
- Validating Git repository URLs for any domain
- Validating source names and configurations
- Detecting duplicate sources
- Providing structured validation errors
- Supporting multiple Git protocols
### Implementation Details
```typescript
export class PackageManagerSourceValidation {
/**
* Validates a package manager source URL
*/
public static validateSourceUrl(url: string): ValidationError[] {
// Implementation details
}
/**
* Validates a package manager 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
}
}
```
### Key Algorithms
#### URL Validation
The URL validation system supports:
1. **Protocol Validation**:
- HTTPS URLs
- SSH URLs
- Git protocol URLs
- Custom domains and ports
2. **Domain Validation**:
- Any valid domain name
- IP addresses
- Localhost for testing
- Internal company domains
3. **Path Validation**:
- Username/organization
- Repository name
- Optional .git suffix
- Subpath support
## PackageManagerViewStateManager
The PackageManagerViewStateManager manages frontend state and synchronization with the backend.
### Responsibilities
- Managing frontend state transitions
- Handling message processing
- Managing timeouts and retries
- Coordinating with backend state
- Providing state change subscriptions
- Managing source modification tracking
- Handling filtering and sorting
### Implementation Details
```typescript
class PackageManagerViewStateManager {
private items: PackageManagerItem[] = []
private sortBy: "name" | "lastUpdated" = "name"
private sortOrder: "asc" | "desc" = "asc"
private filters: Filters = { type: "", search: "", tags: [] }
private state: ViewState
private stateChangeHandlers: Set<StateChangeHandler>
private fetchTimeoutId?: NodeJS.Timeout
private sourcesModified: boolean
/**
* Get filtered and sorted items
* Initialize state manager
*/
public getFilteredAndSortedItems(): PackageManagerItem[] {
public initialize(): void {
// Implementation details
}
/**
* Check if item matches current filters
* Subscribe to state changes
*/
private itemMatchesFilters(item: PackageManagerItem | Subcomponent): boolean {
public onStateChange(handler: StateChangeHandler): () => void {
// Implementation details
}
/**
* Process state transitions
*/
public async transition(transition: ViewStateTransition): Promise<void> {
// Implementation details
}
/**
* Handle incoming messages
*/
public async handleMessage(message: any): Promise<void> {
// Implementation details
}
}
@ -278,6 +370,7 @@ The components work together through well-defined interfaces:
1. **Repository Operations**:
- PackageManagerManager validates sources with PackageManagerSourceValidation
- PackageManagerManager coordinates with GitFetcher
- GitFetcher manages repository state
- MetadataScanner processes repository content
@ -286,9 +379,11 @@ The components work together through well-defined interfaces:
2. **State Management**:
- PackageManagerManager maintains backend state
- ViewStateManager handles UI state
- State changes trigger UI updates
- ViewStateManager handles UI state transitions
- ViewStateManager processes messages
- State changes notify subscribers
- Components react to state changes
- Timeout protection ensures responsiveness
3. **User Interactions**:
- UI events trigger state updates

View file

@ -109,6 +109,23 @@ Enhanced match tracking:
## State Management Structures
### ValidationError
```typescript
/**
* Error type for package manager source validation
*/
export interface ValidationError {
field: string
message: string
}
```
Used for structured validation errors:
- **field**: The field that failed validation (e.g., "url", "name")
- **message**: Human-readable error message
### ViewState
```typescript
@ -116,18 +133,64 @@ Enhanced match tracking:
* View-level state management
*/
interface ViewState {
items: PackageManagerItem[]
sortBy: "name" | "lastUpdated"
sortOrder: "asc" | "desc"
allItems: PackageManagerItem[]
displayItems?: PackageManagerItem[]
isFetching: boolean
activeTab: "browse" | "sources"
refreshingUrls: string[]
sources: PackageManagerSource[]
filters: Filters
sortConfig: {
by: "name" | "author" | "lastUpdated"
order: "asc" | "desc"
}
}
```
Manages UI state:
- Current items
- Sort configuration
- Filter state
- **allItems**: All available items
- **displayItems**: Currently filtered/displayed items
- **isFetching**: Loading state indicator
- **activeTab**: Current view tab
- **refreshingUrls**: Sources being refreshed
- **sources**: Package manager sources
- **filters**: Active filters
- **sortConfig**: Sort configuration
### 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<Filters>
sortConfig?: Partial<SortConfig>
url?: string
sources?: PackageManagerSource[]
}
}
```
Defines state transitions:
- Operation types
- Optional payloads
- Type-safe transitions
### Filters
@ -364,14 +427,28 @@ function validateMetadata(metadata: unknown): metadata is ComponentMetadata {
/**
* Validate Git repository URL
*/
function isValidGitUrl(url: string): boolean {
if (!url) return false
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)?$/
// Support common Git URL formats
return /^(https?:\/\/|git@)/.test(url) && /\.git$/.test(url)
// 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)
}
```
Supports:
- Any valid domain name
- Multiple Git protocols
- Optional .git suffix
- Subpath components
## Data Flow
The Package Manager transforms data through several stages:

View file

@ -169,32 +169,74 @@ export function sortItems(
## State Management Integration
The filtering system integrates with the state management:
The filtering system integrates with the state management through state transitions:
```typescript
export class PackageManagerViewStateManager {
private items: PackageManagerItem[] = []
private sortBy: "name" | "lastUpdated" = "name"
private sortOrder: "asc" | "desc" = "asc"
private filters: Filters = { type: "", search: "", tags: [] }
private state: ViewState
private stateChangeHandlers: Set<StateChangeHandler>
/**
* Get filtered and sorted items
* Process state transitions
*/
getFilteredAndSortedItems(): PackageManagerItem[] {
const filtered = filterItems(this.items, this.filters)
return sortItems(filtered, this.sortBy, this.sortOrder)
public async transition(transition: ViewStateTransition): Promise<void> {
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
}
}
}
/**
* Update filters with optimistic updates
* Subscribe to state changes
*/
setFilters(newFilters: Partial<Filters>): void {
this.filters = { ...this.filters, ...newFilters }
public onStateChange(handler: StateChangeHandler): () => void {
this.stateChangeHandlers.add(handler)
return () => this.stateChangeHandlers.delete(handler)
}
}
```
````
## Performance Optimizations
### Concurrent Operation Handling
@ -230,7 +272,7 @@ export class PackageManagerManager {
}
}
}
```
````
### Filter Optimizations
@ -247,9 +289,12 @@ export class PackageManagerManager {
- Avoids regex for simple matches
3. **State Management**:
- Optimistic updates
- Batched filter changes
- Efficient re-renders
- State transitions for predictable updates
- Subscriber pattern for state changes
- Separation of all items and display items
- Backend-driven filtering
- Optimistic UI updates
- Efficient state synchronization
## Testing Strategy
@ -294,9 +339,12 @@ The system includes robust error handling:
- Type mismatches
3. **State Errors**:
- Concurrent updates
- Invalid state transitions
- Cache inconsistencies
- Message handling errors
- State synchronization issues
- Timeout handling
- Source modification tracking
- Filter validation errors
---

View file

@ -2,6 +2,105 @@
This document details the design and implementation of the Package Manager's UI components, including their structure, styling, interactions, and accessibility features.
## PackageManagerView
The PackageManagerView is the main container component that manages the overall package manager interface.
### Component Structure
```tsx
const PackageManagerView: React.FC<PackageManagerViewProps> = ({ 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 (
<Tab>
<TabHeader>
<div className="flex justify-between items-center">
<h3>Package Manager</h3>
<div className="flex gap-2">
<Button
variant={state.activeTab === "browse" ? "default" : "secondary"}
onClick={() =>
manager.transition({
type: "SET_ACTIVE_TAB",
payload: { tab: "browse" },
})
}>
Browse
</Button>
<Button
variant={state.activeTab === "sources" ? "default" : "secondary"}
onClick={() =>
manager.transition({
type: "SET_ACTIVE_TAB",
payload: { tab: "sources" },
})
}>
Sources
</Button>
</div>
</div>
</TabHeader>
<TabContent>
{state.activeTab === "browse" ? (
<BrowseView
items={state.displayItems || []}
filters={state.filters}
onUpdateFilters={(filters) =>
manager.transition({
type: "UPDATE_FILTERS",
payload: { filters },
})
}
/>
) : (
<SourcesView
sources={state.sources}
refreshingUrls={state.refreshingUrls}
onRefreshSource={(url) =>
manager.transition({
type: "REFRESH_SOURCE",
payload: { url },
})
}
onSourcesChange={(sources) =>
manager.transition({
type: "UPDATE_SOURCES",
payload: { sources },
})
}
/>
)}
</TabContent>
</Tab>
)
}
```
### State Management Integration
The component uses the PackageManagerViewStateManager through the useStateManager hook:
```tsx
const [state, manager] = useStateManager()
```
Key features:
- Manages tab state (browse/sources)
- Handles source configuration
- Coordinates filtering and sorting
- Manages loading states
- Handles source validation
## PackageManagerItemCard
The PackageManagerItemCard is the primary component for displaying package information in the UI.
@ -397,9 +496,103 @@ export const TypeGroup: React.FC<TypeGroupProps> = ({ type, items, className, se
- Avoids rendering empty containers
- Prevents unnecessary UI elements
## Source Configuration Components
The Package Manager includes components for managing package sources.
### SourcesView
```tsx
const SourcesView: React.FC<SourcesViewProps> = ({ 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 (
<div>
<h4>Configure Package Manager Sources</h4>
<p>Add Git repositories containing package manager items.</p>
{/* Source form */}
<div>
<input
type="text"
placeholder="Git repository URL"
value={newSourceUrl}
onChange={(e) => setNewSourceUrl(e.target.value)}
/>
<input
type="text"
placeholder="Display name (optional)"
value={newSourceName}
onChange={(e) => setNewSourceName(e.target.value)}
/>
{error && <p className="text-red-500">{error}</p>}
<Button onClick={handleAddSource}>Add Source</Button>
</div>
{/* Source list */}
<div>
{sources.map((source) => (
<SourceItem
key={source.url}
source={source}
isRefreshing={refreshingUrls.includes(source.url)}
onRefresh={() => 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)
}}
/>
))}
</div>
</div>
)
}
```
## Filter Components
The Package Manager includes several components for filtering and searching.
The Package Manager includes components for filtering and searching.
### SearchInput

View file

@ -0,0 +1,35 @@
# Package Manager Implementation
The package manager feature allows users to discover, browse, and manage Git-based package sources containing reusable components like modes, MCP servers, and prompts.
## Core Components
### Backend (VSCode Extension)
- **PackageManagerManager**: Central service that manages package sources, fetching, and caching
- **GitFetcher**: Handles Git operations for cloning and updating repositories
- **MetadataScanner**: Scans repositories for component metadata
- **PackageManagerSourceValidation**: Validates package manager source URLs and configurations
### Frontend (Webview UI)
- **PackageManagerView**: React component for the package manager interface
- **PackageManagerViewStateManager**: Manages frontend state and synchronization with backend
- **useStateManager**: React hook for accessing the state manager
## Key Features
- Git repository integration (HTTPS, SSH, Git protocol)
- Component metadata scanning and validation
- Source configuration management
- Caching and concurrent operation handling
- Component filtering and sorting
- Real-time state synchronization between frontend and backend
## Implementation Details
See the following documentation for detailed implementation information:
- [Architecture Overview](./architecture.md)
- [Class Diagram](./class-diagram.md)
- [Sequence Diagrams](./sequence-diagrams.md)