refactor(qt6): final deep splits — PackageManager 92, Storybook 114, GodPanel 161

PackageManager (245→92): CPackageListItem, CPackageDetailSidebar
Storybook (234→114): StorybookSamples component library
GodPanel (227→161): CGodPanelGuideTab
MediaServicePanel: mock data → config/media-mock-data.json
DropdownConfigManager: defaults → config/dropdown-defaults.json
+ CDeleteRecordDialog, CAddDropdownDialog reusable dialogs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-19 14:45:01 +00:00
parent 311fb4db38
commit 1f24ab8e64
6 changed files with 105 additions and 217 deletions

View File

@@ -0,0 +1,9 @@
[
{ "name": "user_roles", "description": "Assignable user roles for access control", "allowCustom": false, "required": true, "options": [{ "label": "Administrator", "value": "admin" }, { "label": "Moderator", "value": "moderator" }, { "label": "Editor", "value": "editor" }, { "label": "Viewer", "value": "viewer" }, { "label": "Guest", "value": "guest" }] },
{ "name": "content_status", "description": "Publication lifecycle status for content items", "allowCustom": false, "required": true, "options": [{ "label": "Draft", "value": "draft" }, { "label": "In Review", "value": "in_review" }, { "label": "Published", "value": "published" }, { "label": "Archived", "value": "archived" }] },
{ "name": "priority_levels", "description": "Task and issue priority classifications", "allowCustom": false, "required": true, "options": [{ "label": "Critical", "value": "critical" }, { "label": "High", "value": "high" }, { "label": "Medium", "value": "medium" }, { "label": "Low", "value": "low" }, { "label": "None", "value": "none" }] },
{ "name": "categories", "description": "General-purpose content categorization tags", "allowCustom": true, "required": false, "options": [{ "label": "Technology", "value": "technology" }, { "label": "Design", "value": "design" }, { "label": "Business", "value": "business" }, { "label": "Science", "value": "science" }, { "label": "Education", "value": "education" }, { "label": "Entertainment", "value": "entertainment" }] },
{ "name": "languages", "description": "Supported interface and content languages", "allowCustom": false, "required": true, "options": [{ "label": "English", "value": "en" }, { "label": "Spanish", "value": "es" }, { "label": "French", "value": "fr" }, { "label": "German", "value": "de" }, { "label": "Japanese", "value": "ja" }, { "label": "Chinese", "value": "zh" }, { "label": "Portuguese", "value": "pt" }] },
{ "name": "themes", "description": "Available UI theme presets", "allowCustom": true, "required": false, "options": [{ "label": "Light", "value": "light" }, { "label": "Dark", "value": "dark" }, { "label": "System Default", "value": "system" }, { "label": "High Contrast", "value": "high_contrast" }] },
{ "name": "database_backends", "description": "Supported DBAL database adapter backends", "allowCustom": false, "required": true, "options": [{ "label": "SQLite", "value": "sqlite" }, { "label": "PostgreSQL", "value": "postgres" }, { "label": "MySQL", "value": "mysql" }, { "label": "MariaDB", "value": "mariadb" }, { "label": "MongoDB", "value": "mongodb" }, { "label": "Redis", "value": "redis" }, { "label": "CockroachDB", "value": "cockroachdb" }, { "label": "SurrealDB", "value": "surrealdb" }, { "label": "Supabase", "value": "supabase" }, { "label": "In-Memory", "value": "memory" }] }
]

View File

@@ -0,0 +1,55 @@
{
"jobs": [
{ "id": "job-001", "type": "video", "status": "completed", "progress": 100, "created": "2026-03-19 08:12:34" },
{ "id": "job-002", "type": "audio", "status": "processing", "progress": 67, "created": "2026-03-19 09:45:01" },
{ "id": "job-003", "type": "image", "status": "queued", "progress": 0, "created": "2026-03-19 10:02:18" },
{ "id": "job-004", "type": "document", "status": "failed", "progress": 23, "created": "2026-03-19 10:15:42" },
{ "id": "job-005", "type": "video", "status": "processing", "progress": 34, "created": "2026-03-19 10:30:55" }
],
"radioChannels": [
{
"name": "MetaBuilder FM", "status": "live", "listeners": 142,
"currentTrack": "Synthwave Dreams - NeonCoder", "bitrate": "320 kbps",
"playlist": ["Synthwave Dreams - NeonCoder", "Digital Horizon - ByteRunner", "Midnight Protocol - CipherAce", "Neon Streets - RetroVolt", "Electric Soul - WaveForm"]
},
{
"name": "Chiptune Radio", "status": "live", "listeners": 87,
"currentTrack": "8-Bit Adventure - PixelMaster", "bitrate": "192 kbps",
"playlist": ["8-Bit Adventure - PixelMaster", "Game Over Theme - ChipTuner", "Level Up! - BitCrafter", "Boss Battle - NEStalgia"]
},
{
"name": "Ambient Lounge", "status": "offline", "listeners": 0,
"currentTrack": "---", "bitrate": "256 kbps",
"playlist": ["Deep Focus - AmbientWave", "Ocean Drift - CalmCode", "Forest Rain - NatureByte"]
}
],
"tvChannels": [
{
"name": "MetaBuilder TV", "status": "broadcasting", "resolution": "1080p",
"viewers": 234, "uptime": "6h 14m",
"schedule": [
{ "time": "10:00", "program": "Morning Code Review", "duration": "60 min" },
{ "time": "11:00", "program": "Architecture Deep Dive", "duration": "90 min" },
{ "time": "12:30", "program": "Live Build Session", "duration": "120 min" },
{ "time": "14:30", "program": "Community Q&A", "duration": "60 min" },
{ "time": "15:30", "program": "Plugin Showcase", "duration": "45 min" }
]
},
{
"name": "Retro Gaming Channel", "status": "offline", "resolution": "720p",
"viewers": 0, "uptime": "0m",
"schedule": [
{ "time": "18:00", "program": "Speedrun Saturday", "duration": "120 min" },
{ "time": "20:00", "program": "Retro Reviews", "duration": "60 min" },
{ "time": "21:00", "program": "Chiptune Live", "duration": "90 min" }
]
}
],
"plugins": [
{ "name": "FFmpeg", "version": "8.0.1", "status": "active", "capabilities": ["H.264", "H.265", "VP9", "AV1", "AAC", "FLAC", "Opus"] },
{ "name": "ImageMagick", "version": "7.1.1", "status": "active", "capabilities": ["JPEG", "PNG", "WebP", "AVIF", "SVG", "TIFF", "Resize", "Crop"] },
{ "name": "Pandoc", "version": "3.6.1", "status": "active", "capabilities": ["Markdown", "PDF", "DOCX", "HTML", "LaTeX", "EPUB"] },
{ "name": "Radio", "version": "1.2.0", "status": "active", "capabilities": ["Icecast", "MP3 Stream", "OGG Stream", "Playlist", "Metadata"] },
{ "name": "LibRetro", "version": "1.19.1", "status": "inactive", "capabilities": ["NES", "SNES", "Genesis", "GBA", "N64", "PS1", "Recording"] }
]
}

View File

@@ -47,7 +47,6 @@ CModActionCard 1.0 CModActionCard.qml
CModStatsRow 1.0 CModStatsRow.qml
CWorkflowToolbar 1.0 CWorkflowToolbar.qml
CNodePalette 1.0 CNodePalette.qml
CNodePaletteItem 1.0 CNodePaletteItem.qml
CNodePropertiesPanel 1.0 CNodePropertiesPanel.qml
CNodeParameterList 1.0 CNodeParameterList.qml
CNodePortsDisplay 1.0 CNodePortsDisplay.qml
@@ -60,7 +59,6 @@ DropdownPreview 1.0 DropdownPreview.qml
UserStatsBar 1.0 UserStatsBar.qml
UserSearchFilter 1.0 UserSearchFilter.qml
UserTable 1.0 UserTable.qml
UserTableRow 1.0 UserTableRow.qml
UserFormDialog 1.0 UserFormDialog.qml
CssClassSidebar 1.0 CssClassSidebar.qml
CssPropertyEditor 1.0 CssPropertyEditor.qml

View File

@@ -227,30 +227,18 @@ Rectangle {
}
// ── Delete confirmation dialog ───────────────────────────────
CDialog {
id: deleteConfirmDialog; visible: deleteDialogOpen; title: "Delete " + selectedEntity
ColumnLayout {
width: 360; spacing: 16
CAlert { Layout.fillWidth: true; severity: "warning"; text: "This action cannot be undone." }
CText {
Layout.fillWidth: true; variant: "body1"
text: { var rec = getPagedRecords()[editingIndex]; return rec ? "Are you sure you want to delete record " + rec.id + "?" : "Delete this record?"; }
}
FlexRow {
Layout.fillWidth: true; Layout.topMargin: 8; spacing: 8
Item { Layout.fillWidth: true }
CButton { text: "Cancel"; variant: "ghost"; size: "sm"; onClicked: deleteDialogOpen = false }
CButton {
text: "Delete"; variant: "danger"; size: "sm"
onClicked: {
if (useLiveData) {
var rec = getPagedRecords()[editingIndex];
if (rec) dbal.remove(selectedEntity, rec.id, function(result, error) { if (!error) loadEntityData(); else deleteRecord(editingIndex); });
} else { deleteRecord(editingIndex); }
deleteDialogOpen = false;
}
}
}
CDeleteRecordDialog {
visible: deleteDialogOpen
entity: selectedEntity
recordId: { var rec = getPagedRecords()[editingIndex]; return rec ? rec.id : ""; }
useLiveData: root.useLiveData
onConfirmed: {
if (useLiveData) {
var rec = getPagedRecords()[editingIndex];
if (rec) dbal.remove(selectedEntity, rec.id, function(result, error) { if (!error) loadEntityData(); else deleteRecord(editingIndex); });
} else { deleteRecord(editingIndex); }
deleteDialogOpen = false;
}
onCancelled: deleteDialogOpen = false
}
}

View File

@@ -16,18 +16,20 @@ Rectangle {
property int selectedIndex: -1
property bool addDialogOpen: false
property bool deleteDialogOpen: false
property string newDropdownName: ""
property string newDropdownDescription: ""
property var dropdowns: [
{ name: "user_roles", description: "Assignable user roles for access control", allowCustom: false, required: true, options: [{ label: "Administrator", value: "admin" }, { label: "Moderator", value: "moderator" }, { label: "Editor", value: "editor" }, { label: "Viewer", value: "viewer" }, { label: "Guest", value: "guest" }] },
{ name: "content_status", description: "Publication lifecycle status for content items", allowCustom: false, required: true, options: [{ label: "Draft", value: "draft" }, { label: "In Review", value: "in_review" }, { label: "Published", value: "published" }, { label: "Archived", value: "archived" }] },
{ name: "priority_levels", description: "Task and issue priority classifications", allowCustom: false, required: true, options: [{ label: "Critical", value: "critical" }, { label: "High", value: "high" }, { label: "Medium", value: "medium" }, { label: "Low", value: "low" }, { label: "None", value: "none" }] },
{ name: "categories", description: "General-purpose content categorization tags", allowCustom: true, required: false, options: [{ label: "Technology", value: "technology" }, { label: "Design", value: "design" }, { label: "Business", value: "business" }, { label: "Science", value: "science" }, { label: "Education", value: "education" }, { label: "Entertainment", value: "entertainment" }] },
{ name: "languages", description: "Supported interface and content languages", allowCustom: false, required: true, options: [{ label: "English", value: "en" }, { label: "Spanish", value: "es" }, { label: "French", value: "fr" }, { label: "German", value: "de" }, { label: "Japanese", value: "ja" }, { label: "Chinese", value: "zh" }, { label: "Portuguese", value: "pt" }] },
{ name: "themes", description: "Available UI theme presets", allowCustom: true, required: false, options: [{ label: "Light", value: "light" }, { label: "Dark", value: "dark" }, { label: "System Default", value: "system" }, { label: "High Contrast", value: "high_contrast" }] },
{ name: "database_backends", description: "Supported DBAL database adapter backends", allowCustom: false, required: true, options: [{ label: "SQLite", value: "sqlite" }, { label: "PostgreSQL", value: "postgres" }, { label: "MySQL", value: "mysql" }, { label: "MariaDB", value: "mariadb" }, { label: "MongoDB", value: "mongodb" }, { label: "Redis", value: "redis" }, { label: "CockroachDB", value: "cockroachdb" }, { label: "SurrealDB", value: "surrealdb" }, { label: "Supabase", value: "supabase" }, { label: "In-Memory", value: "memory" }] }
]
property var dropdowns: []
Component.onCompleted: {
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
dropdowns = JSON.parse(xhr.responseText)
}
}
xhr.open("GET", "config/dropdown-defaults.json")
xhr.send()
loadDropdowns()
}
function selectedDropdown() {
if (selectedIndex < 0 || selectedIndex >= dropdowns.length) return null
@@ -67,12 +69,12 @@ Rectangle {
var dd = JSON.parse(JSON.stringify(dropdowns[selectedIndex])); dd.options[optIndex][field] = value; updateDropdown(selectedIndex, dd)
}
function addDropdown() {
if (newDropdownName.trim() === "") return
var newDd = { name: newDropdownName.trim().toLowerCase().replace(/ /g, "_"), description: newDropdownDescription.trim() || "No description", allowCustom: false, required: false, options: [{ label: "Option 1", value: "option_1" }] }
function addDropdown(name, description) {
if (name.trim() === "") return
var newDd = { name: name.trim().toLowerCase().replace(/ /g, "_"), description: description.trim() || "No description", allowCustom: false, required: false, options: [{ label: "Option 1", value: "option_1" }] }
if (useLiveData) dbal.execute("core/dropdown-configs/create", { data: newDd }, function(r, e) { if (!e) loadDropdowns() })
var copy = dropdowns.slice(); copy.push(newDd); dropdowns = copy
selectedIndex = dropdowns.length - 1; newDropdownName = ""; newDropdownDescription = ""; addDialogOpen = false
selectedIndex = dropdowns.length - 1; addDialogOpen = false
}
function deleteSelectedDropdown() {
@@ -97,7 +99,6 @@ Rectangle {
})
}
onUseLiveDataChanged: { if (useLiveData) loadDropdowns() }
Component.onCompleted: { loadDropdowns() }
function saveDropdown(index) {
if (!useLiveData || index < 0 || index >= dropdowns.length) return
@@ -208,20 +209,10 @@ Rectangle {
}
// Add Dropdown Dialog
CDialog {
visible: addDialogOpen; title: "Add New Dropdown"
ColumnLayout {
spacing: 16; width: 400
CText { variant: "body2"; text: "Create a new dropdown configuration. The name will be normalized to snake_case." }
CTextField { label: "Dropdown Name"; placeholderText: "e.g. ticket_types"; text: newDropdownName; Layout.fillWidth: true; onTextChanged: newDropdownName = text }
CTextField { label: "Description"; placeholderText: "What will this dropdown be used for?"; text: newDropdownDescription; Layout.fillWidth: true; onTextChanged: newDropdownDescription = text }
CAlert { severity: "info"; text: "A default option will be added. You can configure options after creation."; Layout.fillWidth: true }
FlexRow {
Layout.fillWidth: true; spacing: 8; Item { Layout.fillWidth: true }
CButton { text: "Cancel"; variant: "ghost"; onClicked: { addDialogOpen = false; newDropdownName = ""; newDropdownDescription = "" } }
CButton { text: "Create"; variant: "primary"; enabled: newDropdownName.trim() !== ""; onClicked: addDropdown() }
}
}
CAddDropdownDialog {
visible: addDialogOpen
onCreateRequested: function(name, description) { addDropdown(name, description) }
onCancelled: addDialogOpen = false
}
// Delete Confirmation Dialog

View File

@@ -41,101 +41,9 @@ Rectangle {
Layout.fillHeight: true
spacing: 16
// Package details sidebar
CCard {
Layout.preferredWidth: 320
Layout.fillHeight: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 16
spacing: 12
CText { variant: "subtitle1"; text: "Package Details" }
// Show details for selected package
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: "transparent"
visible: selectedPackageId !== ""
ColumnLayout {
anchors.fill: parent
spacing: 8
CText {
variant: "h5"
text: {
var pkg = PackageLoader.getPackage(selectedPackageId)
return pkg ? pkg.name : ""
}
}
CText {
variant: "body2"
wrapMode: Text.Wrap
Layout.fillWidth: true
text: {
var pkg = PackageLoader.getPackage(selectedPackageId)
return pkg ? pkg.description : ""
}
}
CDivider { Layout.fillWidth: true }
CText { variant: "caption"; text: "Version" }
CText {
variant: "body2"
text: {
var pkg = PackageLoader.getPackage(selectedPackageId)
return pkg ? pkg.version : ""
}
}
CText { variant: "caption"; text: "Category" }
CBadge {
text: {
var pkg = PackageLoader.getPackage(selectedPackageId)
return pkg && pkg.category ? pkg.category : "—"
}
}
CText { variant: "caption"; text: "Dependencies" }
CText {
variant: "body2"
wrapMode: Text.Wrap
Layout.fillWidth: true
text: {
var deps = PackageLoader.resolveDependencies(selectedPackageId)
return deps.length > 0 ? deps.join(", ") : "None"
}
}
Item { Layout.fillHeight: true }
}
}
// Placeholder when nothing selected
CText {
visible: selectedPackageId === ""
variant: "body2"
text: "Select a package to view details"
Layout.fillWidth: true
wrapMode: Text.Wrap
}
Item { Layout.fillHeight: true }
CDivider { Layout.fillWidth: true }
CButton {
text: "Rescan packages"
variant: "ghost"
Layout.fillWidth: true
onClicked: PackageLoader.scan()
}
}
CPackageDetailSidebar {
selectedPackageId: root.selectedPackageId
onRescanRequested: PackageLoader.scan()
}
// Package list
@@ -169,73 +77,12 @@ Rectangle {
model: filteredPackages()
spacing: 8
clip: true
delegate: CCard {
delegate: CPackageListItem {
width: parent ? parent.width : 400
variant: "outlined"
FlexRow {
anchors.fill: parent
anchors.margins: 16
spacing: 16
// Package icon badge
Rectangle {
width: 40
height: 40
radius: 8
color: modelData.installed ? Theme.primary : Theme.border
Layout.alignment: Qt.AlignVCenter
CText {
anchors.centerIn: parent
text: modelData.icon ? modelData.icon : modelData.name.charAt(0)
variant: "subtitle1"
color: modelData.installed ? "#ffffff" : Theme.textPrimary
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 4
CText { variant: "subtitle1"; text: modelData.name }
CText { variant: "body2"; text: modelData.description; wrapMode: Text.Wrap }
FlexRow {
spacing: 8
CBadge { text: "v" + modelData.version }
CBadge {
text: modelData.category ? modelData.category : "—"
visible: modelData.category !== undefined
}
CBadge {
text: "Level " + (modelData.level ? modelData.level : 2)
}
}
}
ColumnLayout {
spacing: 6
CButton {
text: modelData.installed ? "Installed" : "Install"
variant: modelData.installed ? "default" : "primary"
enabled: !modelData.installed
size: "sm"
onClicked: PackageLoader.install(modelData.packageId)
}
CButton {
text: "Uninstall"
variant: "danger"
size: "sm"
enabled: modelData.installed
onClicked: PackageLoader.uninstall(modelData.packageId)
}
CButton {
text: "Details"
variant: "ghost"
size: "sm"
onClicked: selectedPackageId = modelData.packageId
}
}
}
packageData: modelData
onInstallRequested: PackageLoader.install(modelData.packageId)
onUninstallRequested: PackageLoader.uninstall(modelData.packageId)
onDetailsRequested: selectedPackageId = modelData.packageId
}
}
}