Module:User:Kai/sandbox: Difference between revisions

From The Deadlock Wiki
Jump to navigation Jump to search
Fix select/where calls on Bucket query object (via update-page on MediaWiki MCP Server)
Tag: Manual revert
Format feedback cards and support tabbers view with all, resolved, and unresolved tabs (via update-page on MediaWiki MCP Server)
Line 17: Line 17:
end
end


function p.main(frame)
local function renderCard(entry, showInstruction)
     local parent = frame:getParent()
     local resolved = (entry.status == 'resolved')
     local args = parent and parent.args or frame.args
     local user = entry.user or "Anonymous"
    return p._main(args)
     local feedback = entry.feedback or "No feedback provided"
end
     local page = entry.page
 
function p._main(args)
     local feedback = args.feedback or "No feedback provided"
     local user = args.user or "Anonymous"
    local resolved = isTruthy(args.resolved)
    local statusStr = resolved and 'resolved' or 'unresolved'
    local currentPage = mw.title.getCurrentTitle().fullText


    -- Write directly to the Bucket database
    if mw.ext and mw.ext.bucket then
        mw.ext.bucket('feedback').put({
            page = currentPage,
            user = user,
            status = statusStr,
            feedback = feedback
        })
    end
    -- Build HTML display
     local root = mw.html.create('div')
     local root = mw.html.create('div')
         :addClass('feedback-box')
         :addClass('feedback-box')
Line 47: Line 29:
     local meta = root:tag('div')
     local meta = root:tag('div')
         :addClass('feedback-meta')
         :addClass('feedback-meta')
    if page and page ~= '' then
        meta:tag('span')
            :addClass('feedback-page')
            :wikitext(string.format('[[%s]]', page))
        meta:tag('span')
            :addClass('feedback-separator')
            :wikitext(' • ')
    end


     meta:tag('span')
     meta:tag('span')
Line 65: Line 57:
         :wikitext(feedback)
         :wikitext(feedback)


     if not resolved then
     if showInstruction and not resolved then
         root:tag('div')
         root:tag('div')
             :addClass('feedback-instruction')
             :addClass('feedback-instruction')
             :wikitext('If this feedback has been resolved, edit this page and set <code>|resolved=true</code>.')
             :wikitext('If this feedback has been resolved, edit this page and set <code>|resolved=true</code>.')
     end
     end
    return tostring(root)
end
function p.main(frame)
    local parent = frame:getParent()
    local args = parent and parent.args or frame.args
    return p._main(args)
end
function p._main(args)
    local feedback = args.feedback or "No feedback provided"
    local user = args.user or "Anonymous"
    local resolved = isTruthy(args.resolved)
    local statusStr = resolved and 'resolved' or 'unresolved'
    local currentPage = mw.title.getCurrentTitle().fullText
    -- Write directly to the Bucket database
    if mw.ext and mw.ext.bucket then
        mw.ext.bucket('feedback').put({
            page = currentPage,
            user = user,
            status = statusStr,
            feedback = feedback
        })
    end
    local card = renderCard({
        page = nil,
        user = user,
        status = statusStr,
        feedback = feedback
    }, true)


     local category = resolved and '[[Category:Resolved Feedback]]' or '[[Category:Unresolved Feedback]]'
     local category = resolved and '[[Category:Resolved Feedback]]' or '[[Category:Unresolved Feedback]]'


     return tostring(root) .. category
     return card .. category
end
 
local function renderFeedbackList(results)
    if not results or #results == 0 then
        return "<em>No feedback entries found.</em>"
    end
 
    local list = {}
    for _, row in ipairs(results) do
        table.insert(list, renderCard(row, false))
    end
    return table.concat(list, "\n")
end
end


Line 79: Line 116:
     local parent = frame:getParent()
     local parent = frame:getParent()
     local args = parent and parent.args or frame.args
     local args = parent and parent.args or frame.args
     return p._view(args)
     return p._view(args, frame)
end
end


function p._view(args)
function p._view(args, frame)
     if not (mw.ext and mw.ext.bucket) then
     if not (mw.ext and mw.ext.bucket) then
         return "<em>Bucket extension is not available.</em>"
         return "<em>Bucket extension is not available.</em>"
     end
     end


     local filterStatus = mw.text.trim(args.status or args[1] or 'all'):lower()
    frame = frame or mw.getCurrentFrame()
 
     local filterStatus = mw.text.trim(args.status or args[1] or 'tabber'):lower()
    local query = mw.ext.bucket('feedback')
    query.select('page', 'user', 'status', 'feedback')


     if filterStatus == 'resolved' or filterStatus == 'unresolved' then
     if filterStatus == 'resolved' or filterStatus == 'unresolved' then
        local query = mw.ext.bucket('feedback')
        query.select('page', 'user', 'status', 'feedback')
         query.where('status', filterStatus)
         query.where('status', filterStatus)
        return renderFeedbackList(query.run())
    elseif filterStatus == 'all' then
        local query = mw.ext.bucket('feedback')
        query.select('page', 'user', 'status', 'feedback')
        return renderFeedbackList(query.run())
     end
     end


     local results = query.run()
    -- Tabber mode (default): queries all, unresolved, and resolved tabs
     local qAll = mw.ext.bucket('feedback')
    qAll.select('page', 'user', 'status', 'feedback')
    local allEntries = qAll.run()


     if not results or #results == 0 then
    local allList = {}
         return "<em>No feedback entries found.</em>"
    local unresolvedList = {}
    local resolvedList = {}
 
     if allEntries and #allEntries > 0 then
        for _, row in ipairs(allEntries) do
            local card = renderCard(row, false)
            table.insert(allList, card)
            if row.status == 'resolved' then
                table.insert(resolvedList, card)
            else
                table.insert(unresolvedList, card)
            end
         end
     end
     end


     local tableRoot = mw.html.create('table')
     local allContent = (#allList > 0) and table.concat(allList, "\n") or "<em>No feedback entries found.</em>"
        :addClass('wikitable sortable')
     local unresolvedContent = (#unresolvedList > 0) and table.concat(unresolvedList, "\n") or "<em>No unresolved feedback entries found.</em>"
        :css('width', '100%')
     local resolvedContent = (#resolvedList > 0) and table.concat(resolvedList, "\n") or "<em>No resolved feedback entries found.</em>"
 
     local header = tableRoot:tag('tr')
    header:tag('th'):wikitext('Page')
     header:tag('th'):wikitext('User')
    header:tag('th'):wikitext('Status')
    header:tag('th'):wikitext('Feedback')
 
    for _, row in ipairs(results) do
        local tr = tableRoot:tag('tr')
        tr:tag('td'):wikitext(string.format('[[%s]]', row.page or ''))
        tr:tag('td'):wikitext(formatUser(row.user))
 
        local isResolved = row.status == 'resolved'
        local statusText = isResolved and 'Resolved' or 'Unresolved'
        local statusStyle = isResolved and 'color: #2e7d32; font-weight: bold;' or 'color: #c62828; font-weight: bold;'
 
        tr:tag('td')
            :cssText(statusStyle)
            :wikitext(statusText)


        tr:tag('td'):wikitext(row.feedback or '')
    local tabberBody = string.format("All=\n%s\n|-|Unresolved=\n%s\n|-|Resolved=\n%s", allContent, unresolvedContent, resolvedContent)
    end


     return tostring(tableRoot)
     return frame:callParserFunction('#tag', { 'tabber', tabberBody })
end
end


return p
return p

Revision as of 21:25, 27 August 2026

Documentation for this module may be created at Module:User:Kai/sandbox/doc

local p = {}

local function isTruthy(v)
    if v == nil then
        return false
    end
    v = mw.text.trim(tostring(v)):lower()
    return v ~= '' and v ~= '0' and v ~= 'false' and v ~= 'no' and v ~= 'off'
end

local function formatUser(user)
    user = mw.text.trim(tostring(user or ''))
    if user == '' or user:lower() == 'anonymous' then
        return 'Anonymous'
    end
    return string.format('[[User:%s|%s]]', user, user)
end

local function renderCard(entry, showInstruction)
    local resolved = (entry.status == 'resolved')
    local user = entry.user or "Anonymous"
    local feedback = entry.feedback or "No feedback provided"
    local page = entry.page

    local root = mw.html.create('div')
        :addClass('feedback-box')
        :addClass(resolved and 'feedback-box--resolved' or 'feedback-box--unresolved')

    local meta = root:tag('div')
        :addClass('feedback-meta')

    if page and page ~= '' then
        meta:tag('span')
            :addClass('feedback-page')
            :wikitext(string.format('[[%s]]', page))

        meta:tag('span')
            :addClass('feedback-separator')
            :wikitext(' • ')
    end

    meta:tag('span')
        :addClass('feedback-user')
        :wikitext(formatUser(user))

    meta:tag('span')
        :addClass('feedback-separator')
        :wikitext(' • ')

    meta:tag('span')
        :addClass('feedback-status')
        :addClass(resolved and 'feedback-status--resolved' or 'feedback-status--unresolved')
        :wikitext(resolved and 'Resolved' or 'Unresolved')

    root:tag('div')
        :addClass('feedback-body')
        :wikitext(feedback)

    if showInstruction and not resolved then
        root:tag('div')
            :addClass('feedback-instruction')
            :wikitext('If this feedback has been resolved, edit this page and set <code>|resolved=true</code>.')
    end

    return tostring(root)
end

function p.main(frame)
    local parent = frame:getParent()
    local args = parent and parent.args or frame.args
    return p._main(args)
end

function p._main(args)
    local feedback = args.feedback or "No feedback provided"
    local user = args.user or "Anonymous"
    local resolved = isTruthy(args.resolved)
    local statusStr = resolved and 'resolved' or 'unresolved'
    local currentPage = mw.title.getCurrentTitle().fullText

    -- Write directly to the Bucket database
    if mw.ext and mw.ext.bucket then
        mw.ext.bucket('feedback').put({
            page = currentPage,
            user = user,
            status = statusStr,
            feedback = feedback
        })
    end

    local card = renderCard({
        page = nil,
        user = user,
        status = statusStr,
        feedback = feedback
    }, true)

    local category = resolved and '[[Category:Resolved Feedback]]' or '[[Category:Unresolved Feedback]]'

    return card .. category
end

local function renderFeedbackList(results)
    if not results or #results == 0 then
        return "<em>No feedback entries found.</em>"
    end

    local list = {}
    for _, row in ipairs(results) do
        table.insert(list, renderCard(row, false))
    end
    return table.concat(list, "\n")
end

function p.view(frame)
    local parent = frame:getParent()
    local args = parent and parent.args or frame.args
    return p._view(args, frame)
end

function p._view(args, frame)
    if not (mw.ext and mw.ext.bucket) then
        return "<em>Bucket extension is not available.</em>"
    end

    frame = frame or mw.getCurrentFrame()
    local filterStatus = mw.text.trim(args.status or args[1] or 'tabber'):lower()

    if filterStatus == 'resolved' or filterStatus == 'unresolved' then
        local query = mw.ext.bucket('feedback')
        query.select('page', 'user', 'status', 'feedback')
        query.where('status', filterStatus)
        return renderFeedbackList(query.run())
    elseif filterStatus == 'all' then
        local query = mw.ext.bucket('feedback')
        query.select('page', 'user', 'status', 'feedback')
        return renderFeedbackList(query.run())
    end

    -- Tabber mode (default): queries all, unresolved, and resolved tabs
    local qAll = mw.ext.bucket('feedback')
    qAll.select('page', 'user', 'status', 'feedback')
    local allEntries = qAll.run()

    local allList = {}
    local unresolvedList = {}
    local resolvedList = {}

    if allEntries and #allEntries > 0 then
        for _, row in ipairs(allEntries) do
            local card = renderCard(row, false)
            table.insert(allList, card)
            if row.status == 'resolved' then
                table.insert(resolvedList, card)
            else
                table.insert(unresolvedList, card)
            end
        end
    end

    local allContent = (#allList > 0) and table.concat(allList, "\n") or "<em>No feedback entries found.</em>"
    local unresolvedContent = (#unresolvedList > 0) and table.concat(unresolvedList, "\n") or "<em>No unresolved feedback entries found.</em>"
    local resolvedContent = (#resolvedList > 0) and table.concat(resolvedList, "\n") or "<em>No resolved feedback entries found.</em>"

    local tabberBody = string.format("All=\n%s\n|-|Unresolved=\n%s\n|-|Resolved=\n%s", allContent, unresolvedContent, resolvedContent)

    return frame:callParserFunction('#tag', { 'tabber', tabberBody })
end

return p