mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
refactor(qt6): JSON config extraction + CWorkflowCanvas split
95% JSON config principle applied: - SuperGodPanel: mock tenants/users/metrics/transfers → config/*.json (806→588) - WorkflowEditor: mock workflows → config/workflow-mock-data.json - FrontPage: levels/tech/services/creds → config/frontpage-data.json - App.qml: seed users/views → config/app-config.json CWorkflowCanvas (384→182): CCanvasGrid, CCanvasZoomOverlay, CWorkflowNodeDelegate extracted Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,40 +16,33 @@ Rectangle {
|
||||
|
||||
property int currentTab: 0
|
||||
|
||||
// ── Mock fallback data ──
|
||||
property var mockTenants: [
|
||||
{ name: "default", owner: "admin", status: "active", homepage: "/", created: "2025-01-15" },
|
||||
{ name: "staging", owner: "devops", status: "active", homepage: "/staging", created: "2025-06-01" },
|
||||
{ name: "production", owner: "platform-admin", status: "active", homepage: "/prod", created: "2025-08-20" }
|
||||
]
|
||||
property var mockGodUsers: [
|
||||
{ username: "admin", initials: "AD", role: "supergod", level: 5, tenant: "default", status: "online" },
|
||||
{ username: "platform-admin", initials: "PA", role: "supergod", level: 5, tenant: "production", status: "online" },
|
||||
{ username: "devops", initials: "DO", role: "god", level: 4, tenant: "staging", status: "online" },
|
||||
{ username: "builder01", initials: "B1", role: "god", level: 4, tenant: "default", status: "offline" },
|
||||
{ username: "builder02", initials: "B2", role: "god", level: 4, tenant: "production", status: "away" }
|
||||
]
|
||||
property var mockDaemons: [
|
||||
{ name: "DBAL", status: "healthy", uptime: "14d 7h 32m", port: 8080 },
|
||||
{ name: "Nginx", status: "healthy", uptime: "14d 7h 30m", port: 443 },
|
||||
{ name: "PostgreSQL", status: "healthy", uptime: "14d 6h 55m", port: 5432 },
|
||||
{ name: "Redis", status: "degraded", uptime: "2d 1h 12m", port: 6379 }
|
||||
]
|
||||
property var mockSystemMetrics: ({ cpu: 34, memory: 62, disk: 47, network: 18 })
|
||||
// ── JSON config loader ──
|
||||
function loadJsonFile(path) {
|
||||
var xhr = new XMLHttpRequest()
|
||||
xhr.open("GET", Qt.resolvedUrl(path), false)
|
||||
xhr.send()
|
||||
if (xhr.status === 200 || xhr.status === 0) {
|
||||
return JSON.parse(xhr.responseText)
|
||||
}
|
||||
console.warn("Failed to load JSON:", path, xhr.status)
|
||||
return null
|
||||
}
|
||||
|
||||
// ── Mock fallback data (loaded from JSON config) ──
|
||||
property var mockTenants: []
|
||||
property var mockGodUsers: []
|
||||
property var mockDaemons: []
|
||||
property var mockSystemMetrics: ({ cpu: 0, memory: 0, disk: 0, network: 0 })
|
||||
|
||||
// ── Live data (falls back to mock) ──
|
||||
property var tenants: [
|
||||
{ name: "default", owner: "admin", status: "active", homepage: "/", created: "2025-01-15" },
|
||||
{ name: "staging", owner: "devops", status: "active", homepage: "/staging", created: "2025-06-01" },
|
||||
{ name: "production", owner: "platform-admin", status: "active", homepage: "/prod", created: "2025-08-20" }
|
||||
]
|
||||
property var tenants: []
|
||||
property bool showCreateTenantDialog: false
|
||||
property string newTenantName: ""
|
||||
property string newTenantOwner: ""
|
||||
property string newTenantHomepage: ""
|
||||
|
||||
// ── God users data ──
|
||||
property var godUsers: mockGodUsers
|
||||
property var godUsers: []
|
||||
|
||||
// ── Power transfer data ──
|
||||
property bool showTransferForm: false
|
||||
@@ -57,18 +50,12 @@ Rectangle {
|
||||
property string transferTo: ""
|
||||
property string transferReason: ""
|
||||
property string transferExpiry: ""
|
||||
property var pendingTransfers: [
|
||||
{ from: "admin", to: "devops", reason: "Scheduled maintenance window", expiry: "2026-03-25", status: "pending" }
|
||||
]
|
||||
property var transferHistory: [
|
||||
{ from: "platform-admin", to: "admin", reason: "Emergency access grant", date: "2026-02-10 14:32", status: "approved" },
|
||||
{ from: "admin", to: "builder01", reason: "Sprint deployment authority", date: "2026-01-28 09:15", status: "approved" },
|
||||
{ from: "devops", to: "admin", reason: "Incident response escalation", date: "2025-12-05 22:47", status: "denied" }
|
||||
]
|
||||
property var pendingTransfers: []
|
||||
property var transferHistory: []
|
||||
|
||||
// ── System data ──
|
||||
property var daemons: mockDaemons
|
||||
property var systemMetrics: mockSystemMetrics
|
||||
property var daemons: []
|
||||
property var systemMetrics: ({ cpu: 0, memory: 0, disk: 0, network: 0 })
|
||||
property bool showReseedDialog: false
|
||||
property bool showClearCacheDialog: false
|
||||
property bool showRestartDialog: false
|
||||
@@ -165,6 +152,26 @@ Rectangle {
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
// Load mock data from JSON config files
|
||||
var tenantData = loadJsonFile("config/supergod-tenants.json");
|
||||
if (tenantData) { mockTenants = tenantData; tenants = tenantData; }
|
||||
|
||||
var userData = loadJsonFile("config/supergod-god-users.json");
|
||||
if (userData) { mockGodUsers = userData; godUsers = userData; }
|
||||
|
||||
var systemData = loadJsonFile("config/supergod-system-metrics.json");
|
||||
if (systemData) {
|
||||
if (systemData.daemons) { mockDaemons = systemData.daemons; daemons = systemData.daemons; }
|
||||
if (systemData.metrics) { mockSystemMetrics = systemData.metrics; systemMetrics = systemData.metrics; }
|
||||
}
|
||||
|
||||
var transferData = loadJsonFile("config/supergod-transfers.json");
|
||||
if (transferData) {
|
||||
if (transferData.pending) pendingTransfers = transferData.pending;
|
||||
if (transferData.history) transferHistory = transferData.history;
|
||||
}
|
||||
|
||||
// Then try DBAL for live data
|
||||
dbal.ping(function(success) {
|
||||
if (success) {
|
||||
loadTenants();
|
||||
@@ -194,21 +201,15 @@ Rectangle {
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
CButton {
|
||||
text: "Level 4"
|
||||
variant: "ghost"
|
||||
size: "sm"
|
||||
text: "Level 4"; variant: "ghost"; size: "sm"
|
||||
onClicked: appWindow.currentView = "god"
|
||||
}
|
||||
CButton {
|
||||
text: "Level 3"
|
||||
variant: "ghost"
|
||||
size: "sm"
|
||||
text: "Level 3"; variant: "ghost"; size: "sm"
|
||||
onClicked: appWindow.currentView = "admin"
|
||||
}
|
||||
CButton {
|
||||
text: "Level 2"
|
||||
variant: "ghost"
|
||||
size: "sm"
|
||||
text: "Level 2"; variant: "ghost"; size: "sm"
|
||||
onClicked: appWindow.currentView = "dashboard"
|
||||
}
|
||||
}
|
||||
@@ -218,7 +219,6 @@ Rectangle {
|
||||
FlexRow {
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
|
||||
CChip { text: tenants.length + " Tenants"; chipColor: Theme.primary }
|
||||
CChip { text: godUsers.length + " God Users"; chipColor: Theme.primary }
|
||||
CChip { text: pendingTransfers.length + " Pending Transfers"; chipColor: Theme.warning }
|
||||
@@ -258,9 +258,7 @@ Rectangle {
|
||||
CText { variant: "h3"; text: "Tenant Management" }
|
||||
Item { Layout.fillWidth: true }
|
||||
CButton {
|
||||
text: "Create Tenant"
|
||||
variant: "primary"
|
||||
size: "sm"
|
||||
text: "Create Tenant"; variant: "primary"; size: "sm"
|
||||
onClicked: showCreateTenantDialog = true
|
||||
}
|
||||
}
|
||||
@@ -268,9 +266,7 @@ Rectangle {
|
||||
CText {
|
||||
variant: "body2"
|
||||
text: "Cross-tenant provisioning and configuration. Each tenant operates in full isolation with its own schemas, users, and data."
|
||||
wrapMode: Text.Wrap
|
||||
Layout.fillWidth: true
|
||||
color: Theme.textSecondary
|
||||
wrapMode: Text.Wrap; Layout.fillWidth: true; color: Theme.textSecondary
|
||||
}
|
||||
|
||||
CDivider { Layout.fillWidth: true }
|
||||
@@ -300,9 +296,7 @@ Rectangle {
|
||||
CText {
|
||||
variant: "body2"
|
||||
text: "All users with god-level (L4) or super-god-level (L5) platform access across all tenants."
|
||||
wrapMode: Text.Wrap
|
||||
Layout.fillWidth: true
|
||||
color: Theme.textSecondary
|
||||
wrapMode: Text.Wrap; Layout.fillWidth: true; color: Theme.textSecondary
|
||||
}
|
||||
|
||||
CDivider { Layout.fillWidth: true }
|
||||
@@ -335,8 +329,7 @@ Rectangle {
|
||||
Item { Layout.fillWidth: true }
|
||||
CButton {
|
||||
text: showTransferForm ? "Cancel" : "Initiate Transfer"
|
||||
variant: showTransferForm ? "ghost" : "primary"
|
||||
size: "sm"
|
||||
variant: showTransferForm ? "ghost" : "primary"; size: "sm"
|
||||
onClicked: showTransferForm = !showTransferForm
|
||||
}
|
||||
}
|
||||
@@ -344,9 +337,7 @@ Rectangle {
|
||||
CText {
|
||||
variant: "body2"
|
||||
text: "Transfer elevated privileges between god-level users. All transfers require approval and are logged for audit."
|
||||
wrapMode: Text.Wrap
|
||||
Layout.fillWidth: true
|
||||
color: Theme.textSecondary
|
||||
wrapMode: Text.Wrap; Layout.fillWidth: true; color: Theme.textSecondary
|
||||
}
|
||||
|
||||
// ── Transfer form ──
|
||||
@@ -361,61 +352,40 @@ Rectangle {
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
CTextField {
|
||||
Layout.fillWidth: true
|
||||
label: "From User"
|
||||
placeholderText: "e.g. admin"
|
||||
text: transferFrom
|
||||
Layout.fillWidth: true; label: "From User"
|
||||
placeholderText: "e.g. admin"; text: transferFrom
|
||||
onTextChanged: transferFrom = text
|
||||
}
|
||||
CTextField {
|
||||
Layout.fillWidth: true
|
||||
label: "To User"
|
||||
placeholderText: "e.g. devops"
|
||||
text: transferTo
|
||||
Layout.fillWidth: true; label: "To User"
|
||||
placeholderText: "e.g. devops"; text: transferTo
|
||||
onTextChanged: transferTo = text
|
||||
}
|
||||
}
|
||||
|
||||
CTextField {
|
||||
Layout.fillWidth: true
|
||||
label: "Reason"
|
||||
Layout.fillWidth: true; label: "Reason"
|
||||
placeholderText: "Describe the reason for this transfer"
|
||||
text: transferReason
|
||||
onTextChanged: transferReason = text
|
||||
text: transferReason; onTextChanged: transferReason = text
|
||||
}
|
||||
|
||||
CTextField {
|
||||
Layout.fillWidth: true
|
||||
label: "Expiry Date"
|
||||
Layout.fillWidth: true; label: "Expiry Date"
|
||||
placeholderText: "YYYY-MM-DD"
|
||||
text: transferExpiry
|
||||
onTextChanged: transferExpiry = text
|
||||
text: transferExpiry; onTextChanged: transferExpiry = text
|
||||
}
|
||||
|
||||
FlexRow {
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
Layout.fillWidth: true; spacing: 8
|
||||
Item { Layout.fillWidth: true }
|
||||
CButton {
|
||||
text: "Submit Transfer"
|
||||
variant: "primary"
|
||||
size: "sm"
|
||||
text: "Submit Transfer"; variant: "primary"; size: "sm"
|
||||
onClicked: {
|
||||
if (transferFrom && transferTo && transferReason) {
|
||||
var newTransfer = {
|
||||
from: transferFrom,
|
||||
to: transferTo,
|
||||
reason: transferReason,
|
||||
expiry: transferExpiry || "No expiry",
|
||||
status: "pending"
|
||||
};
|
||||
var updated = pendingTransfers.slice();
|
||||
updated.push(newTransfer);
|
||||
updated.push({ from: transferFrom, to: transferTo, reason: transferReason, expiry: transferExpiry || "No expiry", status: "pending" });
|
||||
pendingTransfers = updated;
|
||||
transferFrom = "";
|
||||
transferTo = "";
|
||||
transferReason = "";
|
||||
transferExpiry = "";
|
||||
transferFrom = ""; transferTo = ""; transferReason = ""; transferExpiry = "";
|
||||
showTransferForm = false;
|
||||
}
|
||||
}
|
||||
@@ -437,11 +407,7 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
CAlert {
|
||||
severity: "info"
|
||||
text: "No pending transfers."
|
||||
visible: pendingTransfers.length === 0
|
||||
}
|
||||
CAlert { severity: "info"; text: "No pending transfers."; visible: pendingTransfers.length === 0 }
|
||||
|
||||
CDivider { Layout.fillWidth: true }
|
||||
|
||||
@@ -451,21 +417,15 @@ Rectangle {
|
||||
Repeater {
|
||||
model: transferHistory
|
||||
delegate: CCard {
|
||||
Layout.fillWidth: true
|
||||
variant: "outlined"
|
||||
Layout.fillWidth: true; variant: "outlined"
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
Layout.fillWidth: true; spacing: 16
|
||||
ColumnLayout {
|
||||
spacing: 4
|
||||
Layout.fillWidth: true
|
||||
spacing: 4; Layout.fillWidth: true
|
||||
FlexRow {
|
||||
spacing: 8
|
||||
CText { variant: "subtitle1"; text: modelData.from + " -> " + modelData.to }
|
||||
CStatusBadge {
|
||||
status: modelData.status === "approved" ? "success" : "error"
|
||||
text: modelData.status
|
||||
}
|
||||
CStatusBadge { status: modelData.status === "approved" ? "success" : "error"; text: modelData.status }
|
||||
}
|
||||
CText { variant: "body2"; text: modelData.reason; wrapMode: Text.Wrap; Layout.fillWidth: true }
|
||||
}
|
||||
@@ -488,28 +448,18 @@ Rectangle {
|
||||
spacing: 16
|
||||
|
||||
CText { variant: "h3"; text: "System Overview" }
|
||||
|
||||
// ── Daemon status cards ──
|
||||
CText { variant: "h4"; text: "Daemon Status" }
|
||||
|
||||
GridLayout {
|
||||
Layout.fillWidth: true
|
||||
columns: 2
|
||||
columnSpacing: 16
|
||||
rowSpacing: 16
|
||||
|
||||
Layout.fillWidth: true; columns: 2; columnSpacing: 16; rowSpacing: 16
|
||||
Repeater {
|
||||
model: daemons
|
||||
delegate: CCard {
|
||||
Layout.fillWidth: true
|
||||
FlexRow {
|
||||
Layout.fillWidth: true
|
||||
spacing: 10
|
||||
Layout.fillWidth: true; spacing: 10
|
||||
CText { variant: "subtitle1"; text: modelData.name }
|
||||
CStatusBadge {
|
||||
status: modelData.status === "healthy" ? "success" : "warning"
|
||||
text: modelData.status
|
||||
}
|
||||
CStatusBadge { status: modelData.status === "healthy" ? "success" : "warning"; text: modelData.status }
|
||||
Item { Layout.fillWidth: true }
|
||||
CBadge { text: ":" + modelData.port; badgeColor: Theme.info }
|
||||
}
|
||||
@@ -519,16 +469,10 @@ Rectangle {
|
||||
}
|
||||
|
||||
CDivider { Layout.fillWidth: true }
|
||||
|
||||
// ── System metrics ──
|
||||
CText { variant: "h4"; text: "System Metrics" }
|
||||
|
||||
GridLayout {
|
||||
Layout.fillWidth: true
|
||||
columns: 4
|
||||
columnSpacing: 16
|
||||
rowSpacing: 16
|
||||
|
||||
Layout.fillWidth: true; columns: 4; columnSpacing: 16; rowSpacing: 16
|
||||
Repeater {
|
||||
model: [
|
||||
{ label: "CPU", value: systemMetrics.cpu },
|
||||
@@ -536,78 +480,32 @@ Rectangle {
|
||||
{ label: "Disk", value: systemMetrics.disk },
|
||||
{ label: "Network", value: systemMetrics.network }
|
||||
]
|
||||
delegate: CSystemMetricCard {
|
||||
label: modelData.label
|
||||
value: modelData.value
|
||||
}
|
||||
delegate: CSystemMetricCard { label: modelData.label; value: modelData.value }
|
||||
}
|
||||
}
|
||||
|
||||
CDivider { Layout.fillWidth: true }
|
||||
|
||||
// ── Actions ──
|
||||
CText { variant: "h4"; text: "System Actions" }
|
||||
|
||||
FlexRow {
|
||||
Layout.fillWidth: true
|
||||
spacing: 12
|
||||
|
||||
CButton {
|
||||
text: "Force Re-seed"
|
||||
variant: "primary"
|
||||
size: "sm"
|
||||
onClicked: showReseedDialog = true
|
||||
}
|
||||
CButton {
|
||||
text: "Clear Cache"
|
||||
variant: "ghost"
|
||||
size: "sm"
|
||||
onClicked: showClearCacheDialog = true
|
||||
}
|
||||
CButton {
|
||||
text: "Restart DBAL"
|
||||
variant: "danger"
|
||||
size: "sm"
|
||||
onClicked: { restartTarget = "DBAL"; showRestartDialog = true }
|
||||
}
|
||||
CButton {
|
||||
text: "Restart Redis"
|
||||
variant: "danger"
|
||||
size: "sm"
|
||||
onClicked: { restartTarget = "Redis"; showRestartDialog = true }
|
||||
}
|
||||
Layout.fillWidth: true; spacing: 12
|
||||
CButton { text: "Force Re-seed"; variant: "primary"; size: "sm"; onClicked: showReseedDialog = true }
|
||||
CButton { text: "Clear Cache"; variant: "ghost"; size: "sm"; onClicked: showClearCacheDialog = true }
|
||||
CButton { text: "Restart DBAL"; variant: "danger"; size: "sm"; onClicked: { restartTarget = "DBAL"; showRestartDialog = true } }
|
||||
CButton { text: "Restart Redis"; variant: "danger"; size: "sm"; onClicked: { restartTarget = "Redis"; showRestartDialog = true } }
|
||||
}
|
||||
|
||||
CDivider { Layout.fillWidth: true }
|
||||
|
||||
// ── Environment info ──
|
||||
CText { variant: "h4"; text: "Environment" }
|
||||
|
||||
CCard {
|
||||
Layout.fillWidth: true
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 24
|
||||
ColumnLayout {
|
||||
spacing: 4
|
||||
CText { variant: "caption"; text: "Version"; color: Theme.textSecondary }
|
||||
CText { variant: "body1"; text: "2.5.0-rc1" }
|
||||
}
|
||||
ColumnLayout {
|
||||
spacing: 4
|
||||
CText { variant: "caption"; text: "Build Date"; color: Theme.textSecondary }
|
||||
CText { variant: "body1"; text: "2026-03-15" }
|
||||
}
|
||||
ColumnLayout {
|
||||
spacing: 4
|
||||
CText { variant: "caption"; text: "Node Count"; color: Theme.textSecondary }
|
||||
CText { variant: "body1"; text: "4 nodes" }
|
||||
}
|
||||
ColumnLayout {
|
||||
spacing: 4
|
||||
CText { variant: "caption"; text: "Platform"; color: Theme.textSecondary }
|
||||
CText { variant: "body1"; text: "MetaBuilder Universal" }
|
||||
}
|
||||
Layout.fillWidth: true; spacing: 24
|
||||
ColumnLayout { spacing: 4; CText { variant: "caption"; text: "Version"; color: Theme.textSecondary }; CText { variant: "body1"; text: "2.5.0-rc1" } }
|
||||
ColumnLayout { spacing: 4; CText { variant: "caption"; text: "Build Date"; color: Theme.textSecondary }; CText { variant: "body1"; text: "2026-03-15" } }
|
||||
ColumnLayout { spacing: 4; CText { variant: "caption"; text: "Node Count"; color: Theme.textSecondary }; CText { variant: "body1"; text: "4 nodes" } }
|
||||
ColumnLayout { spacing: 4; CText { variant: "caption"; text: "Platform"; color: Theme.textSecondary }; CText { variant: "body1"; text: "MetaBuilder Universal" } }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -618,76 +516,26 @@ Rectangle {
|
||||
|
||||
// ── DIALOGS ──
|
||||
|
||||
// ── Create Tenant dialog ──
|
||||
CDialog {
|
||||
id: createTenantDialog
|
||||
visible: showCreateTenantDialog
|
||||
title: "Create Tenant"
|
||||
|
||||
id: createTenantDialog; visible: showCreateTenantDialog; title: "Create Tenant"
|
||||
ColumnLayout {
|
||||
spacing: 12
|
||||
width: 400
|
||||
|
||||
CText {
|
||||
variant: "body2"
|
||||
text: "Provision a new isolated tenant with its own schemas, users, and data store."
|
||||
wrapMode: Text.Wrap
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
CTextField {
|
||||
Layout.fillWidth: true
|
||||
label: "Tenant Name"
|
||||
placeholderText: "e.g. acme-corp"
|
||||
text: newTenantName
|
||||
onTextChanged: newTenantName = text
|
||||
}
|
||||
|
||||
CTextField {
|
||||
Layout.fillWidth: true
|
||||
label: "Owner"
|
||||
placeholderText: "e.g. admin@acme.com"
|
||||
text: newTenantOwner
|
||||
onTextChanged: newTenantOwner = text
|
||||
}
|
||||
|
||||
CTextField {
|
||||
Layout.fillWidth: true
|
||||
label: "Homepage"
|
||||
placeholderText: "e.g. /acme"
|
||||
text: newTenantHomepage
|
||||
onTextChanged: newTenantHomepage = text
|
||||
}
|
||||
|
||||
spacing: 12; width: 400
|
||||
CText { variant: "body2"; text: "Provision a new isolated tenant with its own schemas, users, and data store."; wrapMode: Text.Wrap; Layout.fillWidth: true }
|
||||
CTextField { Layout.fillWidth: true; label: "Tenant Name"; placeholderText: "e.g. acme-corp"; text: newTenantName; onTextChanged: newTenantName = text }
|
||||
CTextField { Layout.fillWidth: true; label: "Owner"; placeholderText: "e.g. admin@acme.com"; text: newTenantOwner; onTextChanged: newTenantOwner = text }
|
||||
CTextField { Layout.fillWidth: true; label: "Homepage"; placeholderText: "e.g. /acme"; text: newTenantHomepage; onTextChanged: newTenantHomepage = text }
|
||||
FlexRow {
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
|
||||
Layout.fillWidth: true; spacing: 8
|
||||
Item { Layout.fillWidth: true }
|
||||
CButton { text: "Cancel"; variant: "ghost"; size: "sm"; onClicked: showCreateTenantDialog = false }
|
||||
CButton {
|
||||
text: "Cancel"
|
||||
variant: "ghost"
|
||||
size: "sm"
|
||||
onClicked: showCreateTenantDialog = false
|
||||
}
|
||||
CButton {
|
||||
text: "Create"
|
||||
variant: "primary"
|
||||
size: "sm"
|
||||
text: "Create"; variant: "primary"; size: "sm"
|
||||
onClicked: {
|
||||
if (newTenantName && newTenantOwner) {
|
||||
var updated = tenants.slice();
|
||||
updated.push({
|
||||
name: newTenantName,
|
||||
owner: newTenantOwner,
|
||||
status: "active",
|
||||
homepage: newTenantHomepage || "/",
|
||||
created: "2026-03-18"
|
||||
});
|
||||
updated.push({ name: newTenantName, owner: newTenantOwner, status: "active", homepage: newTenantHomepage || "/", created: "2026-03-18" });
|
||||
tenants = updated;
|
||||
newTenantName = "";
|
||||
newTenantOwner = "";
|
||||
newTenantHomepage = "";
|
||||
newTenantName = ""; newTenantOwner = ""; newTenantHomepage = "";
|
||||
showCreateTenantDialog = false;
|
||||
}
|
||||
}
|
||||
@@ -696,110 +544,44 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Force Re-seed confirmation dialog ──
|
||||
CDialog {
|
||||
id: reseedDialog
|
||||
visible: showReseedDialog
|
||||
title: "Force Re-seed"
|
||||
|
||||
id: reseedDialog; visible: showReseedDialog; title: "Force Re-seed"
|
||||
ColumnLayout {
|
||||
spacing: 12
|
||||
width: 400
|
||||
|
||||
CAlert {
|
||||
severity: "warning"
|
||||
text: "This will re-run all seed data scripts. Existing seed records will be skipped (idempotent), but this may take several minutes."
|
||||
}
|
||||
|
||||
spacing: 12; width: 400
|
||||
CAlert { severity: "warning"; text: "This will re-run all seed data scripts. Existing seed records will be skipped (idempotent), but this may take several minutes." }
|
||||
FlexRow {
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
|
||||
Layout.fillWidth: true; spacing: 8
|
||||
Item { Layout.fillWidth: true }
|
||||
CButton {
|
||||
text: "Cancel"
|
||||
variant: "ghost"
|
||||
size: "sm"
|
||||
onClicked: showReseedDialog = false
|
||||
}
|
||||
CButton {
|
||||
text: "Re-seed"
|
||||
variant: "primary"
|
||||
size: "sm"
|
||||
onClicked: showReseedDialog = false
|
||||
}
|
||||
CButton { text: "Cancel"; variant: "ghost"; size: "sm"; onClicked: showReseedDialog = false }
|
||||
CButton { text: "Re-seed"; variant: "primary"; size: "sm"; onClicked: showReseedDialog = false }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Clear Cache confirmation dialog ──
|
||||
CDialog {
|
||||
id: clearCacheDialog
|
||||
visible: showClearCacheDialog
|
||||
title: "Clear Cache"
|
||||
|
||||
id: clearCacheDialog; visible: showClearCacheDialog; title: "Clear Cache"
|
||||
ColumnLayout {
|
||||
spacing: 12
|
||||
width: 400
|
||||
|
||||
CAlert {
|
||||
severity: "warning"
|
||||
text: "This will flush all Redis caches across all tenants. Subsequent requests will experience cache misses until the cache is repopulated."
|
||||
}
|
||||
|
||||
spacing: 12; width: 400
|
||||
CAlert { severity: "warning"; text: "This will flush all Redis caches across all tenants. Subsequent requests will experience cache misses until the cache is repopulated." }
|
||||
FlexRow {
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
|
||||
Layout.fillWidth: true; spacing: 8
|
||||
Item { Layout.fillWidth: true }
|
||||
CButton {
|
||||
text: "Cancel"
|
||||
variant: "ghost"
|
||||
size: "sm"
|
||||
onClicked: showClearCacheDialog = false
|
||||
}
|
||||
CButton {
|
||||
text: "Clear Cache"
|
||||
variant: "danger"
|
||||
size: "sm"
|
||||
onClicked: showClearCacheDialog = false
|
||||
}
|
||||
CButton { text: "Cancel"; variant: "ghost"; size: "sm"; onClicked: showClearCacheDialog = false }
|
||||
CButton { text: "Clear Cache"; variant: "danger"; size: "sm"; onClicked: showClearCacheDialog = false }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Restart Daemon confirmation dialog ──
|
||||
CDialog {
|
||||
id: restartDaemonDialog
|
||||
visible: showRestartDialog
|
||||
title: "Restart " + restartTarget
|
||||
|
||||
id: restartDaemonDialog; visible: showRestartDialog; title: "Restart " + restartTarget
|
||||
ColumnLayout {
|
||||
spacing: 12
|
||||
width: 400
|
||||
|
||||
CAlert {
|
||||
severity: "error"
|
||||
text: "Restarting " + restartTarget + " will cause a brief service interruption. All active connections will be dropped. Are you sure?"
|
||||
}
|
||||
|
||||
spacing: 12; width: 400
|
||||
CAlert { severity: "error"; text: "Restarting " + restartTarget + " will cause a brief service interruption. All active connections will be dropped. Are you sure?" }
|
||||
FlexRow {
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
|
||||
Layout.fillWidth: true; spacing: 8
|
||||
Item { Layout.fillWidth: true }
|
||||
CButton {
|
||||
text: "Cancel"
|
||||
variant: "ghost"
|
||||
size: "sm"
|
||||
onClicked: showRestartDialog = false
|
||||
}
|
||||
CButton {
|
||||
text: "Restart"
|
||||
variant: "danger"
|
||||
size: "sm"
|
||||
onClicked: showRestartDialog = false
|
||||
}
|
||||
CButton { text: "Cancel"; variant: "ghost"; size: "sm"; onClicked: showRestartDialog = false }
|
||||
CButton { text: "Restart"; variant: "danger"; size: "sm"; onClicked: showRestartDialog = false }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
52
frontends/qt6/config/GodPanelConfig.js
Normal file
52
frontends/qt6/config/GodPanelConfig.js
Normal file
@@ -0,0 +1,52 @@
|
||||
.pragma library
|
||||
|
||||
// Synchronous JSON loader for Qt resource files
|
||||
function loadJson(path) {
|
||||
var xhr = new XMLHttpRequest()
|
||||
xhr.open("GET", path, false) // synchronous
|
||||
xhr.send()
|
||||
if (xhr.status === 200 || xhr.status === 0) { // status 0 for local/qrc files
|
||||
return JSON.parse(xhr.responseText)
|
||||
}
|
||||
console.warn("GodPanelConfig: failed to load", path, "status:", xhr.status)
|
||||
return []
|
||||
}
|
||||
|
||||
function loadTabs() {
|
||||
return loadJson("qrc:/qt/qml/DBALObservatory/config/god-panel-tabs.json")
|
||||
}
|
||||
|
||||
function loadLevels() {
|
||||
return loadJson("qrc:/qt/qml/DBALObservatory/config/god-panel-levels.json")
|
||||
}
|
||||
|
||||
function loadConfigStats() {
|
||||
return loadJson("qrc:/qt/qml/DBALObservatory/config/god-panel-config-stats.json")
|
||||
}
|
||||
|
||||
// Map accent name strings to actual color values
|
||||
function resolveAccentColor(name, palette) {
|
||||
var map = {
|
||||
"blue": palette.accentBlue,
|
||||
"cyan": palette.accentCyan,
|
||||
"violet": palette.accentViolet,
|
||||
"amber": palette.accentAmber,
|
||||
"rose": palette.accentRose
|
||||
}
|
||||
return map[name] || palette.accentBlue
|
||||
}
|
||||
|
||||
// Build resolved config stat data from JSON + live counts + palette
|
||||
function resolveConfigStats(rawStats, configCounts, palette) {
|
||||
var result = []
|
||||
for (var i = 0; i < rawStats.length; i++) {
|
||||
var s = rawStats[i]
|
||||
var val = configCounts[s.valueKey]
|
||||
result.push({
|
||||
label: s.label,
|
||||
value: (val !== undefined ? val : 0).toString(),
|
||||
accent: resolveAccentColor(s.accentName, palette)
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
41
frontends/qt6/config/admin-entities.json
Normal file
41
frontends/qt6/config/admin-entities.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"entities": [
|
||||
"User", "Session", "Workflow", "Package", "UiPage",
|
||||
"Credential", "Forum", "Notification", "AuditLog", "Media"
|
||||
],
|
||||
"icons": {
|
||||
"User": "\u{1F464}", "Session": "\u{1F513}", "Workflow": "\u2699",
|
||||
"Package": "\u{1F4E6}", "UiPage": "\u{1F4C4}", "Credential": "\u{1F511}",
|
||||
"Forum": "\u{1F4AC}", "Notification": "\u{1F514}", "AuditLog": "\u{1F4CB}",
|
||||
"Media": "\u{1F3AC}"
|
||||
},
|
||||
"idPrefixes": {
|
||||
"User": "USR", "Session": "SES", "Workflow": "WF", "Package": "PKG",
|
||||
"UiPage": "PG", "Credential": "CRD", "Forum": "FRM", "Notification": "NTF",
|
||||
"AuditLog": "AUD", "Media": "MED"
|
||||
},
|
||||
"columns": {
|
||||
"User": ["ID", "Username", "Email", "Role", "Status", "Created"],
|
||||
"Session": ["ID", "User", "IP Address", "Status", "Started", "Expires"],
|
||||
"Workflow": ["ID", "Name", "Trigger", "Nodes", "Status", "Last Run"],
|
||||
"Package": ["ID", "Name", "Version", "Author", "Status", "Installed"],
|
||||
"UiPage": ["ID", "Title", "Route", "Layout", "Status", "Modified"],
|
||||
"Credential": ["ID", "Label", "Type", "Scope", "Status", "Created"],
|
||||
"Forum": ["ID", "Title", "Author", "Replies", "Status", "Created"],
|
||||
"Notification": ["ID", "Type", "Recipient", "Message", "Status", "Sent"],
|
||||
"AuditLog": ["ID", "Action", "User", "Resource", "Status", "Timestamp"],
|
||||
"Media": ["ID", "Filename", "Type", "Size", "Status", "Uploaded"]
|
||||
},
|
||||
"fields": {
|
||||
"User": ["id", "username", "email", "role", "status", "created"],
|
||||
"Session": ["id", "user", "ip", "status", "started", "expires"],
|
||||
"Workflow": ["id", "name", "trigger", "nodes", "status", "lastRun"],
|
||||
"Package": ["id", "name", "version", "author", "status", "installed"],
|
||||
"UiPage": ["id", "title", "route", "layout", "status", "modified"],
|
||||
"Credential": ["id", "label", "type", "scope", "status", "created"],
|
||||
"Forum": ["id", "title", "author", "replies", "status", "created"],
|
||||
"Notification": ["id", "type", "recipient", "message", "status", "sent"],
|
||||
"AuditLog": ["id", "action", "user", "resource", "status", "timestamp"],
|
||||
"Media": ["id", "filename", "type", "size", "status", "uploaded"]
|
||||
}
|
||||
}
|
||||
84
frontends/qt6/config/admin-mock-data.json
Normal file
84
frontends/qt6/config/admin-mock-data.json
Normal file
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"User": [
|
||||
{ "id": "USR-001", "username": "admin", "email": "admin@metabuilder.io", "role": "god", "status": "Active", "created": "2025-11-02" },
|
||||
{ "id": "USR-002", "username": "jdoe", "email": "jdoe@example.com", "role": "admin", "status": "Active", "created": "2025-12-10" },
|
||||
{ "id": "USR-003", "username": "alice", "email": "alice@devteam.org", "role": "editor", "status": "Active", "created": "2026-01-05" },
|
||||
{ "id": "USR-004", "username": "bob_dev", "email": "bob@contractor.io", "role": "user", "status": "Inactive", "created": "2026-01-18" },
|
||||
{ "id": "USR-005", "username": "carol", "email": "carol@metabuilder.io", "role": "admin", "status": "Active", "created": "2026-02-01" },
|
||||
{ "id": "USR-006", "username": "dave", "email": "dave@external.com", "role": "user", "status": "Active", "created": "2026-02-14" },
|
||||
{ "id": "USR-007", "username": "eve_sec", "email": "eve@security.io", "role": "auditor", "status": "Active", "created": "2026-03-01" },
|
||||
{ "id": "USR-008", "username": "frank", "email": "frank@legacy.net", "role": "user", "status": "Inactive", "created": "2025-09-20" }
|
||||
],
|
||||
"Session": [
|
||||
{ "id": "SES-001", "user": "admin", "ip": "192.168.1.10", "status": "Active", "started": "2026-03-18 08:00", "expires": "2026-03-18 20:00" },
|
||||
{ "id": "SES-002", "user": "jdoe", "ip": "10.0.0.42", "status": "Active", "started": "2026-03-18 09:15", "expires": "2026-03-18 21:15" },
|
||||
{ "id": "SES-003", "user": "alice", "ip": "172.16.0.5", "status": "Active", "started": "2026-03-18 10:30", "expires": "2026-03-18 22:30" },
|
||||
{ "id": "SES-004", "user": "bob_dev", "ip": "192.168.1.88", "status": "Inactive", "started": "2026-03-17 14:00", "expires": "2026-03-17 23:59" },
|
||||
{ "id": "SES-005", "user": "carol", "ip": "10.0.0.101", "status": "Active", "started": "2026-03-18 07:45", "expires": "2026-03-18 19:45" },
|
||||
{ "id": "SES-006", "user": "dave", "ip": "192.168.2.33", "status": "Inactive", "started": "2026-03-16 11:00", "expires": "2026-03-16 23:00" }
|
||||
],
|
||||
"Workflow": [
|
||||
{ "id": "WF-001", "name": "on_user_created", "trigger": "User.created", "nodes": "15", "status": "Active", "lastRun": "2026-03-18 09:01" },
|
||||
{ "id": "WF-002", "name": "on_snippet_saved", "trigger": "Snippet.created", "nodes": "8", "status": "Active", "lastRun": "2026-03-18 08:45" },
|
||||
{ "id": "WF-003", "name": "nightly_cleanup", "trigger": "cron:0 2 * * *", "nodes": "12", "status": "Active", "lastRun": "2026-03-18 02:00" },
|
||||
{ "id": "WF-004", "name": "on_login_failed", "trigger": "Auth.failed", "nodes": "6", "status": "Active", "lastRun": "2026-03-17 23:12" },
|
||||
{ "id": "WF-005", "name": "weekly_report", "trigger": "cron:0 9 * * MON", "nodes": "20", "status": "Inactive", "lastRun": "2026-03-11 09:00" },
|
||||
{ "id": "WF-006", "name": "media_transcode", "trigger": "Media.uploaded", "nodes": "10", "status": "Active", "lastRun": "2026-03-18 07:30" }
|
||||
],
|
||||
"Package": [
|
||||
{ "id": "PKG-001", "name": "forum", "version": "2.1.0", "author": "core-team", "status": "Active", "installed": "2025-12-01" },
|
||||
{ "id": "PKG-002", "name": "guestbook", "version": "1.3.2", "author": "core-team", "status": "Active", "installed": "2025-12-01" },
|
||||
{ "id": "PKG-003", "name": "notifications", "version": "1.8.0", "author": "core-team", "status": "Active", "installed": "2026-01-10" },
|
||||
{ "id": "PKG-004", "name": "media-gallery", "version": "3.0.1", "author": "plugins", "status": "Active", "installed": "2026-01-15" },
|
||||
{ "id": "PKG-005", "name": "irc-bridge", "version": "0.9.0", "author": "community", "status": "Inactive", "installed": "2026-02-05" },
|
||||
{ "id": "PKG-006", "name": "analytics", "version": "1.2.0", "author": "core-team", "status": "Active", "installed": "2026-02-20" },
|
||||
{ "id": "PKG-007", "name": "streaming", "version": "1.0.0", "author": "plugins", "status": "Active", "installed": "2026-03-01" }
|
||||
],
|
||||
"UiPage": [
|
||||
{ "id": "PG-001", "title": "Dashboard", "route": "/", "layout": "full", "status": "Active", "modified": "2026-03-15" },
|
||||
{ "id": "PG-002", "title": "User Profile", "route": "/profile", "layout": "sidebar", "status": "Active", "modified": "2026-03-10" },
|
||||
{ "id": "PG-003", "title": "Settings", "route": "/settings", "layout": "full", "status": "Active", "modified": "2026-03-12" },
|
||||
{ "id": "PG-004", "title": "Admin Panel", "route": "/admin", "layout": "sidebar", "status": "Active", "modified": "2026-03-18" },
|
||||
{ "id": "PG-005", "title": "Workflow Editor", "route": "/workflows", "layout": "canvas", "status": "Active", "modified": "2026-03-14" },
|
||||
{ "id": "PG-006", "title": "Legacy Import", "route": "/import", "layout": "full", "status": "Inactive", "modified": "2026-01-20" }
|
||||
],
|
||||
"Credential": [
|
||||
{ "id": "CRD-001", "label": "SMTP Production", "type": "smtp", "scope": "global", "status": "Active", "created": "2025-12-01" },
|
||||
{ "id": "CRD-002", "label": "AWS S3 Bucket", "type": "aws-s3", "scope": "media", "status": "Active", "created": "2026-01-10" },
|
||||
{ "id": "CRD-003", "label": "GitHub Deploy Key", "type": "ssh-key", "scope": "ci-cd", "status": "Active", "created": "2026-01-20" },
|
||||
{ "id": "CRD-004", "label": "Slack Webhook", "type": "webhook", "scope": "notifications", "status": "Active", "created": "2026-02-05" },
|
||||
{ "id": "CRD-005", "label": "DB Staging", "type": "database", "scope": "staging", "status": "Inactive", "created": "2025-11-15" }
|
||||
],
|
||||
"Forum": [
|
||||
{ "id": "FRM-001", "title": "Welcome to MetaBuilder", "author": "admin", "replies": "24", "status": "Active", "created": "2025-12-05" },
|
||||
{ "id": "FRM-002", "title": "Bug: Workflow not firing", "author": "jdoe", "replies": "8", "status": "Active", "created": "2026-02-10" },
|
||||
{ "id": "FRM-003", "title": "Feature: Dark mode toggle", "author": "alice", "replies": "15", "status": "Active", "created": "2026-02-18" },
|
||||
{ "id": "FRM-004", "title": "How to create custom nodes?", "author": "dave", "replies": "6", "status": "Active", "created": "2026-03-02" },
|
||||
{ "id": "FRM-005", "title": "Migration guide v1 to v2", "author": "carol", "replies": "31", "status": "Active", "created": "2026-01-25" },
|
||||
{ "id": "FRM-006", "title": "Deprecated: Old API docs", "author": "admin", "replies": "2", "status": "Inactive", "created": "2025-10-10" }
|
||||
],
|
||||
"Notification": [
|
||||
{ "id": "NTF-001", "type": "system", "recipient": "all", "message": "Maintenance window 03/20", "status": "Active", "sent": "2026-03-18 06:00" },
|
||||
{ "id": "NTF-002", "type": "alert", "recipient": "admin", "message": "High CPU on dbal-prod", "status": "Active", "sent": "2026-03-18 07:30" },
|
||||
{ "id": "NTF-003", "type": "info", "recipient": "jdoe", "message": "Your export is ready", "status": "Active", "sent": "2026-03-18 09:00" },
|
||||
{ "id": "NTF-004", "type": "warning", "recipient": "eve_sec", "message": "3 failed login attempts", "status": "Active", "sent": "2026-03-18 08:15" },
|
||||
{ "id": "NTF-005", "type": "system", "recipient": "all", "message": "v2.1.0 deployed", "status": "Inactive", "sent": "2026-03-15 12:00" }
|
||||
],
|
||||
"AuditLog": [
|
||||
{ "id": "AUD-001", "action": "user.login", "user": "admin", "resource": "auth/session", "status": "Active", "timestamp": "2026-03-18 08:00" },
|
||||
{ "id": "AUD-002", "action": "record.create", "user": "jdoe", "resource": "forum/post", "status": "Active", "timestamp": "2026-03-18 08:30" },
|
||||
{ "id": "AUD-003", "action": "record.update", "user": "alice", "resource": "workflow/WF-001", "status": "Active", "timestamp": "2026-03-18 09:01" },
|
||||
{ "id": "AUD-004", "action": "user.logout", "user": "bob_dev", "resource": "auth/session", "status": "Active", "timestamp": "2026-03-17 18:00" },
|
||||
{ "id": "AUD-005", "action": "record.delete", "user": "admin", "resource": "media/MED-003", "status": "Active", "timestamp": "2026-03-18 07:45" },
|
||||
{ "id": "AUD-006", "action": "config.change", "user": "carol", "resource": "settings/smtp", "status": "Active", "timestamp": "2026-03-17 16:30" },
|
||||
{ "id": "AUD-007", "action": "auth.failed", "user": "unknown", "resource": "auth/login", "status": "Active", "timestamp": "2026-03-18 08:12" }
|
||||
],
|
||||
"Media": [
|
||||
{ "id": "MED-001", "filename": "logo-dark.svg", "type": "image/svg", "size": "12 KB", "status": "Active", "uploaded": "2026-01-05" },
|
||||
{ "id": "MED-002", "filename": "hero-banner.png", "type": "image/png", "size": "2.4 MB", "status": "Active", "uploaded": "2026-02-10" },
|
||||
{ "id": "MED-003", "filename": "intro-video.mp4", "type": "video/mp4", "size": "48 MB", "status": "Active", "uploaded": "2026-02-20" },
|
||||
{ "id": "MED-004", "filename": "user-guide.pdf", "type": "application/pdf", "size": "1.1 MB", "status": "Active", "uploaded": "2026-03-01" },
|
||||
{ "id": "MED-005", "filename": "old-theme.css", "type": "text/css", "size": "85 KB", "status": "Inactive", "uploaded": "2025-09-15" },
|
||||
{ "id": "MED-006", "filename": "avatar-defaults.zip", "type": "application/zip", "size": "5.6 MB", "status": "Active", "uploaded": "2026-03-10" }
|
||||
]
|
||||
}
|
||||
13
frontends/qt6/config/app-config.json
Normal file
13
frontends/qt6/config/app-config.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"seedUsers": [
|
||||
{ "username": "demo", "password": "demo", "role": "user", "level": 2 },
|
||||
{ "username": "mod", "password": "mod", "role": "moderator", "level": 3 },
|
||||
{ "username": "admin", "password": "admin", "role": "admin", "level": 4 },
|
||||
{ "username": "god", "password": "god123", "role": "god", "level": 5 },
|
||||
{ "username": "super", "password": "super123", "role": "supergod", "level": 6 }
|
||||
],
|
||||
"staticViews": [
|
||||
"frontpage", "login", "dashboard", "profile",
|
||||
"moderator", "admin", "god-panel", "supergod", "settings", "comments"
|
||||
]
|
||||
}
|
||||
56
frontends/qt6/config/comments-mock.json
Normal file
56
frontends/qt6/config/comments-mock.json
Normal file
@@ -0,0 +1,56 @@
|
||||
[
|
||||
{
|
||||
"commentId": 1,
|
||||
"username": "alice",
|
||||
"initials": "AL",
|
||||
"timestamp": "2026-03-18 09:42",
|
||||
"body": "Just deployed the new workflow engine -- the event-driven architecture is really clean. Great work on the JSON config approach!",
|
||||
"likes": 12,
|
||||
"liked": false
|
||||
},
|
||||
{
|
||||
"commentId": 2,
|
||||
"username": "demo",
|
||||
"initials": "DE",
|
||||
"timestamp": "2026-03-18 09:15",
|
||||
"body": "Has anyone tested the Redis caching layer with the read-through pattern? Seeing some impressive latency improvements.",
|
||||
"likes": 8,
|
||||
"liked": true
|
||||
},
|
||||
{
|
||||
"commentId": 3,
|
||||
"username": "bob",
|
||||
"initials": "BO",
|
||||
"timestamp": "2026-03-17 22:30",
|
||||
"body": "The FakeMUI component library is coming along nicely. 167 components and counting!",
|
||||
"likes": 5,
|
||||
"liked": false
|
||||
},
|
||||
{
|
||||
"commentId": 4,
|
||||
"username": "charlie",
|
||||
"initials": "CH",
|
||||
"timestamp": "2026-03-17 18:05",
|
||||
"body": "Quick question: is there a recommended way to add custom seed data for a new package? The declarative JSON approach in dbal/shared/seeds/database looks straightforward.",
|
||||
"likes": 3,
|
||||
"liked": false
|
||||
},
|
||||
{
|
||||
"commentId": 5,
|
||||
"username": "demo",
|
||||
"initials": "DE",
|
||||
"timestamp": "2026-03-17 14:20",
|
||||
"body": "Updated the forum package schema to include threaded replies. Pull request is up for review.",
|
||||
"likes": 15,
|
||||
"liked": false
|
||||
},
|
||||
{
|
||||
"commentId": 6,
|
||||
"username": "eve",
|
||||
"initials": "EV",
|
||||
"timestamp": "2026-03-16 11:00",
|
||||
"body": "The Qt6 frontend is shaping up well. Love the CCard and CListItem components -- consistent styling across all views.",
|
||||
"likes": 7,
|
||||
"liked": false
|
||||
}
|
||||
]
|
||||
32
frontends/qt6/config/frontpage-data.json
Normal file
32
frontends/qt6/config/frontpage-data.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"levels": [
|
||||
{ "level": 1, "name": "Guest", "accentKey": "slate", "desc": "Explore the platform. Component library, storybook, and public API.", "tags": ["Landing", "Storybook", "Docs"] },
|
||||
{ "level": 2, "name": "User", "accentKey": "blue", "desc": "Your space. Dashboard, profile, forum, gallery, and packages.", "tags": ["Dashboard", "Profile", "Forum", "Gallery"] },
|
||||
{ "level": 3, "name": "Moderator", "accentKey": "cyan", "desc": "Community management. Moderate content, manage reports, user warnings.", "tags": ["Moderation", "Reports", "Warnings"] },
|
||||
{ "level": 4, "name": "Admin", "accentKey": "amber", "desc": "System administration. User tables, audit logs, entity management.", "tags": ["Users", "Audit", "Entities", "Config"] },
|
||||
{ "level": 5, "name": "God", "accentKey": "violet", "desc": "The builder tier. Visual workflows, schema browser, 14 power tools.", "tags": ["Workflows", "Schemas", "Pages", "14 tools"] },
|
||||
{ "level": 6, "name": "Super God", "accentKey": "rose", "desc": "Platform control. Multi-tenant management, system overrides.", "tags": ["Tenants", "Config", "Promote"] }
|
||||
],
|
||||
"techStack": [
|
||||
{ "name": "Qt6 / QML", "desc": "Native desktop frontend", "accentKey": "blue" },
|
||||
{ "name": "Next.js", "desc": "React web frontend", "accentKey": "cyan" },
|
||||
{ "name": "C++ DBAL", "desc": "14-backend database abstraction", "accentKey": "violet" },
|
||||
{ "name": "JSON Workflows", "desc": "152 node types, visual DAG editor", "accentKey": "amber" },
|
||||
{ "name": "C++ CLI", "desc": "Headless command interface", "accentKey": "slate" },
|
||||
{ "name": "Docker", "desc": "One-command stack deployment", "accentKey": "cyan" }
|
||||
],
|
||||
"services": [
|
||||
{ "name": "DBAL Daemon", "statusKey": "dbal" },
|
||||
{ "name": "PostgreSQL", "statusKey": "standby" },
|
||||
{ "name": "Redis Cache", "statusKey": "standby" },
|
||||
{ "name": "Workflow Engine", "statusKey": "dbal" },
|
||||
{ "name": "Media Service", "statusKey": "standby" }
|
||||
],
|
||||
"quickCreds": [
|
||||
{ "user": "demo", "pass": "demo", "label": "User", "level": 2, "accentKey": "blue" },
|
||||
{ "user": "mod", "pass": "mod", "label": "Moderator", "level": 3, "accentKey": "cyan" },
|
||||
{ "user": "admin", "pass": "admin", "label": "Admin", "level": 4, "accentKey": "amber" },
|
||||
{ "user": "god", "pass": "god123", "label": "God", "level": 5, "accentKey": "violet" },
|
||||
{ "user": "super", "pass": "super123", "label": "Super God", "level": 6, "accentKey": "rose" }
|
||||
]
|
||||
}
|
||||
10
frontends/qt6/config/god-panel-config-stats.json
Normal file
10
frontends/qt6/config/god-panel-config-stats.json
Normal file
@@ -0,0 +1,10 @@
|
||||
[
|
||||
{ "label": "Schemas", "valueKey": "schemas", "accentName": "blue" },
|
||||
{ "label": "Workflows", "valueKey": "workflows", "accentName": "cyan" },
|
||||
{ "label": "Lua Scripts", "valueKey": "luaScripts", "accentName": "violet" },
|
||||
{ "label": "Packages", "valueKey": "packages", "accentName": "blue" },
|
||||
{ "label": "Pages", "valueKey": "pages", "accentName": "cyan" },
|
||||
{ "label": "Components", "valueKey": "components", "accentName": "violet" },
|
||||
{ "label": "CSS Classes", "valueKey": "cssClasses", "accentName": "amber" },
|
||||
{ "label": "DB Backends", "valueKey": "dbBackends", "accentName": "rose" }
|
||||
]
|
||||
32
frontends/qt6/config/god-panel-levels.json
Normal file
32
frontends/qt6/config/god-panel-levels.json
Normal file
@@ -0,0 +1,32 @@
|
||||
[
|
||||
{
|
||||
"level": "Level 1 - Public",
|
||||
"role": "public",
|
||||
"accentIndex": 0,
|
||||
"desc": "Landing page, public content, registration. No authentication required. Read-only access to published pages and packages."
|
||||
},
|
||||
{
|
||||
"level": "Level 2 - User",
|
||||
"role": "user",
|
||||
"accentIndex": 1,
|
||||
"desc": "Authenticated user dashboard. Access to forum, gallery, guestbook, blog, profile. Personal content creation and community interaction."
|
||||
},
|
||||
{
|
||||
"level": "Level 3 - Admin",
|
||||
"role": "admin",
|
||||
"accentIndex": 2,
|
||||
"desc": "Django-style entity admin panel. CRUD operations on all entities, audit logs, analytics, watchtower monitoring. User management within tenant."
|
||||
},
|
||||
{
|
||||
"level": "Level 4 - God Builder",
|
||||
"role": "god",
|
||||
"accentIndex": 3,
|
||||
"desc": "Full builder cockpit (this panel). Schema editor, workflow designer, Lua scripting, page routing, component hierarchy, CSS classes, dropdown configs, database management, and system settings."
|
||||
},
|
||||
{
|
||||
"level": "Level 5 - Super God",
|
||||
"role": "supergod",
|
||||
"accentIndex": 4,
|
||||
"desc": "Cross-tenant platform control. Infrastructure management, deployment orchestration, multi-tenant provisioning, global configuration, and platform-wide observability."
|
||||
}
|
||||
]
|
||||
16
frontends/qt6/config/god-panel-tabs.json
Normal file
16
frontends/qt6/config/god-panel-tabs.json
Normal file
@@ -0,0 +1,16 @@
|
||||
[
|
||||
{ "label": "Guide" },
|
||||
{ "label": "Packages", "source": "PackageManager.qml" },
|
||||
{ "label": "Page Routes", "source": "PageRoutesManager.qml" },
|
||||
{ "label": "Components", "source": "ComponentHierarchyEditor.qml" },
|
||||
{ "label": "Users", "source": "UserManagement.qml" },
|
||||
{ "label": "Schemas", "source": "SchemaEditor.qml" },
|
||||
{ "label": "Workflows", "source": "WorkflowEditor.qml" },
|
||||
{ "label": "Lua Scripts", "source": "LuaEditor.qml" },
|
||||
{ "label": "Snippets", "source": "LuaEditor.qml" },
|
||||
{ "label": "CSS Classes", "source": "CssClassManager.qml" },
|
||||
{ "label": "Dropdowns", "source": "DropdownConfigManager.qml" },
|
||||
{ "label": "Database", "source": "DatabaseManager.qml" },
|
||||
{ "label": "Media", "source": "MediaServicePanel.qml" },
|
||||
{ "label": "Settings" }
|
||||
]
|
||||
34
frontends/qt6/config/profile-mock.json
Normal file
34
frontends/qt6/config/profile-mock.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"defaults": {
|
||||
"bio": "MetaBuilder enthusiast and open-source contributor.",
|
||||
"email": "demo@metabuilder.io"
|
||||
},
|
||||
"activityStats": [
|
||||
{ "label": "Posts", "value": "42" },
|
||||
{ "label": "Comments", "value": "128" },
|
||||
{ "label": "Last Login", "value": "Today, 09:15" }
|
||||
],
|
||||
"passwordFields": [
|
||||
{ "key": "current", "label": "Current Password", "placeholder": "Enter current password" },
|
||||
{ "key": "new", "label": "New Password", "placeholder": "Enter new password" },
|
||||
{ "key": "confirm", "label": "Confirm New Password", "placeholder": "Re-enter new password" }
|
||||
],
|
||||
"connectedAccounts": [
|
||||
{
|
||||
"service": "GitHub",
|
||||
"icon": "github",
|
||||
"linked": true,
|
||||
"statusText": "Connected",
|
||||
"statusType": "success",
|
||||
"unlinkLabel": "Unlink"
|
||||
},
|
||||
{
|
||||
"service": "Discord",
|
||||
"icon": "discord",
|
||||
"linked": false,
|
||||
"statusText": "Not Connected",
|
||||
"statusType": "warning",
|
||||
"linkLabel": "Link Account"
|
||||
}
|
||||
]
|
||||
}
|
||||
6
frontends/qt6/config/settings-about.json
Normal file
6
frontends/qt6/config/settings-about.json
Normal file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{ "label": "Version", "value": "2.1.0" },
|
||||
{ "label": "Build Date", "value": "2026-03-19" },
|
||||
{ "label": "Qt Version", "value": "6.8.x" },
|
||||
{ "label": "DBAL Schema", "value": "v1 REST API" }
|
||||
]
|
||||
5
frontends/qt6/config/settings-font-sizes.json
Normal file
5
frontends/qt6/config/settings-font-sizes.json
Normal file
@@ -0,0 +1,5 @@
|
||||
[
|
||||
{ "id": "small", "label": "Small" },
|
||||
{ "id": "medium", "label": "Medium" },
|
||||
{ "id": "large", "label": "Large" }
|
||||
]
|
||||
20
frontends/qt6/config/settings-notifications.json
Normal file
20
frontends/qt6/config/settings-notifications.json
Normal file
@@ -0,0 +1,20 @@
|
||||
[
|
||||
{
|
||||
"id": "emailNotifications",
|
||||
"title": "Email Notifications",
|
||||
"description": "Receive notification summaries via email",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"id": "desktopNotifications",
|
||||
"title": "Desktop Notifications",
|
||||
"description": "Show desktop push notifications for alerts",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"id": "soundAlerts",
|
||||
"title": "Sound Alerts",
|
||||
"description": "Play a sound when new notifications arrive",
|
||||
"defaultValue": false
|
||||
}
|
||||
]
|
||||
7
frontends/qt6/config/supergod-god-users.json
Normal file
7
frontends/qt6/config/supergod-god-users.json
Normal file
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{ "username": "admin", "initials": "AD", "role": "supergod", "level": 5, "tenant": "default", "status": "online" },
|
||||
{ "username": "platform-admin", "initials": "PA", "role": "supergod", "level": 5, "tenant": "production", "status": "online" },
|
||||
{ "username": "devops", "initials": "DO", "role": "god", "level": 4, "tenant": "staging", "status": "online" },
|
||||
{ "username": "builder01", "initials": "B1", "role": "god", "level": 4, "tenant": "default", "status": "offline" },
|
||||
{ "username": "builder02", "initials": "B2", "role": "god", "level": 4, "tenant": "production", "status": "away" }
|
||||
]
|
||||
14
frontends/qt6/config/supergod-system-metrics.json
Normal file
14
frontends/qt6/config/supergod-system-metrics.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"daemons": [
|
||||
{ "name": "DBAL", "status": "healthy", "uptime": "14d 7h 32m", "port": 8080 },
|
||||
{ "name": "Nginx", "status": "healthy", "uptime": "14d 7h 30m", "port": 443 },
|
||||
{ "name": "PostgreSQL", "status": "healthy", "uptime": "14d 6h 55m", "port": 5432 },
|
||||
{ "name": "Redis", "status": "degraded", "uptime": "2d 1h 12m", "port": 6379 }
|
||||
],
|
||||
"metrics": {
|
||||
"cpu": 34,
|
||||
"memory": 62,
|
||||
"disk": 47,
|
||||
"network": 18
|
||||
}
|
||||
}
|
||||
5
frontends/qt6/config/supergod-tenants.json
Normal file
5
frontends/qt6/config/supergod-tenants.json
Normal file
@@ -0,0 +1,5 @@
|
||||
[
|
||||
{ "name": "default", "owner": "admin", "status": "active", "homepage": "/", "created": "2025-01-15" },
|
||||
{ "name": "staging", "owner": "devops", "status": "active", "homepage": "/staging", "created": "2025-06-01" },
|
||||
{ "name": "production", "owner": "platform-admin", "status": "active", "homepage": "/prod", "created": "2025-08-20" }
|
||||
]
|
||||
10
frontends/qt6/config/supergod-transfers.json
Normal file
10
frontends/qt6/config/supergod-transfers.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"pending": [
|
||||
{ "from": "admin", "to": "devops", "reason": "Scheduled maintenance window", "expiry": "2026-03-25", "status": "pending" }
|
||||
],
|
||||
"history": [
|
||||
{ "from": "platform-admin", "to": "admin", "reason": "Emergency access grant", "date": "2026-02-10 14:32", "status": "approved" },
|
||||
{ "from": "admin", "to": "builder01", "reason": "Sprint deployment authority", "date": "2026-01-28 09:15", "status": "approved" },
|
||||
{ "from": "devops", "to": "admin", "reason": "Incident response escalation", "date": "2025-12-05 22:47", "status": "denied" }
|
||||
]
|
||||
}
|
||||
114
frontends/qt6/config/workflow-mock-data.json
Normal file
114
frontends/qt6/config/workflow-mock-data.json
Normal file
@@ -0,0 +1,114 @@
|
||||
[
|
||||
{
|
||||
"name": "on_user_created",
|
||||
"active": true,
|
||||
"settings": {},
|
||||
"tags": [{ "name": "pastebin" }],
|
||||
"meta": { "description": "Triggered when a new user is created" },
|
||||
"variables": {},
|
||||
"nodes": [
|
||||
{
|
||||
"id": "trigger_1",
|
||||
"name": "UserCreatedEvent",
|
||||
"type": "metabuilder.trigger",
|
||||
"position": [50, 200],
|
||||
"parameters": { "triggerType": "webhook" },
|
||||
"inputs": [],
|
||||
"outputs": [{ "name": "main", "type": "main" }]
|
||||
},
|
||||
{
|
||||
"id": "condition_1",
|
||||
"name": "CheckEmailVerified",
|
||||
"type": "logic.if",
|
||||
"position": [300, 200],
|
||||
"parameters": {},
|
||||
"inputs": [{ "name": "main", "type": "main" }],
|
||||
"outputs": [{ "name": "main", "type": "main" }, { "name": "error", "type": "error" }]
|
||||
},
|
||||
{
|
||||
"id": "action_1",
|
||||
"name": "CreateDefaultNS",
|
||||
"type": "integration.http_request",
|
||||
"position": [550, 100],
|
||||
"parameters": { "url": "/api/namespaces" },
|
||||
"inputs": [{ "name": "main", "type": "main" }],
|
||||
"outputs": [{ "name": "main", "type": "main" }]
|
||||
},
|
||||
{
|
||||
"id": "action_2",
|
||||
"name": "CreateExamplesNS",
|
||||
"type": "integration.http_request",
|
||||
"position": [550, 300],
|
||||
"parameters": { "url": "/api/namespaces" },
|
||||
"inputs": [{ "name": "main", "type": "main" }],
|
||||
"outputs": [{ "name": "main", "type": "main" }]
|
||||
},
|
||||
{
|
||||
"id": "action_3",
|
||||
"name": "SendWelcomeEmail",
|
||||
"type": "integration.send_email",
|
||||
"position": [800, 200],
|
||||
"parameters": { "template": "welcome" },
|
||||
"inputs": [{ "name": "main", "type": "main" }],
|
||||
"outputs": []
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"trigger_1": { "main": { "0": [{ "node": "condition_1", "type": "main", "index": 0 }] } },
|
||||
"condition_1": { "main": { "0": [{ "node": "action_1", "type": "main", "index": 0 }, { "node": "action_2", "type": "main", "index": 0 }] } },
|
||||
"action_1": { "main": { "0": [{ "node": "action_3", "type": "main", "index": 0 }] } },
|
||||
"action_2": { "main": { "0": [{ "node": "action_3", "type": "main", "index": 0 }] } }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "daily_cleanup",
|
||||
"active": true,
|
||||
"settings": { "executionTimeout": 300 },
|
||||
"tags": [{ "name": "cron" }, { "name": "maintenance" }],
|
||||
"meta": { "description": "Nightly cleanup of expired sessions and old audit logs" },
|
||||
"variables": {},
|
||||
"nodes": [
|
||||
{
|
||||
"id": "cron_1",
|
||||
"name": "CronSchedule",
|
||||
"type": "metabuilder.trigger",
|
||||
"position": [50, 150],
|
||||
"parameters": { "triggerType": "schedule" },
|
||||
"inputs": [],
|
||||
"outputs": [{ "name": "main", "type": "main" }]
|
||||
},
|
||||
{
|
||||
"id": "expire_1",
|
||||
"name": "ExpireSessions",
|
||||
"type": "integration.http_request",
|
||||
"position": [300, 80],
|
||||
"parameters": {},
|
||||
"inputs": [{ "name": "main", "type": "main" }],
|
||||
"outputs": [{ "name": "main", "type": "main" }]
|
||||
},
|
||||
{
|
||||
"id": "purge_1",
|
||||
"name": "PurgeAuditLogs",
|
||||
"type": "integration.http_request",
|
||||
"position": [300, 250],
|
||||
"parameters": {},
|
||||
"inputs": [{ "name": "main", "type": "main" }],
|
||||
"outputs": [{ "name": "main", "type": "main" }]
|
||||
},
|
||||
{
|
||||
"id": "agg_1",
|
||||
"name": "AggregateMetrics",
|
||||
"type": "transform.aggregate",
|
||||
"position": [550, 150],
|
||||
"parameters": {},
|
||||
"inputs": [{ "name": "main", "type": "main" }],
|
||||
"outputs": [{ "name": "main", "type": "main" }]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"cron_1": { "main": { "0": [{ "node": "expire_1", "type": "main", "index": 0 }, { "node": "purge_1", "type": "main", "index": 0 }] } },
|
||||
"expire_1": { "main": { "0": [{ "node": "agg_1", "type": "main", "index": 0 }] } },
|
||||
"purge_1": { "main": { "0": [{ "node": "agg_1", "type": "main", "index": 0 }] } }
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -23,6 +23,9 @@ CQuickLoginCard 1.0 CQuickLoginCard.qml
|
||||
CAdminStatsBar 1.0 CAdminStatsBar.qml
|
||||
CEntitySidebar 1.0 CEntitySidebar.qml
|
||||
CDataTable 1.0 CDataTable.qml
|
||||
CTableHeader 1.0 CTableHeader.qml
|
||||
CTablePagination 1.0 CTablePagination.qml
|
||||
CDropdownMenu 1.0 CDropdownMenu.qml
|
||||
CEntityForm 1.0 CEntityForm.qml
|
||||
CGodPanelHeader 1.0 CGodPanelHeader.qml
|
||||
CLevelReferenceCard 1.0 CLevelReferenceCard.qml
|
||||
@@ -96,4 +99,5 @@ CSmtpTemplateList 1.0 CSmtpTemplateList.qml
|
||||
CSmtpTemplateEditor 1.0 CSmtpTemplateEditor.qml
|
||||
CCanvasGrid 1.0 CCanvasGrid.qml
|
||||
CCanvasZoomOverlay 1.0 CCanvasZoomOverlay.qml
|
||||
CNotificationToggles 1.0 CNotificationToggles.qml
|
||||
CWorkflowNodeDelegate 1.0 CWorkflowNodeDelegate.qml
|
||||
|
||||
Reference in New Issue
Block a user