Module:User:Kai/sandbox: Difference between revisionsGive feedback
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 | local function renderCard(entry, showInstruction) | ||
local | local resolved = (entry.status == 'resolved') | ||
local | local user = entry.user or "Anonymous" | ||
local feedback = entry.feedback or "No feedback provided" | |||
local page = entry.page | |||
local feedback = | |||
local | |||
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 | 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 ' | 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 | 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 | -- 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 | 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 | end | ||
local | 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 | |||
local tabberBody = string.format("All=\n%s\n|-|Unresolved=\n%s\n|-|Resolved=\n%s", allContent, unresolvedContent, resolvedContent) | |||
return | 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