14 KiB
COMP-005: Component Import with Version Control
Overview
Track the source and version of imported components, enabling update notifications, selective updates, and clear understanding of component provenance. When a component is imported from a repository, remember where it came from and notify users when updates are available.
Context
Currently, imported components lose connection to their source:
- No tracking of where component came from
- No awareness of available updates
- No way to re-sync with source
- Manual process to check for new versions
This task adds version tracking and update management:
- Track component source (built-in, org, personal, docs)
- Store version information
- Check for updates periodically
- Enable selective component updates
Import Flow Today
User clicks "Clone" → Component imported → No source tracking
Import Flow After This Task
User clicks "Clone" → Component imported → Source/version tracked
↓
Background: Check for updates periodically
↓
Notification: "2 components have updates available"
↓
User reviews and selects updates
Requirements
Functional Requirements
-
Source Tracking
- Record source repository/location for each import
- Store version at time of import
- Track import timestamp
- Handle components without source (legacy)
-
Version Information
- Display current version in component panel
- Show source badge (Built-in, Org name, etc.)
- Link to source documentation
- View changelog
-
Update Detection
- Background check for available updates
- Badge/indicator for components with updates
- List all updatable components
- Compare current vs available version
-
Update Process
- Preview what changes in update
- Selective update (choose which to update)
- Backup current before update
- Rollback option if update fails
-
Import Metadata Storage
- Store in project metadata
- Survive project export/import
- Handle renamed components
Non-Functional Requirements
- Update check < 5 seconds
- No performance impact on project load
- Works offline (shows cached status)
- Handles 100+ tracked components
Technical Approach
1. Import Metadata Schema
// Stored in project.json metadata
interface ComponentImportMetadata {
components: ImportedComponent[];
lastUpdateCheck: string; // ISO timestamp
}
interface ImportedComponent {
componentId: string; // Internal Noodl component ID
componentName: string; // Display name at import time
source: ComponentSource;
importedVersion: string;
importedAt: string; // ISO timestamp
lastUpdatedAt?: string; // When user last updated
updateAvailable?: string; // Available version if any
checksum?: string; // For detecting local modifications
}
interface ComponentSource {
type: 'builtin' | 'organization' | 'personal' | 'docs' | 'unknown';
repository?: string; // GitHub repo URL
organization?: string; // Org name if type is 'organization'
prefabId: string; // ID in source manifest
}
2. Import Tracking Service
// packages/noodl-editor/src/editor/src/services/ComponentTrackingService.ts
class ComponentTrackingService {
private static instance: ComponentTrackingService;
// On import
async trackImport(
componentId: string,
source: ComponentSource,
version: string
): Promise<void>;
// Queries
getImportedComponents(): ImportedComponent[];
getComponentSource(componentId: string): ComponentSource | null;
getComponentsWithUpdates(): ImportedComponent[];
// Update checking
async checkForUpdates(): Promise<UpdateCheckResult>;
async checkComponentUpdate(componentId: string): Promise<UpdateInfo | null>;
// Update application
async updateComponent(componentId: string): Promise<UpdateResult>;
async updateAllComponents(componentIds: string[]): Promise<UpdateResult[]>;
async rollbackUpdate(componentId: string): Promise<void>;
// Metadata
async saveMetadata(): Promise<void>;
async loadMetadata(): Promise<void>;
}
interface UpdateCheckResult {
checked: number;
updatesAvailable: number;
components: {
componentId: string;
currentVersion: string;
availableVersion: string;
changelogUrl?: string;
}[];
}
3. Update Check Process
async checkForUpdates(): Promise<UpdateCheckResult> {
const imported = this.getImportedComponents();
const result: UpdateCheckResult = {
checked: 0,
updatesAvailable: 0,
components: []
};
// Group by source for efficient checking
const bySource = groupBy(imported, c => c.source.repository);
for (const [repo, components] of Object.entries(bySource)) {
const source = PrefabRegistry.instance.getSource(repo);
if (!source) continue;
// Fetch latest manifest
const manifest = await source.getManifest();
for (const component of components) {
result.checked++;
const latest = manifest.components.find(
c => c.id === component.source.prefabId
);
if (latest && semver.gt(latest.version, component.importedVersion)) {
result.updatesAvailable++;
result.components.push({
componentId: component.componentId,
currentVersion: component.importedVersion,
availableVersion: latest.version,
changelogUrl: latest.changelog
});
// Update metadata
component.updateAvailable = latest.version;
}
}
}
await this.saveMetadata();
return result;
}
4. UI Components
Component Panel Badge
┌─────────────────────────────────────────────────────────────────────┐
│ Components │
├─────────────────────────────────────────────────────────────────────┤
│ ├── Pages │
│ │ └── HomePage │
│ │ └── LoginPage │
│ ├── Components │
│ │ └── AcmeButton [🏢 v2.1.0] [⬆️ Update] │
│ │ └── AcmeCard [🏢 v1.3.0] │
│ │ └── MyCustomButton │
│ │ └── FormInput [📦 v1.0.0] │
└─────────────────────────────────────────────────────────────────────┘
Update Available Notification
┌─────────────────────────────────────────────────────────────────────┐
│ 🔔 Component Updates Available │
│ │
│ 2 components have updates available from your organization. │
│ │
│ [View Updates] [Remind Me Later] │
└─────────────────────────────────────────────────────────────────────┘
Update Modal
┌─────────────────────────────────────────────────────────────────────┐
│ Component Updates [×] │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Available Updates │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ ☑ AcmeButton │ │
│ │ Current: v2.1.0 → Available: v2.2.0 │ │
│ │ Source: Acme Corp │ │
│ │ Changes: Added loading state, fixed hover color │ │
│ │ [View Full Changelog] │ │
│ ├─────────────────────────────────────────────────────────────────┤ │
│ │ ☑ AcmeCard │ │
│ │ Current: v1.3.0 → Available: v1.4.0 │ │
│ │ Source: Acme Corp │ │
│ │ Changes: Added shadow variants │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ⚠️ Updates will replace your imported components. Local │
│ modifications may be lost. │
│ │
│ [Cancel] [Update Selected (2)] │
└─────────────────────────────────────────────────────────────────────┘
5. Integration Points
// Hook into existing import flow
// packages/noodl-editor/src/editor/src/models/modulelibrarymodel.ts
async installPrefab(prefabId: string, options?: InstallOptions): Promise<void> {
// ... existing import logic ...
// After successful import, track it
const source = this.detectSource(prefabId);
const version = await this.getPrefabVersion(prefabId);
for (const componentId of importedComponentIds) {
await ComponentTrackingService.instance.trackImport(
componentId,
source,
version
);
}
}
Files to Create
packages/noodl-editor/src/editor/src/services/ComponentTrackingService.tspackages/noodl-core-ui/src/components/common/ComponentSourceBadge/ComponentSourceBadge.tsxpackages/noodl-core-ui/src/components/modals/ComponentUpdatesModal/ComponentUpdatesModal.tsxpackages/noodl-core-ui/src/components/modals/ComponentUpdatesModal/UpdateItem.tsxpackages/noodl-core-ui/src/components/notifications/UpdateAvailableToast/UpdateAvailableToast.tsx
Files to Modify
-
packages/noodl-editor/src/editor/src/models/modulelibrarymodel.ts- Track imports after install
- Add version detection
-
packages/noodl-editor/src/editor/src/views/panels/componentspanel.tsx- Show source badge
- Show update indicator
- Add "Check for Updates" action
-
packages/noodl-editor/src/editor/src/models/projectmodel.ts- Store/load import metadata
- Add to project.json
-
packages/noodl-editor/src/editor/src/pages/EditorPage/EditorPage.tsx- Periodic update check
- Show update notification
-
packages/noodl-editor/src/editor/src/utils/projectimporter.js- Return component IDs after import
- Support update (re-import)
Implementation Steps
Phase 1: Tracking Infrastructure
- Create ComponentTrackingService
- Define metadata schema
- Add to project.json structure
- Implement track/load/save
Phase 2: Import Integration
- Hook into installPrefab
- Extract version from manifest
- Track after successful import
- Handle import errors
Phase 3: Update Checking
- Implement checkForUpdates
- Compare versions (semver)
- Store update availability
- Background check timer
Phase 4: UI - Badges & Indicators
- Create ComponentSourceBadge
- Add to component panel
- Show update indicator
- Add "Check for Updates" button
Phase 5: UI - Update Modal
- Create ComponentUpdatesModal
- Show changelog summaries
- Selective update checkboxes
- Implement update action
Phase 6: Update Application
- Backup current component
- Re-import from source
- Update metadata
- Handle errors/rollback
Testing Checklist
- Import tracks source correctly
- Version stored in metadata
- Badge shows in component panel
- Update check finds updates
- Notification appears when updates available
- Update modal lists all updates
- Selective update works
- Update replaces component correctly
- Changelog link works
- Rollback restores previous
- Works with built-in prefabs
- Works with org prefabs
- Legacy imports show "unknown" source
- Offline shows cached status
Dependencies
- COMP-001 (Prefab System Refactoring)
- COMP-002 (Built-in Prefabs) - for version tracking
- COMP-004 (Organization Components) - for org tracking
Blocked By
- COMP-001
- COMP-002
Blocks
- COMP-006 (extends tracking for forking)
Estimated Effort
- Tracking service: 4-5 hours
- Import integration: 3-4 hours
- Update checking: 3-4 hours
- UI badges/indicators: 3-4 hours
- Update modal: 3-4 hours
- Update application: 3-4 hours
- Total: 19-25 hours
Success Criteria
- Imported components track their source
- Version visible in component panel
- Updates detected automatically
- Users notified of available updates
- Selective update works smoothly
- Update preserves project integrity
Future Enhancements
- Auto-update option (for trusted sources)
- Diff view before update
- Local modification detection
- Update scheduling
- Update history
- Component dependency updates
- Breaking change warnings