mirror of
https://github.com/The-Low-Code-Foundation/OpenNoodl.git
synced 2026-01-12 15:22:55 +01:00
13 KiB
13 KiB
COMP-003: Component Export to Repository
Overview
Enable users to export components from their project to a GitHub repository, creating a personal component library. This allows sharing components across projects and with team members.
Context
Currently, component sharing is manual:
- Export components as zip (Cmd+Shift+E)
- Manually upload to GitHub or share file
- Others download and import
This task streamlines the process:
- Right-click component → "Export to Repository"
- Select target repository
- Component is committed with metadata
- Available in NodePicker for other projects
Existing Export Flow
From exportProjectComponents.ts:
export function exportProjectComponents() {
ProjectImporter.instance.listComponentsAndDependencies(
ProjectModel.instance._retainedProjectDirectory,
(components) => {
// Shows export popup
// User selects components
// Creates zip file
}
);
}
Requirements
Functional Requirements
-
Export Entry Points
- Right-click component → "Export to Repository"
- Component sheet context menu → "Export Sheet to Repository"
- File menu → "Export Components to Repository"
-
Repository Selection
- List user's GitHub repositories
- "Create new repository" option
- Remember last used repository
- Suggest
noodl-componentsnaming convention
-
Component Selection
- Select individual components
- Select entire sheets
- Auto-select dependencies
- Preview what will be exported
-
Metadata Entry
- Component name (prefilled)
- Description
- Tags
- Version (auto-increment option)
- Category selection
-
Export Process
- Create component directory structure
- Generate prefab.json manifest
- Commit to repository
- Optional: Push immediately or stage
-
Repository Structure
- Standard directory layout
- index.json manifest for discovery
- README generation
- License file option
Non-Functional Requirements
- Export completes in < 30 seconds
- Works with existing repositories
- Handles large components (100+ nodes)
- Conflict detection with existing exports
Technical Approach
1. Repository Structure Convention
my-noodl-components/
├── index.json # Repository manifest
├── README.md # Auto-generated docs
├── LICENSE # Optional license
└── components/
├── my-button/
│ ├── prefab.json # Component metadata
│ ├── component.ndjson # Noodl component data
│ ├── dependencies/ # Style/variant dependencies
│ └── assets/ # Images, fonts
├── my-card/
│ └── ...
└── my-form/
└── ...
2. Repository Manifest (index.json)
{
"$schema": "https://opennoodl.net/schemas/component-repo-v1.json",
"name": "My Noodl Components",
"description": "Personal component library",
"author": {
"name": "John Doe",
"github": "johndoe"
},
"version": "1.0.0",
"noodlVersion": ">=2.10.0",
"components": [
{
"id": "my-button",
"name": "My Button",
"description": "Custom styled button",
"version": "1.2.0",
"path": "components/my-button",
"tags": ["form", "button"],
"category": "Forms"
}
],
"updatedAt": "2024-01-15T10:30:00Z"
}
3. Component Export Service
// packages/noodl-editor/src/editor/src/services/ComponentExportService.ts
interface ExportOptions {
components: ComponentModel[];
repository: GitHubRepo;
metadata: {
description: string;
tags: string[];
category: string;
version?: string;
};
commitMessage?: string;
pushImmediately?: boolean;
}
interface ExportResult {
success: boolean;
exportedComponents: string[];
commitSha?: string;
error?: string;
}
class ComponentExportService {
private static instance: ComponentExportService;
// Export flow
async exportToRepository(options: ExportOptions): Promise<ExportResult>;
// Repository management
async listUserRepositories(): Promise<GitHubRepo[]>;
async createComponentRepository(name: string): Promise<GitHubRepo>;
async validateRepository(repo: GitHubRepo): Promise<boolean>;
// Component preparation
async prepareExport(components: ComponentModel[]): Promise<ExportPackage>;
async resolveExportDependencies(components: ComponentModel[]): Promise<ComponentModel[]>;
// File generation
generatePrefabManifest(component: ComponentModel, metadata: ExportMetadata): PrefabManifest;
generateRepoManifest(repo: GitHubRepo, components: PrefabManifest[]): RepoManifest;
generateReadme(repo: GitHubRepo, components: PrefabManifest[]): string;
}
4. Export Modal Flow
┌─────────────────────────────────────────────────────────────────────┐
│ Export to Repository [×] │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ COMPONENTS TO EXPORT │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ ☑ MyButton + 2 dependencies │ │
│ │ └─ ☑ ButtonStyles (variant) │ │
│ │ └─ ☑ PrimaryColor (color style) │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ TARGET REPOSITORY │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ johndoe/noodl-components [▾] │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ [+ Create new repository] │
│ │
│ METADATA │
│ Name: [My Button ] │
│ Description: [Custom styled button with loading state ] │
│ Tags: [form] [button] [+] │
│ Category: [Forms ▾] │
│ Version: [1.0.0 ] ☑ Auto-increment │
│ │
│ COMMIT │
│ Message: [Add MyButton component ] │
│ ☑ Push to GitHub immediately │
│ │
│ [Cancel] [Export] │
└─────────────────────────────────────────────────────────────────────┘
5. Export Process Flow
async exportToRepository(options: ExportOptions): Promise<ExportResult> {
const { components, repository, metadata } = options;
// 1. Clone or open repository locally
const localRepo = await this.getLocalRepository(repository);
// 2. Resolve all dependencies
const allComponents = await this.resolveExportDependencies(components);
// 3. Generate component files
for (const component of allComponents) {
const componentDir = path.join(localRepo.path, 'components', component.id);
// Export component data
await this.exportComponentData(component, componentDir);
// Generate prefab manifest
const manifest = this.generatePrefabManifest(component, metadata);
await fs.writeJson(path.join(componentDir, 'prefab.json'), manifest);
}
// 4. Update repository manifest
const repoManifest = await this.updateRepoManifest(localRepo, allComponents);
// 5. Update README
await this.updateReadme(localRepo, repoManifest);
// 6. Commit changes
const git = new Git(mergeProject);
await git.openRepository(localRepo.path);
await git.commit(options.commitMessage || `Add ${components[0].name}`);
// 7. Push if requested
if (options.pushImmediately) {
await git.push({});
}
return {
success: true,
exportedComponents: allComponents.map(c => c.name),
commitSha: await git.getHeadCommitId()
};
}
Files to Create
packages/noodl-editor/src/editor/src/services/ComponentExportService.tspackages/noodl-core-ui/src/components/modals/ExportToRepoModal/ExportToRepoModal.tsxpackages/noodl-core-ui/src/components/modals/ExportToRepoModal/ComponentSelector.tsxpackages/noodl-core-ui/src/components/modals/ExportToRepoModal/RepoSelector.tsxpackages/noodl-core-ui/src/components/modals/ExportToRepoModal/MetadataForm.tsxpackages/noodl-core-ui/src/components/modals/CreateRepoModal/CreateRepoModal.tsxpackages/noodl-editor/src/editor/src/utils/componentExporter.ts- Low-level export utilities
Files to Modify
-
packages/noodl-editor/src/editor/src/views/nodegrapheditor.js- Add right-click context menu option
-
packages/noodl-editor/src/editor/src/views/panels/componentspanel.tsx- Add export option to component context menu
-
packages/noodl-editor/src/editor/src/utils/exportProjectComponents.ts- Refactor to share code with repository export
-
packages/noodl-editor/src/editor/src/models/prefab/sources/GitHubPrefabSource.ts- Implement full source for reading from component repos
Implementation Steps
Phase 1: Export Service Foundation
- Create ComponentExportService
- Implement dependency resolution
- Create file generation utilities
- Define repository structure
Phase 2: Repository Management
- List user repositories (via GitHub API)
- Create new repository flow
- Local repository management
- Clone/pull existing repos
Phase 3: Export Modal
- Create ExportToRepoModal
- Create ComponentSelector
- Create RepoSelector
- Create MetadataForm
Phase 4: Git Integration
- Stage exported files
- Commit with message
- Push to remote
- Handle conflicts
Phase 5: Context Menu Integration
- Add to component right-click menu
- Add to sheet context menu
- Add to File menu
Phase 6: Testing & Polish
- Test with various component types
- Test dependency resolution
- Error handling
- Progress indication
Testing Checklist
- Export single component works
- Export multiple components works
- Dependencies auto-selected
- Repository selection lists repos
- Create new repository works
- Metadata saved correctly
- Files committed to repo
- Push to GitHub works
- Repository manifest updated
- README generated/updated
- Handles existing components (update)
- Version auto-increment works
- Error messages helpful
Dependencies
- COMP-001 (Prefab System Refactoring)
- GIT-001 (GitHub OAuth) - for repository access
Blocked By
- COMP-001
- GIT-001
Blocks
- COMP-004 (Organization Components)
- COMP-005 (Component Import with Version Control)
Estimated Effort
- Export service: 4-5 hours
- Repository management: 3-4 hours
- Export modal: 4-5 hours
- Git integration: 3-4 hours
- Context menu: 2-3 hours
- Testing & polish: 3-4 hours
- Total: 19-25 hours
Success Criteria
- Components can be exported via right-click
- Dependencies are automatically included
- Repository structure is consistent
- Manifests are generated correctly
- Git operations work smoothly
- Components are importable via COMP-004+
Future Enhancements
- Export to npm package
- Export to Noodl marketplace
- Batch export multiple components
- Export templates/starters
- Preview component before export
- Export history/versioning