fix(qt6): remove QmlComponents symlink, use direct import paths in main.cpp

- Delete QmlComponents symlink (Windows incompatible, bad practice)
- main.cpp: add qml/ and project root as import paths directly
- No more symlink dependency — works cross-platform
- Clean up stale duplicate files from background agents
- Update generate_cmake.py and CMakeLists.txt for new paths

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-19 10:30:43 +00:00
parent d4a42b5aec
commit 99bfd75732
9 changed files with 254 additions and 101 deletions

View File

@@ -1 +0,0 @@
/Users/rmac/Documents/GitHub/metabuilder/qml

View File

@@ -1,5 +1,5 @@
# AUTO-GENERATED by generate_cmake.py — do not edit manually
# Generated from cmake_config.json | 53 QML files, 6 C++ sources, 22 SVGs, 1 audio assets
# Generated from cmake_config.json | 192 QML files, 6 C++ sources, 22 SVGs, 1 audio assets
#
# Discovered packages:
# analytics v1.0.0 - Analytics Studio
@@ -58,36 +58,175 @@ qt_add_qml_module(dbal-qml
URI DBALObservatory
VERSION 1.0
QML_FILES
../../qml/qt6/AdminCrud.js
../../qml/qt6/AdminView.qml
../../qml/qt6/App.qml
../../qml/qt6/CommentsView.qml
../../qml/qt6/ComponentHierarchyEditor.qml
../../qml/qt6/CssClassManager.qml
../../qml/qt6/DashboardView.qml
../../qml/qt6/DatabaseManager.qml
../../qml/qt6/DropdownConfigManager.qml
../../qml/qt6/FrontPage.qml
../../qml/qt6/GodPanel.qml
../../qml/qt6/LoginView.qml
../../qml/qt6/LuaEditor.qml
../../qml/qt6/MaterialLanding.qml
../../qml/qt6/MediaServicePanel.qml
../../qml/qt6/ModPlayerPanel.qml
../../qml/qt6/ModeratorView.qml
../../qml/qt6/NotificationsPanel.qml
../../qml/qt6/PackageManager.qml
../../qml/qt6/PackageViewLoader.qml
../../qml/qt6/PageRoutesManager.qml
../../qml/qt6/ProfileView.qml
../../qml/qt6/SMTPConfigEditor.qml
../../qml/qt6/SchemaEditor.qml
../../qml/qt6/SettingsView.qml
../../qml/qt6/Storybook.qml
../../qml/qt6/SuperGodPanel.qml
../../qml/qt6/ThemeEditor.qml
../../qml/qt6/UserManagement.qml
../../qml/qt6/WorkflowEditor.qml
AdminCrud.js
AdminView.qml
App.qml
CommentsView.qml
ComponentHierarchyEditor.qml
CssClassManager.qml
DashboardView.qml
DatabaseManager.qml
DropdownConfigManager.qml
FrontPage.qml
GodPanel.qml
LoginView.qml
LuaEditor.qml
MaterialLanding.qml
MediaServicePanel.qml
ModPlayerPanel.qml
ModeratorView.qml
NotificationsPanel.qml
PackageManager.qml
PackageViewLoader.qml
PageRoutesManager.qml
ProfileView.qml
SMTPConfigEditor.qml
SchemaEditor.qml
SettingsView.qml
Storybook.qml
SuperGodPanel.qml
ThemeEditor.qml
UserManagement.qml
WorkflowEditor.qml
qmllib/Material/MaterialAccordion.qml
qmllib/Material/MaterialAlert.qml
qmllib/Material/MaterialAppBar.qml
qmllib/Material/MaterialAvatar.qml
qmllib/Material/MaterialBadge.qml
qmllib/Material/MaterialBox.qml
qmllib/Material/MaterialButton.qml
qmllib/Material/MaterialCard.qml
qmllib/Material/MaterialCheckbox.qml
qmllib/Material/MaterialChip.qml
qmllib/Material/MaterialCircularProgress.qml
qmllib/Material/MaterialCollapse.qml
qmllib/Material/MaterialContainer.qml
qmllib/Material/MaterialDialog.qml
qmllib/Material/MaterialDivider.qml
qmllib/Material/MaterialDividerProps.qml
qmllib/Material/MaterialGrid.qml
qmllib/Material/MaterialIconButton.qml
qmllib/Material/MaterialLinearProgress.qml
qmllib/Material/MaterialLink.qml
qmllib/Material/MaterialMenu.qml
qmllib/Material/MaterialMenuItem.qml
qmllib/Material/MaterialMenuProps.qml
qmllib/Material/MaterialPalette.qml
qmllib/Material/MaterialPaper.qml
qmllib/Material/MaterialPopover.qml
qmllib/Material/MaterialPopoverProps.qml
qmllib/Material/MaterialSkeleton.qml
qmllib/Material/MaterialSnackbar.qml
qmllib/Material/MaterialSurface.qml
qmllib/Material/MaterialSwitch.qml
qmllib/Material/MaterialTextField.qml
qmllib/Material/MaterialToolbar.qml
qmllib/Material/MaterialTypography.qml
qmllib/MetaBuilder/CActivityList.qml
qmllib/MetaBuilder/CAdapterPatternSelector.qml
qmllib/MetaBuilder/CAddRouteDialog.qml
qmllib/MetaBuilder/CAdminStatsBar.qml
qmllib/MetaBuilder/CBackendDetailPanel.qml
qmllib/MetaBuilder/CBackendListSidebar.qml
qmllib/MetaBuilder/CCanvasGrid.qml
qmllib/MetaBuilder/CCanvasZoomOverlay.qml
qmllib/MetaBuilder/CCommentCard.qml
qmllib/MetaBuilder/CCommentInput.qml
qmllib/MetaBuilder/CComponentPropertiesPanel.qml
qmllib/MetaBuilder/CComponentTreeRow.qml
qmllib/MetaBuilder/CComponentTypeLegend.qml
qmllib/MetaBuilder/CConfigStatCard.qml
qmllib/MetaBuilder/CConnectionLayer.qml
qmllib/MetaBuilder/CConnectionTest.qml
qmllib/MetaBuilder/CDataTable.qml
qmllib/MetaBuilder/CDatabaseStatsRow.qml
qmllib/MetaBuilder/CDeleteConfirmDialog.qml
qmllib/MetaBuilder/CDropdownMenu.qml
qmllib/MetaBuilder/CEntityForm.qml
qmllib/MetaBuilder/CEntitySidebar.qml
qmllib/MetaBuilder/CGodPanelHeader.qml
qmllib/MetaBuilder/CGodUserCard.qml
qmllib/MetaBuilder/CHeroSection.qml
qmllib/MetaBuilder/CLanguageSelector.qml
qmllib/MetaBuilder/CLevelCard.qml
qmllib/MetaBuilder/CLevelReferenceCard.qml
qmllib/MetaBuilder/CLoginForm.qml
qmllib/MetaBuilder/CModActionCard.qml
qmllib/MetaBuilder/CModStatsRow.qml
qmllib/MetaBuilder/CNavBar.qml
qmllib/MetaBuilder/CNodePalette.qml
qmllib/MetaBuilder/CNodePropertiesPanel.qml
qmllib/MetaBuilder/CNotificationBell.qml
qmllib/MetaBuilder/CNotificationEmptyState.qml
qmllib/MetaBuilder/CNotificationItem.qml
qmllib/MetaBuilder/CNotificationToggles.qml
qmllib/MetaBuilder/CProfileForm.qml
qmllib/MetaBuilder/CProfileHeader.qml
qmllib/MetaBuilder/CQuickActions.qml
qmllib/MetaBuilder/CQuickLoginCard.qml
qmllib/MetaBuilder/CReportCard.qml
qmllib/MetaBuilder/CRouteEditPanel.qml
qmllib/MetaBuilder/CRouteTableHeader.qml
qmllib/MetaBuilder/CRouteTableRow.qml
qmllib/MetaBuilder/CServiceStatus.qml
qmllib/MetaBuilder/CSettingsSection.qml
qmllib/MetaBuilder/CSidebar.qml
qmllib/MetaBuilder/CSmtpSenderForm.qml
qmllib/MetaBuilder/CSmtpServerForm.qml
qmllib/MetaBuilder/CSmtpTemplateEditor.qml
qmllib/MetaBuilder/CSmtpTemplateList.qml
qmllib/MetaBuilder/CSmtpTestEmailForm.qml
qmllib/MetaBuilder/CStatCard.qml
qmllib/MetaBuilder/CStatsStrip.qml
qmllib/MetaBuilder/CSystemMetricCard.qml
qmllib/MetaBuilder/CTableHeader.qml
qmllib/MetaBuilder/CTablePagination.qml
qmllib/MetaBuilder/CTechCard.qml
qmllib/MetaBuilder/CTenantCard.qml
qmllib/MetaBuilder/CThemePicker.qml
qmllib/MetaBuilder/CTransferCard.qml
qmllib/MetaBuilder/CUserMenu.qml
qmllib/MetaBuilder/CWelcomeCard.qml
qmllib/MetaBuilder/CWorkflowCanvas.qml
qmllib/MetaBuilder/CWorkflowNodeDelegate.qml
qmllib/MetaBuilder/CWorkflowSidebar.qml
qmllib/MetaBuilder/CWorkflowTestPanel.qml
qmllib/MetaBuilder/CWorkflowToolbar.qml
qmllib/MetaBuilder/ContactForm.qml
qmllib/MetaBuilder/CssClassPreview.qml
qmllib/MetaBuilder/CssClassSidebar.qml
qmllib/MetaBuilder/CssPropertyEditor.qml
qmllib/MetaBuilder/DropdownGeneralForm.qml
qmllib/MetaBuilder/DropdownOptionsEditor.qml
qmllib/MetaBuilder/DropdownPreview.qml
qmllib/MetaBuilder/DropdownSidebar.qml
qmllib/MetaBuilder/FeatureCard.qml
qmllib/MetaBuilder/HeroSection.qml
qmllib/MetaBuilder/LuaCodeEditor.qml
qmllib/MetaBuilder/LuaOutputPanel.qml
qmllib/MetaBuilder/LuaPropertiesPanel.qml
qmllib/MetaBuilder/LuaScriptSidebar.qml
qmllib/MetaBuilder/MediaJobForm.qml
qmllib/MetaBuilder/MediaJobTable.qml
qmllib/MetaBuilder/MediaPluginsTab.qml
qmllib/MetaBuilder/MediaRadioTab.qml
qmllib/MetaBuilder/MediaTvTab.qml
qmllib/MetaBuilder/NavBar.qml
qmllib/MetaBuilder/SchemaFieldEditor.qml
qmllib/MetaBuilder/SchemaFieldsTable.qml
qmllib/MetaBuilder/SchemaSidebar.qml
qmllib/MetaBuilder/StatusCard.qml
qmllib/MetaBuilder/ThemeColorTokens.qml
qmllib/MetaBuilder/ThemeLivePreview.qml
qmllib/MetaBuilder/ThemePresetGrid.qml
qmllib/MetaBuilder/ThemeSpacingRadius.qml
qmllib/MetaBuilder/ThemeTypography.qml
qmllib/MetaBuilder/UserFormDialog.qml
qmllib/MetaBuilder/UserSearchFilter.qml
qmllib/MetaBuilder/UserStatsBar.qml
qmllib/MetaBuilder/UserTable.qml
qmllib/MetaBuilder/WorkflowNode.qml
qmllib/dbal/DBALProvider.qml
packages/analytics/PackageView.qml
packages/blog/PackageView.qml
packages/breakout/PackageView.qml
@@ -130,6 +269,9 @@ qt_add_qml_module(dbal-qml
config/supergod-tenants.json
config/supergod-transfers.json
config/workflow-mock-data.json
qmllib/Material/qmldir
qmllib/MetaBuilder/qmldir
qmllib/dbal/qmldir
)
# SVG assets

View File

@@ -29,43 +29,64 @@ def load_config(config_path: str) -> dict:
return json.load(f)
def find_root_qml_files(root_dir: Path) -> list[str]:
"""Find all *.qml and *.js files in the project root and ../../qml/qt6/ directories."""
files = sorted(
list(root_dir.glob("*.qml")) + list(root_dir.glob("*.js"))
)
result = [f.name for f in files]
def find_root_qml_files(root_dir: Path) -> list[tuple[str, str]]:
"""Find all *.qml and *.js files in the project root and extracted qml/qt6/ directory.
# Also scan the extracted QML directory (../../qml/qt6/ relative to root_dir)
Returns list of (source_path, qrc_alias) tuples. Files in root_dir use just their
filename; files in ../../qml/qt6/ use relative paths with a QT_RESOURCE_ALIAS.
"""
result = []
# Local root files
for fn in sorted(os.listdir(str(root_dir))):
if fn.endswith((".qml", ".js")):
result.append((fn, None))
# Extracted files in ../../qml/qt6/
extracted_dir = root_dir.parent.parent / "qml" / "qt6"
if extracted_dir.exists():
ext_files = sorted(
list(extracted_dir.glob("*.qml")) + list(extracted_dir.glob("*.js"))
)
for f in ext_files:
rel = os.path.relpath(f, root_dir)
if rel not in result:
result.append(rel)
return sorted(result)
local_names = {t[0] for t in result}
for fn in sorted(os.listdir(str(extracted_dir))):
if fn.endswith((".qml", ".js")) and fn not in local_names:
rel_path = os.path.relpath(extracted_dir / fn, root_dir)
result.append((rel_path, fn))
return result
def find_qmllib_files(root_dir: Path) -> dict[str, list[str]]:
"""Find all *.qml and *.js files and qmldir files in qmllib/ subdirectories.
Returns a dict mapping relative paths (e.g. 'qmllib/dbal/DBALProvider.qml')
grouped by subdirectory.
Follows symlinks so that extracted component directories (e.g., qmllib/MetaBuilder
symlinked to ../../qml/MetaBuilder) are included with qmllib-relative paths.
Returns a dict with 'qml' (list of QML/JS paths) and 'resources' (qmldir paths).
"""
qmllib_dir = root_dir / "qmllib"
result = {"qml": [], "resources": []}
if not qmllib_dir.exists():
return result
qml_files = sorted(
list(qmllib_dir.rglob("*.qml")) + list(qmllib_dir.rglob("*.js"))
)
for qml_file in qml_files:
result["qml"].append(str(qml_file.relative_to(root_dir)))
for qmldir_file in sorted(qmllib_dir.rglob("qmldir")):
result["resources"].append(str(qmldir_file.relative_to(root_dir)))
# Search both local qmllib/ and extracted ../../qml/{MetaBuilder,Material,dbal}
search_dirs = []
qmllib_dir = root_dir / "qmllib"
if qmllib_dir.exists():
search_dirs.append((qmllib_dir, "qmllib"))
extracted_qml = root_dir.parent.parent / "qml"
if extracted_qml.exists():
for subdir in ["MetaBuilder", "Material", "dbal"]:
candidate = extracted_qml / subdir
if candidate.exists():
search_dirs.append((candidate, f"qmllib/{subdir}"))
for search_dir, prefix in search_dirs:
for dirpath, _dirnames, filenames in os.walk(str(search_dir), followlinks=True):
for fn in filenames:
full = os.path.join(dirpath, fn)
# Compute path relative to search_dir, then prepend prefix
rel_to_search = os.path.relpath(full, str(search_dir))
aliased = f"{prefix}/{rel_to_search}" if prefix == f"qmllib/{search_dir.name}" else os.path.relpath(full, str(root_dir))
real_path = os.path.relpath(full, str(root_dir))
if fn.endswith((".qml", ".js")):
result["qml"].append((real_path, f"{prefix}/{rel_to_search}"))
elif fn == "qmldir":
result["resources"].append((real_path, f"{prefix}/{rel_to_search}"))
return result

View File

@@ -14,25 +14,16 @@ int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
// Add shared QML component library path
// Resolves: import QmlComponents 1.0
const auto appDir = QCoreApplication::applicationDirPath();
// Qt6 resolves "import QmlComponents" by looking for a QmlComponents/ dir
// inside each import path. We symlink or reference the parent of qml/.
const QStringList qmlParentPaths = {
appDir + "/../../",
appDir + "/../../../",
appDir + "/../../../../",
QDir::cleanPath(QStringLiteral(SRCDIR) + "/../..")
};
for (const auto &path : qmlParentPaths) {
const QString candidate = QDir(path).absolutePath();
// Check if QmlComponents symlink or qml/ dir with qmldir exists
if (QDir(candidate + "/QmlComponents").exists()
|| QDir(candidate + "/qml").exists()) {
engine.addImportPath(candidate);
break;
}
// Add shared QML component library import paths
// No symlinks — directly reference the qml/ directory tree
const QString projectRoot = QDir::cleanPath(QStringLiteral(SRCDIR) + QStringLiteral("/../.."));
const QString qmlDir = projectRoot + QStringLiteral("/qml");
// Add qml/ parent so Qt finds "import QmlComponents 1.0" at qml/components/
// and "import MetaBuilder 1.0" at qml/MetaBuilder/
if (QDir(qmlDir).exists()) {
engine.addImportPath(qmlDir);
engine.addImportPath(projectRoot);
}
PackageRegistry registry;

View File

@@ -12,8 +12,8 @@ CCard {
property string fromName: ""
property string fromEmail: ""
signal fromNameChanged(string value)
signal fromEmailChanged(string value)
signal fromNameEdited(string value)
signal fromEmailEdited(string value)
ColumnLayout {
anchors.fill: parent
@@ -28,7 +28,7 @@ CCard {
label: "From Name"
placeholderText: "MetaBuilder"
text: root.fromName
onTextChanged: root.fromNameChanged(text)
onTextChanged: root.fromNameEdited(text)
}
CTextField {
@@ -36,7 +36,7 @@ CCard {
label: "From Email"
placeholderText: "noreply@example.com"
text: root.fromEmail
onTextChanged: root.fromEmailChanged(text)
onTextChanged: root.fromEmailEdited(text)
}
CDivider { Layout.fillWidth: true }

View File

@@ -12,9 +12,9 @@ CCard {
property string body: "This is a test email from MetaBuilder."
property bool sending: false
signal recipientChanged(string value)
signal subjectChanged(string value)
signal bodyChanged(string value)
signal recipientEdited(string value)
signal subjectEdited(string value)
signal bodyEdited(string value)
signal sendRequested()
ColumnLayout {
@@ -34,7 +34,7 @@ CCard {
label: "Recipient"
placeholderText: "test@example.com"
text: root.recipient
onTextChanged: root.recipientChanged(text)
onTextChanged: root.recipientEdited(text)
}
CTextField {
@@ -42,7 +42,7 @@ CCard {
label: "Subject"
placeholderText: "Test subject"
text: root.subject
onTextChanged: root.subjectChanged(text)
onTextChanged: root.subjectEdited(text)
}
}
@@ -70,7 +70,7 @@ CCard {
color: Theme.text
font.pixelSize: 13
background: null
onTextChanged: root.bodyChanged(text)
onTextChanged: root.bodyEdited(text)
}
}
}

View File

@@ -13,10 +13,10 @@ ColumnLayout {
property int radiusMedium: 8
property int radiusLarge: 16
signal baseSpacingChanged(int value)
signal radiusSmallChanged(int value)
signal radiusMediumChanged(int value)
signal radiusLargeChanged(int value)
signal baseSpacingEdited(int value)
signal radiusSmallEdited(int value)
signal radiusMediumEdited(int value)
signal radiusLargeEdited(int value)
// Spacing section
CCard {

View File

@@ -143,16 +143,16 @@ Rectangle {
CSmtpSenderForm {
fromName: smtpEditor.fromName; fromEmail: smtpEditor.fromEmail
onFromNameChanged: function(v) { smtpEditor.fromName = v; markDirty() }
onFromEmailChanged: function(v) { smtpEditor.fromEmail = v; markDirty() }
onFromNameEdited: function(v) { smtpEditor.fromName = v; markDirty() }
onFromEmailEdited: function(v) { smtpEditor.fromEmail = v; markDirty() }
}
}
CSmtpTestEmailForm {
recipient: testRecipient; subject: testSubject; body: testBody; sending: sendingTest
onRecipientChanged: function(v) { testRecipient = v }
onSubjectChanged: function(v) { testSubject = v }
onBodyChanged: function(v) { testBody = v }
onRecipientEdited: function(v) { testRecipient = v }
onSubjectEdited: function(v) { testSubject = v }
onBodyEdited: function(v) { testBody = v }
onSendRequested: sendTestEmail()
}

View File

@@ -128,10 +128,10 @@ Rectangle {
radiusSmall: root.radiusSmall
radiusMedium: root.radiusMedium
radiusLarge: root.radiusLarge
onBaseSpacingChanged: function(val) { root.baseSpacing = val; hasUnsavedChanges = true }
onRadiusSmallChanged: function(val) { root.radiusSmall = val; hasUnsavedChanges = true }
onRadiusMediumChanged: function(val) { root.radiusMedium = val; hasUnsavedChanges = true }
onRadiusLargeChanged: function(val) { root.radiusLarge = val; hasUnsavedChanges = true }
onBaseSpacingEdited: function(val) { root.baseSpacing = val; hasUnsavedChanges = true }
onRadiusSmallEdited: function(val) { root.radiusSmall = val; hasUnsavedChanges = true }
onRadiusMediumEdited: function(val) { root.radiusMedium = val; hasUnsavedChanges = true }
onRadiusLargeEdited: function(val) { root.radiusLarge = val; hasUnsavedChanges = true }
}
// Section 6: Live Preview