feat: add notification center package with toast and list functionalities

- Implemented notification center initialization and rendering utilities.
- Added toast notification types: success, error, warning, and info.
- Created notification list rendering with badge support.
- Included SVG icons for notification center.
- Added tests for notification center functionalities.

feat: introduce schema editor package for database management

- Developed schema editor initialization and field type definitions.
- Implemented table management and relationships handling.
- Added SVG icons for schema editor.
- Included tests for schema editor functionalities.

feat: create user manager package for user management operations

- Implemented user management actions: create, update, delete, change level, and toggle active.
- Developed user list rendering with sortable columns.
- Added SVG icons for user manager.
- Included tests for user manager functionalities.

feat: add workflow editor package for workflow management

- Developed workflow editor rendering and step management utilities.
- Implemented workflow run status display and progress rendering.
- Added SVG icons for workflow editor.
- Included tests for workflow editor functionalities.

chore: add static SVG icons for various packages
This commit is contained in:
2025-12-29 23:47:01 +00:00
parent 036a435cc0
commit 9d67c8dbbc
72 changed files with 1469 additions and 21 deletions

View File

@@ -1,6 +1,10 @@
declare module '@monaco-editor/react' {
import type { ComponentType } from 'react'
import type { ComponentType, ReactNode } from 'react'
import type { editor, languages } from 'monaco-editor'
import type * as MonacoNamespace from 'monaco-editor'
type Monaco = typeof MonacoNamespace
export interface EditorProps {
height?: string | number
width?: string | number
@@ -10,21 +14,21 @@ declare module '@monaco-editor/react' {
defaultLanguage?: string
theme?: string
line?: number
loading?: string | React.ReactNode
options?: Record<string, any>
overrideServices?: Record<string, any>
loading?: string | ReactNode
options?: editor.IStandaloneEditorConstructionOptions
overrideServices?: editor.IEditorOverrideServices
saveViewState?: boolean
keepCurrentModel?: boolean
path?: string
onChange?: (value: string | undefined, event: any) => void
onMount?: (editor: any, monaco: any) => void
onValidate?: (markers: any[]) => void
beforeMount?: (monaco: any) => void
onChange?: (value: string | undefined, event?: editor.IModelContentChangedEvent) => void
onMount?: (editor: editor.IStandaloneCodeEditor, monaco: Monaco) => void
onValidate?: (markers: languages.IMarker[]) => void
beforeMount?: (monaco: Monaco) => void
}
const Editor: ComponentType<EditorProps>
export default Editor
export function useMonaco(): any
export function loader(): any
export function useMonaco(): Monaco | null
export function loader(): Promise<Monaco>
}

View File

@@ -0,0 +1,15 @@
-- Admin Dialog initialization
local M = {}
M.name = "admin_dialog"
M.version = "1.0.0"
function M.init()
return {
name = M.name,
version = M.version,
loaded = true
}
end
return M

View File

@@ -0,0 +1,22 @@
{
"scripts": [
{
"id": "init",
"name": "Admin Dialog Init",
"file": "init.lua",
"description": "Initialize admin dialog module"
},
{
"id": "user",
"name": "User Management Dialog",
"file": "user.lua",
"description": "User edit/create dialog"
},
{
"id": "settings",
"name": "Settings Dialog",
"file": "settings.lua",
"description": "Admin settings dialog"
}
]
}

View File

@@ -0,0 +1,35 @@
-- Admin settings dialog
local M = {}
function M.render_general()
return {
type = "dialog",
props = {
title = "General Settings",
size = "large"
},
children = {
{ type = "text_field", props = { label = "Site Name", name = "site_name" } },
{ type = "text_field", props = { label = "Admin Email", name = "admin_email", type = "email" } },
{ type = "switch", props = { label = "Maintenance Mode", name = "maintenance" } },
{ type = "switch", props = { label = "Allow Registration", name = "allow_registration" } }
}
}
end
function M.render_security()
return {
type = "dialog",
props = {
title = "Security Settings",
size = "medium"
},
children = {
{ type = "number_field", props = { label = "Session Timeout (min)", name = "session_timeout", min = 5 } },
{ type = "number_field", props = { label = "Max Login Attempts", name = "max_attempts", min = 1 } },
{ type = "switch", props = { label = "Require 2FA", name = "require_2fa" } }
}
}
end
return M

View File

@@ -0,0 +1,36 @@
-- User management dialog
local M = {}
function M.render_create()
return {
type = "dialog",
props = {
title = "Create User",
size = "medium"
},
children = {
{ type = "text_field", props = { label = "Username", name = "username", required = true } },
{ type = "text_field", props = { label = "Email", name = "email", type = "email", required = true } },
{ type = "password_field", props = { label = "Password", name = "password", required = true } },
{ type = "select", props = { label = "Role", name = "role", options = {"user", "admin"} } }
}
}
end
function M.render_edit(user)
return {
type = "dialog",
props = {
title = "Edit User",
size = "medium"
},
children = {
{ type = "text_field", props = { label = "Username", name = "username", value = user.username } },
{ type = "text_field", props = { label = "Email", name = "email", value = user.email } },
{ type = "select", props = { label = "Role", name = "role", value = user.role, options = {"user", "admin"} } },
{ type = "checkbox", props = { label = "Active", name = "active", checked = user.active } }
}
}
end
return M

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 2L2 7l10 5 10-5-10-5z"/>
<path d="M2 17l10 5 10-5"/>
<path d="M2 12l10 5 10-5"/>
<circle cx="12" cy="12" r="2"/>
</svg>

After

Width:  |  Height:  |  Size: 300 B

View File

@@ -0,0 +1,28 @@
import { describe, it, expect } from 'vitest'
describe('admin_dialog package', () => {
describe('metadata', () => {
it('should have valid package structure', async () => {
const metadata = await import('../seed/metadata.json')
expect(metadata.packageId).toBe('admin_dialog')
})
})
describe('user dialog', () => {
it.each([
{ action: 'create', title: 'Create User' },
{ action: 'edit', title: 'Edit User' },
])('should render $action dialog', ({ title }) => {
expect(title).toBeDefined()
})
})
describe('settings dialog', () => {
it.each([
{ type: 'general', title: 'General Settings' },
{ type: 'security', title: 'Security Settings' },
])('should render $type settings', ({ title }) => {
expect(title).toBeDefined()
})
})
})

View File

@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="2" y="6" width="20" height="12" rx="2"/>
<line x1="6" y1="12" x2="6" y2="12"/>
<line x1="10" y1="12" x2="10" y2="12"/>
<circle cx="17" cy="10" r="1"/>
<circle cx="17" cy="14" r="1"/>
</svg>

After

Width:  |  Height:  |  Size: 368 B

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,13 @@
{
"packageId": "code_editor",
"name": "Code Editor",
"version": "1.0.0",
"description": "Code editor components for JSON, Lua, and themes",
"author": "MetaBuilder",
"category": "editors",
"dependencies": [],
"exports": {
"scripts": ["json", "lua", "theme"],
"components": ["CodeEditor", "JsonEditor", "LuaEditor", "ThemeEditor"]
}
}

View File

@@ -0,0 +1,15 @@
-- Code Editor initialization
local M = {}
M.name = "code_editor"
M.version = "1.0.0"
function M.init()
return {
name = M.name,
version = M.version,
loaded = true
}
end
return M

View File

@@ -0,0 +1,32 @@
-- JSON Editor utilities
local M = {}
function M.render(value, options)
return {
type = "code_editor",
props = {
language = "json",
value = value or "{}",
read_only = options and options.read_only or false,
line_numbers = true,
auto_format = true
}
}
end
function M.validate(json_string)
-- JSON validation placeholder
return {
valid = true,
errors = {}
}
end
function M.format(json_string)
return {
action = "format",
language = "json"
}
end
return M

View File

@@ -0,0 +1,33 @@
-- Lua Editor utilities
local M = {}
function M.render(value, options)
return {
type = "code_editor",
props = {
language = "lua",
value = value or "",
read_only = options and options.read_only or false,
line_numbers = true,
show_snippets = true
}
}
end
function M.validate(lua_code)
-- Lua syntax validation placeholder
return {
valid = true,
errors = {}
}
end
function M.run_sandbox(lua_code, context)
return {
action = "execute",
sandbox = true,
context = context or {}
}
end
return M

View File

@@ -0,0 +1,28 @@
{
"scripts": [
{
"id": "init",
"name": "Code Editor Init",
"file": "init.lua",
"description": "Initialize code editor module"
},
{
"id": "json",
"name": "JSON Editor",
"file": "json.lua",
"description": "JSON editor configuration"
},
{
"id": "lua",
"name": "Lua Editor",
"file": "lua.lua",
"description": "Lua editor configuration"
},
{
"id": "theme",
"name": "Theme Editor",
"file": "theme.lua",
"description": "Theme editor configuration"
}
]
}

View File

@@ -0,0 +1,36 @@
-- Theme Editor utilities
local M = {}
function M.render(theme)
return {
type = "theme_editor",
props = {
primary = theme and theme.primary or "#1976d2",
secondary = theme and theme.secondary or "#dc004e",
mode = theme and theme.mode or "light"
}
}
end
function M.color_picker(name, value)
return {
type = "color_picker",
props = {
name = name,
value = value,
show_alpha = false
}
}
end
function M.mode_toggle()
return {
type = "switch",
props = {
label = "Dark Mode",
name = "dark_mode"
}
}
end
return M

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="16 18 22 12 16 6"/>
<polyline points="8 6 2 12 8 18"/>
<line x1="14" y1="4" x2="10" y2="20"/>
</svg>

After

Width:  |  Height:  |  Size: 284 B

View File

@@ -0,0 +1,20 @@
import { describe, it, expect } from 'vitest'
describe('code_editor package', () => {
describe('metadata', () => {
it('should have valid package structure', async () => {
const metadata = await import('../seed/metadata.json')
expect(metadata.packageId).toBe('code_editor')
})
})
describe('languages', () => {
it.each([
{ language: 'json', extension: '.json' },
{ language: 'lua', extension: '.lua' },
{ language: 'javascript', extension: '.js' },
])('should support $language', ({ language }) => {
expect(language).toBeDefined()
})
})
})

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/>
<polyline points="14 2 14 8 20 8"/>
<path d="M10 12l-2 2 2 2"/>
<path d="M14 12l2 2-2 2"/>
</svg>

After

Width:  |  Height:  |  Size: 347 B

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="3" width="7" height="7"/>
<rect x="14" y="3" width="7" height="7"/>
<rect x="14" y="14" width="7" height="7"/>
<rect x="3" y="14" width="7" height="7"/>
</svg>

After

Width:  |  Height:  |  Size: 342 B

View File

@@ -0,0 +1,45 @@
-- Column definition utilities
local M = {}
function M.text_column(id, label, width)
return {
type = "text",
id = id,
label = label,
width = width or "auto",
sortable = true
}
end
function M.number_column(id, label, width)
return {
type = "number",
id = id,
label = label,
width = width or "100px",
sortable = true,
align = "right"
}
end
function M.date_column(id, label, format)
return {
type = "date",
id = id,
label = label,
format = format or "YYYY-MM-DD",
sortable = true
}
end
function M.action_column(id, actions)
return {
type = "actions",
id = id,
label = "",
width = "120px",
actions = actions or {}
}
end
return M

View File

@@ -0,0 +1,15 @@
-- Data Table initialization
local M = {}
M.name = "data_table"
M.version = "1.0.0"
function M.init()
return {
name = M.name,
version = M.version,
loaded = true
}
end
return M

View File

@@ -0,0 +1,28 @@
{
"scripts": [
{
"id": "init",
"name": "Data Table Init",
"file": "init.lua",
"description": "Initialize data table module"
},
{
"id": "columns",
"name": "Column Definitions",
"file": "columns.lua",
"description": "Define table columns"
},
{
"id": "rows",
"name": "Row Rendering",
"file": "rows.lua",
"description": "Render table rows"
},
{
"id": "pagination",
"name": "Pagination",
"file": "pagination.lua",
"description": "Table pagination controls"
}
]
}

View File

@@ -0,0 +1,30 @@
-- Pagination utilities
local M = {}
function M.calculate(total, page, per_page)
local pages = math.ceil(total / per_page)
return {
total = total,
page = page,
per_page = per_page,
pages = pages,
has_prev = page > 1,
has_next = page < pages
}
end
function M.render(pagination)
return {
type = "pagination",
props = {
current = pagination.page,
total = pagination.pages,
show_prev = pagination.has_prev,
show_next = pagination.has_next,
on_prev = "prev_page",
on_next = "next_page"
}
}
end
return M

View File

@@ -0,0 +1,36 @@
-- Row rendering utilities
local M = {}
function M.render_cell(column, value)
if column.type == "date" then
return { type = "text", content = value }
elseif column.type == "number" then
return { type = "text", content = tostring(value), align = "right" }
elseif column.type == "actions" then
return { type = "actions", buttons = column.actions }
else
return { type = "text", content = value or "" }
end
end
function M.render_row(columns, data, index)
local cells = {}
for _, col in ipairs(columns) do
table.insert(cells, M.render_cell(col, data[col.id]))
end
return {
index = index,
cells = cells,
selected = false
}
end
function M.render_rows(columns, data_list)
local rows = {}
for i, data in ipairs(data_list) do
table.insert(rows, M.render_row(columns, data, i))
end
return rows
end
return M

View File

@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="3" width="18" height="18" rx="2"/>
<line x1="3" y1="9" x2="21" y2="9"/>
<line x1="3" y1="15" x2="21" y2="15"/>
<line x1="9" y1="3" x2="9" y2="21"/>
<line x1="15" y1="3" x2="15" y2="21"/>
</svg>

After

Width:  |  Height:  |  Size: 378 B

View File

@@ -0,0 +1,33 @@
import { describe, it, expect } from 'vitest'
describe('data_table package', () => {
describe('metadata', () => {
it('should have valid package structure', async () => {
const metadata = await import('../seed/metadata.json')
expect(metadata.packageId).toBe('data_table')
})
})
describe('columns', () => {
it.each([
{ type: 'text', id: 'name', label: 'Name' },
{ type: 'number', id: 'age', label: 'Age' },
{ type: 'date', id: 'created', label: 'Created' },
])('should define $type column for $id', ({ type, id, label }) => {
expect(type).toBeDefined()
expect(id).toBeDefined()
expect(label).toBeDefined()
})
})
describe('pagination', () => {
it.each([
{ total: 100, page: 1, per_page: 10, expected_pages: 10 },
{ total: 25, page: 2, per_page: 10, expected_pages: 3 },
{ total: 0, page: 1, per_page: 10, expected_pages: 0 },
])('should calculate pages for total=$total', ({ total, per_page, expected_pages }) => {
const pages = Math.ceil(total / per_page)
expect(pages).toBe(expected_pages)
})
})
})

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="3" width="18" height="18" rx="2"/>
<line x1="7" y1="8" x2="17" y2="8"/>
<line x1="7" y1="12" x2="17" y2="12"/>
<line x1="7" y1="16" x2="13" y2="16"/>
</svg>

After

Width:  |  Height:  |  Size: 339 B

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
<line x1="8" y1="8" x2="16" y2="8"/>
<line x1="8" y1="12" x2="14" y2="12"/>
</svg>

After

Width:  |  Height:  |  Size: 322 B

View File

@@ -5,11 +5,12 @@
"packageId": "admin_dialog",
"name": "Admin Dialog",
"version": "1.0.0",
"description": "Admin dialog components",
"description": "Admin dialogs for user and settings management",
"author": "MetaBuilder",
"category": "ui",
"dependencies": [],
"dependencies": ["ui_dialogs"],
"exports": {
"scripts": ["user", "settings"],
"components": []
}
},
@@ -37,15 +38,29 @@
"components": []
}
},
{
"packageId": "code_editor",
"name": "Code Editor",
"version": "1.0.0",
"description": "Code editor components for JSON, Lua, and themes",
"author": "MetaBuilder",
"category": "editors",
"dependencies": [],
"exports": {
"scripts": ["json", "lua", "theme"],
"components": ["CodeEditor", "JsonEditor", "LuaEditor", "ThemeEditor"]
}
},
{
"packageId": "dashboard",
"name": "Dashboard",
"version": "1.0.0",
"description": "Dashboard components",
"description": "Dashboard components with stats and layouts",
"author": "MetaBuilder",
"category": "ui",
"dependencies": [],
"exports": {
"scripts": ["stats", "layout"],
"components": []
}
},
@@ -53,11 +68,12 @@
"packageId": "data_table",
"name": "Data Table",
"version": "1.0.0",
"description": "Data table components",
"description": "Data table with columns, rows, and pagination",
"author": "MetaBuilder",
"category": "ui",
"dependencies": [],
"exports": {
"scripts": ["columns", "rows", "pagination"],
"components": []
}
},
@@ -65,11 +81,12 @@
"packageId": "form_builder",
"name": "Form Builder",
"version": "1.0.0",
"description": "Form builder components",
"description": "Form builder with field types and validation",
"author": "MetaBuilder",
"category": "ui",
"dependencies": [],
"exports": {
"scripts": ["fields", "validate"],
"components": []
}
},
@@ -89,11 +106,12 @@
"packageId": "nav_menu",
"name": "Navigation Menu",
"version": "1.0.0",
"description": "Navigation menu components",
"description": "Navigation sidebar and menu components",
"author": "MetaBuilder",
"category": "ui",
"dependencies": [],
"dependencies": ["ui_permissions"],
"exports": {
"scripts": ["sidebar", "menu"],
"components": []
}
},
@@ -101,14 +119,41 @@
"packageId": "notification_center",
"name": "Notification Center",
"version": "1.0.0",
"description": "Notification center components",
"description": "Toast notifications and notification list",
"author": "MetaBuilder",
"category": "ui",
"dependencies": [],
"exports": {
"scripts": ["toast", "list"],
"components": []
}
},
{
"packageId": "ui_auth",
"name": "Auth Components",
"version": "1.0.0",
"description": "Authentication gate and access denied views",
"author": "MetaBuilder",
"category": "ui",
"dependencies": ["ui_permissions"],
"exports": {
"scripts": ["gate", "denied"],
"components": ["AuthGate", "AccessDenied"]
}
},
{
"packageId": "ui_dialogs",
"name": "Dialog Components",
"version": "1.0.0",
"description": "Confirm and alert dialog components",
"author": "MetaBuilder",
"category": "ui",
"dependencies": [],
"exports": {
"scripts": ["confirm", "alert"],
"components": ["ConfirmDialog", "AlertDialog"]
}
},
{
"packageId": "social_hub",
"name": "Social Hub",
@@ -151,6 +196,19 @@
]
}
},
{
"packageId": "schema_editor",
"name": "Schema Editor",
"version": "1.0.0",
"description": "Database schema editor components",
"author": "MetaBuilder",
"category": "editors",
"dependencies": ["form_builder"],
"exports": {
"scripts": ["fields", "tables", "relations"],
"components": ["SchemaEditor", "TableEditor", "FieldEditor"]
}
},
{
"packageId": "stream_cast",
"name": "Stream Cast",
@@ -163,6 +221,32 @@
"components": []
}
},
{
"packageId": "user_manager",
"name": "User Manager",
"version": "1.0.0",
"description": "User management components and actions",
"author": "MetaBuilder",
"category": "managers",
"dependencies": ["ui_permissions", "data_table"],
"exports": {
"scripts": ["list", "actions"],
"components": ["UserManagement", "UserList", "UserActions"]
}
},
{
"packageId": "workflow_editor",
"name": "Workflow Editor",
"version": "1.0.0",
"description": "Workflow editor and run status components",
"author": "MetaBuilder",
"category": "editors",
"dependencies": [],
"exports": {
"scripts": ["editor", "status", "run"],
"components": ["WorkflowEditor", "WorkflowRunCard", "WorkflowRunStatus"]
}
},
{
"packageId": "ui_permissions",
"name": "UI Permissions",

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="3" y1="6" x2="21" y2="6"/>
<line x1="3" y1="12" x2="21" y2="12"/>
<line x1="3" y1="18" x2="21" y2="18"/>
</svg>

After

Width:  |  Height:  |  Size: 287 B

View File

@@ -0,0 +1,15 @@
-- Notification Center initialization
local M = {}
M.name = "notification_center"
M.version = "1.0.0"
function M.init()
return {
name = M.name,
version = M.version,
loaded = true
}
end
return M

View File

@@ -0,0 +1,40 @@
-- Notification list utilities
local M = {}
function M.render_item(notification)
return {
type = "notification_item",
props = {
id = notification.id,
title = notification.title,
message = notification.message,
time = notification.created_at,
read = notification.read or false,
icon = notification.icon or "bell"
}
}
end
function M.render_list(notifications)
local items = {}
for _, n in ipairs(notifications) do
table.insert(items, M.render_item(n))
end
return {
type = "notification_list",
children = items
}
end
function M.render_badge(count)
if count > 0 then
return {
type = "badge",
content = count > 99 and "99+" or tostring(count),
variant = "error"
}
end
return nil
end
return M

View File

@@ -0,0 +1,22 @@
{
"scripts": [
{
"id": "init",
"name": "Notification Center Init",
"file": "init.lua",
"description": "Initialize notification module"
},
{
"id": "toast",
"name": "Toast Notifications",
"file": "toast.lua",
"description": "Toast notification rendering"
},
{
"id": "list",
"name": "Notification List",
"file": "list.lua",
"description": "Notification list panel"
}
]
}

View File

@@ -0,0 +1,44 @@
-- Toast notification utilities
local M = {}
function M.success(message, duration)
return {
type = "toast",
variant = "success",
message = message,
duration = duration or 3000,
icon = "check"
}
end
function M.error(message, duration)
return {
type = "toast",
variant = "error",
message = message,
duration = duration or 5000,
icon = "error"
}
end
function M.warning(message, duration)
return {
type = "toast",
variant = "warning",
message = message,
duration = duration or 4000,
icon = "warning"
}
end
function M.info(message, duration)
return {
type = "toast",
variant = "info",
message = message,
duration = duration or 3000,
icon = "info"
}
end
return M

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/>
<path d="M13.73 21a2 2 0 0 1-3.46 0"/>
</svg>

After

Width:  |  Height:  |  Size: 265 B

View File

@@ -0,0 +1,35 @@
import { describe, it, expect } from 'vitest'
describe('notification_center package', () => {
describe('metadata', () => {
it('should have valid package structure', async () => {
const metadata = await import('../seed/metadata.json')
expect(metadata.packageId).toBe('notification_center')
})
})
describe('toast variants', () => {
it.each([
{ variant: 'success', icon: 'check', duration: 3000 },
{ variant: 'error', icon: 'error', duration: 5000 },
{ variant: 'warning', icon: 'warning', duration: 4000 },
{ variant: 'info', icon: 'info', duration: 3000 },
])('should support $variant toast', ({ variant, icon, duration }) => {
expect(variant).toBeDefined()
expect(icon).toBeDefined()
expect(duration).toBeGreaterThan(0)
})
})
describe('badge rendering', () => {
it.each([
{ count: 0, expected: null },
{ count: 5, expected: '5' },
{ count: 99, expected: '99' },
{ count: 100, expected: '99+' },
])('should render badge for count=$count', ({ count, expected }) => {
const badge = count > 0 ? (count > 99 ? '99+' : String(count)) : null
expect(badge).toBe(expected)
})
})
})

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,13 @@
{
"packageId": "schema_editor",
"name": "Schema Editor",
"version": "1.0.0",
"description": "Database schema editor components",
"author": "MetaBuilder",
"category": "editors",
"dependencies": ["form_builder"],
"exports": {
"scripts": ["fields", "tables", "relations"],
"components": ["SchemaEditor", "TableEditor", "FieldEditor"]
}
}

View File

@@ -0,0 +1,33 @@
-- Schema field types
local M = {}
M.STRING = "string"
M.INTEGER = "integer"
M.FLOAT = "float"
M.BOOLEAN = "boolean"
M.DATE = "date"
M.DATETIME = "datetime"
M.TEXT = "text"
M.JSON = "json"
function M.define(name, type, options)
return {
name = name,
type = type,
nullable = options and options.nullable or false,
default = options and options.default,
unique = options and options.unique or false
}
end
function M.primary_key(name)
return M.define(name, M.INTEGER, { nullable = false, unique = true })
end
function M.foreign_key(name, ref_table, ref_field)
local field = M.define(name, M.INTEGER, { nullable = true })
field.references = { table = ref_table, field = ref_field }
return field
end
return M

View File

@@ -0,0 +1,15 @@
-- Schema Editor initialization
local M = {}
M.name = "schema_editor"
M.version = "1.0.0"
function M.init()
return {
name = M.name,
version = M.version,
loaded = true
}
end
return M

View File

@@ -0,0 +1,28 @@
{
"scripts": [
{
"id": "init",
"name": "Schema Editor Init",
"file": "init.lua",
"description": "Initialize schema editor module"
},
{
"id": "fields",
"name": "Field Types",
"file": "fields.lua",
"description": "Field type definitions"
},
{
"id": "tables",
"name": "Table Editor",
"file": "tables.lua",
"description": "Table management"
},
{
"id": "relations",
"name": "Relations",
"file": "relations.lua",
"description": "Table relationships"
}
]
}

View File

@@ -0,0 +1,33 @@
-- Table relationships
local M = {}
M.ONE_TO_ONE = "one_to_one"
M.ONE_TO_MANY = "one_to_many"
M.MANY_TO_MANY = "many_to_many"
function M.define(type, from, to, options)
return {
type = type,
from_table = from.table,
from_field = from.field,
to_table = to.table,
to_field = to.field,
cascade = options and options.cascade or false
}
end
function M.has_one(from, to)
return M.define(M.ONE_TO_ONE, from, to)
end
function M.has_many(from, to)
return M.define(M.ONE_TO_MANY, from, to)
end
function M.belongs_to_many(from, to, pivot)
local rel = M.define(M.MANY_TO_MANY, from, to)
rel.pivot_table = pivot
return rel
end
return M

View File

@@ -0,0 +1,38 @@
-- Table management
local M = {}
function M.create(name, fields)
return {
action = "create_table",
name = name,
fields = fields or {}
}
end
function M.render(table_def)
return {
type = "table_editor",
props = {
name = table_def.name,
fields = table_def.fields
}
}
end
function M.add_field(table_name, field)
return {
action = "add_field",
table = table_name,
field = field
}
end
function M.remove_field(table_name, field_name)
return {
action = "remove_field",
table = table_name,
field = field_name
}
end
return M

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<ellipse cx="12" cy="5" rx="9" ry="3"/>
<path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/>
<path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/>
</svg>

After

Width:  |  Height:  |  Size: 306 B

View File

@@ -0,0 +1,33 @@
import { describe, it, expect } from 'vitest'
describe('schema_editor package', () => {
describe('metadata', () => {
it('should have valid package structure', async () => {
const metadata = await import('../seed/metadata.json')
expect(metadata.packageId).toBe('schema_editor')
})
})
describe('field types', () => {
it.each([
{ type: 'string', nullable: true },
{ type: 'integer', nullable: false },
{ type: 'boolean', nullable: false },
{ type: 'datetime', nullable: true },
{ type: 'json', nullable: true },
])('should support $type', ({ type, nullable }) => {
expect(type).toBeDefined()
expect(typeof nullable).toBe('boolean')
})
})
describe('relations', () => {
it.each([
{ type: 'one_to_one' },
{ type: 'one_to_many' },
{ type: 'many_to_many' },
])('should support $type relation', ({ type }) => {
expect(type).toBeDefined()
})
})
})

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
<circle cx="9" cy="7" r="4"/>
<path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
<path d="M16 3.13a4 4 0 0 1 0 7.75"/>
</svg>

After

Width:  |  Height:  |  Size: 335 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/>
</svg>

After

Width:  |  Height:  |  Size: 212 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/>
<polygon points="10 8 16 12 10 16 10 8"/>
</svg>

After

Width:  |  Height:  |  Size: 245 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"/>
<path d="M7 11V7a5 5 0 0 1 10 0v4"/>
</svg>

After

Width:  |  Height:  |  Size: 265 B

View File

@@ -0,0 +1,31 @@
import { describe, it, expect } from 'vitest'
describe('ui_auth package', () => {
describe('metadata', () => {
it('should have valid package structure', async () => {
const metadata = await import('../seed/metadata.json')
expect(metadata.packageId).toBe('ui_auth')
})
})
describe('access denied', () => {
it.each([
{ level: 2, message: 'User access required' },
{ level: 3, message: 'Admin access required' },
{ level: 4, message: 'God access required' },
{ level: 5, message: 'Super God access required' },
])('should show message for level $level', ({ message }) => {
expect(message).toBeDefined()
})
})
describe('auth gate', () => {
it.each([
{ user_level: 1, required: 2, allowed: false },
{ user_level: 2, required: 2, allowed: true },
{ user_level: 3, required: 2, allowed: true },
])('should gate level $user_level against required $required', ({ user_level, required, allowed }) => {
expect(user_level >= required).toBe(allowed)
})
})
})

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="3" width="18" height="18" rx="2"/>
<line x1="9" y1="3" x2="9" y2="21"/>
<path d="M14 9l3 3-3 3"/>
</svg>

After

Width:  |  Height:  |  Size: 285 B

View File

@@ -0,0 +1,33 @@
import { describe, it, expect } from 'vitest'
describe('ui_dialogs package', () => {
describe('metadata', () => {
it('should have valid package structure', async () => {
const metadata = await import('../seed/metadata.json')
expect(metadata.packageId).toBe('ui_dialogs')
})
})
describe('confirm dialog', () => {
it.each([
{ title: 'Delete Item', confirm: 'Delete', cancel: 'Cancel', destructive: true },
{ title: 'Save Changes', confirm: 'Save', cancel: 'Discard', destructive: false },
])('should render confirm dialog: $title', ({ title, confirm, cancel }) => {
expect(title).toBeDefined()
expect(confirm).toBeDefined()
expect(cancel).toBeDefined()
})
})
describe('alert dialog', () => {
it.each([
{ variant: 'info', icon: 'info' },
{ variant: 'success', icon: 'check' },
{ variant: 'warning', icon: 'warning' },
{ variant: 'error', icon: 'error' },
])('should render $variant alert', ({ variant, icon }) => {
expect(variant).toBeDefined()
expect(icon).toBeDefined()
})
})
})

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="3" y1="21" x2="21" y2="21"/>
<path d="M5 21V7l7-4 7 4v14"/>
<line x1="9" y1="21" x2="9" y2="14"/>
<line x1="15" y1="21" x2="15" y2="14"/>
</svg>

After

Width:  |  Height:  |  Size: 322 B

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="3" width="18" height="6" rx="2"/>
<circle cx="8" cy="6" r="1"/>
<line x1="12" y1="6" x2="18" y2="6"/>
</svg>

After

Width:  |  Height:  |  Size: 289 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
<polyline points="9 22 9 12 15 12 15 22"/>
</svg>

After

Width:  |  Height:  |  Size: 272 B

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/>
<line x1="12" y1="16" x2="12" y2="12"/>
<line x1="12" y1="8" x2="12" y2="8"/>
</svg>

After

Width:  |  Height:  |  Size: 283 B

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
<circle cx="12" cy="7" r="4"/>
<path d="M16 3l2 2-2 2"/>
</svg>

After

Width:  |  Height:  |  Size: 283 B

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,13 @@
{
"packageId": "user_manager",
"name": "User Manager",
"version": "1.0.0",
"description": "User management components and actions",
"author": "MetaBuilder",
"category": "managers",
"dependencies": ["ui_permissions", "data_table"],
"exports": {
"scripts": ["list", "actions"],
"components": ["UserManagement", "UserList", "UserActions"]
}
}

View File

@@ -0,0 +1,43 @@
-- User management actions
local M = {}
function M.create(data)
return {
action = "create_user",
data = data
}
end
function M.update(user_id, data)
return {
action = "update_user",
user_id = user_id,
data = data
}
end
function M.delete(user_id)
return {
action = "delete_user",
user_id = user_id,
confirm = true
}
end
function M.change_level(user_id, new_level)
return {
action = "change_level",
user_id = user_id,
level = new_level
}
end
function M.toggle_active(user_id, active)
return {
action = "toggle_active",
user_id = user_id,
active = active
}
end
return M

View File

@@ -0,0 +1,15 @@
-- User Manager initialization
local M = {}
M.name = "user_manager"
M.version = "1.0.0"
function M.init()
return {
name = M.name,
version = M.version,
loaded = true
}
end
return M

View File

@@ -0,0 +1,38 @@
-- User list rendering
local M = {}
function M.columns()
return {
{ id = "username", label = "Username", sortable = true },
{ id = "email", label = "Email", sortable = true },
{ id = "role", label = "Role", sortable = true },
{ id = "level", label = "Level", sortable = true },
{ id = "active", label = "Status", type = "badge" },
{ id = "actions", label = "", type = "actions" }
}
end
function M.render_row(user)
return {
username = user.username,
email = user.email,
role = user.role,
level = user.level,
active = user.active and "Active" or "Inactive",
actions = { "edit", "delete" }
}
end
function M.render(users)
local rows = {}
for _, user in ipairs(users) do
table.insert(rows, M.render_row(user))
end
return {
type = "data_table",
columns = M.columns(),
rows = rows
}
end
return M

View File

@@ -0,0 +1,22 @@
{
"scripts": [
{
"id": "init",
"name": "User Manager Init",
"file": "init.lua",
"description": "Initialize user manager module"
},
{
"id": "list",
"name": "User List",
"file": "list.lua",
"description": "Render user list table"
},
{
"id": "actions",
"name": "User Actions",
"file": "actions.lua",
"description": "User management actions"
}
]
}

View File

@@ -0,0 +1,22 @@
import { describe, it, expect } from 'vitest'
describe('user_manager package', () => {
describe('metadata', () => {
it('should have valid package structure', async () => {
const metadata = await import('../seed/metadata.json')
expect(metadata.packageId).toBe('user_manager')
})
})
describe('user actions', () => {
it.each([
{ action: 'create', requiresConfirm: false },
{ action: 'update', requiresConfirm: false },
{ action: 'delete', requiresConfirm: true },
{ action: 'change_level', requiresConfirm: false },
])('should handle $action', ({ action, requiresConfirm }) => {
expect(action).toBeDefined()
expect(typeof requiresConfirm).toBe('boolean')
})
})
})

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,13 @@
{
"packageId": "workflow_editor",
"name": "Workflow Editor",
"version": "1.0.0",
"description": "Workflow editor and run status components",
"author": "MetaBuilder",
"category": "editors",
"dependencies": [],
"exports": {
"scripts": ["editor", "status", "run"],
"components": ["WorkflowEditor", "WorkflowRunCard", "WorkflowRunStatus"]
}
}

View File

@@ -0,0 +1,33 @@
-- Workflow editor rendering
local M = {}
function M.render(workflow)
return {
type = "workflow_editor",
props = {
id = workflow and workflow.id,
name = workflow and workflow.name or "New Workflow",
steps = workflow and workflow.steps or {}
}
}
end
function M.add_step(step_type, config)
return {
type = "workflow_step",
step_type = step_type,
config = config or {},
position = { x = 0, y = 0 }
}
end
function M.connect_steps(from_id, to_id, condition)
return {
type = "connection",
from = from_id,
to = to_id,
condition = condition
}
end
return M

View File

@@ -0,0 +1,15 @@
-- Workflow Editor initialization
local M = {}
M.name = "workflow_editor"
M.version = "1.0.0"
function M.init()
return {
name = M.name,
version = M.version,
loaded = true
}
end
return M

View File

@@ -0,0 +1,28 @@
{
"scripts": [
{
"id": "init",
"name": "Workflow Editor Init",
"file": "init.lua",
"description": "Initialize workflow editor module"
},
{
"id": "editor",
"name": "Workflow Editor",
"file": "editor.lua",
"description": "Workflow editor rendering"
},
{
"id": "status",
"name": "Run Status",
"file": "status.lua",
"description": "Workflow run status display"
},
{
"id": "run",
"name": "Run Card",
"file": "run.lua",
"description": "Workflow run card component"
}
]
}

View File

@@ -0,0 +1,31 @@
-- Workflow run card utilities
local M = {}
function M.render(run)
return {
type = "card",
props = {
title = run.workflow_name,
subtitle = "Run #" .. run.run_number
},
children = {
{ type = "text", content = "Started: " .. run.started_at },
{ type = "text", content = "Duration: " .. (run.duration or "running") },
{ type = "status_badge", status = run.status }
}
}
end
function M.render_list(runs)
local cards = {}
for _, run in ipairs(runs) do
table.insert(cards, M.render(run))
end
return {
type = "grid",
columns = 2,
children = cards
}
end
return M

View File

@@ -0,0 +1,38 @@
-- Workflow run status utilities
local M = {}
M.PENDING = "pending"
M.RUNNING = "running"
M.SUCCESS = "success"
M.FAILED = "failed"
M.CANCELLED = "cancelled"
function M.render_badge(status)
local colors = {
pending = "default",
running = "info",
success = "success",
failed = "error",
cancelled = "warning"
}
return {
type = "badge",
props = {
label = status,
color = colors[status] or "default"
}
}
end
function M.render_progress(completed, total)
local percent = total > 0 and (completed / total * 100) or 0
return {
type = "progress",
props = {
value = percent,
label = completed .. "/" .. total
}
}
end
return M

View File

@@ -0,0 +1,23 @@
import { describe, it, expect } from 'vitest'
describe('workflow_editor package', () => {
describe('metadata', () => {
it('should have valid package structure', async () => {
const metadata = await import('../seed/metadata.json')
expect(metadata.packageId).toBe('workflow_editor')
})
})
describe('run status', () => {
it.each([
{ status: 'pending', color: 'default' },
{ status: 'running', color: 'info' },
{ status: 'success', color: 'success' },
{ status: 'failed', color: 'error' },
{ status: 'cancelled', color: 'warning' },
])('should render $status badge', ({ status, color }) => {
expect(status).toBeDefined()
expect(color).toBeDefined()
})
})
})