diff --git a/fakemui/icons/ClipboardCheck.tsx b/fakemui/icons/ClipboardCheck.tsx
new file mode 100644
index 000000000..df9eea59b
--- /dev/null
+++ b/fakemui/icons/ClipboardCheck.tsx
@@ -0,0 +1,10 @@
+import React from 'react'
+import { Icon, IconProps } from './Icon'
+
+export const ClipboardCheck = (props: IconProps) => (
+
+
+
+
+
+)
diff --git a/fakemui/icons/UserMinus.tsx b/fakemui/icons/UserMinus.tsx
new file mode 100644
index 000000000..92ed7b168
--- /dev/null
+++ b/fakemui/icons/UserMinus.tsx
@@ -0,0 +1,10 @@
+import React from 'react'
+import { Icon, IconProps } from './Icon'
+
+export const UserMinus = (props: IconProps) => (
+
+
+
+
+
+)
diff --git a/fakemui/icons/index.ts b/fakemui/icons/index.ts
index 6814d0fa9..896742f2a 100644
--- a/fakemui/icons/index.ts
+++ b/fakemui/icons/index.ts
@@ -53,6 +53,8 @@ export { GearSix } from './GearSix'
export { User } from './User'
export { UserCircle } from './UserCircle'
export { UserPlus } from './UserPlus'
+export { UserMinus } from './UserMinus'
+export { UserX } from './UserX'
export { Users } from './Users'
export { UserSwitch } from './UserSwitch'
export { Menu } from './Menu'
@@ -149,6 +151,7 @@ export { Archive } from './Archive'
export { Bug } from './Bug'
export { Gavel } from './Gavel'
export { Clipboard } from './Clipboard'
+export { ClipboardCheck } from './ClipboardCheck'
export { Package } from './Package'
export { Layers } from './Layers'
export { Tag } from './Tag'
diff --git a/packages/audit_log/seed/scripts/formatting/mappings.lua b/packages/audit_log/seed/scripts/formatting/mappings.lua
index f7b0f1de2..95e933db1 100644
--- a/packages/audit_log/seed/scripts/formatting/mappings.lua
+++ b/packages/audit_log/seed/scripts/formatting/mappings.lua
@@ -14,10 +14,12 @@ M.operationColors = {
--- Resource type to icon mapping
---@type table
-M.resourceIcons = {
- user = "User",
- credential = "ShieldCheck",
- default = "ChartLine"
-}
+M.resourceIcons = {
+ user = "User",
+ credential = "ShieldCheck",
+ post = "ClipboardCheck",
+ settings = "Settings",
+ default = "ChartLine"
+}
return M
diff --git a/packages/nav_menu/seed/scripts/menu.lua b/packages/nav_menu/seed/scripts/menu.lua
index 0c966fec7..46e5b933e 100644
--- a/packages/nav_menu/seed/scripts/menu.lua
+++ b/packages/nav_menu/seed/scripts/menu.lua
@@ -17,13 +17,30 @@ local M = {}
---@class User
---@field level? number
----@class MenuProps
----@field items MenuItem[]
----@field user User
-
----@param props MenuProps
----@return UIComponent
-function M.render(props)
+---@class MenuProps
+---@field items MenuItem[]
+---@field user User
+
+---@class FlexProps
+---@field className string
+
+---@class ButtonProps
+---@field variant string
+---@field text string
+---@field onClick string
+---@field data? string
+
+---@class DropdownMenuTriggerProps
+---@field text string
+
+---@class DropdownMenuItemProps
+---@field text string
+---@field onClick string
+---@field data? string
+
+---@param props MenuProps
+---@return UIComponent
+function M.render(props)
local items = {}
for _, item in ipairs(props.items or {}) do
if M.can_show(props.user, item) then
diff --git a/packages/nav_menu/seed/scripts/tests/items.cases.json b/packages/nav_menu/seed/scripts/tests/items.cases.json
new file mode 100644
index 000000000..6ff3fdd5a
--- /dev/null
+++ b/packages/nav_menu/seed/scripts/tests/items.cases.json
@@ -0,0 +1,10 @@
+{
+ "menu_item": [
+ { "desc": "without icon", "label": "Home", "path": "/", "icon": null },
+ { "desc": "with icon", "label": "Settings", "path": "/settings", "icon": "gear" }
+ ],
+ "menu_group": [
+ { "desc": "empty group", "label": "Admin", "children": null, "icon": null },
+ { "desc": "empty children array", "label": "Settings", "children": [], "icon": "gear" }
+ ]
+}
diff --git a/packages/nav_menu/seed/scripts/tests/items.test.lua b/packages/nav_menu/seed/scripts/tests/items.test.lua
index d9a152655..aaea75313 100644
--- a/packages/nav_menu/seed/scripts/tests/items.test.lua
+++ b/packages/nav_menu/seed/scripts/tests/items.test.lua
@@ -1,35 +1,42 @@
--- Items tests for nav_menu package
--- Tests menu item builder functions
-
-local menu_item = require("items/item")
-local menu_group = require("items/group")
-local menu_divider = require("items/divider")
-
-describe("Menu Item Builders", function()
- describe("menu_item", function()
- it.each({
- { label = "Home", path = "/", icon = nil, desc = "without icon" },
- { label = "Settings", path = "/settings", icon = "gear", desc = "with icon" },
- })("should create item $desc", function(testCase)
- local result = menu_item(testCase.label, testCase.path, testCase.icon)
- expect(result.type).toBe("menu_item")
- expect(result.label).toBe(testCase.label)
- expect(result.path).toBe(testCase.path)
+-- Items tests for nav_menu package
+-- Tests menu item builder functions
+
+---@class MenuItemCase
+---@field label string
+---@field path string
+---@field icon string|nil
+---@field desc string
+
+---@class MenuGroupCase
+---@field label string
+---@field children table|nil
+---@field icon string|nil
+---@field desc string
+
+local menu_item = require("items/item")
+local menu_group = require("items/group")
+local menu_divider = require("items/divider")
+local cases = load_cases("items.cases.json")
+
+describe("Menu Item Builders", function()
+ describe("menu_item", function()
+ it.each(cases.menu_item, "$desc", function(testCase)
+ local result = menu_item(testCase.label, testCase.path, testCase.icon)
+ expect(result.type).toBe("menu_item")
+ expect(result.label).toBe(testCase.label)
+ expect(result.path).toBe(testCase.path)
if testCase.icon then
expect(result.icon).toBe(testCase.icon)
end
end)
end)
- describe("menu_group", function()
- it.each({
- { label = "Admin", children = nil, icon = nil, desc = "empty group" },
- { label = "Settings", children = {}, icon = "gear", desc = "empty children array" },
- })("should create group $desc", function(testCase)
- local result = menu_group(testCase.label, testCase.children, testCase.icon)
- expect(result.type).toBe("menu_group")
- expect(result.label).toBe(testCase.label)
- expect(result.children).toBeType("table")
+ describe("menu_group", function()
+ it.each(cases.menu_group, "$desc", function(testCase)
+ local result = menu_group(testCase.label, testCase.children, testCase.icon)
+ expect(result.type).toBe("menu_group")
+ expect(result.label).toBe(testCase.label)
+ expect(result.children).toBeType("table")
end)
it("should include children in group", function()
diff --git a/packages/nav_menu/seed/scripts/tests/menu.test.lua b/packages/nav_menu/seed/scripts/tests/menu.test.lua
index d6e55b79f..8b7dd9916 100644
--- a/packages/nav_menu/seed/scripts/tests/menu.test.lua
+++ b/packages/nav_menu/seed/scripts/tests/menu.test.lua
@@ -20,15 +20,29 @@
---@field expected boolean
---@field desc string
+---@class MenuItemRenderTestCase
+---@field item MenuItem
+---@field expectedType string
+---@field expectedText? string
+---@field expectedVariant? string
+---@field expectedChildren? integer
+---@field desc string
+
---@class MenuRenderTestCase
---@field props MenuRenderProps
---@field expectedChildren integer
---@field desc string
+---@class MenuCases
+---@field can_show MenuShowTestCase[]
+---@field item MenuItemRenderTestCase[]
+---@field render MenuRenderTestCase[]
+
describe("Menu", function()
-- Mock check module
- ---@type { can_show: MenuShowTestCase[], render: MenuRenderTestCase[] }
+ ---@type MenuCases
local cases = load_cases("menu.cases.json")
+ local it_each = require("lua_test.it_each")
before(function()
-- Create mock for check.can_access
@@ -42,38 +56,39 @@ describe("Menu", function()
local menu = require("menu")
describe("can_show", function()
- it.each(cases.can_show, "$desc", function(testCase)
- local result = menu.can_show(testCase.user, testCase.item)
- expect(result).toBe(testCase.expected)
+ it_each(cases.can_show, "$desc", function(testCase)
+ ---@type MenuShowTestCase
+ local tc = testCase
+ local result = menu.can_show(tc.user, tc.item)
+ expect(result).toBe(tc.expected)
end)
end)
-
- describe("item", function()
- it("should render button for simple item", function()
- local result = menu.item({ label = "Home", path = "/" })
- expect(result.type).toBe("Button")
- expect(result.props.text).toBe("Home")
- expect(result.props.variant).toBe("ghost")
- end)
-
- it("should render dropdown for item with children", function()
- local result = menu.item({
- label = "Settings",
- children = {
- { label = "Profile", path = "/profile" },
- { label = "Security", path = "/security" }
- }
- })
- expect(result.type).toBe("DropdownMenu")
- expect(#result.children).toBe(2)
- end)
- end)
-
+
+ describe("item", function()
+ it_each(cases.item, "$desc", function(testCase)
+ ---@type MenuItemRenderTestCase
+ local tc = testCase
+ local result = menu.item(tc.item)
+ expect(result.type).toBe(tc.expectedType)
+ if tc.expectedText then
+ expect(result.props.text).toBe(tc.expectedText)
+ end
+ if tc.expectedVariant then
+ expect(result.props.variant).toBe(tc.expectedVariant)
+ end
+ if tc.expectedChildren then
+ expect(#result.children).toBe(tc.expectedChildren)
+ end
+ end)
+ end)
+
describe("render", function()
- it.each(cases.render, "$desc", function(testCase)
- local result = menu.render(testCase.props)
+ it_each(cases.render, "$desc", function(testCase)
+ ---@type MenuRenderTestCase
+ local tc = testCase
+ local result = menu.render(tc.props)
expect(result.type).toBe("Flex")
- expect(#result.children).toBe(testCase.expectedChildren)
+ expect(#result.children).toBe(tc.expectedChildren)
end)
end)
end)
diff --git a/packages/ui_level2/seed/scripts/profile/render.lua b/packages/ui_level2/seed/scripts/profile/render.lua
index 07ae84133..5161e57e1 100644
--- a/packages/ui_level2/seed/scripts/profile/render.lua
+++ b/packages/ui_level2/seed/scripts/profile/render.lua
@@ -14,54 +14,58 @@
---@class ButtonProps
---@field text string
---@field onClick string
+---@field variant? string
---@class UserInfo
---@field username string
---@field email? string
-
----@class RenderContext
----@field user UserInfo
+
+---@class RenderContext
+---@field user UserInfo
local M = {}
---Renders the user profile card with form inputs
---@param ctx RenderContext
---@return UIComponent
-function M.render(ctx)
- return {
- type = "Card",
- children = {
- {
- type = "CardHeader",
- children = {
- { type = "CardTitle", props = { text = "Your Profile" } }
- }
- },
- {
- type = "CardContent",
- children = {
- {
- type = "Input",
- props = {
- label = "Username",
- value = ctx.user.username,
- disabled = true
- }
- },
- {
- type = "Input",
- props = {
- label = "Email",
- name = "email",
- value = ctx.user.email or ""
- }
- },
- {
- type = "Button",
- props = {
- text = "Save Changes",
- onClick = "saveProfile"
- }
+function M.render(ctx)
+ return {
+ type = "Card",
+ children = {
+ {
+ type = "CardHeader",
+ children = {
+ { type = "CardTitle", props = { text = "Your Profile" } }
+ }
+ },
+ {
+ type = "CardContent",
+ children = {
+ {
+ type = "Input",
+ props = {
+ ---@type InputProps
+ label = "Username",
+ value = ctx.user.username,
+ disabled = true
+ }
+ },
+ {
+ type = "Input",
+ props = {
+ ---@type InputProps
+ label = "Email",
+ name = "email",
+ value = ctx.user.email or ""
+ }
+ },
+ {
+ type = "Button",
+ props = {
+ ---@type ButtonProps
+ text = "Save Changes",
+ onClick = "saveProfile"
+ }
}
}
}
diff --git a/packages/ui_level3/seed/scripts/moderation/init.lua b/packages/ui_level3/seed/scripts/moderation/init.lua
index fbb6ea57b..2da27f257 100644
--- a/packages/ui_level3/seed/scripts/moderation/init.lua
+++ b/packages/ui_level3/seed/scripts/moderation/init.lua
@@ -2,14 +2,21 @@
-- Re-exports all moderation functions for backward compatibility
-- Each function is defined in its own file following 1-function-per-file pattern
+---@class ModerationUpdates
+---@field username? string
+---@field email? string
+---@field role? string
+---@field level? number
+---@field status? string
+
---@class Moderation
---@field deleteUser fun(userId: string): boolean
----@field editUser fun(userId: string, updates: table): boolean
+---@field editUser fun(userId: string, updates: ModerationUpdates): boolean
---@field banUser fun(userId: string, reason: string): boolean
local M = {}
-
--- Import all single-function modules
-local deleteUser = require("moderation.delete_user")
+
+-- Import all single-function modules
+local deleteUser = require("moderation.delete_user")
local editUser = require("moderation.edit_user")
local banUser = require("moderation.ban_user")
diff --git a/packages/ui_level3/seed/scripts/moderation/types.lua b/packages/ui_level3/seed/scripts/moderation/types.lua
index 191f85be8..c96731c57 100644
--- a/packages/ui_level3/seed/scripts/moderation/types.lua
+++ b/packages/ui_level3/seed/scripts/moderation/types.lua
@@ -8,11 +8,13 @@
---@class ModerationContext
---@field user ModerationUser User object for permission checking
---@field targetId string ID of the target user for moderation action
-
----@class ActionResult
----@field success boolean Whether the action was successful
----@field error string? Error message if unsuccessful
----@field action string? Action type to perform
----@field id string? ID of the affected user
+
+---@alias ModerationAction "delete_user"|"ban_user"|"open_edit_dialog"
+
+---@class ActionResult
+---@field success boolean Whether the action was successful
+---@field error string? Error message if unsuccessful
+---@field action ModerationAction? Action type to perform
+---@field id string? ID of the affected user
return {}
diff --git a/packages/ui_level4/seed/scripts/schemas/render.lua b/packages/ui_level4/seed/scripts/schemas/render.lua
index da323da5f..dff653821 100644
--- a/packages/ui_level4/seed/scripts/schemas/render.lua
+++ b/packages/ui_level4/seed/scripts/schemas/render.lua
@@ -39,31 +39,78 @@
---Renders the schemas tab with a grid of schema cards
---@param ctx SchemasRenderContext
---@return UIComponent
-local function render(ctx)
- local items = {}
- for _, s in ipairs(ctx.schemas or {}) do
- items[#items + 1] = {
- type = "Card",
- children = {
- { type = "CardHeader", children = { { type = "CardTitle", props = { text = s.name } } } },
- { type = "CardContent", children = {
- { type = "Typography", props = { text = s.description or "No description" } },
- { type = "Badge", props = { text = #(s.fields or {}) .. " fields" } }
- }},
- { type = "CardFooter", children = {
- { type = "Button", props = { text = "Edit", onClick = "editSchema", data = s.id } }
- }}
- }
- }
- end
- return {
- type = "Stack",
- props = { spacing = 4 },
- children = {
- { type = "Button", props = { text = "Add Schema", onClick = "addSchema" } },
- { type = "Grid", props = { cols = 2, gap = 4 }, children = items }
- }
- }
-end
+local function render(ctx)
+ ---@type UIComponent[]
+ local items = {}
+ for _, s in ipairs(ctx.schemas or {}) do
+ items[#items + 1] = {
+ type = "Card",
+ children = {
+ {
+ type = "CardHeader",
+ children = {
+ { type = "CardTitle", props = { text = s.name } }
+ }
+ },
+ {
+ type = "CardContent",
+ children = {
+ {
+ type = "Typography",
+ props = {
+ ---@type TypographyProps
+ text = s.description or "No description"
+ }
+ },
+ {
+ type = "Badge",
+ props = {
+ ---@type BadgeProps
+ text = #(s.fields or {}) .. " fields"
+ }
+ }
+ }
+ },
+ {
+ type = "CardFooter",
+ children = {
+ {
+ type = "Button",
+ props = {
+ ---@type ButtonProps
+ text = "Edit",
+ onClick = "editSchema",
+ data = s.id
+ }
+ }
+ }
+ }
+ }
+ }
+ end
+ return {
+ type = "Stack",
+ props = { spacing = 4 },
+ children = {
+ {
+ type = "Button",
+ props = {
+ ---@type ButtonProps
+ text = "Add Schema",
+ onClick = "addSchema"
+ }
+ },
+ {
+ type = "Grid",
+ props = {
+ ---@type GridProps
+ cols = 2,
+ gap = 4
+ },
+ children = items
+ }
+ }
+ }
+end
return render