Modul:ProjectGraph
Die Dokumentation für dieses Modul kann unter Modul:ProjectGraph/Doku erstellt werden
local p = {}
local function mermaidId(title)
local base = mw.ustring.gsub(title, "[^%w]", "_")
if mw.ustring.match(base, "^%d") then base = "T_" .. base end
if #base > 40 then
local h = mw.hash.hashValue("md5", title):sub(1, 10)
base = base:sub(1, 30) .. "_" .. h
end
return base
end
local function stripNs(title)
return mw.ustring.gsub(title or "", "^[^:]+:", "")
end
local function getPrintouts(row)
if row.printouts then return row.printouts end
return row
end
local function asList(v)
if not v then return {} end
if type(v) ~= "table" then return { v } end
return v
end
local function valueToString(v)
if type(v) == "table" then
if v.fulltext then return v.fulltext end
if v.value then return tostring(v.value) end
if v[1] then return valueToString(v[1]) end
end
if type(v) == "string" then return v end
if type(v) == "number" then return tostring(v) end
return nil
end
local function rowTitle(row)
if row.fulltext then return row.fulltext end
if row[1] and type(row[1]) == "string" then return row[1] end
if row[1] and type(row[1]) == "table" and row[1].fulltext then return row[1].fulltext end
return nil
end
local function norm(s)
if not s then return "todo" end
s = mw.ustring.lower(mw.text.trim(tostring(s)))
if s == "" then return "todo" end
return s
end
local function firstText(po, key)
local v = po[key]
if not v then return nil end
if type(v) == "table" and v[1] ~= nil then
return valueToString(v[1])
end
return valueToString(v)
end
function p.mermaid(frame)
local args = frame.args
local parentArgs = frame:getParent() and frame:getParent().args or {}
local project = args.project or parentArgs.project
if not project or project == "" then
return "Fehler: project=... fehlt."
end
local q = {
string.format("[[Gehört zu Projekt::%s]]", project),
"?Abhängig von",
"?Status",
"limit=2000"
}
local res = mw.smw.ask(q) or {}
local nodes = {}
local edges = {}
for _, row in ipairs(res) do
local title = rowTitle(row)
if title then
local po = getPrintouts(row)
local st = norm(firstText(po, "Status"))
nodes[title] = nodes[title] or { id = mermaidId(title), status = st }
local deps = po["Abhängig von"]
for _, dv in ipairs(asList(deps)) do
local depTitle = valueToString(dv)
if depTitle and depTitle ~= "" then
nodes[depTitle] = nodes[depTitle] or { id = mermaidId(depTitle), status = "todo" }
edges[nodes[depTitle].id .. "-->" .. nodes[title].id] = true
end
end
end
end
local out = {}
table.insert(out, "{{#mermaid:")
table.insert(out, "flowchart LR")
-- Node labels
for t, n in pairs(nodes) do
local label = stripNs(t)
label = mw.ustring.gsub(label, '"', '\\"')
table.insert(out, string.format(' %s["%s"]', n.id, label))
end
-- edges
for k, _ in pairs(edges) do
local fromId, toId = k:match("^(.-)%-%-%>(.-)$")
if fromId and toId then
table.insert(out, string.format(" %s --> %s", fromId, toId))
end
end
-- Styles (optional)
table.insert(out, " classDef todo fill:#fff,stroke:#333;")
table.insert(out, " classDef doing fill:#fff,stroke:#333,stroke-width:2px;")
table.insert(out, " classDef done fill:#fff,stroke:#0a0,stroke-width:2px;")
table.insert(out, " classDef onhold fill:#fff,stroke:#999,stroke-dasharray: 5 5;")
table.insert(out, " classDef blocked fill:#fff,stroke:#f00,stroke-width:2px;")
for _, n in pairs(nodes) do
table.insert(out, string.format(" class %s %s;", n.id, norm(n.status)))
end
table.insert(out, "}}")
return table.concat(out, "\n")
end
return p