config: fakemui,packages,menu (9 files)

This commit is contained in:
Richard Ward
2025-12-30 13:25:20 +00:00
parent 8c9b6661ce
commit b2b0ade653
9 changed files with 126 additions and 42 deletions

View File

@@ -0,0 +1,10 @@
import React from 'react'
import { Icon, IconProps } from './Icon'
export const FilterOff = (props: IconProps) => (
<Icon {...props}>
<path d="M42.1 48h171.8c7.4 0 11.6 8.4 7.1 14.3L152 142.7V216l-48-24v-49.3L35 62.3c-4.5-5.9-.3-14.3 7.1-14.3Z" />
<line x1="92" y1="92" x2="164" y2="164" />
<line x1="164" y1="92" x2="92" y2="164" />
</Icon>
)

9
fakemui/icons/Flag.tsx Normal file
View File

@@ -0,0 +1,9 @@
import React from 'react'
import { Icon, IconProps } from './Icon'
export const Flag = (props: IconProps) => (
<Icon {...props}>
<line x1="64" y1="32" x2="64" y2="224" />
<path d="M64 48h96l-16 32 16 32H64z" />
</Icon>
)

View File

@@ -0,0 +1,9 @@
import React from 'react'
import { Icon, IconProps } from './Icon'
export const ShieldSlash = (props: IconProps) => (
<Icon {...props}>
<path d="M128 24l80 28v68c0 36.2-21.7 68.9-56 83.2-34.3-14.3-56-47-56-83.2V52z" />
<line x1="48" y1="40" x2="208" y2="216" />
</Icon>
)

View File

@@ -16,6 +16,7 @@ export { Stop } from './Stop'
export { Download } from './Download'
export { Upload } from './Upload'
export { Filter } from './Filter'
export { FilterOff } from './FilterOff'
export { Refresh } from './Refresh'
// Navigation
@@ -138,6 +139,7 @@ export { LockOpen } from './LockOpen'
export { Key } from './Key'
export { Shield } from './Shield'
export { UserShield } from './UserShield'
export { ShieldSlash } from './ShieldSlash'
export { Globe } from './Globe'
export { Cloud } from './Cloud'

View File

@@ -10,6 +10,8 @@ export {
Copy,
Check,
X,
Filter,
FilterOff,
// Navigation
ArrowUp,
ArrowDown,

View File

@@ -20,6 +20,14 @@ local M = {}
---@field resources string[]
---@field usernames string[]
---@class ApplyFiltersInput
---@field operation string|nil
---@field resource string|nil
---@field success boolean|nil
---@field username string|nil
---@field startTime number|nil
---@field endTime number|nil
---@class FilterByOperationCase
---@field operation string|nil
---@field expected integer

View File

@@ -0,0 +1,48 @@
{
"can_show": [
{
"user": { "level": 0 },
"item": { "label": "Home" },
"expected": true,
"desc": "item with no minLevel"
},
{
"user": { "level": 0 },
"item": { "label": "Admin", "minLevel": 3 },
"expected": false,
"desc": "low level user for admin"
},
{
"user": { "level": 3 },
"item": { "label": "Admin", "minLevel": 3 },
"expected": true,
"desc": "admin for admin item"
},
{
"user": { "level": 5 },
"item": { "label": "Admin", "minLevel": 3 },
"expected": true,
"desc": "high level for admin item"
},
{
"user": {},
"item": { "label": "Users", "minLevel": 2 },
"expected": false,
"desc": "no level user"
}
],
"render": [
{
"props": {
"user": { "level": 2 },
"items": [
{ "label": "Home", "path": "/" },
{ "label": "Admin", "path": "/admin", "minLevel": 3 },
{ "label": "Users", "path": "/users", "minLevel": 2 }
]
},
"expectedChildren": 2,
"desc": "filters items by permission"
}
]
}

View File

@@ -14,15 +14,21 @@
---@field user MenuUser
---@field items MenuItem[]
---@class MenuShowTestCase
---@field user MenuUser
---@field item MenuItem
---@field expected boolean
---@field desc string
describe("Menu", function()
-- Mock check module
local original_can_access
---@class MenuShowTestCase
---@field user MenuUser
---@field item MenuItem
---@field expected boolean
---@field desc string
---@class MenuRenderTestCase
---@field props MenuRenderProps
---@field expectedChildren integer
---@field desc string
describe("Menu", function()
-- Mock check module
---@type { can_show: MenuShowTestCase[], render: MenuRenderTestCase[] }
local cases = load_cases("menu.cases.json")
before(function()
-- Create mock for check.can_access
@@ -33,20 +39,14 @@ describe("Menu", function()
}
end)
local menu = require("menu")
describe("can_show", function()
it.each({
{ user = { level = 0 }, item = { label = "Home" }, expected = true, desc = "item with no minLevel" },
{ user = { level = 0 }, item = { label = "Admin", minLevel = 3 }, expected = false, desc = "low level user for admin" },
{ user = { level = 3 }, item = { label = "Admin", minLevel = 3 }, expected = true, desc = "admin for admin item" },
{ user = { level = 5 }, item = { label = "Admin", minLevel = 3 }, expected = true, desc = "high level for admin item" },
{ user = {}, item = { label = "Users", minLevel = 2 }, expected = false, desc = "no level user" },
})("should return $expected for $desc", function(testCase)
local result = menu.can_show(testCase.user, testCase.item)
expect(result).toBe(testCase.expected)
end)
end)
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)
end)
end)
describe("item", function()
it("should render button for simple item", function()
@@ -69,19 +69,11 @@ describe("Menu", function()
end)
end)
describe("render", function()
it("should filter items by permission", function()
local props = {
user = { level = 2 },
items = {
{ label = "Home", path = "/" },
{ label = "Admin", path = "/admin", minLevel = 3 },
{ label = "Users", path = "/users", minLevel = 2 }
}
}
local result = menu.render(props)
expect(result.type).toBe("Flex")
expect(#result.children).toBe(2) -- Home and Users, not Admin
end)
end)
end)
describe("render", function()
it.each(cases.render, "$desc", function(testCase)
local result = menu.render(testCase.props)
expect(result.type).toBe("Flex")
expect(#result.children).toBe(testCase.expectedChildren)
end)
end)
end)

View File

@@ -1,9 +1,13 @@
-- Type definitions for moderation module
-- Shared across all moderation functions
---@class ModerationContext
---@field user table User object for permission checking
---@field targetId string ID of the target user for moderation action
---@class ModerationUser
---@field id string
---@field level? number
---@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