mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-25 06:14:59 +00:00
Merge pull request #7 from johndoe6345789/copilot/create-weak-link-packages-folder
Commit packages folder to repository with on-demand package creation and merge conflict detection
This commit is contained in:
132
.github/workflows/merge-conflict-check.yml
vendored
Normal file
132
.github/workflows/merge-conflict-check.yml
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
name: Check for Merge Conflicts
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
# Also run when the base branch is updated
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
|
||||
jobs:
|
||||
check-conflicts:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Fetch base branch
|
||||
run: |
|
||||
git fetch origin ${{ github.base_ref || github.event.repository.default_branch }}
|
||||
|
||||
- name: Check for merge conflicts
|
||||
id: conflict-check
|
||||
run: |
|
||||
# Determine the base branch
|
||||
BASE_BRANCH="${{ github.base_ref }}"
|
||||
if [ -z "$BASE_BRANCH" ]; then
|
||||
BASE_BRANCH="${{ github.event.repository.default_branch }}"
|
||||
fi
|
||||
|
||||
echo "Checking for conflicts with origin/$BASE_BRANCH"
|
||||
|
||||
# Try to merge the base branch to see if there are conflicts
|
||||
if git merge-tree $(git merge-base HEAD origin/$BASE_BRANCH) origin/$BASE_BRANCH HEAD | grep -q "^<<<<<"; then
|
||||
echo "has_conflicts=true" >> $GITHUB_OUTPUT
|
||||
echo "✗ Merge conflicts detected!"
|
||||
else
|
||||
echo "has_conflicts=false" >> $GITHUB_OUTPUT
|
||||
echo "✓ No merge conflicts detected"
|
||||
fi
|
||||
|
||||
- name: Comment on PR if conflicts exist
|
||||
if: steps.conflict-check.outputs.has_conflicts == 'true' && github.event_name == 'pull_request'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const comment = `## ⚠️ Merge Conflicts Detected
|
||||
|
||||
@copilot This pull request has merge conflicts that need to be resolved.
|
||||
|
||||
**Please resolve the conflicts by:**
|
||||
1. Merging the latest changes from the base branch
|
||||
2. Resolving any conflicting files
|
||||
3. Pushing the updated changes
|
||||
|
||||
---
|
||||
*This is an automated message from the merge conflict checker.*`;
|
||||
|
||||
// Check if we already commented
|
||||
const { data: comments } = await github.rest.issues.listComments({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
});
|
||||
|
||||
const botComment = comments.find(comment =>
|
||||
comment.user.type === 'Bot' &&
|
||||
comment.body.includes('Merge Conflicts Detected')
|
||||
);
|
||||
|
||||
if (botComment) {
|
||||
// Update existing comment
|
||||
await github.rest.issues.updateComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: botComment.id,
|
||||
body: comment
|
||||
});
|
||||
} else {
|
||||
// Create new comment
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
body: comment
|
||||
});
|
||||
}
|
||||
|
||||
- name: Add label if conflicts exist
|
||||
if: steps.conflict-check.outputs.has_conflicts == 'true' && github.event_name == 'pull_request'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
try {
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
labels: ['merge-conflict']
|
||||
});
|
||||
} catch (error) {
|
||||
console.log('Label might not exist yet, skipping...');
|
||||
}
|
||||
|
||||
- name: Remove label if no conflicts
|
||||
if: steps.conflict-check.outputs.has_conflicts == 'false' && github.event_name == 'pull_request'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
try {
|
||||
await github.rest.issues.removeLabel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
name: 'merge-conflict'
|
||||
});
|
||||
} catch (error) {
|
||||
console.log('Label does not exist or is not applied, skipping...');
|
||||
}
|
||||
|
||||
- name: Fail if conflicts exist
|
||||
if: steps.conflict-check.outputs.has_conflicts == 'true'
|
||||
run: |
|
||||
echo "❌ This PR has merge conflicts and cannot be merged."
|
||||
exit 1
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -26,7 +26,6 @@ dist-ssr
|
||||
|
||||
.env
|
||||
**/agent-eval-report*
|
||||
packages
|
||||
pids
|
||||
.file-manifest
|
||||
.devcontainer/
|
||||
|
||||
23
README.md
23
README.md
@@ -13,11 +13,24 @@ A declarative admin panel generator that creates full-featured CRUD interfaces f
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Launch the app
|
||||
2. Use the sidebar to navigate between models
|
||||
3. Click "Create New" to add records
|
||||
4. Edit or delete records using the action buttons
|
||||
5. Click "Edit Schema" to customize your data models
|
||||
1. Clone the repository
|
||||
2. Install dependencies: `npm install`
|
||||
3. Launch the app: `npm run dev`
|
||||
4. Use the sidebar to navigate between models
|
||||
5. Click "Create New" to add records
|
||||
6. Edit or delete records using the action buttons
|
||||
7. Click "Edit Schema" to customize your data models
|
||||
|
||||
## Packages
|
||||
|
||||
This project uses a modular package system. The `packages/` folder contains component packages that are committed to the repository.
|
||||
|
||||
If you need to add a new package, use:
|
||||
```bash
|
||||
npm run setup-packages <package-name>
|
||||
```
|
||||
|
||||
This will create the required package structure with placeholder files.
|
||||
|
||||
## Schema Structure
|
||||
|
||||
|
||||
13
package-lock.json
generated
13
package-lock.json
generated
@@ -7,6 +7,7 @@
|
||||
"": {
|
||||
"name": "spark-template",
|
||||
"version": "0.0.0",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@github/spark": ">=0.43.1 <1",
|
||||
"@heroicons/react": "^2.2.0",
|
||||
@@ -7106,6 +7107,8 @@
|
||||
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz",
|
||||
"integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"dompurify": "3.2.7",
|
||||
"marked": "14.0.0"
|
||||
@@ -7851,16 +7854,8 @@
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/router/node_modules/ms": {
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
"build": "tsc -b --noCheck && vite build",
|
||||
"lint": "eslint .",
|
||||
"optimize": "vite optimize",
|
||||
"preview": "vite preview"
|
||||
"preview": "vite preview",
|
||||
"setup-packages": "node scripts/setup-packages.cjs",
|
||||
"postinstall": "node scripts/setup-packages.cjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@github/spark": ">=0.43.1 <1",
|
||||
|
||||
61
packages/README.md
Normal file
61
packages/README.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Packages Folder
|
||||
|
||||
This folder contains modular packages for the MetaBuilder application. Each package is self-contained with its own components, metadata, and examples.
|
||||
|
||||
## Structure
|
||||
|
||||
Each package follows this structure:
|
||||
|
||||
```
|
||||
packages/
|
||||
├── package_name/
|
||||
│ ├── seed/
|
||||
│ │ ├── components.json # Component definitions
|
||||
│ │ ├── metadata.json # Package metadata
|
||||
│ │ └── scripts/ # Optional Lua scripts
|
||||
│ └── static_content/
|
||||
│ └── examples.json # Optional usage examples
|
||||
```
|
||||
|
||||
## Available Packages
|
||||
|
||||
- **admin_dialog**: Admin dialog components for management interfaces
|
||||
- **data_table**: Data table components for displaying tabular data
|
||||
- **form_builder**: Form builder components for creating dynamic forms
|
||||
- **nav_menu**: Navigation menu components
|
||||
- **dashboard**: Dashboard layout components
|
||||
- **notification_center**: Notification center components
|
||||
|
||||
## Package Metadata Format
|
||||
|
||||
Each `metadata.json` file should contain:
|
||||
|
||||
```json
|
||||
{
|
||||
"packageId": "package_name",
|
||||
"name": "Display Name",
|
||||
"version": "1.0.0",
|
||||
"description": "Package description",
|
||||
"author": "Author name",
|
||||
"category": "ui",
|
||||
"dependencies": [],
|
||||
"exports": {
|
||||
"components": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Components Format
|
||||
|
||||
Each `components.json` file should contain an array of component definitions.
|
||||
|
||||
## Development
|
||||
|
||||
The main application imports from these packages via relative paths in `src/lib/package-glue.ts`.
|
||||
|
||||
To add a new package:
|
||||
|
||||
1. Run `npm run setup-packages <package-name>` to create the package structure
|
||||
2. Add optional `static_content/examples.json` if needed
|
||||
3. Update `src/lib/package-glue.ts` to import the new package
|
||||
4. Commit the new package files to the repository
|
||||
1
packages/admin_dialog/seed/components.json
Normal file
1
packages/admin_dialog/seed/components.json
Normal file
@@ -0,0 +1 @@
|
||||
[]
|
||||
12
packages/admin_dialog/seed/metadata.json
Normal file
12
packages/admin_dialog/seed/metadata.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"packageId": "admin_dialog",
|
||||
"name": "Admin Dialog",
|
||||
"version": "1.0.0",
|
||||
"description": "Admin dialog components",
|
||||
"author": "MetaBuilder",
|
||||
"category": "ui",
|
||||
"dependencies": [],
|
||||
"exports": {
|
||||
"components": []
|
||||
}
|
||||
}
|
||||
1
packages/admin_dialog/static_content/examples.json
Normal file
1
packages/admin_dialog/static_content/examples.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
packages/dashboard/seed/components.json
Normal file
1
packages/dashboard/seed/components.json
Normal file
@@ -0,0 +1 @@
|
||||
[]
|
||||
12
packages/dashboard/seed/metadata.json
Normal file
12
packages/dashboard/seed/metadata.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"packageId": "dashboard",
|
||||
"name": "Dashboard",
|
||||
"version": "1.0.0",
|
||||
"description": "Dashboard components",
|
||||
"author": "MetaBuilder",
|
||||
"category": "ui",
|
||||
"dependencies": [],
|
||||
"exports": {
|
||||
"components": []
|
||||
}
|
||||
}
|
||||
1
packages/data_table/seed/components.json
Normal file
1
packages/data_table/seed/components.json
Normal file
@@ -0,0 +1 @@
|
||||
[]
|
||||
12
packages/data_table/seed/metadata.json
Normal file
12
packages/data_table/seed/metadata.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"packageId": "data_table",
|
||||
"name": "Data Table",
|
||||
"version": "1.0.0",
|
||||
"description": "Data table components",
|
||||
"author": "MetaBuilder",
|
||||
"category": "ui",
|
||||
"dependencies": [],
|
||||
"exports": {
|
||||
"components": []
|
||||
}
|
||||
}
|
||||
1
packages/data_table/static_content/examples.json
Normal file
1
packages/data_table/static_content/examples.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
packages/form_builder/seed/components.json
Normal file
1
packages/form_builder/seed/components.json
Normal file
@@ -0,0 +1 @@
|
||||
[]
|
||||
12
packages/form_builder/seed/metadata.json
Normal file
12
packages/form_builder/seed/metadata.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"packageId": "form_builder",
|
||||
"name": "Form Builder",
|
||||
"version": "1.0.0",
|
||||
"description": "Form builder components",
|
||||
"author": "MetaBuilder",
|
||||
"category": "ui",
|
||||
"dependencies": [],
|
||||
"exports": {
|
||||
"components": []
|
||||
}
|
||||
}
|
||||
1
packages/form_builder/static_content/examples.json
Normal file
1
packages/form_builder/static_content/examples.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
packages/nav_menu/seed/components.json
Normal file
1
packages/nav_menu/seed/components.json
Normal file
@@ -0,0 +1 @@
|
||||
[]
|
||||
12
packages/nav_menu/seed/metadata.json
Normal file
12
packages/nav_menu/seed/metadata.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"packageId": "nav_menu",
|
||||
"name": "Navigation Menu",
|
||||
"version": "1.0.0",
|
||||
"description": "Navigation menu components",
|
||||
"author": "MetaBuilder",
|
||||
"category": "ui",
|
||||
"dependencies": [],
|
||||
"exports": {
|
||||
"components": []
|
||||
}
|
||||
}
|
||||
1
packages/notification_center/seed/components.json
Normal file
1
packages/notification_center/seed/components.json
Normal file
@@ -0,0 +1 @@
|
||||
[]
|
||||
12
packages/notification_center/seed/metadata.json
Normal file
12
packages/notification_center/seed/metadata.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"packageId": "notification_center",
|
||||
"name": "Notification Center",
|
||||
"version": "1.0.0",
|
||||
"description": "Notification center components",
|
||||
"author": "MetaBuilder",
|
||||
"category": "ui",
|
||||
"dependencies": [],
|
||||
"exports": {
|
||||
"components": []
|
||||
}
|
||||
}
|
||||
168
scripts/setup-packages.cjs
Executable file
168
scripts/setup-packages.cjs
Executable file
@@ -0,0 +1,168 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Setup script for creating package folder structure
|
||||
* Usage:
|
||||
* node scripts/setup-packages.cjs <package-name> - Create a specific package
|
||||
* node scripts/setup-packages.cjs - Verify all required packages exist
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const packagesDir = path.join(__dirname, '..', 'packages');
|
||||
|
||||
// Get package name from command line argument
|
||||
const packageName = process.argv[2];
|
||||
|
||||
// Package definitions
|
||||
const packageTemplates = {
|
||||
'admin_dialog': {
|
||||
id: 'admin_dialog',
|
||||
name: 'Admin Dialog',
|
||||
description: 'Admin dialog components',
|
||||
hasExamples: true
|
||||
},
|
||||
'data_table': {
|
||||
id: 'data_table',
|
||||
name: 'Data Table',
|
||||
description: 'Data table components',
|
||||
hasExamples: true
|
||||
},
|
||||
'form_builder': {
|
||||
id: 'form_builder',
|
||||
name: 'Form Builder',
|
||||
description: 'Form builder components',
|
||||
hasExamples: true
|
||||
},
|
||||
'nav_menu': {
|
||||
id: 'nav_menu',
|
||||
name: 'Navigation Menu',
|
||||
description: 'Navigation menu components',
|
||||
hasExamples: false
|
||||
},
|
||||
'dashboard': {
|
||||
id: 'dashboard',
|
||||
name: 'Dashboard',
|
||||
description: 'Dashboard components',
|
||||
hasExamples: false
|
||||
},
|
||||
'notification_center': {
|
||||
id: 'notification_center',
|
||||
name: 'Notification Center',
|
||||
description: 'Notification center components',
|
||||
hasExamples: false
|
||||
}
|
||||
};
|
||||
|
||||
function createPackage(pkg) {
|
||||
const pkgDir = path.join(packagesDir, pkg.id);
|
||||
const seedDir = path.join(pkgDir, 'seed');
|
||||
|
||||
// Create directories
|
||||
if (!fs.existsSync(packagesDir)) {
|
||||
fs.mkdirSync(packagesDir, { recursive: true });
|
||||
}
|
||||
|
||||
if (!fs.existsSync(seedDir)) {
|
||||
fs.mkdirSync(seedDir, { recursive: true });
|
||||
}
|
||||
|
||||
// Create components.json
|
||||
const componentsPath = path.join(seedDir, 'components.json');
|
||||
if (!fs.existsSync(componentsPath)) {
|
||||
fs.writeFileSync(componentsPath, '[]', 'utf8');
|
||||
}
|
||||
|
||||
// Create metadata.json
|
||||
const metadataPath = path.join(seedDir, 'metadata.json');
|
||||
if (!fs.existsSync(metadataPath)) {
|
||||
const metadata = {
|
||||
packageId: pkg.id,
|
||||
name: pkg.name,
|
||||
version: '1.0.0',
|
||||
description: pkg.description,
|
||||
author: 'MetaBuilder',
|
||||
category: 'ui',
|
||||
dependencies: [],
|
||||
exports: {
|
||||
components: []
|
||||
}
|
||||
};
|
||||
fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2), 'utf8');
|
||||
}
|
||||
|
||||
// Create examples.json if needed
|
||||
if (pkg.hasExamples) {
|
||||
const staticDir = path.join(pkgDir, 'static_content');
|
||||
if (!fs.existsSync(staticDir)) {
|
||||
fs.mkdirSync(staticDir, { recursive: true });
|
||||
}
|
||||
|
||||
const examplesPath = path.join(staticDir, 'examples.json');
|
||||
if (!fs.existsSync(examplesPath)) {
|
||||
fs.writeFileSync(examplesPath, '{}', 'utf8');
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`✓ Created ${pkg.name} package`);
|
||||
}
|
||||
|
||||
// If a specific package name is provided
|
||||
if (packageName) {
|
||||
const pkg = packageTemplates[packageName];
|
||||
|
||||
if (!pkg) {
|
||||
console.error(`Error: Unknown package '${packageName}'`);
|
||||
console.log('\nAvailable packages:');
|
||||
Object.keys(packageTemplates).forEach(key => {
|
||||
console.log(` - ${key}`);
|
||||
});
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Check if package already exists
|
||||
const pkgDir = path.join(packagesDir, pkg.id);
|
||||
if (fs.existsSync(pkgDir)) {
|
||||
console.log(`✓ Package '${pkg.name}' already exists`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.log(`Creating package: ${pkg.name}...\n`);
|
||||
createPackage(pkg);
|
||||
console.log('\n✅ Package created successfully!');
|
||||
} else {
|
||||
// No package name provided - verification mode (postinstall or manual check)
|
||||
// Verify that all required packages exist
|
||||
const requiredPackages = Object.keys(packageTemplates);
|
||||
const missingPackages = [];
|
||||
|
||||
if (!fs.existsSync(packagesDir)) {
|
||||
console.error('Error: packages folder does not exist!');
|
||||
console.log('Run this script with a package name to create packages.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
for (const pkgId of requiredPackages) {
|
||||
const componentsPath = path.join(packagesDir, pkgId, 'seed', 'components.json');
|
||||
const metadataPath = path.join(packagesDir, pkgId, 'seed', 'metadata.json');
|
||||
|
||||
if (!fs.existsSync(componentsPath) || !fs.existsSync(metadataPath)) {
|
||||
missingPackages.push(pkgId);
|
||||
}
|
||||
}
|
||||
|
||||
if (missingPackages.length > 0) {
|
||||
console.error('Error: Missing required packages:', missingPackages.join(', '));
|
||||
console.log('\nCreate missing packages with:');
|
||||
missingPackages.forEach(pkg => {
|
||||
console.log(` npm run setup-packages ${pkg}`);
|
||||
});
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('✓ All required packages exist and are committed to the repository.');
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
},
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
"src",
|
||||
"packages"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user