Module:MaintenanceDashboard: Difference between revisions
Fix category links by adding colon prefix so they render as links instead of category assignments (via update-page on MediaWiki MCP Server) |
Change Missing Brand Pages link to point to maintenance page section instead of Special:WantedPages (via update-page on MediaWiki MCP Server) |
||
| (2 intermediate revisions by the same user not shown) | |||
| Line 19: | Line 19: | ||
-- Generate a single status card | -- Generate a single status card | ||
local function statusCard(label, count, link, threshold_warning, threshold_error) | -- If fixedStatus is provided, it overrides threshold-based status | ||
local function statusCard(label, count, link, threshold_warning, threshold_error, fixedStatus) | |||
threshold_warning = threshold_warning or 1 | threshold_warning = threshold_warning or 1 | ||
threshold_error = threshold_error or 10 | threshold_error = threshold_error or 10 | ||
local status = 'ok' | local status | ||
if fixedStatus then | |||
status = fixedStatus | |||
else | |||
status = 'ok' | |||
if count >= threshold_error then | |||
status = 'error' | |||
elseif count >= threshold_warning then | |||
status = 'warning' | |||
end | |||
end | end | ||
| Line 41: | Line 47: | ||
return '{{Maintenance status card|label=' .. label .. '|count=' .. count .. '|status=' .. status .. linkAttr .. '}}' | return '{{Maintenance status card|label=' .. label .. '|count=' .. count .. '|status=' .. status .. linkAttr .. '}}' | ||
end | |||
-- Count missing brand pages (brands used but no wiki page exists) | |||
local function countMissingBrandPages(frame) | |||
local missingCount = 0 | |||
local checkedBrands = {} | |||
-- Get all brands from CRT models | |||
local crtBrandQuery = frame:preprocess('{{#ask:[[Category:CRT models]][[Has brand::+]]|?Has brand|format=broadtable|headers=hide|link=none|mainlabel=-|limit=500|searchlabel=}}') | |||
if crtBrandQuery then | |||
for cell in crtBrandQuery:gmatch('<td[^>]*>(.-)</td>') do | |||
local brand = trim(cell:gsub('<[^>]+>', '')) | |||
if brand and brand ~= '' and not checkedBrands[brand] then | |||
checkedBrands[brand] = true | |||
local title = mw.title.new(brand) | |||
if title and not title.exists then | |||
missingCount = missingCount + 1 | |||
end | |||
end | |||
end | |||
end | |||
-- Get all brands from AV devices | |||
local avBrandQuery = frame:preprocess('{{#ask:[[Category:AV devices]][[Has brand::+]]|?Has brand|format=broadtable|headers=hide|link=none|mainlabel=-|limit=500|searchlabel=}}') | |||
if avBrandQuery then | |||
for cell in avBrandQuery:gmatch('<td[^>]*>(.-)</td>') do | |||
local brand = trim(cell:gsub('<[^>]+>', '')) | |||
if brand and brand ~= '' and not checkedBrands[brand] then | |||
checkedBrands[brand] = true | |||
local title = mw.title.new(brand) | |||
if title and not title.exists then | |||
missingCount = missingCount + 1 | |||
end | |||
end | |||
end | |||
end | |||
return missingCount | |||
end | end | ||
| Line 172: | Line 216: | ||
-- Build output | -- Build output | ||
-- All category issues should be red/green (any missing = red) | |||
local cards = {} | local cards = {} | ||
table.insert(cards, statusCard('CRT Brand Categories', missingCRTBrands, 'EveryCRT:Category maintenance#CRT Brands Missing Category Pages', 1, | table.insert(cards, statusCard('CRT Brand Categories', missingCRTBrands, 'EveryCRT:Category maintenance#CRT Brands Missing Category Pages', 1, 1)) | ||
table.insert(cards, statusCard('CRT Type Categories', missingCRTTypes, 'EveryCRT:Category maintenance#CRT Types Missing Category Pages', 1, | table.insert(cards, statusCard('CRT Type Categories', missingCRTTypes, 'EveryCRT:Category maintenance#CRT Types Missing Category Pages', 1, 1)) | ||
table.insert(cards, statusCard('AV Brand Categories', missingAVBrands, 'EveryCRT:Category maintenance#AV Brands Missing Category Pages', 1, | table.insert(cards, statusCard('AV Brand Categories', missingAVBrands, 'EveryCRT:Category maintenance#AV Brands Missing Category Pages', 1, 1)) | ||
table.insert(cards, statusCard('AV Type Categories', missingAVTypes, 'EveryCRT:Category maintenance#AV Device Types Missing Category Pages', 1, | table.insert(cards, statusCard('AV Type Categories', missingAVTypes, 'EveryCRT:Category maintenance#AV Device Types Missing Category Pages', 1, 1)) | ||
local output = '<div class="maintenance-status-grid">\n' | local output = '<div class="maintenance-status-grid">\n' | ||
| Line 194: | Line 239: | ||
local crtNoSeries = getCount(frame, '[[Category:CRTs without series]]') | local crtNoSeries = getCount(frame, '[[Category:CRTs without series]]') | ||
local avStubs = getCount(frame, '[[Category:AV device stubs]]') | local avStubs = getCount(frame, '[[Category:AV device stubs]]') | ||
local docsMissingContent = getCount(frame, '[[Category:Documents missing content]]') | |||
local docsOrphaned = getCount(frame, '[[Category:Orphaned documents]]') | |||
local missingBrandPages = countMissingBrandPages(frame) | |||
local cards = {} | local cards = {} | ||
table.insert(cards, statusCard('CRT Stubs', crtStubs, 'Category:CRT stubs', | -- Missing brand pages: red/green (any = red) - links to section on this page | ||
table.insert(cards, statusCard('CRTs Need Images', crtNoImage, 'Category:CRT models needing images', | table.insert(cards, statusCard('Missing Brand Pages', missingBrandPages, 'EveryCRT:Maintenance#Missing Brand Pages', 1, 1)) | ||
table.insert(cards, statusCard(' | -- Missing type: red/green (any missing = red) | ||
table.insert(cards, statusCard(' | table.insert(cards, statusCard('CRTs Missing Type', crtNoType, 'Category:CRTs missing type', 1, 1)) | ||
table.insert(cards, statusCard(' | -- Stubs and missing images: yellow/green (warning at 1, no red) | ||
table.insert(cards, statusCard('CRT Stubs', crtStubs, 'Category:CRT stubs', 1, 99999)) | |||
table.insert(cards, statusCard('CRTs Need Images', crtNoImage, 'Category:CRT models needing images', 1, 99999)) | |||
-- AV stubs: yellow/green (warning at 1, no red) | |||
table.insert(cards, statusCard('AV Device Stubs', avStubs, 'Category:AV device stubs', 1, 99999)) | |||
-- Documents: yellow/green (warning at 1, no red) | |||
table.insert(cards, statusCard('Docs Missing Content', docsMissingContent, 'Category:Documents missing content', 1, 99999)) | |||
table.insert(cards, statusCard('Orphaned Docs', docsOrphaned, 'Category:Orphaned documents', 1, 99999)) | |||
-- No series: informational only (gray), not an issue | |||
table.insert(cards, statusCard('CRTs No Series', crtNoSeries, 'Category:CRTs without series', nil, nil, 'info')) | |||
local output = '<div class="maintenance-status-grid">\n' | local output = '<div class="maintenance-status-grid">\n' | ||
| Line 260: | Line 317: | ||
return tostring(totalIssues) | return tostring(totalIssues) | ||
end | |||
-- List missing brand pages for a detailed view | |||
function p.listMissingBrandPages(frame) | |||
local missingBrands = {} | |||
local checkedBrands = {} | |||
-- Get all brands from CRT models | |||
local crtBrandQuery = frame:preprocess('{{#ask:[[Category:CRT models]][[Has brand::+]]|?Has brand|format=broadtable|headers=hide|link=none|mainlabel=-|limit=500|searchlabel=}}') | |||
if crtBrandQuery then | |||
for cell in crtBrandQuery:gmatch('<td[^>]*>(.-)</td>') do | |||
local brand = trim(cell:gsub('<[^>]+>', '')) | |||
if brand and brand ~= '' and not checkedBrands[brand] then | |||
checkedBrands[brand] = true | |||
local title = mw.title.new(brand) | |||
if title and not title.exists then | |||
table.insert(missingBrands, brand) | |||
end | |||
end | |||
end | |||
end | |||
-- Get all brands from AV devices | |||
local avBrandQuery = frame:preprocess('{{#ask:[[Category:AV devices]][[Has brand::+]]|?Has brand|format=broadtable|headers=hide|link=none|mainlabel=-|limit=500|searchlabel=}}') | |||
if avBrandQuery then | |||
for cell in avBrandQuery:gmatch('<td[^>]*>(.-)</td>') do | |||
local brand = trim(cell:gsub('<[^>]+>', '')) | |||
if brand and brand ~= '' and not checkedBrands[brand] then | |||
checkedBrands[brand] = true | |||
local title = mw.title.new(brand) | |||
if title and not title.exists then | |||
table.insert(missingBrands, brand) | |||
end | |||
end | |||
end | |||
end | |||
table.sort(missingBrands) | |||
if #missingBrands == 0 then | |||
return "✓ ''All brand pages exist.''" | |||
end | |||
local output = {} | |||
for _, brand in ipairs(missingBrands) do | |||
-- Count how many products use this brand | |||
local crtCount = getCount(frame, '[[Category:CRT models]][[Has brand::' .. brand .. ']]') | |||
local avCount = getCount(frame, '[[Category:AV devices]][[Has brand::' .. brand .. ']]') | |||
local totalCount = crtCount + avCount | |||
table.insert(output, '* [[' .. brand .. ']] — ' .. totalCount .. ' products') | |||
end | |||
return table.concat(output, '\n') | |||
end | end | ||
return p | return p | ||