feat: write template
This commit is contained in:
commit
a0a6d2cf84
98 files changed
+6609
No files matched your search
@@ -0,0 +1,45 @@
|
||||
#let _acronymDict = state("b57641b0-ef4f-4914-9114-20ce81a4a2ab", (:))
|
||||
|
||||
|
||||
#let setDefaults(defaults) = {
|
||||
_acronymDict.update(dict => {
|
||||
for (acronym, explanation) in defaults.pairs() {
|
||||
dict.insert(acronym, explanation)
|
||||
}
|
||||
return dict
|
||||
})
|
||||
}
|
||||
|
||||
#let acronym(acronym, explanation) = {
|
||||
_acronymDict.update(dict => {
|
||||
dict.insert(acronym, explanation)
|
||||
return dict
|
||||
})
|
||||
acronym
|
||||
}
|
||||
|
||||
#let acronymList() = {
|
||||
context {
|
||||
[ = Abkürzungsverzeichnis]
|
||||
terms(tight: true)
|
||||
figure(
|
||||
table(
|
||||
columns: (1fr, 3fr),
|
||||
table.header([Abkürzung], [Bedeutung]),
|
||||
|
||||
.._acronymDict
|
||||
.get()
|
||||
.keys()
|
||||
.sorted(key: lower)
|
||||
.map(key => {
|
||||
return (
|
||||
key,
|
||||
_acronymDict.get().at(key),
|
||||
)
|
||||
})
|
||||
.flatten(),
|
||||
),
|
||||
caption: [Abkürzungsverzeichnis],
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
#let timetable = state("6467cc7b-cfda-4f4d-a2fe-2e5e696dff91", (:))
|
||||
|
||||
#let format_int(x) = (
|
||||
if x == 0 [0] else if x > 0 [$+$#str(x)] else [#str(x)]
|
||||
)
|
||||
|
||||
#let addTimetable(times) = {
|
||||
timetable.update(tt => {
|
||||
for (date, tasks) in times.pairs() {
|
||||
tt.insert(date, tasks.filter(t => t.name != "Total"))
|
||||
}
|
||||
return tt
|
||||
})
|
||||
}
|
||||
|
||||
#let dayNr = state("345de571-1c11-4fba-9ebf-61c2088e286a", 0)
|
||||
#let entry(
|
||||
day: datetime,
|
||||
defaultPerson: str,
|
||||
supplementaryPersons: (:),
|
||||
tagesablauf,
|
||||
hilfestellungen,
|
||||
gut,
|
||||
schlecht,
|
||||
erkenntnisse,
|
||||
) = {
|
||||
dayNr.update(i => i + 1)
|
||||
context {
|
||||
if dayNr.get() > 1 { pagebreak(weak: true) }
|
||||
|
||||
heading(level: 2, [Tag #dayNr.get() | #day.display("[day].[month].[year]")])
|
||||
|
||||
show heading.where(level: 3): set heading(numbering: none, outlined: false)
|
||||
show heading.where(level: 3): set heading(numbering: none, outlined: false)
|
||||
|
||||
|
||||
let taetigkeiten = timetable.get().at(day.display("[day padding:none]-[month padding:none]-[year]"))
|
||||
|
||||
|
||||
let total_soll = (
|
||||
taetigkeiten.fold(
|
||||
0,
|
||||
(acc, t) => if t.keys().contains("should") { acc + t.should } else { acc },
|
||||
)
|
||||
/ 60
|
||||
) // total should hours
|
||||
|
||||
let total_ist = (
|
||||
taetigkeiten.fold(
|
||||
0,
|
||||
(acc, t) => if t.keys().contains("is") { acc + t.is } else { acc },
|
||||
)
|
||||
/ 60
|
||||
) // total should hours
|
||||
|
||||
figure(
|
||||
table(
|
||||
columns: (3fr, 1fr, 1fr, 1fr, 1fr),
|
||||
align: (left, center, center, center, center),
|
||||
table.header([Tätigkeiten], [Beteiligte Personen], [Aufwand SOLL [h]], [Aufwand IST [h]], [Differenz [h]]),
|
||||
|
||||
..taetigkeiten
|
||||
.map(t => (
|
||||
t.at("name"),
|
||||
if supplementaryPersons.keys().contains(t.at("name")) {
|
||||
(defaultPerson, ..supplementaryPersons.at(t.at("name"))).join(", ")
|
||||
} else {
|
||||
defaultPerson
|
||||
},
|
||||
str(t.at("should", default: "") / 60),
|
||||
str(t.at("is", default: "") / 60),
|
||||
if t.keys().contains("is") and t.keys().contains("should") {
|
||||
format_int((t.is / 60) - (t.should / 60))
|
||||
} else { "" },
|
||||
))
|
||||
.flatten(),
|
||||
[*Totaler Zeitaufwand*],
|
||||
[],
|
||||
str(total_soll),
|
||||
str(total_ist),
|
||||
|
||||
format_int(total_ist - total_soll),
|
||||
),
|
||||
caption: [Tätigkeiten Tag #dayNr.get()],
|
||||
)
|
||||
[
|
||||
=== Tagesablauf
|
||||
|
||||
#tagesablauf
|
||||
|
||||
=== Hilfestellungen
|
||||
|
||||
#hilfestellungen
|
||||
|
||||
=== Reflexion
|
||||
|
||||
_Was lief gut?_
|
||||
|
||||
#gut
|
||||
|
||||
_Was lief weniger gut?_
|
||||
|
||||
#schlecht
|
||||
|
||||
_Erkenntnisse_
|
||||
|
||||
#erkenntnisse
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
// Execute: `git ls-files > ../../07_Anhang/source-paths.txt` while in the code directory
|
||||
#import "../pallete.typ": palette
|
||||
#import "@preview/shadowed:0.3.0": shadow
|
||||
|
||||
#let excluded = (
|
||||
"package-lock.json",
|
||||
"go.sum",
|
||||
".vscode",
|
||||
".husky",
|
||||
".npmrc",
|
||||
)
|
||||
|
||||
#let generated = (
|
||||
"package.json",
|
||||
"go.mod",
|
||||
"tsconfig.",
|
||||
"jestGlobalMocks.ts",
|
||||
"setupJest.ts",
|
||||
"jest.config.ts",
|
||||
"jest.config.js",
|
||||
"styles.scss",
|
||||
"index.html",
|
||||
".browserslistrc",
|
||||
".editorconfig",
|
||||
".prettierrc",
|
||||
".npmrc",
|
||||
".husky",
|
||||
"code-project",
|
||||
"eslint.config.mjs",
|
||||
"angular.json",
|
||||
"api.gen.go",
|
||||
".bru",
|
||||
)
|
||||
|
||||
#let generated-changed = (
|
||||
"angular.json",
|
||||
)
|
||||
|
||||
#let refs = (
|
||||
"schema.cql": "schema-cql",
|
||||
"kafka-startup.sh": "kafka-startup",
|
||||
"service_test.go": "journal-integrationtest",
|
||||
"auto-backup": "auto-backup",
|
||||
)
|
||||
|
||||
#let code(files: (), generated: generated, excluded: excluded) = {
|
||||
show figure.where(kind: raw): set block(breakable: true)
|
||||
|
||||
// Sort files by path
|
||||
let sorted-files = files.sorted(key: f => f.path)
|
||||
|
||||
for file in sorted-files {
|
||||
let path = file.path
|
||||
if excluded.any(ex => path.contains(ex)) {
|
||||
continue
|
||||
}
|
||||
|
||||
let content = file.content
|
||||
|
||||
let refkey = refs.keys().find(r => path.contains(r))
|
||||
let ref = if refkey != none { refs.at(refkey) } else { none }
|
||||
|
||||
let filetype = path.split(".").last()
|
||||
|
||||
let map = (
|
||||
kt: "kotlin",
|
||||
sh: "bash",
|
||||
ts: "typescript",
|
||||
scss: "css",
|
||||
html: "html",
|
||||
go: "go",
|
||||
mod: "gomod",
|
||||
gitignore: "gitignore",
|
||||
json: "json",
|
||||
"Dockerfile": "Dockerfile",
|
||||
cql: "sql",
|
||||
yaml: "yml",
|
||||
yml: "yml",
|
||||
example: "env", // .env.exampln
|
||||
md: "markdown",
|
||||
js: "js",
|
||||
mjs: "js",
|
||||
Makefile: "make",
|
||||
makefile: "make",
|
||||
)
|
||||
|
||||
if map.keys().contains(filetype) {
|
||||
filetype = map.at(filetype)
|
||||
} else {
|
||||
filetype = "text"
|
||||
}
|
||||
|
||||
[
|
||||
// #show heading: it => {
|
||||
// let h1 = query(metadata.where(value: path).before(here()))
|
||||
// if h1.len() != 0 and h1.first().location().position().y > page.height * .8 {
|
||||
// pagebreak()
|
||||
// }
|
||||
// it
|
||||
// }
|
||||
// #show figure: set block(breakable: true)
|
||||
//
|
||||
|
||||
|
||||
|
||||
#show heading.where(level: 3): it => {
|
||||
let threshold = 20%
|
||||
block(breakable: false, height: threshold, spacing: 0pt)
|
||||
v(-threshold)
|
||||
it
|
||||
}
|
||||
|
||||
#metadata(path)
|
||||
#heading(outlined: false, level: 3)[
|
||||
#path #if generated.any(gen => path.contains(gen)) { [ | Generiert ] }
|
||||
]
|
||||
|
||||
#figure(
|
||||
block(
|
||||
stroke: 0.5pt + palette.ui.border,
|
||||
width: 100%,
|
||||
inset: 5pt,
|
||||
fill: white,
|
||||
)[
|
||||
#set align(left)
|
||||
#raw(content, block: true, lang: filetype, align: start)
|
||||
],
|
||||
placement: none,
|
||||
caption: [Datei #path],
|
||||
)
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#import "@preview/shadowed:0.3.0": shadow
|
||||
#import "../pallete.typ": palette
|
||||
|
||||
#let cover(img: bytes, part: content, description: content) = {
|
||||
page(
|
||||
background: image(
|
||||
img,
|
||||
height: 100%,
|
||||
),
|
||||
margin: 0pt,
|
||||
)[
|
||||
#align(
|
||||
bottom,
|
||||
shadow(blur: 140pt, fill: rgb(0, 0, 0, 50%), radius: -50pt, rect(
|
||||
width: 100%,
|
||||
fill: palette.secondary.at("900"),
|
||||
inset: 2.25cm,
|
||||
{
|
||||
show heading: set text(26pt, font: "Arial", fill: white)
|
||||
heading(bookmarked: true, numbering: none, strong(part))
|
||||
par(text(size: 26pt, font: "Arial", fill: palette.gray.at("50"), weight: "bold", description))
|
||||
par(
|
||||
text(
|
||||
size: 12pt,
|
||||
fill: palette.gray.at("300"),
|
||||
)[Individuelle praktische Arbeit],
|
||||
)
|
||||
},
|
||||
)),
|
||||
)
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#let _glossaryDict = state("e8759020-8d68-4920-9ce6-246b09c3094b", none)
|
||||
|
||||
#let setDefaults(defaults) = {
|
||||
_glossaryDict.update(dict => {
|
||||
for (term, explanation) in defaults.pairs() {
|
||||
dict.insert(term, explanation)
|
||||
}
|
||||
return dict
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
#let term(term, explanation) = {
|
||||
_glossaryDict.update(dict => {
|
||||
if dict == none {
|
||||
return (
|
||||
"" + term: explanation,
|
||||
)
|
||||
}
|
||||
dict.insert(term, explanation)
|
||||
return dict
|
||||
})
|
||||
term
|
||||
}
|
||||
|
||||
#let glossary() = {
|
||||
context {
|
||||
if _glossaryDict.get() == none {
|
||||
return
|
||||
}
|
||||
[ = Glossar]
|
||||
terms(tight: true)
|
||||
figure(
|
||||
table(
|
||||
columns: (1fr, 3fr),
|
||||
table.header([Begriff], [Bedeutung]),
|
||||
|
||||
.._glossaryDict
|
||||
.get()
|
||||
.keys()
|
||||
.sorted(key: lower)
|
||||
.map(key => (
|
||||
key,
|
||||
_glossaryDict.get().at(key),
|
||||
))
|
||||
.flatten(),
|
||||
),
|
||||
caption: [Glossar],
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
#let _persons = state("598041ec-f6ce-4a04-872a-032a8325b760", ())
|
||||
|
||||
#let byFunction(
|
||||
function,
|
||||
) = {
|
||||
let ps = _persons.get().filter(person => person.at("function", default: "") == function)
|
||||
if ps.len() > 0 {
|
||||
return ps.at(0)
|
||||
} else {
|
||||
return (
|
||||
name: "Axel Schweiss",
|
||||
email: "axel.schweiss@bit.admin.ch",
|
||||
shorthand: "AS",
|
||||
function: function,
|
||||
where: "In der Genehmigung",
|
||||
git: "xxxxxxxxx",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#let overview() = {
|
||||
return (
|
||||
[Name],
|
||||
[Kontakt],
|
||||
[Kürzel],
|
||||
.._persons
|
||||
.get()
|
||||
.map(p => (
|
||||
[#p.at("function-name", default: p.function): \ #p.name],
|
||||
[
|
||||
#if p.at("phone", default: "") != "" { [Telefon: #link("tel:" + p.phone, p.phone) \ ] }
|
||||
#if p.at("email", default: "") != "" { [Email: #link("mailto:" + p.email, p.email) \ ] }
|
||||
],
|
||||
p.shorthand,
|
||||
))
|
||||
.flatten(),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#let requirementIDCounter = state("8067fd32-20a6-4b95-b50d-c5e2f431b7b0", 0)
|
||||
|
||||
#let id(uid: "") = {
|
||||
requirementIDCounter.update(s => s + 1)
|
||||
|
||||
context {
|
||||
let val = requirementIDCounter.get()
|
||||
let myLabel = label("req-" + if uid == "" { "a" + str(val) } else { uid })
|
||||
|
||||
[#figure([A#val], kind: "req", supplement: "Anforderung ", numbering: num => (
|
||||
"A" + str(num)
|
||||
)) #myLabel]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
#import "../pallete.typ": palette
|
||||
|
||||
|
||||
|
||||
#let sideways(..args) = {
|
||||
// This rule is scoped only to this specific table
|
||||
|
||||
show table.cell.where(x: 0): strong
|
||||
show table.cell.where(y: 0): it => strong(delta: -300, it)
|
||||
|
||||
table(
|
||||
// Your existing stroke/fill logic
|
||||
fill: (_, y) => if calc.odd(y) { rgb(palette.ui.bg-dark) },
|
||||
stroke: (x, y) => (
|
||||
top: none,
|
||||
bottom: none,
|
||||
left: if x == 0 { 0pt } else if x == 1 { palette.ui.border } else { 1pt + palette.ui.border },
|
||||
right: if x == 0 { 2pt },
|
||||
),
|
||||
..args
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
#import "./testcase.typ": case, cases, defectClassToString, protocoll, results
|
||||
@@ -0,0 +1,166 @@
|
||||
#import "../../pallete.typ": palette
|
||||
#import "../tabler.typ"
|
||||
#let _testCases = state("9ca8f801-3bfd-4a72-a716-966aec564315", ())
|
||||
#let _testResults = state("7372165e-6204-43a2-8780-46a41d7e2841", ())
|
||||
|
||||
#let defectClassToString(defectClass) = {
|
||||
if (defectClass == 4) {
|
||||
return "kritischer Mangel"
|
||||
}
|
||||
if (defectClass == 3) {
|
||||
return "schwerer Mangel"
|
||||
}
|
||||
if (defectClass == 2) {
|
||||
return "leichter Mangel"
|
||||
}
|
||||
if (defectClass == 1) {
|
||||
return "belangloser Mangel"
|
||||
}
|
||||
|
||||
return "mängelfrei"
|
||||
}
|
||||
|
||||
#let case(
|
||||
// Welcher Usercase oder requirement der testfall testet.
|
||||
requirement: [],
|
||||
description: [],
|
||||
precondition: [],
|
||||
steps: [],
|
||||
result: [],
|
||||
) = {
|
||||
// style
|
||||
// show table.cell.where(x: 0): strong
|
||||
// show table.cell.where(y: 0): it => strong(delta: -300, it)
|
||||
|
||||
|
||||
_testCases.update(cases => {
|
||||
cases.push((
|
||||
requirement: requirement,
|
||||
description: description,
|
||||
precondition: precondition,
|
||||
steps: steps,
|
||||
result: result,
|
||||
))
|
||||
return cases
|
||||
})
|
||||
|
||||
context {
|
||||
let id = "TC-" + str(_testCases.get().len())
|
||||
[
|
||||
#figure(
|
||||
tabler.sideways(
|
||||
columns: (auto, 1fr, 10em),
|
||||
[ID / Bezeichnung],
|
||||
[#id],
|
||||
[Testet: #requirement],
|
||||
|
||||
[Beschreibung],
|
||||
table.cell(colspan: 2, description),
|
||||
[Testvoraussetzung],
|
||||
table.cell(colspan: 2, precondition),
|
||||
[Testschritte],
|
||||
table.cell(colspan: 2, steps),
|
||||
[Erwartetes Ergebnis],
|
||||
table.cell(colspan: 2, result),
|
||||
),
|
||||
caption: [Testfall #id],
|
||||
)#label(id)
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
#let cases() = {
|
||||
return _testCases
|
||||
.final()
|
||||
.enumerate(start: 1)
|
||||
.map(c => (
|
||||
id: "TC-" + str(c.at(0)),
|
||||
requirement: c.at(1).requirement,
|
||||
description: c.at(1).description,
|
||||
precondition: c.at(1).precondition,
|
||||
steps: c.at(1).steps,
|
||||
result: c.at(1).result,
|
||||
))
|
||||
}
|
||||
|
||||
#let protocoll(
|
||||
case: "",
|
||||
date: datetime.today(),
|
||||
tester: "",
|
||||
defectClass: none,
|
||||
defect: "",
|
||||
result,
|
||||
) = {
|
||||
// style
|
||||
show table.cell.where(x: 0): strong
|
||||
show table.cell.where(y: 0): it => strong(delta: -300, it)
|
||||
|
||||
|
||||
if (defectClass == none) {
|
||||
defectClass = 0
|
||||
}
|
||||
|
||||
let dcColor() = {
|
||||
if (defectClass >= 4) {
|
||||
return palette.red.at("300")
|
||||
}
|
||||
if (defectClass >= 2) {
|
||||
return palette.orange.at("300")
|
||||
}
|
||||
if (defectClass > 0) {
|
||||
return palette.yellow.at("300")
|
||||
}
|
||||
return palette.green.at("300")
|
||||
}
|
||||
|
||||
_testResults.update(cases => {
|
||||
cases.push((
|
||||
case: case,
|
||||
date: date,
|
||||
defectClass: defectClass,
|
||||
defect: defect,
|
||||
))
|
||||
return cases
|
||||
})
|
||||
|
||||
|
||||
context {
|
||||
figure(
|
||||
tabler.sideways(
|
||||
columns: (auto, 1fr),
|
||||
[Testfall:],
|
||||
link(label(case), case),
|
||||
[Tester:],
|
||||
[#tester],
|
||||
[Datum:],
|
||||
date.display("[day].[month].[year]"),
|
||||
[Mängelklasse:],
|
||||
table.cell(fill: dcColor())[#defectClass],
|
||||
..if (defectClass > 0) {
|
||||
([Mängel:], defect)
|
||||
},
|
||||
[Ergebnis:],
|
||||
result,
|
||||
),
|
||||
caption: [Testergebnis für #link(label(case), case) vom #date.display("[day].[month].[year]")],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// table.header([Testfall], [Durchführungsdatum], [Mängelklasse], [Mängel]),
|
||||
#let results() = {
|
||||
return _testResults
|
||||
.final()
|
||||
.map(r => (
|
||||
r.case,
|
||||
r.date.display("[day].[month].[year]"),
|
||||
table.cell(fill: if (r.defectClass >= 4) {
|
||||
palette.red.at("300")
|
||||
} else if (r.defectClass >= 2) {
|
||||
palette.orange.at("300")
|
||||
} else if (r.defectClass > 0) {
|
||||
palette.yellow.at("300")
|
||||
} else { palette.green.at("300") })[#r.defectClass],
|
||||
if r.defect == "" { "-" } else { r.defect },
|
||||
))
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
#import "./persons.typ"
|
||||
#import "../pallete.typ": palette
|
||||
// helpers for title
|
||||
#let getWhere(person) = {
|
||||
let function = person.function
|
||||
if function == "Validierungsexperte" {
|
||||
return "In der Genehmigung"
|
||||
}
|
||||
if function == "Hauptexperte" or function == "Nebenexperte" or function == "Verantwortliche Fachkraft" {
|
||||
return "In der Durchführung"
|
||||
}
|
||||
if function == "Berufsbildner" {
|
||||
return "Zur Information, Kenntnis"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
#let beteiligtePersonen() = {
|
||||
return (
|
||||
persons.byFunction("Validierungsexperte"),
|
||||
persons.byFunction("Hauptexperte"),
|
||||
persons.byFunction("Nebenexperte"),
|
||||
persons.byFunction("Verantwortliche Fachkraft"),
|
||||
persons.byFunction("Berufsbildner"),
|
||||
)
|
||||
}
|
||||
#let title(
|
||||
title: content,
|
||||
author: content,
|
||||
company: content,
|
||||
departement: content,
|
||||
tradeschool: "Gewerblich-industrielle Berufsschule Bern GIBB",
|
||||
metadata: (
|
||||
specialisation: "Applikationsentwicklung",
|
||||
managementMethod: "HERMES",
|
||||
// year as in "Jahrgang"
|
||||
year: "IPA 2025",
|
||||
place: "Kanton Bern",
|
||||
dateOfSubmission: datetime,
|
||||
currentversion: version,
|
||||
),
|
||||
) = {
|
||||
// set text(font: "Helvetica Neue")
|
||||
|
||||
place(
|
||||
top + left,
|
||||
image("../assets/Logo_RGB_farbig_positiv.svg", height: 2cm),
|
||||
)
|
||||
place(
|
||||
top + right,
|
||||
[
|
||||
#set text(size: 8pt, font: "Helvetica Neue")
|
||||
#v(4pt)
|
||||
Eidgenössisches Finanzdepartement EFD
|
||||
|
||||
*#company* \
|
||||
#departement \
|
||||
Individuelle praktische Arbeit
|
||||
],
|
||||
)
|
||||
|
||||
v(4cm)
|
||||
|
||||
text(
|
||||
size: 21pt,
|
||||
font: "Helvetica Neue",
|
||||
fill: palette.secondary.at("500"),
|
||||
title,
|
||||
)
|
||||
|
||||
align(
|
||||
right,
|
||||
text(
|
||||
size: 17pt,
|
||||
font: "Helvetica Neue",
|
||||
fill: gray,
|
||||
[
|
||||
Individuelle praktische Arbeit \
|
||||
#author
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
set table(stroke: 0.1pt + palette.ui.border)
|
||||
|
||||
v(.5cm)
|
||||
[
|
||||
#set text(font: "Helvetica Neue")
|
||||
#table(
|
||||
columns: (.5fr, 1fr),
|
||||
inset: 8pt,
|
||||
align: horizon,
|
||||
[*Autor*], author,
|
||||
[*Firma*], company,
|
||||
[*Abteilung*], departement,
|
||||
[*Berufsschule*], [gibb Berufsfachschule Bern],
|
||||
)
|
||||
|
||||
#heading(level: 3, [Beteiligte Personen], outlined: false)
|
||||
|
||||
#context table(
|
||||
columns: (.5fr, .5fr, .5fr),
|
||||
inset: 8pt,
|
||||
..beteiligtePersonen()
|
||||
.map(p => (
|
||||
par([*#p.at("function-name", default: p.function)*], justify: false),
|
||||
link("mailto:" + p.email)[#p.name],
|
||||
context getWhere(p),
|
||||
))
|
||||
.flatten()
|
||||
)
|
||||
|
||||
#table(
|
||||
columns: (.5fr, 1fr),
|
||||
inset: 8pt,
|
||||
align: horizon,
|
||||
[*Fachrichtung*], [#metadata.specialisation],
|
||||
[*Projektvorgehensmodell*], [#metadata.managementMethod],
|
||||
[*Jahrgang, Kanton*], [#metadata.dateOfSubmission.year(), #metadata.place],
|
||||
[*Abgabedatum*], metadata.dateOfSubmission.display("[day].[month].[year]"),
|
||||
[*Version*], [Version v#metadata.currentversion],
|
||||
)
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,81 @@
|
||||
#import "tabler.typ"
|
||||
// Colors used across the template.
|
||||
#let stroke-color = luma(200)
|
||||
#let fill-color = luma(240)
|
||||
|
||||
|
||||
#let idState = state("04cb31e7-92f1-4e72-82d8-e5ef190d0745", 0)
|
||||
|
||||
|
||||
|
||||
#let usecase(
|
||||
name: "",
|
||||
diagramm: none,
|
||||
actors: ([],),
|
||||
precondition: [],
|
||||
process: [],
|
||||
acceptanceCriteria: none,
|
||||
offset: 2,
|
||||
) = {
|
||||
idState.update(s => s + 1)
|
||||
|
||||
set heading(offset: offset, numbering: none)
|
||||
|
||||
context [
|
||||
#figure(
|
||||
none,
|
||||
kind: "usecase",
|
||||
supplement: _ => [UC-#h(-0.25em)],
|
||||
)
|
||||
#label("usecase-" + str(idState.get()))
|
||||
|
||||
#figure(
|
||||
tabler.sideways(
|
||||
columns: (auto, 1fr),
|
||||
|
||||
[Bezeichnung ],
|
||||
[UC-#idState.get(): #name],
|
||||
|
||||
..(
|
||||
if diagramm != none {
|
||||
(
|
||||
[Diagramm],
|
||||
block(
|
||||
inset: (top: 0.5em, left: 0.5em, right: 0.5em),
|
||||
width: 100%,
|
||||
figure(
|
||||
diagramm,
|
||||
caption: [Diagramm für #{ "UC-" + str(idState.get()) }],
|
||||
),
|
||||
),
|
||||
)
|
||||
} else { () }
|
||||
),
|
||||
|
||||
[Beteiligte Akteure],
|
||||
actors.join(", "),
|
||||
|
||||
[Vorbedingungen],
|
||||
precondition,
|
||||
|
||||
[Ablauf],
|
||||
process,
|
||||
..(
|
||||
if acceptanceCriteria != none {
|
||||
(
|
||||
[Akzeptanzkriterien],
|
||||
[
|
||||
#for criteria in acceptanceCriteria {
|
||||
[+ #criteria]
|
||||
}
|
||||
],
|
||||
)
|
||||
}
|
||||
),
|
||||
),
|
||||
caption: [Anwendungsfall: #{ "UC-" + str(idState.get()) }],
|
||||
)
|
||||
|
||||
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
#let toVersions(commits: (("2025-11-19", "u80864958", "msg"),), persons: dictionary, final: false) = {
|
||||
let versions = ()
|
||||
for commit in commits.rev() {
|
||||
let v = version(0, 0, 0)
|
||||
let message = str(commit.at(2))
|
||||
if versions.len() > 0 {
|
||||
// versions.at(-1).v
|
||||
v = versions.at(-1).v
|
||||
if message.starts-with("fix") or message.starts-with("chore") {
|
||||
v = version(v.at(0), v.at(1), v.at(2) + 1)
|
||||
} else if message.starts-with("feat") {
|
||||
v = version(v.at(0), v.at(1) + 1, 0)
|
||||
}
|
||||
}
|
||||
if message.contains(":") {
|
||||
message = commit.at(2).split(":").slice(1).flatten().at(0).trim()
|
||||
}
|
||||
versions.push(
|
||||
(
|
||||
date: toml(bytes("date = " + commit.at(0))).date,
|
||||
v: v,
|
||||
author: persons.at(default: persons.at(persons.keys().at(0)), commit.at(1)),
|
||||
topic: message,
|
||||
),
|
||||
)
|
||||
}
|
||||
if final {
|
||||
versions.push(
|
||||
(
|
||||
date: datetime.today(),
|
||||
v: version(1, 0, 0),
|
||||
author: persons.at(persons.keys().at(0)),
|
||||
topic: "Finalisierung",
|
||||
),
|
||||
)
|
||||
}
|
||||
return versions
|
||||
}
|
||||
|
||||
#let parseCurrentVersion(
|
||||
commits: (("2025-11-19", "u80864958", "init"),),
|
||||
persons: (
|
||||
"u80864958": "Niklas Breitenstein",
|
||||
"u80864987": "Johar Naamneh",
|
||||
),
|
||||
final: false,
|
||||
) = {
|
||||
return toVersions(commits: commits, persons: persons, final: final).at(-1).v
|
||||
}
|
||||
|
||||
|
||||
#let versionhistoryTable(
|
||||
commits: (("2025-11-19", "u80864958", "init"),),
|
||||
persons: (
|
||||
"u80864958": "Niklas Breitenstein",
|
||||
"u80864987": "Johar Naamneh",
|
||||
),
|
||||
final: false,
|
||||
) = {
|
||||
let versions = toVersions(commits: commits, persons: persons, final: final)
|
||||
set heading(numbering: none)
|
||||
[= Änderungsverzeichnis]
|
||||
set par(justify: false)
|
||||
|
||||
figure(
|
||||
table(
|
||||
columns: (6em, 6em, 2fr, 2.7fr),
|
||||
table.header([Version], [Datum], [Name], [Themen]),
|
||||
|
||||
..versions
|
||||
.map(v => (
|
||||
[v#v.v],
|
||||
v.date.display("[day].[month].[year]"),
|
||||
v.author,
|
||||
v.topic,
|
||||
))
|
||||
.flatten(),
|
||||
),
|
||||
caption: [Änderungsverzeichnis],
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user