feat(qt6): MD3 rework all views — Dashboard, Profile, Admin, SuperGod, Comments, Settings

- Fix CCard content nesting (no anchors.fill inside CCard)
- chipColor/badgeColor string→Theme color fixes
- anchors-in-layout warnings resolved
- Tonal surfaces, proper MD3 spacing
- CButton replaces hand-rolled Rectangle buttons
- All 6 views preserved with full functionality

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-19 09:26:42 +00:00
parent cb96431a12
commit c4f72ded99
6 changed files with 986 additions and 934 deletions

View File

@@ -6,7 +6,7 @@ import "qmllib/dbal"
Rectangle {
id: root
color: "transparent"
color: Theme.background
// ── DBAL connection ──────────────────────────────────────────
DBALProvider { id: dbal }
@@ -239,7 +239,6 @@ Rectangle {
function deleteRecord(idx) {
var data = records[selectedEntity].slice();
var filtered = getFilteredRecords();
var actualRec = getPagedRecords()[idx];
for (var i = 0; i < data.length; i++) {
if (data[i].id === actualRec.id) {
@@ -326,10 +325,9 @@ Rectangle {
// ── Stats bar ──────────────────────────────────────────────
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 80
color: Theme.paper
border.color: Theme.border
border.width: 1
Layout.preferredHeight: 88
color: Theme.surface
radius: 0
RowLayout {
anchors.fill: parent
@@ -349,8 +347,7 @@ Rectangle {
Layout.fillHeight: true
RowLayout {
anchors.fill: parent
anchors.margins: 12
Layout.fillWidth: true
spacing: 8
Rectangle {
@@ -382,9 +379,7 @@ Rectangle {
Rectangle {
Layout.preferredWidth: 220
Layout.fillHeight: true
color: Theme.paper
border.color: Theme.border
border.width: 1
color: Theme.surface
ColumnLayout {
anchors.fill: parent
@@ -418,7 +413,7 @@ Rectangle {
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: "transparent"
color: Theme.background
ColumnLayout {
anchors.fill: parent
@@ -466,6 +461,7 @@ Rectangle {
delegate: CChip {
text: modelData
checked: activeFilter === modelData
chipColor: activeFilter === modelData ? Theme.primary : Theme.surface
onClicked: { activeFilter = modelData; currentPage = 0; }
}
}
@@ -487,15 +483,15 @@ Rectangle {
Layout.fillHeight: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 1
Layout.fillWidth: true
spacing: 0
// ── Column headers ────────────────────
Rectangle {
Layout.fillWidth: true
height: 44
color: Theme.surface
color: Theme.surfaceVariant
radius: 0
RowLayout {
anchors.fill: parent
@@ -557,8 +553,9 @@ Rectangle {
color: {
if (selectedRow === rowIndex) return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
if (selectedRows[rowIndex]) return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.06);
return rowIndex % 2 === 0 ? "transparent" : Qt.rgba(Theme.surface.r, Theme.surface.g, Theme.surface.b, 0.4);
return rowIndex % 2 === 0 ? "transparent" : Theme.surfaceVariant;
}
radius: 0
MouseArea {
anchors.fill: parent
@@ -638,11 +635,24 @@ Rectangle {
visible: totalFiltered() === 0
Layout.preferredHeight: visible ? 120 : 0
CText {
ColumnLayout {
anchors.centerIn: parent
variant: "body1"
text: "No records found"
color: Theme.textSecondary
spacing: 8
CText {
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
variant: "h4"
text: "No records found"
color: Theme.textSecondary
}
CText {
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
variant: "caption"
text: "Try adjusting your search or filter criteria."
color: Theme.textMuted
}
}
}
@@ -652,7 +662,8 @@ Rectangle {
Rectangle {
Layout.fillWidth: true
height: 48
color: Theme.surface
color: Theme.surfaceVariant
radius: 0
RowLayout {
anchors.fill: parent

View File

@@ -168,6 +168,7 @@ Rectangle {
CBadge {
text: commentsModel.count + " comments"
badgeColor: Theme.info
}
Item { Layout.fillWidth: true }
@@ -186,32 +187,26 @@ Rectangle {
CCard {
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 12
CText { variant: "subtitle1"; text: "Post a Comment" }
CText { variant: "subtitle1"; text: "Post a Comment" }
CTextField {
Layout.fillWidth: true
label: "Your comment"
placeholderText: "Write your thoughts..."
text: newCommentText
onTextChanged: newCommentText = text
}
CTextField {
Layout.fillWidth: true
label: "Your comment"
placeholderText: "Write your thoughts..."
text: newCommentText
onTextChanged: newCommentText = text
}
FlexRow {
Layout.fillWidth: true
spacing: 8
Item { Layout.fillWidth: true }
CButton {
text: "Post Comment"
variant: "primary"
size: "sm"
enabled: newCommentText.trim().length > 0
onClicked: addComment()
}
FlexRow {
Layout.fillWidth: true
spacing: 8
Item { Layout.fillWidth: true }
CButton {
text: "Post Comment"
variant: "primary"
size: "sm"
enabled: newCommentText.trim().length > 0
onClicked: addComment()
}
}
}
@@ -223,88 +218,83 @@ Rectangle {
delegate: CCard {
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 10
// Comment header: avatar, user, time
FlexRow {
Layout.fillWidth: true
spacing: 12
// Comment header: avatar, user, time
FlexRow {
CAvatar {
initials: model.initials
}
ColumnLayout {
Layout.fillWidth: true
spacing: 12
CAvatar {
initials: model.initials
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
FlexRow {
spacing: 8
CText {
variant: "subtitle1"
text: model.username
}
CChip {
text: model.username === appWindow.currentUser ? "You" : ""
visible: model.username === appWindow.currentUser
}
}
spacing: 2
FlexRow {
spacing: 8
CText {
variant: "caption"
text: model.timestamp
variant: "subtitle1"
text: model.username
}
}
}
// Comment body
CText {
Layout.fillWidth: true
variant: "body1"
text: model.body
wrapMode: Text.WordWrap
}
CDivider { Layout.fillWidth: true }
// Actions row
FlexRow {
Layout.fillWidth: true
spacing: 8
CButton {
text: model.liked ? "Liked (" + model.likes + ")" : "Like (" + model.likes + ")"
variant: model.liked ? "primary" : "ghost"
size: "sm"
onClicked: {
var newLikes;
if (model.liked) {
newLikes = model.likes - 1;
commentsModel.setProperty(index, "likes", newLikes)
commentsModel.setProperty(index, "liked", false)
} else {
newLikes = model.likes + 1;
commentsModel.setProperty(index, "likes", newLikes)
commentsModel.setProperty(index, "liked", true)
}
likeCommentOnDBAL(model.commentId, newLikes)
CChip {
text: model.username === appWindow.currentUser ? "You" : ""
chipColor: Theme.primary
visible: model.username === appWindow.currentUser
}
}
Item { Layout.fillWidth: true }
CText {
variant: "caption"
text: model.timestamp
}
}
}
CButton {
text: "Delete"
variant: "danger"
size: "sm"
visible: canDelete(model.username)
onClicked: {
deleteCommentOnDBAL(model.commentId)
commentsModel.remove(index)
// Comment body
CText {
Layout.fillWidth: true
variant: "body1"
text: model.body
wrapMode: Text.WordWrap
}
CDivider { Layout.fillWidth: true }
// Actions row
FlexRow {
Layout.fillWidth: true
spacing: 8
CButton {
text: model.liked ? "Liked (" + model.likes + ")" : "Like (" + model.likes + ")"
variant: model.liked ? "primary" : "ghost"
size: "sm"
onClicked: {
var newLikes;
if (model.liked) {
newLikes = model.likes - 1;
commentsModel.setProperty(index, "likes", newLikes)
commentsModel.setProperty(index, "liked", false)
} else {
newLikes = model.likes + 1;
commentsModel.setProperty(index, "likes", newLikes)
commentsModel.setProperty(index, "liked", true)
}
likeCommentOnDBAL(model.commentId, newLikes)
}
}
Item { Layout.fillWidth: true }
CButton {
text: "Delete"
variant: "danger"
size: "sm"
visible: canDelete(model.username)
onClicked: {
deleteCommentOnDBAL(model.commentId)
commentsModel.remove(index)
}
}
}
@@ -316,22 +306,22 @@ Rectangle {
Layout.fillWidth: true
visible: commentsModel.count === 0
ColumnLayout {
anchors.fill: parent
anchors.margins: 40
spacing: 12
Item { Layout.preferredHeight: 24 }
CText {
Layout.alignment: Qt.AlignHCenter
variant: "h4"
text: "No comments yet"
}
CText {
Layout.alignment: Qt.AlignHCenter
variant: "body2"
text: "Be the first to start the discussion!"
}
CText {
Layout.fillWidth: true
variant: "h4"
text: "No comments yet"
horizontalAlignment: Text.AlignHCenter
}
CText {
Layout.fillWidth: true
variant: "body2"
text: "Be the first to start the discussion!"
horizontalAlignment: Text.AlignHCenter
}
Item { Layout.preferredHeight: 24 }
}
// Bottom spacer

View File

@@ -6,7 +6,7 @@ import "qmllib/dbal"
Rectangle {
id: dashRoot
color: "transparent"
color: Theme.background
// ── DBAL connection ──────────────────────────────────────────
DBALProvider { id: dbal }
@@ -14,6 +14,13 @@ Rectangle {
property var healthData: ({})
property bool dbalOnline: dbal.connected
// ── MD3 palette ──────────────────────────────────────────────
readonly property bool isDark: Theme.mode === "dark"
readonly property color surfaceContainer: isDark ? Qt.rgba(1, 1, 1, 0.05) : Qt.rgba(0.31, 0.31, 0.44, 0.06)
readonly property color surfaceContainerHigh: isDark ? Qt.rgba(1, 1, 1, 0.08) : Qt.rgba(0.31, 0.31, 0.44, 0.10)
readonly property color onSurface: Theme.text
readonly property color onSurfaceVariant: Theme.textSecondary
function refreshDBAL() {
dbal.ping(function(success, error) {
if (success) {
@@ -28,43 +35,55 @@ Rectangle {
ScrollView {
anchors.fill: parent
anchors.margins: 24
clip: true
contentWidth: availableWidth
ColumnLayout {
width: parent.width
spacing: 20
spacing: 0
// Welcome header
Item { Layout.preferredHeight: 24 }
// ── Welcome header ───────────────────────────────────
CCard {
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 24
spacing: 12
Layout.leftMargin: 24
Layout.rightMargin: 24
variant: "filled"
CText {
variant: "h3"
text: "Welcome back, " + appWindow.currentUser
}
CText {
variant: "body1"
text: "Level " + appWindow.currentLevel + " \u00b7 " + appWindow.currentRole + " access"
}
CText {
Layout.fillWidth: true
variant: "h3"
text: "Welcome back, " + appWindow.currentUser
}
CButton {
text: dbal.loading ? "Refreshing..." : "Refresh"
variant: "ghost"
size: "sm"
enabled: !dbal.loading
onClicked: refreshDBAL()
}
Item { Layout.preferredHeight: 4 }
CText {
Layout.fillWidth: true
variant: "body1"
text: "Level " + appWindow.currentLevel + " \u00b7 " + appWindow.currentRole + " access"
color: onSurfaceVariant
}
Item { Layout.preferredHeight: 12 }
CButton {
text: dbal.loading ? "Refreshing..." : "Refresh"
variant: "ghost"
size: "sm"
enabled: !dbal.loading
onClicked: refreshDBAL()
}
}
// Stats row
Item { Layout.preferredHeight: 16 }
// ── Stats row ────────────────────────────────────────
FlexRow {
Layout.fillWidth: true
Layout.leftMargin: 24
Layout.rightMargin: 24
spacing: 16
Repeater {
@@ -76,67 +95,100 @@ Rectangle {
]
delegate: CCard {
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 16
spacing: 8
CText { variant: "caption"; text: modelData.title }
CText { variant: "h3"; text: modelData.value }
CStatusBadge { status: modelData.status; text: modelData.status === "success" ? "Online" : "Active" }
}
}
}
}
variant: "outlined"
// Recent activity
CCard {
Layout.fillWidth: true
title: "Recent Activity"
ColumnLayout {
anchors.fill: parent
anchors.margins: 16
spacing: 8
CText { variant: "h4"; text: "Recent Activity" }
CDivider { Layout.fillWidth: true }
Repeater {
model: [
{ action: "Package installed", detail: "material_ui v2.1.0", time: "2 min ago" },
{ action: "User logged in", detail: "admin", time: "5 min ago" },
{ action: "Workflow executed", detail: "on_user_created", time: "12 min ago" },
{ action: "Schema updated", detail: "forum entity", time: "1 hr ago" },
{ action: "Seed data loaded", detail: "5 namespaces", time: "2 hr ago" }
]
delegate: CListItem {
CText {
Layout.fillWidth: true
title: modelData.action
subtitle: modelData.detail + " \u00b7 " + modelData.time
variant: "caption"
text: modelData.title
color: onSurfaceVariant
}
Item { Layout.preferredHeight: 4 }
CText {
Layout.fillWidth: true
variant: "h3"
text: modelData.value
}
Item { Layout.preferredHeight: 8 }
CStatusBadge {
status: modelData.status
text: modelData.status === "success" ? "Online" : "Active"
}
}
}
}
// Quick actions
Item { Layout.preferredHeight: 16 }
// ── Recent activity ──────────────────────────────────
CCard {
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 16
spacing: 12
CText { variant: "h4"; text: "Quick Actions" }
FlexRow {
Layout.leftMargin: 24
Layout.rightMargin: 24
variant: "filled"
CText {
Layout.fillWidth: true
variant: "h4"
text: "Recent Activity"
}
Item { Layout.preferredHeight: 8 }
CDivider { Layout.fillWidth: true }
Item { Layout.preferredHeight: 8 }
Repeater {
model: [
{ action: "Package installed", detail: "material_ui v2.1.0", time: "2 min ago" },
{ action: "User logged in", detail: "admin", time: "5 min ago" },
{ action: "Workflow executed", detail: "on_user_created", time: "12 min ago" },
{ action: "Schema updated", detail: "forum entity", time: "1 hr ago" },
{ action: "Seed data loaded", detail: "5 namespaces", time: "2 hr ago" }
]
delegate: CListItem {
Layout.fillWidth: true
spacing: 10
CButton { text: "Forum"; variant: "default"; onClicked: appWindow.currentView = "forum" }
CButton { text: "Gallery"; variant: "default"; onClicked: appWindow.currentView = "gallery" }
CButton { text: "Guestbook"; variant: "default"; onClicked: appWindow.currentView = "guestbook" }
CButton { text: "Blog"; variant: "default"; onClicked: appWindow.currentView = "blog" }
CButton { text: "Profile"; variant: "ghost"; onClicked: appWindow.currentView = "profile" }
title: modelData.action
subtitle: modelData.detail + " \u00b7 " + modelData.time
}
}
}
Item { Layout.preferredHeight: 16 }
// ── Quick actions ────────────────────────────────────
CCard {
Layout.fillWidth: true
Layout.leftMargin: 24
Layout.rightMargin: 24
variant: "filled"
CText {
Layout.fillWidth: true
variant: "h4"
text: "Quick Actions"
}
Item { Layout.preferredHeight: 12 }
FlexRow {
Layout.fillWidth: true
spacing: 10
CButton { text: "Forum"; variant: "default"; onClicked: appWindow.currentView = "forum" }
CButton { text: "Gallery"; variant: "default"; onClicked: appWindow.currentView = "gallery" }
CButton { text: "Guestbook"; variant: "default"; onClicked: appWindow.currentView = "guestbook" }
CButton { text: "Blog"; variant: "default"; onClicked: appWindow.currentView = "blog" }
CButton { text: "Profile"; variant: "ghost"; onClicked: appWindow.currentView = "profile" }
}
}
// Bottom spacer
Item { Layout.preferredHeight: 24 }
}
}
}

View File

@@ -5,12 +5,20 @@ import QmlComponents 1.0
import "qmllib/dbal"
Rectangle {
color: "transparent"
id: profileRoot
color: Theme.background
// ── DBAL connection ──
// ── DBAL connection ──────────────────────────────────────────
DBALProvider { id: dbal }
// ── Mock fallback data ──
// ── MD3 palette ──────────────────────────────────────────────
readonly property bool isDark: Theme.mode === "dark"
readonly property color surfaceContainer: isDark ? Qt.rgba(1, 1, 1, 0.05) : Qt.rgba(0.31, 0.31, 0.44, 0.06)
readonly property color surfaceContainerHigh: isDark ? Qt.rgba(1, 1, 1, 0.08) : Qt.rgba(0.31, 0.31, 0.44, 0.10)
readonly property color onSurface: Theme.text
readonly property color onSurfaceVariant: Theme.textSecondary
// ── Mock fallback data ───────────────────────────────────────
property string mockBio: "MetaBuilder enthusiast and open-source contributor."
property string mockEmail: "demo@metabuilder.io"
@@ -23,7 +31,7 @@ Rectangle {
property bool saving: false
property string saveStatus: ""
// ── DBAL data loading ──
// ── DBAL data loading ────────────────────────────────────────
function loadProfile() {
if (!appWindow.currentUser) return;
dbal.read("user", appWindow.currentUser, function(result, error) {
@@ -91,241 +99,303 @@ Rectangle {
ScrollView {
anchors.fill: parent
anchors.margins: 24
clip: true
contentWidth: availableWidth
ColumnLayout {
width: parent.width
spacing: 20
spacing: 0
// Profile card
Item { Layout.preferredHeight: 24 }
// ── Profile header card ──────────────────────────────
CCard {
Layout.fillWidth: true
Layout.leftMargin: 24
Layout.rightMargin: 24
variant: "filled"
ColumnLayout {
anchors.fill: parent
anchors.margins: 24
FlexRow {
Layout.fillWidth: true
spacing: 16
FlexRow {
CAvatar {
initials: userInitials()
}
ColumnLayout {
Layout.fillWidth: true
spacing: 16
spacing: 6
CAvatar {
initials: userInitials()
}
ColumnLayout {
CText {
Layout.fillWidth: true
spacing: 6
variant: "h3"
text: appWindow.currentUser
}
CText {
variant: "h3"
text: appWindow.currentUser
}
CText {
variant: "body2"
text: userEmail
color: Theme.text
opacity: 0.7
}
CText {
Layout.fillWidth: true
variant: "body2"
text: userEmail
color: onSurfaceVariant
}
FlexRow {
spacing: 8
CBadge { text: appWindow.currentRole }
CBadge { text: "Level 2" }
}
FlexRow {
spacing: 8
CBadge { text: appWindow.currentRole; badgeColor: Theme.primary }
CBadge { text: "Level 2"; badgeColor: Theme.info }
}
CText {
variant: "caption"
text: "Member since January 15, 2026"
}
CText {
Layout.fillWidth: true
variant: "caption"
text: "Member since January 15, 2026"
color: onSurfaceVariant
}
}
}
}
// Activity summary
Item { Layout.preferredHeight: 16 }
// ── Activity summary ─────────────────────────────────
CCard {
Layout.fillWidth: true
Layout.leftMargin: 24
Layout.rightMargin: 24
variant: "filled"
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 12
CText {
Layout.fillWidth: true
variant: "h4"
text: "Activity Summary"
}
CText { variant: "h4"; text: "Activity Summary" }
CDivider { Layout.fillWidth: true }
Item { Layout.preferredHeight: 8 }
FlexRow {
Layout.fillWidth: true
spacing: 16
CDivider { Layout.fillWidth: true }
Repeater {
model: [
{ label: "Posts", value: "42" },
{ label: "Comments", value: "128" },
{ label: "Last Login", value: "Today, 09:15" }
]
delegate: CCard {
Item { Layout.preferredHeight: 12 }
FlexRow {
Layout.fillWidth: true
spacing: 16
Repeater {
model: [
{ label: "Posts", value: "42" },
{ label: "Comments", value: "128" },
{ label: "Last Login", value: "Today, 09:15" }
]
delegate: CCard {
Layout.fillWidth: true
variant: "outlined"
CText {
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 16
spacing: 6
CText { variant: "caption"; text: modelData.label }
CText { variant: "h4"; text: modelData.value }
}
variant: "caption"
text: modelData.label
color: onSurfaceVariant
}
Item { Layout.preferredHeight: 4 }
CText {
Layout.fillWidth: true
variant: "h4"
text: modelData.value
}
}
}
}
}
// Edit profile section
Item { Layout.preferredHeight: 16 }
// ── Edit profile ─────────────────────────────────────
CCard {
Layout.fillWidth: true
Layout.leftMargin: 24
Layout.rightMargin: 24
variant: "filled"
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 14
CText {
Layout.fillWidth: true
variant: "h4"
text: "Edit Profile"
}
CText { variant: "h4"; text: "Edit Profile" }
CDivider { Layout.fillWidth: true }
Item { Layout.preferredHeight: 8 }
CTextField {
Layout.fillWidth: true
label: "Display Name"
placeholderText: "Enter display name"
text: userDisplayName
onTextChanged: userDisplayName = text
}
CDivider { Layout.fillWidth: true }
CTextField {
Layout.fillWidth: true
label: "Email"
placeholderText: "Enter email address"
text: userEmail
onTextChanged: userEmail = text
}
Item { Layout.preferredHeight: 14 }
CTextField {
Layout.fillWidth: true
label: "Bio"
placeholderText: "Tell us about yourself..."
text: userBio
onTextChanged: userBio = text
}
CTextField {
Layout.fillWidth: true
label: "Display Name"
placeholderText: "Enter display name"
text: userDisplayName
onTextChanged: userDisplayName = text
}
Item { Layout.preferredHeight: 14 }
CTextField {
Layout.fillWidth: true
label: "Email"
placeholderText: "Enter email address"
text: userEmail
onTextChanged: userEmail = text
}
Item { Layout.preferredHeight: 14 }
CTextField {
Layout.fillWidth: true
label: "Bio"
placeholderText: "Tell us about yourself..."
text: userBio
onTextChanged: userBio = text
}
}
// Change password section
Item { Layout.preferredHeight: 16 }
// ── Change password ───────────────────────────────────
CCard {
Layout.fillWidth: true
Layout.leftMargin: 24
Layout.rightMargin: 24
variant: "filled"
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 14
CText {
Layout.fillWidth: true
variant: "h4"
text: "Change Password"
}
CText { variant: "h4"; text: "Change Password" }
CDivider { Layout.fillWidth: true }
Item { Layout.preferredHeight: 8 }
CTextField {
Layout.fillWidth: true
label: "Current Password"
placeholderText: "Enter current password"
echoMode: TextInput.Password
text: currentPassword
onTextChanged: currentPassword = text
}
CDivider { Layout.fillWidth: true }
CTextField {
Layout.fillWidth: true
label: "New Password"
placeholderText: "Enter new password"
echoMode: TextInput.Password
text: newPassword
onTextChanged: newPassword = text
}
Item { Layout.preferredHeight: 14 }
CTextField {
Layout.fillWidth: true
label: "Confirm New Password"
placeholderText: "Re-enter new password"
echoMode: TextInput.Password
text: confirmPassword
onTextChanged: confirmPassword = text
}
CTextField {
Layout.fillWidth: true
label: "Current Password"
placeholderText: "Enter current password"
echoMode: TextInput.Password
text: currentPassword
onTextChanged: currentPassword = text
}
CAlert {
Layout.fillWidth: true
severity: "info"
text: "Passwords must be at least 8 characters with uppercase, lowercase, and a number."
visible: newPassword.length > 0
}
Item { Layout.preferredHeight: 14 }
CAlert {
Layout.fillWidth: true
severity: "error"
text: "Passwords do not match."
visible: confirmPassword.length > 0 && newPassword !== confirmPassword
}
CTextField {
Layout.fillWidth: true
label: "New Password"
placeholderText: "Enter new password"
echoMode: TextInput.Password
text: newPassword
onTextChanged: newPassword = text
}
Item { Layout.preferredHeight: 14 }
CTextField {
Layout.fillWidth: true
label: "Confirm New Password"
placeholderText: "Re-enter new password"
echoMode: TextInput.Password
text: confirmPassword
onTextChanged: confirmPassword = text
}
Item { Layout.preferredHeight: 14 }
CAlert {
Layout.fillWidth: true
severity: "info"
text: "Passwords must be at least 8 characters with uppercase, lowercase, and a number."
visible: newPassword.length > 0
}
CAlert {
Layout.fillWidth: true
severity: "error"
text: "Passwords do not match."
visible: confirmPassword.length > 0 && newPassword !== confirmPassword
}
}
// Connected accounts
Item { Layout.preferredHeight: 16 }
// ── Connected accounts ────────────────────────────────
CCard {
Layout.fillWidth: true
Layout.leftMargin: 24
Layout.rightMargin: 24
variant: "filled"
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 12
CText {
Layout.fillWidth: true
variant: "h4"
text: "Connected Accounts"
}
CText { variant: "h4"; text: "Connected Accounts" }
CDivider { Layout.fillWidth: true }
Item { Layout.preferredHeight: 8 }
CListItem {
Layout.fillWidth: true
title: "GitHub"
subtitle: "Linked as @" + appWindow.currentUser
leadingIcon: "github"
}
CDivider { Layout.fillWidth: true }
FlexRow {
Layout.fillWidth: true
Layout.leftMargin: 12
spacing: 8
CStatusBadge { status: "success"; text: "Connected" }
Item { Layout.fillWidth: true }
CButton { text: "Unlink"; variant: "ghost"; size: "sm" }
}
Item { Layout.preferredHeight: 8 }
CDivider { Layout.fillWidth: true }
CListItem {
Layout.fillWidth: true
title: "GitHub"
subtitle: "Linked as @" + appWindow.currentUser
leadingIcon: "github"
}
CListItem {
Layout.fillWidth: true
title: "Discord"
subtitle: "Not linked"
leadingIcon: "discord"
}
FlexRow {
Layout.fillWidth: true
Layout.leftMargin: 12
spacing: 8
CStatusBadge { status: "success"; text: "Connected" }
Item { Layout.fillWidth: true }
CButton { text: "Unlink"; variant: "ghost"; size: "sm" }
}
FlexRow {
Layout.fillWidth: true
Layout.leftMargin: 12
spacing: 8
CStatusBadge { status: "warning"; text: "Not Connected" }
Item { Layout.fillWidth: true }
CButton { text: "Link Account"; variant: "primary"; size: "sm" }
}
Item { Layout.preferredHeight: 8 }
CDivider { Layout.fillWidth: true }
Item { Layout.preferredHeight: 8 }
CListItem {
Layout.fillWidth: true
title: "Discord"
subtitle: "Not linked"
leadingIcon: "discord"
}
FlexRow {
Layout.fillWidth: true
Layout.leftMargin: 12
spacing: 8
CStatusBadge { status: "warning"; text: "Not Connected" }
Item { Layout.fillWidth: true }
CButton { text: "Link Account"; variant: "primary"; size: "sm" }
}
}
// Save button
Item { Layout.preferredHeight: 16 }
// ── Save button ──────────────────────────────────────
FlexRow {
Layout.fillWidth: true
Layout.leftMargin: 24
Layout.rightMargin: 24
spacing: 12
Item { Layout.fillWidth: true }
CButton {
@@ -337,7 +407,7 @@ Rectangle {
}
// Bottom spacer
Item { Layout.preferredHeight: 20 }
Item { Layout.preferredHeight: 24 }
}
}
}

View File

@@ -180,85 +180,70 @@ Rectangle {
CCard {
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
CText { variant: "h4"; text: "Profile" }
CDivider { Layout.fillWidth: true }
FlexRow {
Layout.fillWidth: true
Layout.topMargin: 4
spacing: 16
CText { variant: "h4"; text: "Profile" }
CDivider { Layout.fillWidth: true }
FlexRow {
Layout.fillWidth: true
spacing: 16
// Avatar
Rectangle {
width: 64
height: 64
radius: 32
color: Theme.primary
Layout.alignment: Qt.AlignTop
CText {
anchors.centerIn: parent
text: userInitials()
variant: "h4"
color: "#ffffff"
font.bold: true
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 4
CText {
variant: "subtitle1"
text: appWindow.currentUser
font.bold: true
}
CText {
variant: "body2"
text: appWindow.currentRole + " \u00b7 Level " + appWindow.currentLevel
opacity: 0.7
}
}
// Avatar
CAvatar {
size: "lg"
initials: userInitials()
}
CTextField {
ColumnLayout {
Layout.fillWidth: true
label: "Display Name"
placeholderText: "Enter display name"
text: displayName
onTextChanged: displayName = text
spacing: 4
CText {
variant: "subtitle1"
text: appWindow.currentUser
font.bold: true
}
CText {
variant: "body2"
text: appWindow.currentRole + " \u00b7 Level " + appWindow.currentLevel
opacity: 0.7
}
}
}
CTextField {
Layout.fillWidth: true
Layout.topMargin: 8
label: "Display Name"
placeholderText: "Enter display name"
text: displayName
onTextChanged: displayName = text
}
CTextField {
Layout.fillWidth: true
label: "Email"
placeholderText: "Enter email address"
text: userEmail
onTextChanged: userEmail = text
}
FlexRow {
Layout.fillWidth: true
spacing: 12
Item { Layout.fillWidth: true }
CAlert {
visible: profileSaved
severity: "success"
text: "Profile saved successfully"
}
CTextField {
Layout.fillWidth: true
label: "Email"
placeholderText: "Enter email address"
text: userEmail
onTextChanged: userEmail = text
}
FlexRow {
Layout.fillWidth: true
spacing: 12
Item { Layout.fillWidth: true }
CAlert {
visible: profileSaved
severity: "success"
text: "Profile saved successfully"
}
CButton {
text: "Save Profile"
variant: "primary"
onClicked: saveProfile()
}
CButton {
text: "Save Profile"
variant: "primary"
onClicked: saveProfile()
}
}
}
@@ -267,67 +252,62 @@ Rectangle {
CCard {
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 16
CText { variant: "h4"; text: "Appearance" }
CDivider { Layout.fillWidth: true }
CText { variant: "h4"; text: "Appearance" }
CDivider { Layout.fillWidth: true }
// Theme selector
CText {
variant: "subtitle2"
text: "Theme"
Layout.topMargin: 4
}
// Theme selector
CText {
variant: "subtitle2"
text: "Theme"
}
Flow {
Layout.fillWidth: true
spacing: 8
Flow {
Layout.fillWidth: true
spacing: 8
Repeater {
model: availableThemes
delegate: CButton {
text: modelData.label
variant: selectedTheme === modelData.id ? "primary" : "default"
size: "sm"
onClicked: {
selectedTheme = modelData.id
appWindow.currentTheme = modelData.id
if (typeof Theme.setTheme === "function") {
Theme.setTheme(modelData.id)
}
savePreferences()
Repeater {
model: availableThemes
delegate: CButton {
text: modelData.label
variant: selectedTheme === modelData.id ? "primary" : "default"
size: "sm"
onClicked: {
selectedTheme = modelData.id
appWindow.currentTheme = modelData.id
if (typeof Theme.setTheme === "function") {
Theme.setTheme(modelData.id)
}
savePreferences()
}
}
}
}
// Font size selector
CText {
variant: "subtitle2"
text: "Font Size"
Layout.topMargin: 8
}
// Font size selector
CText {
variant: "subtitle2"
text: "Font Size"
Layout.topMargin: 8
}
FlexRow {
Layout.fillWidth: true
spacing: 8
FlexRow {
Layout.fillWidth: true
spacing: 8
Repeater {
model: [
{ id: "small", label: "Small" },
{ id: "medium", label: "Medium" },
{ id: "large", label: "Large" }
]
delegate: CButton {
text: modelData.label
variant: fontSize === modelData.id ? "primary" : "default"
size: "sm"
onClicked: {
fontSize = modelData.id
savePreferences()
}
Repeater {
model: [
{ id: "small", label: "Small" },
{ id: "medium", label: "Medium" },
{ id: "large", label: "Large" }
]
delegate: CButton {
text: modelData.label
variant: fontSize === modelData.id ? "primary" : "default"
size: "sm"
onClicked: {
fontSize = modelData.id
savePreferences()
}
}
}
@@ -338,78 +318,73 @@ Rectangle {
CCard {
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 16
CText { variant: "h4"; text: "Notifications" }
CDivider { Layout.fillWidth: true }
CText { variant: "h4"; text: "Notifications" }
CDivider { Layout.fillWidth: true }
// Email notifications toggle
FlexRow {
Layout.fillWidth: true
Layout.topMargin: 4
spacing: 12
// Email notifications toggle
FlexRow {
ColumnLayout {
Layout.fillWidth: true
spacing: 12
ColumnLayout {
Layout.fillWidth: true
spacing: 2
CText { variant: "subtitle2"; text: "Email Notifications" }
CText { variant: "caption"; text: "Receive notification summaries via email"; opacity: 0.6 }
}
Switch {
checked: emailNotifications
onCheckedChanged: {
emailNotifications = checked
savePreferences()
}
}
spacing: 2
CText { variant: "subtitle2"; text: "Email Notifications" }
CText { variant: "caption"; text: "Receive notification summaries via email"; opacity: 0.6 }
}
CDivider { Layout.fillWidth: true }
// Desktop notifications toggle
FlexRow {
Layout.fillWidth: true
spacing: 12
ColumnLayout {
Layout.fillWidth: true
spacing: 2
CText { variant: "subtitle2"; text: "Desktop Notifications" }
CText { variant: "caption"; text: "Show desktop push notifications for alerts"; opacity: 0.6 }
}
Switch {
checked: desktopNotifications
onCheckedChanged: {
desktopNotifications = checked
savePreferences()
}
CSwitch {
checked: emailNotifications
onToggled: function(value) {
emailNotifications = value
savePreferences()
}
}
}
CDivider { Layout.fillWidth: true }
CDivider { Layout.fillWidth: true }
// Sound alerts toggle
FlexRow {
// Desktop notifications toggle
FlexRow {
Layout.fillWidth: true
spacing: 12
ColumnLayout {
Layout.fillWidth: true
spacing: 12
spacing: 2
CText { variant: "subtitle2"; text: "Desktop Notifications" }
CText { variant: "caption"; text: "Show desktop push notifications for alerts"; opacity: 0.6 }
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
CText { variant: "subtitle2"; text: "Sound Alerts" }
CText { variant: "caption"; text: "Play a sound when new notifications arrive"; opacity: 0.6 }
CSwitch {
checked: desktopNotifications
onToggled: function(value) {
desktopNotifications = value
savePreferences()
}
}
}
Switch {
checked: soundAlerts
onCheckedChanged: {
soundAlerts = checked
savePreferences()
}
CDivider { Layout.fillWidth: true }
// Sound alerts toggle
FlexRow {
Layout.fillWidth: true
spacing: 12
ColumnLayout {
Layout.fillWidth: true
spacing: 2
CText { variant: "subtitle2"; text: "Sound Alerts" }
CText { variant: "caption"; text: "Play a sound when new notifications arrive"; opacity: 0.6 }
}
CSwitch {
checked: soundAlerts
onToggled: function(value) {
soundAlerts = value
savePreferences()
}
}
}
@@ -419,81 +394,75 @@ Rectangle {
CCard {
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 16
CText { variant: "h4"; text: "Connection" }
CDivider { Layout.fillWidth: true }
CText { variant: "h4"; text: "Connection" }
CDivider { Layout.fillWidth: true }
// DBAL URL
CText { variant: "subtitle2"; text: "DBAL Server"; Layout.topMargin: 4 }
// DBAL URL
CText { variant: "subtitle2"; text: "DBAL Server" }
FlexRow {
Layout.fillWidth: true
spacing: 12
FlexRow {
CTextField {
Layout.fillWidth: true
spacing: 12
CTextField {
Layout.fillWidth: true
label: "DBAL URL"
placeholderText: "http://localhost:8080"
text: dbalUrl
onTextChanged: dbalUrl = text
}
ColumnLayout {
spacing: 4
Layout.alignment: Qt.AlignBottom
CButton {
text: dbalConnectionStatus === "testing" ? "Testing..." : "Test Connection"
variant: "default"
size: "sm"
enabled: dbalConnectionStatus !== "testing"
onClicked: testDBALConnection()
}
CStatusBadge {
status: connectionStatusColor(dbalConnectionStatus)
text: connectionStatusLabel(dbalConnectionStatus)
}
}
label: "DBAL URL"
placeholderText: "http://localhost:8080"
text: dbalUrl
onTextChanged: dbalUrl = text
}
CDivider { Layout.fillWidth: true }
ColumnLayout {
spacing: 4
Layout.alignment: Qt.AlignBottom
// Media Service URL
CText { variant: "subtitle2"; text: "Media Service" }
FlexRow {
Layout.fillWidth: true
spacing: 12
CTextField {
Layout.fillWidth: true
label: "Media Service URL"
placeholderText: "http://localhost:9090"
text: mediaServiceUrl
onTextChanged: mediaServiceUrl = text
CButton {
text: dbalConnectionStatus === "testing" ? "Testing..." : "Test Connection"
variant: "default"
size: "sm"
enabled: dbalConnectionStatus !== "testing"
onClicked: testDBALConnection()
}
ColumnLayout {
spacing: 4
Layout.alignment: Qt.AlignBottom
CStatusBadge {
status: connectionStatusColor(dbalConnectionStatus)
text: connectionStatusLabel(dbalConnectionStatus)
}
}
}
CButton {
text: mediaConnectionStatus === "testing" ? "Testing..." : "Test Connection"
variant: "default"
size: "sm"
enabled: mediaConnectionStatus !== "testing"
onClicked: testMediaConnection()
}
CDivider { Layout.fillWidth: true }
CStatusBadge {
status: connectionStatusColor(mediaConnectionStatus)
text: connectionStatusLabel(mediaConnectionStatus)
}
// Media Service URL
CText { variant: "subtitle2"; text: "Media Service" }
FlexRow {
Layout.fillWidth: true
spacing: 12
CTextField {
Layout.fillWidth: true
label: "Media Service URL"
placeholderText: "http://localhost:9090"
text: mediaServiceUrl
onTextChanged: mediaServiceUrl = text
}
ColumnLayout {
spacing: 4
Layout.alignment: Qt.AlignBottom
CButton {
text: mediaConnectionStatus === "testing" ? "Testing..." : "Test Connection"
variant: "default"
size: "sm"
enabled: mediaConnectionStatus !== "testing"
onClicked: testMediaConnection()
}
CStatusBadge {
status: connectionStatusColor(mediaConnectionStatus)
text: connectionStatusLabel(mediaConnectionStatus)
}
}
}
@@ -503,62 +472,56 @@ Rectangle {
CCard {
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 12
CText { variant: "h4"; text: "About" }
CDivider { Layout.fillWidth: true }
CText { variant: "h4"; text: "About" }
CDivider { Layout.fillWidth: true }
Repeater {
model: [
{ label: "Version", value: "2.1.0" },
{ label: "Build Date", value: "2026-03-19" },
{ label: "Qt Version", value: "6.8.x" },
{ label: "Platform", value: Qt.platform.os },
{ label: "DBAL Schema", value: "v1 REST API" }
]
Repeater {
model: [
{ label: "Version", value: "2.1.0" },
{ label: "Build Date", value: "2026-03-19" },
{ label: "Qt Version", value: "6.8.x" },
{ label: "Platform", value: Qt.platform.os },
{ label: "DBAL Schema", value: "v1 REST API" }
]
delegate: FlexRow {
Layout.fillWidth: true
spacing: 12
CText {
variant: "body2"
text: modelData.label
opacity: 0.6
Layout.preferredWidth: 120
}
CText {
variant: "body1"
text: modelData.value
}
}
}
CDivider { Layout.fillWidth: true }
FlexRow {
delegate: FlexRow {
Layout.fillWidth: true
spacing: 12
CButton {
text: "View Documentation"
variant: "default"
size: "sm"
onClicked: Qt.openUrlExternally("https://github.com/nicholasgriffintn/metabuilder")
CText {
variant: "body2"
text: modelData.label
opacity: 0.6
Layout.preferredWidth: 120
}
CButton {
text: "Report Issue"
variant: "ghost"
size: "sm"
onClicked: Qt.openUrlExternally("https://github.com/nicholasgriffintn/metabuilder/issues")
CText {
variant: "body1"
text: modelData.value
}
}
}
CDivider { Layout.fillWidth: true }
FlexRow {
Layout.fillWidth: true
spacing: 12
CButton {
text: "View Documentation"
variant: "default"
size: "sm"
onClicked: Qt.openUrlExternally("https://github.com/nicholasgriffintn/metabuilder")
}
CButton {
text: "Report Issue"
variant: "ghost"
size: "sm"
onClicked: Qt.openUrlExternally("https://github.com/nicholasgriffintn/metabuilder/issues")
}
}
}
// ── Data status footer ──────────────────────────────

View File

@@ -6,7 +6,7 @@ import "qmllib/dbal"
Rectangle {
id: superGodPanel
color: "transparent"
color: Theme.background
// ── DBAL connection ──
DBALProvider { id: dbal }
@@ -150,53 +150,47 @@ Rectangle {
CCard {
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
FlexRow {
Layout.fillWidth: true
spacing: 12
FlexRow {
Layout.fillWidth: true
spacing: 12
CText { variant: "h2"; text: "Super God Panel" }
CBadge { text: "Level 5"; badgeColor: Theme.primary }
CStatusBadge { status: "success"; text: "Platform Control" }
CText { variant: "h2"; text: "Super God Panel" }
CBadge { text: "Level 5" }
CStatusBadge { status: "success"; text: "Platform Control" }
Item { Layout.fillWidth: true }
Item { Layout.fillWidth: true }
CButton {
text: "Level 4"
variant: "ghost"
size: "sm"
onClicked: appWindow.currentView = "god"
}
CButton {
text: "Level 3"
variant: "ghost"
size: "sm"
onClicked: appWindow.currentView = "admin"
}
CButton {
text: "Level 2"
variant: "ghost"
size: "sm"
onClicked: appWindow.currentView = "dashboard"
}
CButton {
text: "Level 4"
variant: "ghost"
size: "sm"
onClicked: appWindow.currentView = "god"
}
CDivider { Layout.fillWidth: true }
FlexRow {
Layout.fillWidth: true
spacing: 8
CChip { text: tenants.length + " Tenants" }
CChip { text: godUsers.length + " God Users" }
CChip { text: pendingTransfers.length + " Pending Transfers" }
CChip { text: "14 DB Backends" }
CChip { text: "4 Daemons" }
CButton {
text: "Level 3"
variant: "ghost"
size: "sm"
onClicked: appWindow.currentView = "admin"
}
CButton {
text: "Level 2"
variant: "ghost"
size: "sm"
onClicked: appWindow.currentView = "dashboard"
}
}
CDivider { Layout.fillWidth: true }
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 }
CChip { text: "14 DB Backends"; chipColor: Theme.info }
CChip { text: "4 Daemons"; chipColor: Theme.success }
}
}
@@ -259,51 +253,45 @@ Rectangle {
delegate: CCard {
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 16
FlexRow {
Layout.fillWidth: true
spacing: 10
FlexRow {
Layout.fillWidth: true
spacing: 10
CText { variant: "h4"; text: modelData.name }
CStatusBadge {
status: modelData.status === "active" ? "success" : "warning"
text: modelData.status
}
Item { Layout.fillWidth: true }
CBadge { text: "Tenant" }
CText { variant: "h4"; text: modelData.name }
CStatusBadge {
status: modelData.status === "active" ? "success" : "warning"
text: modelData.status
}
Item { Layout.fillWidth: true }
CBadge { text: "Tenant"; badgeColor: Theme.primary }
}
CDivider { Layout.fillWidth: true }
CDivider { Layout.fillWidth: true }
RowLayout {
Layout.fillWidth: true
spacing: 24
RowLayout {
Layout.fillWidth: true
spacing: 24
ColumnLayout {
spacing: 4
CText { variant: "caption"; text: "Owner"; color: Theme.textSecondary }
CText { variant: "body1"; text: modelData.owner }
}
ColumnLayout {
spacing: 4
CText { variant: "caption"; text: "Homepage"; color: Theme.textSecondary }
CText { variant: "body1"; text: modelData.homepage }
}
ColumnLayout {
spacing: 4
CText { variant: "caption"; text: "Created"; color: Theme.textSecondary }
CText { variant: "body1"; text: modelData.created }
}
Item { Layout.fillWidth: true }
CButton {
text: "Configure"
variant: "ghost"
size: "sm"
}
ColumnLayout {
spacing: 4
CText { variant: "caption"; text: "Owner"; color: Theme.textSecondary }
CText { variant: "body1"; text: modelData.owner }
}
ColumnLayout {
spacing: 4
CText { variant: "caption"; text: "Homepage"; color: Theme.textSecondary }
CText { variant: "body1"; text: modelData.homepage }
}
ColumnLayout {
spacing: 4
CText { variant: "caption"; text: "Created"; color: Theme.textSecondary }
CText { variant: "body1"; text: modelData.created }
}
Item { Layout.fillWidth: true }
CButton {
text: "Configure"
variant: "ghost"
size: "sm"
}
}
}
@@ -344,8 +332,7 @@ Rectangle {
Layout.fillWidth: true
RowLayout {
anchors.fill: parent
anchors.margins: 16
Layout.fillWidth: true
spacing: 16
CAvatar { initials: modelData.initials }
@@ -357,8 +344,8 @@ Rectangle {
FlexRow {
spacing: 8
CText { variant: "subtitle1"; text: modelData.username }
CBadge { text: "L" + modelData.level }
CBadge { text: modelData.role }
CBadge { text: "L" + modelData.level; badgeColor: Theme.primary }
CBadge { text: modelData.role; badgeColor: Theme.secondary }
}
FlexRow {
@@ -425,77 +412,71 @@ Rectangle {
Layout.fillWidth: true
visible: showTransferForm
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 12
CText { variant: "h4"; text: "New Transfer Request" }
CDivider { Layout.fillWidth: true }
CText { variant: "h4"; text: "New Transfer Request" }
CDivider { Layout.fillWidth: true }
RowLayout {
Layout.fillWidth: true
spacing: 16
CTextField {
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
onTextChanged: transferTo = text
}
}
RowLayout {
Layout.fillWidth: true
spacing: 16
CTextField {
Layout.fillWidth: true
label: "Reason"
placeholderText: "Describe the reason for this transfer"
text: transferReason
onTextChanged: transferReason = text
label: "From User"
placeholderText: "e.g. admin"
text: transferFrom
onTextChanged: transferFrom = text
}
CTextField {
Layout.fillWidth: true
label: "Expiry Date"
placeholderText: "YYYY-MM-DD"
text: transferExpiry
onTextChanged: transferExpiry = text
label: "To User"
placeholderText: "e.g. devops"
text: transferTo
onTextChanged: transferTo = text
}
}
FlexRow {
Layout.fillWidth: true
spacing: 8
CTextField {
Layout.fillWidth: true
label: "Reason"
placeholderText: "Describe the reason for this transfer"
text: transferReason
onTextChanged: transferReason = text
}
Item { Layout.fillWidth: true }
CButton {
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);
pendingTransfers = updated;
transferFrom = "";
transferTo = "";
transferReason = "";
transferExpiry = "";
showTransferForm = false;
}
CTextField {
Layout.fillWidth: true
label: "Expiry Date"
placeholderText: "YYYY-MM-DD"
text: transferExpiry
onTextChanged: transferExpiry = text
}
FlexRow {
Layout.fillWidth: true
spacing: 8
Item { Layout.fillWidth: true }
CButton {
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);
pendingTransfers = updated;
transferFrom = "";
transferTo = "";
transferReason = "";
transferExpiry = "";
showTransferForm = false;
}
}
}
@@ -513,72 +494,66 @@ Rectangle {
delegate: CCard {
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 16
FlexRow {
Layout.fillWidth: true
spacing: 10
FlexRow {
Layout.fillWidth: true
spacing: 10
CText { variant: "subtitle1"; text: modelData.from + " -> " + modelData.to }
CStatusBadge { status: "warning"; text: "Pending" }
Item { Layout.fillWidth: true }
CText { variant: "caption"; text: "Expires: " + modelData.expiry; color: Theme.textSecondary }
}
CText { variant: "subtitle1"; text: modelData.from + " → " + modelData.to }
CStatusBadge { status: "warning"; text: "Pending" }
Item { Layout.fillWidth: true }
CText { variant: "caption"; text: "Expires: " + modelData.expiry; color: Theme.textSecondary }
}
CText {
variant: "body2"
text: modelData.reason
wrapMode: Text.Wrap
Layout.fillWidth: true
}
CText {
variant: "body2"
text: modelData.reason
wrapMode: Text.Wrap
Layout.fillWidth: true
}
FlexRow {
Layout.fillWidth: true
spacing: 8
FlexRow {
Layout.fillWidth: true
spacing: 8
Item { Layout.fillWidth: true }
CButton {
text: "Approve"
variant: "primary"
size: "sm"
onClicked: {
var entry = {
from: pendingTransfers[index].from,
to: pendingTransfers[index].to,
reason: pendingTransfers[index].reason,
date: "2026-03-18 " + Qt.formatTime(new Date(), "hh:mm"),
status: "approved"
};
var hist = transferHistory.slice();
hist.unshift(entry);
transferHistory = hist;
var pend = pendingTransfers.slice();
pend.splice(index, 1);
pendingTransfers = pend;
}
Item { Layout.fillWidth: true }
CButton {
text: "Approve"
variant: "primary"
size: "sm"
onClicked: {
var entry = {
from: pendingTransfers[index].from,
to: pendingTransfers[index].to,
reason: pendingTransfers[index].reason,
date: "2026-03-18 " + Qt.formatTime(new Date(), "hh:mm"),
status: "approved"
};
var hist = transferHistory.slice();
hist.unshift(entry);
transferHistory = hist;
var pend = pendingTransfers.slice();
pend.splice(index, 1);
pendingTransfers = pend;
}
CButton {
text: "Deny"
variant: "danger"
size: "sm"
onClicked: {
var entry = {
from: pendingTransfers[index].from,
to: pendingTransfers[index].to,
reason: pendingTransfers[index].reason,
date: "2026-03-18 " + Qt.formatTime(new Date(), "hh:mm"),
status: "denied"
};
var hist = transferHistory.slice();
hist.unshift(entry);
transferHistory = hist;
var pend = pendingTransfers.slice();
pend.splice(index, 1);
pendingTransfers = pend;
}
}
CButton {
text: "Deny"
variant: "danger"
size: "sm"
onClicked: {
var entry = {
from: pendingTransfers[index].from,
to: pendingTransfers[index].to,
reason: pendingTransfers[index].reason,
date: "2026-03-18 " + Qt.formatTime(new Date(), "hh:mm"),
status: "denied"
};
var hist = transferHistory.slice();
hist.unshift(entry);
transferHistory = hist;
var pend = pendingTransfers.slice();
pend.splice(index, 1);
pendingTransfers = pend;
}
}
}
@@ -604,8 +579,7 @@ Rectangle {
variant: "outlined"
RowLayout {
anchors.fill: parent
anchors.margins: 14
Layout.fillWidth: true
spacing: 16
ColumnLayout {
@@ -614,7 +588,7 @@ Rectangle {
FlexRow {
spacing: 8
CText { variant: "subtitle1"; text: modelData.from + " " + modelData.to }
CText { variant: "subtitle1"; text: modelData.from + " -> " + modelData.to }
CStatusBadge {
status: modelData.status === "approved" ? "success" : "error"
text: modelData.status
@@ -662,26 +636,20 @@ Rectangle {
delegate: CCard {
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 16
FlexRow {
Layout.fillWidth: true
spacing: 10
FlexRow {
Layout.fillWidth: true
spacing: 10
CText { variant: "subtitle1"; text: modelData.name }
CStatusBadge {
status: modelData.status === "healthy" ? "success" : "warning"
text: modelData.status
}
Item { Layout.fillWidth: true }
CBadge { text: ":" + modelData.port }
CText { variant: "subtitle1"; text: modelData.name }
CStatusBadge {
status: modelData.status === "healthy" ? "success" : "warning"
text: modelData.status
}
CText { variant: "caption"; text: "Uptime: " + modelData.uptime; color: Theme.textSecondary }
Item { Layout.fillWidth: true }
CBadge { text: ":" + modelData.port; badgeColor: Theme.info }
}
CText { variant: "caption"; text: "Uptime: " + modelData.uptime; color: Theme.textSecondary }
}
}
}
@@ -708,26 +676,30 @@ Rectangle {
delegate: CCard {
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 16
spacing: 8
CText {
variant: "caption"
text: modelData.label
color: Theme.textSecondary
Layout.fillWidth: true
}
CText { variant: "caption"; text: modelData.label; color: Theme.textSecondary }
CText { variant: "h3"; text: modelData.value + "%" }
CText {
variant: "h3"
text: modelData.value + "%"
Layout.fillWidth: true
}
Rectangle {
Layout.fillWidth: true
height: 6
radius: 3
color: Theme.surfaceVariant
Rectangle {
Layout.fillWidth: true
height: 6
width: parent.width * (modelData.value / 100)
height: parent.height
radius: 3
color: Theme.border
Rectangle {
width: parent.width * (modelData.value / 100)
height: parent.height
radius: 3
color: modelData.value > 80 ? Theme.error : modelData.value > 60 ? Theme.warning : Theme.primary
}
color: modelData.value > 80 ? Theme.error : modelData.value > 60 ? Theme.warning : Theme.primary
}
}
}
@@ -777,35 +749,29 @@ Rectangle {
CCard {
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 16
spacing: 8
RowLayout {
Layout.fillWidth: true
spacing: 24
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" }
}
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" }
}
}
}