Skip to main content

Gantt Projects - Releases

← App details

Nextcloud 34

Gantt Projects 1.6.1
Release Details
UpdatedSept. 2, 2026, 6:15 p.m.
Changelog

Security

  • Ressourcen-, Gruppen- und Kapazitätsdaten fremder Projekte waren über geteilte Projekte einsehbar (Issue #183). ResourceMapper, ResourceGroupMapper und ResourceCapacityMapper::findVisibleToUser() gaben pauschal alle Datensätze eines Eigentümers frei, sobald irgendein Projekt dieses Eigentümers mit dem Nutzer geteilt war — unabhängig davon, ob die konkrete Ressource überhaupt in einem geteilten Projekt verwendet wird. Der neue zentrale ResourceVisibilityService prüft stattdessen, ob die Ressource tatsächlich in einer für den Nutzer sichtbaren Aufgabe verwendet wird, und wird von ResourceService, ResourceCapacityService, ResourceGroupService und TaskResourceAssignmentService genutzt. Damit lassen sich über eine geteilte Ressource weder die übrigen, nicht geteilten Ressourcen desselben Eigentümers einsehen noch eigenen Aufgaben zuordnen
  • GET /api/v1/resources/{id}/utilization gab Planungsdaten aus nicht zugänglichen Projekten preis (Issue #181). ResourceUtilizationService::findVisibleResource() prüfte nur, ob der Ressourcen-Eigentümer irgendein Projekt mit dem Nutzer geteilt hat; über die Auslastung waren dadurch Aufgaben- und Projekttitel samt Terminen aus fremden Projekten abgreifbar. Die Prüfung stellt jetzt projektbezogen fest, ob die Ressource in mindestens einem über AccessService::canViewOrOwn() sichtbaren Projekt verwendet wird; zusätzlich filtert collectPlannedHours() die Aufgaben auf genau diese Projekte, sodass auch bei erlaubtem Ressourcenzugriff nichts aus fremden Projekten durchsickert
  • Aufgaben und Teilprojekte ließen sich an fremde Projekte hängen (Issue #179). TaskService::create()/update() und SubProjectService::create()/update() prüften nur die Schreibberechtigung auf die eigene projectId, nicht aber, ob eine mitgesendete subproject_id bzw. parent_id überhaupt zu diesem Projekt gehört — mit Folgewirkung beim Löschen eines Teilprojekts (SubProjectService::deleteTasksForSubproject()) und im öffentlichen ICS-Feed (CalendarFeedService::buildIcs()), da beide über TaskMapper::findBySubProject() allein nach subproject_id filtern. Analog zum Schutz aus Issue #97 prüfen jetzt AccessService::assertTaskBelongsToProject() und assertSubprojectBelongsToProject() die Zugehörigkeit; deleteTasksForSubproject() und buildIcs() filtern die geladenen Aufgaben zusätzlich defensiv nach project_id, um vor dem Fix entstandene Altdaten abzudecken

Changed

  • Dokumentation aufgeräumt: Die Doku ist jetzt nach Zielgruppe getrennt — alles, was Nutzerinnen und Nutzer brauchen, liegt in nc_gantt/ und wird damit vom release.sh-Archiv mit ausgeliefert, das Repository-Root enthält nur noch Entwickler-Doku. Dafür sind FEATURES.md, INSTALL.md und die neue HOWTO.md nach nc_gantt/ gewandert; die Root-README.md beschreibt die zehn wichtigsten Anwendungsfälle des Werkzeugs, erklärt je Fall den gedachten Arbeitsweg und führt in einer Repository-Übersicht auf, welches Dokument für wen gedacht ist. Neu ist nc_gantt/HOWTO.md: eine Schritt-für-Schritt-Anleitung entlang eines durchgerechneten Beispielprojekts, die alle zehn Anwendungsfälle mit konkreten Feldwerten, Abhängigkeiten und Terminen durchspielt
  • Dabei korrigierte Verweise und Angaben: der Lizenz-Link in nc_gantt/README.md zeigte auf das nicht vorhandene LICENSES/AGPL-3.0-or-later.txt statt auf LICENSE.md; die Nextcloud-Anforderung stand mit „28–33" in README.md und „28–34" in FEATURES.md gegen die tatsächlichen 31–34 aus appinfo/info.xml; FEATURES.md nannte noch Version 1.5.0; INSTALL.md verwies auf ein dist/nc_gantt-<version>.zip im Repository, das es nicht gibt (dist/ ist nicht versioniert und release.sh baut .tar.gz), und in CONTRIBUTE.md trug ein Link auf RELEASE.md die Beschriftung release.sh. Alle relativen Links und Abschnitts-Anker der versionierten Markdown-Dateien lösen jetzt auf
  • Tests laufen künftig vor jedem Commit (Issue #185): setup-dev.sh installiert einen pre-commit-Hook, der Vitest und PHPUnit (über Docker) ausführt und den Commit bei Fehlern abbricht — genau die Stelle, an der die vier defekten Tests aus dem Ressourcen-Sichtbarkeits-Commit hängen geblieben wären. phpunit.xml schaltet zusätzlich failOnRisky und failOnWarning ein, damit ein Test ohne Assertion den Lauf rot färbt statt unauffällig grün zu bleiben, und CONTRIBUTE.md dokumentiert die Regel zu Mock-Defaults ohne with() in setUp()
  • Die Default-Stubs in setUp() von ResourceVisibilityServiceTest blockierten die spezifischeren Stubs der einzelnen Testmethoden — PHPUnit wertet für dieselbe Methode den zuerst registrierten Matcher aus, und der greift per any() bei jedem Aufruf. findByResourceId(), findByIds() und findByResourceIdExcluding() lieferten dadurch immer ein leeres Array, was vier Failures und zwei risky Tests verursachte. Die Defaults sind entbehrlich, weil PHPUnit-Mocks für den Rückgabetyp array ohnehin ein leeres Array liefern; der Produktivcode blieb unverändert
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturerHm/UxN1WTCOMd9LklleINo7LKDOEAyn1zlsR5eTCaUmdGaN1m8Knqk/EKDYcj73
zWx7TXmT4cP91Ag7mCMwY/gRqJabF7TgeXiA7CeV7VE7/D/+apIatMWRT7zYCjkF
oxXKimNrtpDSKWNXKSQn6RfJaEHu5WnIoF4X9Nyx/wf1WoWoThyvWMSSW/3jdajV
WXCV4XQjzbTULw9T+Ini/e8vp6mXt5CrmCdyUDQQcj2t9PF9Hq3GvWT1VQlYA8Kf
IJuqnArSc4JdtJiJnozpOKSBkAbDPTrFytwUTVUO4XlrGIvyqHv14ZVmBM8UCMo6
yVNA9HEBW62/b8W+Z3BtCBTuBnkRk3Wka8qhMMbqOe8kl/1vQtTKQkaDdnXaShUs
18mfDHjLZhcIrJEwbtPvo9Xpf+IWEZeoiRzEqa30n70iZTkPEVv/GxNVmJ74XYH/
Xa/vMWI/sxtXKtKY60XBXXCEVMuyxR+vfIbJOpDCcFlKyWHiXPEdYh2Ac8Bs1hc7
bk+lolw8FEWISrFdUwYdOrfRr4CMW+h2CYzgZsDKKYrVn+hRUy5mVOL1QXZJbNJJ
wr9O/JrUbXAMGdhtLuRUwM4tsPgMF2+cTLMe+wuFzUjWBBNiqb8GKJP2K94hdurD
+VMd/p/TtU02M23ooysu2mft5RCmD0/QbP8yxEACbHg=
Signature digestsha512
Dependencies
Required Nextcloud versions >=31.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.6.0
Release Details
UpdatedAug. 28, 2026, 2:34 p.m.
Changelog

Achtung: Diese Version setzt Nextcloud 31 oder neuer voraus. Die bisherige Untergrenze war Nextcloud 28. Mit dem Umstieg auf @nextcloud/vue 9 — unvermeidbar, weil Vue 2 seit dem 31.12.2023 End-of-Life ist und keine Sicherheitskorrekturen mehr bekommt — fällt die Unterstützung für Nextcloud 28, 29 und 30 weg. Installationen auf diesen Versionen bekommen das Update nicht angeboten und bleiben auf 1.5.4; sie werden von dort nicht weiter gepflegt. Wer die App weiter nutzen möchte, aktualisiert zuerst den Nextcloud-Server auf mindestens Version 31 (max-version bleibt unverändert 34).

Changed

  • Das Frontend läuft auf Vue 3.5 statt Vue 2.7 (Issue #150). Vue 2 ist seit dem 31.12.2023 End-of-Life und bekommt weder Sicherheits- noch Fehlerkorrekturen; die Nextcloud-Server-Generation, gegen die die App freigegeben ist, hat ihren Frontend-Stack längst auf Vue 3 umgestellt. Mit umgestellt sind @nextcloud/vue 8 → 9, @nextcloud/dialogs 6 → 7, Pinia 2 → 3 und @nextcloud/webpack-vue-config 5 → 7; die dreizehn Build-Pakete, die das Webpack-Preset ab Version 7 als peerDependencies erwartet (webpack, vue-loader, sass, babel-loader …), stehen jetzt explizit in den devDependencies. npm audit --omit=dev meldet damit 0 statt 14 Befunde — die vier an Vue 2 hängenden Advisories (vue, vue-template-compiler, vue-resize, vue2-datepicker) waren ohne diese Migration nicht auflösbar
  • appinfo/info.xml fordert jetzt Nextcloud 31 statt 28 (max-version bleibt 34). @nextcloud/vue 9 lässt die Unterstützung für Nextcloud vor 31 fallen; das ist die unvermeidbare Gegenleistung der Migration. Installationen auf Nextcloud 28–30 bleiben auf Version 1.5.4
  • Die drei Einstiegspunkte src/main.js, src/admin.js und src/dashboard.js erzeugen ihre Anwendung über createApp() statt new Vue(); Pinia wird als Plugin registriert (app.use(pinia)), das Weiterreichen der Store-Instanz an das Vanilla-Detailmodal per setActivePinia() bleibt unverändert. Die Vue.prototype-Zuweisungen im Dashboard-Einstiegspunkt sind entfallen — DashboardWidget.vue importiert t ohnehin selbst
  • Anpassungen in den 17 Komponenten an die API von @nextcloud/vue 9: Import-Pfade (@nextcloud/vue/components/NcButton statt @nextcloud/vue/dist/Components/NcButton.js), type="primary"variant="primary" bei NcButton/NcActions, NcActionCheckbox und NcSelect auf modelValue (:checked/@update:checked bzw. :value/@input sind entfallen), :shown.syncv-model:shown bei NcPopover. Dazu die Vue-3-Umstellungen im eigenen Code: beforeDestroy()beforeUnmount() in GanttTable.vue, ResourceGrid.vue und GanttChart.vue (siehe Issue #149), this.$set()/this.$delete() durch direkte Zuweisung bzw. splice() ersetzt
  • css/main.css und der zugehörige Util::addStyle()-Aufruf im PageController sind entfallen. Die Datei enthielt einzig #content { margin-top: 0 !important } gegen eine Doppelmarge, die NcContent unter @nextcloud/vue 8 zusätzlich zum Nextcloud-Layout gesetzt hat. Unter Version 9 gibt es diese Marge nicht mehr, der Reset schob die App stattdessen um die Höhe der Kopfzeile nach oben — die Navigationsleiste lag dadurch unter dem Nextcloud-Header und war nicht mehr anklickbar. Der Mount-Punkt #nc-gantt-app bleibt als Wrapper im DOM stehen (Vue 3 rendert in das Element hinein, statt es wie Vue 2 zu ersetzen), nimmt aber nachgemessen exakt die Maße des Content-Bereichs an und braucht keine eigene Regel
  • ESLint nutzt das Preset @nextcloud/eslint-config/vue3. Es lässt vue/custom-event-name-casing auf dem Vue-3-Default (camelCase) laufen, während das Vue-2-Preset kebab-case erzwungen hat; da der Bestand durchgängig kebab-case verwendet — unter Vue 3 gleichermaßen gültig — setzt .eslintrc.js die Regel explizit auf kebab-case
  • Der <style>-Block in GanttChart.vue war mit 581 Zeilen ungescopt und wirkte damit auf die gesamte Nextcloud-Oberfläche statt nur auf die Komponente (Issue #151). Die 65 eigenen .nc-gantt-*/.nc-*-Regeln laufen jetzt über <style scoped>, mit :deep() dort, wo Overlays ihre Elemente per createElementNS() bzw. innerHTML außerhalb des Vue-Templates in .nc-gantt-container einhängen. Die Regeln, die auf frappe-gantt-eigene Klassennamen zugreifen (.gantt .bar & Co.), liegen gebündelt in src/vendor/frappe-gantt/theme.css direkt neben dem vendorten Quellcode der Bibliothek und werden von dort per index.js importiert; die beiden nicht unter .gantt verankerten Selektoren (.bar-wrapper.gantt-milestone .bar-label/.handle) sind dabei korrigiert. In App.vue laufen die drei Core-Überschreibungen (.app-navigation__content, #app-settings, .app-navigation .app-navigation-list) ebenfalls über :deep() in einem scoped Block. Abgesichert ist das durch vue/enforce-style-attribute aus eslint-plugin-vue, das ab sofort scoped für jeden <style>-Block in src/ erzwingt
  • TaskService bündelte auf 774 Zeilen drei Verantwortlichkeiten und brauchte dafür acht Konstruktor-Abhängigkeiten; der Schnitt trennt sie (Issue #153). TaskSchedulingService übernimmt Constraint-Propagation über EA/AA/EE/AE mit Lag, Kahn-Sortierung, Arbeitstagsrechnung, Zyklenprüfung und What-if-Simulation — CriticalPathService wird dort regulär injiziert, statt simulate() als Methodenparameter durchgereicht zu werden. TaskResourceAssignmentService übernimmt Auflösung und Persistierung der Ressourcenzuordnung inklusive MAX_TASK_RESOURCES und PT-Umrechnung. TaskService bleibt als CRUD-Fassade mit Berechtigungsprüfung, Validierung, Änderungsprotokoll und API-Aufbereitung: 311 statt 774 Zeilen, sieben statt acht Abhängigkeiten. Die Methodenrümpfe sind unverändert verschoben, es ändert sich keine Terminlogik. TaskServiceTest ist entlang derselben Grenzen aufgeteilt (TaskServiceTestCase als gemeinsame Basis, dazu TaskSchedulingServiceTest mit 39, TaskResourceAssignmentServiceTest mit 8 und TaskServiceTest mit 11 Fällen — exakt der bisherige Umfang), wobei die ausgelagerten Services weiterhin über ihren Aufrufer TaskService angetrieben werden, damit neben der Rechnung auch die Verdrahtung zwischen Fassade und Engine abgedeckt bleibt
  • Die 212 Zeilen CSS der Vanilla-Detaildialoge wurden zur Laufzeit als <style> in den <head> injiziert (src/detail/styles.js); sie liegen jetzt als src/detail/detail.css vor und werden von Webpack eingebunden (Issue #152). Der im Kopfkommentar genannte Grund — nicht von der Loader-Konfiguration abhängen zu wollen — trifft seit dem Vendoring nicht mehr zu, src/vendor/ importiert .css und .scss ebenfalls direkt. Dabei fiel auf, dass das Stylelint-Glob unquoted an die Shell ging und ohne globstar nur eine Verzeichnisebene traf: weder src/App.vue noch eine .css in src/vendor/ wurde je geprüft. Mit Quotes globbt Stylelint selbst; die dadurch aufgedeckten Findings in App.vue sind mitbehoben
  • Die PHP-Einrückung ist auf Tabs vereinheitlicht (Issue #170). nextcloud/coding-standard erwartet Tabs, die Codebasis nutzte durchgehend vier Leerzeichen — composer cs:check beanstandete dadurch 144 von 146 Dateien, der CI-Job wäre ab dem ersten Lauf dauerhaft rot und als Gate wertlos gewesen. Ursache der Drift war ein falscher Kommentar in .editorconfig, der dem Coding-Standard vier Leerzeichen unterstellte; der ist mitkorrigiert. Die Änderung ist rein mechanisch (php-cs-fixer fix): Einrückung, Klammern um einzeilige if-Rümpfe, sortierte use-Blöcke und einfache statt doppelte Anführungszeichen, wo keine Escape-Sequenz im Spiel ist. Der Commit steht in .git-blame-ignore-revs, damit git blame weiterhin die inhaltlich letzte Änderung einer Zeile zeigt

Added

  • appinfo/info.xml wird jetzt automatisch gegen das App-Store-Schema geprüft, statt den Fehler erst beim Upload zu erfahren: scripts/validate-appinfo.js (npm-Script validate:appinfo) validiert gegen die eingecheckte Schema-Kopie tests/fixtures/info.xsd — per xmllint, ersatzweise über lokales php oder das composer:2-Image — und prüft zusätzlich Semver-Format, Gleichstand mit package.json und den CHANGELOG-Abschnitt zur Version. release.sh ruft das als erstes Gate mit --online auf, lädt das Schema dabei frisch und meldet, wenn die Kopie veraltet ist
  • tests/Unit/AppInfoXmlTest.php führt dieselbe Schema-Validierung in der Testsuite aus (DOMDocument::schemaValidate()) und gleicht zusätzlich die Übersetzungen in l10n/ gegen die Store-Texte ab: gettext-Codes wie pt_BR werden als solche erkannt, und zu jeder übersetzten Sprache müssen <name>, <summary> und <description> in info.xml existieren
  • Die Stunden je Personentag sind konfigurierbar (Issue #169). Der Umrechnungsfaktor lag dreifach hartkodiert vor (TaskResourceAssignmentService, ResourceUtilizationService, ResourceGrid.vue) und wurde über gegenseitige Kommentarverweise von Hand konsistent gehalten — eine feste 8-Stunden-Annahme passt aber nicht zu jedem Arbeitszeitmodell. Der Wert liegt jetzt an genau einer Stelle: WorkTimeService liest ihn als App-Config-Wert hours_per_pt (Standard 8), validiert ihn gegen 1..24 und fällt bei unplausibel gespeicherten Werten auf den Standard zurück, damit die Auslastungsrechnung nicht durch 0 teilt; in ResourceUtilizationService entfällt damit auch die Konstante DEFAULT_CAPACITY_H, die denselben Vollzeit-Referenzwert doppelt hielt. Ins Frontend kommt der Faktor über den Initial State des PageController, sodass er schon beim ersten Rendern des Ressourcen-Rasters bereitsteht; GET/PUT /settings liefern und setzen ihn zusätzlich, wobei ein PUT ohne hours_per_pt den gespeicherten Wert unverändert lässt, damit ältere Clients ihn nicht auf den Standard zurücksetzen. Gepflegt wird er im Admin-Bereich neben Arbeitsbeginn und -ende
  • Die Vanilla-Detaildialoge sind für Screenreader und Tastatur verdrahtet (Issue #152): Die Dialoge verweisen über aria-labelledby auf ihre Überschrift, section() verknüpft Beschriftung und Bedienelement (bei Gruppen über role="group"), Knöpfe ohne Text bekommen einen Namen, Umschaltknöpfe melden ihren Zustand über aria-pressed, und die Datums-Plausibilitätsmeldung hängt per aria-describedby am Feld statt nur im title-Attribut des Icons zu stehen. Der Fokus beginnt beim Öffnen im Formular statt auf dem Schließen-Knopf und kehrt beim Schließen zum Auslöser zurück. Abgesichert durch payload.test.js (19 Fälle für Speicher- und Löschlogik) und accessibility.spec.js (6 E2E-Fälle) — für DOM-Code ist der E2E-Lauf die tragfähigere Absicherung als eine neue jsdom-Abhängigkeit. src/detail/README.md erklärt, warum das Modul außerhalb von Vue steht und welche Regeln daraus folgen; CONTRIBUTE.md verweist darauf
  • Die CI läuft. Der Workflow lag unter nc_gantt/.gitea/workflows/ci.yml und war eine reine GitHub-Actions-Datei; vier voneinander unabhängige Gründe verhinderten, dass davon jemals etwas ausgeführt wurde (Issue #170): Forgejo liest Workflows ausschließlich im Repo-Root, runs-on: ubuntu-latest passt auf kein Codeberg-Label (die gehosteten Runner heißen codeberg-tiny/-small/-medium), die Kurzform shivammathur/setup-php@v2 wird gegen Forgejos Action-Host aufgelöst, wo es die Action nicht gibt, und die Repo-Einheit „Actions" war deaktiviert. Die Datei liegt jetzt unter .forgejo/workflows/ci.yml, die App bleibt via defaults.run.working-directory erreichbar. Inhaltlich sind php-lint und php-tests zu einem Job zusammengefasst und laufen beide über die volle Matrix 8.1/8.2/8.3 (vorher lief PHPUnit nur auf 8.2, obwohl composer.json >=8.1 fordert), die Syntaxprüfung nutzt xargs statt find -exec (find liefert seinen eigenen Exitcode, nicht den von php -l — der Schritt konnte gar nicht fehlschlagen), und der JS-Job führt neu vitest mit 180 bislang nie automatisiert gelaufenen Tests aus, dazu validate:appinfo und l10n:check. paths-ignore hält die geteilten Codeberg-Runner von reinen Doku- und Screenshot-Änderungen frei

Fixed

  • Nach der Migration auf @nextcloud/dialogs 7 erschienen Statusmeldungen wie „Einstellungen gespeichert" als unformatierter Text oben links statt als Badge. Version 7 hat Toastify durch eigene Vue-Komponenten ersetzt, deren Styles nicht mehr im JS-Bundle stecken, sondern über den separaten Export @nextcloud/dialogs/style.css eingebunden werden müssen; ohne diesen Import lief der Toast-Container ungestylt im normalen Dokumentfluss mit. src/main.js importiert das Stylesheet jetzt. Die Toasts erscheinen dabei an der neuen Standardposition der Bibliothek unten links neben der Navigation statt wie früher oben zentriert — Version 7 bietet dafür keine Option mehr
  • testBuildIcsStripsCarriageReturnToPreventLineInjection prüfte das gesamte ICS-Dokument auf Freiheit von \r. RFC 5545 trennt Zeilen aber genau damit, und buildIcs() setzt sie korrekt als CRLF — der Test konnte nie grün sein und schlug auf main dauerhaft fehl. Der Schutz selbst greift; nur die Assertion war zu weit gefasst. Geprüft wird jetzt, was die Line-Injection tatsächlich ausschließt: kein einzelnes CR außerhalb der CRLF-Zeilentrenner, der eingeschleuste Titel erzeugt keine eigene ICS-Zeile, und er landet escaped im SUMMARY-Wert. Gegenprobe mit entfernter CR-Normalisierung in escapeText() schlägt weiterhin fehl, der Schutz bleibt also scharf getestet. Dass der Fehlschlag so lange unbemerkt blieb, lag daran, dass die Workflows nicht ausgeführt wurden (siehe Issue #170)
  • validate:appinfo brach im ersten CI-Lauf mit einer Meldung über einen nicht erreichbaren Docker-Socket ab (Issue #170). Die Validator-Kette in scripts/validate-appinfo.js probiert xmllint, dann php, dann docker und nimmt den erstbesten verfügbaren — „verfügbar" hieß dabei aber nur, dass das Binary existiert. Das Runner-Image bringt die docker-CLI mit, ohne dass ein Daemon erreichbar wäre, und hat weder xmllint noch php. isAvailable prüft jetzt, ob der Validator wirklich läuft (docker info statt --version), sodass die Kette korrekt durchfällt und bei gänzlich untauglicher Umgebung „Kein Schema-Validator gefunden" meldet statt eines Socket-Fehlers; zusätzlich installiert der JS-Job libxml2-utils, damit im CI immer xmllint gewinnt — der native XSD-Validator, ohne Daemon und ohne Netzwerk. Welcher Validator läuft, hing zuvor davon ab, was auf der Maschine zufällig installiert war
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturegDK8JkRgxBUCFljhxHFzTzf37tjhwQ/k9E+DCDeVHxPECDOF0J3FbWmv2uqmm9R7
H8yyFfL/KFEDK3Jt24o2gujQZ9KlyBYJvrfwv//zvACtgGoErBUamME+FzFfK3x8
rRdXt1iXctmwutRvTNPj8uvfMJmo/vdbJRDGEihI/9wVdt4S+O3/OlpdjUg+QGFP
cMmlQwIAHAWrYSUllnN4GeryrFPGB7fLi/Nrhx0eAwQHUjIZHEb/s9ZxjmnYZd0c
8FJsgAUXfjowOIrDtWxr0P+HVj4c5qhGx4XEUFdfR0slriaL+zPbo2Li1wgsBA7r
+yoo8ocOJPaN3iCpRNL4z8q2sxEuWRt2Dx0I5ck6F7g+gpzDoTo5bFEvq4Eir0wN
lGHhyxcdEK653dTKOBYI07tCjJYU+9VxCbRzR7O+sVI412Tox5W5cYGl4WpN8aNH
00CX7PLaruaEjwuFdAvhY6SzsXA3RFmN3Dv9qFx3dl3HjoQ+OCqy89XzT3tbBN07
3aZO7OgyB26al2XdRFaaRQaVLqjJzUCz2B5nh+z9+L+QcBl3F9sE2sFZnkWwx3bp
MOdj2nCS11r3Z0utRI9uDEanys6HkqnpGed4WEGX9O+EfocqNg2b0wgyqjFNWbxI
n4uoeakhyWYOVHCUfzU8tn6kmU4b8n+GfpMjKPhBeRw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=31.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.4
Release Details
UpdatedAug. 27, 2026, 7:06 p.m.
Changelog

Fixed

  • appinfo/info.xml wurde vom Nextcloud App Store abgelehnt: der Sprachcode pt_BR in <name>, <summary> und <description> ist im Schema nicht enthalten — die Enumeration kennt nur BCP-47-Schreibweise in Kleinbuchstaben mit Bindestrich. Alle drei Vorkommen heißen jetzt pt-br
  • Die Kindelemente von <info> sind im Schema eine feste Sequenz; <settings> stand vor <dependencies> und wäre nach dem Sprachcode-Fix als nächster Validierungsfehler aufgeschlagen. Der Block steht jetzt an der vom Schema vorgesehenen Position hinter <dependencies>. xmllint --schema gegen https://apps.nextcloud.com/schema/apps/info.xsd läuft damit sauber durch
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureYbjiEkGYW1s8Xg9Jvrt4nNo/67zkrQDA16yfK2MzVa58R982qrLUupNbvUE/FscP
pFg9nlqxd81cpyH1ZhWOM7fMq98mPyjSUsJZ7xjYzNccF13xvDpBXFlfX4UyCknc
50Rmw9a8RxiCH0mEpH9zWjdanX194R8cUIMDY+BcymCgyBVRQub9yaL5iiHH3hNA
OOD+UOiSUNHns9R6sgZ+tF4OeoTufWR5//AfRmuL5qC5spyuP1iKr7FnzPar+/sS
pHKojfUyi0sAjlrThVZDo8fvVPqkkH4jgvVmNE41t1UOlVdajIRd2yhbHX0h0SSs
rmt4CQqNXAjLE/Wlq2lu9Viw4M2BhhPIfVb5YJFzaxjhB8RRy53rquXRL64f7vGa
agq0ri3eD+0ZWmMOlJmHaMv6AXYd0ZG8myb3PAyNC0NYXzrw2PAVL8jDfzmq2cNY
Q3rIh101vtGPytqanNS2VmtfZ8BX63rd4SLR4PJdRYrm3Wbqanx8WZa20eLgYF8S
M9xhxl5Jf8+TnYLwHi1sGm1ID2XJ4krfgOxiUlB8lGeSweUK1uueC0bmUDsrXyhJ
RMGST41TU1HqXx/3Eeh91JKq/Jbx15kPuxu7WNKyuSOj4vKbgFwBUSmHKDU6lvEZ
L/bnxZi965/4K3kvyJ8o2j5e4xUmJLeusi9Fg0yrRqE=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.2
Release Details
UpdatedAug. 26, 2026, 5:18 p.m.
Changelog

Changed

  • Teilen-Dialog: das Eingabefeld für den einzuladenden Nutzer ist jetzt ein Suchfeld statt eines reinen Textfelds für die Benutzer-ID (Issue #144). Getippt wird nach Anzeigename, Benutzer-ID oder E-Mail-Adresse; ein neuer, admin-unabhängiger Endpunkt GET /api/v1/users/search (UserController::search(), IUserManager::search(), max. 20 Treffer, der eigene Account wird ausgeblendet) liefert dazu Anzeigename, Benutzer-ID und E-Mail als Vorschlagsliste. Gespeichert wird weiterhin die Benutzer-ID als principal_id – für Umgebungen mit LDAP/AD-Benutzerverwaltung war die zufällig generierte ID zuvor nicht ohne Umweg über die Benutzerverwaltung in Erfahrung zu bringen. Die Liste bereits geteilter Zugriffe zeigt ebenfalls den Anzeigenamen statt der rohen ID (ShareController::index() reichert die Antwort um display_name an, Fallback auf principal_id falls der Account inzwischen gelöscht wurde)
  • Übersetzungen für alle sechs Sprachen ergänzt
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureyLn/jlYbk3gIYfgIcjON0z467/xL9L6QNcmfgOa/4zhTJjLknXq7eu1UJddWWlLJ
NG2U9d/OEFO9wLHPYPGNiWgQMRIk+TGYlQVTXcZH3WpBxdJOm3XMnk5hq2kNB2FN
TJemqr/dxafGB2hTIgivPMXMnemdrtxWN1RAdzCxZIg9HwJWjG5JxdqHmURHwske
p/Ki/iZghKjrxbPIghbqtrvkCJRImbgVWY8AmUNUPLgotNIthiWFnkTDVhYWcreP
pWleWHxEn57UOtehff1aJa+hRI+8WVkx9iXArx0SThmOCYYgJ/HeG8dOOtmr9jSm
1nzETAL87YLxL/+qM6DyBIgNWhrq1oj9Q12bBm1+la477z6fpOgUlMjWkPEYRQi/
vhxirXwB4BZBYvaMEkNlN2U3+7BqgigGoaTcbN2rG/TP1JuOjdj9jEjMMRye0JbT
35XOoM/VPYGovrT9slHg8r3Wolyd8ioXVOu4IcMImvC5OrTzpKY7NLEc/S+cOKwz
ijOKcnoV0j++KxtQKKgEO96HJpEM0jteQVOGCoPbghjS3OFzkiB1bUVJAlu1jn54
38Q2zw8rZ0EMm1rEPmIrl72DIIXionbWKatREgy7QPwuL/WKZ2c+J1UIUTKck5eO
7M2VHh6P3FnIg/UsOCMu3U7ja0Y8vQ3YUo3tazLfob0=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.1
Release Details
UpdatedAug. 25, 2026, 1:28 p.m.
Changelog

Added

  • Screenshot des gerenderten Gantt-Charts als PNG, SVG oder PDF (Issue #116): ein neuer „Screenshot"-Eintrag in der Chart-Toolbar öffnet ein Menü mit den drei Formaten, derselbe Export steht im Bearbeiten-Dialog des Projekts neben JSON und CSV bereit (dort mit vorgeschalteter Formatwahl statt Menü, openScreenshotFormatDialog()). Exportiert wird stets das gesamte Chart, nicht nur der sichtbare Scroll-Ausschnitt — frappe-gantt rendert die volle Breite und Höhe ohnehin als eine SVG. PNG und SVG klonen die aktuell gerenderte SVG und schreiben getComputedStyle() als Inline-Attribute (löst auch CSS-Variablen auf), sodass die Datei ohne das App-Stylesheet eigenständig darstellbar ist; sie folgen dem eingestellten UI-Theme, ein hinterlegtes Rechteck in --color-main-background deckt dabei auch die Fläche unterhalb der Aufgabenzeilen (Workload-Chart, Leerraum) ab, die sonst transparent bliebe. PNG rastert per Canvas mit doppelter Auflösung
  • Zeitraum-Auswahl für den PDF-/Druck-Export (Issue #116): vor dem Drucken fragt ein Dialog, welchen Zeitraum die PDF abdecken soll — gesamter Projektzeitraum (Vorbelegung), laufendes Kalenderjahr, „aktives Quartal" (Vormonat bis einschließlich übernächstem Monat) oder ein frei eingegebener Bereich. Der Vorschlag ist der tatsächlich von Balken belegte Zeitraum, nicht gantt_start/gantt_end — frappe-gantt legt darum großzügig Puffer, der andernfalls mitgedruckt würde. Umgesetzt wird der Zuschnitt als viewBox auf dem SVG-Klon; die dafür nötige Skala (Chart-Start, Pixel pro Millisekunde) schreibt GanttChart.vue nach jedem Render als data-Attribute an den Chart-Container, sodass auch Aufrufer ohne Zugriff auf die frappe-Instanz (Bearbeiten-Dialog) sie lesen können. Die Zeitraum-Logik steckt isoliert testbar in src/gantt/printRange.js (src/gantt/printRange.test.js)

Changed

  • Der PDF-Export druckt nicht mehr den Live-Container, sondern einen gestylten, selbst gerasterten Klon des Charts (Issue #116). Bisher wurde das Inline-SVG direkt gedruckt — wie fein die Browser-Engine das rastert, ist nicht steuerbar und fiel je nach Browser sichtbar grob aus. Jetzt wird der Klon mit 300 dpi bezogen auf die bedruckbare Fläche (A4 quer, 10 mm Rand → 277 × 190 mm) in ein Canvas gerastert und als Bild mit fest vorgegebener physischer Größe in den Druck gegeben; schlägt die Rasterung fehl, bleibt der SVG-Klon als Druckinhalt übrig und skaliert per CSS auf die Seitenbreite. Der Klon wird immer im hellen Theme berechnet (Papier ist weiß, ein dunkles UI-Theme ergäbe sonst dunkelgraue Flächen und helle Schrift) — dafür genügt ein ausgelagerter Container mit gesetztem data-theme-light, da Nextcloud die Stylesheets aller Theme-Varianten lädt und nur über dieses Attribut umschaltet. Das Ausblenden der übrigen Seite läuft über display: none statt visibility: hidden, sonst blieb die Fläche der App als Leerseiten erhalten; Nextclouds Hintergrundbild auf html/body wird für den Druck abgeschaltet. Aufgeräumt wird über afterprint mit Timeout-Fallback für Browser, die das Event nicht feuern
  • Der Toolbar-Eintrag heißt „Screenshot" (Icon MonitorScreenshot) statt „Export" (Icon ExportVariant) — „Export" ist im Projekt bereits für den Daten-Export nach JSON/CSV belegt, der Chart-Export ist demgegenüber eine reine Abbildung der aktuellen Darstellung
  • Übersetzungen für alle sechs Sprachen ergänzt
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
Signaturek6kpvF53IR8tnkOFXyoSPFPGlwVzO/RUTgI1p1ppRcFmoFPUyFeIokOqWA1OtD9q
wdo+qkQQPyJGph0Uwp+hwP9oGmeKWErnlv8HMdA5I5iaXIN7afGvdfxWfKgqWetw
tGmCF7l2IzMmT2Ol/3pKgCnFkXTDPCVeNINNbUdi7EjeRpbcbOGWt3+5UVwZgVTX
Z9/kEEPvjMV98s1zT5yBXcFvyqZA7bhhezmBkfzaLa0DAIczFJbhyFtR06WuS7bP
CWBCs/xvSRuCwo61oyXRAWLohz/2GsrMSa5jvPvnEG1XEHpGPVorCijAvsBm4sX5
yAZTrBm3zbNYObqVE2idxTH/eqP8xXtE38JFjpG5IahpeFNb9V2EbH1nrjfRKYcH
NVvXcXFREAmvorShKDE0ymFN+/BCjvU1vnJCnRD5RMsoSGUzXSVHPrF1emtusLHj
ltP22eYOCpraEpZheTkFftqvpbiQKVXsZ+8wY4dJnh5Ymi71loxZhggoH8s/pmp+
WbSx6MZwSPBqJ0HOJWckFiZXur2OQYOVLfXt8uPYNU/EZSoYDqm81GVMglQXxyM6
YDh0xXqwJ7Qft7k0O/3Fa5YLJGP4B4RvjU29N3/WDsfjuk7PeCSTPhRlTOfV/Fbn
jS83WVBavmyklhu0rNYuCYfdYvUxemIO3VuGmYzFXgI=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.0
Release Details
UpdatedAug. 24, 2026, 5:26 p.m.
Changelog

Added

  • Editierbare Vorgänger-Spalte in der Tabellenansicht, Teilschritt F von #117 (Issue #124): eine neue, über das Spaltenmenü einblendbare Spalte „Vorgänger“ zeigt die Abhängigkeiten einer Aufgabe in der aus MS Project bekannten Kurznotation (12EA+2d = Vorgänger Aufgabe 12, Ende-Anfang, zwei Arbeitstage Abstand; mehrere durch ; getrennt) und nimmt sie dort auch entgegen. Typ (EA/AA/EE/AE, englische Kürzel FS/SS/FF/SF werden beim Eingeben mit akzeptiert) und Abstand sind optional, 12 allein bedeutet also EA ohne Abstand. Geprüft wird beim Verlassen der Zelle: Syntax, Existenz der Aufgabe im selben Projekt, Selbstbezug, Dubletten und Kreisschluss über die gesamte Abhängigkeitskette – bei einem Fehler bleibt die Zelle im Bearbeitungsmodus und nennt den Grund im Klartext, die bisherigen Abhängigkeiten bleiben unangetastet. Gespeichert wird über dieselbe PUT /tasks/{id}-Route wie der Detail-Dialog (inkl. dep_mode), sodass der Server die Termine anwendet und durch die Nachfolgerkette propagiert; Balken, Pfeile und Typ-Labels im Chart zeichnen sich mit der Antwort neu. Bewusst ohne Undo-Toast, da ein Zurücknehmen nur der Termine (nicht der Abhängigkeit) beim nächsten Neuberechnen wieder überschrieben würde. Nur Aufgaben haben eine editierbare Zelle – Meilensteine hängen über task_id an genau einer Aufgabe, Projekte und Teilprojekte sind berechnete Strukturebenen. Notation und Prüfungen stecken isoliert testbar in src/gantt/dependencyNotation.js (src/gantt/dependencyNotation.test.js)
  • Zeitabstand (Lag/Lead) je Aufgaben-Abhängigkeit (Issue #124): neue Spalte lag_days in nc_gantt_task_deps (Version1032; der Name vermeidet das seit MySQL 8.0 reservierte Wort LAG und nennt die Einheit). Der Abstand zählt in Arbeitstagen über den Ressourcenkalender wie die übrige Terminberechnung, wirkt bei allen vier Abhängigkeitstypen auf deren Ankertag und darf negativ sein (Lead: der Nachfolger beginnt früher). Bestandsabhängigkeiten bekommen 0 und verhalten sich unverändert. TaskService::update() weist eine gesendete Vorgängerliste jetzt vollständig zurück (invalid_dependency, dependency_cycle), bevor die bisherigen Abhängigkeiten dafür gelöscht werden, statt Vorgänger aus fremden Projekten oder Zyklen zu speichern – letztere hätten die topologische Sortierung in recalculateProject() stillschweigend Aufgaben überspringen lassen

  • Konfigurierbare Spalten in der Tabellenansicht, Teilschritt E von #117 (Issue #122): ein Menü in der Tabellenkopfzeile blendet Spalten ein und aus, die Reihenfolge lässt sich per Drag & Drop der Kopfzellen ändern (barrierefreie Alternative: Strg+Pfeil links/rechts auf der fokussierten Kopfzelle), die Breiten per Ziehen am Spaltentrenner (Doppelklick setzt auf die Standardbreite zurück). Zusätzlich zu den bisherigen Spalten (Titel, Start, Ende, Fortschritt) stehen ID, Dauer (Kalendertage inkl. Start- und Endtag, bei Meilensteinen 0), Status (Issue #78, nur Aufgaben/Teilprojekte) und Ressource (Issue #103, zugeordnete Ressourcennamen einer Aufgabe) bereit – alle vier als reine Anzeigespalten, die das Inline-Editing und die Tastaturnavigation daher überspringen. Auswahl, Reihenfolge und Breiten werden pro Nutzer über den in Teilschritt B angelegten UI-Preferences-Endpunkt persistiert (neuer Key gantt_table_columns, kein Schema- oder Endpunktwechsel nötig); eine gespeicherte Konfiguration wird beim Laden validiert, sodass entfernte Spalten oder unplausible Breiten die Ansicht nicht beschädigen können. Die Tastaturnavigation folgt jetzt der sichtbaren Spaltenreihenfolge statt einer festen Liste. Reicht die Tabellenbreite für die gewählten Spalten nicht aus, scrollen Kopfzeile und Zeilen gemeinsam horizontal; die Obergrenze des Splitters steigt dafür von 560 auf 900 px. Die Spaltenlogik steckt isoliert testbar in src/gantt/tableColumns.js (src/gantt/tableColumns.test.js). Ein Sortieren der Zeilen nach Spaltenwert ist bewusst nicht enthalten – es kollidiert mit der Hierarchie Projekt → Teilprojekt → Aufgabe und der sort_order, die das Chart für dieselbe Zeilenreihenfolge braucht

  • Tastatur-Navigation in der Tabellenansicht, Teilschritt D von #117 (Issue #121): Tab/Shift+Tab springen zur nächsten bzw. vorigen editierbaren Zelle (überspringt Zeilen ohne Schreibrecht, springt am Zeilenende zur nächsten/vorigen Zeile), Enter speichert und springt in dieselbe Spalte der nächsten Zeile, Esc bricht ab und stellt den vorigen Wert wieder her. Pfeiltasten bewegen die Zellauswahl, wenn gerade keine Zelle im Editiermodus ist (innerhalb einer Zelle bleiben sie für Cursor-/Wertänderung nutzbar). Die reine Traversierungslogik steckt isoliert testbar in src/gantt/tableNav.js (src/gantt/tableNav.test.js). Die ausgewählte Zelle bekommt einen sichtbaren Fokusrahmen und wird per scrollIntoView() ins Sichtfeld gescrollt – über den bestehenden bidirektionalen Scroll-Sync (Issue #119) folgt das Gantt-Chart automatisch mit. Neue ARIA-Rollen (grid/row/columnheader/gridcell, aria-readonly je Zelle) machen die Tabelle für Screenreader als Grid erkennbar
  • Read-only Tabellenansicht links vom Zeitstrahl, Teilschritt B von #117 (Issue #119): neue Komponente GanttTable.vue zeigt dieselben Zeilen wie das Chart (Titel mit Einrückung nach depth, Startdatum, Enddatum, Fortschritt), gespeist aus buildRowModel()/buildTableRows() (siehe Teilschritt A, Issue #118) – Reihenfolge, Filter-Dimming, kritischer Pfad und Projektfarben bleiben so exakt konsistent zum Chart. Zeilenhöhen sind fest an frappe-gantt gekoppelt (40 px = bar_height 22 + padding 18, Kopfzeile 52 px = header_height). Ein Toolbar-Button blendet die Tabelle ein/aus, ein Splitter macht die Breite verstellbar (160–560 px), vertikales Scrollen ist bidirektional mit .nc-gantt-container synchronisiert. Sichtbarkeit und Breite werden pro Nutzer über einen neuen, generischen UI-Preferences-Endpunkt (GET/PUT /api/v1/ui-preferences, SettingsController über IConfig::get/setUserValue() als JSON-Blob) persistiert, damit Teilschritt E (Editieren) das Schema nur noch um weitere Keys erweitern muss, ohne Endpunkt oder Speicherformat anzupassen. Rein lesend – Editieren folgt in Teilschritt C
  • Projekt-Export/-Import (JSON, format_version: 2) kann jetzt optional die von den Aufgaben referenzierten Ressourcen inkl. Gruppe, Wochenmodell, Arbeitskalender+Feiertagen und Tageskapazitäten mitnehmen, statt wie bisher nur die rohe resource_id in eine Zieldatei zu schreiben, die dort ungeprüft übernommen wurde – auf einem System ohne identische Ressourcen-IDs ging die Zuordnung damit verloren oder landete schlimmstenfalls bei einer fremden Ressource (Issue #115). Vor dem JSON-Download entscheidet ein Options-Dialog, was mitexportiert wird (Ressourcen / Verfügbarkeiten / Kalender, gestaffelt); vor dem JSON-Import zeigt ein passender Dialog, wie viele Ressourcen die Datei enthält, und lässt auswählen, was übernommen wird sowie ob bei Namensgleichheit die vorhandene Ressource wiederverwendet (Default) oder immer neu angelegt wird. Referenzen werden ausschließlich über eine Mapping-Tabelle aufgelöst und nie roh durchgereicht; nicht auflösbare Referenzen werden verworfen (Regressionsschutz zu #112/#113). Neu angelegte Ressourcen/Gruppen/Kapazitäten gehören stets dem importierenden Nutzer. Wochenmodelle/Kalender/Feiertage sind weiterhin admin-only anlegbar – ohne Adminrechte werden nur namensgleiche vorhandene Einträge gemappt. CSV bleibt unverändert aufgabenzentriert mit Ressourcen nur als ID-Referenz; der volle Ressourcenumfang ist JSON-only. Alt-Exporte ohne resources-Schlüssel importieren unverändert wie bisher, ohne Options-Dialog
  • Inline-Editing der Basisfelder in der Tabellenansicht, Teilschritt C von #117 (Issue #120): die Zellen für Titel, Start, Ende und Fortschritt sind direkt editierbar und aktualisieren die Balken im Chart sofort. Gespeichert wird über die bestehenden Store-Actions (updateTask/updateSubproject/updateMilestone/updateProject) inkl. Terminpropagation und dem vorhandenen Undo-Toast für Aufgaben (analog Drag & Drop im Chart); ein lokaler pendingEdits-Overlay zeigt die Änderung optimistisch an und rollt sie bei einem fehlgeschlagenen Request mit Fehlermeldung zurück. Die Schreibrechte löst tableRows.js je Feld über store.canEditProject() auf (titleEditable/startEditable/endEditable/progressEditable) – Projekte und Teilprojekte bleiben bei Datum und Fortschritt read-only, da diese Werte aus den Aufgaben berechnet werden. Geprüft wird: Titel nicht leer, Enddatum nicht vor Startdatum (Meilensteine ausgenommen, deren Start- und Endspalte dasselbe milestone_date zeigen) und Fortschritt 0–100. Im Simulationsmodus rufen Datumsänderungen an Aufgaben simulateTaskChange() statt einer echten Speicherung auf
  • Ressourcen-Überbuchungswarnung (Issue #82): die Kapazitätsplanung war bisher reine Datenerfassung ohne Abgleich mit dem tatsächlich verplanten Aufwand. Der neue Endpunkt GET /api/v1/resources/{id}/utilization?from=&to=&group= (ResourceUtilizationService/ResourceUtilizationController) stellt den geplanten Aufwand aus den Aufgaben-Ressourcen-Zuordnungen – gleichmäßig auf die Arbeitstage der Aufgabe verteilt, über WorkCalendarService mit ressourcenspezifischen Arbeitstagen und Feiertagen – der erfassten Tageskapazität gegenüber. Mehrfach-Ressourcen-Zuordnungen (Issue #103) samt Alt-Aufgaben werden berücksichtigt, ohne gepflegte Tageskapazität gilt ein Fallback von 1 PT/Tag. Im Ressourcen-Raster färben sich die Zellen nach Auslastungsgrad (> 90 % gelb, > 100 % rot) und der Tooltip zeigt geplante Stunden gegen Kapazität samt Aufschlüsselung nach Projekt und Aufgabe; das Workload-Chart im Gantt markiert überbuchte Perioden jetzt rot. Übersetzungen für alle sechs Sprachen ergänzt
  • Nachgetragen – beide Funktionen wurden bereits mit 1.4.2 ausgeliefert, waren dort aber nicht im Changelog dokumentiert:
  • Einheitliches Statusmodell für Teilprojekte und Aufgaben (Issue #78): neues Feld status (not_started/in_progress/blocked/done) auf nc_gantt_subprojects und nc_gantt_tasks ergänzend zum numerischen Fortschritt, Bestandsdaten leitet Migration Version1030 daraus ab. Validierung per StatusValidator (Whitelist analog ColorValidator), Status-Dropdown in den Detailformularen, blockierte Balken im Gantt schraffiert und mit Warnsymbol, blocked_count je Projekt im Rollup sowie ein Badge in der Projektliste
  • Mehrere Ressourcen mit individuellem Aufwand je Aufgabe (Issue #103): bis zu vier Ressourcen je Aufgabe mit eigener Aufwandsschätzung in der Einheit der Ressource (neue Tabelle nc_gantt_task_resources, Migration Version1029, Backfill aus den vorhandenen resource_id/work-Werten). Das manuelle Work-Feld entfällt: TaskService::resolveResources() summiert die Einzel-Aufwände zur Gesamt-Work (1 PT = 8 h) und übernimmt die erste Zuordnung als primäre resource_id, die weiterhin für Arbeitskalender und CPM maßgeblich ist. Ressourcen-Filter sowie CSV-/JSON-Export und -Import berücksichtigen alle Zuordnungen statt nur der primären

Changed

  • buildFrappeRows() (src/gantt/frappeRows.js) mischte bisher Datenmodell und frappe-gantt-Formatierung: die Einrückungstiefe steckte als Leerzeichen im name, Zustände (Dimming, kritischer Pfad, Summenbalken) hingen in custom_class – eine geplante Tabellenansicht neben dem Gantt-Chart (Issue #117) hätte dieselbe Logik duplizieren müssen (Teilschritt A, Issue #118). Neue Funktion buildRowModel() (src/gantt/rowModel.js) liefert dieselbe Zeilenliste jetzt als neutrales Modell (id, type, entityId, depth, title, start, end, progress, parentId, editable, matched, critical), resolveMilestoneDate() wandert mit ins Modell. buildFrappeRows() ist nur noch ein dünner Adapter darüber, der name/custom_class/dependencies wie bisher erzeugt. Reines Refactoring ohne sichtbare Änderung, per Fixture-Vergleich gegen die alte Implementierung geprüft; neue Unit-Tests (src/gantt/rowModel.test.js, npm run test:unit, via neu eingeführtem vitest) decken Hierarchie, Einrückungstiefe, Meilenstein-Datumsauflösung und Filter-Dimming ab

Fixed

  • Abhängigkeitsfortschreibung bei Aufgaben lieferte für alle vier Abhängigkeitstypen (EA/AA/EE/AE) einen um einen Arbeitstag zu langen Nachfolger-Termin – bei EA zusätzlich mit falschem Anschlusstag, da der Nachfolger auf dem Endtag des Vorgängers statt am folgenden Arbeitstag begann und dadurch mit dem Vorgänger überlappte (Issue #114). Ursache war eine Off-by-one-Vermischung zwischen der inklusiven Arbeitstagszählung und der exklusiven Datumsfortschreibung in TaskService::applyConstraint()/computeMultiConstraint(). Betroffen sind sowohl das direkte Setzen einer Abhängigkeit als auch die Terminpropagation nach Drag & Drop und die What-if-Simulation. Verhaltensänderung: Bestehende Pläne mit EA-Abhängigkeiten verschieben sich beim nächsten Speichern/Neuberechnen um einen Arbeitstag nach vorne (auf den korrekten Anschlusstag); bei AA/EE/AE verkürzt sich der zuvor fälschlich verlängerte Nachfolger-Zeitraum um einen Arbeitstag, die ursprüngliche Dauer bleibt jetzt garantiert erhalten. Abhängige Meilensteine (Dauer 0) sind unverändert korrekt und von diesem Fix nicht betroffen

  • Security: jeder Nutzer mit Schreibrecht auf ein eigenes Projekt konnte jede in der Instanz existierende resource_id einer eigenen Aufgabe zuordnen – unabhängig vom Eigentümer und ohne jede Share-Beziehung (Cross-Tenant-IDOR, Issue #112). TaskService::resolveResources() lud die vom Client gesendeten IDs bisher nur über ResourceMapper::findByIds(), also als reine Existenzprüfung ohne Berechtigungscheck; da die IDs fortlaufende Integer sind, waren sie trivial zu erraten. Der Listen- wie der Legacy-Einzelfeld-Pfad in create()/update() filtern referenzierte IDs jetzt über ResourceMapper::findVisibleToUser(), nicht sichtbare IDs werden wie unbekannte verworfen (Liste) bzw. nicht übernommen (Einzelfeld, der bestehende Wert bleibt erhalten). Regressionstests decken beide Pfade für create() und update() ab

  • Feiertage ließen sich nicht in mehreren Regionskalendern führen: POST /admin/holidays lief in einen HTTP 500, sobald dasselbe Datum in einem zweiten Kalender angelegt wurde, weil der Unique-Index aus Version1006 allein auf holiday_date lag, obwohl Feiertage seit Version1013 über calendar_id kalenderbezogen sind. Version1031 verschiebt den Index auf (holiday_date, calendar_id); die Eindeutigkeit globaler Feiertage sichert weiterhin der Upsert in HolidayAdminController::create(). Betroffen war neben der Feiertagsverwaltung auch der Kalender-Import aus einem Projekt-Export, wo der Fehler still verschluckt wurde. Zweitens war GET /admin/holidays admin-only, während work-calendars und work-schedules lesend für alle offen sind – für normale Nutzer blieb der Store deshalb immer leer (keine Feiertage im Projekt-Export, keine Markierung arbeitsfreier Tage im Ressourcen-Raster); der Lese-Endpunkt zieht nach dem Muster der übrigen Stammdaten auf /api/v1/holidays um (NoAdminRequired), Anlegen und Löschen bleiben unter /api/v1/admin/holidays. Ergänzend werden Feiertage jetzt mit ihrem Kalender gelöscht (WorkCalendarController::destroy(), HolidayMapper::deleteByCalendar()) und Bestandswaisen bereits gelöschter Kalender in Version1031 aufgeräumt – über verweisende Ressourcen haben sie bis dahin weiter als arbeitsfreie Tage gewirkt
  • Die Installation der Tabelle nc_gantt_task_resources scheiterte auf Instanzen, deren Tabellenpräfix die von Nextcloud aus Oracle-Kompatibilität erzwungene 30-Zeichen-Grenze für Bezeichner reizt: der von Doctrine automatisch vergebene Primary-Key-Name (Tabellenname + _pkey) wird mit Präfix oc_ zu lang (Issue #132). Die Primärschlüssel-Definition bekommt – analog zu den bestehenden Migrationen für nc_gantt_resource_capacity und nc_gantt_resource_groups – einen expliziten kurzen Namen
  • Der absolut positionierte Toggle-Button der Nextcloud-App-Navigation ragte in den App-Content hinein und verdeckte dort den Titel des ersten Eintrags in der Projekt-Rollup-Leiste (Issue #134); der linke Innenabstand reserviert jetzt Platz für den Button
  • Ein leerer Balken in Höhe der Kopfzeile erschien oberhalb des App-Inhalts, weil der CSS-Reset für den Nextcloud-Content-Wrapper an main#content.app-nc_gantt gekoppelt war (Issue #126). Ändert sich das Markup zwischen Nextcloud-Versionen (Klasse oder Tag), griff der Reset nicht mehr und der von NcContent (#content-vue) selbst gesetzte margin-top: var(--header-height) addierte sich zum Rand des Cores. Der Reset hängt jetzt robust an #content mit !important, ohne Abhängigkeit vom app-spezifischen Klassennamen
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturegO8Qmtdwg8LOBKr5G+mq4co374hsqqSN6oCIRV9atUx0KqogPxisJiIExkPoSIbu
e4EeIaUzg2alhZsKBLWOwR3Ab3fNm5vvd2DzJn6Hei7A70woz9m/LXkVlcx3vALW
bwolClUX1XCZOBVo/kSS5AOVwak3/huzT1iF9xH9BnpdzVuOjZ563LYwSayfb2Gq
SkWNfLZlKlDkTTF2PIszrNmaa89GmyqTbraxSP16/9nYdIj8ZU0zrhC3HtpihgAT
wya2lwnMf6I73HU0xxgT/+ITTmurx4eHwKWH80P4tjg/Y9mnHODIpAslbW3351mc
qdTHXIBW1MB1YGCQ+JPt11v1X2ccn29kEF9d1nkizKZ1+Du+LJQhPhwHiQxPWSwAUlTlQ4tj1lbe3+FJ1jsVTCqWbDUN02EoV7ZwtN15/HLJfM6w4drUi8ThJ1aLG3v6
cIwMJjYgWeepxR2gv4YgBf4u7txodm5bAWuzySk4rfAG1dBxmie/bfNnWmQ9LrYy
spwKc73gsPhg03ll+jp0b27fJfNF4IpOysz3i+r1ExVfeNIWWO91JPatO2pXZh4O
q0rczM8wYvctvcEkKQIL67HoIrKw4GVIXfqM9Oc8e/Ay7d/NPL+BjpCO6zvoFBY+
SRmjit15YmGW4EQwweQfKXuZ2YeySj+7OjhKHpKfvfg=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.2
Release Details
UpdatedAug. 20, 2026, 4:41 a.m.
Changelog

Changed

  • release.sh fragt die Versionsnummer jetzt interaktiv ab, statt sie nur aus appinfo/info.xml zu lesen: zu Beginn werden die aktuelle Version und das letzte Release-Tag angezeigt und es wird gefragt, ob eine neue Nummer vergeben werden soll (Vorschlag: nächster Patch-Level). Die Eingabe wird auf das Format X.Y.Z, auf einen echten Versionssprung und auf ein noch nicht vergebenes Tag geprüft und dann nach appinfo/info.xml, package.json und package-lock.json geschrieben. Fehlt ein Changelog-Abschnitt zur neuen Version, warnt das Skript; anschließend bietet es an, den Bump als chore: Version X.Y.Z zu committen — nötig, weil der Tag-Name den Commit-Hash enthält. Für nicht-interaktive Läufe gibt es --version=X.Y.Z und --no-bump; ohne TTY wird nie gefragt, make release bleibt also unverändert nutzbar
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturepoVHZxteU3AR2cpRRV98jNfv4j7rWnLEd3kbpn5Dp4T1ubAI+0QlRf9jxi0BaYz1
+1dg+3Yt25uN6Slp1FHiw7kyqt5HJ60XgnOWo+Zt0YBHSnWqLDhF8zxPEnQCkF+v
nUvscpcoQY2bRiIBZhVWVgeAD592uvOA4gfRDrUyLVDKjOrzBu3ScbNvCqTqE9IC
vs8qZkRLIcaD6tKoSLT2pZqmwBoCdClvEw5D5v40WSvLq232BZnXpQ4ogG3QvJdL
mYO8HlPZKVOxANp0MGnWle4IFRMbMt22Ebpkjc18Q9Q4AIv/Sd3zTsc+uMONTM95
s0GXvLSm95o0UCFZ1CL7fCEq7NwlprjVrTeWGmlJNVjHJuIyRKHEz5DR12s0lAGm
/rKGWjoVP+Wvk3upRizR/5y2fpWoiwuDqCtz9gQN6+HHYLaqLvYqsAJ/SxmtLtP7
8B2rK61ClKowz4phbTZdrCaF8w3IWnFFBTFquIVFuN2jUoHvdCMtd0910sLAMY5M
Xs9nk0FVsP23zKXlQpOojq7ouCQagRhsnBJDLxWRR+NIq582f7SDgcrkBqxlGJX4
/Ql9V+2iFx61QANCTjdJIO3LbvbK60vGos+ency0GfvSDbPovDAVyJzt8ZUh5BNw
UXQ4XOHJZAagAr36rKttk1DQbZZ/2bUEq231c96m83g=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.1
Release Details
UpdatedAug. 17, 2026, 7:43 p.m.
Changelog

Fixed

  • Die Meilenstein-Raute hatte eine fest verdrahtete Farbe (#fbbf24) statt der Projektfarbe zu folgen, obwohl Balken für Aufgaben und Teilprojekte bereits korrekt eingefärbt wurden (Issue #102). Zusätzlich wurden die separaten – und wirkungslosen – Farbwähler bei Teilprojekt und Aufgabe entfernt, da deren Anzeige ohnehin immer der Projektfarbe folgt
  • „Meilenstein hinzufügen" im Drei-Punkte-Menü der Projektliste nutzte zwei aufeinanderfolgende window.prompt()-Dialoge (Name, dann Datum als Freitext) statt des regulären Detail-Dialogs (Issue #101). Der Klick emittiert jetzt add-milestone analog zu „Aufgabe hinzufügen" (Issue #91) und öffnet denselben Meilenstein-Dialog wie beim Bearbeiten, mit vorbelegtem Projekt
  • Im festen Datumsmodus des Aufgaben-Detaildialogs konnte ein Enddatum vor dem Startdatum eingegeben und gespeichert werden (Issue #100). Jetzt zieht ein über das Enddatum hinaus verschobenes Startdatum das Enddatum mit; ein zu frühes Enddatum erzeugt ein rotes Fehler-Icon am Feld, hält den Fokus dort und deaktiviert den Speichern-Button, bis ein gültiges Datum eingetragen ist (dateField() in fields.js mit neuer setError()-Methode)
  • Eine Aufgabe mit Abhängigkeit behielt trotzdem die manuell eingegebenen Start-/Enddatumsfelder, die beim Speichern durch die Abhängigkeitsberechnung überschrieben wurden – für Nutzer nicht nachvollziehbar (Issue #99). Der Aufgaben-Detaildialog hat jetzt denselben Fixed-date/Dependency-Umschalter wie Meilensteine (Issue #90): im Dependency-Modus ersetzt eine Dauer (Tage) die Datumsfelder, die Abhängigkeit bestimmt den Termin. Serverseitig wendet TaskService::create() neu hinzugefügte Abhängigkeiten sofort an (bisher nur update()), damit auch neu angelegte Aufgaben keinen die Abhängigkeit ignorierenden Platzhaltertermin behalten
  • Der Speichern-Button des Detail-Dialogs blieb nach dem Hinzufügen einer Abhängigkeit deaktiviert: die Gültigkeitsprüfung hing allein am input-Event, das bei einem <select> vor dem change-Event feuert – zu diesem Zeitpunkt war die Abhängigkeit noch nicht in der Liste. detailModal.js wertet jetzt zusätzlich change aus, der Abhängigkeits-Editor (fields.js) meldet jede Mutation (Hinzufügen, Entfernen, Typwechsel) und der Fixed-date/Dependency-Umschalter in taskForm.js den Moduswechsel über ein eigenes bubbelndes change-Event

Added

  • CONTRIBUTE.md und setup-dev.sh für neue Mitwirkende (Issue #98): Projekt-Leitlinien (FOSS, Datensparsamkeit, Security), VIBE Coding ausdrücklich erlaubt, sowie der komplette lokale Dev-Setup-Weg (Docker-only, Nextcloud + MariaDB unter localhost:8088, optionales E2E-Setup, Git-/Bot-Auth). setup-dev.sh automatisiert diese Schritte, konfigurierbar über --workdir/--no-e2e/--no-docker-install
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturetYcUvVtDEQrAakG32EQF1atSOmz91/8XudCUh60A9r/AxMv+AA5AX2rIvNYDkEn0
OuTmXA6Iz0DoVkdij11MPDhfLaUy0mXeLbwB5fj/xF/cFYcNeCFGKD3k2jyRwOTo
2n1sEp0r8sn0fitHzLfhcB/By0VJkZyhaO/NctP01XfcSQM7lGEOeY/uagtGaDTI
JnPLoQTHo0nUOv4y7jUMZuurEgBOc4yeUxTKv4A/m642hvNQIS0q6K9ON41JHKIO
UtI7DbDWSboVhct1Go3zoj5XcaAGG9ZiwSkJDt/BXT5tWH4SOnSn7mys0j1F6Y0g
vIJWjz6S2RlekwIrIxgyaeEVBOeQ4OM1ilJGWKXDyYJM/0IBxqnqRXDkAFlOopDo
xezlcFdWTkYL5OBKMFJhKuTy7dEQ9hxx5Nz4+vLbNV8gDJZBI+5yI5m8W+809WIH
iKUpIda1ShOblvYH6Ek5AzBdTmoFQ6T4f7iWT7j1i4uUP2DsgehjGVl8yDIT/wyx
nV9t7koXapu1WeXrunSa++mXsi3lceNpthdz5/cUEOe9yWvc1rrulRhiWzePga8H
zjVQYGAIPvwYkWa47U6Zh7HBsQaS+9yQ8NDnD49SS4jUWTGlwNqfM+q9fZ16/G9d
7l4chZUPPbBv+xWfdxmFw+MC5zdkAq27isHToTqnm+w=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.0
Release Details
UpdatedAug. 13, 2026, 6:41 a.m.
Changelog

Added

  • Meilensteine werden jetzt immer direkt unter ihrem übergeordneten Objekt angezeigt statt gesammelt am Projektende (Issue #90): Meilensteine lassen sich neu auch einer Aufgabe zuordnen (bisher nur Projekt/Teilprojekt, Spalte task_id war bereits vorhanden, es fehlte nur die UI), das Auswahlfeld im Detail-Dialog heißt entsprechend „Übergeordnetes Objekt" statt „Teilprojekt". Zusätzlich können Meilensteine ihr Datum jetzt statt eines fixen Werts aus einer Abhängigkeit zum übergeordneten Objekt beziehen (EA/AA/EE/AE, analog zu Aufgaben-Abhängigkeiten; neue Spalte dependency_type, Migration Version1028) – da ein Meilenstein keine Dauer hat, bestimmen EA/EE das Ende und AA/AE den Start des Zielobjekts. Die Berechnung übernimmt der neue MilestoneDateService (serverseitig live bei jedem Abruf sowie im ICS-Feed neu aufgelöst, nicht persistiert propagiert) sowie clientseitig in frappeRows.js für sofortige Reaktivität ohne Neuladen
  • Undo für Drag-&-Drop-Verschiebungen inkl. Propagationskette (Issue #85, Umsetzung der einstufigen Empfehlung: letzte eigene Operation, kein Redo, zunächst nur Drag & Drop): Migration Version1027Date20260810020000 ergänzt nc_gantt_change_events um op_id (UUID) – alle Change-Events einer zusammenhängenden Operation (Drag + gesamte Propagationskette B→C→D) erhalten dieselbe op_id, erzeugt in TaskService::update()/propagateDates() und über ChangeEventService::log() protokolliert (dieses Change-Tracking war bisher tote Scaffolding-Logik ohne Aufrufer). Neuer Endpoint POST /api/v1/changes/{opId}/revert (ChangeEventController::revert, ChangeEventService::revertOperation) wendet alle Change-Events der Operation invers an, in einer DB-Transaktion mit Rechteprüfung über AccessService::canEditOrOwn(). Konfliktschutz: Revert wird mit HTTP 409 abgelehnt, sobald der aktuelle Feldwert nicht mehr dem protokollierten new_value entspricht (jemand hat zwischenzeitlich erneut geändert); der Revert selbst erzeugt wiederum neue Change-Events, die Audit-Historie bleibt lückenlos. Frontend: nach jedem gespeicherten Drag zeigt GanttChart.vue einen Toast „N Termine verschoben — Rückgängig" (showUndo aus @nextcloud/dialogs, 10 s sichtbar) sowie ein globales Ctrl+Z für die letzte eigene Operation der Session (stores/projects.js: lastOperation, revertOperation(), undoLastOperation())
  • Kalender-Export als abonnierbarer ICS-Feed pro Projekt (Issue #83, Variante A aus dem Umsetzungsvorschlag): neue öffentliche Route GET /apps/nc_gantt/projects/{id}/calendar.ics?token=… (regulärer, unauthentifizierter CalendarFeedController, damit externe Clients wie Thunderbird, Nextcloud Kalender oder mobile Apps ohne Nextcloud-Login abonnieren können) liefert Meilensteine als ganztägige VEVENTs (◆-Präfix), den aus den Aufgaben abgeleiteten Projektzeitraum sowie optional Teilprojekt-Zeiträume (Schalter „Auch Teilprojekt-Zeiträume einschließen", standardmäßig aus, um den Feed bei großen Projekten nicht zu überladen). Zugriff erfolgt über einen pro Projekt generierten, 256-Bit-zufälligen Token in der URL (CalendarFeedService, neue Spalte calendar_token auf nc_gantt_projects, Migration Version1026), der über einen neuen „Kalender-Feed"-Bereich im Freigabe-Dialog angezeigt, kopiert und jederzeit widerrufen/neu generiert werden kann (CalendarTokenController, nur für Projekt-Admins/-Eigentümer). ICS-Generierung ohne neue Abhängigkeit, RFC-5545-konform (Escaping, Zeilenfaltung)
  • What-if-Simulationsmodus für Terminverschiebungen (Issue #84): neuer Endpunkt POST /api/v1/projects/{id}/simulate führt Terminpropagation und CPM rein im Speicher aus (kein DB-Schreibzugriff) – TaskService::simulate() nutzt die neu extrahierte, stateless propagateDatesCore()-Kernlogik, die auch der persistierende update()-Pfad verwendet, CriticalPathService::computeFromTasks() erlaubt CPM auf einem hypothetisch veränderten Task-Datensatz. Frontend: „Simulation"-Toggle in der Gantt-Toolbar mit Banner inkl. Projektende-Delta in Arbeitstagen, Geisterbalken für die Ist-Termine (analog Baseline-Overlay) sowie Verwerfen/Übernehmen. Drag & Drop ruft im Simulationsmodus simulate() statt einer echten Speicherung auf. Szenarien bleiben bewusst flüchtig (kein Speichern benannter Szenarien), „Übernehmen" wendet die Änderungen als einzelne Task-Updates an, Simulation läuft pro Projekt
  • Neuer Eintrag „Aufgabe hinzufügen" im Drei-Punkte-Menü der Projektliste (Issue #91): legt wie der „Neu"-Button eine Aufgabe an, belegt dabei aber das gewählte Projekt direkt vor, sodass der Projekt-Auswahlschritt in der Maske entfällt
  • Such-/Filterleiste für Projekte, Teilprojekte und Aufgaben (Issue #81, Stufe 1: rein clientseitig auf Basis der bereits geladenen Daten aktivierter Projekte): Freitextsuche im Titel, Risiko, „überfällig" (Ende < heute und Fortschritt < 100 %), „über Budget" (Ist-Kosten > geplantes Budget), Ressource und „ohne Deck-Verknüpfung". Neuer Pinia-Store stores/filters.js (Zustand pro Nutzer in localStorage persistiert) und reine Matching-Logik in gantt/filterMatch.js. Nicht passende Balken werden in GanttChart.vue gedimmt statt ausgeblendet (Abhängigkeitspfeile und Zeitkontext bleiben lesbar), Projekte/Teilprojekte gelten als Treffer, sobald ein Nachfahre passt. Dieselbe Filterleiste (components/FilterBar.vue) dimmt in ProjectList.vue nicht passende Projekte; für nicht aktivierte Projekte sind nur Titel-Treffer zuverlässig auswertbar, da deren Aufgaben/Teilprojekte nicht geladen sind

Changed

  • Freigabe für Nextcloud 34 (Issue #94): max-version in appinfo/info.xml von 33 auf 34 angehoben, unterstützter Bereich damit NC 28–34. Verifiziert gegen Nextcloud 34.0.2 mit PHP 8.5 und MariaDB 11.4 (148 Unit-Tests, 39 E2E-Tests)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturerdYQI+Semnk0cWtKqUZinVDHk0KpxyqB5Ox4NBL9pyf5nrpK8xZpe9lBxc6zhDfW
8adLfVIwQtX+bI7S1O05xm0hwrUHQQ2ii6ADD8mlAxnZjdhKSCAhZ0NcaqT7Em0X
nD7yRP2B8zAAQMJNjzeBsLbzveNrXMoGzFrvm/jFxskUIUS01ykfWEg2C5+5/IAf
7jBAM8x2Qj92b8zyBFpLjfJQw9aTE/trtCsmZXQFmkJjGS0anrJc9dXKfqnHxknX
8jmLOv4Yq4Qtk3UF35HTiIGcA2W0UKfVyFb4XcrIMeSmLXXcagJWjeH5nB18UUNn
JyCgE/qY4v/SnrNQU92mIdMOQGuvYg7xbaz226lgNdwM2HuM9U8nc2juqJxAO+Wp
xs85yl82qIviZ5YY39HK371MZ/ufMsaVsVy3Nfn3PjqqkzGLmtAL6KJDcKHZWdDw
ugEPwO61DxnERZsNGeFpXfzCxjMpZc/qwUIfGw85idmU2vdedtrxHBkDGoqu1IP7
xZOO8uSYrzbXM6g1gs3WPBOY51CmZLs5pIQTN1tVl5ifGw4uOuzDBUCKiR5oA2MI
352HbA7wwWFgwoN9W5t4MRTowmaYpM8AB+nh9f1A5q9S8SelfMpXOqGew9VZb2jd
AuiJK/LEPjRgs5s3/FfC4Sb1MSsXDr1N1jziaF4MomM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32

Nextcloud 33

Gantt Projects 1.6.1
Release Details
UpdatedSept. 2, 2026, 6:15 p.m.
Changelog

Security

  • Ressourcen-, Gruppen- und Kapazitätsdaten fremder Projekte waren über geteilte Projekte einsehbar (Issue #183). ResourceMapper, ResourceGroupMapper und ResourceCapacityMapper::findVisibleToUser() gaben pauschal alle Datensätze eines Eigentümers frei, sobald irgendein Projekt dieses Eigentümers mit dem Nutzer geteilt war — unabhängig davon, ob die konkrete Ressource überhaupt in einem geteilten Projekt verwendet wird. Der neue zentrale ResourceVisibilityService prüft stattdessen, ob die Ressource tatsächlich in einer für den Nutzer sichtbaren Aufgabe verwendet wird, und wird von ResourceService, ResourceCapacityService, ResourceGroupService und TaskResourceAssignmentService genutzt. Damit lassen sich über eine geteilte Ressource weder die übrigen, nicht geteilten Ressourcen desselben Eigentümers einsehen noch eigenen Aufgaben zuordnen
  • GET /api/v1/resources/{id}/utilization gab Planungsdaten aus nicht zugänglichen Projekten preis (Issue #181). ResourceUtilizationService::findVisibleResource() prüfte nur, ob der Ressourcen-Eigentümer irgendein Projekt mit dem Nutzer geteilt hat; über die Auslastung waren dadurch Aufgaben- und Projekttitel samt Terminen aus fremden Projekten abgreifbar. Die Prüfung stellt jetzt projektbezogen fest, ob die Ressource in mindestens einem über AccessService::canViewOrOwn() sichtbaren Projekt verwendet wird; zusätzlich filtert collectPlannedHours() die Aufgaben auf genau diese Projekte, sodass auch bei erlaubtem Ressourcenzugriff nichts aus fremden Projekten durchsickert
  • Aufgaben und Teilprojekte ließen sich an fremde Projekte hängen (Issue #179). TaskService::create()/update() und SubProjectService::create()/update() prüften nur die Schreibberechtigung auf die eigene projectId, nicht aber, ob eine mitgesendete subproject_id bzw. parent_id überhaupt zu diesem Projekt gehört — mit Folgewirkung beim Löschen eines Teilprojekts (SubProjectService::deleteTasksForSubproject()) und im öffentlichen ICS-Feed (CalendarFeedService::buildIcs()), da beide über TaskMapper::findBySubProject() allein nach subproject_id filtern. Analog zum Schutz aus Issue #97 prüfen jetzt AccessService::assertTaskBelongsToProject() und assertSubprojectBelongsToProject() die Zugehörigkeit; deleteTasksForSubproject() und buildIcs() filtern die geladenen Aufgaben zusätzlich defensiv nach project_id, um vor dem Fix entstandene Altdaten abzudecken

Changed

  • Dokumentation aufgeräumt: Die Doku ist jetzt nach Zielgruppe getrennt — alles, was Nutzerinnen und Nutzer brauchen, liegt in nc_gantt/ und wird damit vom release.sh-Archiv mit ausgeliefert, das Repository-Root enthält nur noch Entwickler-Doku. Dafür sind FEATURES.md, INSTALL.md und die neue HOWTO.md nach nc_gantt/ gewandert; die Root-README.md beschreibt die zehn wichtigsten Anwendungsfälle des Werkzeugs, erklärt je Fall den gedachten Arbeitsweg und führt in einer Repository-Übersicht auf, welches Dokument für wen gedacht ist. Neu ist nc_gantt/HOWTO.md: eine Schritt-für-Schritt-Anleitung entlang eines durchgerechneten Beispielprojekts, die alle zehn Anwendungsfälle mit konkreten Feldwerten, Abhängigkeiten und Terminen durchspielt
  • Dabei korrigierte Verweise und Angaben: der Lizenz-Link in nc_gantt/README.md zeigte auf das nicht vorhandene LICENSES/AGPL-3.0-or-later.txt statt auf LICENSE.md; die Nextcloud-Anforderung stand mit „28–33" in README.md und „28–34" in FEATURES.md gegen die tatsächlichen 31–34 aus appinfo/info.xml; FEATURES.md nannte noch Version 1.5.0; INSTALL.md verwies auf ein dist/nc_gantt-<version>.zip im Repository, das es nicht gibt (dist/ ist nicht versioniert und release.sh baut .tar.gz), und in CONTRIBUTE.md trug ein Link auf RELEASE.md die Beschriftung release.sh. Alle relativen Links und Abschnitts-Anker der versionierten Markdown-Dateien lösen jetzt auf
  • Tests laufen künftig vor jedem Commit (Issue #185): setup-dev.sh installiert einen pre-commit-Hook, der Vitest und PHPUnit (über Docker) ausführt und den Commit bei Fehlern abbricht — genau die Stelle, an der die vier defekten Tests aus dem Ressourcen-Sichtbarkeits-Commit hängen geblieben wären. phpunit.xml schaltet zusätzlich failOnRisky und failOnWarning ein, damit ein Test ohne Assertion den Lauf rot färbt statt unauffällig grün zu bleiben, und CONTRIBUTE.md dokumentiert die Regel zu Mock-Defaults ohne with() in setUp()
  • Die Default-Stubs in setUp() von ResourceVisibilityServiceTest blockierten die spezifischeren Stubs der einzelnen Testmethoden — PHPUnit wertet für dieselbe Methode den zuerst registrierten Matcher aus, und der greift per any() bei jedem Aufruf. findByResourceId(), findByIds() und findByResourceIdExcluding() lieferten dadurch immer ein leeres Array, was vier Failures und zwei risky Tests verursachte. Die Defaults sind entbehrlich, weil PHPUnit-Mocks für den Rückgabetyp array ohnehin ein leeres Array liefern; der Produktivcode blieb unverändert
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturerHm/UxN1WTCOMd9LklleINo7LKDOEAyn1zlsR5eTCaUmdGaN1m8Knqk/EKDYcj73
zWx7TXmT4cP91Ag7mCMwY/gRqJabF7TgeXiA7CeV7VE7/D/+apIatMWRT7zYCjkF
oxXKimNrtpDSKWNXKSQn6RfJaEHu5WnIoF4X9Nyx/wf1WoWoThyvWMSSW/3jdajV
WXCV4XQjzbTULw9T+Ini/e8vp6mXt5CrmCdyUDQQcj2t9PF9Hq3GvWT1VQlYA8Kf
IJuqnArSc4JdtJiJnozpOKSBkAbDPTrFytwUTVUO4XlrGIvyqHv14ZVmBM8UCMo6
yVNA9HEBW62/b8W+Z3BtCBTuBnkRk3Wka8qhMMbqOe8kl/1vQtTKQkaDdnXaShUs
18mfDHjLZhcIrJEwbtPvo9Xpf+IWEZeoiRzEqa30n70iZTkPEVv/GxNVmJ74XYH/
Xa/vMWI/sxtXKtKY60XBXXCEVMuyxR+vfIbJOpDCcFlKyWHiXPEdYh2Ac8Bs1hc7
bk+lolw8FEWISrFdUwYdOrfRr4CMW+h2CYzgZsDKKYrVn+hRUy5mVOL1QXZJbNJJ
wr9O/JrUbXAMGdhtLuRUwM4tsPgMF2+cTLMe+wuFzUjWBBNiqb8GKJP2K94hdurD
+VMd/p/TtU02M23ooysu2mft5RCmD0/QbP8yxEACbHg=
Signature digestsha512
Dependencies
Required Nextcloud versions >=31.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.6.0
Release Details
UpdatedAug. 28, 2026, 2:34 p.m.
Changelog

Achtung: Diese Version setzt Nextcloud 31 oder neuer voraus. Die bisherige Untergrenze war Nextcloud 28. Mit dem Umstieg auf @nextcloud/vue 9 — unvermeidbar, weil Vue 2 seit dem 31.12.2023 End-of-Life ist und keine Sicherheitskorrekturen mehr bekommt — fällt die Unterstützung für Nextcloud 28, 29 und 30 weg. Installationen auf diesen Versionen bekommen das Update nicht angeboten und bleiben auf 1.5.4; sie werden von dort nicht weiter gepflegt. Wer die App weiter nutzen möchte, aktualisiert zuerst den Nextcloud-Server auf mindestens Version 31 (max-version bleibt unverändert 34).

Changed

  • Das Frontend läuft auf Vue 3.5 statt Vue 2.7 (Issue #150). Vue 2 ist seit dem 31.12.2023 End-of-Life und bekommt weder Sicherheits- noch Fehlerkorrekturen; die Nextcloud-Server-Generation, gegen die die App freigegeben ist, hat ihren Frontend-Stack längst auf Vue 3 umgestellt. Mit umgestellt sind @nextcloud/vue 8 → 9, @nextcloud/dialogs 6 → 7, Pinia 2 → 3 und @nextcloud/webpack-vue-config 5 → 7; die dreizehn Build-Pakete, die das Webpack-Preset ab Version 7 als peerDependencies erwartet (webpack, vue-loader, sass, babel-loader …), stehen jetzt explizit in den devDependencies. npm audit --omit=dev meldet damit 0 statt 14 Befunde — die vier an Vue 2 hängenden Advisories (vue, vue-template-compiler, vue-resize, vue2-datepicker) waren ohne diese Migration nicht auflösbar
  • appinfo/info.xml fordert jetzt Nextcloud 31 statt 28 (max-version bleibt 34). @nextcloud/vue 9 lässt die Unterstützung für Nextcloud vor 31 fallen; das ist die unvermeidbare Gegenleistung der Migration. Installationen auf Nextcloud 28–30 bleiben auf Version 1.5.4
  • Die drei Einstiegspunkte src/main.js, src/admin.js und src/dashboard.js erzeugen ihre Anwendung über createApp() statt new Vue(); Pinia wird als Plugin registriert (app.use(pinia)), das Weiterreichen der Store-Instanz an das Vanilla-Detailmodal per setActivePinia() bleibt unverändert. Die Vue.prototype-Zuweisungen im Dashboard-Einstiegspunkt sind entfallen — DashboardWidget.vue importiert t ohnehin selbst
  • Anpassungen in den 17 Komponenten an die API von @nextcloud/vue 9: Import-Pfade (@nextcloud/vue/components/NcButton statt @nextcloud/vue/dist/Components/NcButton.js), type="primary"variant="primary" bei NcButton/NcActions, NcActionCheckbox und NcSelect auf modelValue (:checked/@update:checked bzw. :value/@input sind entfallen), :shown.syncv-model:shown bei NcPopover. Dazu die Vue-3-Umstellungen im eigenen Code: beforeDestroy()beforeUnmount() in GanttTable.vue, ResourceGrid.vue und GanttChart.vue (siehe Issue #149), this.$set()/this.$delete() durch direkte Zuweisung bzw. splice() ersetzt
  • css/main.css und der zugehörige Util::addStyle()-Aufruf im PageController sind entfallen. Die Datei enthielt einzig #content { margin-top: 0 !important } gegen eine Doppelmarge, die NcContent unter @nextcloud/vue 8 zusätzlich zum Nextcloud-Layout gesetzt hat. Unter Version 9 gibt es diese Marge nicht mehr, der Reset schob die App stattdessen um die Höhe der Kopfzeile nach oben — die Navigationsleiste lag dadurch unter dem Nextcloud-Header und war nicht mehr anklickbar. Der Mount-Punkt #nc-gantt-app bleibt als Wrapper im DOM stehen (Vue 3 rendert in das Element hinein, statt es wie Vue 2 zu ersetzen), nimmt aber nachgemessen exakt die Maße des Content-Bereichs an und braucht keine eigene Regel
  • ESLint nutzt das Preset @nextcloud/eslint-config/vue3. Es lässt vue/custom-event-name-casing auf dem Vue-3-Default (camelCase) laufen, während das Vue-2-Preset kebab-case erzwungen hat; da der Bestand durchgängig kebab-case verwendet — unter Vue 3 gleichermaßen gültig — setzt .eslintrc.js die Regel explizit auf kebab-case
  • Der <style>-Block in GanttChart.vue war mit 581 Zeilen ungescopt und wirkte damit auf die gesamte Nextcloud-Oberfläche statt nur auf die Komponente (Issue #151). Die 65 eigenen .nc-gantt-*/.nc-*-Regeln laufen jetzt über <style scoped>, mit :deep() dort, wo Overlays ihre Elemente per createElementNS() bzw. innerHTML außerhalb des Vue-Templates in .nc-gantt-container einhängen. Die Regeln, die auf frappe-gantt-eigene Klassennamen zugreifen (.gantt .bar & Co.), liegen gebündelt in src/vendor/frappe-gantt/theme.css direkt neben dem vendorten Quellcode der Bibliothek und werden von dort per index.js importiert; die beiden nicht unter .gantt verankerten Selektoren (.bar-wrapper.gantt-milestone .bar-label/.handle) sind dabei korrigiert. In App.vue laufen die drei Core-Überschreibungen (.app-navigation__content, #app-settings, .app-navigation .app-navigation-list) ebenfalls über :deep() in einem scoped Block. Abgesichert ist das durch vue/enforce-style-attribute aus eslint-plugin-vue, das ab sofort scoped für jeden <style>-Block in src/ erzwingt
  • TaskService bündelte auf 774 Zeilen drei Verantwortlichkeiten und brauchte dafür acht Konstruktor-Abhängigkeiten; der Schnitt trennt sie (Issue #153). TaskSchedulingService übernimmt Constraint-Propagation über EA/AA/EE/AE mit Lag, Kahn-Sortierung, Arbeitstagsrechnung, Zyklenprüfung und What-if-Simulation — CriticalPathService wird dort regulär injiziert, statt simulate() als Methodenparameter durchgereicht zu werden. TaskResourceAssignmentService übernimmt Auflösung und Persistierung der Ressourcenzuordnung inklusive MAX_TASK_RESOURCES und PT-Umrechnung. TaskService bleibt als CRUD-Fassade mit Berechtigungsprüfung, Validierung, Änderungsprotokoll und API-Aufbereitung: 311 statt 774 Zeilen, sieben statt acht Abhängigkeiten. Die Methodenrümpfe sind unverändert verschoben, es ändert sich keine Terminlogik. TaskServiceTest ist entlang derselben Grenzen aufgeteilt (TaskServiceTestCase als gemeinsame Basis, dazu TaskSchedulingServiceTest mit 39, TaskResourceAssignmentServiceTest mit 8 und TaskServiceTest mit 11 Fällen — exakt der bisherige Umfang), wobei die ausgelagerten Services weiterhin über ihren Aufrufer TaskService angetrieben werden, damit neben der Rechnung auch die Verdrahtung zwischen Fassade und Engine abgedeckt bleibt
  • Die 212 Zeilen CSS der Vanilla-Detaildialoge wurden zur Laufzeit als <style> in den <head> injiziert (src/detail/styles.js); sie liegen jetzt als src/detail/detail.css vor und werden von Webpack eingebunden (Issue #152). Der im Kopfkommentar genannte Grund — nicht von der Loader-Konfiguration abhängen zu wollen — trifft seit dem Vendoring nicht mehr zu, src/vendor/ importiert .css und .scss ebenfalls direkt. Dabei fiel auf, dass das Stylelint-Glob unquoted an die Shell ging und ohne globstar nur eine Verzeichnisebene traf: weder src/App.vue noch eine .css in src/vendor/ wurde je geprüft. Mit Quotes globbt Stylelint selbst; die dadurch aufgedeckten Findings in App.vue sind mitbehoben
  • Die PHP-Einrückung ist auf Tabs vereinheitlicht (Issue #170). nextcloud/coding-standard erwartet Tabs, die Codebasis nutzte durchgehend vier Leerzeichen — composer cs:check beanstandete dadurch 144 von 146 Dateien, der CI-Job wäre ab dem ersten Lauf dauerhaft rot und als Gate wertlos gewesen. Ursache der Drift war ein falscher Kommentar in .editorconfig, der dem Coding-Standard vier Leerzeichen unterstellte; der ist mitkorrigiert. Die Änderung ist rein mechanisch (php-cs-fixer fix): Einrückung, Klammern um einzeilige if-Rümpfe, sortierte use-Blöcke und einfache statt doppelte Anführungszeichen, wo keine Escape-Sequenz im Spiel ist. Der Commit steht in .git-blame-ignore-revs, damit git blame weiterhin die inhaltlich letzte Änderung einer Zeile zeigt

Added

  • appinfo/info.xml wird jetzt automatisch gegen das App-Store-Schema geprüft, statt den Fehler erst beim Upload zu erfahren: scripts/validate-appinfo.js (npm-Script validate:appinfo) validiert gegen die eingecheckte Schema-Kopie tests/fixtures/info.xsd — per xmllint, ersatzweise über lokales php oder das composer:2-Image — und prüft zusätzlich Semver-Format, Gleichstand mit package.json und den CHANGELOG-Abschnitt zur Version. release.sh ruft das als erstes Gate mit --online auf, lädt das Schema dabei frisch und meldet, wenn die Kopie veraltet ist
  • tests/Unit/AppInfoXmlTest.php führt dieselbe Schema-Validierung in der Testsuite aus (DOMDocument::schemaValidate()) und gleicht zusätzlich die Übersetzungen in l10n/ gegen die Store-Texte ab: gettext-Codes wie pt_BR werden als solche erkannt, und zu jeder übersetzten Sprache müssen <name>, <summary> und <description> in info.xml existieren
  • Die Stunden je Personentag sind konfigurierbar (Issue #169). Der Umrechnungsfaktor lag dreifach hartkodiert vor (TaskResourceAssignmentService, ResourceUtilizationService, ResourceGrid.vue) und wurde über gegenseitige Kommentarverweise von Hand konsistent gehalten — eine feste 8-Stunden-Annahme passt aber nicht zu jedem Arbeitszeitmodell. Der Wert liegt jetzt an genau einer Stelle: WorkTimeService liest ihn als App-Config-Wert hours_per_pt (Standard 8), validiert ihn gegen 1..24 und fällt bei unplausibel gespeicherten Werten auf den Standard zurück, damit die Auslastungsrechnung nicht durch 0 teilt; in ResourceUtilizationService entfällt damit auch die Konstante DEFAULT_CAPACITY_H, die denselben Vollzeit-Referenzwert doppelt hielt. Ins Frontend kommt der Faktor über den Initial State des PageController, sodass er schon beim ersten Rendern des Ressourcen-Rasters bereitsteht; GET/PUT /settings liefern und setzen ihn zusätzlich, wobei ein PUT ohne hours_per_pt den gespeicherten Wert unverändert lässt, damit ältere Clients ihn nicht auf den Standard zurücksetzen. Gepflegt wird er im Admin-Bereich neben Arbeitsbeginn und -ende
  • Die Vanilla-Detaildialoge sind für Screenreader und Tastatur verdrahtet (Issue #152): Die Dialoge verweisen über aria-labelledby auf ihre Überschrift, section() verknüpft Beschriftung und Bedienelement (bei Gruppen über role="group"), Knöpfe ohne Text bekommen einen Namen, Umschaltknöpfe melden ihren Zustand über aria-pressed, und die Datums-Plausibilitätsmeldung hängt per aria-describedby am Feld statt nur im title-Attribut des Icons zu stehen. Der Fokus beginnt beim Öffnen im Formular statt auf dem Schließen-Knopf und kehrt beim Schließen zum Auslöser zurück. Abgesichert durch payload.test.js (19 Fälle für Speicher- und Löschlogik) und accessibility.spec.js (6 E2E-Fälle) — für DOM-Code ist der E2E-Lauf die tragfähigere Absicherung als eine neue jsdom-Abhängigkeit. src/detail/README.md erklärt, warum das Modul außerhalb von Vue steht und welche Regeln daraus folgen; CONTRIBUTE.md verweist darauf
  • Die CI läuft. Der Workflow lag unter nc_gantt/.gitea/workflows/ci.yml und war eine reine GitHub-Actions-Datei; vier voneinander unabhängige Gründe verhinderten, dass davon jemals etwas ausgeführt wurde (Issue #170): Forgejo liest Workflows ausschließlich im Repo-Root, runs-on: ubuntu-latest passt auf kein Codeberg-Label (die gehosteten Runner heißen codeberg-tiny/-small/-medium), die Kurzform shivammathur/setup-php@v2 wird gegen Forgejos Action-Host aufgelöst, wo es die Action nicht gibt, und die Repo-Einheit „Actions" war deaktiviert. Die Datei liegt jetzt unter .forgejo/workflows/ci.yml, die App bleibt via defaults.run.working-directory erreichbar. Inhaltlich sind php-lint und php-tests zu einem Job zusammengefasst und laufen beide über die volle Matrix 8.1/8.2/8.3 (vorher lief PHPUnit nur auf 8.2, obwohl composer.json >=8.1 fordert), die Syntaxprüfung nutzt xargs statt find -exec (find liefert seinen eigenen Exitcode, nicht den von php -l — der Schritt konnte gar nicht fehlschlagen), und der JS-Job führt neu vitest mit 180 bislang nie automatisiert gelaufenen Tests aus, dazu validate:appinfo und l10n:check. paths-ignore hält die geteilten Codeberg-Runner von reinen Doku- und Screenshot-Änderungen frei

Fixed

  • Nach der Migration auf @nextcloud/dialogs 7 erschienen Statusmeldungen wie „Einstellungen gespeichert" als unformatierter Text oben links statt als Badge. Version 7 hat Toastify durch eigene Vue-Komponenten ersetzt, deren Styles nicht mehr im JS-Bundle stecken, sondern über den separaten Export @nextcloud/dialogs/style.css eingebunden werden müssen; ohne diesen Import lief der Toast-Container ungestylt im normalen Dokumentfluss mit. src/main.js importiert das Stylesheet jetzt. Die Toasts erscheinen dabei an der neuen Standardposition der Bibliothek unten links neben der Navigation statt wie früher oben zentriert — Version 7 bietet dafür keine Option mehr
  • testBuildIcsStripsCarriageReturnToPreventLineInjection prüfte das gesamte ICS-Dokument auf Freiheit von \r. RFC 5545 trennt Zeilen aber genau damit, und buildIcs() setzt sie korrekt als CRLF — der Test konnte nie grün sein und schlug auf main dauerhaft fehl. Der Schutz selbst greift; nur die Assertion war zu weit gefasst. Geprüft wird jetzt, was die Line-Injection tatsächlich ausschließt: kein einzelnes CR außerhalb der CRLF-Zeilentrenner, der eingeschleuste Titel erzeugt keine eigene ICS-Zeile, und er landet escaped im SUMMARY-Wert. Gegenprobe mit entfernter CR-Normalisierung in escapeText() schlägt weiterhin fehl, der Schutz bleibt also scharf getestet. Dass der Fehlschlag so lange unbemerkt blieb, lag daran, dass die Workflows nicht ausgeführt wurden (siehe Issue #170)
  • validate:appinfo brach im ersten CI-Lauf mit einer Meldung über einen nicht erreichbaren Docker-Socket ab (Issue #170). Die Validator-Kette in scripts/validate-appinfo.js probiert xmllint, dann php, dann docker und nimmt den erstbesten verfügbaren — „verfügbar" hieß dabei aber nur, dass das Binary existiert. Das Runner-Image bringt die docker-CLI mit, ohne dass ein Daemon erreichbar wäre, und hat weder xmllint noch php. isAvailable prüft jetzt, ob der Validator wirklich läuft (docker info statt --version), sodass die Kette korrekt durchfällt und bei gänzlich untauglicher Umgebung „Kein Schema-Validator gefunden" meldet statt eines Socket-Fehlers; zusätzlich installiert der JS-Job libxml2-utils, damit im CI immer xmllint gewinnt — der native XSD-Validator, ohne Daemon und ohne Netzwerk. Welcher Validator läuft, hing zuvor davon ab, was auf der Maschine zufällig installiert war
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturegDK8JkRgxBUCFljhxHFzTzf37tjhwQ/k9E+DCDeVHxPECDOF0J3FbWmv2uqmm9R7
H8yyFfL/KFEDK3Jt24o2gujQZ9KlyBYJvrfwv//zvACtgGoErBUamME+FzFfK3x8
rRdXt1iXctmwutRvTNPj8uvfMJmo/vdbJRDGEihI/9wVdt4S+O3/OlpdjUg+QGFP
cMmlQwIAHAWrYSUllnN4GeryrFPGB7fLi/Nrhx0eAwQHUjIZHEb/s9ZxjmnYZd0c
8FJsgAUXfjowOIrDtWxr0P+HVj4c5qhGx4XEUFdfR0slriaL+zPbo2Li1wgsBA7r
+yoo8ocOJPaN3iCpRNL4z8q2sxEuWRt2Dx0I5ck6F7g+gpzDoTo5bFEvq4Eir0wN
lGHhyxcdEK653dTKOBYI07tCjJYU+9VxCbRzR7O+sVI412Tox5W5cYGl4WpN8aNH
00CX7PLaruaEjwuFdAvhY6SzsXA3RFmN3Dv9qFx3dl3HjoQ+OCqy89XzT3tbBN07
3aZO7OgyB26al2XdRFaaRQaVLqjJzUCz2B5nh+z9+L+QcBl3F9sE2sFZnkWwx3bp
MOdj2nCS11r3Z0utRI9uDEanys6HkqnpGed4WEGX9O+EfocqNg2b0wgyqjFNWbxI
n4uoeakhyWYOVHCUfzU8tn6kmU4b8n+GfpMjKPhBeRw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=31.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.4
Release Details
UpdatedAug. 27, 2026, 7:06 p.m.
Changelog

Fixed

  • appinfo/info.xml wurde vom Nextcloud App Store abgelehnt: der Sprachcode pt_BR in <name>, <summary> und <description> ist im Schema nicht enthalten — die Enumeration kennt nur BCP-47-Schreibweise in Kleinbuchstaben mit Bindestrich. Alle drei Vorkommen heißen jetzt pt-br
  • Die Kindelemente von <info> sind im Schema eine feste Sequenz; <settings> stand vor <dependencies> und wäre nach dem Sprachcode-Fix als nächster Validierungsfehler aufgeschlagen. Der Block steht jetzt an der vom Schema vorgesehenen Position hinter <dependencies>. xmllint --schema gegen https://apps.nextcloud.com/schema/apps/info.xsd läuft damit sauber durch
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureYbjiEkGYW1s8Xg9Jvrt4nNo/67zkrQDA16yfK2MzVa58R982qrLUupNbvUE/FscP
pFg9nlqxd81cpyH1ZhWOM7fMq98mPyjSUsJZ7xjYzNccF13xvDpBXFlfX4UyCknc
50Rmw9a8RxiCH0mEpH9zWjdanX194R8cUIMDY+BcymCgyBVRQub9yaL5iiHH3hNA
OOD+UOiSUNHns9R6sgZ+tF4OeoTufWR5//AfRmuL5qC5spyuP1iKr7FnzPar+/sS
pHKojfUyi0sAjlrThVZDo8fvVPqkkH4jgvVmNE41t1UOlVdajIRd2yhbHX0h0SSs
rmt4CQqNXAjLE/Wlq2lu9Viw4M2BhhPIfVb5YJFzaxjhB8RRy53rquXRL64f7vGa
agq0ri3eD+0ZWmMOlJmHaMv6AXYd0ZG8myb3PAyNC0NYXzrw2PAVL8jDfzmq2cNY
Q3rIh101vtGPytqanNS2VmtfZ8BX63rd4SLR4PJdRYrm3Wbqanx8WZa20eLgYF8S
M9xhxl5Jf8+TnYLwHi1sGm1ID2XJ4krfgOxiUlB8lGeSweUK1uueC0bmUDsrXyhJ
RMGST41TU1HqXx/3Eeh91JKq/Jbx15kPuxu7WNKyuSOj4vKbgFwBUSmHKDU6lvEZ
L/bnxZi965/4K3kvyJ8o2j5e4xUmJLeusi9Fg0yrRqE=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.2
Release Details
UpdatedAug. 26, 2026, 5:18 p.m.
Changelog

Changed

  • Teilen-Dialog: das Eingabefeld für den einzuladenden Nutzer ist jetzt ein Suchfeld statt eines reinen Textfelds für die Benutzer-ID (Issue #144). Getippt wird nach Anzeigename, Benutzer-ID oder E-Mail-Adresse; ein neuer, admin-unabhängiger Endpunkt GET /api/v1/users/search (UserController::search(), IUserManager::search(), max. 20 Treffer, der eigene Account wird ausgeblendet) liefert dazu Anzeigename, Benutzer-ID und E-Mail als Vorschlagsliste. Gespeichert wird weiterhin die Benutzer-ID als principal_id – für Umgebungen mit LDAP/AD-Benutzerverwaltung war die zufällig generierte ID zuvor nicht ohne Umweg über die Benutzerverwaltung in Erfahrung zu bringen. Die Liste bereits geteilter Zugriffe zeigt ebenfalls den Anzeigenamen statt der rohen ID (ShareController::index() reichert die Antwort um display_name an, Fallback auf principal_id falls der Account inzwischen gelöscht wurde)
  • Übersetzungen für alle sechs Sprachen ergänzt
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureyLn/jlYbk3gIYfgIcjON0z467/xL9L6QNcmfgOa/4zhTJjLknXq7eu1UJddWWlLJ
NG2U9d/OEFO9wLHPYPGNiWgQMRIk+TGYlQVTXcZH3WpBxdJOm3XMnk5hq2kNB2FN
TJemqr/dxafGB2hTIgivPMXMnemdrtxWN1RAdzCxZIg9HwJWjG5JxdqHmURHwske
p/Ki/iZghKjrxbPIghbqtrvkCJRImbgVWY8AmUNUPLgotNIthiWFnkTDVhYWcreP
pWleWHxEn57UOtehff1aJa+hRI+8WVkx9iXArx0SThmOCYYgJ/HeG8dOOtmr9jSm
1nzETAL87YLxL/+qM6DyBIgNWhrq1oj9Q12bBm1+la477z6fpOgUlMjWkPEYRQi/
vhxirXwB4BZBYvaMEkNlN2U3+7BqgigGoaTcbN2rG/TP1JuOjdj9jEjMMRye0JbT
35XOoM/VPYGovrT9slHg8r3Wolyd8ioXVOu4IcMImvC5OrTzpKY7NLEc/S+cOKwz
ijOKcnoV0j++KxtQKKgEO96HJpEM0jteQVOGCoPbghjS3OFzkiB1bUVJAlu1jn54
38Q2zw8rZ0EMm1rEPmIrl72DIIXionbWKatREgy7QPwuL/WKZ2c+J1UIUTKck5eO
7M2VHh6P3FnIg/UsOCMu3U7ja0Y8vQ3YUo3tazLfob0=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.1
Release Details
UpdatedAug. 25, 2026, 1:28 p.m.
Changelog

Added

  • Screenshot des gerenderten Gantt-Charts als PNG, SVG oder PDF (Issue #116): ein neuer „Screenshot"-Eintrag in der Chart-Toolbar öffnet ein Menü mit den drei Formaten, derselbe Export steht im Bearbeiten-Dialog des Projekts neben JSON und CSV bereit (dort mit vorgeschalteter Formatwahl statt Menü, openScreenshotFormatDialog()). Exportiert wird stets das gesamte Chart, nicht nur der sichtbare Scroll-Ausschnitt — frappe-gantt rendert die volle Breite und Höhe ohnehin als eine SVG. PNG und SVG klonen die aktuell gerenderte SVG und schreiben getComputedStyle() als Inline-Attribute (löst auch CSS-Variablen auf), sodass die Datei ohne das App-Stylesheet eigenständig darstellbar ist; sie folgen dem eingestellten UI-Theme, ein hinterlegtes Rechteck in --color-main-background deckt dabei auch die Fläche unterhalb der Aufgabenzeilen (Workload-Chart, Leerraum) ab, die sonst transparent bliebe. PNG rastert per Canvas mit doppelter Auflösung
  • Zeitraum-Auswahl für den PDF-/Druck-Export (Issue #116): vor dem Drucken fragt ein Dialog, welchen Zeitraum die PDF abdecken soll — gesamter Projektzeitraum (Vorbelegung), laufendes Kalenderjahr, „aktives Quartal" (Vormonat bis einschließlich übernächstem Monat) oder ein frei eingegebener Bereich. Der Vorschlag ist der tatsächlich von Balken belegte Zeitraum, nicht gantt_start/gantt_end — frappe-gantt legt darum großzügig Puffer, der andernfalls mitgedruckt würde. Umgesetzt wird der Zuschnitt als viewBox auf dem SVG-Klon; die dafür nötige Skala (Chart-Start, Pixel pro Millisekunde) schreibt GanttChart.vue nach jedem Render als data-Attribute an den Chart-Container, sodass auch Aufrufer ohne Zugriff auf die frappe-Instanz (Bearbeiten-Dialog) sie lesen können. Die Zeitraum-Logik steckt isoliert testbar in src/gantt/printRange.js (src/gantt/printRange.test.js)

Changed

  • Der PDF-Export druckt nicht mehr den Live-Container, sondern einen gestylten, selbst gerasterten Klon des Charts (Issue #116). Bisher wurde das Inline-SVG direkt gedruckt — wie fein die Browser-Engine das rastert, ist nicht steuerbar und fiel je nach Browser sichtbar grob aus. Jetzt wird der Klon mit 300 dpi bezogen auf die bedruckbare Fläche (A4 quer, 10 mm Rand → 277 × 190 mm) in ein Canvas gerastert und als Bild mit fest vorgegebener physischer Größe in den Druck gegeben; schlägt die Rasterung fehl, bleibt der SVG-Klon als Druckinhalt übrig und skaliert per CSS auf die Seitenbreite. Der Klon wird immer im hellen Theme berechnet (Papier ist weiß, ein dunkles UI-Theme ergäbe sonst dunkelgraue Flächen und helle Schrift) — dafür genügt ein ausgelagerter Container mit gesetztem data-theme-light, da Nextcloud die Stylesheets aller Theme-Varianten lädt und nur über dieses Attribut umschaltet. Das Ausblenden der übrigen Seite läuft über display: none statt visibility: hidden, sonst blieb die Fläche der App als Leerseiten erhalten; Nextclouds Hintergrundbild auf html/body wird für den Druck abgeschaltet. Aufgeräumt wird über afterprint mit Timeout-Fallback für Browser, die das Event nicht feuern
  • Der Toolbar-Eintrag heißt „Screenshot" (Icon MonitorScreenshot) statt „Export" (Icon ExportVariant) — „Export" ist im Projekt bereits für den Daten-Export nach JSON/CSV belegt, der Chart-Export ist demgegenüber eine reine Abbildung der aktuellen Darstellung
  • Übersetzungen für alle sechs Sprachen ergänzt
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
Signaturek6kpvF53IR8tnkOFXyoSPFPGlwVzO/RUTgI1p1ppRcFmoFPUyFeIokOqWA1OtD9q
wdo+qkQQPyJGph0Uwp+hwP9oGmeKWErnlv8HMdA5I5iaXIN7afGvdfxWfKgqWetw
tGmCF7l2IzMmT2Ol/3pKgCnFkXTDPCVeNINNbUdi7EjeRpbcbOGWt3+5UVwZgVTX
Z9/kEEPvjMV98s1zT5yBXcFvyqZA7bhhezmBkfzaLa0DAIczFJbhyFtR06WuS7bP
CWBCs/xvSRuCwo61oyXRAWLohz/2GsrMSa5jvPvnEG1XEHpGPVorCijAvsBm4sX5
yAZTrBm3zbNYObqVE2idxTH/eqP8xXtE38JFjpG5IahpeFNb9V2EbH1nrjfRKYcH
NVvXcXFREAmvorShKDE0ymFN+/BCjvU1vnJCnRD5RMsoSGUzXSVHPrF1emtusLHj
ltP22eYOCpraEpZheTkFftqvpbiQKVXsZ+8wY4dJnh5Ymi71loxZhggoH8s/pmp+
WbSx6MZwSPBqJ0HOJWckFiZXur2OQYOVLfXt8uPYNU/EZSoYDqm81GVMglQXxyM6
YDh0xXqwJ7Qft7k0O/3Fa5YLJGP4B4RvjU29N3/WDsfjuk7PeCSTPhRlTOfV/Fbn
jS83WVBavmyklhu0rNYuCYfdYvUxemIO3VuGmYzFXgI=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.0
Release Details
UpdatedAug. 24, 2026, 5:26 p.m.
Changelog

Added

  • Editierbare Vorgänger-Spalte in der Tabellenansicht, Teilschritt F von #117 (Issue #124): eine neue, über das Spaltenmenü einblendbare Spalte „Vorgänger“ zeigt die Abhängigkeiten einer Aufgabe in der aus MS Project bekannten Kurznotation (12EA+2d = Vorgänger Aufgabe 12, Ende-Anfang, zwei Arbeitstage Abstand; mehrere durch ; getrennt) und nimmt sie dort auch entgegen. Typ (EA/AA/EE/AE, englische Kürzel FS/SS/FF/SF werden beim Eingeben mit akzeptiert) und Abstand sind optional, 12 allein bedeutet also EA ohne Abstand. Geprüft wird beim Verlassen der Zelle: Syntax, Existenz der Aufgabe im selben Projekt, Selbstbezug, Dubletten und Kreisschluss über die gesamte Abhängigkeitskette – bei einem Fehler bleibt die Zelle im Bearbeitungsmodus und nennt den Grund im Klartext, die bisherigen Abhängigkeiten bleiben unangetastet. Gespeichert wird über dieselbe PUT /tasks/{id}-Route wie der Detail-Dialog (inkl. dep_mode), sodass der Server die Termine anwendet und durch die Nachfolgerkette propagiert; Balken, Pfeile und Typ-Labels im Chart zeichnen sich mit der Antwort neu. Bewusst ohne Undo-Toast, da ein Zurücknehmen nur der Termine (nicht der Abhängigkeit) beim nächsten Neuberechnen wieder überschrieben würde. Nur Aufgaben haben eine editierbare Zelle – Meilensteine hängen über task_id an genau einer Aufgabe, Projekte und Teilprojekte sind berechnete Strukturebenen. Notation und Prüfungen stecken isoliert testbar in src/gantt/dependencyNotation.js (src/gantt/dependencyNotation.test.js)
  • Zeitabstand (Lag/Lead) je Aufgaben-Abhängigkeit (Issue #124): neue Spalte lag_days in nc_gantt_task_deps (Version1032; der Name vermeidet das seit MySQL 8.0 reservierte Wort LAG und nennt die Einheit). Der Abstand zählt in Arbeitstagen über den Ressourcenkalender wie die übrige Terminberechnung, wirkt bei allen vier Abhängigkeitstypen auf deren Ankertag und darf negativ sein (Lead: der Nachfolger beginnt früher). Bestandsabhängigkeiten bekommen 0 und verhalten sich unverändert. TaskService::update() weist eine gesendete Vorgängerliste jetzt vollständig zurück (invalid_dependency, dependency_cycle), bevor die bisherigen Abhängigkeiten dafür gelöscht werden, statt Vorgänger aus fremden Projekten oder Zyklen zu speichern – letztere hätten die topologische Sortierung in recalculateProject() stillschweigend Aufgaben überspringen lassen

  • Konfigurierbare Spalten in der Tabellenansicht, Teilschritt E von #117 (Issue #122): ein Menü in der Tabellenkopfzeile blendet Spalten ein und aus, die Reihenfolge lässt sich per Drag & Drop der Kopfzellen ändern (barrierefreie Alternative: Strg+Pfeil links/rechts auf der fokussierten Kopfzelle), die Breiten per Ziehen am Spaltentrenner (Doppelklick setzt auf die Standardbreite zurück). Zusätzlich zu den bisherigen Spalten (Titel, Start, Ende, Fortschritt) stehen ID, Dauer (Kalendertage inkl. Start- und Endtag, bei Meilensteinen 0), Status (Issue #78, nur Aufgaben/Teilprojekte) und Ressource (Issue #103, zugeordnete Ressourcennamen einer Aufgabe) bereit – alle vier als reine Anzeigespalten, die das Inline-Editing und die Tastaturnavigation daher überspringen. Auswahl, Reihenfolge und Breiten werden pro Nutzer über den in Teilschritt B angelegten UI-Preferences-Endpunkt persistiert (neuer Key gantt_table_columns, kein Schema- oder Endpunktwechsel nötig); eine gespeicherte Konfiguration wird beim Laden validiert, sodass entfernte Spalten oder unplausible Breiten die Ansicht nicht beschädigen können. Die Tastaturnavigation folgt jetzt der sichtbaren Spaltenreihenfolge statt einer festen Liste. Reicht die Tabellenbreite für die gewählten Spalten nicht aus, scrollen Kopfzeile und Zeilen gemeinsam horizontal; die Obergrenze des Splitters steigt dafür von 560 auf 900 px. Die Spaltenlogik steckt isoliert testbar in src/gantt/tableColumns.js (src/gantt/tableColumns.test.js). Ein Sortieren der Zeilen nach Spaltenwert ist bewusst nicht enthalten – es kollidiert mit der Hierarchie Projekt → Teilprojekt → Aufgabe und der sort_order, die das Chart für dieselbe Zeilenreihenfolge braucht

  • Tastatur-Navigation in der Tabellenansicht, Teilschritt D von #117 (Issue #121): Tab/Shift+Tab springen zur nächsten bzw. vorigen editierbaren Zelle (überspringt Zeilen ohne Schreibrecht, springt am Zeilenende zur nächsten/vorigen Zeile), Enter speichert und springt in dieselbe Spalte der nächsten Zeile, Esc bricht ab und stellt den vorigen Wert wieder her. Pfeiltasten bewegen die Zellauswahl, wenn gerade keine Zelle im Editiermodus ist (innerhalb einer Zelle bleiben sie für Cursor-/Wertänderung nutzbar). Die reine Traversierungslogik steckt isoliert testbar in src/gantt/tableNav.js (src/gantt/tableNav.test.js). Die ausgewählte Zelle bekommt einen sichtbaren Fokusrahmen und wird per scrollIntoView() ins Sichtfeld gescrollt – über den bestehenden bidirektionalen Scroll-Sync (Issue #119) folgt das Gantt-Chart automatisch mit. Neue ARIA-Rollen (grid/row/columnheader/gridcell, aria-readonly je Zelle) machen die Tabelle für Screenreader als Grid erkennbar
  • Read-only Tabellenansicht links vom Zeitstrahl, Teilschritt B von #117 (Issue #119): neue Komponente GanttTable.vue zeigt dieselben Zeilen wie das Chart (Titel mit Einrückung nach depth, Startdatum, Enddatum, Fortschritt), gespeist aus buildRowModel()/buildTableRows() (siehe Teilschritt A, Issue #118) – Reihenfolge, Filter-Dimming, kritischer Pfad und Projektfarben bleiben so exakt konsistent zum Chart. Zeilenhöhen sind fest an frappe-gantt gekoppelt (40 px = bar_height 22 + padding 18, Kopfzeile 52 px = header_height). Ein Toolbar-Button blendet die Tabelle ein/aus, ein Splitter macht die Breite verstellbar (160–560 px), vertikales Scrollen ist bidirektional mit .nc-gantt-container synchronisiert. Sichtbarkeit und Breite werden pro Nutzer über einen neuen, generischen UI-Preferences-Endpunkt (GET/PUT /api/v1/ui-preferences, SettingsController über IConfig::get/setUserValue() als JSON-Blob) persistiert, damit Teilschritt E (Editieren) das Schema nur noch um weitere Keys erweitern muss, ohne Endpunkt oder Speicherformat anzupassen. Rein lesend – Editieren folgt in Teilschritt C
  • Projekt-Export/-Import (JSON, format_version: 2) kann jetzt optional die von den Aufgaben referenzierten Ressourcen inkl. Gruppe, Wochenmodell, Arbeitskalender+Feiertagen und Tageskapazitäten mitnehmen, statt wie bisher nur die rohe resource_id in eine Zieldatei zu schreiben, die dort ungeprüft übernommen wurde – auf einem System ohne identische Ressourcen-IDs ging die Zuordnung damit verloren oder landete schlimmstenfalls bei einer fremden Ressource (Issue #115). Vor dem JSON-Download entscheidet ein Options-Dialog, was mitexportiert wird (Ressourcen / Verfügbarkeiten / Kalender, gestaffelt); vor dem JSON-Import zeigt ein passender Dialog, wie viele Ressourcen die Datei enthält, und lässt auswählen, was übernommen wird sowie ob bei Namensgleichheit die vorhandene Ressource wiederverwendet (Default) oder immer neu angelegt wird. Referenzen werden ausschließlich über eine Mapping-Tabelle aufgelöst und nie roh durchgereicht; nicht auflösbare Referenzen werden verworfen (Regressionsschutz zu #112/#113). Neu angelegte Ressourcen/Gruppen/Kapazitäten gehören stets dem importierenden Nutzer. Wochenmodelle/Kalender/Feiertage sind weiterhin admin-only anlegbar – ohne Adminrechte werden nur namensgleiche vorhandene Einträge gemappt. CSV bleibt unverändert aufgabenzentriert mit Ressourcen nur als ID-Referenz; der volle Ressourcenumfang ist JSON-only. Alt-Exporte ohne resources-Schlüssel importieren unverändert wie bisher, ohne Options-Dialog
  • Inline-Editing der Basisfelder in der Tabellenansicht, Teilschritt C von #117 (Issue #120): die Zellen für Titel, Start, Ende und Fortschritt sind direkt editierbar und aktualisieren die Balken im Chart sofort. Gespeichert wird über die bestehenden Store-Actions (updateTask/updateSubproject/updateMilestone/updateProject) inkl. Terminpropagation und dem vorhandenen Undo-Toast für Aufgaben (analog Drag & Drop im Chart); ein lokaler pendingEdits-Overlay zeigt die Änderung optimistisch an und rollt sie bei einem fehlgeschlagenen Request mit Fehlermeldung zurück. Die Schreibrechte löst tableRows.js je Feld über store.canEditProject() auf (titleEditable/startEditable/endEditable/progressEditable) – Projekte und Teilprojekte bleiben bei Datum und Fortschritt read-only, da diese Werte aus den Aufgaben berechnet werden. Geprüft wird: Titel nicht leer, Enddatum nicht vor Startdatum (Meilensteine ausgenommen, deren Start- und Endspalte dasselbe milestone_date zeigen) und Fortschritt 0–100. Im Simulationsmodus rufen Datumsänderungen an Aufgaben simulateTaskChange() statt einer echten Speicherung auf
  • Ressourcen-Überbuchungswarnung (Issue #82): die Kapazitätsplanung war bisher reine Datenerfassung ohne Abgleich mit dem tatsächlich verplanten Aufwand. Der neue Endpunkt GET /api/v1/resources/{id}/utilization?from=&to=&group= (ResourceUtilizationService/ResourceUtilizationController) stellt den geplanten Aufwand aus den Aufgaben-Ressourcen-Zuordnungen – gleichmäßig auf die Arbeitstage der Aufgabe verteilt, über WorkCalendarService mit ressourcenspezifischen Arbeitstagen und Feiertagen – der erfassten Tageskapazität gegenüber. Mehrfach-Ressourcen-Zuordnungen (Issue #103) samt Alt-Aufgaben werden berücksichtigt, ohne gepflegte Tageskapazität gilt ein Fallback von 1 PT/Tag. Im Ressourcen-Raster färben sich die Zellen nach Auslastungsgrad (> 90 % gelb, > 100 % rot) und der Tooltip zeigt geplante Stunden gegen Kapazität samt Aufschlüsselung nach Projekt und Aufgabe; das Workload-Chart im Gantt markiert überbuchte Perioden jetzt rot. Übersetzungen für alle sechs Sprachen ergänzt
  • Nachgetragen – beide Funktionen wurden bereits mit 1.4.2 ausgeliefert, waren dort aber nicht im Changelog dokumentiert:
  • Einheitliches Statusmodell für Teilprojekte und Aufgaben (Issue #78): neues Feld status (not_started/in_progress/blocked/done) auf nc_gantt_subprojects und nc_gantt_tasks ergänzend zum numerischen Fortschritt, Bestandsdaten leitet Migration Version1030 daraus ab. Validierung per StatusValidator (Whitelist analog ColorValidator), Status-Dropdown in den Detailformularen, blockierte Balken im Gantt schraffiert und mit Warnsymbol, blocked_count je Projekt im Rollup sowie ein Badge in der Projektliste
  • Mehrere Ressourcen mit individuellem Aufwand je Aufgabe (Issue #103): bis zu vier Ressourcen je Aufgabe mit eigener Aufwandsschätzung in der Einheit der Ressource (neue Tabelle nc_gantt_task_resources, Migration Version1029, Backfill aus den vorhandenen resource_id/work-Werten). Das manuelle Work-Feld entfällt: TaskService::resolveResources() summiert die Einzel-Aufwände zur Gesamt-Work (1 PT = 8 h) und übernimmt die erste Zuordnung als primäre resource_id, die weiterhin für Arbeitskalender und CPM maßgeblich ist. Ressourcen-Filter sowie CSV-/JSON-Export und -Import berücksichtigen alle Zuordnungen statt nur der primären

Changed

  • buildFrappeRows() (src/gantt/frappeRows.js) mischte bisher Datenmodell und frappe-gantt-Formatierung: die Einrückungstiefe steckte als Leerzeichen im name, Zustände (Dimming, kritischer Pfad, Summenbalken) hingen in custom_class – eine geplante Tabellenansicht neben dem Gantt-Chart (Issue #117) hätte dieselbe Logik duplizieren müssen (Teilschritt A, Issue #118). Neue Funktion buildRowModel() (src/gantt/rowModel.js) liefert dieselbe Zeilenliste jetzt als neutrales Modell (id, type, entityId, depth, title, start, end, progress, parentId, editable, matched, critical), resolveMilestoneDate() wandert mit ins Modell. buildFrappeRows() ist nur noch ein dünner Adapter darüber, der name/custom_class/dependencies wie bisher erzeugt. Reines Refactoring ohne sichtbare Änderung, per Fixture-Vergleich gegen die alte Implementierung geprüft; neue Unit-Tests (src/gantt/rowModel.test.js, npm run test:unit, via neu eingeführtem vitest) decken Hierarchie, Einrückungstiefe, Meilenstein-Datumsauflösung und Filter-Dimming ab

Fixed

  • Abhängigkeitsfortschreibung bei Aufgaben lieferte für alle vier Abhängigkeitstypen (EA/AA/EE/AE) einen um einen Arbeitstag zu langen Nachfolger-Termin – bei EA zusätzlich mit falschem Anschlusstag, da der Nachfolger auf dem Endtag des Vorgängers statt am folgenden Arbeitstag begann und dadurch mit dem Vorgänger überlappte (Issue #114). Ursache war eine Off-by-one-Vermischung zwischen der inklusiven Arbeitstagszählung und der exklusiven Datumsfortschreibung in TaskService::applyConstraint()/computeMultiConstraint(). Betroffen sind sowohl das direkte Setzen einer Abhängigkeit als auch die Terminpropagation nach Drag & Drop und die What-if-Simulation. Verhaltensänderung: Bestehende Pläne mit EA-Abhängigkeiten verschieben sich beim nächsten Speichern/Neuberechnen um einen Arbeitstag nach vorne (auf den korrekten Anschlusstag); bei AA/EE/AE verkürzt sich der zuvor fälschlich verlängerte Nachfolger-Zeitraum um einen Arbeitstag, die ursprüngliche Dauer bleibt jetzt garantiert erhalten. Abhängige Meilensteine (Dauer 0) sind unverändert korrekt und von diesem Fix nicht betroffen

  • Security: jeder Nutzer mit Schreibrecht auf ein eigenes Projekt konnte jede in der Instanz existierende resource_id einer eigenen Aufgabe zuordnen – unabhängig vom Eigentümer und ohne jede Share-Beziehung (Cross-Tenant-IDOR, Issue #112). TaskService::resolveResources() lud die vom Client gesendeten IDs bisher nur über ResourceMapper::findByIds(), also als reine Existenzprüfung ohne Berechtigungscheck; da die IDs fortlaufende Integer sind, waren sie trivial zu erraten. Der Listen- wie der Legacy-Einzelfeld-Pfad in create()/update() filtern referenzierte IDs jetzt über ResourceMapper::findVisibleToUser(), nicht sichtbare IDs werden wie unbekannte verworfen (Liste) bzw. nicht übernommen (Einzelfeld, der bestehende Wert bleibt erhalten). Regressionstests decken beide Pfade für create() und update() ab

  • Feiertage ließen sich nicht in mehreren Regionskalendern führen: POST /admin/holidays lief in einen HTTP 500, sobald dasselbe Datum in einem zweiten Kalender angelegt wurde, weil der Unique-Index aus Version1006 allein auf holiday_date lag, obwohl Feiertage seit Version1013 über calendar_id kalenderbezogen sind. Version1031 verschiebt den Index auf (holiday_date, calendar_id); die Eindeutigkeit globaler Feiertage sichert weiterhin der Upsert in HolidayAdminController::create(). Betroffen war neben der Feiertagsverwaltung auch der Kalender-Import aus einem Projekt-Export, wo der Fehler still verschluckt wurde. Zweitens war GET /admin/holidays admin-only, während work-calendars und work-schedules lesend für alle offen sind – für normale Nutzer blieb der Store deshalb immer leer (keine Feiertage im Projekt-Export, keine Markierung arbeitsfreier Tage im Ressourcen-Raster); der Lese-Endpunkt zieht nach dem Muster der übrigen Stammdaten auf /api/v1/holidays um (NoAdminRequired), Anlegen und Löschen bleiben unter /api/v1/admin/holidays. Ergänzend werden Feiertage jetzt mit ihrem Kalender gelöscht (WorkCalendarController::destroy(), HolidayMapper::deleteByCalendar()) und Bestandswaisen bereits gelöschter Kalender in Version1031 aufgeräumt – über verweisende Ressourcen haben sie bis dahin weiter als arbeitsfreie Tage gewirkt
  • Die Installation der Tabelle nc_gantt_task_resources scheiterte auf Instanzen, deren Tabellenpräfix die von Nextcloud aus Oracle-Kompatibilität erzwungene 30-Zeichen-Grenze für Bezeichner reizt: der von Doctrine automatisch vergebene Primary-Key-Name (Tabellenname + _pkey) wird mit Präfix oc_ zu lang (Issue #132). Die Primärschlüssel-Definition bekommt – analog zu den bestehenden Migrationen für nc_gantt_resource_capacity und nc_gantt_resource_groups – einen expliziten kurzen Namen
  • Der absolut positionierte Toggle-Button der Nextcloud-App-Navigation ragte in den App-Content hinein und verdeckte dort den Titel des ersten Eintrags in der Projekt-Rollup-Leiste (Issue #134); der linke Innenabstand reserviert jetzt Platz für den Button
  • Ein leerer Balken in Höhe der Kopfzeile erschien oberhalb des App-Inhalts, weil der CSS-Reset für den Nextcloud-Content-Wrapper an main#content.app-nc_gantt gekoppelt war (Issue #126). Ändert sich das Markup zwischen Nextcloud-Versionen (Klasse oder Tag), griff der Reset nicht mehr und der von NcContent (#content-vue) selbst gesetzte margin-top: var(--header-height) addierte sich zum Rand des Cores. Der Reset hängt jetzt robust an #content mit !important, ohne Abhängigkeit vom app-spezifischen Klassennamen
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturegO8Qmtdwg8LOBKr5G+mq4co374hsqqSN6oCIRV9atUx0KqogPxisJiIExkPoSIbu
e4EeIaUzg2alhZsKBLWOwR3Ab3fNm5vvd2DzJn6Hei7A70woz9m/LXkVlcx3vALW
bwolClUX1XCZOBVo/kSS5AOVwak3/huzT1iF9xH9BnpdzVuOjZ563LYwSayfb2Gq
SkWNfLZlKlDkTTF2PIszrNmaa89GmyqTbraxSP16/9nYdIj8ZU0zrhC3HtpihgAT
wya2lwnMf6I73HU0xxgT/+ITTmurx4eHwKWH80P4tjg/Y9mnHODIpAslbW3351mc
qdTHXIBW1MB1YGCQ+JPt11v1X2ccn29kEF9d1nkizKZ1+Du+LJQhPhwHiQxPWSwAUlTlQ4tj1lbe3+FJ1jsVTCqWbDUN02EoV7ZwtN15/HLJfM6w4drUi8ThJ1aLG3v6
cIwMJjYgWeepxR2gv4YgBf4u7txodm5bAWuzySk4rfAG1dBxmie/bfNnWmQ9LrYy
spwKc73gsPhg03ll+jp0b27fJfNF4IpOysz3i+r1ExVfeNIWWO91JPatO2pXZh4O
q0rczM8wYvctvcEkKQIL67HoIrKw4GVIXfqM9Oc8e/Ay7d/NPL+BjpCO6zvoFBY+
SRmjit15YmGW4EQwweQfKXuZ2YeySj+7OjhKHpKfvfg=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.2
Release Details
UpdatedAug. 20, 2026, 4:41 a.m.
Changelog

Changed

  • release.sh fragt die Versionsnummer jetzt interaktiv ab, statt sie nur aus appinfo/info.xml zu lesen: zu Beginn werden die aktuelle Version und das letzte Release-Tag angezeigt und es wird gefragt, ob eine neue Nummer vergeben werden soll (Vorschlag: nächster Patch-Level). Die Eingabe wird auf das Format X.Y.Z, auf einen echten Versionssprung und auf ein noch nicht vergebenes Tag geprüft und dann nach appinfo/info.xml, package.json und package-lock.json geschrieben. Fehlt ein Changelog-Abschnitt zur neuen Version, warnt das Skript; anschließend bietet es an, den Bump als chore: Version X.Y.Z zu committen — nötig, weil der Tag-Name den Commit-Hash enthält. Für nicht-interaktive Läufe gibt es --version=X.Y.Z und --no-bump; ohne TTY wird nie gefragt, make release bleibt also unverändert nutzbar
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturepoVHZxteU3AR2cpRRV98jNfv4j7rWnLEd3kbpn5Dp4T1ubAI+0QlRf9jxi0BaYz1
+1dg+3Yt25uN6Slp1FHiw7kyqt5HJ60XgnOWo+Zt0YBHSnWqLDhF8zxPEnQCkF+v
nUvscpcoQY2bRiIBZhVWVgeAD592uvOA4gfRDrUyLVDKjOrzBu3ScbNvCqTqE9IC
vs8qZkRLIcaD6tKoSLT2pZqmwBoCdClvEw5D5v40WSvLq232BZnXpQ4ogG3QvJdL
mYO8HlPZKVOxANp0MGnWle4IFRMbMt22Ebpkjc18Q9Q4AIv/Sd3zTsc+uMONTM95
s0GXvLSm95o0UCFZ1CL7fCEq7NwlprjVrTeWGmlJNVjHJuIyRKHEz5DR12s0lAGm
/rKGWjoVP+Wvk3upRizR/5y2fpWoiwuDqCtz9gQN6+HHYLaqLvYqsAJ/SxmtLtP7
8B2rK61ClKowz4phbTZdrCaF8w3IWnFFBTFquIVFuN2jUoHvdCMtd0910sLAMY5M
Xs9nk0FVsP23zKXlQpOojq7ouCQagRhsnBJDLxWRR+NIq582f7SDgcrkBqxlGJX4
/Ql9V+2iFx61QANCTjdJIO3LbvbK60vGos+ency0GfvSDbPovDAVyJzt8ZUh5BNw
UXQ4XOHJZAagAr36rKttk1DQbZZ/2bUEq231c96m83g=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.1
Release Details
UpdatedAug. 17, 2026, 7:43 p.m.
Changelog

Fixed

  • Die Meilenstein-Raute hatte eine fest verdrahtete Farbe (#fbbf24) statt der Projektfarbe zu folgen, obwohl Balken für Aufgaben und Teilprojekte bereits korrekt eingefärbt wurden (Issue #102). Zusätzlich wurden die separaten – und wirkungslosen – Farbwähler bei Teilprojekt und Aufgabe entfernt, da deren Anzeige ohnehin immer der Projektfarbe folgt
  • „Meilenstein hinzufügen" im Drei-Punkte-Menü der Projektliste nutzte zwei aufeinanderfolgende window.prompt()-Dialoge (Name, dann Datum als Freitext) statt des regulären Detail-Dialogs (Issue #101). Der Klick emittiert jetzt add-milestone analog zu „Aufgabe hinzufügen" (Issue #91) und öffnet denselben Meilenstein-Dialog wie beim Bearbeiten, mit vorbelegtem Projekt
  • Im festen Datumsmodus des Aufgaben-Detaildialogs konnte ein Enddatum vor dem Startdatum eingegeben und gespeichert werden (Issue #100). Jetzt zieht ein über das Enddatum hinaus verschobenes Startdatum das Enddatum mit; ein zu frühes Enddatum erzeugt ein rotes Fehler-Icon am Feld, hält den Fokus dort und deaktiviert den Speichern-Button, bis ein gültiges Datum eingetragen ist (dateField() in fields.js mit neuer setError()-Methode)
  • Eine Aufgabe mit Abhängigkeit behielt trotzdem die manuell eingegebenen Start-/Enddatumsfelder, die beim Speichern durch die Abhängigkeitsberechnung überschrieben wurden – für Nutzer nicht nachvollziehbar (Issue #99). Der Aufgaben-Detaildialog hat jetzt denselben Fixed-date/Dependency-Umschalter wie Meilensteine (Issue #90): im Dependency-Modus ersetzt eine Dauer (Tage) die Datumsfelder, die Abhängigkeit bestimmt den Termin. Serverseitig wendet TaskService::create() neu hinzugefügte Abhängigkeiten sofort an (bisher nur update()), damit auch neu angelegte Aufgaben keinen die Abhängigkeit ignorierenden Platzhaltertermin behalten
  • Der Speichern-Button des Detail-Dialogs blieb nach dem Hinzufügen einer Abhängigkeit deaktiviert: die Gültigkeitsprüfung hing allein am input-Event, das bei einem <select> vor dem change-Event feuert – zu diesem Zeitpunkt war die Abhängigkeit noch nicht in der Liste. detailModal.js wertet jetzt zusätzlich change aus, der Abhängigkeits-Editor (fields.js) meldet jede Mutation (Hinzufügen, Entfernen, Typwechsel) und der Fixed-date/Dependency-Umschalter in taskForm.js den Moduswechsel über ein eigenes bubbelndes change-Event

Added

  • CONTRIBUTE.md und setup-dev.sh für neue Mitwirkende (Issue #98): Projekt-Leitlinien (FOSS, Datensparsamkeit, Security), VIBE Coding ausdrücklich erlaubt, sowie der komplette lokale Dev-Setup-Weg (Docker-only, Nextcloud + MariaDB unter localhost:8088, optionales E2E-Setup, Git-/Bot-Auth). setup-dev.sh automatisiert diese Schritte, konfigurierbar über --workdir/--no-e2e/--no-docker-install
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturetYcUvVtDEQrAakG32EQF1atSOmz91/8XudCUh60A9r/AxMv+AA5AX2rIvNYDkEn0
OuTmXA6Iz0DoVkdij11MPDhfLaUy0mXeLbwB5fj/xF/cFYcNeCFGKD3k2jyRwOTo
2n1sEp0r8sn0fitHzLfhcB/By0VJkZyhaO/NctP01XfcSQM7lGEOeY/uagtGaDTI
JnPLoQTHo0nUOv4y7jUMZuurEgBOc4yeUxTKv4A/m642hvNQIS0q6K9ON41JHKIO
UtI7DbDWSboVhct1Go3zoj5XcaAGG9ZiwSkJDt/BXT5tWH4SOnSn7mys0j1F6Y0g
vIJWjz6S2RlekwIrIxgyaeEVBOeQ4OM1ilJGWKXDyYJM/0IBxqnqRXDkAFlOopDo
xezlcFdWTkYL5OBKMFJhKuTy7dEQ9hxx5Nz4+vLbNV8gDJZBI+5yI5m8W+809WIH
iKUpIda1ShOblvYH6Ek5AzBdTmoFQ6T4f7iWT7j1i4uUP2DsgehjGVl8yDIT/wyx
nV9t7koXapu1WeXrunSa++mXsi3lceNpthdz5/cUEOe9yWvc1rrulRhiWzePga8H
zjVQYGAIPvwYkWa47U6Zh7HBsQaS+9yQ8NDnD49SS4jUWTGlwNqfM+q9fZ16/G9d
7l4chZUPPbBv+xWfdxmFw+MC5zdkAq27isHToTqnm+w=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.0
Release Details
UpdatedAug. 13, 2026, 6:41 a.m.
Changelog

Added

  • Meilensteine werden jetzt immer direkt unter ihrem übergeordneten Objekt angezeigt statt gesammelt am Projektende (Issue #90): Meilensteine lassen sich neu auch einer Aufgabe zuordnen (bisher nur Projekt/Teilprojekt, Spalte task_id war bereits vorhanden, es fehlte nur die UI), das Auswahlfeld im Detail-Dialog heißt entsprechend „Übergeordnetes Objekt" statt „Teilprojekt". Zusätzlich können Meilensteine ihr Datum jetzt statt eines fixen Werts aus einer Abhängigkeit zum übergeordneten Objekt beziehen (EA/AA/EE/AE, analog zu Aufgaben-Abhängigkeiten; neue Spalte dependency_type, Migration Version1028) – da ein Meilenstein keine Dauer hat, bestimmen EA/EE das Ende und AA/AE den Start des Zielobjekts. Die Berechnung übernimmt der neue MilestoneDateService (serverseitig live bei jedem Abruf sowie im ICS-Feed neu aufgelöst, nicht persistiert propagiert) sowie clientseitig in frappeRows.js für sofortige Reaktivität ohne Neuladen
  • Undo für Drag-&-Drop-Verschiebungen inkl. Propagationskette (Issue #85, Umsetzung der einstufigen Empfehlung: letzte eigene Operation, kein Redo, zunächst nur Drag & Drop): Migration Version1027Date20260810020000 ergänzt nc_gantt_change_events um op_id (UUID) – alle Change-Events einer zusammenhängenden Operation (Drag + gesamte Propagationskette B→C→D) erhalten dieselbe op_id, erzeugt in TaskService::update()/propagateDates() und über ChangeEventService::log() protokolliert (dieses Change-Tracking war bisher tote Scaffolding-Logik ohne Aufrufer). Neuer Endpoint POST /api/v1/changes/{opId}/revert (ChangeEventController::revert, ChangeEventService::revertOperation) wendet alle Change-Events der Operation invers an, in einer DB-Transaktion mit Rechteprüfung über AccessService::canEditOrOwn(). Konfliktschutz: Revert wird mit HTTP 409 abgelehnt, sobald der aktuelle Feldwert nicht mehr dem protokollierten new_value entspricht (jemand hat zwischenzeitlich erneut geändert); der Revert selbst erzeugt wiederum neue Change-Events, die Audit-Historie bleibt lückenlos. Frontend: nach jedem gespeicherten Drag zeigt GanttChart.vue einen Toast „N Termine verschoben — Rückgängig" (showUndo aus @nextcloud/dialogs, 10 s sichtbar) sowie ein globales Ctrl+Z für die letzte eigene Operation der Session (stores/projects.js: lastOperation, revertOperation(), undoLastOperation())
  • Kalender-Export als abonnierbarer ICS-Feed pro Projekt (Issue #83, Variante A aus dem Umsetzungsvorschlag): neue öffentliche Route GET /apps/nc_gantt/projects/{id}/calendar.ics?token=… (regulärer, unauthentifizierter CalendarFeedController, damit externe Clients wie Thunderbird, Nextcloud Kalender oder mobile Apps ohne Nextcloud-Login abonnieren können) liefert Meilensteine als ganztägige VEVENTs (◆-Präfix), den aus den Aufgaben abgeleiteten Projektzeitraum sowie optional Teilprojekt-Zeiträume (Schalter „Auch Teilprojekt-Zeiträume einschließen", standardmäßig aus, um den Feed bei großen Projekten nicht zu überladen). Zugriff erfolgt über einen pro Projekt generierten, 256-Bit-zufälligen Token in der URL (CalendarFeedService, neue Spalte calendar_token auf nc_gantt_projects, Migration Version1026), der über einen neuen „Kalender-Feed"-Bereich im Freigabe-Dialog angezeigt, kopiert und jederzeit widerrufen/neu generiert werden kann (CalendarTokenController, nur für Projekt-Admins/-Eigentümer). ICS-Generierung ohne neue Abhängigkeit, RFC-5545-konform (Escaping, Zeilenfaltung)
  • What-if-Simulationsmodus für Terminverschiebungen (Issue #84): neuer Endpunkt POST /api/v1/projects/{id}/simulate führt Terminpropagation und CPM rein im Speicher aus (kein DB-Schreibzugriff) – TaskService::simulate() nutzt die neu extrahierte, stateless propagateDatesCore()-Kernlogik, die auch der persistierende update()-Pfad verwendet, CriticalPathService::computeFromTasks() erlaubt CPM auf einem hypothetisch veränderten Task-Datensatz. Frontend: „Simulation"-Toggle in der Gantt-Toolbar mit Banner inkl. Projektende-Delta in Arbeitstagen, Geisterbalken für die Ist-Termine (analog Baseline-Overlay) sowie Verwerfen/Übernehmen. Drag & Drop ruft im Simulationsmodus simulate() statt einer echten Speicherung auf. Szenarien bleiben bewusst flüchtig (kein Speichern benannter Szenarien), „Übernehmen" wendet die Änderungen als einzelne Task-Updates an, Simulation läuft pro Projekt
  • Neuer Eintrag „Aufgabe hinzufügen" im Drei-Punkte-Menü der Projektliste (Issue #91): legt wie der „Neu"-Button eine Aufgabe an, belegt dabei aber das gewählte Projekt direkt vor, sodass der Projekt-Auswahlschritt in der Maske entfällt
  • Such-/Filterleiste für Projekte, Teilprojekte und Aufgaben (Issue #81, Stufe 1: rein clientseitig auf Basis der bereits geladenen Daten aktivierter Projekte): Freitextsuche im Titel, Risiko, „überfällig" (Ende < heute und Fortschritt < 100 %), „über Budget" (Ist-Kosten > geplantes Budget), Ressource und „ohne Deck-Verknüpfung". Neuer Pinia-Store stores/filters.js (Zustand pro Nutzer in localStorage persistiert) und reine Matching-Logik in gantt/filterMatch.js. Nicht passende Balken werden in GanttChart.vue gedimmt statt ausgeblendet (Abhängigkeitspfeile und Zeitkontext bleiben lesbar), Projekte/Teilprojekte gelten als Treffer, sobald ein Nachfahre passt. Dieselbe Filterleiste (components/FilterBar.vue) dimmt in ProjectList.vue nicht passende Projekte; für nicht aktivierte Projekte sind nur Titel-Treffer zuverlässig auswertbar, da deren Aufgaben/Teilprojekte nicht geladen sind

Changed

  • Freigabe für Nextcloud 34 (Issue #94): max-version in appinfo/info.xml von 33 auf 34 angehoben, unterstützter Bereich damit NC 28–34. Verifiziert gegen Nextcloud 34.0.2 mit PHP 8.5 und MariaDB 11.4 (148 Unit-Tests, 39 E2E-Tests)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturerdYQI+Semnk0cWtKqUZinVDHk0KpxyqB5Ox4NBL9pyf5nrpK8xZpe9lBxc6zhDfW
8adLfVIwQtX+bI7S1O05xm0hwrUHQQ2ii6ADD8mlAxnZjdhKSCAhZ0NcaqT7Em0X
nD7yRP2B8zAAQMJNjzeBsLbzveNrXMoGzFrvm/jFxskUIUS01ykfWEg2C5+5/IAf
7jBAM8x2Qj92b8zyBFpLjfJQw9aTE/trtCsmZXQFmkJjGS0anrJc9dXKfqnHxknX
8jmLOv4Yq4Qtk3UF35HTiIGcA2W0UKfVyFb4XcrIMeSmLXXcagJWjeH5nB18UUNn
JyCgE/qY4v/SnrNQU92mIdMOQGuvYg7xbaz226lgNdwM2HuM9U8nc2juqJxAO+Wp
xs85yl82qIviZ5YY39HK371MZ/ufMsaVsVy3Nfn3PjqqkzGLmtAL6KJDcKHZWdDw
ugEPwO61DxnERZsNGeFpXfzCxjMpZc/qwUIfGw85idmU2vdedtrxHBkDGoqu1IP7
xZOO8uSYrzbXM6g1gs3WPBOY51CmZLs5pIQTN1tVl5ifGw4uOuzDBUCKiR5oA2MI
352HbA7wwWFgwoN9W5t4MRTowmaYpM8AB+nh9f1A5q9S8SelfMpXOqGew9VZb2jd
AuiJK/LEPjRgs5s3/FfC4Sb1MSsXDr1N1jziaF4MomM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.3.1
Release Details
UpdatedAug. 6, 2026, 12:57 p.m.
Changelog

Added

  • Regressionstests für die Rollentrennung Viewer/Editor/Admin: ForbiddenException-Tests für TaskService::create/update/delete/syncProgress und ProjectService::updateProject/deleteProject (inkl. „Editor darf nicht löschen") sowie erstmalige Testabdeckung für SubProjectService und MilestoneService

Fixed

  • CSV-/Formel-Injection im Aufgaben-Export (detail/io.js exportCsv): Task-Felder wie Titel oder Beschreibung, die mit =, +, - oder @ beginnen, wurden unverändert übernommen und von Excel/LibreOffice/Google Sheets als Formel ausgewertet. Die Absicherung aus ReportView.vue liegt jetzt in einer gemeinsamen Utility (src/utils/csv.js, escCsvCell) und wird an beiden Export-Stellen verwendet
  • Viewer sahen im Frontend dieselbe Oberfläche wie Editor/Admin (Add Task/Subproject/Milestone, Share, Delete Project, Drag/Resize im Gantt-Chart, volle Bearbeitungsformulare), obwohl das Backend Schreibversuche ohnehin korrekt ablehnte – kein Least-Privilege an der UI. ProjectService::getAccessibleProjects()/getProject()/createProject()/updateProject() liefern jetzt das effektive permission-Feld (AccessService::getEffectivePermission()) mit; ProjectList.vue, GanttChart.vue (inkl. Drag/Resize-Sperre je Projekt) und das Detail-Modal (detail/detailModal.js) blenden Schreib-Aktionen für Viewer aus bzw. schalten Formulare read-only
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureBUyDeI9y7iKD1wQJLHrW6IFq0zuXOJQ1Zv/x+0RryIIQ0fAGAUjwQyLDYLYpRzPg
6ITDPfY9bftVlwkB8w9LqZiFETkH8mgc6l5XB7F6NKzFrdaSnNw21CIVJjWyHpkR
mxDq+vQepZd+YtB9jMz39kbFk9BNHrpKIwIXXZVqEqj1U54NmT+5XnT892m9mY6o
RWQNf3Mn5WcH3vmoDi/UAOgDaO30GFCRJePryurVpK7stkub8K6fYsWIkS5NeJlP
YHdb4nBlkhUzQFjo0ZDSkCSiWjMdyCrtEanX6m6Ffhr+j0jpd+J9soMSjrzdzt4T
5mETo8xc61IQIVFWMD6fZ3/oCmbx2TFDZsJjRpFKxoPA08AkdC7xjxHoaKYZHvi4
+tzowxPzMfyjQ/hEj2dwq22doM2lXK1Y13VvV8kkaomrAQjB97gf+ODrYZNDgNvc
2ijU08B4cAB0HbEveDpDRjCJj8D5OwCMafRMa4Ul/nm0+RiBFOhIjDYdVAnCp7Ql
IEc4UQZM9WYLQlouwGPk83POpbqkbc8vKAucGBXvHAbxNpUSOGbssMYFGU/e9pOg
+oT2gcJrC3MYPGIWnS8iLn75PK1H063KFJv5yqC+h/rqwX/FxyTzKvofJi68GpLs
WtG3y67W8Ju4y1I9iQ9raJxxhFUJrStibGy9gc7L0DM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.3.0
Release Details
UpdatedJuly 9, 2026, 5:23 a.m.
Changelog

Fixed

  • Baseline-Toggle im Gantt-Toolbar zeigte nie Baseline-Balken und PUT baseline/active warf einen SQL-Fehler: baseline_id auf nc_gantt_projects wurde mit der 3-Ebenen-Migration versehentlich zusammen mit den tatsächlich berechneten Spalten entfernt (Migration Version1025 stellt die Spalte wieder her). BaselineService::create() aktiviert eine frisch eingefrorene Baseline jetzt automatisch fürs Projekt; renderBaselineBars() (GanttChart.vue) und baselineOverlay.js lesen Baseline-Items dafür über task_id statt des seit der Umstellung auf das 3-Ebenen-Modell nicht mehr existierenden subproject_id-Felds
  • OCS-API-Fehlerantworten (400/404/500 …) lieferten für alle OCSController-Endpunkte einen leeren text/html-Body statt des erwarteten JSON-Envelopes mit message; ExceptionMiddleware wirft jetzt passende OCP\AppFramework\OCS\OCSException-Subklassen statt einer rohen DataResponse, die Nextcloud-Core nur für 401/403 automatisch formatiert. Betroffene Controller (ProjectController, ReportController, ShareController, ChangeEventController, WorkScheduleController, WorkCalendarController, HolidayAdminController, SettingsController) wurden zusätzlich auf die bestehende ApiException-Hierarchie umgestellt

Removed

  • Nie ausgewertete Gruppen-Freigabe-Option entfernt: Share::TYPE_GROUP, principal_type-Parameter in ShareController sowie die DB-Spalte principal_type (Migration Version1024) wurden gestrichen; Freigaben sind jetzt ausschließlich benutzerbezogen

Changed

  • Dashboard-Summary (DashboardController::summary) lädt Baselines und Aufgaben-KPIs jetzt über gruppierte SQL-Aggregat-Queries statt pro Projekt einzeln (N+1-Fix, gilt auch für den Admin-Fall mit allen Instanz-Projekten)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureNJfbRJEXzKGipUjUW9tUKayHoY6ltSU0ZeCQXcDx6XVDY/naLK0dVY9ciofXU7oy
40sJIOsjxcUZbalDwqncPn0vjGoqmk3BFUT7KotEpLLf8/ZmIjdHEbQbJHzEpdQV
y5YedjqRLKB7/Ul35JWVFxY8eutCsYkonfof7v6AGMGB/RjQ7GDB6jWunEEwqUGV
3Y1isvdq5N3oo9NDY/QR0C2C7jiMnB9Kon0KzZ2yp0oF5euOpA/qrtmqxG3L9PoZ
DW1ppwAuARWtRDu4tcDAAQAkF1Mrg5YyYgRoKm7uVazlKEP7DxX56g/g4RS2otEE
rKsA/ER9yYiHnNyGcZuK9Jkfe2Ua6/R7gzJilRvHZ7CBPkhY+XNPcrjlsHbCJEJJ
cX/b0B56p7FyAFy6XjMY9PYFhxy/ubHE7Sk8ixX88uxgM4vf/sSFQaN84CcG/qqA
Nq/OEytBjZP82TsFFYBRcPKEPskF4ejjhNVC4bJpiuCIpo51nIxjeFGtDpeQiDG7
0OWc/GCvsz5W3eG7ShmQsRf0DoivL8tjgDUlMWO9boTpUy2Vnm1rDMKu6nFGKZ8o
TWTZR6u4zGZW1OBERdlU5NQmqxqXrsuGlT6r6DuQnWsWiscjXOyIFeHz+EOKhQOk
wUuN6xN8QES1CDFB27PYV0Sz2KhYhM78GKLCc9B10Ic=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.2.0
Release Details
UpdatedJuly 5, 2026, 9:21 a.m.
Changelog

Added

  • Löschen-Buttons im Detail-Modal für Teilprojekt, Aufgabe und Meilenstein
  • Deutsche App-Beschreibung in info.xml ergänzt

Fixed

  • Baseline-Datum und Kommentar im Report werden untereinander angezeigt
  • Dashboard-Widget zeigt Baseline-Datum und KPI-Werte korrekt an
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureXuYTZMxTlGNJVrGvU/GcIjSlBTYreXdvF5FilCmsi+l7MBvFlyeW1DsnxAsao3pu
HyhvaKXRnkraVQNT2ULgX4BmjUnhsELROrK03gtY88Odzqzh7RIXYkNkRcy92ara
56HIP8BBRD3m1c8pYPfpZfLAzkuurAzVqbJ6qbxw1AebdlPCFEq2g6C+IOcTon0T
q9ZD2I2XJmWd42EXXqva+NMrcx1jfjmHWVtl7xHKhwPndFCtHPMMAdoDS0Xpbh1V
3Ns4h/DphDpC8/ZYZ5sbpMCBekHw4VTZDGxNAuXJ5DMPhkqg2MxVplkS19PuBHLx
r74sgsz611Gjg55gjKOqCb5ZZEvqZTrwKTEYIbu8HicWtq/HxKRZS3FZN9MThTTX
Hesv65vsq9fH0UhEM6MVJjE5Phnw8Wb5ivtAiaUA+NzPrDfrHZAsSfR9NFL3rhFC
7wOmnXtzK40NjmqyMWJu/UP9UVbz3SeEiHiQO9GwBc2krzmXzcmLZFgEjty4CGoJ
SzXAA1QGpUGO4n0b3Y/5zSY4UxogGWybW+mOs27KDLytI915wNYGvBtcdAKCj6Ws
1uVA98npwMid/WSJJ04BXHX8LbowrDeTezSFJyGh+u/KnhlzkA7fqEuu3nQGT5rA
a9qeMmd5kmLBIVcG9RVVmw1kc0AK0qIqZDmlk9dWGJs=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.1.1
Release Details
UpdatedMay 27, 2026, 6:43 p.m.
Changelog

Added

  • Glossar-Button in der Navigation (über den Einstellungen) mit interaktivem Nachschlagewerk
  • Dreispaltige Glossar-Tabelle: Begriff/Abkürzung, Bedeutung/Englisch, Erklärung mit Berechnungsformeln
  • 30 Einträge in 6 Abschnitten: Allgemein, Terminplanung, Baseline & Berichtswesen, Earned Value Management, Ressourcen & Kapazität, Budget

Fixed

  • Fehlende deutsche Übersetzungen für englische UI-Strings ergänzt (Add dependency, Baseline, Dependencies, Remove, Work, No projects yet, Open Gantt Projects, u.a.)
  • Leere Übersetzung für Deck-Fortschritt-Hinweis befüllt
  • de.js vollständig mit de.json synchronisiert (war ~70 Einträge veraltet)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureF1RHJx15J/N8tWNrDlAX1MFE/9tsct4PViEcBDeo8U/V2qJ/tezL7Xk0BVmYxjWw
pB+J685mcHjikh93/aZUqG8C6y0mR3TTJfaa7dLCIRMc1034x6Xj9Nd7Q9YVH4yi
RLTcRhrG2pN1Iqc23kwId995GJXHnCBEyuQuzo9m1VtA7GoFa8W2nqhXVT94khDS
8ZHQrixDfv63d4GfA5N2x4+phaiyObdskvCmVSuKrmouYvCGpPevtKG5YxzOrHid
aL48Kod0YgOCAD8nAqOhEmioP0m+wP2e/NC4Z5svSKT3vdlE67W1M68ipQQfnhPI
txui+2X8zFvoe/M5sE3DaXbLnOVNGQ7YRpyXFI5GsQmQ0cPSSO/94Mw15hLZfwMf
TDOrrvzf+Vu05sUTZ6CFh4FrSl4e5Q6Xjv6uH4BZtyOpPxl+ajgW4OkZvQDbt4KC
8aTZodMcDpXlRMDdBSxT1bT9tD05KUKmEZYtpxHiARrHDuQQCRSuxtjitQD9lbla
CMxKrBiO0YgdUb3FuczYkWEH+y8gW5egU6TDMnjAVbuUecGuGZN1Cc6tarcFWRu2
+V7Qn+aNoXEwP5e/0TM4Ig8ETAYseZRiTPHxeWiSg3RnU3HuT6kPVWw8LERACDT4
6F4WU9t2+4kESMLMjeV0/2UBQSykR/42Idsg0PtvpyQ=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.1.1 (nightly)
Release Details
UpdatedMay 27, 2026, 5:24 p.m.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureF4W7QJB8rVJ2xARdnhUbEouzRZMKcowz/ToDwr0oVFrVUbInFvHAMqXFTOVD1a5N
kDTb0pOhv+hCStTh70bN+aapjbdtp7SdQ3SbP5VoXBKLhUii41OqN/i4yM7itdSs
M8d5PVo9TJYVnfaij2xwWghMqZEyzxgOw4Q98dYIysf2BxsjjCtxGEMo/pISS90G
OE2RaVEFbwUcvu1XKszLP5X/k/onOchengURYVuzHP7VgVuomZpPSZ9VEIRKITyL
GpgSDrdqm5AXdQc7l/2OqprW6G+MxsuVzChbyPGslIYYXYsP9HLc/FfwVxaCJjh2
Nsiqfd+dMwnf7f9yrrBuZjbNwNa5x++IynrwaU01jVISkl9pgkbUYRaPSMTGFDAd
lsEEqlgs9KdzGoTFjDXNdTwDOsUMiu/ag8tPo7YxsxLFbVGa7laRAUhlGUT9QGPr
IOAAWvKqivsYnU5iwTCY/5HGza3SDfZc/e5upPfB+lTQTYijp1aAYRBAsoOLmuga
f0aP45pnfnYBJkT1kMsthjbGMdlL46wLiNHKRct9OlFwx74IRIyZdcs5Q3pC0aNN
DSLvsCSmY8/9PtTLzcOJKXTqqDVupCqq82bUlGRn7NR6xsinzv74MuOVnGY21tBm
iB5ceYpgiEukUz6YtS2quIIiMTnYmM+HBFnkXgBV0/Y=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32

Nextcloud 32

Gantt Projects 1.6.1
Release Details
UpdatedSept. 2, 2026, 6:15 p.m.
Changelog

Security

  • Ressourcen-, Gruppen- und Kapazitätsdaten fremder Projekte waren über geteilte Projekte einsehbar (Issue #183). ResourceMapper, ResourceGroupMapper und ResourceCapacityMapper::findVisibleToUser() gaben pauschal alle Datensätze eines Eigentümers frei, sobald irgendein Projekt dieses Eigentümers mit dem Nutzer geteilt war — unabhängig davon, ob die konkrete Ressource überhaupt in einem geteilten Projekt verwendet wird. Der neue zentrale ResourceVisibilityService prüft stattdessen, ob die Ressource tatsächlich in einer für den Nutzer sichtbaren Aufgabe verwendet wird, und wird von ResourceService, ResourceCapacityService, ResourceGroupService und TaskResourceAssignmentService genutzt. Damit lassen sich über eine geteilte Ressource weder die übrigen, nicht geteilten Ressourcen desselben Eigentümers einsehen noch eigenen Aufgaben zuordnen
  • GET /api/v1/resources/{id}/utilization gab Planungsdaten aus nicht zugänglichen Projekten preis (Issue #181). ResourceUtilizationService::findVisibleResource() prüfte nur, ob der Ressourcen-Eigentümer irgendein Projekt mit dem Nutzer geteilt hat; über die Auslastung waren dadurch Aufgaben- und Projekttitel samt Terminen aus fremden Projekten abgreifbar. Die Prüfung stellt jetzt projektbezogen fest, ob die Ressource in mindestens einem über AccessService::canViewOrOwn() sichtbaren Projekt verwendet wird; zusätzlich filtert collectPlannedHours() die Aufgaben auf genau diese Projekte, sodass auch bei erlaubtem Ressourcenzugriff nichts aus fremden Projekten durchsickert
  • Aufgaben und Teilprojekte ließen sich an fremde Projekte hängen (Issue #179). TaskService::create()/update() und SubProjectService::create()/update() prüften nur die Schreibberechtigung auf die eigene projectId, nicht aber, ob eine mitgesendete subproject_id bzw. parent_id überhaupt zu diesem Projekt gehört — mit Folgewirkung beim Löschen eines Teilprojekts (SubProjectService::deleteTasksForSubproject()) und im öffentlichen ICS-Feed (CalendarFeedService::buildIcs()), da beide über TaskMapper::findBySubProject() allein nach subproject_id filtern. Analog zum Schutz aus Issue #97 prüfen jetzt AccessService::assertTaskBelongsToProject() und assertSubprojectBelongsToProject() die Zugehörigkeit; deleteTasksForSubproject() und buildIcs() filtern die geladenen Aufgaben zusätzlich defensiv nach project_id, um vor dem Fix entstandene Altdaten abzudecken

Changed

  • Dokumentation aufgeräumt: Die Doku ist jetzt nach Zielgruppe getrennt — alles, was Nutzerinnen und Nutzer brauchen, liegt in nc_gantt/ und wird damit vom release.sh-Archiv mit ausgeliefert, das Repository-Root enthält nur noch Entwickler-Doku. Dafür sind FEATURES.md, INSTALL.md und die neue HOWTO.md nach nc_gantt/ gewandert; die Root-README.md beschreibt die zehn wichtigsten Anwendungsfälle des Werkzeugs, erklärt je Fall den gedachten Arbeitsweg und führt in einer Repository-Übersicht auf, welches Dokument für wen gedacht ist. Neu ist nc_gantt/HOWTO.md: eine Schritt-für-Schritt-Anleitung entlang eines durchgerechneten Beispielprojekts, die alle zehn Anwendungsfälle mit konkreten Feldwerten, Abhängigkeiten und Terminen durchspielt
  • Dabei korrigierte Verweise und Angaben: der Lizenz-Link in nc_gantt/README.md zeigte auf das nicht vorhandene LICENSES/AGPL-3.0-or-later.txt statt auf LICENSE.md; die Nextcloud-Anforderung stand mit „28–33" in README.md und „28–34" in FEATURES.md gegen die tatsächlichen 31–34 aus appinfo/info.xml; FEATURES.md nannte noch Version 1.5.0; INSTALL.md verwies auf ein dist/nc_gantt-<version>.zip im Repository, das es nicht gibt (dist/ ist nicht versioniert und release.sh baut .tar.gz), und in CONTRIBUTE.md trug ein Link auf RELEASE.md die Beschriftung release.sh. Alle relativen Links und Abschnitts-Anker der versionierten Markdown-Dateien lösen jetzt auf
  • Tests laufen künftig vor jedem Commit (Issue #185): setup-dev.sh installiert einen pre-commit-Hook, der Vitest und PHPUnit (über Docker) ausführt und den Commit bei Fehlern abbricht — genau die Stelle, an der die vier defekten Tests aus dem Ressourcen-Sichtbarkeits-Commit hängen geblieben wären. phpunit.xml schaltet zusätzlich failOnRisky und failOnWarning ein, damit ein Test ohne Assertion den Lauf rot färbt statt unauffällig grün zu bleiben, und CONTRIBUTE.md dokumentiert die Regel zu Mock-Defaults ohne with() in setUp()
  • Die Default-Stubs in setUp() von ResourceVisibilityServiceTest blockierten die spezifischeren Stubs der einzelnen Testmethoden — PHPUnit wertet für dieselbe Methode den zuerst registrierten Matcher aus, und der greift per any() bei jedem Aufruf. findByResourceId(), findByIds() und findByResourceIdExcluding() lieferten dadurch immer ein leeres Array, was vier Failures und zwei risky Tests verursachte. Die Defaults sind entbehrlich, weil PHPUnit-Mocks für den Rückgabetyp array ohnehin ein leeres Array liefern; der Produktivcode blieb unverändert
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturerHm/UxN1WTCOMd9LklleINo7LKDOEAyn1zlsR5eTCaUmdGaN1m8Knqk/EKDYcj73
zWx7TXmT4cP91Ag7mCMwY/gRqJabF7TgeXiA7CeV7VE7/D/+apIatMWRT7zYCjkF
oxXKimNrtpDSKWNXKSQn6RfJaEHu5WnIoF4X9Nyx/wf1WoWoThyvWMSSW/3jdajV
WXCV4XQjzbTULw9T+Ini/e8vp6mXt5CrmCdyUDQQcj2t9PF9Hq3GvWT1VQlYA8Kf
IJuqnArSc4JdtJiJnozpOKSBkAbDPTrFytwUTVUO4XlrGIvyqHv14ZVmBM8UCMo6
yVNA9HEBW62/b8W+Z3BtCBTuBnkRk3Wka8qhMMbqOe8kl/1vQtTKQkaDdnXaShUs
18mfDHjLZhcIrJEwbtPvo9Xpf+IWEZeoiRzEqa30n70iZTkPEVv/GxNVmJ74XYH/
Xa/vMWI/sxtXKtKY60XBXXCEVMuyxR+vfIbJOpDCcFlKyWHiXPEdYh2Ac8Bs1hc7
bk+lolw8FEWISrFdUwYdOrfRr4CMW+h2CYzgZsDKKYrVn+hRUy5mVOL1QXZJbNJJ
wr9O/JrUbXAMGdhtLuRUwM4tsPgMF2+cTLMe+wuFzUjWBBNiqb8GKJP2K94hdurD
+VMd/p/TtU02M23ooysu2mft5RCmD0/QbP8yxEACbHg=
Signature digestsha512
Dependencies
Required Nextcloud versions >=31.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.6.0
Release Details
UpdatedAug. 28, 2026, 2:34 p.m.
Changelog

Achtung: Diese Version setzt Nextcloud 31 oder neuer voraus. Die bisherige Untergrenze war Nextcloud 28. Mit dem Umstieg auf @nextcloud/vue 9 — unvermeidbar, weil Vue 2 seit dem 31.12.2023 End-of-Life ist und keine Sicherheitskorrekturen mehr bekommt — fällt die Unterstützung für Nextcloud 28, 29 und 30 weg. Installationen auf diesen Versionen bekommen das Update nicht angeboten und bleiben auf 1.5.4; sie werden von dort nicht weiter gepflegt. Wer die App weiter nutzen möchte, aktualisiert zuerst den Nextcloud-Server auf mindestens Version 31 (max-version bleibt unverändert 34).

Changed

  • Das Frontend läuft auf Vue 3.5 statt Vue 2.7 (Issue #150). Vue 2 ist seit dem 31.12.2023 End-of-Life und bekommt weder Sicherheits- noch Fehlerkorrekturen; die Nextcloud-Server-Generation, gegen die die App freigegeben ist, hat ihren Frontend-Stack längst auf Vue 3 umgestellt. Mit umgestellt sind @nextcloud/vue 8 → 9, @nextcloud/dialogs 6 → 7, Pinia 2 → 3 und @nextcloud/webpack-vue-config 5 → 7; die dreizehn Build-Pakete, die das Webpack-Preset ab Version 7 als peerDependencies erwartet (webpack, vue-loader, sass, babel-loader …), stehen jetzt explizit in den devDependencies. npm audit --omit=dev meldet damit 0 statt 14 Befunde — die vier an Vue 2 hängenden Advisories (vue, vue-template-compiler, vue-resize, vue2-datepicker) waren ohne diese Migration nicht auflösbar
  • appinfo/info.xml fordert jetzt Nextcloud 31 statt 28 (max-version bleibt 34). @nextcloud/vue 9 lässt die Unterstützung für Nextcloud vor 31 fallen; das ist die unvermeidbare Gegenleistung der Migration. Installationen auf Nextcloud 28–30 bleiben auf Version 1.5.4
  • Die drei Einstiegspunkte src/main.js, src/admin.js und src/dashboard.js erzeugen ihre Anwendung über createApp() statt new Vue(); Pinia wird als Plugin registriert (app.use(pinia)), das Weiterreichen der Store-Instanz an das Vanilla-Detailmodal per setActivePinia() bleibt unverändert. Die Vue.prototype-Zuweisungen im Dashboard-Einstiegspunkt sind entfallen — DashboardWidget.vue importiert t ohnehin selbst
  • Anpassungen in den 17 Komponenten an die API von @nextcloud/vue 9: Import-Pfade (@nextcloud/vue/components/NcButton statt @nextcloud/vue/dist/Components/NcButton.js), type="primary"variant="primary" bei NcButton/NcActions, NcActionCheckbox und NcSelect auf modelValue (:checked/@update:checked bzw. :value/@input sind entfallen), :shown.syncv-model:shown bei NcPopover. Dazu die Vue-3-Umstellungen im eigenen Code: beforeDestroy()beforeUnmount() in GanttTable.vue, ResourceGrid.vue und GanttChart.vue (siehe Issue #149), this.$set()/this.$delete() durch direkte Zuweisung bzw. splice() ersetzt
  • css/main.css und der zugehörige Util::addStyle()-Aufruf im PageController sind entfallen. Die Datei enthielt einzig #content { margin-top: 0 !important } gegen eine Doppelmarge, die NcContent unter @nextcloud/vue 8 zusätzlich zum Nextcloud-Layout gesetzt hat. Unter Version 9 gibt es diese Marge nicht mehr, der Reset schob die App stattdessen um die Höhe der Kopfzeile nach oben — die Navigationsleiste lag dadurch unter dem Nextcloud-Header und war nicht mehr anklickbar. Der Mount-Punkt #nc-gantt-app bleibt als Wrapper im DOM stehen (Vue 3 rendert in das Element hinein, statt es wie Vue 2 zu ersetzen), nimmt aber nachgemessen exakt die Maße des Content-Bereichs an und braucht keine eigene Regel
  • ESLint nutzt das Preset @nextcloud/eslint-config/vue3. Es lässt vue/custom-event-name-casing auf dem Vue-3-Default (camelCase) laufen, während das Vue-2-Preset kebab-case erzwungen hat; da der Bestand durchgängig kebab-case verwendet — unter Vue 3 gleichermaßen gültig — setzt .eslintrc.js die Regel explizit auf kebab-case
  • Der <style>-Block in GanttChart.vue war mit 581 Zeilen ungescopt und wirkte damit auf die gesamte Nextcloud-Oberfläche statt nur auf die Komponente (Issue #151). Die 65 eigenen .nc-gantt-*/.nc-*-Regeln laufen jetzt über <style scoped>, mit :deep() dort, wo Overlays ihre Elemente per createElementNS() bzw. innerHTML außerhalb des Vue-Templates in .nc-gantt-container einhängen. Die Regeln, die auf frappe-gantt-eigene Klassennamen zugreifen (.gantt .bar & Co.), liegen gebündelt in src/vendor/frappe-gantt/theme.css direkt neben dem vendorten Quellcode der Bibliothek und werden von dort per index.js importiert; die beiden nicht unter .gantt verankerten Selektoren (.bar-wrapper.gantt-milestone .bar-label/.handle) sind dabei korrigiert. In App.vue laufen die drei Core-Überschreibungen (.app-navigation__content, #app-settings, .app-navigation .app-navigation-list) ebenfalls über :deep() in einem scoped Block. Abgesichert ist das durch vue/enforce-style-attribute aus eslint-plugin-vue, das ab sofort scoped für jeden <style>-Block in src/ erzwingt
  • TaskService bündelte auf 774 Zeilen drei Verantwortlichkeiten und brauchte dafür acht Konstruktor-Abhängigkeiten; der Schnitt trennt sie (Issue #153). TaskSchedulingService übernimmt Constraint-Propagation über EA/AA/EE/AE mit Lag, Kahn-Sortierung, Arbeitstagsrechnung, Zyklenprüfung und What-if-Simulation — CriticalPathService wird dort regulär injiziert, statt simulate() als Methodenparameter durchgereicht zu werden. TaskResourceAssignmentService übernimmt Auflösung und Persistierung der Ressourcenzuordnung inklusive MAX_TASK_RESOURCES und PT-Umrechnung. TaskService bleibt als CRUD-Fassade mit Berechtigungsprüfung, Validierung, Änderungsprotokoll und API-Aufbereitung: 311 statt 774 Zeilen, sieben statt acht Abhängigkeiten. Die Methodenrümpfe sind unverändert verschoben, es ändert sich keine Terminlogik. TaskServiceTest ist entlang derselben Grenzen aufgeteilt (TaskServiceTestCase als gemeinsame Basis, dazu TaskSchedulingServiceTest mit 39, TaskResourceAssignmentServiceTest mit 8 und TaskServiceTest mit 11 Fällen — exakt der bisherige Umfang), wobei die ausgelagerten Services weiterhin über ihren Aufrufer TaskService angetrieben werden, damit neben der Rechnung auch die Verdrahtung zwischen Fassade und Engine abgedeckt bleibt
  • Die 212 Zeilen CSS der Vanilla-Detaildialoge wurden zur Laufzeit als <style> in den <head> injiziert (src/detail/styles.js); sie liegen jetzt als src/detail/detail.css vor und werden von Webpack eingebunden (Issue #152). Der im Kopfkommentar genannte Grund — nicht von der Loader-Konfiguration abhängen zu wollen — trifft seit dem Vendoring nicht mehr zu, src/vendor/ importiert .css und .scss ebenfalls direkt. Dabei fiel auf, dass das Stylelint-Glob unquoted an die Shell ging und ohne globstar nur eine Verzeichnisebene traf: weder src/App.vue noch eine .css in src/vendor/ wurde je geprüft. Mit Quotes globbt Stylelint selbst; die dadurch aufgedeckten Findings in App.vue sind mitbehoben
  • Die PHP-Einrückung ist auf Tabs vereinheitlicht (Issue #170). nextcloud/coding-standard erwartet Tabs, die Codebasis nutzte durchgehend vier Leerzeichen — composer cs:check beanstandete dadurch 144 von 146 Dateien, der CI-Job wäre ab dem ersten Lauf dauerhaft rot und als Gate wertlos gewesen. Ursache der Drift war ein falscher Kommentar in .editorconfig, der dem Coding-Standard vier Leerzeichen unterstellte; der ist mitkorrigiert. Die Änderung ist rein mechanisch (php-cs-fixer fix): Einrückung, Klammern um einzeilige if-Rümpfe, sortierte use-Blöcke und einfache statt doppelte Anführungszeichen, wo keine Escape-Sequenz im Spiel ist. Der Commit steht in .git-blame-ignore-revs, damit git blame weiterhin die inhaltlich letzte Änderung einer Zeile zeigt

Added

  • appinfo/info.xml wird jetzt automatisch gegen das App-Store-Schema geprüft, statt den Fehler erst beim Upload zu erfahren: scripts/validate-appinfo.js (npm-Script validate:appinfo) validiert gegen die eingecheckte Schema-Kopie tests/fixtures/info.xsd — per xmllint, ersatzweise über lokales php oder das composer:2-Image — und prüft zusätzlich Semver-Format, Gleichstand mit package.json und den CHANGELOG-Abschnitt zur Version. release.sh ruft das als erstes Gate mit --online auf, lädt das Schema dabei frisch und meldet, wenn die Kopie veraltet ist
  • tests/Unit/AppInfoXmlTest.php führt dieselbe Schema-Validierung in der Testsuite aus (DOMDocument::schemaValidate()) und gleicht zusätzlich die Übersetzungen in l10n/ gegen die Store-Texte ab: gettext-Codes wie pt_BR werden als solche erkannt, und zu jeder übersetzten Sprache müssen <name>, <summary> und <description> in info.xml existieren
  • Die Stunden je Personentag sind konfigurierbar (Issue #169). Der Umrechnungsfaktor lag dreifach hartkodiert vor (TaskResourceAssignmentService, ResourceUtilizationService, ResourceGrid.vue) und wurde über gegenseitige Kommentarverweise von Hand konsistent gehalten — eine feste 8-Stunden-Annahme passt aber nicht zu jedem Arbeitszeitmodell. Der Wert liegt jetzt an genau einer Stelle: WorkTimeService liest ihn als App-Config-Wert hours_per_pt (Standard 8), validiert ihn gegen 1..24 und fällt bei unplausibel gespeicherten Werten auf den Standard zurück, damit die Auslastungsrechnung nicht durch 0 teilt; in ResourceUtilizationService entfällt damit auch die Konstante DEFAULT_CAPACITY_H, die denselben Vollzeit-Referenzwert doppelt hielt. Ins Frontend kommt der Faktor über den Initial State des PageController, sodass er schon beim ersten Rendern des Ressourcen-Rasters bereitsteht; GET/PUT /settings liefern und setzen ihn zusätzlich, wobei ein PUT ohne hours_per_pt den gespeicherten Wert unverändert lässt, damit ältere Clients ihn nicht auf den Standard zurücksetzen. Gepflegt wird er im Admin-Bereich neben Arbeitsbeginn und -ende
  • Die Vanilla-Detaildialoge sind für Screenreader und Tastatur verdrahtet (Issue #152): Die Dialoge verweisen über aria-labelledby auf ihre Überschrift, section() verknüpft Beschriftung und Bedienelement (bei Gruppen über role="group"), Knöpfe ohne Text bekommen einen Namen, Umschaltknöpfe melden ihren Zustand über aria-pressed, und die Datums-Plausibilitätsmeldung hängt per aria-describedby am Feld statt nur im title-Attribut des Icons zu stehen. Der Fokus beginnt beim Öffnen im Formular statt auf dem Schließen-Knopf und kehrt beim Schließen zum Auslöser zurück. Abgesichert durch payload.test.js (19 Fälle für Speicher- und Löschlogik) und accessibility.spec.js (6 E2E-Fälle) — für DOM-Code ist der E2E-Lauf die tragfähigere Absicherung als eine neue jsdom-Abhängigkeit. src/detail/README.md erklärt, warum das Modul außerhalb von Vue steht und welche Regeln daraus folgen; CONTRIBUTE.md verweist darauf
  • Die CI läuft. Der Workflow lag unter nc_gantt/.gitea/workflows/ci.yml und war eine reine GitHub-Actions-Datei; vier voneinander unabhängige Gründe verhinderten, dass davon jemals etwas ausgeführt wurde (Issue #170): Forgejo liest Workflows ausschließlich im Repo-Root, runs-on: ubuntu-latest passt auf kein Codeberg-Label (die gehosteten Runner heißen codeberg-tiny/-small/-medium), die Kurzform shivammathur/setup-php@v2 wird gegen Forgejos Action-Host aufgelöst, wo es die Action nicht gibt, und die Repo-Einheit „Actions" war deaktiviert. Die Datei liegt jetzt unter .forgejo/workflows/ci.yml, die App bleibt via defaults.run.working-directory erreichbar. Inhaltlich sind php-lint und php-tests zu einem Job zusammengefasst und laufen beide über die volle Matrix 8.1/8.2/8.3 (vorher lief PHPUnit nur auf 8.2, obwohl composer.json >=8.1 fordert), die Syntaxprüfung nutzt xargs statt find -exec (find liefert seinen eigenen Exitcode, nicht den von php -l — der Schritt konnte gar nicht fehlschlagen), und der JS-Job führt neu vitest mit 180 bislang nie automatisiert gelaufenen Tests aus, dazu validate:appinfo und l10n:check. paths-ignore hält die geteilten Codeberg-Runner von reinen Doku- und Screenshot-Änderungen frei

Fixed

  • Nach der Migration auf @nextcloud/dialogs 7 erschienen Statusmeldungen wie „Einstellungen gespeichert" als unformatierter Text oben links statt als Badge. Version 7 hat Toastify durch eigene Vue-Komponenten ersetzt, deren Styles nicht mehr im JS-Bundle stecken, sondern über den separaten Export @nextcloud/dialogs/style.css eingebunden werden müssen; ohne diesen Import lief der Toast-Container ungestylt im normalen Dokumentfluss mit. src/main.js importiert das Stylesheet jetzt. Die Toasts erscheinen dabei an der neuen Standardposition der Bibliothek unten links neben der Navigation statt wie früher oben zentriert — Version 7 bietet dafür keine Option mehr
  • testBuildIcsStripsCarriageReturnToPreventLineInjection prüfte das gesamte ICS-Dokument auf Freiheit von \r. RFC 5545 trennt Zeilen aber genau damit, und buildIcs() setzt sie korrekt als CRLF — der Test konnte nie grün sein und schlug auf main dauerhaft fehl. Der Schutz selbst greift; nur die Assertion war zu weit gefasst. Geprüft wird jetzt, was die Line-Injection tatsächlich ausschließt: kein einzelnes CR außerhalb der CRLF-Zeilentrenner, der eingeschleuste Titel erzeugt keine eigene ICS-Zeile, und er landet escaped im SUMMARY-Wert. Gegenprobe mit entfernter CR-Normalisierung in escapeText() schlägt weiterhin fehl, der Schutz bleibt also scharf getestet. Dass der Fehlschlag so lange unbemerkt blieb, lag daran, dass die Workflows nicht ausgeführt wurden (siehe Issue #170)
  • validate:appinfo brach im ersten CI-Lauf mit einer Meldung über einen nicht erreichbaren Docker-Socket ab (Issue #170). Die Validator-Kette in scripts/validate-appinfo.js probiert xmllint, dann php, dann docker und nimmt den erstbesten verfügbaren — „verfügbar" hieß dabei aber nur, dass das Binary existiert. Das Runner-Image bringt die docker-CLI mit, ohne dass ein Daemon erreichbar wäre, und hat weder xmllint noch php. isAvailable prüft jetzt, ob der Validator wirklich läuft (docker info statt --version), sodass die Kette korrekt durchfällt und bei gänzlich untauglicher Umgebung „Kein Schema-Validator gefunden" meldet statt eines Socket-Fehlers; zusätzlich installiert der JS-Job libxml2-utils, damit im CI immer xmllint gewinnt — der native XSD-Validator, ohne Daemon und ohne Netzwerk. Welcher Validator läuft, hing zuvor davon ab, was auf der Maschine zufällig installiert war
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturegDK8JkRgxBUCFljhxHFzTzf37tjhwQ/k9E+DCDeVHxPECDOF0J3FbWmv2uqmm9R7
H8yyFfL/KFEDK3Jt24o2gujQZ9KlyBYJvrfwv//zvACtgGoErBUamME+FzFfK3x8
rRdXt1iXctmwutRvTNPj8uvfMJmo/vdbJRDGEihI/9wVdt4S+O3/OlpdjUg+QGFP
cMmlQwIAHAWrYSUllnN4GeryrFPGB7fLi/Nrhx0eAwQHUjIZHEb/s9ZxjmnYZd0c
8FJsgAUXfjowOIrDtWxr0P+HVj4c5qhGx4XEUFdfR0slriaL+zPbo2Li1wgsBA7r
+yoo8ocOJPaN3iCpRNL4z8q2sxEuWRt2Dx0I5ck6F7g+gpzDoTo5bFEvq4Eir0wN
lGHhyxcdEK653dTKOBYI07tCjJYU+9VxCbRzR7O+sVI412Tox5W5cYGl4WpN8aNH
00CX7PLaruaEjwuFdAvhY6SzsXA3RFmN3Dv9qFx3dl3HjoQ+OCqy89XzT3tbBN07
3aZO7OgyB26al2XdRFaaRQaVLqjJzUCz2B5nh+z9+L+QcBl3F9sE2sFZnkWwx3bp
MOdj2nCS11r3Z0utRI9uDEanys6HkqnpGed4WEGX9O+EfocqNg2b0wgyqjFNWbxI
n4uoeakhyWYOVHCUfzU8tn6kmU4b8n+GfpMjKPhBeRw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=31.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.4
Release Details
UpdatedAug. 27, 2026, 7:06 p.m.
Changelog

Fixed

  • appinfo/info.xml wurde vom Nextcloud App Store abgelehnt: der Sprachcode pt_BR in <name>, <summary> und <description> ist im Schema nicht enthalten — die Enumeration kennt nur BCP-47-Schreibweise in Kleinbuchstaben mit Bindestrich. Alle drei Vorkommen heißen jetzt pt-br
  • Die Kindelemente von <info> sind im Schema eine feste Sequenz; <settings> stand vor <dependencies> und wäre nach dem Sprachcode-Fix als nächster Validierungsfehler aufgeschlagen. Der Block steht jetzt an der vom Schema vorgesehenen Position hinter <dependencies>. xmllint --schema gegen https://apps.nextcloud.com/schema/apps/info.xsd läuft damit sauber durch
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureYbjiEkGYW1s8Xg9Jvrt4nNo/67zkrQDA16yfK2MzVa58R982qrLUupNbvUE/FscP
pFg9nlqxd81cpyH1ZhWOM7fMq98mPyjSUsJZ7xjYzNccF13xvDpBXFlfX4UyCknc
50Rmw9a8RxiCH0mEpH9zWjdanX194R8cUIMDY+BcymCgyBVRQub9yaL5iiHH3hNA
OOD+UOiSUNHns9R6sgZ+tF4OeoTufWR5//AfRmuL5qC5spyuP1iKr7FnzPar+/sS
pHKojfUyi0sAjlrThVZDo8fvVPqkkH4jgvVmNE41t1UOlVdajIRd2yhbHX0h0SSs
rmt4CQqNXAjLE/Wlq2lu9Viw4M2BhhPIfVb5YJFzaxjhB8RRy53rquXRL64f7vGa
agq0ri3eD+0ZWmMOlJmHaMv6AXYd0ZG8myb3PAyNC0NYXzrw2PAVL8jDfzmq2cNY
Q3rIh101vtGPytqanNS2VmtfZ8BX63rd4SLR4PJdRYrm3Wbqanx8WZa20eLgYF8S
M9xhxl5Jf8+TnYLwHi1sGm1ID2XJ4krfgOxiUlB8lGeSweUK1uueC0bmUDsrXyhJ
RMGST41TU1HqXx/3Eeh91JKq/Jbx15kPuxu7WNKyuSOj4vKbgFwBUSmHKDU6lvEZ
L/bnxZi965/4K3kvyJ8o2j5e4xUmJLeusi9Fg0yrRqE=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.2
Release Details
UpdatedAug. 26, 2026, 5:18 p.m.
Changelog

Changed

  • Teilen-Dialog: das Eingabefeld für den einzuladenden Nutzer ist jetzt ein Suchfeld statt eines reinen Textfelds für die Benutzer-ID (Issue #144). Getippt wird nach Anzeigename, Benutzer-ID oder E-Mail-Adresse; ein neuer, admin-unabhängiger Endpunkt GET /api/v1/users/search (UserController::search(), IUserManager::search(), max. 20 Treffer, der eigene Account wird ausgeblendet) liefert dazu Anzeigename, Benutzer-ID und E-Mail als Vorschlagsliste. Gespeichert wird weiterhin die Benutzer-ID als principal_id – für Umgebungen mit LDAP/AD-Benutzerverwaltung war die zufällig generierte ID zuvor nicht ohne Umweg über die Benutzerverwaltung in Erfahrung zu bringen. Die Liste bereits geteilter Zugriffe zeigt ebenfalls den Anzeigenamen statt der rohen ID (ShareController::index() reichert die Antwort um display_name an, Fallback auf principal_id falls der Account inzwischen gelöscht wurde)
  • Übersetzungen für alle sechs Sprachen ergänzt
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureyLn/jlYbk3gIYfgIcjON0z467/xL9L6QNcmfgOa/4zhTJjLknXq7eu1UJddWWlLJ
NG2U9d/OEFO9wLHPYPGNiWgQMRIk+TGYlQVTXcZH3WpBxdJOm3XMnk5hq2kNB2FN
TJemqr/dxafGB2hTIgivPMXMnemdrtxWN1RAdzCxZIg9HwJWjG5JxdqHmURHwske
p/Ki/iZghKjrxbPIghbqtrvkCJRImbgVWY8AmUNUPLgotNIthiWFnkTDVhYWcreP
pWleWHxEn57UOtehff1aJa+hRI+8WVkx9iXArx0SThmOCYYgJ/HeG8dOOtmr9jSm
1nzETAL87YLxL/+qM6DyBIgNWhrq1oj9Q12bBm1+la477z6fpOgUlMjWkPEYRQi/
vhxirXwB4BZBYvaMEkNlN2U3+7BqgigGoaTcbN2rG/TP1JuOjdj9jEjMMRye0JbT
35XOoM/VPYGovrT9slHg8r3Wolyd8ioXVOu4IcMImvC5OrTzpKY7NLEc/S+cOKwz
ijOKcnoV0j++KxtQKKgEO96HJpEM0jteQVOGCoPbghjS3OFzkiB1bUVJAlu1jn54
38Q2zw8rZ0EMm1rEPmIrl72DIIXionbWKatREgy7QPwuL/WKZ2c+J1UIUTKck5eO
7M2VHh6P3FnIg/UsOCMu3U7ja0Y8vQ3YUo3tazLfob0=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.1
Release Details
UpdatedAug. 25, 2026, 1:28 p.m.
Changelog

Added

  • Screenshot des gerenderten Gantt-Charts als PNG, SVG oder PDF (Issue #116): ein neuer „Screenshot"-Eintrag in der Chart-Toolbar öffnet ein Menü mit den drei Formaten, derselbe Export steht im Bearbeiten-Dialog des Projekts neben JSON und CSV bereit (dort mit vorgeschalteter Formatwahl statt Menü, openScreenshotFormatDialog()). Exportiert wird stets das gesamte Chart, nicht nur der sichtbare Scroll-Ausschnitt — frappe-gantt rendert die volle Breite und Höhe ohnehin als eine SVG. PNG und SVG klonen die aktuell gerenderte SVG und schreiben getComputedStyle() als Inline-Attribute (löst auch CSS-Variablen auf), sodass die Datei ohne das App-Stylesheet eigenständig darstellbar ist; sie folgen dem eingestellten UI-Theme, ein hinterlegtes Rechteck in --color-main-background deckt dabei auch die Fläche unterhalb der Aufgabenzeilen (Workload-Chart, Leerraum) ab, die sonst transparent bliebe. PNG rastert per Canvas mit doppelter Auflösung
  • Zeitraum-Auswahl für den PDF-/Druck-Export (Issue #116): vor dem Drucken fragt ein Dialog, welchen Zeitraum die PDF abdecken soll — gesamter Projektzeitraum (Vorbelegung), laufendes Kalenderjahr, „aktives Quartal" (Vormonat bis einschließlich übernächstem Monat) oder ein frei eingegebener Bereich. Der Vorschlag ist der tatsächlich von Balken belegte Zeitraum, nicht gantt_start/gantt_end — frappe-gantt legt darum großzügig Puffer, der andernfalls mitgedruckt würde. Umgesetzt wird der Zuschnitt als viewBox auf dem SVG-Klon; die dafür nötige Skala (Chart-Start, Pixel pro Millisekunde) schreibt GanttChart.vue nach jedem Render als data-Attribute an den Chart-Container, sodass auch Aufrufer ohne Zugriff auf die frappe-Instanz (Bearbeiten-Dialog) sie lesen können. Die Zeitraum-Logik steckt isoliert testbar in src/gantt/printRange.js (src/gantt/printRange.test.js)

Changed

  • Der PDF-Export druckt nicht mehr den Live-Container, sondern einen gestylten, selbst gerasterten Klon des Charts (Issue #116). Bisher wurde das Inline-SVG direkt gedruckt — wie fein die Browser-Engine das rastert, ist nicht steuerbar und fiel je nach Browser sichtbar grob aus. Jetzt wird der Klon mit 300 dpi bezogen auf die bedruckbare Fläche (A4 quer, 10 mm Rand → 277 × 190 mm) in ein Canvas gerastert und als Bild mit fest vorgegebener physischer Größe in den Druck gegeben; schlägt die Rasterung fehl, bleibt der SVG-Klon als Druckinhalt übrig und skaliert per CSS auf die Seitenbreite. Der Klon wird immer im hellen Theme berechnet (Papier ist weiß, ein dunkles UI-Theme ergäbe sonst dunkelgraue Flächen und helle Schrift) — dafür genügt ein ausgelagerter Container mit gesetztem data-theme-light, da Nextcloud die Stylesheets aller Theme-Varianten lädt und nur über dieses Attribut umschaltet. Das Ausblenden der übrigen Seite läuft über display: none statt visibility: hidden, sonst blieb die Fläche der App als Leerseiten erhalten; Nextclouds Hintergrundbild auf html/body wird für den Druck abgeschaltet. Aufgeräumt wird über afterprint mit Timeout-Fallback für Browser, die das Event nicht feuern
  • Der Toolbar-Eintrag heißt „Screenshot" (Icon MonitorScreenshot) statt „Export" (Icon ExportVariant) — „Export" ist im Projekt bereits für den Daten-Export nach JSON/CSV belegt, der Chart-Export ist demgegenüber eine reine Abbildung der aktuellen Darstellung
  • Übersetzungen für alle sechs Sprachen ergänzt
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
Signaturek6kpvF53IR8tnkOFXyoSPFPGlwVzO/RUTgI1p1ppRcFmoFPUyFeIokOqWA1OtD9q
wdo+qkQQPyJGph0Uwp+hwP9oGmeKWErnlv8HMdA5I5iaXIN7afGvdfxWfKgqWetw
tGmCF7l2IzMmT2Ol/3pKgCnFkXTDPCVeNINNbUdi7EjeRpbcbOGWt3+5UVwZgVTX
Z9/kEEPvjMV98s1zT5yBXcFvyqZA7bhhezmBkfzaLa0DAIczFJbhyFtR06WuS7bP
CWBCs/xvSRuCwo61oyXRAWLohz/2GsrMSa5jvPvnEG1XEHpGPVorCijAvsBm4sX5
yAZTrBm3zbNYObqVE2idxTH/eqP8xXtE38JFjpG5IahpeFNb9V2EbH1nrjfRKYcH
NVvXcXFREAmvorShKDE0ymFN+/BCjvU1vnJCnRD5RMsoSGUzXSVHPrF1emtusLHj
ltP22eYOCpraEpZheTkFftqvpbiQKVXsZ+8wY4dJnh5Ymi71loxZhggoH8s/pmp+
WbSx6MZwSPBqJ0HOJWckFiZXur2OQYOVLfXt8uPYNU/EZSoYDqm81GVMglQXxyM6
YDh0xXqwJ7Qft7k0O/3Fa5YLJGP4B4RvjU29N3/WDsfjuk7PeCSTPhRlTOfV/Fbn
jS83WVBavmyklhu0rNYuCYfdYvUxemIO3VuGmYzFXgI=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.0
Release Details
UpdatedAug. 24, 2026, 5:26 p.m.
Changelog

Added

  • Editierbare Vorgänger-Spalte in der Tabellenansicht, Teilschritt F von #117 (Issue #124): eine neue, über das Spaltenmenü einblendbare Spalte „Vorgänger“ zeigt die Abhängigkeiten einer Aufgabe in der aus MS Project bekannten Kurznotation (12EA+2d = Vorgänger Aufgabe 12, Ende-Anfang, zwei Arbeitstage Abstand; mehrere durch ; getrennt) und nimmt sie dort auch entgegen. Typ (EA/AA/EE/AE, englische Kürzel FS/SS/FF/SF werden beim Eingeben mit akzeptiert) und Abstand sind optional, 12 allein bedeutet also EA ohne Abstand. Geprüft wird beim Verlassen der Zelle: Syntax, Existenz der Aufgabe im selben Projekt, Selbstbezug, Dubletten und Kreisschluss über die gesamte Abhängigkeitskette – bei einem Fehler bleibt die Zelle im Bearbeitungsmodus und nennt den Grund im Klartext, die bisherigen Abhängigkeiten bleiben unangetastet. Gespeichert wird über dieselbe PUT /tasks/{id}-Route wie der Detail-Dialog (inkl. dep_mode), sodass der Server die Termine anwendet und durch die Nachfolgerkette propagiert; Balken, Pfeile und Typ-Labels im Chart zeichnen sich mit der Antwort neu. Bewusst ohne Undo-Toast, da ein Zurücknehmen nur der Termine (nicht der Abhängigkeit) beim nächsten Neuberechnen wieder überschrieben würde. Nur Aufgaben haben eine editierbare Zelle – Meilensteine hängen über task_id an genau einer Aufgabe, Projekte und Teilprojekte sind berechnete Strukturebenen. Notation und Prüfungen stecken isoliert testbar in src/gantt/dependencyNotation.js (src/gantt/dependencyNotation.test.js)
  • Zeitabstand (Lag/Lead) je Aufgaben-Abhängigkeit (Issue #124): neue Spalte lag_days in nc_gantt_task_deps (Version1032; der Name vermeidet das seit MySQL 8.0 reservierte Wort LAG und nennt die Einheit). Der Abstand zählt in Arbeitstagen über den Ressourcenkalender wie die übrige Terminberechnung, wirkt bei allen vier Abhängigkeitstypen auf deren Ankertag und darf negativ sein (Lead: der Nachfolger beginnt früher). Bestandsabhängigkeiten bekommen 0 und verhalten sich unverändert. TaskService::update() weist eine gesendete Vorgängerliste jetzt vollständig zurück (invalid_dependency, dependency_cycle), bevor die bisherigen Abhängigkeiten dafür gelöscht werden, statt Vorgänger aus fremden Projekten oder Zyklen zu speichern – letztere hätten die topologische Sortierung in recalculateProject() stillschweigend Aufgaben überspringen lassen

  • Konfigurierbare Spalten in der Tabellenansicht, Teilschritt E von #117 (Issue #122): ein Menü in der Tabellenkopfzeile blendet Spalten ein und aus, die Reihenfolge lässt sich per Drag & Drop der Kopfzellen ändern (barrierefreie Alternative: Strg+Pfeil links/rechts auf der fokussierten Kopfzelle), die Breiten per Ziehen am Spaltentrenner (Doppelklick setzt auf die Standardbreite zurück). Zusätzlich zu den bisherigen Spalten (Titel, Start, Ende, Fortschritt) stehen ID, Dauer (Kalendertage inkl. Start- und Endtag, bei Meilensteinen 0), Status (Issue #78, nur Aufgaben/Teilprojekte) und Ressource (Issue #103, zugeordnete Ressourcennamen einer Aufgabe) bereit – alle vier als reine Anzeigespalten, die das Inline-Editing und die Tastaturnavigation daher überspringen. Auswahl, Reihenfolge und Breiten werden pro Nutzer über den in Teilschritt B angelegten UI-Preferences-Endpunkt persistiert (neuer Key gantt_table_columns, kein Schema- oder Endpunktwechsel nötig); eine gespeicherte Konfiguration wird beim Laden validiert, sodass entfernte Spalten oder unplausible Breiten die Ansicht nicht beschädigen können. Die Tastaturnavigation folgt jetzt der sichtbaren Spaltenreihenfolge statt einer festen Liste. Reicht die Tabellenbreite für die gewählten Spalten nicht aus, scrollen Kopfzeile und Zeilen gemeinsam horizontal; die Obergrenze des Splitters steigt dafür von 560 auf 900 px. Die Spaltenlogik steckt isoliert testbar in src/gantt/tableColumns.js (src/gantt/tableColumns.test.js). Ein Sortieren der Zeilen nach Spaltenwert ist bewusst nicht enthalten – es kollidiert mit der Hierarchie Projekt → Teilprojekt → Aufgabe und der sort_order, die das Chart für dieselbe Zeilenreihenfolge braucht

  • Tastatur-Navigation in der Tabellenansicht, Teilschritt D von #117 (Issue #121): Tab/Shift+Tab springen zur nächsten bzw. vorigen editierbaren Zelle (überspringt Zeilen ohne Schreibrecht, springt am Zeilenende zur nächsten/vorigen Zeile), Enter speichert und springt in dieselbe Spalte der nächsten Zeile, Esc bricht ab und stellt den vorigen Wert wieder her. Pfeiltasten bewegen die Zellauswahl, wenn gerade keine Zelle im Editiermodus ist (innerhalb einer Zelle bleiben sie für Cursor-/Wertänderung nutzbar). Die reine Traversierungslogik steckt isoliert testbar in src/gantt/tableNav.js (src/gantt/tableNav.test.js). Die ausgewählte Zelle bekommt einen sichtbaren Fokusrahmen und wird per scrollIntoView() ins Sichtfeld gescrollt – über den bestehenden bidirektionalen Scroll-Sync (Issue #119) folgt das Gantt-Chart automatisch mit. Neue ARIA-Rollen (grid/row/columnheader/gridcell, aria-readonly je Zelle) machen die Tabelle für Screenreader als Grid erkennbar
  • Read-only Tabellenansicht links vom Zeitstrahl, Teilschritt B von #117 (Issue #119): neue Komponente GanttTable.vue zeigt dieselben Zeilen wie das Chart (Titel mit Einrückung nach depth, Startdatum, Enddatum, Fortschritt), gespeist aus buildRowModel()/buildTableRows() (siehe Teilschritt A, Issue #118) – Reihenfolge, Filter-Dimming, kritischer Pfad und Projektfarben bleiben so exakt konsistent zum Chart. Zeilenhöhen sind fest an frappe-gantt gekoppelt (40 px = bar_height 22 + padding 18, Kopfzeile 52 px = header_height). Ein Toolbar-Button blendet die Tabelle ein/aus, ein Splitter macht die Breite verstellbar (160–560 px), vertikales Scrollen ist bidirektional mit .nc-gantt-container synchronisiert. Sichtbarkeit und Breite werden pro Nutzer über einen neuen, generischen UI-Preferences-Endpunkt (GET/PUT /api/v1/ui-preferences, SettingsController über IConfig::get/setUserValue() als JSON-Blob) persistiert, damit Teilschritt E (Editieren) das Schema nur noch um weitere Keys erweitern muss, ohne Endpunkt oder Speicherformat anzupassen. Rein lesend – Editieren folgt in Teilschritt C
  • Projekt-Export/-Import (JSON, format_version: 2) kann jetzt optional die von den Aufgaben referenzierten Ressourcen inkl. Gruppe, Wochenmodell, Arbeitskalender+Feiertagen und Tageskapazitäten mitnehmen, statt wie bisher nur die rohe resource_id in eine Zieldatei zu schreiben, die dort ungeprüft übernommen wurde – auf einem System ohne identische Ressourcen-IDs ging die Zuordnung damit verloren oder landete schlimmstenfalls bei einer fremden Ressource (Issue #115). Vor dem JSON-Download entscheidet ein Options-Dialog, was mitexportiert wird (Ressourcen / Verfügbarkeiten / Kalender, gestaffelt); vor dem JSON-Import zeigt ein passender Dialog, wie viele Ressourcen die Datei enthält, und lässt auswählen, was übernommen wird sowie ob bei Namensgleichheit die vorhandene Ressource wiederverwendet (Default) oder immer neu angelegt wird. Referenzen werden ausschließlich über eine Mapping-Tabelle aufgelöst und nie roh durchgereicht; nicht auflösbare Referenzen werden verworfen (Regressionsschutz zu #112/#113). Neu angelegte Ressourcen/Gruppen/Kapazitäten gehören stets dem importierenden Nutzer. Wochenmodelle/Kalender/Feiertage sind weiterhin admin-only anlegbar – ohne Adminrechte werden nur namensgleiche vorhandene Einträge gemappt. CSV bleibt unverändert aufgabenzentriert mit Ressourcen nur als ID-Referenz; der volle Ressourcenumfang ist JSON-only. Alt-Exporte ohne resources-Schlüssel importieren unverändert wie bisher, ohne Options-Dialog
  • Inline-Editing der Basisfelder in der Tabellenansicht, Teilschritt C von #117 (Issue #120): die Zellen für Titel, Start, Ende und Fortschritt sind direkt editierbar und aktualisieren die Balken im Chart sofort. Gespeichert wird über die bestehenden Store-Actions (updateTask/updateSubproject/updateMilestone/updateProject) inkl. Terminpropagation und dem vorhandenen Undo-Toast für Aufgaben (analog Drag & Drop im Chart); ein lokaler pendingEdits-Overlay zeigt die Änderung optimistisch an und rollt sie bei einem fehlgeschlagenen Request mit Fehlermeldung zurück. Die Schreibrechte löst tableRows.js je Feld über store.canEditProject() auf (titleEditable/startEditable/endEditable/progressEditable) – Projekte und Teilprojekte bleiben bei Datum und Fortschritt read-only, da diese Werte aus den Aufgaben berechnet werden. Geprüft wird: Titel nicht leer, Enddatum nicht vor Startdatum (Meilensteine ausgenommen, deren Start- und Endspalte dasselbe milestone_date zeigen) und Fortschritt 0–100. Im Simulationsmodus rufen Datumsänderungen an Aufgaben simulateTaskChange() statt einer echten Speicherung auf
  • Ressourcen-Überbuchungswarnung (Issue #82): die Kapazitätsplanung war bisher reine Datenerfassung ohne Abgleich mit dem tatsächlich verplanten Aufwand. Der neue Endpunkt GET /api/v1/resources/{id}/utilization?from=&to=&group= (ResourceUtilizationService/ResourceUtilizationController) stellt den geplanten Aufwand aus den Aufgaben-Ressourcen-Zuordnungen – gleichmäßig auf die Arbeitstage der Aufgabe verteilt, über WorkCalendarService mit ressourcenspezifischen Arbeitstagen und Feiertagen – der erfassten Tageskapazität gegenüber. Mehrfach-Ressourcen-Zuordnungen (Issue #103) samt Alt-Aufgaben werden berücksichtigt, ohne gepflegte Tageskapazität gilt ein Fallback von 1 PT/Tag. Im Ressourcen-Raster färben sich die Zellen nach Auslastungsgrad (> 90 % gelb, > 100 % rot) und der Tooltip zeigt geplante Stunden gegen Kapazität samt Aufschlüsselung nach Projekt und Aufgabe; das Workload-Chart im Gantt markiert überbuchte Perioden jetzt rot. Übersetzungen für alle sechs Sprachen ergänzt
  • Nachgetragen – beide Funktionen wurden bereits mit 1.4.2 ausgeliefert, waren dort aber nicht im Changelog dokumentiert:
  • Einheitliches Statusmodell für Teilprojekte und Aufgaben (Issue #78): neues Feld status (not_started/in_progress/blocked/done) auf nc_gantt_subprojects und nc_gantt_tasks ergänzend zum numerischen Fortschritt, Bestandsdaten leitet Migration Version1030 daraus ab. Validierung per StatusValidator (Whitelist analog ColorValidator), Status-Dropdown in den Detailformularen, blockierte Balken im Gantt schraffiert und mit Warnsymbol, blocked_count je Projekt im Rollup sowie ein Badge in der Projektliste
  • Mehrere Ressourcen mit individuellem Aufwand je Aufgabe (Issue #103): bis zu vier Ressourcen je Aufgabe mit eigener Aufwandsschätzung in der Einheit der Ressource (neue Tabelle nc_gantt_task_resources, Migration Version1029, Backfill aus den vorhandenen resource_id/work-Werten). Das manuelle Work-Feld entfällt: TaskService::resolveResources() summiert die Einzel-Aufwände zur Gesamt-Work (1 PT = 8 h) und übernimmt die erste Zuordnung als primäre resource_id, die weiterhin für Arbeitskalender und CPM maßgeblich ist. Ressourcen-Filter sowie CSV-/JSON-Export und -Import berücksichtigen alle Zuordnungen statt nur der primären

Changed

  • buildFrappeRows() (src/gantt/frappeRows.js) mischte bisher Datenmodell und frappe-gantt-Formatierung: die Einrückungstiefe steckte als Leerzeichen im name, Zustände (Dimming, kritischer Pfad, Summenbalken) hingen in custom_class – eine geplante Tabellenansicht neben dem Gantt-Chart (Issue #117) hätte dieselbe Logik duplizieren müssen (Teilschritt A, Issue #118). Neue Funktion buildRowModel() (src/gantt/rowModel.js) liefert dieselbe Zeilenliste jetzt als neutrales Modell (id, type, entityId, depth, title, start, end, progress, parentId, editable, matched, critical), resolveMilestoneDate() wandert mit ins Modell. buildFrappeRows() ist nur noch ein dünner Adapter darüber, der name/custom_class/dependencies wie bisher erzeugt. Reines Refactoring ohne sichtbare Änderung, per Fixture-Vergleich gegen die alte Implementierung geprüft; neue Unit-Tests (src/gantt/rowModel.test.js, npm run test:unit, via neu eingeführtem vitest) decken Hierarchie, Einrückungstiefe, Meilenstein-Datumsauflösung und Filter-Dimming ab

Fixed

  • Abhängigkeitsfortschreibung bei Aufgaben lieferte für alle vier Abhängigkeitstypen (EA/AA/EE/AE) einen um einen Arbeitstag zu langen Nachfolger-Termin – bei EA zusätzlich mit falschem Anschlusstag, da der Nachfolger auf dem Endtag des Vorgängers statt am folgenden Arbeitstag begann und dadurch mit dem Vorgänger überlappte (Issue #114). Ursache war eine Off-by-one-Vermischung zwischen der inklusiven Arbeitstagszählung und der exklusiven Datumsfortschreibung in TaskService::applyConstraint()/computeMultiConstraint(). Betroffen sind sowohl das direkte Setzen einer Abhängigkeit als auch die Terminpropagation nach Drag & Drop und die What-if-Simulation. Verhaltensänderung: Bestehende Pläne mit EA-Abhängigkeiten verschieben sich beim nächsten Speichern/Neuberechnen um einen Arbeitstag nach vorne (auf den korrekten Anschlusstag); bei AA/EE/AE verkürzt sich der zuvor fälschlich verlängerte Nachfolger-Zeitraum um einen Arbeitstag, die ursprüngliche Dauer bleibt jetzt garantiert erhalten. Abhängige Meilensteine (Dauer 0) sind unverändert korrekt und von diesem Fix nicht betroffen

  • Security: jeder Nutzer mit Schreibrecht auf ein eigenes Projekt konnte jede in der Instanz existierende resource_id einer eigenen Aufgabe zuordnen – unabhängig vom Eigentümer und ohne jede Share-Beziehung (Cross-Tenant-IDOR, Issue #112). TaskService::resolveResources() lud die vom Client gesendeten IDs bisher nur über ResourceMapper::findByIds(), also als reine Existenzprüfung ohne Berechtigungscheck; da die IDs fortlaufende Integer sind, waren sie trivial zu erraten. Der Listen- wie der Legacy-Einzelfeld-Pfad in create()/update() filtern referenzierte IDs jetzt über ResourceMapper::findVisibleToUser(), nicht sichtbare IDs werden wie unbekannte verworfen (Liste) bzw. nicht übernommen (Einzelfeld, der bestehende Wert bleibt erhalten). Regressionstests decken beide Pfade für create() und update() ab

  • Feiertage ließen sich nicht in mehreren Regionskalendern führen: POST /admin/holidays lief in einen HTTP 500, sobald dasselbe Datum in einem zweiten Kalender angelegt wurde, weil der Unique-Index aus Version1006 allein auf holiday_date lag, obwohl Feiertage seit Version1013 über calendar_id kalenderbezogen sind. Version1031 verschiebt den Index auf (holiday_date, calendar_id); die Eindeutigkeit globaler Feiertage sichert weiterhin der Upsert in HolidayAdminController::create(). Betroffen war neben der Feiertagsverwaltung auch der Kalender-Import aus einem Projekt-Export, wo der Fehler still verschluckt wurde. Zweitens war GET /admin/holidays admin-only, während work-calendars und work-schedules lesend für alle offen sind – für normale Nutzer blieb der Store deshalb immer leer (keine Feiertage im Projekt-Export, keine Markierung arbeitsfreier Tage im Ressourcen-Raster); der Lese-Endpunkt zieht nach dem Muster der übrigen Stammdaten auf /api/v1/holidays um (NoAdminRequired), Anlegen und Löschen bleiben unter /api/v1/admin/holidays. Ergänzend werden Feiertage jetzt mit ihrem Kalender gelöscht (WorkCalendarController::destroy(), HolidayMapper::deleteByCalendar()) und Bestandswaisen bereits gelöschter Kalender in Version1031 aufgeräumt – über verweisende Ressourcen haben sie bis dahin weiter als arbeitsfreie Tage gewirkt
  • Die Installation der Tabelle nc_gantt_task_resources scheiterte auf Instanzen, deren Tabellenpräfix die von Nextcloud aus Oracle-Kompatibilität erzwungene 30-Zeichen-Grenze für Bezeichner reizt: der von Doctrine automatisch vergebene Primary-Key-Name (Tabellenname + _pkey) wird mit Präfix oc_ zu lang (Issue #132). Die Primärschlüssel-Definition bekommt – analog zu den bestehenden Migrationen für nc_gantt_resource_capacity und nc_gantt_resource_groups – einen expliziten kurzen Namen
  • Der absolut positionierte Toggle-Button der Nextcloud-App-Navigation ragte in den App-Content hinein und verdeckte dort den Titel des ersten Eintrags in der Projekt-Rollup-Leiste (Issue #134); der linke Innenabstand reserviert jetzt Platz für den Button
  • Ein leerer Balken in Höhe der Kopfzeile erschien oberhalb des App-Inhalts, weil der CSS-Reset für den Nextcloud-Content-Wrapper an main#content.app-nc_gantt gekoppelt war (Issue #126). Ändert sich das Markup zwischen Nextcloud-Versionen (Klasse oder Tag), griff der Reset nicht mehr und der von NcContent (#content-vue) selbst gesetzte margin-top: var(--header-height) addierte sich zum Rand des Cores. Der Reset hängt jetzt robust an #content mit !important, ohne Abhängigkeit vom app-spezifischen Klassennamen
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturegO8Qmtdwg8LOBKr5G+mq4co374hsqqSN6oCIRV9atUx0KqogPxisJiIExkPoSIbu
e4EeIaUzg2alhZsKBLWOwR3Ab3fNm5vvd2DzJn6Hei7A70woz9m/LXkVlcx3vALW
bwolClUX1XCZOBVo/kSS5AOVwak3/huzT1iF9xH9BnpdzVuOjZ563LYwSayfb2Gq
SkWNfLZlKlDkTTF2PIszrNmaa89GmyqTbraxSP16/9nYdIj8ZU0zrhC3HtpihgAT
wya2lwnMf6I73HU0xxgT/+ITTmurx4eHwKWH80P4tjg/Y9mnHODIpAslbW3351mc
qdTHXIBW1MB1YGCQ+JPt11v1X2ccn29kEF9d1nkizKZ1+Du+LJQhPhwHiQxPWSwAUlTlQ4tj1lbe3+FJ1jsVTCqWbDUN02EoV7ZwtN15/HLJfM6w4drUi8ThJ1aLG3v6
cIwMJjYgWeepxR2gv4YgBf4u7txodm5bAWuzySk4rfAG1dBxmie/bfNnWmQ9LrYy
spwKc73gsPhg03ll+jp0b27fJfNF4IpOysz3i+r1ExVfeNIWWO91JPatO2pXZh4O
q0rczM8wYvctvcEkKQIL67HoIrKw4GVIXfqM9Oc8e/Ay7d/NPL+BjpCO6zvoFBY+
SRmjit15YmGW4EQwweQfKXuZ2YeySj+7OjhKHpKfvfg=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.2
Release Details
UpdatedAug. 20, 2026, 4:41 a.m.
Changelog

Changed

  • release.sh fragt die Versionsnummer jetzt interaktiv ab, statt sie nur aus appinfo/info.xml zu lesen: zu Beginn werden die aktuelle Version und das letzte Release-Tag angezeigt und es wird gefragt, ob eine neue Nummer vergeben werden soll (Vorschlag: nächster Patch-Level). Die Eingabe wird auf das Format X.Y.Z, auf einen echten Versionssprung und auf ein noch nicht vergebenes Tag geprüft und dann nach appinfo/info.xml, package.json und package-lock.json geschrieben. Fehlt ein Changelog-Abschnitt zur neuen Version, warnt das Skript; anschließend bietet es an, den Bump als chore: Version X.Y.Z zu committen — nötig, weil der Tag-Name den Commit-Hash enthält. Für nicht-interaktive Läufe gibt es --version=X.Y.Z und --no-bump; ohne TTY wird nie gefragt, make release bleibt also unverändert nutzbar
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturepoVHZxteU3AR2cpRRV98jNfv4j7rWnLEd3kbpn5Dp4T1ubAI+0QlRf9jxi0BaYz1
+1dg+3Yt25uN6Slp1FHiw7kyqt5HJ60XgnOWo+Zt0YBHSnWqLDhF8zxPEnQCkF+v
nUvscpcoQY2bRiIBZhVWVgeAD592uvOA4gfRDrUyLVDKjOrzBu3ScbNvCqTqE9IC
vs8qZkRLIcaD6tKoSLT2pZqmwBoCdClvEw5D5v40WSvLq232BZnXpQ4ogG3QvJdL
mYO8HlPZKVOxANp0MGnWle4IFRMbMt22Ebpkjc18Q9Q4AIv/Sd3zTsc+uMONTM95
s0GXvLSm95o0UCFZ1CL7fCEq7NwlprjVrTeWGmlJNVjHJuIyRKHEz5DR12s0lAGm
/rKGWjoVP+Wvk3upRizR/5y2fpWoiwuDqCtz9gQN6+HHYLaqLvYqsAJ/SxmtLtP7
8B2rK61ClKowz4phbTZdrCaF8w3IWnFFBTFquIVFuN2jUoHvdCMtd0910sLAMY5M
Xs9nk0FVsP23zKXlQpOojq7ouCQagRhsnBJDLxWRR+NIq582f7SDgcrkBqxlGJX4
/Ql9V+2iFx61QANCTjdJIO3LbvbK60vGos+ency0GfvSDbPovDAVyJzt8ZUh5BNw
UXQ4XOHJZAagAr36rKttk1DQbZZ/2bUEq231c96m83g=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.1
Release Details
UpdatedAug. 17, 2026, 7:43 p.m.
Changelog

Fixed

  • Die Meilenstein-Raute hatte eine fest verdrahtete Farbe (#fbbf24) statt der Projektfarbe zu folgen, obwohl Balken für Aufgaben und Teilprojekte bereits korrekt eingefärbt wurden (Issue #102). Zusätzlich wurden die separaten – und wirkungslosen – Farbwähler bei Teilprojekt und Aufgabe entfernt, da deren Anzeige ohnehin immer der Projektfarbe folgt
  • „Meilenstein hinzufügen" im Drei-Punkte-Menü der Projektliste nutzte zwei aufeinanderfolgende window.prompt()-Dialoge (Name, dann Datum als Freitext) statt des regulären Detail-Dialogs (Issue #101). Der Klick emittiert jetzt add-milestone analog zu „Aufgabe hinzufügen" (Issue #91) und öffnet denselben Meilenstein-Dialog wie beim Bearbeiten, mit vorbelegtem Projekt
  • Im festen Datumsmodus des Aufgaben-Detaildialogs konnte ein Enddatum vor dem Startdatum eingegeben und gespeichert werden (Issue #100). Jetzt zieht ein über das Enddatum hinaus verschobenes Startdatum das Enddatum mit; ein zu frühes Enddatum erzeugt ein rotes Fehler-Icon am Feld, hält den Fokus dort und deaktiviert den Speichern-Button, bis ein gültiges Datum eingetragen ist (dateField() in fields.js mit neuer setError()-Methode)
  • Eine Aufgabe mit Abhängigkeit behielt trotzdem die manuell eingegebenen Start-/Enddatumsfelder, die beim Speichern durch die Abhängigkeitsberechnung überschrieben wurden – für Nutzer nicht nachvollziehbar (Issue #99). Der Aufgaben-Detaildialog hat jetzt denselben Fixed-date/Dependency-Umschalter wie Meilensteine (Issue #90): im Dependency-Modus ersetzt eine Dauer (Tage) die Datumsfelder, die Abhängigkeit bestimmt den Termin. Serverseitig wendet TaskService::create() neu hinzugefügte Abhängigkeiten sofort an (bisher nur update()), damit auch neu angelegte Aufgaben keinen die Abhängigkeit ignorierenden Platzhaltertermin behalten
  • Der Speichern-Button des Detail-Dialogs blieb nach dem Hinzufügen einer Abhängigkeit deaktiviert: die Gültigkeitsprüfung hing allein am input-Event, das bei einem <select> vor dem change-Event feuert – zu diesem Zeitpunkt war die Abhängigkeit noch nicht in der Liste. detailModal.js wertet jetzt zusätzlich change aus, der Abhängigkeits-Editor (fields.js) meldet jede Mutation (Hinzufügen, Entfernen, Typwechsel) und der Fixed-date/Dependency-Umschalter in taskForm.js den Moduswechsel über ein eigenes bubbelndes change-Event

Added

  • CONTRIBUTE.md und setup-dev.sh für neue Mitwirkende (Issue #98): Projekt-Leitlinien (FOSS, Datensparsamkeit, Security), VIBE Coding ausdrücklich erlaubt, sowie der komplette lokale Dev-Setup-Weg (Docker-only, Nextcloud + MariaDB unter localhost:8088, optionales E2E-Setup, Git-/Bot-Auth). setup-dev.sh automatisiert diese Schritte, konfigurierbar über --workdir/--no-e2e/--no-docker-install
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturetYcUvVtDEQrAakG32EQF1atSOmz91/8XudCUh60A9r/AxMv+AA5AX2rIvNYDkEn0
OuTmXA6Iz0DoVkdij11MPDhfLaUy0mXeLbwB5fj/xF/cFYcNeCFGKD3k2jyRwOTo
2n1sEp0r8sn0fitHzLfhcB/By0VJkZyhaO/NctP01XfcSQM7lGEOeY/uagtGaDTI
JnPLoQTHo0nUOv4y7jUMZuurEgBOc4yeUxTKv4A/m642hvNQIS0q6K9ON41JHKIO
UtI7DbDWSboVhct1Go3zoj5XcaAGG9ZiwSkJDt/BXT5tWH4SOnSn7mys0j1F6Y0g
vIJWjz6S2RlekwIrIxgyaeEVBOeQ4OM1ilJGWKXDyYJM/0IBxqnqRXDkAFlOopDo
xezlcFdWTkYL5OBKMFJhKuTy7dEQ9hxx5Nz4+vLbNV8gDJZBI+5yI5m8W+809WIH
iKUpIda1ShOblvYH6Ek5AzBdTmoFQ6T4f7iWT7j1i4uUP2DsgehjGVl8yDIT/wyx
nV9t7koXapu1WeXrunSa++mXsi3lceNpthdz5/cUEOe9yWvc1rrulRhiWzePga8H
zjVQYGAIPvwYkWa47U6Zh7HBsQaS+9yQ8NDnD49SS4jUWTGlwNqfM+q9fZ16/G9d
7l4chZUPPbBv+xWfdxmFw+MC5zdkAq27isHToTqnm+w=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.0
Release Details
UpdatedAug. 13, 2026, 6:41 a.m.
Changelog

Added

  • Meilensteine werden jetzt immer direkt unter ihrem übergeordneten Objekt angezeigt statt gesammelt am Projektende (Issue #90): Meilensteine lassen sich neu auch einer Aufgabe zuordnen (bisher nur Projekt/Teilprojekt, Spalte task_id war bereits vorhanden, es fehlte nur die UI), das Auswahlfeld im Detail-Dialog heißt entsprechend „Übergeordnetes Objekt" statt „Teilprojekt". Zusätzlich können Meilensteine ihr Datum jetzt statt eines fixen Werts aus einer Abhängigkeit zum übergeordneten Objekt beziehen (EA/AA/EE/AE, analog zu Aufgaben-Abhängigkeiten; neue Spalte dependency_type, Migration Version1028) – da ein Meilenstein keine Dauer hat, bestimmen EA/EE das Ende und AA/AE den Start des Zielobjekts. Die Berechnung übernimmt der neue MilestoneDateService (serverseitig live bei jedem Abruf sowie im ICS-Feed neu aufgelöst, nicht persistiert propagiert) sowie clientseitig in frappeRows.js für sofortige Reaktivität ohne Neuladen
  • Undo für Drag-&-Drop-Verschiebungen inkl. Propagationskette (Issue #85, Umsetzung der einstufigen Empfehlung: letzte eigene Operation, kein Redo, zunächst nur Drag & Drop): Migration Version1027Date20260810020000 ergänzt nc_gantt_change_events um op_id (UUID) – alle Change-Events einer zusammenhängenden Operation (Drag + gesamte Propagationskette B→C→D) erhalten dieselbe op_id, erzeugt in TaskService::update()/propagateDates() und über ChangeEventService::log() protokolliert (dieses Change-Tracking war bisher tote Scaffolding-Logik ohne Aufrufer). Neuer Endpoint POST /api/v1/changes/{opId}/revert (ChangeEventController::revert, ChangeEventService::revertOperation) wendet alle Change-Events der Operation invers an, in einer DB-Transaktion mit Rechteprüfung über AccessService::canEditOrOwn(). Konfliktschutz: Revert wird mit HTTP 409 abgelehnt, sobald der aktuelle Feldwert nicht mehr dem protokollierten new_value entspricht (jemand hat zwischenzeitlich erneut geändert); der Revert selbst erzeugt wiederum neue Change-Events, die Audit-Historie bleibt lückenlos. Frontend: nach jedem gespeicherten Drag zeigt GanttChart.vue einen Toast „N Termine verschoben — Rückgängig" (showUndo aus @nextcloud/dialogs, 10 s sichtbar) sowie ein globales Ctrl+Z für die letzte eigene Operation der Session (stores/projects.js: lastOperation, revertOperation(), undoLastOperation())
  • Kalender-Export als abonnierbarer ICS-Feed pro Projekt (Issue #83, Variante A aus dem Umsetzungsvorschlag): neue öffentliche Route GET /apps/nc_gantt/projects/{id}/calendar.ics?token=… (regulärer, unauthentifizierter CalendarFeedController, damit externe Clients wie Thunderbird, Nextcloud Kalender oder mobile Apps ohne Nextcloud-Login abonnieren können) liefert Meilensteine als ganztägige VEVENTs (◆-Präfix), den aus den Aufgaben abgeleiteten Projektzeitraum sowie optional Teilprojekt-Zeiträume (Schalter „Auch Teilprojekt-Zeiträume einschließen", standardmäßig aus, um den Feed bei großen Projekten nicht zu überladen). Zugriff erfolgt über einen pro Projekt generierten, 256-Bit-zufälligen Token in der URL (CalendarFeedService, neue Spalte calendar_token auf nc_gantt_projects, Migration Version1026), der über einen neuen „Kalender-Feed"-Bereich im Freigabe-Dialog angezeigt, kopiert und jederzeit widerrufen/neu generiert werden kann (CalendarTokenController, nur für Projekt-Admins/-Eigentümer). ICS-Generierung ohne neue Abhängigkeit, RFC-5545-konform (Escaping, Zeilenfaltung)
  • What-if-Simulationsmodus für Terminverschiebungen (Issue #84): neuer Endpunkt POST /api/v1/projects/{id}/simulate führt Terminpropagation und CPM rein im Speicher aus (kein DB-Schreibzugriff) – TaskService::simulate() nutzt die neu extrahierte, stateless propagateDatesCore()-Kernlogik, die auch der persistierende update()-Pfad verwendet, CriticalPathService::computeFromTasks() erlaubt CPM auf einem hypothetisch veränderten Task-Datensatz. Frontend: „Simulation"-Toggle in der Gantt-Toolbar mit Banner inkl. Projektende-Delta in Arbeitstagen, Geisterbalken für die Ist-Termine (analog Baseline-Overlay) sowie Verwerfen/Übernehmen. Drag & Drop ruft im Simulationsmodus simulate() statt einer echten Speicherung auf. Szenarien bleiben bewusst flüchtig (kein Speichern benannter Szenarien), „Übernehmen" wendet die Änderungen als einzelne Task-Updates an, Simulation läuft pro Projekt
  • Neuer Eintrag „Aufgabe hinzufügen" im Drei-Punkte-Menü der Projektliste (Issue #91): legt wie der „Neu"-Button eine Aufgabe an, belegt dabei aber das gewählte Projekt direkt vor, sodass der Projekt-Auswahlschritt in der Maske entfällt
  • Such-/Filterleiste für Projekte, Teilprojekte und Aufgaben (Issue #81, Stufe 1: rein clientseitig auf Basis der bereits geladenen Daten aktivierter Projekte): Freitextsuche im Titel, Risiko, „überfällig" (Ende < heute und Fortschritt < 100 %), „über Budget" (Ist-Kosten > geplantes Budget), Ressource und „ohne Deck-Verknüpfung". Neuer Pinia-Store stores/filters.js (Zustand pro Nutzer in localStorage persistiert) und reine Matching-Logik in gantt/filterMatch.js. Nicht passende Balken werden in GanttChart.vue gedimmt statt ausgeblendet (Abhängigkeitspfeile und Zeitkontext bleiben lesbar), Projekte/Teilprojekte gelten als Treffer, sobald ein Nachfahre passt. Dieselbe Filterleiste (components/FilterBar.vue) dimmt in ProjectList.vue nicht passende Projekte; für nicht aktivierte Projekte sind nur Titel-Treffer zuverlässig auswertbar, da deren Aufgaben/Teilprojekte nicht geladen sind

Changed

  • Freigabe für Nextcloud 34 (Issue #94): max-version in appinfo/info.xml von 33 auf 34 angehoben, unterstützter Bereich damit NC 28–34. Verifiziert gegen Nextcloud 34.0.2 mit PHP 8.5 und MariaDB 11.4 (148 Unit-Tests, 39 E2E-Tests)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturerdYQI+Semnk0cWtKqUZinVDHk0KpxyqB5Ox4NBL9pyf5nrpK8xZpe9lBxc6zhDfW
8adLfVIwQtX+bI7S1O05xm0hwrUHQQ2ii6ADD8mlAxnZjdhKSCAhZ0NcaqT7Em0X
nD7yRP2B8zAAQMJNjzeBsLbzveNrXMoGzFrvm/jFxskUIUS01ykfWEg2C5+5/IAf
7jBAM8x2Qj92b8zyBFpLjfJQw9aTE/trtCsmZXQFmkJjGS0anrJc9dXKfqnHxknX
8jmLOv4Yq4Qtk3UF35HTiIGcA2W0UKfVyFb4XcrIMeSmLXXcagJWjeH5nB18UUNn
JyCgE/qY4v/SnrNQU92mIdMOQGuvYg7xbaz226lgNdwM2HuM9U8nc2juqJxAO+Wp
xs85yl82qIviZ5YY39HK371MZ/ufMsaVsVy3Nfn3PjqqkzGLmtAL6KJDcKHZWdDw
ugEPwO61DxnERZsNGeFpXfzCxjMpZc/qwUIfGw85idmU2vdedtrxHBkDGoqu1IP7
xZOO8uSYrzbXM6g1gs3WPBOY51CmZLs5pIQTN1tVl5ifGw4uOuzDBUCKiR5oA2MI
352HbA7wwWFgwoN9W5t4MRTowmaYpM8AB+nh9f1A5q9S8SelfMpXOqGew9VZb2jd
AuiJK/LEPjRgs5s3/FfC4Sb1MSsXDr1N1jziaF4MomM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.3.1
Release Details
UpdatedAug. 6, 2026, 12:57 p.m.
Changelog

Added

  • Regressionstests für die Rollentrennung Viewer/Editor/Admin: ForbiddenException-Tests für TaskService::create/update/delete/syncProgress und ProjectService::updateProject/deleteProject (inkl. „Editor darf nicht löschen") sowie erstmalige Testabdeckung für SubProjectService und MilestoneService

Fixed

  • CSV-/Formel-Injection im Aufgaben-Export (detail/io.js exportCsv): Task-Felder wie Titel oder Beschreibung, die mit =, +, - oder @ beginnen, wurden unverändert übernommen und von Excel/LibreOffice/Google Sheets als Formel ausgewertet. Die Absicherung aus ReportView.vue liegt jetzt in einer gemeinsamen Utility (src/utils/csv.js, escCsvCell) und wird an beiden Export-Stellen verwendet
  • Viewer sahen im Frontend dieselbe Oberfläche wie Editor/Admin (Add Task/Subproject/Milestone, Share, Delete Project, Drag/Resize im Gantt-Chart, volle Bearbeitungsformulare), obwohl das Backend Schreibversuche ohnehin korrekt ablehnte – kein Least-Privilege an der UI. ProjectService::getAccessibleProjects()/getProject()/createProject()/updateProject() liefern jetzt das effektive permission-Feld (AccessService::getEffectivePermission()) mit; ProjectList.vue, GanttChart.vue (inkl. Drag/Resize-Sperre je Projekt) und das Detail-Modal (detail/detailModal.js) blenden Schreib-Aktionen für Viewer aus bzw. schalten Formulare read-only
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureBUyDeI9y7iKD1wQJLHrW6IFq0zuXOJQ1Zv/x+0RryIIQ0fAGAUjwQyLDYLYpRzPg
6ITDPfY9bftVlwkB8w9LqZiFETkH8mgc6l5XB7F6NKzFrdaSnNw21CIVJjWyHpkR
mxDq+vQepZd+YtB9jMz39kbFk9BNHrpKIwIXXZVqEqj1U54NmT+5XnT892m9mY6o
RWQNf3Mn5WcH3vmoDi/UAOgDaO30GFCRJePryurVpK7stkub8K6fYsWIkS5NeJlP
YHdb4nBlkhUzQFjo0ZDSkCSiWjMdyCrtEanX6m6Ffhr+j0jpd+J9soMSjrzdzt4T
5mETo8xc61IQIVFWMD6fZ3/oCmbx2TFDZsJjRpFKxoPA08AkdC7xjxHoaKYZHvi4
+tzowxPzMfyjQ/hEj2dwq22doM2lXK1Y13VvV8kkaomrAQjB97gf+ODrYZNDgNvc
2ijU08B4cAB0HbEveDpDRjCJj8D5OwCMafRMa4Ul/nm0+RiBFOhIjDYdVAnCp7Ql
IEc4UQZM9WYLQlouwGPk83POpbqkbc8vKAucGBXvHAbxNpUSOGbssMYFGU/e9pOg
+oT2gcJrC3MYPGIWnS8iLn75PK1H063KFJv5yqC+h/rqwX/FxyTzKvofJi68GpLs
WtG3y67W8Ju4y1I9iQ9raJxxhFUJrStibGy9gc7L0DM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.3.0
Release Details
UpdatedJuly 9, 2026, 5:23 a.m.
Changelog

Fixed

  • Baseline-Toggle im Gantt-Toolbar zeigte nie Baseline-Balken und PUT baseline/active warf einen SQL-Fehler: baseline_id auf nc_gantt_projects wurde mit der 3-Ebenen-Migration versehentlich zusammen mit den tatsächlich berechneten Spalten entfernt (Migration Version1025 stellt die Spalte wieder her). BaselineService::create() aktiviert eine frisch eingefrorene Baseline jetzt automatisch fürs Projekt; renderBaselineBars() (GanttChart.vue) und baselineOverlay.js lesen Baseline-Items dafür über task_id statt des seit der Umstellung auf das 3-Ebenen-Modell nicht mehr existierenden subproject_id-Felds
  • OCS-API-Fehlerantworten (400/404/500 …) lieferten für alle OCSController-Endpunkte einen leeren text/html-Body statt des erwarteten JSON-Envelopes mit message; ExceptionMiddleware wirft jetzt passende OCP\AppFramework\OCS\OCSException-Subklassen statt einer rohen DataResponse, die Nextcloud-Core nur für 401/403 automatisch formatiert. Betroffene Controller (ProjectController, ReportController, ShareController, ChangeEventController, WorkScheduleController, WorkCalendarController, HolidayAdminController, SettingsController) wurden zusätzlich auf die bestehende ApiException-Hierarchie umgestellt

Removed

  • Nie ausgewertete Gruppen-Freigabe-Option entfernt: Share::TYPE_GROUP, principal_type-Parameter in ShareController sowie die DB-Spalte principal_type (Migration Version1024) wurden gestrichen; Freigaben sind jetzt ausschließlich benutzerbezogen

Changed

  • Dashboard-Summary (DashboardController::summary) lädt Baselines und Aufgaben-KPIs jetzt über gruppierte SQL-Aggregat-Queries statt pro Projekt einzeln (N+1-Fix, gilt auch für den Admin-Fall mit allen Instanz-Projekten)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureNJfbRJEXzKGipUjUW9tUKayHoY6ltSU0ZeCQXcDx6XVDY/naLK0dVY9ciofXU7oy
40sJIOsjxcUZbalDwqncPn0vjGoqmk3BFUT7KotEpLLf8/ZmIjdHEbQbJHzEpdQV
y5YedjqRLKB7/Ul35JWVFxY8eutCsYkonfof7v6AGMGB/RjQ7GDB6jWunEEwqUGV
3Y1isvdq5N3oo9NDY/QR0C2C7jiMnB9Kon0KzZ2yp0oF5euOpA/qrtmqxG3L9PoZ
DW1ppwAuARWtRDu4tcDAAQAkF1Mrg5YyYgRoKm7uVazlKEP7DxX56g/g4RS2otEE
rKsA/ER9yYiHnNyGcZuK9Jkfe2Ua6/R7gzJilRvHZ7CBPkhY+XNPcrjlsHbCJEJJ
cX/b0B56p7FyAFy6XjMY9PYFhxy/ubHE7Sk8ixX88uxgM4vf/sSFQaN84CcG/qqA
Nq/OEytBjZP82TsFFYBRcPKEPskF4ejjhNVC4bJpiuCIpo51nIxjeFGtDpeQiDG7
0OWc/GCvsz5W3eG7ShmQsRf0DoivL8tjgDUlMWO9boTpUy2Vnm1rDMKu6nFGKZ8o
TWTZR6u4zGZW1OBERdlU5NQmqxqXrsuGlT6r6DuQnWsWiscjXOyIFeHz+EOKhQOk
wUuN6xN8QES1CDFB27PYV0Sz2KhYhM78GKLCc9B10Ic=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.2.0
Release Details
UpdatedJuly 5, 2026, 9:21 a.m.
Changelog

Added

  • Löschen-Buttons im Detail-Modal für Teilprojekt, Aufgabe und Meilenstein
  • Deutsche App-Beschreibung in info.xml ergänzt

Fixed

  • Baseline-Datum und Kommentar im Report werden untereinander angezeigt
  • Dashboard-Widget zeigt Baseline-Datum und KPI-Werte korrekt an
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureXuYTZMxTlGNJVrGvU/GcIjSlBTYreXdvF5FilCmsi+l7MBvFlyeW1DsnxAsao3pu
HyhvaKXRnkraVQNT2ULgX4BmjUnhsELROrK03gtY88Odzqzh7RIXYkNkRcy92ara
56HIP8BBRD3m1c8pYPfpZfLAzkuurAzVqbJ6qbxw1AebdlPCFEq2g6C+IOcTon0T
q9ZD2I2XJmWd42EXXqva+NMrcx1jfjmHWVtl7xHKhwPndFCtHPMMAdoDS0Xpbh1V
3Ns4h/DphDpC8/ZYZ5sbpMCBekHw4VTZDGxNAuXJ5DMPhkqg2MxVplkS19PuBHLx
r74sgsz611Gjg55gjKOqCb5ZZEvqZTrwKTEYIbu8HicWtq/HxKRZS3FZN9MThTTX
Hesv65vsq9fH0UhEM6MVJjE5Phnw8Wb5ivtAiaUA+NzPrDfrHZAsSfR9NFL3rhFC
7wOmnXtzK40NjmqyMWJu/UP9UVbz3SeEiHiQO9GwBc2krzmXzcmLZFgEjty4CGoJ
SzXAA1QGpUGO4n0b3Y/5zSY4UxogGWybW+mOs27KDLytI915wNYGvBtcdAKCj6Ws
1uVA98npwMid/WSJJ04BXHX8LbowrDeTezSFJyGh+u/KnhlzkA7fqEuu3nQGT5rA
a9qeMmd5kmLBIVcG9RVVmw1kc0AK0qIqZDmlk9dWGJs=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.1.1
Release Details
UpdatedMay 27, 2026, 6:43 p.m.
Changelog

Added

  • Glossar-Button in der Navigation (über den Einstellungen) mit interaktivem Nachschlagewerk
  • Dreispaltige Glossar-Tabelle: Begriff/Abkürzung, Bedeutung/Englisch, Erklärung mit Berechnungsformeln
  • 30 Einträge in 6 Abschnitten: Allgemein, Terminplanung, Baseline & Berichtswesen, Earned Value Management, Ressourcen & Kapazität, Budget

Fixed

  • Fehlende deutsche Übersetzungen für englische UI-Strings ergänzt (Add dependency, Baseline, Dependencies, Remove, Work, No projects yet, Open Gantt Projects, u.a.)
  • Leere Übersetzung für Deck-Fortschritt-Hinweis befüllt
  • de.js vollständig mit de.json synchronisiert (war ~70 Einträge veraltet)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureF1RHJx15J/N8tWNrDlAX1MFE/9tsct4PViEcBDeo8U/V2qJ/tezL7Xk0BVmYxjWw
pB+J685mcHjikh93/aZUqG8C6y0mR3TTJfaa7dLCIRMc1034x6Xj9Nd7Q9YVH4yi
RLTcRhrG2pN1Iqc23kwId995GJXHnCBEyuQuzo9m1VtA7GoFa8W2nqhXVT94khDS
8ZHQrixDfv63d4GfA5N2x4+phaiyObdskvCmVSuKrmouYvCGpPevtKG5YxzOrHid
aL48Kod0YgOCAD8nAqOhEmioP0m+wP2e/NC4Z5svSKT3vdlE67W1M68ipQQfnhPI
txui+2X8zFvoe/M5sE3DaXbLnOVNGQ7YRpyXFI5GsQmQ0cPSSO/94Mw15hLZfwMf
TDOrrvzf+Vu05sUTZ6CFh4FrSl4e5Q6Xjv6uH4BZtyOpPxl+ajgW4OkZvQDbt4KC
8aTZodMcDpXlRMDdBSxT1bT9tD05KUKmEZYtpxHiARrHDuQQCRSuxtjitQD9lbla
CMxKrBiO0YgdUb3FuczYkWEH+y8gW5egU6TDMnjAVbuUecGuGZN1Cc6tarcFWRu2
+V7Qn+aNoXEwP5e/0TM4Ig8ETAYseZRiTPHxeWiSg3RnU3HuT6kPVWw8LERACDT4
6F4WU9t2+4kESMLMjeV0/2UBQSykR/42Idsg0PtvpyQ=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.1.1 (nightly)
Release Details
UpdatedMay 27, 2026, 5:24 p.m.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureF4W7QJB8rVJ2xARdnhUbEouzRZMKcowz/ToDwr0oVFrVUbInFvHAMqXFTOVD1a5N
kDTb0pOhv+hCStTh70bN+aapjbdtp7SdQ3SbP5VoXBKLhUii41OqN/i4yM7itdSs
M8d5PVo9TJYVnfaij2xwWghMqZEyzxgOw4Q98dYIysf2BxsjjCtxGEMo/pISS90G
OE2RaVEFbwUcvu1XKszLP5X/k/onOchengURYVuzHP7VgVuomZpPSZ9VEIRKITyL
GpgSDrdqm5AXdQc7l/2OqprW6G+MxsuVzChbyPGslIYYXYsP9HLc/FfwVxaCJjh2
Nsiqfd+dMwnf7f9yrrBuZjbNwNa5x++IynrwaU01jVISkl9pgkbUYRaPSMTGFDAd
lsEEqlgs9KdzGoTFjDXNdTwDOsUMiu/ag8tPo7YxsxLFbVGa7laRAUhlGUT9QGPr
IOAAWvKqivsYnU5iwTCY/5HGza3SDfZc/e5upPfB+lTQTYijp1aAYRBAsoOLmuga
f0aP45pnfnYBJkT1kMsthjbGMdlL46wLiNHKRct9OlFwx74IRIyZdcs5Q3pC0aNN
DSLvsCSmY8/9PtTLzcOJKXTqqDVupCqq82bUlGRn7NR6xsinzv74MuOVnGY21tBm
iB5ceYpgiEukUz6YtS2quIIiMTnYmM+HBFnkXgBV0/Y=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32

Nextcloud 31

Gantt Projects 1.6.1
Release Details
UpdatedSept. 2, 2026, 6:15 p.m.
Changelog

Security

  • Ressourcen-, Gruppen- und Kapazitätsdaten fremder Projekte waren über geteilte Projekte einsehbar (Issue #183). ResourceMapper, ResourceGroupMapper und ResourceCapacityMapper::findVisibleToUser() gaben pauschal alle Datensätze eines Eigentümers frei, sobald irgendein Projekt dieses Eigentümers mit dem Nutzer geteilt war — unabhängig davon, ob die konkrete Ressource überhaupt in einem geteilten Projekt verwendet wird. Der neue zentrale ResourceVisibilityService prüft stattdessen, ob die Ressource tatsächlich in einer für den Nutzer sichtbaren Aufgabe verwendet wird, und wird von ResourceService, ResourceCapacityService, ResourceGroupService und TaskResourceAssignmentService genutzt. Damit lassen sich über eine geteilte Ressource weder die übrigen, nicht geteilten Ressourcen desselben Eigentümers einsehen noch eigenen Aufgaben zuordnen
  • GET /api/v1/resources/{id}/utilization gab Planungsdaten aus nicht zugänglichen Projekten preis (Issue #181). ResourceUtilizationService::findVisibleResource() prüfte nur, ob der Ressourcen-Eigentümer irgendein Projekt mit dem Nutzer geteilt hat; über die Auslastung waren dadurch Aufgaben- und Projekttitel samt Terminen aus fremden Projekten abgreifbar. Die Prüfung stellt jetzt projektbezogen fest, ob die Ressource in mindestens einem über AccessService::canViewOrOwn() sichtbaren Projekt verwendet wird; zusätzlich filtert collectPlannedHours() die Aufgaben auf genau diese Projekte, sodass auch bei erlaubtem Ressourcenzugriff nichts aus fremden Projekten durchsickert
  • Aufgaben und Teilprojekte ließen sich an fremde Projekte hängen (Issue #179). TaskService::create()/update() und SubProjectService::create()/update() prüften nur die Schreibberechtigung auf die eigene projectId, nicht aber, ob eine mitgesendete subproject_id bzw. parent_id überhaupt zu diesem Projekt gehört — mit Folgewirkung beim Löschen eines Teilprojekts (SubProjectService::deleteTasksForSubproject()) und im öffentlichen ICS-Feed (CalendarFeedService::buildIcs()), da beide über TaskMapper::findBySubProject() allein nach subproject_id filtern. Analog zum Schutz aus Issue #97 prüfen jetzt AccessService::assertTaskBelongsToProject() und assertSubprojectBelongsToProject() die Zugehörigkeit; deleteTasksForSubproject() und buildIcs() filtern die geladenen Aufgaben zusätzlich defensiv nach project_id, um vor dem Fix entstandene Altdaten abzudecken

Changed

  • Dokumentation aufgeräumt: Die Doku ist jetzt nach Zielgruppe getrennt — alles, was Nutzerinnen und Nutzer brauchen, liegt in nc_gantt/ und wird damit vom release.sh-Archiv mit ausgeliefert, das Repository-Root enthält nur noch Entwickler-Doku. Dafür sind FEATURES.md, INSTALL.md und die neue HOWTO.md nach nc_gantt/ gewandert; die Root-README.md beschreibt die zehn wichtigsten Anwendungsfälle des Werkzeugs, erklärt je Fall den gedachten Arbeitsweg und führt in einer Repository-Übersicht auf, welches Dokument für wen gedacht ist. Neu ist nc_gantt/HOWTO.md: eine Schritt-für-Schritt-Anleitung entlang eines durchgerechneten Beispielprojekts, die alle zehn Anwendungsfälle mit konkreten Feldwerten, Abhängigkeiten und Terminen durchspielt
  • Dabei korrigierte Verweise und Angaben: der Lizenz-Link in nc_gantt/README.md zeigte auf das nicht vorhandene LICENSES/AGPL-3.0-or-later.txt statt auf LICENSE.md; die Nextcloud-Anforderung stand mit „28–33" in README.md und „28–34" in FEATURES.md gegen die tatsächlichen 31–34 aus appinfo/info.xml; FEATURES.md nannte noch Version 1.5.0; INSTALL.md verwies auf ein dist/nc_gantt-<version>.zip im Repository, das es nicht gibt (dist/ ist nicht versioniert und release.sh baut .tar.gz), und in CONTRIBUTE.md trug ein Link auf RELEASE.md die Beschriftung release.sh. Alle relativen Links und Abschnitts-Anker der versionierten Markdown-Dateien lösen jetzt auf
  • Tests laufen künftig vor jedem Commit (Issue #185): setup-dev.sh installiert einen pre-commit-Hook, der Vitest und PHPUnit (über Docker) ausführt und den Commit bei Fehlern abbricht — genau die Stelle, an der die vier defekten Tests aus dem Ressourcen-Sichtbarkeits-Commit hängen geblieben wären. phpunit.xml schaltet zusätzlich failOnRisky und failOnWarning ein, damit ein Test ohne Assertion den Lauf rot färbt statt unauffällig grün zu bleiben, und CONTRIBUTE.md dokumentiert die Regel zu Mock-Defaults ohne with() in setUp()
  • Die Default-Stubs in setUp() von ResourceVisibilityServiceTest blockierten die spezifischeren Stubs der einzelnen Testmethoden — PHPUnit wertet für dieselbe Methode den zuerst registrierten Matcher aus, und der greift per any() bei jedem Aufruf. findByResourceId(), findByIds() und findByResourceIdExcluding() lieferten dadurch immer ein leeres Array, was vier Failures und zwei risky Tests verursachte. Die Defaults sind entbehrlich, weil PHPUnit-Mocks für den Rückgabetyp array ohnehin ein leeres Array liefern; der Produktivcode blieb unverändert
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturerHm/UxN1WTCOMd9LklleINo7LKDOEAyn1zlsR5eTCaUmdGaN1m8Knqk/EKDYcj73
zWx7TXmT4cP91Ag7mCMwY/gRqJabF7TgeXiA7CeV7VE7/D/+apIatMWRT7zYCjkF
oxXKimNrtpDSKWNXKSQn6RfJaEHu5WnIoF4X9Nyx/wf1WoWoThyvWMSSW/3jdajV
WXCV4XQjzbTULw9T+Ini/e8vp6mXt5CrmCdyUDQQcj2t9PF9Hq3GvWT1VQlYA8Kf
IJuqnArSc4JdtJiJnozpOKSBkAbDPTrFytwUTVUO4XlrGIvyqHv14ZVmBM8UCMo6
yVNA9HEBW62/b8W+Z3BtCBTuBnkRk3Wka8qhMMbqOe8kl/1vQtTKQkaDdnXaShUs
18mfDHjLZhcIrJEwbtPvo9Xpf+IWEZeoiRzEqa30n70iZTkPEVv/GxNVmJ74XYH/
Xa/vMWI/sxtXKtKY60XBXXCEVMuyxR+vfIbJOpDCcFlKyWHiXPEdYh2Ac8Bs1hc7
bk+lolw8FEWISrFdUwYdOrfRr4CMW+h2CYzgZsDKKYrVn+hRUy5mVOL1QXZJbNJJ
wr9O/JrUbXAMGdhtLuRUwM4tsPgMF2+cTLMe+wuFzUjWBBNiqb8GKJP2K94hdurD
+VMd/p/TtU02M23ooysu2mft5RCmD0/QbP8yxEACbHg=
Signature digestsha512
Dependencies
Required Nextcloud versions >=31.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.6.0
Release Details
UpdatedAug. 28, 2026, 2:34 p.m.
Changelog

Achtung: Diese Version setzt Nextcloud 31 oder neuer voraus. Die bisherige Untergrenze war Nextcloud 28. Mit dem Umstieg auf @nextcloud/vue 9 — unvermeidbar, weil Vue 2 seit dem 31.12.2023 End-of-Life ist und keine Sicherheitskorrekturen mehr bekommt — fällt die Unterstützung für Nextcloud 28, 29 und 30 weg. Installationen auf diesen Versionen bekommen das Update nicht angeboten und bleiben auf 1.5.4; sie werden von dort nicht weiter gepflegt. Wer die App weiter nutzen möchte, aktualisiert zuerst den Nextcloud-Server auf mindestens Version 31 (max-version bleibt unverändert 34).

Changed

  • Das Frontend läuft auf Vue 3.5 statt Vue 2.7 (Issue #150). Vue 2 ist seit dem 31.12.2023 End-of-Life und bekommt weder Sicherheits- noch Fehlerkorrekturen; die Nextcloud-Server-Generation, gegen die die App freigegeben ist, hat ihren Frontend-Stack längst auf Vue 3 umgestellt. Mit umgestellt sind @nextcloud/vue 8 → 9, @nextcloud/dialogs 6 → 7, Pinia 2 → 3 und @nextcloud/webpack-vue-config 5 → 7; die dreizehn Build-Pakete, die das Webpack-Preset ab Version 7 als peerDependencies erwartet (webpack, vue-loader, sass, babel-loader …), stehen jetzt explizit in den devDependencies. npm audit --omit=dev meldet damit 0 statt 14 Befunde — die vier an Vue 2 hängenden Advisories (vue, vue-template-compiler, vue-resize, vue2-datepicker) waren ohne diese Migration nicht auflösbar
  • appinfo/info.xml fordert jetzt Nextcloud 31 statt 28 (max-version bleibt 34). @nextcloud/vue 9 lässt die Unterstützung für Nextcloud vor 31 fallen; das ist die unvermeidbare Gegenleistung der Migration. Installationen auf Nextcloud 28–30 bleiben auf Version 1.5.4
  • Die drei Einstiegspunkte src/main.js, src/admin.js und src/dashboard.js erzeugen ihre Anwendung über createApp() statt new Vue(); Pinia wird als Plugin registriert (app.use(pinia)), das Weiterreichen der Store-Instanz an das Vanilla-Detailmodal per setActivePinia() bleibt unverändert. Die Vue.prototype-Zuweisungen im Dashboard-Einstiegspunkt sind entfallen — DashboardWidget.vue importiert t ohnehin selbst
  • Anpassungen in den 17 Komponenten an die API von @nextcloud/vue 9: Import-Pfade (@nextcloud/vue/components/NcButton statt @nextcloud/vue/dist/Components/NcButton.js), type="primary"variant="primary" bei NcButton/NcActions, NcActionCheckbox und NcSelect auf modelValue (:checked/@update:checked bzw. :value/@input sind entfallen), :shown.syncv-model:shown bei NcPopover. Dazu die Vue-3-Umstellungen im eigenen Code: beforeDestroy()beforeUnmount() in GanttTable.vue, ResourceGrid.vue und GanttChart.vue (siehe Issue #149), this.$set()/this.$delete() durch direkte Zuweisung bzw. splice() ersetzt
  • css/main.css und der zugehörige Util::addStyle()-Aufruf im PageController sind entfallen. Die Datei enthielt einzig #content { margin-top: 0 !important } gegen eine Doppelmarge, die NcContent unter @nextcloud/vue 8 zusätzlich zum Nextcloud-Layout gesetzt hat. Unter Version 9 gibt es diese Marge nicht mehr, der Reset schob die App stattdessen um die Höhe der Kopfzeile nach oben — die Navigationsleiste lag dadurch unter dem Nextcloud-Header und war nicht mehr anklickbar. Der Mount-Punkt #nc-gantt-app bleibt als Wrapper im DOM stehen (Vue 3 rendert in das Element hinein, statt es wie Vue 2 zu ersetzen), nimmt aber nachgemessen exakt die Maße des Content-Bereichs an und braucht keine eigene Regel
  • ESLint nutzt das Preset @nextcloud/eslint-config/vue3. Es lässt vue/custom-event-name-casing auf dem Vue-3-Default (camelCase) laufen, während das Vue-2-Preset kebab-case erzwungen hat; da der Bestand durchgängig kebab-case verwendet — unter Vue 3 gleichermaßen gültig — setzt .eslintrc.js die Regel explizit auf kebab-case
  • Der <style>-Block in GanttChart.vue war mit 581 Zeilen ungescopt und wirkte damit auf die gesamte Nextcloud-Oberfläche statt nur auf die Komponente (Issue #151). Die 65 eigenen .nc-gantt-*/.nc-*-Regeln laufen jetzt über <style scoped>, mit :deep() dort, wo Overlays ihre Elemente per createElementNS() bzw. innerHTML außerhalb des Vue-Templates in .nc-gantt-container einhängen. Die Regeln, die auf frappe-gantt-eigene Klassennamen zugreifen (.gantt .bar & Co.), liegen gebündelt in src/vendor/frappe-gantt/theme.css direkt neben dem vendorten Quellcode der Bibliothek und werden von dort per index.js importiert; die beiden nicht unter .gantt verankerten Selektoren (.bar-wrapper.gantt-milestone .bar-label/.handle) sind dabei korrigiert. In App.vue laufen die drei Core-Überschreibungen (.app-navigation__content, #app-settings, .app-navigation .app-navigation-list) ebenfalls über :deep() in einem scoped Block. Abgesichert ist das durch vue/enforce-style-attribute aus eslint-plugin-vue, das ab sofort scoped für jeden <style>-Block in src/ erzwingt
  • TaskService bündelte auf 774 Zeilen drei Verantwortlichkeiten und brauchte dafür acht Konstruktor-Abhängigkeiten; der Schnitt trennt sie (Issue #153). TaskSchedulingService übernimmt Constraint-Propagation über EA/AA/EE/AE mit Lag, Kahn-Sortierung, Arbeitstagsrechnung, Zyklenprüfung und What-if-Simulation — CriticalPathService wird dort regulär injiziert, statt simulate() als Methodenparameter durchgereicht zu werden. TaskResourceAssignmentService übernimmt Auflösung und Persistierung der Ressourcenzuordnung inklusive MAX_TASK_RESOURCES und PT-Umrechnung. TaskService bleibt als CRUD-Fassade mit Berechtigungsprüfung, Validierung, Änderungsprotokoll und API-Aufbereitung: 311 statt 774 Zeilen, sieben statt acht Abhängigkeiten. Die Methodenrümpfe sind unverändert verschoben, es ändert sich keine Terminlogik. TaskServiceTest ist entlang derselben Grenzen aufgeteilt (TaskServiceTestCase als gemeinsame Basis, dazu TaskSchedulingServiceTest mit 39, TaskResourceAssignmentServiceTest mit 8 und TaskServiceTest mit 11 Fällen — exakt der bisherige Umfang), wobei die ausgelagerten Services weiterhin über ihren Aufrufer TaskService angetrieben werden, damit neben der Rechnung auch die Verdrahtung zwischen Fassade und Engine abgedeckt bleibt
  • Die 212 Zeilen CSS der Vanilla-Detaildialoge wurden zur Laufzeit als <style> in den <head> injiziert (src/detail/styles.js); sie liegen jetzt als src/detail/detail.css vor und werden von Webpack eingebunden (Issue #152). Der im Kopfkommentar genannte Grund — nicht von der Loader-Konfiguration abhängen zu wollen — trifft seit dem Vendoring nicht mehr zu, src/vendor/ importiert .css und .scss ebenfalls direkt. Dabei fiel auf, dass das Stylelint-Glob unquoted an die Shell ging und ohne globstar nur eine Verzeichnisebene traf: weder src/App.vue noch eine .css in src/vendor/ wurde je geprüft. Mit Quotes globbt Stylelint selbst; die dadurch aufgedeckten Findings in App.vue sind mitbehoben
  • Die PHP-Einrückung ist auf Tabs vereinheitlicht (Issue #170). nextcloud/coding-standard erwartet Tabs, die Codebasis nutzte durchgehend vier Leerzeichen — composer cs:check beanstandete dadurch 144 von 146 Dateien, der CI-Job wäre ab dem ersten Lauf dauerhaft rot und als Gate wertlos gewesen. Ursache der Drift war ein falscher Kommentar in .editorconfig, der dem Coding-Standard vier Leerzeichen unterstellte; der ist mitkorrigiert. Die Änderung ist rein mechanisch (php-cs-fixer fix): Einrückung, Klammern um einzeilige if-Rümpfe, sortierte use-Blöcke und einfache statt doppelte Anführungszeichen, wo keine Escape-Sequenz im Spiel ist. Der Commit steht in .git-blame-ignore-revs, damit git blame weiterhin die inhaltlich letzte Änderung einer Zeile zeigt

Added

  • appinfo/info.xml wird jetzt automatisch gegen das App-Store-Schema geprüft, statt den Fehler erst beim Upload zu erfahren: scripts/validate-appinfo.js (npm-Script validate:appinfo) validiert gegen die eingecheckte Schema-Kopie tests/fixtures/info.xsd — per xmllint, ersatzweise über lokales php oder das composer:2-Image — und prüft zusätzlich Semver-Format, Gleichstand mit package.json und den CHANGELOG-Abschnitt zur Version. release.sh ruft das als erstes Gate mit --online auf, lädt das Schema dabei frisch und meldet, wenn die Kopie veraltet ist
  • tests/Unit/AppInfoXmlTest.php führt dieselbe Schema-Validierung in der Testsuite aus (DOMDocument::schemaValidate()) und gleicht zusätzlich die Übersetzungen in l10n/ gegen die Store-Texte ab: gettext-Codes wie pt_BR werden als solche erkannt, und zu jeder übersetzten Sprache müssen <name>, <summary> und <description> in info.xml existieren
  • Die Stunden je Personentag sind konfigurierbar (Issue #169). Der Umrechnungsfaktor lag dreifach hartkodiert vor (TaskResourceAssignmentService, ResourceUtilizationService, ResourceGrid.vue) und wurde über gegenseitige Kommentarverweise von Hand konsistent gehalten — eine feste 8-Stunden-Annahme passt aber nicht zu jedem Arbeitszeitmodell. Der Wert liegt jetzt an genau einer Stelle: WorkTimeService liest ihn als App-Config-Wert hours_per_pt (Standard 8), validiert ihn gegen 1..24 und fällt bei unplausibel gespeicherten Werten auf den Standard zurück, damit die Auslastungsrechnung nicht durch 0 teilt; in ResourceUtilizationService entfällt damit auch die Konstante DEFAULT_CAPACITY_H, die denselben Vollzeit-Referenzwert doppelt hielt. Ins Frontend kommt der Faktor über den Initial State des PageController, sodass er schon beim ersten Rendern des Ressourcen-Rasters bereitsteht; GET/PUT /settings liefern und setzen ihn zusätzlich, wobei ein PUT ohne hours_per_pt den gespeicherten Wert unverändert lässt, damit ältere Clients ihn nicht auf den Standard zurücksetzen. Gepflegt wird er im Admin-Bereich neben Arbeitsbeginn und -ende
  • Die Vanilla-Detaildialoge sind für Screenreader und Tastatur verdrahtet (Issue #152): Die Dialoge verweisen über aria-labelledby auf ihre Überschrift, section() verknüpft Beschriftung und Bedienelement (bei Gruppen über role="group"), Knöpfe ohne Text bekommen einen Namen, Umschaltknöpfe melden ihren Zustand über aria-pressed, und die Datums-Plausibilitätsmeldung hängt per aria-describedby am Feld statt nur im title-Attribut des Icons zu stehen. Der Fokus beginnt beim Öffnen im Formular statt auf dem Schließen-Knopf und kehrt beim Schließen zum Auslöser zurück. Abgesichert durch payload.test.js (19 Fälle für Speicher- und Löschlogik) und accessibility.spec.js (6 E2E-Fälle) — für DOM-Code ist der E2E-Lauf die tragfähigere Absicherung als eine neue jsdom-Abhängigkeit. src/detail/README.md erklärt, warum das Modul außerhalb von Vue steht und welche Regeln daraus folgen; CONTRIBUTE.md verweist darauf
  • Die CI läuft. Der Workflow lag unter nc_gantt/.gitea/workflows/ci.yml und war eine reine GitHub-Actions-Datei; vier voneinander unabhängige Gründe verhinderten, dass davon jemals etwas ausgeführt wurde (Issue #170): Forgejo liest Workflows ausschließlich im Repo-Root, runs-on: ubuntu-latest passt auf kein Codeberg-Label (die gehosteten Runner heißen codeberg-tiny/-small/-medium), die Kurzform shivammathur/setup-php@v2 wird gegen Forgejos Action-Host aufgelöst, wo es die Action nicht gibt, und die Repo-Einheit „Actions" war deaktiviert. Die Datei liegt jetzt unter .forgejo/workflows/ci.yml, die App bleibt via defaults.run.working-directory erreichbar. Inhaltlich sind php-lint und php-tests zu einem Job zusammengefasst und laufen beide über die volle Matrix 8.1/8.2/8.3 (vorher lief PHPUnit nur auf 8.2, obwohl composer.json >=8.1 fordert), die Syntaxprüfung nutzt xargs statt find -exec (find liefert seinen eigenen Exitcode, nicht den von php -l — der Schritt konnte gar nicht fehlschlagen), und der JS-Job führt neu vitest mit 180 bislang nie automatisiert gelaufenen Tests aus, dazu validate:appinfo und l10n:check. paths-ignore hält die geteilten Codeberg-Runner von reinen Doku- und Screenshot-Änderungen frei

Fixed

  • Nach der Migration auf @nextcloud/dialogs 7 erschienen Statusmeldungen wie „Einstellungen gespeichert" als unformatierter Text oben links statt als Badge. Version 7 hat Toastify durch eigene Vue-Komponenten ersetzt, deren Styles nicht mehr im JS-Bundle stecken, sondern über den separaten Export @nextcloud/dialogs/style.css eingebunden werden müssen; ohne diesen Import lief der Toast-Container ungestylt im normalen Dokumentfluss mit. src/main.js importiert das Stylesheet jetzt. Die Toasts erscheinen dabei an der neuen Standardposition der Bibliothek unten links neben der Navigation statt wie früher oben zentriert — Version 7 bietet dafür keine Option mehr
  • testBuildIcsStripsCarriageReturnToPreventLineInjection prüfte das gesamte ICS-Dokument auf Freiheit von \r. RFC 5545 trennt Zeilen aber genau damit, und buildIcs() setzt sie korrekt als CRLF — der Test konnte nie grün sein und schlug auf main dauerhaft fehl. Der Schutz selbst greift; nur die Assertion war zu weit gefasst. Geprüft wird jetzt, was die Line-Injection tatsächlich ausschließt: kein einzelnes CR außerhalb der CRLF-Zeilentrenner, der eingeschleuste Titel erzeugt keine eigene ICS-Zeile, und er landet escaped im SUMMARY-Wert. Gegenprobe mit entfernter CR-Normalisierung in escapeText() schlägt weiterhin fehl, der Schutz bleibt also scharf getestet. Dass der Fehlschlag so lange unbemerkt blieb, lag daran, dass die Workflows nicht ausgeführt wurden (siehe Issue #170)
  • validate:appinfo brach im ersten CI-Lauf mit einer Meldung über einen nicht erreichbaren Docker-Socket ab (Issue #170). Die Validator-Kette in scripts/validate-appinfo.js probiert xmllint, dann php, dann docker und nimmt den erstbesten verfügbaren — „verfügbar" hieß dabei aber nur, dass das Binary existiert. Das Runner-Image bringt die docker-CLI mit, ohne dass ein Daemon erreichbar wäre, und hat weder xmllint noch php. isAvailable prüft jetzt, ob der Validator wirklich läuft (docker info statt --version), sodass die Kette korrekt durchfällt und bei gänzlich untauglicher Umgebung „Kein Schema-Validator gefunden" meldet statt eines Socket-Fehlers; zusätzlich installiert der JS-Job libxml2-utils, damit im CI immer xmllint gewinnt — der native XSD-Validator, ohne Daemon und ohne Netzwerk. Welcher Validator läuft, hing zuvor davon ab, was auf der Maschine zufällig installiert war
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturegDK8JkRgxBUCFljhxHFzTzf37tjhwQ/k9E+DCDeVHxPECDOF0J3FbWmv2uqmm9R7
H8yyFfL/KFEDK3Jt24o2gujQZ9KlyBYJvrfwv//zvACtgGoErBUamME+FzFfK3x8
rRdXt1iXctmwutRvTNPj8uvfMJmo/vdbJRDGEihI/9wVdt4S+O3/OlpdjUg+QGFP
cMmlQwIAHAWrYSUllnN4GeryrFPGB7fLi/Nrhx0eAwQHUjIZHEb/s9ZxjmnYZd0c
8FJsgAUXfjowOIrDtWxr0P+HVj4c5qhGx4XEUFdfR0slriaL+zPbo2Li1wgsBA7r
+yoo8ocOJPaN3iCpRNL4z8q2sxEuWRt2Dx0I5ck6F7g+gpzDoTo5bFEvq4Eir0wN
lGHhyxcdEK653dTKOBYI07tCjJYU+9VxCbRzR7O+sVI412Tox5W5cYGl4WpN8aNH
00CX7PLaruaEjwuFdAvhY6SzsXA3RFmN3Dv9qFx3dl3HjoQ+OCqy89XzT3tbBN07
3aZO7OgyB26al2XdRFaaRQaVLqjJzUCz2B5nh+z9+L+QcBl3F9sE2sFZnkWwx3bp
MOdj2nCS11r3Z0utRI9uDEanys6HkqnpGed4WEGX9O+EfocqNg2b0wgyqjFNWbxI
n4uoeakhyWYOVHCUfzU8tn6kmU4b8n+GfpMjKPhBeRw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=31.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.4
Release Details
UpdatedAug. 27, 2026, 7:06 p.m.
Changelog

Fixed

  • appinfo/info.xml wurde vom Nextcloud App Store abgelehnt: der Sprachcode pt_BR in <name>, <summary> und <description> ist im Schema nicht enthalten — die Enumeration kennt nur BCP-47-Schreibweise in Kleinbuchstaben mit Bindestrich. Alle drei Vorkommen heißen jetzt pt-br
  • Die Kindelemente von <info> sind im Schema eine feste Sequenz; <settings> stand vor <dependencies> und wäre nach dem Sprachcode-Fix als nächster Validierungsfehler aufgeschlagen. Der Block steht jetzt an der vom Schema vorgesehenen Position hinter <dependencies>. xmllint --schema gegen https://apps.nextcloud.com/schema/apps/info.xsd läuft damit sauber durch
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureYbjiEkGYW1s8Xg9Jvrt4nNo/67zkrQDA16yfK2MzVa58R982qrLUupNbvUE/FscP
pFg9nlqxd81cpyH1ZhWOM7fMq98mPyjSUsJZ7xjYzNccF13xvDpBXFlfX4UyCknc
50Rmw9a8RxiCH0mEpH9zWjdanX194R8cUIMDY+BcymCgyBVRQub9yaL5iiHH3hNA
OOD+UOiSUNHns9R6sgZ+tF4OeoTufWR5//AfRmuL5qC5spyuP1iKr7FnzPar+/sS
pHKojfUyi0sAjlrThVZDo8fvVPqkkH4jgvVmNE41t1UOlVdajIRd2yhbHX0h0SSs
rmt4CQqNXAjLE/Wlq2lu9Viw4M2BhhPIfVb5YJFzaxjhB8RRy53rquXRL64f7vGa
agq0ri3eD+0ZWmMOlJmHaMv6AXYd0ZG8myb3PAyNC0NYXzrw2PAVL8jDfzmq2cNY
Q3rIh101vtGPytqanNS2VmtfZ8BX63rd4SLR4PJdRYrm3Wbqanx8WZa20eLgYF8S
M9xhxl5Jf8+TnYLwHi1sGm1ID2XJ4krfgOxiUlB8lGeSweUK1uueC0bmUDsrXyhJ
RMGST41TU1HqXx/3Eeh91JKq/Jbx15kPuxu7WNKyuSOj4vKbgFwBUSmHKDU6lvEZ
L/bnxZi965/4K3kvyJ8o2j5e4xUmJLeusi9Fg0yrRqE=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.2
Release Details
UpdatedAug. 26, 2026, 5:18 p.m.
Changelog

Changed

  • Teilen-Dialog: das Eingabefeld für den einzuladenden Nutzer ist jetzt ein Suchfeld statt eines reinen Textfelds für die Benutzer-ID (Issue #144). Getippt wird nach Anzeigename, Benutzer-ID oder E-Mail-Adresse; ein neuer, admin-unabhängiger Endpunkt GET /api/v1/users/search (UserController::search(), IUserManager::search(), max. 20 Treffer, der eigene Account wird ausgeblendet) liefert dazu Anzeigename, Benutzer-ID und E-Mail als Vorschlagsliste. Gespeichert wird weiterhin die Benutzer-ID als principal_id – für Umgebungen mit LDAP/AD-Benutzerverwaltung war die zufällig generierte ID zuvor nicht ohne Umweg über die Benutzerverwaltung in Erfahrung zu bringen. Die Liste bereits geteilter Zugriffe zeigt ebenfalls den Anzeigenamen statt der rohen ID (ShareController::index() reichert die Antwort um display_name an, Fallback auf principal_id falls der Account inzwischen gelöscht wurde)
  • Übersetzungen für alle sechs Sprachen ergänzt
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureyLn/jlYbk3gIYfgIcjON0z467/xL9L6QNcmfgOa/4zhTJjLknXq7eu1UJddWWlLJ
NG2U9d/OEFO9wLHPYPGNiWgQMRIk+TGYlQVTXcZH3WpBxdJOm3XMnk5hq2kNB2FN
TJemqr/dxafGB2hTIgivPMXMnemdrtxWN1RAdzCxZIg9HwJWjG5JxdqHmURHwske
p/Ki/iZghKjrxbPIghbqtrvkCJRImbgVWY8AmUNUPLgotNIthiWFnkTDVhYWcreP
pWleWHxEn57UOtehff1aJa+hRI+8WVkx9iXArx0SThmOCYYgJ/HeG8dOOtmr9jSm
1nzETAL87YLxL/+qM6DyBIgNWhrq1oj9Q12bBm1+la477z6fpOgUlMjWkPEYRQi/
vhxirXwB4BZBYvaMEkNlN2U3+7BqgigGoaTcbN2rG/TP1JuOjdj9jEjMMRye0JbT
35XOoM/VPYGovrT9slHg8r3Wolyd8ioXVOu4IcMImvC5OrTzpKY7NLEc/S+cOKwz
ijOKcnoV0j++KxtQKKgEO96HJpEM0jteQVOGCoPbghjS3OFzkiB1bUVJAlu1jn54
38Q2zw8rZ0EMm1rEPmIrl72DIIXionbWKatREgy7QPwuL/WKZ2c+J1UIUTKck5eO
7M2VHh6P3FnIg/UsOCMu3U7ja0Y8vQ3YUo3tazLfob0=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.1
Release Details
UpdatedAug. 25, 2026, 1:28 p.m.
Changelog

Added

  • Screenshot des gerenderten Gantt-Charts als PNG, SVG oder PDF (Issue #116): ein neuer „Screenshot"-Eintrag in der Chart-Toolbar öffnet ein Menü mit den drei Formaten, derselbe Export steht im Bearbeiten-Dialog des Projekts neben JSON und CSV bereit (dort mit vorgeschalteter Formatwahl statt Menü, openScreenshotFormatDialog()). Exportiert wird stets das gesamte Chart, nicht nur der sichtbare Scroll-Ausschnitt — frappe-gantt rendert die volle Breite und Höhe ohnehin als eine SVG. PNG und SVG klonen die aktuell gerenderte SVG und schreiben getComputedStyle() als Inline-Attribute (löst auch CSS-Variablen auf), sodass die Datei ohne das App-Stylesheet eigenständig darstellbar ist; sie folgen dem eingestellten UI-Theme, ein hinterlegtes Rechteck in --color-main-background deckt dabei auch die Fläche unterhalb der Aufgabenzeilen (Workload-Chart, Leerraum) ab, die sonst transparent bliebe. PNG rastert per Canvas mit doppelter Auflösung
  • Zeitraum-Auswahl für den PDF-/Druck-Export (Issue #116): vor dem Drucken fragt ein Dialog, welchen Zeitraum die PDF abdecken soll — gesamter Projektzeitraum (Vorbelegung), laufendes Kalenderjahr, „aktives Quartal" (Vormonat bis einschließlich übernächstem Monat) oder ein frei eingegebener Bereich. Der Vorschlag ist der tatsächlich von Balken belegte Zeitraum, nicht gantt_start/gantt_end — frappe-gantt legt darum großzügig Puffer, der andernfalls mitgedruckt würde. Umgesetzt wird der Zuschnitt als viewBox auf dem SVG-Klon; die dafür nötige Skala (Chart-Start, Pixel pro Millisekunde) schreibt GanttChart.vue nach jedem Render als data-Attribute an den Chart-Container, sodass auch Aufrufer ohne Zugriff auf die frappe-Instanz (Bearbeiten-Dialog) sie lesen können. Die Zeitraum-Logik steckt isoliert testbar in src/gantt/printRange.js (src/gantt/printRange.test.js)

Changed

  • Der PDF-Export druckt nicht mehr den Live-Container, sondern einen gestylten, selbst gerasterten Klon des Charts (Issue #116). Bisher wurde das Inline-SVG direkt gedruckt — wie fein die Browser-Engine das rastert, ist nicht steuerbar und fiel je nach Browser sichtbar grob aus. Jetzt wird der Klon mit 300 dpi bezogen auf die bedruckbare Fläche (A4 quer, 10 mm Rand → 277 × 190 mm) in ein Canvas gerastert und als Bild mit fest vorgegebener physischer Größe in den Druck gegeben; schlägt die Rasterung fehl, bleibt der SVG-Klon als Druckinhalt übrig und skaliert per CSS auf die Seitenbreite. Der Klon wird immer im hellen Theme berechnet (Papier ist weiß, ein dunkles UI-Theme ergäbe sonst dunkelgraue Flächen und helle Schrift) — dafür genügt ein ausgelagerter Container mit gesetztem data-theme-light, da Nextcloud die Stylesheets aller Theme-Varianten lädt und nur über dieses Attribut umschaltet. Das Ausblenden der übrigen Seite läuft über display: none statt visibility: hidden, sonst blieb die Fläche der App als Leerseiten erhalten; Nextclouds Hintergrundbild auf html/body wird für den Druck abgeschaltet. Aufgeräumt wird über afterprint mit Timeout-Fallback für Browser, die das Event nicht feuern
  • Der Toolbar-Eintrag heißt „Screenshot" (Icon MonitorScreenshot) statt „Export" (Icon ExportVariant) — „Export" ist im Projekt bereits für den Daten-Export nach JSON/CSV belegt, der Chart-Export ist demgegenüber eine reine Abbildung der aktuellen Darstellung
  • Übersetzungen für alle sechs Sprachen ergänzt
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
Signaturek6kpvF53IR8tnkOFXyoSPFPGlwVzO/RUTgI1p1ppRcFmoFPUyFeIokOqWA1OtD9q
wdo+qkQQPyJGph0Uwp+hwP9oGmeKWErnlv8HMdA5I5iaXIN7afGvdfxWfKgqWetw
tGmCF7l2IzMmT2Ol/3pKgCnFkXTDPCVeNINNbUdi7EjeRpbcbOGWt3+5UVwZgVTX
Z9/kEEPvjMV98s1zT5yBXcFvyqZA7bhhezmBkfzaLa0DAIczFJbhyFtR06WuS7bP
CWBCs/xvSRuCwo61oyXRAWLohz/2GsrMSa5jvPvnEG1XEHpGPVorCijAvsBm4sX5
yAZTrBm3zbNYObqVE2idxTH/eqP8xXtE38JFjpG5IahpeFNb9V2EbH1nrjfRKYcH
NVvXcXFREAmvorShKDE0ymFN+/BCjvU1vnJCnRD5RMsoSGUzXSVHPrF1emtusLHj
ltP22eYOCpraEpZheTkFftqvpbiQKVXsZ+8wY4dJnh5Ymi71loxZhggoH8s/pmp+
WbSx6MZwSPBqJ0HOJWckFiZXur2OQYOVLfXt8uPYNU/EZSoYDqm81GVMglQXxyM6
YDh0xXqwJ7Qft7k0O/3Fa5YLJGP4B4RvjU29N3/WDsfjuk7PeCSTPhRlTOfV/Fbn
jS83WVBavmyklhu0rNYuCYfdYvUxemIO3VuGmYzFXgI=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.0
Release Details
UpdatedAug. 24, 2026, 5:26 p.m.
Changelog

Added

  • Editierbare Vorgänger-Spalte in der Tabellenansicht, Teilschritt F von #117 (Issue #124): eine neue, über das Spaltenmenü einblendbare Spalte „Vorgänger“ zeigt die Abhängigkeiten einer Aufgabe in der aus MS Project bekannten Kurznotation (12EA+2d = Vorgänger Aufgabe 12, Ende-Anfang, zwei Arbeitstage Abstand; mehrere durch ; getrennt) und nimmt sie dort auch entgegen. Typ (EA/AA/EE/AE, englische Kürzel FS/SS/FF/SF werden beim Eingeben mit akzeptiert) und Abstand sind optional, 12 allein bedeutet also EA ohne Abstand. Geprüft wird beim Verlassen der Zelle: Syntax, Existenz der Aufgabe im selben Projekt, Selbstbezug, Dubletten und Kreisschluss über die gesamte Abhängigkeitskette – bei einem Fehler bleibt die Zelle im Bearbeitungsmodus und nennt den Grund im Klartext, die bisherigen Abhängigkeiten bleiben unangetastet. Gespeichert wird über dieselbe PUT /tasks/{id}-Route wie der Detail-Dialog (inkl. dep_mode), sodass der Server die Termine anwendet und durch die Nachfolgerkette propagiert; Balken, Pfeile und Typ-Labels im Chart zeichnen sich mit der Antwort neu. Bewusst ohne Undo-Toast, da ein Zurücknehmen nur der Termine (nicht der Abhängigkeit) beim nächsten Neuberechnen wieder überschrieben würde. Nur Aufgaben haben eine editierbare Zelle – Meilensteine hängen über task_id an genau einer Aufgabe, Projekte und Teilprojekte sind berechnete Strukturebenen. Notation und Prüfungen stecken isoliert testbar in src/gantt/dependencyNotation.js (src/gantt/dependencyNotation.test.js)
  • Zeitabstand (Lag/Lead) je Aufgaben-Abhängigkeit (Issue #124): neue Spalte lag_days in nc_gantt_task_deps (Version1032; der Name vermeidet das seit MySQL 8.0 reservierte Wort LAG und nennt die Einheit). Der Abstand zählt in Arbeitstagen über den Ressourcenkalender wie die übrige Terminberechnung, wirkt bei allen vier Abhängigkeitstypen auf deren Ankertag und darf negativ sein (Lead: der Nachfolger beginnt früher). Bestandsabhängigkeiten bekommen 0 und verhalten sich unverändert. TaskService::update() weist eine gesendete Vorgängerliste jetzt vollständig zurück (invalid_dependency, dependency_cycle), bevor die bisherigen Abhängigkeiten dafür gelöscht werden, statt Vorgänger aus fremden Projekten oder Zyklen zu speichern – letztere hätten die topologische Sortierung in recalculateProject() stillschweigend Aufgaben überspringen lassen

  • Konfigurierbare Spalten in der Tabellenansicht, Teilschritt E von #117 (Issue #122): ein Menü in der Tabellenkopfzeile blendet Spalten ein und aus, die Reihenfolge lässt sich per Drag & Drop der Kopfzellen ändern (barrierefreie Alternative: Strg+Pfeil links/rechts auf der fokussierten Kopfzelle), die Breiten per Ziehen am Spaltentrenner (Doppelklick setzt auf die Standardbreite zurück). Zusätzlich zu den bisherigen Spalten (Titel, Start, Ende, Fortschritt) stehen ID, Dauer (Kalendertage inkl. Start- und Endtag, bei Meilensteinen 0), Status (Issue #78, nur Aufgaben/Teilprojekte) und Ressource (Issue #103, zugeordnete Ressourcennamen einer Aufgabe) bereit – alle vier als reine Anzeigespalten, die das Inline-Editing und die Tastaturnavigation daher überspringen. Auswahl, Reihenfolge und Breiten werden pro Nutzer über den in Teilschritt B angelegten UI-Preferences-Endpunkt persistiert (neuer Key gantt_table_columns, kein Schema- oder Endpunktwechsel nötig); eine gespeicherte Konfiguration wird beim Laden validiert, sodass entfernte Spalten oder unplausible Breiten die Ansicht nicht beschädigen können. Die Tastaturnavigation folgt jetzt der sichtbaren Spaltenreihenfolge statt einer festen Liste. Reicht die Tabellenbreite für die gewählten Spalten nicht aus, scrollen Kopfzeile und Zeilen gemeinsam horizontal; die Obergrenze des Splitters steigt dafür von 560 auf 900 px. Die Spaltenlogik steckt isoliert testbar in src/gantt/tableColumns.js (src/gantt/tableColumns.test.js). Ein Sortieren der Zeilen nach Spaltenwert ist bewusst nicht enthalten – es kollidiert mit der Hierarchie Projekt → Teilprojekt → Aufgabe und der sort_order, die das Chart für dieselbe Zeilenreihenfolge braucht

  • Tastatur-Navigation in der Tabellenansicht, Teilschritt D von #117 (Issue #121): Tab/Shift+Tab springen zur nächsten bzw. vorigen editierbaren Zelle (überspringt Zeilen ohne Schreibrecht, springt am Zeilenende zur nächsten/vorigen Zeile), Enter speichert und springt in dieselbe Spalte der nächsten Zeile, Esc bricht ab und stellt den vorigen Wert wieder her. Pfeiltasten bewegen die Zellauswahl, wenn gerade keine Zelle im Editiermodus ist (innerhalb einer Zelle bleiben sie für Cursor-/Wertänderung nutzbar). Die reine Traversierungslogik steckt isoliert testbar in src/gantt/tableNav.js (src/gantt/tableNav.test.js). Die ausgewählte Zelle bekommt einen sichtbaren Fokusrahmen und wird per scrollIntoView() ins Sichtfeld gescrollt – über den bestehenden bidirektionalen Scroll-Sync (Issue #119) folgt das Gantt-Chart automatisch mit. Neue ARIA-Rollen (grid/row/columnheader/gridcell, aria-readonly je Zelle) machen die Tabelle für Screenreader als Grid erkennbar
  • Read-only Tabellenansicht links vom Zeitstrahl, Teilschritt B von #117 (Issue #119): neue Komponente GanttTable.vue zeigt dieselben Zeilen wie das Chart (Titel mit Einrückung nach depth, Startdatum, Enddatum, Fortschritt), gespeist aus buildRowModel()/buildTableRows() (siehe Teilschritt A, Issue #118) – Reihenfolge, Filter-Dimming, kritischer Pfad und Projektfarben bleiben so exakt konsistent zum Chart. Zeilenhöhen sind fest an frappe-gantt gekoppelt (40 px = bar_height 22 + padding 18, Kopfzeile 52 px = header_height). Ein Toolbar-Button blendet die Tabelle ein/aus, ein Splitter macht die Breite verstellbar (160–560 px), vertikales Scrollen ist bidirektional mit .nc-gantt-container synchronisiert. Sichtbarkeit und Breite werden pro Nutzer über einen neuen, generischen UI-Preferences-Endpunkt (GET/PUT /api/v1/ui-preferences, SettingsController über IConfig::get/setUserValue() als JSON-Blob) persistiert, damit Teilschritt E (Editieren) das Schema nur noch um weitere Keys erweitern muss, ohne Endpunkt oder Speicherformat anzupassen. Rein lesend – Editieren folgt in Teilschritt C
  • Projekt-Export/-Import (JSON, format_version: 2) kann jetzt optional die von den Aufgaben referenzierten Ressourcen inkl. Gruppe, Wochenmodell, Arbeitskalender+Feiertagen und Tageskapazitäten mitnehmen, statt wie bisher nur die rohe resource_id in eine Zieldatei zu schreiben, die dort ungeprüft übernommen wurde – auf einem System ohne identische Ressourcen-IDs ging die Zuordnung damit verloren oder landete schlimmstenfalls bei einer fremden Ressource (Issue #115). Vor dem JSON-Download entscheidet ein Options-Dialog, was mitexportiert wird (Ressourcen / Verfügbarkeiten / Kalender, gestaffelt); vor dem JSON-Import zeigt ein passender Dialog, wie viele Ressourcen die Datei enthält, und lässt auswählen, was übernommen wird sowie ob bei Namensgleichheit die vorhandene Ressource wiederverwendet (Default) oder immer neu angelegt wird. Referenzen werden ausschließlich über eine Mapping-Tabelle aufgelöst und nie roh durchgereicht; nicht auflösbare Referenzen werden verworfen (Regressionsschutz zu #112/#113). Neu angelegte Ressourcen/Gruppen/Kapazitäten gehören stets dem importierenden Nutzer. Wochenmodelle/Kalender/Feiertage sind weiterhin admin-only anlegbar – ohne Adminrechte werden nur namensgleiche vorhandene Einträge gemappt. CSV bleibt unverändert aufgabenzentriert mit Ressourcen nur als ID-Referenz; der volle Ressourcenumfang ist JSON-only. Alt-Exporte ohne resources-Schlüssel importieren unverändert wie bisher, ohne Options-Dialog
  • Inline-Editing der Basisfelder in der Tabellenansicht, Teilschritt C von #117 (Issue #120): die Zellen für Titel, Start, Ende und Fortschritt sind direkt editierbar und aktualisieren die Balken im Chart sofort. Gespeichert wird über die bestehenden Store-Actions (updateTask/updateSubproject/updateMilestone/updateProject) inkl. Terminpropagation und dem vorhandenen Undo-Toast für Aufgaben (analog Drag & Drop im Chart); ein lokaler pendingEdits-Overlay zeigt die Änderung optimistisch an und rollt sie bei einem fehlgeschlagenen Request mit Fehlermeldung zurück. Die Schreibrechte löst tableRows.js je Feld über store.canEditProject() auf (titleEditable/startEditable/endEditable/progressEditable) – Projekte und Teilprojekte bleiben bei Datum und Fortschritt read-only, da diese Werte aus den Aufgaben berechnet werden. Geprüft wird: Titel nicht leer, Enddatum nicht vor Startdatum (Meilensteine ausgenommen, deren Start- und Endspalte dasselbe milestone_date zeigen) und Fortschritt 0–100. Im Simulationsmodus rufen Datumsänderungen an Aufgaben simulateTaskChange() statt einer echten Speicherung auf
  • Ressourcen-Überbuchungswarnung (Issue #82): die Kapazitätsplanung war bisher reine Datenerfassung ohne Abgleich mit dem tatsächlich verplanten Aufwand. Der neue Endpunkt GET /api/v1/resources/{id}/utilization?from=&to=&group= (ResourceUtilizationService/ResourceUtilizationController) stellt den geplanten Aufwand aus den Aufgaben-Ressourcen-Zuordnungen – gleichmäßig auf die Arbeitstage der Aufgabe verteilt, über WorkCalendarService mit ressourcenspezifischen Arbeitstagen und Feiertagen – der erfassten Tageskapazität gegenüber. Mehrfach-Ressourcen-Zuordnungen (Issue #103) samt Alt-Aufgaben werden berücksichtigt, ohne gepflegte Tageskapazität gilt ein Fallback von 1 PT/Tag. Im Ressourcen-Raster färben sich die Zellen nach Auslastungsgrad (> 90 % gelb, > 100 % rot) und der Tooltip zeigt geplante Stunden gegen Kapazität samt Aufschlüsselung nach Projekt und Aufgabe; das Workload-Chart im Gantt markiert überbuchte Perioden jetzt rot. Übersetzungen für alle sechs Sprachen ergänzt
  • Nachgetragen – beide Funktionen wurden bereits mit 1.4.2 ausgeliefert, waren dort aber nicht im Changelog dokumentiert:
  • Einheitliches Statusmodell für Teilprojekte und Aufgaben (Issue #78): neues Feld status (not_started/in_progress/blocked/done) auf nc_gantt_subprojects und nc_gantt_tasks ergänzend zum numerischen Fortschritt, Bestandsdaten leitet Migration Version1030 daraus ab. Validierung per StatusValidator (Whitelist analog ColorValidator), Status-Dropdown in den Detailformularen, blockierte Balken im Gantt schraffiert und mit Warnsymbol, blocked_count je Projekt im Rollup sowie ein Badge in der Projektliste
  • Mehrere Ressourcen mit individuellem Aufwand je Aufgabe (Issue #103): bis zu vier Ressourcen je Aufgabe mit eigener Aufwandsschätzung in der Einheit der Ressource (neue Tabelle nc_gantt_task_resources, Migration Version1029, Backfill aus den vorhandenen resource_id/work-Werten). Das manuelle Work-Feld entfällt: TaskService::resolveResources() summiert die Einzel-Aufwände zur Gesamt-Work (1 PT = 8 h) und übernimmt die erste Zuordnung als primäre resource_id, die weiterhin für Arbeitskalender und CPM maßgeblich ist. Ressourcen-Filter sowie CSV-/JSON-Export und -Import berücksichtigen alle Zuordnungen statt nur der primären

Changed

  • buildFrappeRows() (src/gantt/frappeRows.js) mischte bisher Datenmodell und frappe-gantt-Formatierung: die Einrückungstiefe steckte als Leerzeichen im name, Zustände (Dimming, kritischer Pfad, Summenbalken) hingen in custom_class – eine geplante Tabellenansicht neben dem Gantt-Chart (Issue #117) hätte dieselbe Logik duplizieren müssen (Teilschritt A, Issue #118). Neue Funktion buildRowModel() (src/gantt/rowModel.js) liefert dieselbe Zeilenliste jetzt als neutrales Modell (id, type, entityId, depth, title, start, end, progress, parentId, editable, matched, critical), resolveMilestoneDate() wandert mit ins Modell. buildFrappeRows() ist nur noch ein dünner Adapter darüber, der name/custom_class/dependencies wie bisher erzeugt. Reines Refactoring ohne sichtbare Änderung, per Fixture-Vergleich gegen die alte Implementierung geprüft; neue Unit-Tests (src/gantt/rowModel.test.js, npm run test:unit, via neu eingeführtem vitest) decken Hierarchie, Einrückungstiefe, Meilenstein-Datumsauflösung und Filter-Dimming ab

Fixed

  • Abhängigkeitsfortschreibung bei Aufgaben lieferte für alle vier Abhängigkeitstypen (EA/AA/EE/AE) einen um einen Arbeitstag zu langen Nachfolger-Termin – bei EA zusätzlich mit falschem Anschlusstag, da der Nachfolger auf dem Endtag des Vorgängers statt am folgenden Arbeitstag begann und dadurch mit dem Vorgänger überlappte (Issue #114). Ursache war eine Off-by-one-Vermischung zwischen der inklusiven Arbeitstagszählung und der exklusiven Datumsfortschreibung in TaskService::applyConstraint()/computeMultiConstraint(). Betroffen sind sowohl das direkte Setzen einer Abhängigkeit als auch die Terminpropagation nach Drag & Drop und die What-if-Simulation. Verhaltensänderung: Bestehende Pläne mit EA-Abhängigkeiten verschieben sich beim nächsten Speichern/Neuberechnen um einen Arbeitstag nach vorne (auf den korrekten Anschlusstag); bei AA/EE/AE verkürzt sich der zuvor fälschlich verlängerte Nachfolger-Zeitraum um einen Arbeitstag, die ursprüngliche Dauer bleibt jetzt garantiert erhalten. Abhängige Meilensteine (Dauer 0) sind unverändert korrekt und von diesem Fix nicht betroffen

  • Security: jeder Nutzer mit Schreibrecht auf ein eigenes Projekt konnte jede in der Instanz existierende resource_id einer eigenen Aufgabe zuordnen – unabhängig vom Eigentümer und ohne jede Share-Beziehung (Cross-Tenant-IDOR, Issue #112). TaskService::resolveResources() lud die vom Client gesendeten IDs bisher nur über ResourceMapper::findByIds(), also als reine Existenzprüfung ohne Berechtigungscheck; da die IDs fortlaufende Integer sind, waren sie trivial zu erraten. Der Listen- wie der Legacy-Einzelfeld-Pfad in create()/update() filtern referenzierte IDs jetzt über ResourceMapper::findVisibleToUser(), nicht sichtbare IDs werden wie unbekannte verworfen (Liste) bzw. nicht übernommen (Einzelfeld, der bestehende Wert bleibt erhalten). Regressionstests decken beide Pfade für create() und update() ab

  • Feiertage ließen sich nicht in mehreren Regionskalendern führen: POST /admin/holidays lief in einen HTTP 500, sobald dasselbe Datum in einem zweiten Kalender angelegt wurde, weil der Unique-Index aus Version1006 allein auf holiday_date lag, obwohl Feiertage seit Version1013 über calendar_id kalenderbezogen sind. Version1031 verschiebt den Index auf (holiday_date, calendar_id); die Eindeutigkeit globaler Feiertage sichert weiterhin der Upsert in HolidayAdminController::create(). Betroffen war neben der Feiertagsverwaltung auch der Kalender-Import aus einem Projekt-Export, wo der Fehler still verschluckt wurde. Zweitens war GET /admin/holidays admin-only, während work-calendars und work-schedules lesend für alle offen sind – für normale Nutzer blieb der Store deshalb immer leer (keine Feiertage im Projekt-Export, keine Markierung arbeitsfreier Tage im Ressourcen-Raster); der Lese-Endpunkt zieht nach dem Muster der übrigen Stammdaten auf /api/v1/holidays um (NoAdminRequired), Anlegen und Löschen bleiben unter /api/v1/admin/holidays. Ergänzend werden Feiertage jetzt mit ihrem Kalender gelöscht (WorkCalendarController::destroy(), HolidayMapper::deleteByCalendar()) und Bestandswaisen bereits gelöschter Kalender in Version1031 aufgeräumt – über verweisende Ressourcen haben sie bis dahin weiter als arbeitsfreie Tage gewirkt
  • Die Installation der Tabelle nc_gantt_task_resources scheiterte auf Instanzen, deren Tabellenpräfix die von Nextcloud aus Oracle-Kompatibilität erzwungene 30-Zeichen-Grenze für Bezeichner reizt: der von Doctrine automatisch vergebene Primary-Key-Name (Tabellenname + _pkey) wird mit Präfix oc_ zu lang (Issue #132). Die Primärschlüssel-Definition bekommt – analog zu den bestehenden Migrationen für nc_gantt_resource_capacity und nc_gantt_resource_groups – einen expliziten kurzen Namen
  • Der absolut positionierte Toggle-Button der Nextcloud-App-Navigation ragte in den App-Content hinein und verdeckte dort den Titel des ersten Eintrags in der Projekt-Rollup-Leiste (Issue #134); der linke Innenabstand reserviert jetzt Platz für den Button
  • Ein leerer Balken in Höhe der Kopfzeile erschien oberhalb des App-Inhalts, weil der CSS-Reset für den Nextcloud-Content-Wrapper an main#content.app-nc_gantt gekoppelt war (Issue #126). Ändert sich das Markup zwischen Nextcloud-Versionen (Klasse oder Tag), griff der Reset nicht mehr und der von NcContent (#content-vue) selbst gesetzte margin-top: var(--header-height) addierte sich zum Rand des Cores. Der Reset hängt jetzt robust an #content mit !important, ohne Abhängigkeit vom app-spezifischen Klassennamen
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturegO8Qmtdwg8LOBKr5G+mq4co374hsqqSN6oCIRV9atUx0KqogPxisJiIExkPoSIbu
e4EeIaUzg2alhZsKBLWOwR3Ab3fNm5vvd2DzJn6Hei7A70woz9m/LXkVlcx3vALW
bwolClUX1XCZOBVo/kSS5AOVwak3/huzT1iF9xH9BnpdzVuOjZ563LYwSayfb2Gq
SkWNfLZlKlDkTTF2PIszrNmaa89GmyqTbraxSP16/9nYdIj8ZU0zrhC3HtpihgAT
wya2lwnMf6I73HU0xxgT/+ITTmurx4eHwKWH80P4tjg/Y9mnHODIpAslbW3351mc
qdTHXIBW1MB1YGCQ+JPt11v1X2ccn29kEF9d1nkizKZ1+Du+LJQhPhwHiQxPWSwAUlTlQ4tj1lbe3+FJ1jsVTCqWbDUN02EoV7ZwtN15/HLJfM6w4drUi8ThJ1aLG3v6
cIwMJjYgWeepxR2gv4YgBf4u7txodm5bAWuzySk4rfAG1dBxmie/bfNnWmQ9LrYy
spwKc73gsPhg03ll+jp0b27fJfNF4IpOysz3i+r1ExVfeNIWWO91JPatO2pXZh4O
q0rczM8wYvctvcEkKQIL67HoIrKw4GVIXfqM9Oc8e/Ay7d/NPL+BjpCO6zvoFBY+
SRmjit15YmGW4EQwweQfKXuZ2YeySj+7OjhKHpKfvfg=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.2
Release Details
UpdatedAug. 20, 2026, 4:41 a.m.
Changelog

Changed

  • release.sh fragt die Versionsnummer jetzt interaktiv ab, statt sie nur aus appinfo/info.xml zu lesen: zu Beginn werden die aktuelle Version und das letzte Release-Tag angezeigt und es wird gefragt, ob eine neue Nummer vergeben werden soll (Vorschlag: nächster Patch-Level). Die Eingabe wird auf das Format X.Y.Z, auf einen echten Versionssprung und auf ein noch nicht vergebenes Tag geprüft und dann nach appinfo/info.xml, package.json und package-lock.json geschrieben. Fehlt ein Changelog-Abschnitt zur neuen Version, warnt das Skript; anschließend bietet es an, den Bump als chore: Version X.Y.Z zu committen — nötig, weil der Tag-Name den Commit-Hash enthält. Für nicht-interaktive Läufe gibt es --version=X.Y.Z und --no-bump; ohne TTY wird nie gefragt, make release bleibt also unverändert nutzbar
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturepoVHZxteU3AR2cpRRV98jNfv4j7rWnLEd3kbpn5Dp4T1ubAI+0QlRf9jxi0BaYz1
+1dg+3Yt25uN6Slp1FHiw7kyqt5HJ60XgnOWo+Zt0YBHSnWqLDhF8zxPEnQCkF+v
nUvscpcoQY2bRiIBZhVWVgeAD592uvOA4gfRDrUyLVDKjOrzBu3ScbNvCqTqE9IC
vs8qZkRLIcaD6tKoSLT2pZqmwBoCdClvEw5D5v40WSvLq232BZnXpQ4ogG3QvJdL
mYO8HlPZKVOxANp0MGnWle4IFRMbMt22Ebpkjc18Q9Q4AIv/Sd3zTsc+uMONTM95
s0GXvLSm95o0UCFZ1CL7fCEq7NwlprjVrTeWGmlJNVjHJuIyRKHEz5DR12s0lAGm
/rKGWjoVP+Wvk3upRizR/5y2fpWoiwuDqCtz9gQN6+HHYLaqLvYqsAJ/SxmtLtP7
8B2rK61ClKowz4phbTZdrCaF8w3IWnFFBTFquIVFuN2jUoHvdCMtd0910sLAMY5M
Xs9nk0FVsP23zKXlQpOojq7ouCQagRhsnBJDLxWRR+NIq582f7SDgcrkBqxlGJX4
/Ql9V+2iFx61QANCTjdJIO3LbvbK60vGos+ency0GfvSDbPovDAVyJzt8ZUh5BNw
UXQ4XOHJZAagAr36rKttk1DQbZZ/2bUEq231c96m83g=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.1
Release Details
UpdatedAug. 17, 2026, 7:43 p.m.
Changelog

Fixed

  • Die Meilenstein-Raute hatte eine fest verdrahtete Farbe (#fbbf24) statt der Projektfarbe zu folgen, obwohl Balken für Aufgaben und Teilprojekte bereits korrekt eingefärbt wurden (Issue #102). Zusätzlich wurden die separaten – und wirkungslosen – Farbwähler bei Teilprojekt und Aufgabe entfernt, da deren Anzeige ohnehin immer der Projektfarbe folgt
  • „Meilenstein hinzufügen" im Drei-Punkte-Menü der Projektliste nutzte zwei aufeinanderfolgende window.prompt()-Dialoge (Name, dann Datum als Freitext) statt des regulären Detail-Dialogs (Issue #101). Der Klick emittiert jetzt add-milestone analog zu „Aufgabe hinzufügen" (Issue #91) und öffnet denselben Meilenstein-Dialog wie beim Bearbeiten, mit vorbelegtem Projekt
  • Im festen Datumsmodus des Aufgaben-Detaildialogs konnte ein Enddatum vor dem Startdatum eingegeben und gespeichert werden (Issue #100). Jetzt zieht ein über das Enddatum hinaus verschobenes Startdatum das Enddatum mit; ein zu frühes Enddatum erzeugt ein rotes Fehler-Icon am Feld, hält den Fokus dort und deaktiviert den Speichern-Button, bis ein gültiges Datum eingetragen ist (dateField() in fields.js mit neuer setError()-Methode)
  • Eine Aufgabe mit Abhängigkeit behielt trotzdem die manuell eingegebenen Start-/Enddatumsfelder, die beim Speichern durch die Abhängigkeitsberechnung überschrieben wurden – für Nutzer nicht nachvollziehbar (Issue #99). Der Aufgaben-Detaildialog hat jetzt denselben Fixed-date/Dependency-Umschalter wie Meilensteine (Issue #90): im Dependency-Modus ersetzt eine Dauer (Tage) die Datumsfelder, die Abhängigkeit bestimmt den Termin. Serverseitig wendet TaskService::create() neu hinzugefügte Abhängigkeiten sofort an (bisher nur update()), damit auch neu angelegte Aufgaben keinen die Abhängigkeit ignorierenden Platzhaltertermin behalten
  • Der Speichern-Button des Detail-Dialogs blieb nach dem Hinzufügen einer Abhängigkeit deaktiviert: die Gültigkeitsprüfung hing allein am input-Event, das bei einem <select> vor dem change-Event feuert – zu diesem Zeitpunkt war die Abhängigkeit noch nicht in der Liste. detailModal.js wertet jetzt zusätzlich change aus, der Abhängigkeits-Editor (fields.js) meldet jede Mutation (Hinzufügen, Entfernen, Typwechsel) und der Fixed-date/Dependency-Umschalter in taskForm.js den Moduswechsel über ein eigenes bubbelndes change-Event

Added

  • CONTRIBUTE.md und setup-dev.sh für neue Mitwirkende (Issue #98): Projekt-Leitlinien (FOSS, Datensparsamkeit, Security), VIBE Coding ausdrücklich erlaubt, sowie der komplette lokale Dev-Setup-Weg (Docker-only, Nextcloud + MariaDB unter localhost:8088, optionales E2E-Setup, Git-/Bot-Auth). setup-dev.sh automatisiert diese Schritte, konfigurierbar über --workdir/--no-e2e/--no-docker-install
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturetYcUvVtDEQrAakG32EQF1atSOmz91/8XudCUh60A9r/AxMv+AA5AX2rIvNYDkEn0
OuTmXA6Iz0DoVkdij11MPDhfLaUy0mXeLbwB5fj/xF/cFYcNeCFGKD3k2jyRwOTo
2n1sEp0r8sn0fitHzLfhcB/By0VJkZyhaO/NctP01XfcSQM7lGEOeY/uagtGaDTI
JnPLoQTHo0nUOv4y7jUMZuurEgBOc4yeUxTKv4A/m642hvNQIS0q6K9ON41JHKIO
UtI7DbDWSboVhct1Go3zoj5XcaAGG9ZiwSkJDt/BXT5tWH4SOnSn7mys0j1F6Y0g
vIJWjz6S2RlekwIrIxgyaeEVBOeQ4OM1ilJGWKXDyYJM/0IBxqnqRXDkAFlOopDo
xezlcFdWTkYL5OBKMFJhKuTy7dEQ9hxx5Nz4+vLbNV8gDJZBI+5yI5m8W+809WIH
iKUpIda1ShOblvYH6Ek5AzBdTmoFQ6T4f7iWT7j1i4uUP2DsgehjGVl8yDIT/wyx
nV9t7koXapu1WeXrunSa++mXsi3lceNpthdz5/cUEOe9yWvc1rrulRhiWzePga8H
zjVQYGAIPvwYkWa47U6Zh7HBsQaS+9yQ8NDnD49SS4jUWTGlwNqfM+q9fZ16/G9d
7l4chZUPPbBv+xWfdxmFw+MC5zdkAq27isHToTqnm+w=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.0
Release Details
UpdatedAug. 13, 2026, 6:41 a.m.
Changelog

Added

  • Meilensteine werden jetzt immer direkt unter ihrem übergeordneten Objekt angezeigt statt gesammelt am Projektende (Issue #90): Meilensteine lassen sich neu auch einer Aufgabe zuordnen (bisher nur Projekt/Teilprojekt, Spalte task_id war bereits vorhanden, es fehlte nur die UI), das Auswahlfeld im Detail-Dialog heißt entsprechend „Übergeordnetes Objekt" statt „Teilprojekt". Zusätzlich können Meilensteine ihr Datum jetzt statt eines fixen Werts aus einer Abhängigkeit zum übergeordneten Objekt beziehen (EA/AA/EE/AE, analog zu Aufgaben-Abhängigkeiten; neue Spalte dependency_type, Migration Version1028) – da ein Meilenstein keine Dauer hat, bestimmen EA/EE das Ende und AA/AE den Start des Zielobjekts. Die Berechnung übernimmt der neue MilestoneDateService (serverseitig live bei jedem Abruf sowie im ICS-Feed neu aufgelöst, nicht persistiert propagiert) sowie clientseitig in frappeRows.js für sofortige Reaktivität ohne Neuladen
  • Undo für Drag-&-Drop-Verschiebungen inkl. Propagationskette (Issue #85, Umsetzung der einstufigen Empfehlung: letzte eigene Operation, kein Redo, zunächst nur Drag & Drop): Migration Version1027Date20260810020000 ergänzt nc_gantt_change_events um op_id (UUID) – alle Change-Events einer zusammenhängenden Operation (Drag + gesamte Propagationskette B→C→D) erhalten dieselbe op_id, erzeugt in TaskService::update()/propagateDates() und über ChangeEventService::log() protokolliert (dieses Change-Tracking war bisher tote Scaffolding-Logik ohne Aufrufer). Neuer Endpoint POST /api/v1/changes/{opId}/revert (ChangeEventController::revert, ChangeEventService::revertOperation) wendet alle Change-Events der Operation invers an, in einer DB-Transaktion mit Rechteprüfung über AccessService::canEditOrOwn(). Konfliktschutz: Revert wird mit HTTP 409 abgelehnt, sobald der aktuelle Feldwert nicht mehr dem protokollierten new_value entspricht (jemand hat zwischenzeitlich erneut geändert); der Revert selbst erzeugt wiederum neue Change-Events, die Audit-Historie bleibt lückenlos. Frontend: nach jedem gespeicherten Drag zeigt GanttChart.vue einen Toast „N Termine verschoben — Rückgängig" (showUndo aus @nextcloud/dialogs, 10 s sichtbar) sowie ein globales Ctrl+Z für die letzte eigene Operation der Session (stores/projects.js: lastOperation, revertOperation(), undoLastOperation())
  • Kalender-Export als abonnierbarer ICS-Feed pro Projekt (Issue #83, Variante A aus dem Umsetzungsvorschlag): neue öffentliche Route GET /apps/nc_gantt/projects/{id}/calendar.ics?token=… (regulärer, unauthentifizierter CalendarFeedController, damit externe Clients wie Thunderbird, Nextcloud Kalender oder mobile Apps ohne Nextcloud-Login abonnieren können) liefert Meilensteine als ganztägige VEVENTs (◆-Präfix), den aus den Aufgaben abgeleiteten Projektzeitraum sowie optional Teilprojekt-Zeiträume (Schalter „Auch Teilprojekt-Zeiträume einschließen", standardmäßig aus, um den Feed bei großen Projekten nicht zu überladen). Zugriff erfolgt über einen pro Projekt generierten, 256-Bit-zufälligen Token in der URL (CalendarFeedService, neue Spalte calendar_token auf nc_gantt_projects, Migration Version1026), der über einen neuen „Kalender-Feed"-Bereich im Freigabe-Dialog angezeigt, kopiert und jederzeit widerrufen/neu generiert werden kann (CalendarTokenController, nur für Projekt-Admins/-Eigentümer). ICS-Generierung ohne neue Abhängigkeit, RFC-5545-konform (Escaping, Zeilenfaltung)
  • What-if-Simulationsmodus für Terminverschiebungen (Issue #84): neuer Endpunkt POST /api/v1/projects/{id}/simulate führt Terminpropagation und CPM rein im Speicher aus (kein DB-Schreibzugriff) – TaskService::simulate() nutzt die neu extrahierte, stateless propagateDatesCore()-Kernlogik, die auch der persistierende update()-Pfad verwendet, CriticalPathService::computeFromTasks() erlaubt CPM auf einem hypothetisch veränderten Task-Datensatz. Frontend: „Simulation"-Toggle in der Gantt-Toolbar mit Banner inkl. Projektende-Delta in Arbeitstagen, Geisterbalken für die Ist-Termine (analog Baseline-Overlay) sowie Verwerfen/Übernehmen. Drag & Drop ruft im Simulationsmodus simulate() statt einer echten Speicherung auf. Szenarien bleiben bewusst flüchtig (kein Speichern benannter Szenarien), „Übernehmen" wendet die Änderungen als einzelne Task-Updates an, Simulation läuft pro Projekt
  • Neuer Eintrag „Aufgabe hinzufügen" im Drei-Punkte-Menü der Projektliste (Issue #91): legt wie der „Neu"-Button eine Aufgabe an, belegt dabei aber das gewählte Projekt direkt vor, sodass der Projekt-Auswahlschritt in der Maske entfällt
  • Such-/Filterleiste für Projekte, Teilprojekte und Aufgaben (Issue #81, Stufe 1: rein clientseitig auf Basis der bereits geladenen Daten aktivierter Projekte): Freitextsuche im Titel, Risiko, „überfällig" (Ende < heute und Fortschritt < 100 %), „über Budget" (Ist-Kosten > geplantes Budget), Ressource und „ohne Deck-Verknüpfung". Neuer Pinia-Store stores/filters.js (Zustand pro Nutzer in localStorage persistiert) und reine Matching-Logik in gantt/filterMatch.js. Nicht passende Balken werden in GanttChart.vue gedimmt statt ausgeblendet (Abhängigkeitspfeile und Zeitkontext bleiben lesbar), Projekte/Teilprojekte gelten als Treffer, sobald ein Nachfahre passt. Dieselbe Filterleiste (components/FilterBar.vue) dimmt in ProjectList.vue nicht passende Projekte; für nicht aktivierte Projekte sind nur Titel-Treffer zuverlässig auswertbar, da deren Aufgaben/Teilprojekte nicht geladen sind

Changed

  • Freigabe für Nextcloud 34 (Issue #94): max-version in appinfo/info.xml von 33 auf 34 angehoben, unterstützter Bereich damit NC 28–34. Verifiziert gegen Nextcloud 34.0.2 mit PHP 8.5 und MariaDB 11.4 (148 Unit-Tests, 39 E2E-Tests)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturerdYQI+Semnk0cWtKqUZinVDHk0KpxyqB5Ox4NBL9pyf5nrpK8xZpe9lBxc6zhDfW
8adLfVIwQtX+bI7S1O05xm0hwrUHQQ2ii6ADD8mlAxnZjdhKSCAhZ0NcaqT7Em0X
nD7yRP2B8zAAQMJNjzeBsLbzveNrXMoGzFrvm/jFxskUIUS01ykfWEg2C5+5/IAf
7jBAM8x2Qj92b8zyBFpLjfJQw9aTE/trtCsmZXQFmkJjGS0anrJc9dXKfqnHxknX
8jmLOv4Yq4Qtk3UF35HTiIGcA2W0UKfVyFb4XcrIMeSmLXXcagJWjeH5nB18UUNn
JyCgE/qY4v/SnrNQU92mIdMOQGuvYg7xbaz226lgNdwM2HuM9U8nc2juqJxAO+Wp
xs85yl82qIviZ5YY39HK371MZ/ufMsaVsVy3Nfn3PjqqkzGLmtAL6KJDcKHZWdDw
ugEPwO61DxnERZsNGeFpXfzCxjMpZc/qwUIfGw85idmU2vdedtrxHBkDGoqu1IP7
xZOO8uSYrzbXM6g1gs3WPBOY51CmZLs5pIQTN1tVl5ifGw4uOuzDBUCKiR5oA2MI
352HbA7wwWFgwoN9W5t4MRTowmaYpM8AB+nh9f1A5q9S8SelfMpXOqGew9VZb2jd
AuiJK/LEPjRgs5s3/FfC4Sb1MSsXDr1N1jziaF4MomM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.3.1
Release Details
UpdatedAug. 6, 2026, 12:57 p.m.
Changelog

Added

  • Regressionstests für die Rollentrennung Viewer/Editor/Admin: ForbiddenException-Tests für TaskService::create/update/delete/syncProgress und ProjectService::updateProject/deleteProject (inkl. „Editor darf nicht löschen") sowie erstmalige Testabdeckung für SubProjectService und MilestoneService

Fixed

  • CSV-/Formel-Injection im Aufgaben-Export (detail/io.js exportCsv): Task-Felder wie Titel oder Beschreibung, die mit =, +, - oder @ beginnen, wurden unverändert übernommen und von Excel/LibreOffice/Google Sheets als Formel ausgewertet. Die Absicherung aus ReportView.vue liegt jetzt in einer gemeinsamen Utility (src/utils/csv.js, escCsvCell) und wird an beiden Export-Stellen verwendet
  • Viewer sahen im Frontend dieselbe Oberfläche wie Editor/Admin (Add Task/Subproject/Milestone, Share, Delete Project, Drag/Resize im Gantt-Chart, volle Bearbeitungsformulare), obwohl das Backend Schreibversuche ohnehin korrekt ablehnte – kein Least-Privilege an der UI. ProjectService::getAccessibleProjects()/getProject()/createProject()/updateProject() liefern jetzt das effektive permission-Feld (AccessService::getEffectivePermission()) mit; ProjectList.vue, GanttChart.vue (inkl. Drag/Resize-Sperre je Projekt) und das Detail-Modal (detail/detailModal.js) blenden Schreib-Aktionen für Viewer aus bzw. schalten Formulare read-only
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureBUyDeI9y7iKD1wQJLHrW6IFq0zuXOJQ1Zv/x+0RryIIQ0fAGAUjwQyLDYLYpRzPg
6ITDPfY9bftVlwkB8w9LqZiFETkH8mgc6l5XB7F6NKzFrdaSnNw21CIVJjWyHpkR
mxDq+vQepZd+YtB9jMz39kbFk9BNHrpKIwIXXZVqEqj1U54NmT+5XnT892m9mY6o
RWQNf3Mn5WcH3vmoDi/UAOgDaO30GFCRJePryurVpK7stkub8K6fYsWIkS5NeJlP
YHdb4nBlkhUzQFjo0ZDSkCSiWjMdyCrtEanX6m6Ffhr+j0jpd+J9soMSjrzdzt4T
5mETo8xc61IQIVFWMD6fZ3/oCmbx2TFDZsJjRpFKxoPA08AkdC7xjxHoaKYZHvi4
+tzowxPzMfyjQ/hEj2dwq22doM2lXK1Y13VvV8kkaomrAQjB97gf+ODrYZNDgNvc
2ijU08B4cAB0HbEveDpDRjCJj8D5OwCMafRMa4Ul/nm0+RiBFOhIjDYdVAnCp7Ql
IEc4UQZM9WYLQlouwGPk83POpbqkbc8vKAucGBXvHAbxNpUSOGbssMYFGU/e9pOg
+oT2gcJrC3MYPGIWnS8iLn75PK1H063KFJv5yqC+h/rqwX/FxyTzKvofJi68GpLs
WtG3y67W8Ju4y1I9iQ9raJxxhFUJrStibGy9gc7L0DM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.3.0
Release Details
UpdatedJuly 9, 2026, 5:23 a.m.
Changelog

Fixed

  • Baseline-Toggle im Gantt-Toolbar zeigte nie Baseline-Balken und PUT baseline/active warf einen SQL-Fehler: baseline_id auf nc_gantt_projects wurde mit der 3-Ebenen-Migration versehentlich zusammen mit den tatsächlich berechneten Spalten entfernt (Migration Version1025 stellt die Spalte wieder her). BaselineService::create() aktiviert eine frisch eingefrorene Baseline jetzt automatisch fürs Projekt; renderBaselineBars() (GanttChart.vue) und baselineOverlay.js lesen Baseline-Items dafür über task_id statt des seit der Umstellung auf das 3-Ebenen-Modell nicht mehr existierenden subproject_id-Felds
  • OCS-API-Fehlerantworten (400/404/500 …) lieferten für alle OCSController-Endpunkte einen leeren text/html-Body statt des erwarteten JSON-Envelopes mit message; ExceptionMiddleware wirft jetzt passende OCP\AppFramework\OCS\OCSException-Subklassen statt einer rohen DataResponse, die Nextcloud-Core nur für 401/403 automatisch formatiert. Betroffene Controller (ProjectController, ReportController, ShareController, ChangeEventController, WorkScheduleController, WorkCalendarController, HolidayAdminController, SettingsController) wurden zusätzlich auf die bestehende ApiException-Hierarchie umgestellt

Removed

  • Nie ausgewertete Gruppen-Freigabe-Option entfernt: Share::TYPE_GROUP, principal_type-Parameter in ShareController sowie die DB-Spalte principal_type (Migration Version1024) wurden gestrichen; Freigaben sind jetzt ausschließlich benutzerbezogen

Changed

  • Dashboard-Summary (DashboardController::summary) lädt Baselines und Aufgaben-KPIs jetzt über gruppierte SQL-Aggregat-Queries statt pro Projekt einzeln (N+1-Fix, gilt auch für den Admin-Fall mit allen Instanz-Projekten)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureNJfbRJEXzKGipUjUW9tUKayHoY6ltSU0ZeCQXcDx6XVDY/naLK0dVY9ciofXU7oy
40sJIOsjxcUZbalDwqncPn0vjGoqmk3BFUT7KotEpLLf8/ZmIjdHEbQbJHzEpdQV
y5YedjqRLKB7/Ul35JWVFxY8eutCsYkonfof7v6AGMGB/RjQ7GDB6jWunEEwqUGV
3Y1isvdq5N3oo9NDY/QR0C2C7jiMnB9Kon0KzZ2yp0oF5euOpA/qrtmqxG3L9PoZ
DW1ppwAuARWtRDu4tcDAAQAkF1Mrg5YyYgRoKm7uVazlKEP7DxX56g/g4RS2otEE
rKsA/ER9yYiHnNyGcZuK9Jkfe2Ua6/R7gzJilRvHZ7CBPkhY+XNPcrjlsHbCJEJJ
cX/b0B56p7FyAFy6XjMY9PYFhxy/ubHE7Sk8ixX88uxgM4vf/sSFQaN84CcG/qqA
Nq/OEytBjZP82TsFFYBRcPKEPskF4ejjhNVC4bJpiuCIpo51nIxjeFGtDpeQiDG7
0OWc/GCvsz5W3eG7ShmQsRf0DoivL8tjgDUlMWO9boTpUy2Vnm1rDMKu6nFGKZ8o
TWTZR6u4zGZW1OBERdlU5NQmqxqXrsuGlT6r6DuQnWsWiscjXOyIFeHz+EOKhQOk
wUuN6xN8QES1CDFB27PYV0Sz2KhYhM78GKLCc9B10Ic=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.2.0
Release Details
UpdatedJuly 5, 2026, 9:21 a.m.
Changelog

Added

  • Löschen-Buttons im Detail-Modal für Teilprojekt, Aufgabe und Meilenstein
  • Deutsche App-Beschreibung in info.xml ergänzt

Fixed

  • Baseline-Datum und Kommentar im Report werden untereinander angezeigt
  • Dashboard-Widget zeigt Baseline-Datum und KPI-Werte korrekt an
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureXuYTZMxTlGNJVrGvU/GcIjSlBTYreXdvF5FilCmsi+l7MBvFlyeW1DsnxAsao3pu
HyhvaKXRnkraVQNT2ULgX4BmjUnhsELROrK03gtY88Odzqzh7RIXYkNkRcy92ara
56HIP8BBRD3m1c8pYPfpZfLAzkuurAzVqbJ6qbxw1AebdlPCFEq2g6C+IOcTon0T
q9ZD2I2XJmWd42EXXqva+NMrcx1jfjmHWVtl7xHKhwPndFCtHPMMAdoDS0Xpbh1V
3Ns4h/DphDpC8/ZYZ5sbpMCBekHw4VTZDGxNAuXJ5DMPhkqg2MxVplkS19PuBHLx
r74sgsz611Gjg55gjKOqCb5ZZEvqZTrwKTEYIbu8HicWtq/HxKRZS3FZN9MThTTX
Hesv65vsq9fH0UhEM6MVJjE5Phnw8Wb5ivtAiaUA+NzPrDfrHZAsSfR9NFL3rhFC
7wOmnXtzK40NjmqyMWJu/UP9UVbz3SeEiHiQO9GwBc2krzmXzcmLZFgEjty4CGoJ
SzXAA1QGpUGO4n0b3Y/5zSY4UxogGWybW+mOs27KDLytI915wNYGvBtcdAKCj6Ws
1uVA98npwMid/WSJJ04BXHX8LbowrDeTezSFJyGh+u/KnhlzkA7fqEuu3nQGT5rA
a9qeMmd5kmLBIVcG9RVVmw1kc0AK0qIqZDmlk9dWGJs=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.1.1
Release Details
UpdatedMay 27, 2026, 6:43 p.m.
Changelog

Added

  • Glossar-Button in der Navigation (über den Einstellungen) mit interaktivem Nachschlagewerk
  • Dreispaltige Glossar-Tabelle: Begriff/Abkürzung, Bedeutung/Englisch, Erklärung mit Berechnungsformeln
  • 30 Einträge in 6 Abschnitten: Allgemein, Terminplanung, Baseline & Berichtswesen, Earned Value Management, Ressourcen & Kapazität, Budget

Fixed

  • Fehlende deutsche Übersetzungen für englische UI-Strings ergänzt (Add dependency, Baseline, Dependencies, Remove, Work, No projects yet, Open Gantt Projects, u.a.)
  • Leere Übersetzung für Deck-Fortschritt-Hinweis befüllt
  • de.js vollständig mit de.json synchronisiert (war ~70 Einträge veraltet)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureF1RHJx15J/N8tWNrDlAX1MFE/9tsct4PViEcBDeo8U/V2qJ/tezL7Xk0BVmYxjWw
pB+J685mcHjikh93/aZUqG8C6y0mR3TTJfaa7dLCIRMc1034x6Xj9Nd7Q9YVH4yi
RLTcRhrG2pN1Iqc23kwId995GJXHnCBEyuQuzo9m1VtA7GoFa8W2nqhXVT94khDS
8ZHQrixDfv63d4GfA5N2x4+phaiyObdskvCmVSuKrmouYvCGpPevtKG5YxzOrHid
aL48Kod0YgOCAD8nAqOhEmioP0m+wP2e/NC4Z5svSKT3vdlE67W1M68ipQQfnhPI
txui+2X8zFvoe/M5sE3DaXbLnOVNGQ7YRpyXFI5GsQmQ0cPSSO/94Mw15hLZfwMf
TDOrrvzf+Vu05sUTZ6CFh4FrSl4e5Q6Xjv6uH4BZtyOpPxl+ajgW4OkZvQDbt4KC
8aTZodMcDpXlRMDdBSxT1bT9tD05KUKmEZYtpxHiARrHDuQQCRSuxtjitQD9lbla
CMxKrBiO0YgdUb3FuczYkWEH+y8gW5egU6TDMnjAVbuUecGuGZN1Cc6tarcFWRu2
+V7Qn+aNoXEwP5e/0TM4Ig8ETAYseZRiTPHxeWiSg3RnU3HuT6kPVWw8LERACDT4
6F4WU9t2+4kESMLMjeV0/2UBQSykR/42Idsg0PtvpyQ=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.1.1 (nightly)
Release Details
UpdatedMay 27, 2026, 5:24 p.m.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureF4W7QJB8rVJ2xARdnhUbEouzRZMKcowz/ToDwr0oVFrVUbInFvHAMqXFTOVD1a5N
kDTb0pOhv+hCStTh70bN+aapjbdtp7SdQ3SbP5VoXBKLhUii41OqN/i4yM7itdSs
M8d5PVo9TJYVnfaij2xwWghMqZEyzxgOw4Q98dYIysf2BxsjjCtxGEMo/pISS90G
OE2RaVEFbwUcvu1XKszLP5X/k/onOchengURYVuzHP7VgVuomZpPSZ9VEIRKITyL
GpgSDrdqm5AXdQc7l/2OqprW6G+MxsuVzChbyPGslIYYXYsP9HLc/FfwVxaCJjh2
Nsiqfd+dMwnf7f9yrrBuZjbNwNa5x++IynrwaU01jVISkl9pgkbUYRaPSMTGFDAd
lsEEqlgs9KdzGoTFjDXNdTwDOsUMiu/ag8tPo7YxsxLFbVGa7laRAUhlGUT9QGPr
IOAAWvKqivsYnU5iwTCY/5HGza3SDfZc/e5upPfB+lTQTYijp1aAYRBAsoOLmuga
f0aP45pnfnYBJkT1kMsthjbGMdlL46wLiNHKRct9OlFwx74IRIyZdcs5Q3pC0aNN
DSLvsCSmY8/9PtTLzcOJKXTqqDVupCqq82bUlGRn7NR6xsinzv74MuOVnGY21tBm
iB5ceYpgiEukUz6YtS2quIIiMTnYmM+HBFnkXgBV0/Y=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32

Nextcloud 30

Gantt Projects 1.5.4
Release Details
UpdatedAug. 27, 2026, 7:06 p.m.
Changelog

Fixed

  • appinfo/info.xml wurde vom Nextcloud App Store abgelehnt: der Sprachcode pt_BR in <name>, <summary> und <description> ist im Schema nicht enthalten — die Enumeration kennt nur BCP-47-Schreibweise in Kleinbuchstaben mit Bindestrich. Alle drei Vorkommen heißen jetzt pt-br
  • Die Kindelemente von <info> sind im Schema eine feste Sequenz; <settings> stand vor <dependencies> und wäre nach dem Sprachcode-Fix als nächster Validierungsfehler aufgeschlagen. Der Block steht jetzt an der vom Schema vorgesehenen Position hinter <dependencies>. xmllint --schema gegen https://apps.nextcloud.com/schema/apps/info.xsd läuft damit sauber durch
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureYbjiEkGYW1s8Xg9Jvrt4nNo/67zkrQDA16yfK2MzVa58R982qrLUupNbvUE/FscP
pFg9nlqxd81cpyH1ZhWOM7fMq98mPyjSUsJZ7xjYzNccF13xvDpBXFlfX4UyCknc
50Rmw9a8RxiCH0mEpH9zWjdanX194R8cUIMDY+BcymCgyBVRQub9yaL5iiHH3hNA
OOD+UOiSUNHns9R6sgZ+tF4OeoTufWR5//AfRmuL5qC5spyuP1iKr7FnzPar+/sS
pHKojfUyi0sAjlrThVZDo8fvVPqkkH4jgvVmNE41t1UOlVdajIRd2yhbHX0h0SSs
rmt4CQqNXAjLE/Wlq2lu9Viw4M2BhhPIfVb5YJFzaxjhB8RRy53rquXRL64f7vGa
agq0ri3eD+0ZWmMOlJmHaMv6AXYd0ZG8myb3PAyNC0NYXzrw2PAVL8jDfzmq2cNY
Q3rIh101vtGPytqanNS2VmtfZ8BX63rd4SLR4PJdRYrm3Wbqanx8WZa20eLgYF8S
M9xhxl5Jf8+TnYLwHi1sGm1ID2XJ4krfgOxiUlB8lGeSweUK1uueC0bmUDsrXyhJ
RMGST41TU1HqXx/3Eeh91JKq/Jbx15kPuxu7WNKyuSOj4vKbgFwBUSmHKDU6lvEZ
L/bnxZi965/4K3kvyJ8o2j5e4xUmJLeusi9Fg0yrRqE=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.2
Release Details
UpdatedAug. 26, 2026, 5:18 p.m.
Changelog

Changed

  • Teilen-Dialog: das Eingabefeld für den einzuladenden Nutzer ist jetzt ein Suchfeld statt eines reinen Textfelds für die Benutzer-ID (Issue #144). Getippt wird nach Anzeigename, Benutzer-ID oder E-Mail-Adresse; ein neuer, admin-unabhängiger Endpunkt GET /api/v1/users/search (UserController::search(), IUserManager::search(), max. 20 Treffer, der eigene Account wird ausgeblendet) liefert dazu Anzeigename, Benutzer-ID und E-Mail als Vorschlagsliste. Gespeichert wird weiterhin die Benutzer-ID als principal_id – für Umgebungen mit LDAP/AD-Benutzerverwaltung war die zufällig generierte ID zuvor nicht ohne Umweg über die Benutzerverwaltung in Erfahrung zu bringen. Die Liste bereits geteilter Zugriffe zeigt ebenfalls den Anzeigenamen statt der rohen ID (ShareController::index() reichert die Antwort um display_name an, Fallback auf principal_id falls der Account inzwischen gelöscht wurde)
  • Übersetzungen für alle sechs Sprachen ergänzt
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureyLn/jlYbk3gIYfgIcjON0z467/xL9L6QNcmfgOa/4zhTJjLknXq7eu1UJddWWlLJ
NG2U9d/OEFO9wLHPYPGNiWgQMRIk+TGYlQVTXcZH3WpBxdJOm3XMnk5hq2kNB2FN
TJemqr/dxafGB2hTIgivPMXMnemdrtxWN1RAdzCxZIg9HwJWjG5JxdqHmURHwske
p/Ki/iZghKjrxbPIghbqtrvkCJRImbgVWY8AmUNUPLgotNIthiWFnkTDVhYWcreP
pWleWHxEn57UOtehff1aJa+hRI+8WVkx9iXArx0SThmOCYYgJ/HeG8dOOtmr9jSm
1nzETAL87YLxL/+qM6DyBIgNWhrq1oj9Q12bBm1+la477z6fpOgUlMjWkPEYRQi/
vhxirXwB4BZBYvaMEkNlN2U3+7BqgigGoaTcbN2rG/TP1JuOjdj9jEjMMRye0JbT
35XOoM/VPYGovrT9slHg8r3Wolyd8ioXVOu4IcMImvC5OrTzpKY7NLEc/S+cOKwz
ijOKcnoV0j++KxtQKKgEO96HJpEM0jteQVOGCoPbghjS3OFzkiB1bUVJAlu1jn54
38Q2zw8rZ0EMm1rEPmIrl72DIIXionbWKatREgy7QPwuL/WKZ2c+J1UIUTKck5eO
7M2VHh6P3FnIg/UsOCMu3U7ja0Y8vQ3YUo3tazLfob0=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.1
Release Details
UpdatedAug. 25, 2026, 1:28 p.m.
Changelog

Added

  • Screenshot des gerenderten Gantt-Charts als PNG, SVG oder PDF (Issue #116): ein neuer „Screenshot"-Eintrag in der Chart-Toolbar öffnet ein Menü mit den drei Formaten, derselbe Export steht im Bearbeiten-Dialog des Projekts neben JSON und CSV bereit (dort mit vorgeschalteter Formatwahl statt Menü, openScreenshotFormatDialog()). Exportiert wird stets das gesamte Chart, nicht nur der sichtbare Scroll-Ausschnitt — frappe-gantt rendert die volle Breite und Höhe ohnehin als eine SVG. PNG und SVG klonen die aktuell gerenderte SVG und schreiben getComputedStyle() als Inline-Attribute (löst auch CSS-Variablen auf), sodass die Datei ohne das App-Stylesheet eigenständig darstellbar ist; sie folgen dem eingestellten UI-Theme, ein hinterlegtes Rechteck in --color-main-background deckt dabei auch die Fläche unterhalb der Aufgabenzeilen (Workload-Chart, Leerraum) ab, die sonst transparent bliebe. PNG rastert per Canvas mit doppelter Auflösung
  • Zeitraum-Auswahl für den PDF-/Druck-Export (Issue #116): vor dem Drucken fragt ein Dialog, welchen Zeitraum die PDF abdecken soll — gesamter Projektzeitraum (Vorbelegung), laufendes Kalenderjahr, „aktives Quartal" (Vormonat bis einschließlich übernächstem Monat) oder ein frei eingegebener Bereich. Der Vorschlag ist der tatsächlich von Balken belegte Zeitraum, nicht gantt_start/gantt_end — frappe-gantt legt darum großzügig Puffer, der andernfalls mitgedruckt würde. Umgesetzt wird der Zuschnitt als viewBox auf dem SVG-Klon; die dafür nötige Skala (Chart-Start, Pixel pro Millisekunde) schreibt GanttChart.vue nach jedem Render als data-Attribute an den Chart-Container, sodass auch Aufrufer ohne Zugriff auf die frappe-Instanz (Bearbeiten-Dialog) sie lesen können. Die Zeitraum-Logik steckt isoliert testbar in src/gantt/printRange.js (src/gantt/printRange.test.js)

Changed

  • Der PDF-Export druckt nicht mehr den Live-Container, sondern einen gestylten, selbst gerasterten Klon des Charts (Issue #116). Bisher wurde das Inline-SVG direkt gedruckt — wie fein die Browser-Engine das rastert, ist nicht steuerbar und fiel je nach Browser sichtbar grob aus. Jetzt wird der Klon mit 300 dpi bezogen auf die bedruckbare Fläche (A4 quer, 10 mm Rand → 277 × 190 mm) in ein Canvas gerastert und als Bild mit fest vorgegebener physischer Größe in den Druck gegeben; schlägt die Rasterung fehl, bleibt der SVG-Klon als Druckinhalt übrig und skaliert per CSS auf die Seitenbreite. Der Klon wird immer im hellen Theme berechnet (Papier ist weiß, ein dunkles UI-Theme ergäbe sonst dunkelgraue Flächen und helle Schrift) — dafür genügt ein ausgelagerter Container mit gesetztem data-theme-light, da Nextcloud die Stylesheets aller Theme-Varianten lädt und nur über dieses Attribut umschaltet. Das Ausblenden der übrigen Seite läuft über display: none statt visibility: hidden, sonst blieb die Fläche der App als Leerseiten erhalten; Nextclouds Hintergrundbild auf html/body wird für den Druck abgeschaltet. Aufgeräumt wird über afterprint mit Timeout-Fallback für Browser, die das Event nicht feuern
  • Der Toolbar-Eintrag heißt „Screenshot" (Icon MonitorScreenshot) statt „Export" (Icon ExportVariant) — „Export" ist im Projekt bereits für den Daten-Export nach JSON/CSV belegt, der Chart-Export ist demgegenüber eine reine Abbildung der aktuellen Darstellung
  • Übersetzungen für alle sechs Sprachen ergänzt
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
Signaturek6kpvF53IR8tnkOFXyoSPFPGlwVzO/RUTgI1p1ppRcFmoFPUyFeIokOqWA1OtD9q
wdo+qkQQPyJGph0Uwp+hwP9oGmeKWErnlv8HMdA5I5iaXIN7afGvdfxWfKgqWetw
tGmCF7l2IzMmT2Ol/3pKgCnFkXTDPCVeNINNbUdi7EjeRpbcbOGWt3+5UVwZgVTX
Z9/kEEPvjMV98s1zT5yBXcFvyqZA7bhhezmBkfzaLa0DAIczFJbhyFtR06WuS7bP
CWBCs/xvSRuCwo61oyXRAWLohz/2GsrMSa5jvPvnEG1XEHpGPVorCijAvsBm4sX5
yAZTrBm3zbNYObqVE2idxTH/eqP8xXtE38JFjpG5IahpeFNb9V2EbH1nrjfRKYcH
NVvXcXFREAmvorShKDE0ymFN+/BCjvU1vnJCnRD5RMsoSGUzXSVHPrF1emtusLHj
ltP22eYOCpraEpZheTkFftqvpbiQKVXsZ+8wY4dJnh5Ymi71loxZhggoH8s/pmp+
WbSx6MZwSPBqJ0HOJWckFiZXur2OQYOVLfXt8uPYNU/EZSoYDqm81GVMglQXxyM6
YDh0xXqwJ7Qft7k0O/3Fa5YLJGP4B4RvjU29N3/WDsfjuk7PeCSTPhRlTOfV/Fbn
jS83WVBavmyklhu0rNYuCYfdYvUxemIO3VuGmYzFXgI=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.0
Release Details
UpdatedAug. 24, 2026, 5:26 p.m.
Changelog

Added

  • Editierbare Vorgänger-Spalte in der Tabellenansicht, Teilschritt F von #117 (Issue #124): eine neue, über das Spaltenmenü einblendbare Spalte „Vorgänger“ zeigt die Abhängigkeiten einer Aufgabe in der aus MS Project bekannten Kurznotation (12EA+2d = Vorgänger Aufgabe 12, Ende-Anfang, zwei Arbeitstage Abstand; mehrere durch ; getrennt) und nimmt sie dort auch entgegen. Typ (EA/AA/EE/AE, englische Kürzel FS/SS/FF/SF werden beim Eingeben mit akzeptiert) und Abstand sind optional, 12 allein bedeutet also EA ohne Abstand. Geprüft wird beim Verlassen der Zelle: Syntax, Existenz der Aufgabe im selben Projekt, Selbstbezug, Dubletten und Kreisschluss über die gesamte Abhängigkeitskette – bei einem Fehler bleibt die Zelle im Bearbeitungsmodus und nennt den Grund im Klartext, die bisherigen Abhängigkeiten bleiben unangetastet. Gespeichert wird über dieselbe PUT /tasks/{id}-Route wie der Detail-Dialog (inkl. dep_mode), sodass der Server die Termine anwendet und durch die Nachfolgerkette propagiert; Balken, Pfeile und Typ-Labels im Chart zeichnen sich mit der Antwort neu. Bewusst ohne Undo-Toast, da ein Zurücknehmen nur der Termine (nicht der Abhängigkeit) beim nächsten Neuberechnen wieder überschrieben würde. Nur Aufgaben haben eine editierbare Zelle – Meilensteine hängen über task_id an genau einer Aufgabe, Projekte und Teilprojekte sind berechnete Strukturebenen. Notation und Prüfungen stecken isoliert testbar in src/gantt/dependencyNotation.js (src/gantt/dependencyNotation.test.js)
  • Zeitabstand (Lag/Lead) je Aufgaben-Abhängigkeit (Issue #124): neue Spalte lag_days in nc_gantt_task_deps (Version1032; der Name vermeidet das seit MySQL 8.0 reservierte Wort LAG und nennt die Einheit). Der Abstand zählt in Arbeitstagen über den Ressourcenkalender wie die übrige Terminberechnung, wirkt bei allen vier Abhängigkeitstypen auf deren Ankertag und darf negativ sein (Lead: der Nachfolger beginnt früher). Bestandsabhängigkeiten bekommen 0 und verhalten sich unverändert. TaskService::update() weist eine gesendete Vorgängerliste jetzt vollständig zurück (invalid_dependency, dependency_cycle), bevor die bisherigen Abhängigkeiten dafür gelöscht werden, statt Vorgänger aus fremden Projekten oder Zyklen zu speichern – letztere hätten die topologische Sortierung in recalculateProject() stillschweigend Aufgaben überspringen lassen

  • Konfigurierbare Spalten in der Tabellenansicht, Teilschritt E von #117 (Issue #122): ein Menü in der Tabellenkopfzeile blendet Spalten ein und aus, die Reihenfolge lässt sich per Drag & Drop der Kopfzellen ändern (barrierefreie Alternative: Strg+Pfeil links/rechts auf der fokussierten Kopfzelle), die Breiten per Ziehen am Spaltentrenner (Doppelklick setzt auf die Standardbreite zurück). Zusätzlich zu den bisherigen Spalten (Titel, Start, Ende, Fortschritt) stehen ID, Dauer (Kalendertage inkl. Start- und Endtag, bei Meilensteinen 0), Status (Issue #78, nur Aufgaben/Teilprojekte) und Ressource (Issue #103, zugeordnete Ressourcennamen einer Aufgabe) bereit – alle vier als reine Anzeigespalten, die das Inline-Editing und die Tastaturnavigation daher überspringen. Auswahl, Reihenfolge und Breiten werden pro Nutzer über den in Teilschritt B angelegten UI-Preferences-Endpunkt persistiert (neuer Key gantt_table_columns, kein Schema- oder Endpunktwechsel nötig); eine gespeicherte Konfiguration wird beim Laden validiert, sodass entfernte Spalten oder unplausible Breiten die Ansicht nicht beschädigen können. Die Tastaturnavigation folgt jetzt der sichtbaren Spaltenreihenfolge statt einer festen Liste. Reicht die Tabellenbreite für die gewählten Spalten nicht aus, scrollen Kopfzeile und Zeilen gemeinsam horizontal; die Obergrenze des Splitters steigt dafür von 560 auf 900 px. Die Spaltenlogik steckt isoliert testbar in src/gantt/tableColumns.js (src/gantt/tableColumns.test.js). Ein Sortieren der Zeilen nach Spaltenwert ist bewusst nicht enthalten – es kollidiert mit der Hierarchie Projekt → Teilprojekt → Aufgabe und der sort_order, die das Chart für dieselbe Zeilenreihenfolge braucht

  • Tastatur-Navigation in der Tabellenansicht, Teilschritt D von #117 (Issue #121): Tab/Shift+Tab springen zur nächsten bzw. vorigen editierbaren Zelle (überspringt Zeilen ohne Schreibrecht, springt am Zeilenende zur nächsten/vorigen Zeile), Enter speichert und springt in dieselbe Spalte der nächsten Zeile, Esc bricht ab und stellt den vorigen Wert wieder her. Pfeiltasten bewegen die Zellauswahl, wenn gerade keine Zelle im Editiermodus ist (innerhalb einer Zelle bleiben sie für Cursor-/Wertänderung nutzbar). Die reine Traversierungslogik steckt isoliert testbar in src/gantt/tableNav.js (src/gantt/tableNav.test.js). Die ausgewählte Zelle bekommt einen sichtbaren Fokusrahmen und wird per scrollIntoView() ins Sichtfeld gescrollt – über den bestehenden bidirektionalen Scroll-Sync (Issue #119) folgt das Gantt-Chart automatisch mit. Neue ARIA-Rollen (grid/row/columnheader/gridcell, aria-readonly je Zelle) machen die Tabelle für Screenreader als Grid erkennbar
  • Read-only Tabellenansicht links vom Zeitstrahl, Teilschritt B von #117 (Issue #119): neue Komponente GanttTable.vue zeigt dieselben Zeilen wie das Chart (Titel mit Einrückung nach depth, Startdatum, Enddatum, Fortschritt), gespeist aus buildRowModel()/buildTableRows() (siehe Teilschritt A, Issue #118) – Reihenfolge, Filter-Dimming, kritischer Pfad und Projektfarben bleiben so exakt konsistent zum Chart. Zeilenhöhen sind fest an frappe-gantt gekoppelt (40 px = bar_height 22 + padding 18, Kopfzeile 52 px = header_height). Ein Toolbar-Button blendet die Tabelle ein/aus, ein Splitter macht die Breite verstellbar (160–560 px), vertikales Scrollen ist bidirektional mit .nc-gantt-container synchronisiert. Sichtbarkeit und Breite werden pro Nutzer über einen neuen, generischen UI-Preferences-Endpunkt (GET/PUT /api/v1/ui-preferences, SettingsController über IConfig::get/setUserValue() als JSON-Blob) persistiert, damit Teilschritt E (Editieren) das Schema nur noch um weitere Keys erweitern muss, ohne Endpunkt oder Speicherformat anzupassen. Rein lesend – Editieren folgt in Teilschritt C
  • Projekt-Export/-Import (JSON, format_version: 2) kann jetzt optional die von den Aufgaben referenzierten Ressourcen inkl. Gruppe, Wochenmodell, Arbeitskalender+Feiertagen und Tageskapazitäten mitnehmen, statt wie bisher nur die rohe resource_id in eine Zieldatei zu schreiben, die dort ungeprüft übernommen wurde – auf einem System ohne identische Ressourcen-IDs ging die Zuordnung damit verloren oder landete schlimmstenfalls bei einer fremden Ressource (Issue #115). Vor dem JSON-Download entscheidet ein Options-Dialog, was mitexportiert wird (Ressourcen / Verfügbarkeiten / Kalender, gestaffelt); vor dem JSON-Import zeigt ein passender Dialog, wie viele Ressourcen die Datei enthält, und lässt auswählen, was übernommen wird sowie ob bei Namensgleichheit die vorhandene Ressource wiederverwendet (Default) oder immer neu angelegt wird. Referenzen werden ausschließlich über eine Mapping-Tabelle aufgelöst und nie roh durchgereicht; nicht auflösbare Referenzen werden verworfen (Regressionsschutz zu #112/#113). Neu angelegte Ressourcen/Gruppen/Kapazitäten gehören stets dem importierenden Nutzer. Wochenmodelle/Kalender/Feiertage sind weiterhin admin-only anlegbar – ohne Adminrechte werden nur namensgleiche vorhandene Einträge gemappt. CSV bleibt unverändert aufgabenzentriert mit Ressourcen nur als ID-Referenz; der volle Ressourcenumfang ist JSON-only. Alt-Exporte ohne resources-Schlüssel importieren unverändert wie bisher, ohne Options-Dialog
  • Inline-Editing der Basisfelder in der Tabellenansicht, Teilschritt C von #117 (Issue #120): die Zellen für Titel, Start, Ende und Fortschritt sind direkt editierbar und aktualisieren die Balken im Chart sofort. Gespeichert wird über die bestehenden Store-Actions (updateTask/updateSubproject/updateMilestone/updateProject) inkl. Terminpropagation und dem vorhandenen Undo-Toast für Aufgaben (analog Drag & Drop im Chart); ein lokaler pendingEdits-Overlay zeigt die Änderung optimistisch an und rollt sie bei einem fehlgeschlagenen Request mit Fehlermeldung zurück. Die Schreibrechte löst tableRows.js je Feld über store.canEditProject() auf (titleEditable/startEditable/endEditable/progressEditable) – Projekte und Teilprojekte bleiben bei Datum und Fortschritt read-only, da diese Werte aus den Aufgaben berechnet werden. Geprüft wird: Titel nicht leer, Enddatum nicht vor Startdatum (Meilensteine ausgenommen, deren Start- und Endspalte dasselbe milestone_date zeigen) und Fortschritt 0–100. Im Simulationsmodus rufen Datumsänderungen an Aufgaben simulateTaskChange() statt einer echten Speicherung auf
  • Ressourcen-Überbuchungswarnung (Issue #82): die Kapazitätsplanung war bisher reine Datenerfassung ohne Abgleich mit dem tatsächlich verplanten Aufwand. Der neue Endpunkt GET /api/v1/resources/{id}/utilization?from=&to=&group= (ResourceUtilizationService/ResourceUtilizationController) stellt den geplanten Aufwand aus den Aufgaben-Ressourcen-Zuordnungen – gleichmäßig auf die Arbeitstage der Aufgabe verteilt, über WorkCalendarService mit ressourcenspezifischen Arbeitstagen und Feiertagen – der erfassten Tageskapazität gegenüber. Mehrfach-Ressourcen-Zuordnungen (Issue #103) samt Alt-Aufgaben werden berücksichtigt, ohne gepflegte Tageskapazität gilt ein Fallback von 1 PT/Tag. Im Ressourcen-Raster färben sich die Zellen nach Auslastungsgrad (> 90 % gelb, > 100 % rot) und der Tooltip zeigt geplante Stunden gegen Kapazität samt Aufschlüsselung nach Projekt und Aufgabe; das Workload-Chart im Gantt markiert überbuchte Perioden jetzt rot. Übersetzungen für alle sechs Sprachen ergänzt
  • Nachgetragen – beide Funktionen wurden bereits mit 1.4.2 ausgeliefert, waren dort aber nicht im Changelog dokumentiert:
  • Einheitliches Statusmodell für Teilprojekte und Aufgaben (Issue #78): neues Feld status (not_started/in_progress/blocked/done) auf nc_gantt_subprojects und nc_gantt_tasks ergänzend zum numerischen Fortschritt, Bestandsdaten leitet Migration Version1030 daraus ab. Validierung per StatusValidator (Whitelist analog ColorValidator), Status-Dropdown in den Detailformularen, blockierte Balken im Gantt schraffiert und mit Warnsymbol, blocked_count je Projekt im Rollup sowie ein Badge in der Projektliste
  • Mehrere Ressourcen mit individuellem Aufwand je Aufgabe (Issue #103): bis zu vier Ressourcen je Aufgabe mit eigener Aufwandsschätzung in der Einheit der Ressource (neue Tabelle nc_gantt_task_resources, Migration Version1029, Backfill aus den vorhandenen resource_id/work-Werten). Das manuelle Work-Feld entfällt: TaskService::resolveResources() summiert die Einzel-Aufwände zur Gesamt-Work (1 PT = 8 h) und übernimmt die erste Zuordnung als primäre resource_id, die weiterhin für Arbeitskalender und CPM maßgeblich ist. Ressourcen-Filter sowie CSV-/JSON-Export und -Import berücksichtigen alle Zuordnungen statt nur der primären

Changed

  • buildFrappeRows() (src/gantt/frappeRows.js) mischte bisher Datenmodell und frappe-gantt-Formatierung: die Einrückungstiefe steckte als Leerzeichen im name, Zustände (Dimming, kritischer Pfad, Summenbalken) hingen in custom_class – eine geplante Tabellenansicht neben dem Gantt-Chart (Issue #117) hätte dieselbe Logik duplizieren müssen (Teilschritt A, Issue #118). Neue Funktion buildRowModel() (src/gantt/rowModel.js) liefert dieselbe Zeilenliste jetzt als neutrales Modell (id, type, entityId, depth, title, start, end, progress, parentId, editable, matched, critical), resolveMilestoneDate() wandert mit ins Modell. buildFrappeRows() ist nur noch ein dünner Adapter darüber, der name/custom_class/dependencies wie bisher erzeugt. Reines Refactoring ohne sichtbare Änderung, per Fixture-Vergleich gegen die alte Implementierung geprüft; neue Unit-Tests (src/gantt/rowModel.test.js, npm run test:unit, via neu eingeführtem vitest) decken Hierarchie, Einrückungstiefe, Meilenstein-Datumsauflösung und Filter-Dimming ab

Fixed

  • Abhängigkeitsfortschreibung bei Aufgaben lieferte für alle vier Abhängigkeitstypen (EA/AA/EE/AE) einen um einen Arbeitstag zu langen Nachfolger-Termin – bei EA zusätzlich mit falschem Anschlusstag, da der Nachfolger auf dem Endtag des Vorgängers statt am folgenden Arbeitstag begann und dadurch mit dem Vorgänger überlappte (Issue #114). Ursache war eine Off-by-one-Vermischung zwischen der inklusiven Arbeitstagszählung und der exklusiven Datumsfortschreibung in TaskService::applyConstraint()/computeMultiConstraint(). Betroffen sind sowohl das direkte Setzen einer Abhängigkeit als auch die Terminpropagation nach Drag & Drop und die What-if-Simulation. Verhaltensänderung: Bestehende Pläne mit EA-Abhängigkeiten verschieben sich beim nächsten Speichern/Neuberechnen um einen Arbeitstag nach vorne (auf den korrekten Anschlusstag); bei AA/EE/AE verkürzt sich der zuvor fälschlich verlängerte Nachfolger-Zeitraum um einen Arbeitstag, die ursprüngliche Dauer bleibt jetzt garantiert erhalten. Abhängige Meilensteine (Dauer 0) sind unverändert korrekt und von diesem Fix nicht betroffen

  • Security: jeder Nutzer mit Schreibrecht auf ein eigenes Projekt konnte jede in der Instanz existierende resource_id einer eigenen Aufgabe zuordnen – unabhängig vom Eigentümer und ohne jede Share-Beziehung (Cross-Tenant-IDOR, Issue #112). TaskService::resolveResources() lud die vom Client gesendeten IDs bisher nur über ResourceMapper::findByIds(), also als reine Existenzprüfung ohne Berechtigungscheck; da die IDs fortlaufende Integer sind, waren sie trivial zu erraten. Der Listen- wie der Legacy-Einzelfeld-Pfad in create()/update() filtern referenzierte IDs jetzt über ResourceMapper::findVisibleToUser(), nicht sichtbare IDs werden wie unbekannte verworfen (Liste) bzw. nicht übernommen (Einzelfeld, der bestehende Wert bleibt erhalten). Regressionstests decken beide Pfade für create() und update() ab

  • Feiertage ließen sich nicht in mehreren Regionskalendern führen: POST /admin/holidays lief in einen HTTP 500, sobald dasselbe Datum in einem zweiten Kalender angelegt wurde, weil der Unique-Index aus Version1006 allein auf holiday_date lag, obwohl Feiertage seit Version1013 über calendar_id kalenderbezogen sind. Version1031 verschiebt den Index auf (holiday_date, calendar_id); die Eindeutigkeit globaler Feiertage sichert weiterhin der Upsert in HolidayAdminController::create(). Betroffen war neben der Feiertagsverwaltung auch der Kalender-Import aus einem Projekt-Export, wo der Fehler still verschluckt wurde. Zweitens war GET /admin/holidays admin-only, während work-calendars und work-schedules lesend für alle offen sind – für normale Nutzer blieb der Store deshalb immer leer (keine Feiertage im Projekt-Export, keine Markierung arbeitsfreier Tage im Ressourcen-Raster); der Lese-Endpunkt zieht nach dem Muster der übrigen Stammdaten auf /api/v1/holidays um (NoAdminRequired), Anlegen und Löschen bleiben unter /api/v1/admin/holidays. Ergänzend werden Feiertage jetzt mit ihrem Kalender gelöscht (WorkCalendarController::destroy(), HolidayMapper::deleteByCalendar()) und Bestandswaisen bereits gelöschter Kalender in Version1031 aufgeräumt – über verweisende Ressourcen haben sie bis dahin weiter als arbeitsfreie Tage gewirkt
  • Die Installation der Tabelle nc_gantt_task_resources scheiterte auf Instanzen, deren Tabellenpräfix die von Nextcloud aus Oracle-Kompatibilität erzwungene 30-Zeichen-Grenze für Bezeichner reizt: der von Doctrine automatisch vergebene Primary-Key-Name (Tabellenname + _pkey) wird mit Präfix oc_ zu lang (Issue #132). Die Primärschlüssel-Definition bekommt – analog zu den bestehenden Migrationen für nc_gantt_resource_capacity und nc_gantt_resource_groups – einen expliziten kurzen Namen
  • Der absolut positionierte Toggle-Button der Nextcloud-App-Navigation ragte in den App-Content hinein und verdeckte dort den Titel des ersten Eintrags in der Projekt-Rollup-Leiste (Issue #134); der linke Innenabstand reserviert jetzt Platz für den Button
  • Ein leerer Balken in Höhe der Kopfzeile erschien oberhalb des App-Inhalts, weil der CSS-Reset für den Nextcloud-Content-Wrapper an main#content.app-nc_gantt gekoppelt war (Issue #126). Ändert sich das Markup zwischen Nextcloud-Versionen (Klasse oder Tag), griff der Reset nicht mehr und der von NcContent (#content-vue) selbst gesetzte margin-top: var(--header-height) addierte sich zum Rand des Cores. Der Reset hängt jetzt robust an #content mit !important, ohne Abhängigkeit vom app-spezifischen Klassennamen
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturegO8Qmtdwg8LOBKr5G+mq4co374hsqqSN6oCIRV9atUx0KqogPxisJiIExkPoSIbu
e4EeIaUzg2alhZsKBLWOwR3Ab3fNm5vvd2DzJn6Hei7A70woz9m/LXkVlcx3vALW
bwolClUX1XCZOBVo/kSS5AOVwak3/huzT1iF9xH9BnpdzVuOjZ563LYwSayfb2Gq
SkWNfLZlKlDkTTF2PIszrNmaa89GmyqTbraxSP16/9nYdIj8ZU0zrhC3HtpihgAT
wya2lwnMf6I73HU0xxgT/+ITTmurx4eHwKWH80P4tjg/Y9mnHODIpAslbW3351mc
qdTHXIBW1MB1YGCQ+JPt11v1X2ccn29kEF9d1nkizKZ1+Du+LJQhPhwHiQxPWSwAUlTlQ4tj1lbe3+FJ1jsVTCqWbDUN02EoV7ZwtN15/HLJfM6w4drUi8ThJ1aLG3v6
cIwMJjYgWeepxR2gv4YgBf4u7txodm5bAWuzySk4rfAG1dBxmie/bfNnWmQ9LrYy
spwKc73gsPhg03ll+jp0b27fJfNF4IpOysz3i+r1ExVfeNIWWO91JPatO2pXZh4O
q0rczM8wYvctvcEkKQIL67HoIrKw4GVIXfqM9Oc8e/Ay7d/NPL+BjpCO6zvoFBY+
SRmjit15YmGW4EQwweQfKXuZ2YeySj+7OjhKHpKfvfg=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.2
Release Details
UpdatedAug. 20, 2026, 4:41 a.m.
Changelog

Changed

  • release.sh fragt die Versionsnummer jetzt interaktiv ab, statt sie nur aus appinfo/info.xml zu lesen: zu Beginn werden die aktuelle Version und das letzte Release-Tag angezeigt und es wird gefragt, ob eine neue Nummer vergeben werden soll (Vorschlag: nächster Patch-Level). Die Eingabe wird auf das Format X.Y.Z, auf einen echten Versionssprung und auf ein noch nicht vergebenes Tag geprüft und dann nach appinfo/info.xml, package.json und package-lock.json geschrieben. Fehlt ein Changelog-Abschnitt zur neuen Version, warnt das Skript; anschließend bietet es an, den Bump als chore: Version X.Y.Z zu committen — nötig, weil der Tag-Name den Commit-Hash enthält. Für nicht-interaktive Läufe gibt es --version=X.Y.Z und --no-bump; ohne TTY wird nie gefragt, make release bleibt also unverändert nutzbar
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturepoVHZxteU3AR2cpRRV98jNfv4j7rWnLEd3kbpn5Dp4T1ubAI+0QlRf9jxi0BaYz1
+1dg+3Yt25uN6Slp1FHiw7kyqt5HJ60XgnOWo+Zt0YBHSnWqLDhF8zxPEnQCkF+v
nUvscpcoQY2bRiIBZhVWVgeAD592uvOA4gfRDrUyLVDKjOrzBu3ScbNvCqTqE9IC
vs8qZkRLIcaD6tKoSLT2pZqmwBoCdClvEw5D5v40WSvLq232BZnXpQ4ogG3QvJdL
mYO8HlPZKVOxANp0MGnWle4IFRMbMt22Ebpkjc18Q9Q4AIv/Sd3zTsc+uMONTM95
s0GXvLSm95o0UCFZ1CL7fCEq7NwlprjVrTeWGmlJNVjHJuIyRKHEz5DR12s0lAGm
/rKGWjoVP+Wvk3upRizR/5y2fpWoiwuDqCtz9gQN6+HHYLaqLvYqsAJ/SxmtLtP7
8B2rK61ClKowz4phbTZdrCaF8w3IWnFFBTFquIVFuN2jUoHvdCMtd0910sLAMY5M
Xs9nk0FVsP23zKXlQpOojq7ouCQagRhsnBJDLxWRR+NIq582f7SDgcrkBqxlGJX4
/Ql9V+2iFx61QANCTjdJIO3LbvbK60vGos+ency0GfvSDbPovDAVyJzt8ZUh5BNw
UXQ4XOHJZAagAr36rKttk1DQbZZ/2bUEq231c96m83g=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.1
Release Details
UpdatedAug. 17, 2026, 7:43 p.m.
Changelog

Fixed

  • Die Meilenstein-Raute hatte eine fest verdrahtete Farbe (#fbbf24) statt der Projektfarbe zu folgen, obwohl Balken für Aufgaben und Teilprojekte bereits korrekt eingefärbt wurden (Issue #102). Zusätzlich wurden die separaten – und wirkungslosen – Farbwähler bei Teilprojekt und Aufgabe entfernt, da deren Anzeige ohnehin immer der Projektfarbe folgt
  • „Meilenstein hinzufügen" im Drei-Punkte-Menü der Projektliste nutzte zwei aufeinanderfolgende window.prompt()-Dialoge (Name, dann Datum als Freitext) statt des regulären Detail-Dialogs (Issue #101). Der Klick emittiert jetzt add-milestone analog zu „Aufgabe hinzufügen" (Issue #91) und öffnet denselben Meilenstein-Dialog wie beim Bearbeiten, mit vorbelegtem Projekt
  • Im festen Datumsmodus des Aufgaben-Detaildialogs konnte ein Enddatum vor dem Startdatum eingegeben und gespeichert werden (Issue #100). Jetzt zieht ein über das Enddatum hinaus verschobenes Startdatum das Enddatum mit; ein zu frühes Enddatum erzeugt ein rotes Fehler-Icon am Feld, hält den Fokus dort und deaktiviert den Speichern-Button, bis ein gültiges Datum eingetragen ist (dateField() in fields.js mit neuer setError()-Methode)
  • Eine Aufgabe mit Abhängigkeit behielt trotzdem die manuell eingegebenen Start-/Enddatumsfelder, die beim Speichern durch die Abhängigkeitsberechnung überschrieben wurden – für Nutzer nicht nachvollziehbar (Issue #99). Der Aufgaben-Detaildialog hat jetzt denselben Fixed-date/Dependency-Umschalter wie Meilensteine (Issue #90): im Dependency-Modus ersetzt eine Dauer (Tage) die Datumsfelder, die Abhängigkeit bestimmt den Termin. Serverseitig wendet TaskService::create() neu hinzugefügte Abhängigkeiten sofort an (bisher nur update()), damit auch neu angelegte Aufgaben keinen die Abhängigkeit ignorierenden Platzhaltertermin behalten
  • Der Speichern-Button des Detail-Dialogs blieb nach dem Hinzufügen einer Abhängigkeit deaktiviert: die Gültigkeitsprüfung hing allein am input-Event, das bei einem <select> vor dem change-Event feuert – zu diesem Zeitpunkt war die Abhängigkeit noch nicht in der Liste. detailModal.js wertet jetzt zusätzlich change aus, der Abhängigkeits-Editor (fields.js) meldet jede Mutation (Hinzufügen, Entfernen, Typwechsel) und der Fixed-date/Dependency-Umschalter in taskForm.js den Moduswechsel über ein eigenes bubbelndes change-Event

Added

  • CONTRIBUTE.md und setup-dev.sh für neue Mitwirkende (Issue #98): Projekt-Leitlinien (FOSS, Datensparsamkeit, Security), VIBE Coding ausdrücklich erlaubt, sowie der komplette lokale Dev-Setup-Weg (Docker-only, Nextcloud + MariaDB unter localhost:8088, optionales E2E-Setup, Git-/Bot-Auth). setup-dev.sh automatisiert diese Schritte, konfigurierbar über --workdir/--no-e2e/--no-docker-install
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturetYcUvVtDEQrAakG32EQF1atSOmz91/8XudCUh60A9r/AxMv+AA5AX2rIvNYDkEn0
OuTmXA6Iz0DoVkdij11MPDhfLaUy0mXeLbwB5fj/xF/cFYcNeCFGKD3k2jyRwOTo
2n1sEp0r8sn0fitHzLfhcB/By0VJkZyhaO/NctP01XfcSQM7lGEOeY/uagtGaDTI
JnPLoQTHo0nUOv4y7jUMZuurEgBOc4yeUxTKv4A/m642hvNQIS0q6K9ON41JHKIO
UtI7DbDWSboVhct1Go3zoj5XcaAGG9ZiwSkJDt/BXT5tWH4SOnSn7mys0j1F6Y0g
vIJWjz6S2RlekwIrIxgyaeEVBOeQ4OM1ilJGWKXDyYJM/0IBxqnqRXDkAFlOopDo
xezlcFdWTkYL5OBKMFJhKuTy7dEQ9hxx5Nz4+vLbNV8gDJZBI+5yI5m8W+809WIH
iKUpIda1ShOblvYH6Ek5AzBdTmoFQ6T4f7iWT7j1i4uUP2DsgehjGVl8yDIT/wyx
nV9t7koXapu1WeXrunSa++mXsi3lceNpthdz5/cUEOe9yWvc1rrulRhiWzePga8H
zjVQYGAIPvwYkWa47U6Zh7HBsQaS+9yQ8NDnD49SS4jUWTGlwNqfM+q9fZ16/G9d
7l4chZUPPbBv+xWfdxmFw+MC5zdkAq27isHToTqnm+w=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.0
Release Details
UpdatedAug. 13, 2026, 6:41 a.m.
Changelog

Added

  • Meilensteine werden jetzt immer direkt unter ihrem übergeordneten Objekt angezeigt statt gesammelt am Projektende (Issue #90): Meilensteine lassen sich neu auch einer Aufgabe zuordnen (bisher nur Projekt/Teilprojekt, Spalte task_id war bereits vorhanden, es fehlte nur die UI), das Auswahlfeld im Detail-Dialog heißt entsprechend „Übergeordnetes Objekt" statt „Teilprojekt". Zusätzlich können Meilensteine ihr Datum jetzt statt eines fixen Werts aus einer Abhängigkeit zum übergeordneten Objekt beziehen (EA/AA/EE/AE, analog zu Aufgaben-Abhängigkeiten; neue Spalte dependency_type, Migration Version1028) – da ein Meilenstein keine Dauer hat, bestimmen EA/EE das Ende und AA/AE den Start des Zielobjekts. Die Berechnung übernimmt der neue MilestoneDateService (serverseitig live bei jedem Abruf sowie im ICS-Feed neu aufgelöst, nicht persistiert propagiert) sowie clientseitig in frappeRows.js für sofortige Reaktivität ohne Neuladen
  • Undo für Drag-&-Drop-Verschiebungen inkl. Propagationskette (Issue #85, Umsetzung der einstufigen Empfehlung: letzte eigene Operation, kein Redo, zunächst nur Drag & Drop): Migration Version1027Date20260810020000 ergänzt nc_gantt_change_events um op_id (UUID) – alle Change-Events einer zusammenhängenden Operation (Drag + gesamte Propagationskette B→C→D) erhalten dieselbe op_id, erzeugt in TaskService::update()/propagateDates() und über ChangeEventService::log() protokolliert (dieses Change-Tracking war bisher tote Scaffolding-Logik ohne Aufrufer). Neuer Endpoint POST /api/v1/changes/{opId}/revert (ChangeEventController::revert, ChangeEventService::revertOperation) wendet alle Change-Events der Operation invers an, in einer DB-Transaktion mit Rechteprüfung über AccessService::canEditOrOwn(). Konfliktschutz: Revert wird mit HTTP 409 abgelehnt, sobald der aktuelle Feldwert nicht mehr dem protokollierten new_value entspricht (jemand hat zwischenzeitlich erneut geändert); der Revert selbst erzeugt wiederum neue Change-Events, die Audit-Historie bleibt lückenlos. Frontend: nach jedem gespeicherten Drag zeigt GanttChart.vue einen Toast „N Termine verschoben — Rückgängig" (showUndo aus @nextcloud/dialogs, 10 s sichtbar) sowie ein globales Ctrl+Z für die letzte eigene Operation der Session (stores/projects.js: lastOperation, revertOperation(), undoLastOperation())
  • Kalender-Export als abonnierbarer ICS-Feed pro Projekt (Issue #83, Variante A aus dem Umsetzungsvorschlag): neue öffentliche Route GET /apps/nc_gantt/projects/{id}/calendar.ics?token=… (regulärer, unauthentifizierter CalendarFeedController, damit externe Clients wie Thunderbird, Nextcloud Kalender oder mobile Apps ohne Nextcloud-Login abonnieren können) liefert Meilensteine als ganztägige VEVENTs (◆-Präfix), den aus den Aufgaben abgeleiteten Projektzeitraum sowie optional Teilprojekt-Zeiträume (Schalter „Auch Teilprojekt-Zeiträume einschließen", standardmäßig aus, um den Feed bei großen Projekten nicht zu überladen). Zugriff erfolgt über einen pro Projekt generierten, 256-Bit-zufälligen Token in der URL (CalendarFeedService, neue Spalte calendar_token auf nc_gantt_projects, Migration Version1026), der über einen neuen „Kalender-Feed"-Bereich im Freigabe-Dialog angezeigt, kopiert und jederzeit widerrufen/neu generiert werden kann (CalendarTokenController, nur für Projekt-Admins/-Eigentümer). ICS-Generierung ohne neue Abhängigkeit, RFC-5545-konform (Escaping, Zeilenfaltung)
  • What-if-Simulationsmodus für Terminverschiebungen (Issue #84): neuer Endpunkt POST /api/v1/projects/{id}/simulate führt Terminpropagation und CPM rein im Speicher aus (kein DB-Schreibzugriff) – TaskService::simulate() nutzt die neu extrahierte, stateless propagateDatesCore()-Kernlogik, die auch der persistierende update()-Pfad verwendet, CriticalPathService::computeFromTasks() erlaubt CPM auf einem hypothetisch veränderten Task-Datensatz. Frontend: „Simulation"-Toggle in der Gantt-Toolbar mit Banner inkl. Projektende-Delta in Arbeitstagen, Geisterbalken für die Ist-Termine (analog Baseline-Overlay) sowie Verwerfen/Übernehmen. Drag & Drop ruft im Simulationsmodus simulate() statt einer echten Speicherung auf. Szenarien bleiben bewusst flüchtig (kein Speichern benannter Szenarien), „Übernehmen" wendet die Änderungen als einzelne Task-Updates an, Simulation läuft pro Projekt
  • Neuer Eintrag „Aufgabe hinzufügen" im Drei-Punkte-Menü der Projektliste (Issue #91): legt wie der „Neu"-Button eine Aufgabe an, belegt dabei aber das gewählte Projekt direkt vor, sodass der Projekt-Auswahlschritt in der Maske entfällt
  • Such-/Filterleiste für Projekte, Teilprojekte und Aufgaben (Issue #81, Stufe 1: rein clientseitig auf Basis der bereits geladenen Daten aktivierter Projekte): Freitextsuche im Titel, Risiko, „überfällig" (Ende < heute und Fortschritt < 100 %), „über Budget" (Ist-Kosten > geplantes Budget), Ressource und „ohne Deck-Verknüpfung". Neuer Pinia-Store stores/filters.js (Zustand pro Nutzer in localStorage persistiert) und reine Matching-Logik in gantt/filterMatch.js. Nicht passende Balken werden in GanttChart.vue gedimmt statt ausgeblendet (Abhängigkeitspfeile und Zeitkontext bleiben lesbar), Projekte/Teilprojekte gelten als Treffer, sobald ein Nachfahre passt. Dieselbe Filterleiste (components/FilterBar.vue) dimmt in ProjectList.vue nicht passende Projekte; für nicht aktivierte Projekte sind nur Titel-Treffer zuverlässig auswertbar, da deren Aufgaben/Teilprojekte nicht geladen sind

Changed

  • Freigabe für Nextcloud 34 (Issue #94): max-version in appinfo/info.xml von 33 auf 34 angehoben, unterstützter Bereich damit NC 28–34. Verifiziert gegen Nextcloud 34.0.2 mit PHP 8.5 und MariaDB 11.4 (148 Unit-Tests, 39 E2E-Tests)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturerdYQI+Semnk0cWtKqUZinVDHk0KpxyqB5Ox4NBL9pyf5nrpK8xZpe9lBxc6zhDfW
8adLfVIwQtX+bI7S1O05xm0hwrUHQQ2ii6ADD8mlAxnZjdhKSCAhZ0NcaqT7Em0X
nD7yRP2B8zAAQMJNjzeBsLbzveNrXMoGzFrvm/jFxskUIUS01ykfWEg2C5+5/IAf
7jBAM8x2Qj92b8zyBFpLjfJQw9aTE/trtCsmZXQFmkJjGS0anrJc9dXKfqnHxknX
8jmLOv4Yq4Qtk3UF35HTiIGcA2W0UKfVyFb4XcrIMeSmLXXcagJWjeH5nB18UUNn
JyCgE/qY4v/SnrNQU92mIdMOQGuvYg7xbaz226lgNdwM2HuM9U8nc2juqJxAO+Wp
xs85yl82qIviZ5YY39HK371MZ/ufMsaVsVy3Nfn3PjqqkzGLmtAL6KJDcKHZWdDw
ugEPwO61DxnERZsNGeFpXfzCxjMpZc/qwUIfGw85idmU2vdedtrxHBkDGoqu1IP7
xZOO8uSYrzbXM6g1gs3WPBOY51CmZLs5pIQTN1tVl5ifGw4uOuzDBUCKiR5oA2MI
352HbA7wwWFgwoN9W5t4MRTowmaYpM8AB+nh9f1A5q9S8SelfMpXOqGew9VZb2jd
AuiJK/LEPjRgs5s3/FfC4Sb1MSsXDr1N1jziaF4MomM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.3.1
Release Details
UpdatedAug. 6, 2026, 12:57 p.m.
Changelog

Added

  • Regressionstests für die Rollentrennung Viewer/Editor/Admin: ForbiddenException-Tests für TaskService::create/update/delete/syncProgress und ProjectService::updateProject/deleteProject (inkl. „Editor darf nicht löschen") sowie erstmalige Testabdeckung für SubProjectService und MilestoneService

Fixed

  • CSV-/Formel-Injection im Aufgaben-Export (detail/io.js exportCsv): Task-Felder wie Titel oder Beschreibung, die mit =, +, - oder @ beginnen, wurden unverändert übernommen und von Excel/LibreOffice/Google Sheets als Formel ausgewertet. Die Absicherung aus ReportView.vue liegt jetzt in einer gemeinsamen Utility (src/utils/csv.js, escCsvCell) und wird an beiden Export-Stellen verwendet
  • Viewer sahen im Frontend dieselbe Oberfläche wie Editor/Admin (Add Task/Subproject/Milestone, Share, Delete Project, Drag/Resize im Gantt-Chart, volle Bearbeitungsformulare), obwohl das Backend Schreibversuche ohnehin korrekt ablehnte – kein Least-Privilege an der UI. ProjectService::getAccessibleProjects()/getProject()/createProject()/updateProject() liefern jetzt das effektive permission-Feld (AccessService::getEffectivePermission()) mit; ProjectList.vue, GanttChart.vue (inkl. Drag/Resize-Sperre je Projekt) und das Detail-Modal (detail/detailModal.js) blenden Schreib-Aktionen für Viewer aus bzw. schalten Formulare read-only
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureBUyDeI9y7iKD1wQJLHrW6IFq0zuXOJQ1Zv/x+0RryIIQ0fAGAUjwQyLDYLYpRzPg
6ITDPfY9bftVlwkB8w9LqZiFETkH8mgc6l5XB7F6NKzFrdaSnNw21CIVJjWyHpkR
mxDq+vQepZd+YtB9jMz39kbFk9BNHrpKIwIXXZVqEqj1U54NmT+5XnT892m9mY6o
RWQNf3Mn5WcH3vmoDi/UAOgDaO30GFCRJePryurVpK7stkub8K6fYsWIkS5NeJlP
YHdb4nBlkhUzQFjo0ZDSkCSiWjMdyCrtEanX6m6Ffhr+j0jpd+J9soMSjrzdzt4T
5mETo8xc61IQIVFWMD6fZ3/oCmbx2TFDZsJjRpFKxoPA08AkdC7xjxHoaKYZHvi4
+tzowxPzMfyjQ/hEj2dwq22doM2lXK1Y13VvV8kkaomrAQjB97gf+ODrYZNDgNvc
2ijU08B4cAB0HbEveDpDRjCJj8D5OwCMafRMa4Ul/nm0+RiBFOhIjDYdVAnCp7Ql
IEc4UQZM9WYLQlouwGPk83POpbqkbc8vKAucGBXvHAbxNpUSOGbssMYFGU/e9pOg
+oT2gcJrC3MYPGIWnS8iLn75PK1H063KFJv5yqC+h/rqwX/FxyTzKvofJi68GpLs
WtG3y67W8Ju4y1I9iQ9raJxxhFUJrStibGy9gc7L0DM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.3.0
Release Details
UpdatedJuly 9, 2026, 5:23 a.m.
Changelog

Fixed

  • Baseline-Toggle im Gantt-Toolbar zeigte nie Baseline-Balken und PUT baseline/active warf einen SQL-Fehler: baseline_id auf nc_gantt_projects wurde mit der 3-Ebenen-Migration versehentlich zusammen mit den tatsächlich berechneten Spalten entfernt (Migration Version1025 stellt die Spalte wieder her). BaselineService::create() aktiviert eine frisch eingefrorene Baseline jetzt automatisch fürs Projekt; renderBaselineBars() (GanttChart.vue) und baselineOverlay.js lesen Baseline-Items dafür über task_id statt des seit der Umstellung auf das 3-Ebenen-Modell nicht mehr existierenden subproject_id-Felds
  • OCS-API-Fehlerantworten (400/404/500 …) lieferten für alle OCSController-Endpunkte einen leeren text/html-Body statt des erwarteten JSON-Envelopes mit message; ExceptionMiddleware wirft jetzt passende OCP\AppFramework\OCS\OCSException-Subklassen statt einer rohen DataResponse, die Nextcloud-Core nur für 401/403 automatisch formatiert. Betroffene Controller (ProjectController, ReportController, ShareController, ChangeEventController, WorkScheduleController, WorkCalendarController, HolidayAdminController, SettingsController) wurden zusätzlich auf die bestehende ApiException-Hierarchie umgestellt

Removed

  • Nie ausgewertete Gruppen-Freigabe-Option entfernt: Share::TYPE_GROUP, principal_type-Parameter in ShareController sowie die DB-Spalte principal_type (Migration Version1024) wurden gestrichen; Freigaben sind jetzt ausschließlich benutzerbezogen

Changed

  • Dashboard-Summary (DashboardController::summary) lädt Baselines und Aufgaben-KPIs jetzt über gruppierte SQL-Aggregat-Queries statt pro Projekt einzeln (N+1-Fix, gilt auch für den Admin-Fall mit allen Instanz-Projekten)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureNJfbRJEXzKGipUjUW9tUKayHoY6ltSU0ZeCQXcDx6XVDY/naLK0dVY9ciofXU7oy
40sJIOsjxcUZbalDwqncPn0vjGoqmk3BFUT7KotEpLLf8/ZmIjdHEbQbJHzEpdQV
y5YedjqRLKB7/Ul35JWVFxY8eutCsYkonfof7v6AGMGB/RjQ7GDB6jWunEEwqUGV
3Y1isvdq5N3oo9NDY/QR0C2C7jiMnB9Kon0KzZ2yp0oF5euOpA/qrtmqxG3L9PoZ
DW1ppwAuARWtRDu4tcDAAQAkF1Mrg5YyYgRoKm7uVazlKEP7DxX56g/g4RS2otEE
rKsA/ER9yYiHnNyGcZuK9Jkfe2Ua6/R7gzJilRvHZ7CBPkhY+XNPcrjlsHbCJEJJ
cX/b0B56p7FyAFy6XjMY9PYFhxy/ubHE7Sk8ixX88uxgM4vf/sSFQaN84CcG/qqA
Nq/OEytBjZP82TsFFYBRcPKEPskF4ejjhNVC4bJpiuCIpo51nIxjeFGtDpeQiDG7
0OWc/GCvsz5W3eG7ShmQsRf0DoivL8tjgDUlMWO9boTpUy2Vnm1rDMKu6nFGKZ8o
TWTZR6u4zGZW1OBERdlU5NQmqxqXrsuGlT6r6DuQnWsWiscjXOyIFeHz+EOKhQOk
wUuN6xN8QES1CDFB27PYV0Sz2KhYhM78GKLCc9B10Ic=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.2.0
Release Details
UpdatedJuly 5, 2026, 9:21 a.m.
Changelog

Added

  • Löschen-Buttons im Detail-Modal für Teilprojekt, Aufgabe und Meilenstein
  • Deutsche App-Beschreibung in info.xml ergänzt

Fixed

  • Baseline-Datum und Kommentar im Report werden untereinander angezeigt
  • Dashboard-Widget zeigt Baseline-Datum und KPI-Werte korrekt an
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureXuYTZMxTlGNJVrGvU/GcIjSlBTYreXdvF5FilCmsi+l7MBvFlyeW1DsnxAsao3pu
HyhvaKXRnkraVQNT2ULgX4BmjUnhsELROrK03gtY88Odzqzh7RIXYkNkRcy92ara
56HIP8BBRD3m1c8pYPfpZfLAzkuurAzVqbJ6qbxw1AebdlPCFEq2g6C+IOcTon0T
q9ZD2I2XJmWd42EXXqva+NMrcx1jfjmHWVtl7xHKhwPndFCtHPMMAdoDS0Xpbh1V
3Ns4h/DphDpC8/ZYZ5sbpMCBekHw4VTZDGxNAuXJ5DMPhkqg2MxVplkS19PuBHLx
r74sgsz611Gjg55gjKOqCb5ZZEvqZTrwKTEYIbu8HicWtq/HxKRZS3FZN9MThTTX
Hesv65vsq9fH0UhEM6MVJjE5Phnw8Wb5ivtAiaUA+NzPrDfrHZAsSfR9NFL3rhFC
7wOmnXtzK40NjmqyMWJu/UP9UVbz3SeEiHiQO9GwBc2krzmXzcmLZFgEjty4CGoJ
SzXAA1QGpUGO4n0b3Y/5zSY4UxogGWybW+mOs27KDLytI915wNYGvBtcdAKCj6Ws
1uVA98npwMid/WSJJ04BXHX8LbowrDeTezSFJyGh+u/KnhlzkA7fqEuu3nQGT5rA
a9qeMmd5kmLBIVcG9RVVmw1kc0AK0qIqZDmlk9dWGJs=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.1.1
Release Details
UpdatedMay 27, 2026, 6:43 p.m.
Changelog

Added

  • Glossar-Button in der Navigation (über den Einstellungen) mit interaktivem Nachschlagewerk
  • Dreispaltige Glossar-Tabelle: Begriff/Abkürzung, Bedeutung/Englisch, Erklärung mit Berechnungsformeln
  • 30 Einträge in 6 Abschnitten: Allgemein, Terminplanung, Baseline & Berichtswesen, Earned Value Management, Ressourcen & Kapazität, Budget

Fixed

  • Fehlende deutsche Übersetzungen für englische UI-Strings ergänzt (Add dependency, Baseline, Dependencies, Remove, Work, No projects yet, Open Gantt Projects, u.a.)
  • Leere Übersetzung für Deck-Fortschritt-Hinweis befüllt
  • de.js vollständig mit de.json synchronisiert (war ~70 Einträge veraltet)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureF1RHJx15J/N8tWNrDlAX1MFE/9tsct4PViEcBDeo8U/V2qJ/tezL7Xk0BVmYxjWw
pB+J685mcHjikh93/aZUqG8C6y0mR3TTJfaa7dLCIRMc1034x6Xj9Nd7Q9YVH4yi
RLTcRhrG2pN1Iqc23kwId995GJXHnCBEyuQuzo9m1VtA7GoFa8W2nqhXVT94khDS
8ZHQrixDfv63d4GfA5N2x4+phaiyObdskvCmVSuKrmouYvCGpPevtKG5YxzOrHid
aL48Kod0YgOCAD8nAqOhEmioP0m+wP2e/NC4Z5svSKT3vdlE67W1M68ipQQfnhPI
txui+2X8zFvoe/M5sE3DaXbLnOVNGQ7YRpyXFI5GsQmQ0cPSSO/94Mw15hLZfwMf
TDOrrvzf+Vu05sUTZ6CFh4FrSl4e5Q6Xjv6uH4BZtyOpPxl+ajgW4OkZvQDbt4KC
8aTZodMcDpXlRMDdBSxT1bT9tD05KUKmEZYtpxHiARrHDuQQCRSuxtjitQD9lbla
CMxKrBiO0YgdUb3FuczYkWEH+y8gW5egU6TDMnjAVbuUecGuGZN1Cc6tarcFWRu2
+V7Qn+aNoXEwP5e/0TM4Ig8ETAYseZRiTPHxeWiSg3RnU3HuT6kPVWw8LERACDT4
6F4WU9t2+4kESMLMjeV0/2UBQSykR/42Idsg0PtvpyQ=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.1.1 (nightly)
Release Details
UpdatedMay 27, 2026, 5:24 p.m.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureF4W7QJB8rVJ2xARdnhUbEouzRZMKcowz/ToDwr0oVFrVUbInFvHAMqXFTOVD1a5N
kDTb0pOhv+hCStTh70bN+aapjbdtp7SdQ3SbP5VoXBKLhUii41OqN/i4yM7itdSs
M8d5PVo9TJYVnfaij2xwWghMqZEyzxgOw4Q98dYIysf2BxsjjCtxGEMo/pISS90G
OE2RaVEFbwUcvu1XKszLP5X/k/onOchengURYVuzHP7VgVuomZpPSZ9VEIRKITyL
GpgSDrdqm5AXdQc7l/2OqprW6G+MxsuVzChbyPGslIYYXYsP9HLc/FfwVxaCJjh2
Nsiqfd+dMwnf7f9yrrBuZjbNwNa5x++IynrwaU01jVISkl9pgkbUYRaPSMTGFDAd
lsEEqlgs9KdzGoTFjDXNdTwDOsUMiu/ag8tPo7YxsxLFbVGa7laRAUhlGUT9QGPr
IOAAWvKqivsYnU5iwTCY/5HGza3SDfZc/e5upPfB+lTQTYijp1aAYRBAsoOLmuga
f0aP45pnfnYBJkT1kMsthjbGMdlL46wLiNHKRct9OlFwx74IRIyZdcs5Q3pC0aNN
DSLvsCSmY8/9PtTLzcOJKXTqqDVupCqq82bUlGRn7NR6xsinzv74MuOVnGY21tBm
iB5ceYpgiEukUz6YtS2quIIiMTnYmM+HBFnkXgBV0/Y=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32

Nextcloud 29

Gantt Projects 1.5.4
Release Details
UpdatedAug. 27, 2026, 7:06 p.m.
Changelog

Fixed

  • appinfo/info.xml wurde vom Nextcloud App Store abgelehnt: der Sprachcode pt_BR in <name>, <summary> und <description> ist im Schema nicht enthalten — die Enumeration kennt nur BCP-47-Schreibweise in Kleinbuchstaben mit Bindestrich. Alle drei Vorkommen heißen jetzt pt-br
  • Die Kindelemente von <info> sind im Schema eine feste Sequenz; <settings> stand vor <dependencies> und wäre nach dem Sprachcode-Fix als nächster Validierungsfehler aufgeschlagen. Der Block steht jetzt an der vom Schema vorgesehenen Position hinter <dependencies>. xmllint --schema gegen https://apps.nextcloud.com/schema/apps/info.xsd läuft damit sauber durch
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureYbjiEkGYW1s8Xg9Jvrt4nNo/67zkrQDA16yfK2MzVa58R982qrLUupNbvUE/FscP
pFg9nlqxd81cpyH1ZhWOM7fMq98mPyjSUsJZ7xjYzNccF13xvDpBXFlfX4UyCknc
50Rmw9a8RxiCH0mEpH9zWjdanX194R8cUIMDY+BcymCgyBVRQub9yaL5iiHH3hNA
OOD+UOiSUNHns9R6sgZ+tF4OeoTufWR5//AfRmuL5qC5spyuP1iKr7FnzPar+/sS
pHKojfUyi0sAjlrThVZDo8fvVPqkkH4jgvVmNE41t1UOlVdajIRd2yhbHX0h0SSs
rmt4CQqNXAjLE/Wlq2lu9Viw4M2BhhPIfVb5YJFzaxjhB8RRy53rquXRL64f7vGa
agq0ri3eD+0ZWmMOlJmHaMv6AXYd0ZG8myb3PAyNC0NYXzrw2PAVL8jDfzmq2cNY
Q3rIh101vtGPytqanNS2VmtfZ8BX63rd4SLR4PJdRYrm3Wbqanx8WZa20eLgYF8S
M9xhxl5Jf8+TnYLwHi1sGm1ID2XJ4krfgOxiUlB8lGeSweUK1uueC0bmUDsrXyhJ
RMGST41TU1HqXx/3Eeh91JKq/Jbx15kPuxu7WNKyuSOj4vKbgFwBUSmHKDU6lvEZ
L/bnxZi965/4K3kvyJ8o2j5e4xUmJLeusi9Fg0yrRqE=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.2
Release Details
UpdatedAug. 26, 2026, 5:18 p.m.
Changelog

Changed

  • Teilen-Dialog: das Eingabefeld für den einzuladenden Nutzer ist jetzt ein Suchfeld statt eines reinen Textfelds für die Benutzer-ID (Issue #144). Getippt wird nach Anzeigename, Benutzer-ID oder E-Mail-Adresse; ein neuer, admin-unabhängiger Endpunkt GET /api/v1/users/search (UserController::search(), IUserManager::search(), max. 20 Treffer, der eigene Account wird ausgeblendet) liefert dazu Anzeigename, Benutzer-ID und E-Mail als Vorschlagsliste. Gespeichert wird weiterhin die Benutzer-ID als principal_id – für Umgebungen mit LDAP/AD-Benutzerverwaltung war die zufällig generierte ID zuvor nicht ohne Umweg über die Benutzerverwaltung in Erfahrung zu bringen. Die Liste bereits geteilter Zugriffe zeigt ebenfalls den Anzeigenamen statt der rohen ID (ShareController::index() reichert die Antwort um display_name an, Fallback auf principal_id falls der Account inzwischen gelöscht wurde)
  • Übersetzungen für alle sechs Sprachen ergänzt
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureyLn/jlYbk3gIYfgIcjON0z467/xL9L6QNcmfgOa/4zhTJjLknXq7eu1UJddWWlLJ
NG2U9d/OEFO9wLHPYPGNiWgQMRIk+TGYlQVTXcZH3WpBxdJOm3XMnk5hq2kNB2FN
TJemqr/dxafGB2hTIgivPMXMnemdrtxWN1RAdzCxZIg9HwJWjG5JxdqHmURHwske
p/Ki/iZghKjrxbPIghbqtrvkCJRImbgVWY8AmUNUPLgotNIthiWFnkTDVhYWcreP
pWleWHxEn57UOtehff1aJa+hRI+8WVkx9iXArx0SThmOCYYgJ/HeG8dOOtmr9jSm
1nzETAL87YLxL/+qM6DyBIgNWhrq1oj9Q12bBm1+la477z6fpOgUlMjWkPEYRQi/
vhxirXwB4BZBYvaMEkNlN2U3+7BqgigGoaTcbN2rG/TP1JuOjdj9jEjMMRye0JbT
35XOoM/VPYGovrT9slHg8r3Wolyd8ioXVOu4IcMImvC5OrTzpKY7NLEc/S+cOKwz
ijOKcnoV0j++KxtQKKgEO96HJpEM0jteQVOGCoPbghjS3OFzkiB1bUVJAlu1jn54
38Q2zw8rZ0EMm1rEPmIrl72DIIXionbWKatREgy7QPwuL/WKZ2c+J1UIUTKck5eO
7M2VHh6P3FnIg/UsOCMu3U7ja0Y8vQ3YUo3tazLfob0=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.1
Release Details
UpdatedAug. 25, 2026, 1:28 p.m.
Changelog

Added

  • Screenshot des gerenderten Gantt-Charts als PNG, SVG oder PDF (Issue #116): ein neuer „Screenshot"-Eintrag in der Chart-Toolbar öffnet ein Menü mit den drei Formaten, derselbe Export steht im Bearbeiten-Dialog des Projekts neben JSON und CSV bereit (dort mit vorgeschalteter Formatwahl statt Menü, openScreenshotFormatDialog()). Exportiert wird stets das gesamte Chart, nicht nur der sichtbare Scroll-Ausschnitt — frappe-gantt rendert die volle Breite und Höhe ohnehin als eine SVG. PNG und SVG klonen die aktuell gerenderte SVG und schreiben getComputedStyle() als Inline-Attribute (löst auch CSS-Variablen auf), sodass die Datei ohne das App-Stylesheet eigenständig darstellbar ist; sie folgen dem eingestellten UI-Theme, ein hinterlegtes Rechteck in --color-main-background deckt dabei auch die Fläche unterhalb der Aufgabenzeilen (Workload-Chart, Leerraum) ab, die sonst transparent bliebe. PNG rastert per Canvas mit doppelter Auflösung
  • Zeitraum-Auswahl für den PDF-/Druck-Export (Issue #116): vor dem Drucken fragt ein Dialog, welchen Zeitraum die PDF abdecken soll — gesamter Projektzeitraum (Vorbelegung), laufendes Kalenderjahr, „aktives Quartal" (Vormonat bis einschließlich übernächstem Monat) oder ein frei eingegebener Bereich. Der Vorschlag ist der tatsächlich von Balken belegte Zeitraum, nicht gantt_start/gantt_end — frappe-gantt legt darum großzügig Puffer, der andernfalls mitgedruckt würde. Umgesetzt wird der Zuschnitt als viewBox auf dem SVG-Klon; die dafür nötige Skala (Chart-Start, Pixel pro Millisekunde) schreibt GanttChart.vue nach jedem Render als data-Attribute an den Chart-Container, sodass auch Aufrufer ohne Zugriff auf die frappe-Instanz (Bearbeiten-Dialog) sie lesen können. Die Zeitraum-Logik steckt isoliert testbar in src/gantt/printRange.js (src/gantt/printRange.test.js)

Changed

  • Der PDF-Export druckt nicht mehr den Live-Container, sondern einen gestylten, selbst gerasterten Klon des Charts (Issue #116). Bisher wurde das Inline-SVG direkt gedruckt — wie fein die Browser-Engine das rastert, ist nicht steuerbar und fiel je nach Browser sichtbar grob aus. Jetzt wird der Klon mit 300 dpi bezogen auf die bedruckbare Fläche (A4 quer, 10 mm Rand → 277 × 190 mm) in ein Canvas gerastert und als Bild mit fest vorgegebener physischer Größe in den Druck gegeben; schlägt die Rasterung fehl, bleibt der SVG-Klon als Druckinhalt übrig und skaliert per CSS auf die Seitenbreite. Der Klon wird immer im hellen Theme berechnet (Papier ist weiß, ein dunkles UI-Theme ergäbe sonst dunkelgraue Flächen und helle Schrift) — dafür genügt ein ausgelagerter Container mit gesetztem data-theme-light, da Nextcloud die Stylesheets aller Theme-Varianten lädt und nur über dieses Attribut umschaltet. Das Ausblenden der übrigen Seite läuft über display: none statt visibility: hidden, sonst blieb die Fläche der App als Leerseiten erhalten; Nextclouds Hintergrundbild auf html/body wird für den Druck abgeschaltet. Aufgeräumt wird über afterprint mit Timeout-Fallback für Browser, die das Event nicht feuern
  • Der Toolbar-Eintrag heißt „Screenshot" (Icon MonitorScreenshot) statt „Export" (Icon ExportVariant) — „Export" ist im Projekt bereits für den Daten-Export nach JSON/CSV belegt, der Chart-Export ist demgegenüber eine reine Abbildung der aktuellen Darstellung
  • Übersetzungen für alle sechs Sprachen ergänzt
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
Signaturek6kpvF53IR8tnkOFXyoSPFPGlwVzO/RUTgI1p1ppRcFmoFPUyFeIokOqWA1OtD9q
wdo+qkQQPyJGph0Uwp+hwP9oGmeKWErnlv8HMdA5I5iaXIN7afGvdfxWfKgqWetw
tGmCF7l2IzMmT2Ol/3pKgCnFkXTDPCVeNINNbUdi7EjeRpbcbOGWt3+5UVwZgVTX
Z9/kEEPvjMV98s1zT5yBXcFvyqZA7bhhezmBkfzaLa0DAIczFJbhyFtR06WuS7bP
CWBCs/xvSRuCwo61oyXRAWLohz/2GsrMSa5jvPvnEG1XEHpGPVorCijAvsBm4sX5
yAZTrBm3zbNYObqVE2idxTH/eqP8xXtE38JFjpG5IahpeFNb9V2EbH1nrjfRKYcH
NVvXcXFREAmvorShKDE0ymFN+/BCjvU1vnJCnRD5RMsoSGUzXSVHPrF1emtusLHj
ltP22eYOCpraEpZheTkFftqvpbiQKVXsZ+8wY4dJnh5Ymi71loxZhggoH8s/pmp+
WbSx6MZwSPBqJ0HOJWckFiZXur2OQYOVLfXt8uPYNU/EZSoYDqm81GVMglQXxyM6
YDh0xXqwJ7Qft7k0O/3Fa5YLJGP4B4RvjU29N3/WDsfjuk7PeCSTPhRlTOfV/Fbn
jS83WVBavmyklhu0rNYuCYfdYvUxemIO3VuGmYzFXgI=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.0
Release Details
UpdatedAug. 24, 2026, 5:26 p.m.
Changelog

Added

  • Editierbare Vorgänger-Spalte in der Tabellenansicht, Teilschritt F von #117 (Issue #124): eine neue, über das Spaltenmenü einblendbare Spalte „Vorgänger“ zeigt die Abhängigkeiten einer Aufgabe in der aus MS Project bekannten Kurznotation (12EA+2d = Vorgänger Aufgabe 12, Ende-Anfang, zwei Arbeitstage Abstand; mehrere durch ; getrennt) und nimmt sie dort auch entgegen. Typ (EA/AA/EE/AE, englische Kürzel FS/SS/FF/SF werden beim Eingeben mit akzeptiert) und Abstand sind optional, 12 allein bedeutet also EA ohne Abstand. Geprüft wird beim Verlassen der Zelle: Syntax, Existenz der Aufgabe im selben Projekt, Selbstbezug, Dubletten und Kreisschluss über die gesamte Abhängigkeitskette – bei einem Fehler bleibt die Zelle im Bearbeitungsmodus und nennt den Grund im Klartext, die bisherigen Abhängigkeiten bleiben unangetastet. Gespeichert wird über dieselbe PUT /tasks/{id}-Route wie der Detail-Dialog (inkl. dep_mode), sodass der Server die Termine anwendet und durch die Nachfolgerkette propagiert; Balken, Pfeile und Typ-Labels im Chart zeichnen sich mit der Antwort neu. Bewusst ohne Undo-Toast, da ein Zurücknehmen nur der Termine (nicht der Abhängigkeit) beim nächsten Neuberechnen wieder überschrieben würde. Nur Aufgaben haben eine editierbare Zelle – Meilensteine hängen über task_id an genau einer Aufgabe, Projekte und Teilprojekte sind berechnete Strukturebenen. Notation und Prüfungen stecken isoliert testbar in src/gantt/dependencyNotation.js (src/gantt/dependencyNotation.test.js)
  • Zeitabstand (Lag/Lead) je Aufgaben-Abhängigkeit (Issue #124): neue Spalte lag_days in nc_gantt_task_deps (Version1032; der Name vermeidet das seit MySQL 8.0 reservierte Wort LAG und nennt die Einheit). Der Abstand zählt in Arbeitstagen über den Ressourcenkalender wie die übrige Terminberechnung, wirkt bei allen vier Abhängigkeitstypen auf deren Ankertag und darf negativ sein (Lead: der Nachfolger beginnt früher). Bestandsabhängigkeiten bekommen 0 und verhalten sich unverändert. TaskService::update() weist eine gesendete Vorgängerliste jetzt vollständig zurück (invalid_dependency, dependency_cycle), bevor die bisherigen Abhängigkeiten dafür gelöscht werden, statt Vorgänger aus fremden Projekten oder Zyklen zu speichern – letztere hätten die topologische Sortierung in recalculateProject() stillschweigend Aufgaben überspringen lassen

  • Konfigurierbare Spalten in der Tabellenansicht, Teilschritt E von #117 (Issue #122): ein Menü in der Tabellenkopfzeile blendet Spalten ein und aus, die Reihenfolge lässt sich per Drag & Drop der Kopfzellen ändern (barrierefreie Alternative: Strg+Pfeil links/rechts auf der fokussierten Kopfzelle), die Breiten per Ziehen am Spaltentrenner (Doppelklick setzt auf die Standardbreite zurück). Zusätzlich zu den bisherigen Spalten (Titel, Start, Ende, Fortschritt) stehen ID, Dauer (Kalendertage inkl. Start- und Endtag, bei Meilensteinen 0), Status (Issue #78, nur Aufgaben/Teilprojekte) und Ressource (Issue #103, zugeordnete Ressourcennamen einer Aufgabe) bereit – alle vier als reine Anzeigespalten, die das Inline-Editing und die Tastaturnavigation daher überspringen. Auswahl, Reihenfolge und Breiten werden pro Nutzer über den in Teilschritt B angelegten UI-Preferences-Endpunkt persistiert (neuer Key gantt_table_columns, kein Schema- oder Endpunktwechsel nötig); eine gespeicherte Konfiguration wird beim Laden validiert, sodass entfernte Spalten oder unplausible Breiten die Ansicht nicht beschädigen können. Die Tastaturnavigation folgt jetzt der sichtbaren Spaltenreihenfolge statt einer festen Liste. Reicht die Tabellenbreite für die gewählten Spalten nicht aus, scrollen Kopfzeile und Zeilen gemeinsam horizontal; die Obergrenze des Splitters steigt dafür von 560 auf 900 px. Die Spaltenlogik steckt isoliert testbar in src/gantt/tableColumns.js (src/gantt/tableColumns.test.js). Ein Sortieren der Zeilen nach Spaltenwert ist bewusst nicht enthalten – es kollidiert mit der Hierarchie Projekt → Teilprojekt → Aufgabe und der sort_order, die das Chart für dieselbe Zeilenreihenfolge braucht

  • Tastatur-Navigation in der Tabellenansicht, Teilschritt D von #117 (Issue #121): Tab/Shift+Tab springen zur nächsten bzw. vorigen editierbaren Zelle (überspringt Zeilen ohne Schreibrecht, springt am Zeilenende zur nächsten/vorigen Zeile), Enter speichert und springt in dieselbe Spalte der nächsten Zeile, Esc bricht ab und stellt den vorigen Wert wieder her. Pfeiltasten bewegen die Zellauswahl, wenn gerade keine Zelle im Editiermodus ist (innerhalb einer Zelle bleiben sie für Cursor-/Wertänderung nutzbar). Die reine Traversierungslogik steckt isoliert testbar in src/gantt/tableNav.js (src/gantt/tableNav.test.js). Die ausgewählte Zelle bekommt einen sichtbaren Fokusrahmen und wird per scrollIntoView() ins Sichtfeld gescrollt – über den bestehenden bidirektionalen Scroll-Sync (Issue #119) folgt das Gantt-Chart automatisch mit. Neue ARIA-Rollen (grid/row/columnheader/gridcell, aria-readonly je Zelle) machen die Tabelle für Screenreader als Grid erkennbar
  • Read-only Tabellenansicht links vom Zeitstrahl, Teilschritt B von #117 (Issue #119): neue Komponente GanttTable.vue zeigt dieselben Zeilen wie das Chart (Titel mit Einrückung nach depth, Startdatum, Enddatum, Fortschritt), gespeist aus buildRowModel()/buildTableRows() (siehe Teilschritt A, Issue #118) – Reihenfolge, Filter-Dimming, kritischer Pfad und Projektfarben bleiben so exakt konsistent zum Chart. Zeilenhöhen sind fest an frappe-gantt gekoppelt (40 px = bar_height 22 + padding 18, Kopfzeile 52 px = header_height). Ein Toolbar-Button blendet die Tabelle ein/aus, ein Splitter macht die Breite verstellbar (160–560 px), vertikales Scrollen ist bidirektional mit .nc-gantt-container synchronisiert. Sichtbarkeit und Breite werden pro Nutzer über einen neuen, generischen UI-Preferences-Endpunkt (GET/PUT /api/v1/ui-preferences, SettingsController über IConfig::get/setUserValue() als JSON-Blob) persistiert, damit Teilschritt E (Editieren) das Schema nur noch um weitere Keys erweitern muss, ohne Endpunkt oder Speicherformat anzupassen. Rein lesend – Editieren folgt in Teilschritt C
  • Projekt-Export/-Import (JSON, format_version: 2) kann jetzt optional die von den Aufgaben referenzierten Ressourcen inkl. Gruppe, Wochenmodell, Arbeitskalender+Feiertagen und Tageskapazitäten mitnehmen, statt wie bisher nur die rohe resource_id in eine Zieldatei zu schreiben, die dort ungeprüft übernommen wurde – auf einem System ohne identische Ressourcen-IDs ging die Zuordnung damit verloren oder landete schlimmstenfalls bei einer fremden Ressource (Issue #115). Vor dem JSON-Download entscheidet ein Options-Dialog, was mitexportiert wird (Ressourcen / Verfügbarkeiten / Kalender, gestaffelt); vor dem JSON-Import zeigt ein passender Dialog, wie viele Ressourcen die Datei enthält, und lässt auswählen, was übernommen wird sowie ob bei Namensgleichheit die vorhandene Ressource wiederverwendet (Default) oder immer neu angelegt wird. Referenzen werden ausschließlich über eine Mapping-Tabelle aufgelöst und nie roh durchgereicht; nicht auflösbare Referenzen werden verworfen (Regressionsschutz zu #112/#113). Neu angelegte Ressourcen/Gruppen/Kapazitäten gehören stets dem importierenden Nutzer. Wochenmodelle/Kalender/Feiertage sind weiterhin admin-only anlegbar – ohne Adminrechte werden nur namensgleiche vorhandene Einträge gemappt. CSV bleibt unverändert aufgabenzentriert mit Ressourcen nur als ID-Referenz; der volle Ressourcenumfang ist JSON-only. Alt-Exporte ohne resources-Schlüssel importieren unverändert wie bisher, ohne Options-Dialog
  • Inline-Editing der Basisfelder in der Tabellenansicht, Teilschritt C von #117 (Issue #120): die Zellen für Titel, Start, Ende und Fortschritt sind direkt editierbar und aktualisieren die Balken im Chart sofort. Gespeichert wird über die bestehenden Store-Actions (updateTask/updateSubproject/updateMilestone/updateProject) inkl. Terminpropagation und dem vorhandenen Undo-Toast für Aufgaben (analog Drag & Drop im Chart); ein lokaler pendingEdits-Overlay zeigt die Änderung optimistisch an und rollt sie bei einem fehlgeschlagenen Request mit Fehlermeldung zurück. Die Schreibrechte löst tableRows.js je Feld über store.canEditProject() auf (titleEditable/startEditable/endEditable/progressEditable) – Projekte und Teilprojekte bleiben bei Datum und Fortschritt read-only, da diese Werte aus den Aufgaben berechnet werden. Geprüft wird: Titel nicht leer, Enddatum nicht vor Startdatum (Meilensteine ausgenommen, deren Start- und Endspalte dasselbe milestone_date zeigen) und Fortschritt 0–100. Im Simulationsmodus rufen Datumsänderungen an Aufgaben simulateTaskChange() statt einer echten Speicherung auf
  • Ressourcen-Überbuchungswarnung (Issue #82): die Kapazitätsplanung war bisher reine Datenerfassung ohne Abgleich mit dem tatsächlich verplanten Aufwand. Der neue Endpunkt GET /api/v1/resources/{id}/utilization?from=&to=&group= (ResourceUtilizationService/ResourceUtilizationController) stellt den geplanten Aufwand aus den Aufgaben-Ressourcen-Zuordnungen – gleichmäßig auf die Arbeitstage der Aufgabe verteilt, über WorkCalendarService mit ressourcenspezifischen Arbeitstagen und Feiertagen – der erfassten Tageskapazität gegenüber. Mehrfach-Ressourcen-Zuordnungen (Issue #103) samt Alt-Aufgaben werden berücksichtigt, ohne gepflegte Tageskapazität gilt ein Fallback von 1 PT/Tag. Im Ressourcen-Raster färben sich die Zellen nach Auslastungsgrad (> 90 % gelb, > 100 % rot) und der Tooltip zeigt geplante Stunden gegen Kapazität samt Aufschlüsselung nach Projekt und Aufgabe; das Workload-Chart im Gantt markiert überbuchte Perioden jetzt rot. Übersetzungen für alle sechs Sprachen ergänzt
  • Nachgetragen – beide Funktionen wurden bereits mit 1.4.2 ausgeliefert, waren dort aber nicht im Changelog dokumentiert:
  • Einheitliches Statusmodell für Teilprojekte und Aufgaben (Issue #78): neues Feld status (not_started/in_progress/blocked/done) auf nc_gantt_subprojects und nc_gantt_tasks ergänzend zum numerischen Fortschritt, Bestandsdaten leitet Migration Version1030 daraus ab. Validierung per StatusValidator (Whitelist analog ColorValidator), Status-Dropdown in den Detailformularen, blockierte Balken im Gantt schraffiert und mit Warnsymbol, blocked_count je Projekt im Rollup sowie ein Badge in der Projektliste
  • Mehrere Ressourcen mit individuellem Aufwand je Aufgabe (Issue #103): bis zu vier Ressourcen je Aufgabe mit eigener Aufwandsschätzung in der Einheit der Ressource (neue Tabelle nc_gantt_task_resources, Migration Version1029, Backfill aus den vorhandenen resource_id/work-Werten). Das manuelle Work-Feld entfällt: TaskService::resolveResources() summiert die Einzel-Aufwände zur Gesamt-Work (1 PT = 8 h) und übernimmt die erste Zuordnung als primäre resource_id, die weiterhin für Arbeitskalender und CPM maßgeblich ist. Ressourcen-Filter sowie CSV-/JSON-Export und -Import berücksichtigen alle Zuordnungen statt nur der primären

Changed

  • buildFrappeRows() (src/gantt/frappeRows.js) mischte bisher Datenmodell und frappe-gantt-Formatierung: die Einrückungstiefe steckte als Leerzeichen im name, Zustände (Dimming, kritischer Pfad, Summenbalken) hingen in custom_class – eine geplante Tabellenansicht neben dem Gantt-Chart (Issue #117) hätte dieselbe Logik duplizieren müssen (Teilschritt A, Issue #118). Neue Funktion buildRowModel() (src/gantt/rowModel.js) liefert dieselbe Zeilenliste jetzt als neutrales Modell (id, type, entityId, depth, title, start, end, progress, parentId, editable, matched, critical), resolveMilestoneDate() wandert mit ins Modell. buildFrappeRows() ist nur noch ein dünner Adapter darüber, der name/custom_class/dependencies wie bisher erzeugt. Reines Refactoring ohne sichtbare Änderung, per Fixture-Vergleich gegen die alte Implementierung geprüft; neue Unit-Tests (src/gantt/rowModel.test.js, npm run test:unit, via neu eingeführtem vitest) decken Hierarchie, Einrückungstiefe, Meilenstein-Datumsauflösung und Filter-Dimming ab

Fixed

  • Abhängigkeitsfortschreibung bei Aufgaben lieferte für alle vier Abhängigkeitstypen (EA/AA/EE/AE) einen um einen Arbeitstag zu langen Nachfolger-Termin – bei EA zusätzlich mit falschem Anschlusstag, da der Nachfolger auf dem Endtag des Vorgängers statt am folgenden Arbeitstag begann und dadurch mit dem Vorgänger überlappte (Issue #114). Ursache war eine Off-by-one-Vermischung zwischen der inklusiven Arbeitstagszählung und der exklusiven Datumsfortschreibung in TaskService::applyConstraint()/computeMultiConstraint(). Betroffen sind sowohl das direkte Setzen einer Abhängigkeit als auch die Terminpropagation nach Drag & Drop und die What-if-Simulation. Verhaltensänderung: Bestehende Pläne mit EA-Abhängigkeiten verschieben sich beim nächsten Speichern/Neuberechnen um einen Arbeitstag nach vorne (auf den korrekten Anschlusstag); bei AA/EE/AE verkürzt sich der zuvor fälschlich verlängerte Nachfolger-Zeitraum um einen Arbeitstag, die ursprüngliche Dauer bleibt jetzt garantiert erhalten. Abhängige Meilensteine (Dauer 0) sind unverändert korrekt und von diesem Fix nicht betroffen

  • Security: jeder Nutzer mit Schreibrecht auf ein eigenes Projekt konnte jede in der Instanz existierende resource_id einer eigenen Aufgabe zuordnen – unabhängig vom Eigentümer und ohne jede Share-Beziehung (Cross-Tenant-IDOR, Issue #112). TaskService::resolveResources() lud die vom Client gesendeten IDs bisher nur über ResourceMapper::findByIds(), also als reine Existenzprüfung ohne Berechtigungscheck; da die IDs fortlaufende Integer sind, waren sie trivial zu erraten. Der Listen- wie der Legacy-Einzelfeld-Pfad in create()/update() filtern referenzierte IDs jetzt über ResourceMapper::findVisibleToUser(), nicht sichtbare IDs werden wie unbekannte verworfen (Liste) bzw. nicht übernommen (Einzelfeld, der bestehende Wert bleibt erhalten). Regressionstests decken beide Pfade für create() und update() ab

  • Feiertage ließen sich nicht in mehreren Regionskalendern führen: POST /admin/holidays lief in einen HTTP 500, sobald dasselbe Datum in einem zweiten Kalender angelegt wurde, weil der Unique-Index aus Version1006 allein auf holiday_date lag, obwohl Feiertage seit Version1013 über calendar_id kalenderbezogen sind. Version1031 verschiebt den Index auf (holiday_date, calendar_id); die Eindeutigkeit globaler Feiertage sichert weiterhin der Upsert in HolidayAdminController::create(). Betroffen war neben der Feiertagsverwaltung auch der Kalender-Import aus einem Projekt-Export, wo der Fehler still verschluckt wurde. Zweitens war GET /admin/holidays admin-only, während work-calendars und work-schedules lesend für alle offen sind – für normale Nutzer blieb der Store deshalb immer leer (keine Feiertage im Projekt-Export, keine Markierung arbeitsfreier Tage im Ressourcen-Raster); der Lese-Endpunkt zieht nach dem Muster der übrigen Stammdaten auf /api/v1/holidays um (NoAdminRequired), Anlegen und Löschen bleiben unter /api/v1/admin/holidays. Ergänzend werden Feiertage jetzt mit ihrem Kalender gelöscht (WorkCalendarController::destroy(), HolidayMapper::deleteByCalendar()) und Bestandswaisen bereits gelöschter Kalender in Version1031 aufgeräumt – über verweisende Ressourcen haben sie bis dahin weiter als arbeitsfreie Tage gewirkt
  • Die Installation der Tabelle nc_gantt_task_resources scheiterte auf Instanzen, deren Tabellenpräfix die von Nextcloud aus Oracle-Kompatibilität erzwungene 30-Zeichen-Grenze für Bezeichner reizt: der von Doctrine automatisch vergebene Primary-Key-Name (Tabellenname + _pkey) wird mit Präfix oc_ zu lang (Issue #132). Die Primärschlüssel-Definition bekommt – analog zu den bestehenden Migrationen für nc_gantt_resource_capacity und nc_gantt_resource_groups – einen expliziten kurzen Namen
  • Der absolut positionierte Toggle-Button der Nextcloud-App-Navigation ragte in den App-Content hinein und verdeckte dort den Titel des ersten Eintrags in der Projekt-Rollup-Leiste (Issue #134); der linke Innenabstand reserviert jetzt Platz für den Button
  • Ein leerer Balken in Höhe der Kopfzeile erschien oberhalb des App-Inhalts, weil der CSS-Reset für den Nextcloud-Content-Wrapper an main#content.app-nc_gantt gekoppelt war (Issue #126). Ändert sich das Markup zwischen Nextcloud-Versionen (Klasse oder Tag), griff der Reset nicht mehr und der von NcContent (#content-vue) selbst gesetzte margin-top: var(--header-height) addierte sich zum Rand des Cores. Der Reset hängt jetzt robust an #content mit !important, ohne Abhängigkeit vom app-spezifischen Klassennamen
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturegO8Qmtdwg8LOBKr5G+mq4co374hsqqSN6oCIRV9atUx0KqogPxisJiIExkPoSIbu
e4EeIaUzg2alhZsKBLWOwR3Ab3fNm5vvd2DzJn6Hei7A70woz9m/LXkVlcx3vALW
bwolClUX1XCZOBVo/kSS5AOVwak3/huzT1iF9xH9BnpdzVuOjZ563LYwSayfb2Gq
SkWNfLZlKlDkTTF2PIszrNmaa89GmyqTbraxSP16/9nYdIj8ZU0zrhC3HtpihgAT
wya2lwnMf6I73HU0xxgT/+ITTmurx4eHwKWH80P4tjg/Y9mnHODIpAslbW3351mc
qdTHXIBW1MB1YGCQ+JPt11v1X2ccn29kEF9d1nkizKZ1+Du+LJQhPhwHiQxPWSwAUlTlQ4tj1lbe3+FJ1jsVTCqWbDUN02EoV7ZwtN15/HLJfM6w4drUi8ThJ1aLG3v6
cIwMJjYgWeepxR2gv4YgBf4u7txodm5bAWuzySk4rfAG1dBxmie/bfNnWmQ9LrYy
spwKc73gsPhg03ll+jp0b27fJfNF4IpOysz3i+r1ExVfeNIWWO91JPatO2pXZh4O
q0rczM8wYvctvcEkKQIL67HoIrKw4GVIXfqM9Oc8e/Ay7d/NPL+BjpCO6zvoFBY+
SRmjit15YmGW4EQwweQfKXuZ2YeySj+7OjhKHpKfvfg=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.2
Release Details
UpdatedAug. 20, 2026, 4:41 a.m.
Changelog

Changed

  • release.sh fragt die Versionsnummer jetzt interaktiv ab, statt sie nur aus appinfo/info.xml zu lesen: zu Beginn werden die aktuelle Version und das letzte Release-Tag angezeigt und es wird gefragt, ob eine neue Nummer vergeben werden soll (Vorschlag: nächster Patch-Level). Die Eingabe wird auf das Format X.Y.Z, auf einen echten Versionssprung und auf ein noch nicht vergebenes Tag geprüft und dann nach appinfo/info.xml, package.json und package-lock.json geschrieben. Fehlt ein Changelog-Abschnitt zur neuen Version, warnt das Skript; anschließend bietet es an, den Bump als chore: Version X.Y.Z zu committen — nötig, weil der Tag-Name den Commit-Hash enthält. Für nicht-interaktive Läufe gibt es --version=X.Y.Z und --no-bump; ohne TTY wird nie gefragt, make release bleibt also unverändert nutzbar
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturepoVHZxteU3AR2cpRRV98jNfv4j7rWnLEd3kbpn5Dp4T1ubAI+0QlRf9jxi0BaYz1
+1dg+3Yt25uN6Slp1FHiw7kyqt5HJ60XgnOWo+Zt0YBHSnWqLDhF8zxPEnQCkF+v
nUvscpcoQY2bRiIBZhVWVgeAD592uvOA4gfRDrUyLVDKjOrzBu3ScbNvCqTqE9IC
vs8qZkRLIcaD6tKoSLT2pZqmwBoCdClvEw5D5v40WSvLq232BZnXpQ4ogG3QvJdL
mYO8HlPZKVOxANp0MGnWle4IFRMbMt22Ebpkjc18Q9Q4AIv/Sd3zTsc+uMONTM95
s0GXvLSm95o0UCFZ1CL7fCEq7NwlprjVrTeWGmlJNVjHJuIyRKHEz5DR12s0lAGm
/rKGWjoVP+Wvk3upRizR/5y2fpWoiwuDqCtz9gQN6+HHYLaqLvYqsAJ/SxmtLtP7
8B2rK61ClKowz4phbTZdrCaF8w3IWnFFBTFquIVFuN2jUoHvdCMtd0910sLAMY5M
Xs9nk0FVsP23zKXlQpOojq7ouCQagRhsnBJDLxWRR+NIq582f7SDgcrkBqxlGJX4
/Ql9V+2iFx61QANCTjdJIO3LbvbK60vGos+ency0GfvSDbPovDAVyJzt8ZUh5BNw
UXQ4XOHJZAagAr36rKttk1DQbZZ/2bUEq231c96m83g=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.1
Release Details
UpdatedAug. 17, 2026, 7:43 p.m.
Changelog

Fixed

  • Die Meilenstein-Raute hatte eine fest verdrahtete Farbe (#fbbf24) statt der Projektfarbe zu folgen, obwohl Balken für Aufgaben und Teilprojekte bereits korrekt eingefärbt wurden (Issue #102). Zusätzlich wurden die separaten – und wirkungslosen – Farbwähler bei Teilprojekt und Aufgabe entfernt, da deren Anzeige ohnehin immer der Projektfarbe folgt
  • „Meilenstein hinzufügen" im Drei-Punkte-Menü der Projektliste nutzte zwei aufeinanderfolgende window.prompt()-Dialoge (Name, dann Datum als Freitext) statt des regulären Detail-Dialogs (Issue #101). Der Klick emittiert jetzt add-milestone analog zu „Aufgabe hinzufügen" (Issue #91) und öffnet denselben Meilenstein-Dialog wie beim Bearbeiten, mit vorbelegtem Projekt
  • Im festen Datumsmodus des Aufgaben-Detaildialogs konnte ein Enddatum vor dem Startdatum eingegeben und gespeichert werden (Issue #100). Jetzt zieht ein über das Enddatum hinaus verschobenes Startdatum das Enddatum mit; ein zu frühes Enddatum erzeugt ein rotes Fehler-Icon am Feld, hält den Fokus dort und deaktiviert den Speichern-Button, bis ein gültiges Datum eingetragen ist (dateField() in fields.js mit neuer setError()-Methode)
  • Eine Aufgabe mit Abhängigkeit behielt trotzdem die manuell eingegebenen Start-/Enddatumsfelder, die beim Speichern durch die Abhängigkeitsberechnung überschrieben wurden – für Nutzer nicht nachvollziehbar (Issue #99). Der Aufgaben-Detaildialog hat jetzt denselben Fixed-date/Dependency-Umschalter wie Meilensteine (Issue #90): im Dependency-Modus ersetzt eine Dauer (Tage) die Datumsfelder, die Abhängigkeit bestimmt den Termin. Serverseitig wendet TaskService::create() neu hinzugefügte Abhängigkeiten sofort an (bisher nur update()), damit auch neu angelegte Aufgaben keinen die Abhängigkeit ignorierenden Platzhaltertermin behalten
  • Der Speichern-Button des Detail-Dialogs blieb nach dem Hinzufügen einer Abhängigkeit deaktiviert: die Gültigkeitsprüfung hing allein am input-Event, das bei einem <select> vor dem change-Event feuert – zu diesem Zeitpunkt war die Abhängigkeit noch nicht in der Liste. detailModal.js wertet jetzt zusätzlich change aus, der Abhängigkeits-Editor (fields.js) meldet jede Mutation (Hinzufügen, Entfernen, Typwechsel) und der Fixed-date/Dependency-Umschalter in taskForm.js den Moduswechsel über ein eigenes bubbelndes change-Event

Added

  • CONTRIBUTE.md und setup-dev.sh für neue Mitwirkende (Issue #98): Projekt-Leitlinien (FOSS, Datensparsamkeit, Security), VIBE Coding ausdrücklich erlaubt, sowie der komplette lokale Dev-Setup-Weg (Docker-only, Nextcloud + MariaDB unter localhost:8088, optionales E2E-Setup, Git-/Bot-Auth). setup-dev.sh automatisiert diese Schritte, konfigurierbar über --workdir/--no-e2e/--no-docker-install
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturetYcUvVtDEQrAakG32EQF1atSOmz91/8XudCUh60A9r/AxMv+AA5AX2rIvNYDkEn0
OuTmXA6Iz0DoVkdij11MPDhfLaUy0mXeLbwB5fj/xF/cFYcNeCFGKD3k2jyRwOTo
2n1sEp0r8sn0fitHzLfhcB/By0VJkZyhaO/NctP01XfcSQM7lGEOeY/uagtGaDTI
JnPLoQTHo0nUOv4y7jUMZuurEgBOc4yeUxTKv4A/m642hvNQIS0q6K9ON41JHKIO
UtI7DbDWSboVhct1Go3zoj5XcaAGG9ZiwSkJDt/BXT5tWH4SOnSn7mys0j1F6Y0g
vIJWjz6S2RlekwIrIxgyaeEVBOeQ4OM1ilJGWKXDyYJM/0IBxqnqRXDkAFlOopDo
xezlcFdWTkYL5OBKMFJhKuTy7dEQ9hxx5Nz4+vLbNV8gDJZBI+5yI5m8W+809WIH
iKUpIda1ShOblvYH6Ek5AzBdTmoFQ6T4f7iWT7j1i4uUP2DsgehjGVl8yDIT/wyx
nV9t7koXapu1WeXrunSa++mXsi3lceNpthdz5/cUEOe9yWvc1rrulRhiWzePga8H
zjVQYGAIPvwYkWa47U6Zh7HBsQaS+9yQ8NDnD49SS4jUWTGlwNqfM+q9fZ16/G9d
7l4chZUPPbBv+xWfdxmFw+MC5zdkAq27isHToTqnm+w=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.0
Release Details
UpdatedAug. 13, 2026, 6:41 a.m.
Changelog

Added

  • Meilensteine werden jetzt immer direkt unter ihrem übergeordneten Objekt angezeigt statt gesammelt am Projektende (Issue #90): Meilensteine lassen sich neu auch einer Aufgabe zuordnen (bisher nur Projekt/Teilprojekt, Spalte task_id war bereits vorhanden, es fehlte nur die UI), das Auswahlfeld im Detail-Dialog heißt entsprechend „Übergeordnetes Objekt" statt „Teilprojekt". Zusätzlich können Meilensteine ihr Datum jetzt statt eines fixen Werts aus einer Abhängigkeit zum übergeordneten Objekt beziehen (EA/AA/EE/AE, analog zu Aufgaben-Abhängigkeiten; neue Spalte dependency_type, Migration Version1028) – da ein Meilenstein keine Dauer hat, bestimmen EA/EE das Ende und AA/AE den Start des Zielobjekts. Die Berechnung übernimmt der neue MilestoneDateService (serverseitig live bei jedem Abruf sowie im ICS-Feed neu aufgelöst, nicht persistiert propagiert) sowie clientseitig in frappeRows.js für sofortige Reaktivität ohne Neuladen
  • Undo für Drag-&-Drop-Verschiebungen inkl. Propagationskette (Issue #85, Umsetzung der einstufigen Empfehlung: letzte eigene Operation, kein Redo, zunächst nur Drag & Drop): Migration Version1027Date20260810020000 ergänzt nc_gantt_change_events um op_id (UUID) – alle Change-Events einer zusammenhängenden Operation (Drag + gesamte Propagationskette B→C→D) erhalten dieselbe op_id, erzeugt in TaskService::update()/propagateDates() und über ChangeEventService::log() protokolliert (dieses Change-Tracking war bisher tote Scaffolding-Logik ohne Aufrufer). Neuer Endpoint POST /api/v1/changes/{opId}/revert (ChangeEventController::revert, ChangeEventService::revertOperation) wendet alle Change-Events der Operation invers an, in einer DB-Transaktion mit Rechteprüfung über AccessService::canEditOrOwn(). Konfliktschutz: Revert wird mit HTTP 409 abgelehnt, sobald der aktuelle Feldwert nicht mehr dem protokollierten new_value entspricht (jemand hat zwischenzeitlich erneut geändert); der Revert selbst erzeugt wiederum neue Change-Events, die Audit-Historie bleibt lückenlos. Frontend: nach jedem gespeicherten Drag zeigt GanttChart.vue einen Toast „N Termine verschoben — Rückgängig" (showUndo aus @nextcloud/dialogs, 10 s sichtbar) sowie ein globales Ctrl+Z für die letzte eigene Operation der Session (stores/projects.js: lastOperation, revertOperation(), undoLastOperation())
  • Kalender-Export als abonnierbarer ICS-Feed pro Projekt (Issue #83, Variante A aus dem Umsetzungsvorschlag): neue öffentliche Route GET /apps/nc_gantt/projects/{id}/calendar.ics?token=… (regulärer, unauthentifizierter CalendarFeedController, damit externe Clients wie Thunderbird, Nextcloud Kalender oder mobile Apps ohne Nextcloud-Login abonnieren können) liefert Meilensteine als ganztägige VEVENTs (◆-Präfix), den aus den Aufgaben abgeleiteten Projektzeitraum sowie optional Teilprojekt-Zeiträume (Schalter „Auch Teilprojekt-Zeiträume einschließen", standardmäßig aus, um den Feed bei großen Projekten nicht zu überladen). Zugriff erfolgt über einen pro Projekt generierten, 256-Bit-zufälligen Token in der URL (CalendarFeedService, neue Spalte calendar_token auf nc_gantt_projects, Migration Version1026), der über einen neuen „Kalender-Feed"-Bereich im Freigabe-Dialog angezeigt, kopiert und jederzeit widerrufen/neu generiert werden kann (CalendarTokenController, nur für Projekt-Admins/-Eigentümer). ICS-Generierung ohne neue Abhängigkeit, RFC-5545-konform (Escaping, Zeilenfaltung)
  • What-if-Simulationsmodus für Terminverschiebungen (Issue #84): neuer Endpunkt POST /api/v1/projects/{id}/simulate führt Terminpropagation und CPM rein im Speicher aus (kein DB-Schreibzugriff) – TaskService::simulate() nutzt die neu extrahierte, stateless propagateDatesCore()-Kernlogik, die auch der persistierende update()-Pfad verwendet, CriticalPathService::computeFromTasks() erlaubt CPM auf einem hypothetisch veränderten Task-Datensatz. Frontend: „Simulation"-Toggle in der Gantt-Toolbar mit Banner inkl. Projektende-Delta in Arbeitstagen, Geisterbalken für die Ist-Termine (analog Baseline-Overlay) sowie Verwerfen/Übernehmen. Drag & Drop ruft im Simulationsmodus simulate() statt einer echten Speicherung auf. Szenarien bleiben bewusst flüchtig (kein Speichern benannter Szenarien), „Übernehmen" wendet die Änderungen als einzelne Task-Updates an, Simulation läuft pro Projekt
  • Neuer Eintrag „Aufgabe hinzufügen" im Drei-Punkte-Menü der Projektliste (Issue #91): legt wie der „Neu"-Button eine Aufgabe an, belegt dabei aber das gewählte Projekt direkt vor, sodass der Projekt-Auswahlschritt in der Maske entfällt
  • Such-/Filterleiste für Projekte, Teilprojekte und Aufgaben (Issue #81, Stufe 1: rein clientseitig auf Basis der bereits geladenen Daten aktivierter Projekte): Freitextsuche im Titel, Risiko, „überfällig" (Ende < heute und Fortschritt < 100 %), „über Budget" (Ist-Kosten > geplantes Budget), Ressource und „ohne Deck-Verknüpfung". Neuer Pinia-Store stores/filters.js (Zustand pro Nutzer in localStorage persistiert) und reine Matching-Logik in gantt/filterMatch.js. Nicht passende Balken werden in GanttChart.vue gedimmt statt ausgeblendet (Abhängigkeitspfeile und Zeitkontext bleiben lesbar), Projekte/Teilprojekte gelten als Treffer, sobald ein Nachfahre passt. Dieselbe Filterleiste (components/FilterBar.vue) dimmt in ProjectList.vue nicht passende Projekte; für nicht aktivierte Projekte sind nur Titel-Treffer zuverlässig auswertbar, da deren Aufgaben/Teilprojekte nicht geladen sind

Changed

  • Freigabe für Nextcloud 34 (Issue #94): max-version in appinfo/info.xml von 33 auf 34 angehoben, unterstützter Bereich damit NC 28–34. Verifiziert gegen Nextcloud 34.0.2 mit PHP 8.5 und MariaDB 11.4 (148 Unit-Tests, 39 E2E-Tests)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturerdYQI+Semnk0cWtKqUZinVDHk0KpxyqB5Ox4NBL9pyf5nrpK8xZpe9lBxc6zhDfW
8adLfVIwQtX+bI7S1O05xm0hwrUHQQ2ii6ADD8mlAxnZjdhKSCAhZ0NcaqT7Em0X
nD7yRP2B8zAAQMJNjzeBsLbzveNrXMoGzFrvm/jFxskUIUS01ykfWEg2C5+5/IAf
7jBAM8x2Qj92b8zyBFpLjfJQw9aTE/trtCsmZXQFmkJjGS0anrJc9dXKfqnHxknX
8jmLOv4Yq4Qtk3UF35HTiIGcA2W0UKfVyFb4XcrIMeSmLXXcagJWjeH5nB18UUNn
JyCgE/qY4v/SnrNQU92mIdMOQGuvYg7xbaz226lgNdwM2HuM9U8nc2juqJxAO+Wp
xs85yl82qIviZ5YY39HK371MZ/ufMsaVsVy3Nfn3PjqqkzGLmtAL6KJDcKHZWdDw
ugEPwO61DxnERZsNGeFpXfzCxjMpZc/qwUIfGw85idmU2vdedtrxHBkDGoqu1IP7
xZOO8uSYrzbXM6g1gs3WPBOY51CmZLs5pIQTN1tVl5ifGw4uOuzDBUCKiR5oA2MI
352HbA7wwWFgwoN9W5t4MRTowmaYpM8AB+nh9f1A5q9S8SelfMpXOqGew9VZb2jd
AuiJK/LEPjRgs5s3/FfC4Sb1MSsXDr1N1jziaF4MomM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.3.1
Release Details
UpdatedAug. 6, 2026, 12:57 p.m.
Changelog

Added

  • Regressionstests für die Rollentrennung Viewer/Editor/Admin: ForbiddenException-Tests für TaskService::create/update/delete/syncProgress und ProjectService::updateProject/deleteProject (inkl. „Editor darf nicht löschen") sowie erstmalige Testabdeckung für SubProjectService und MilestoneService

Fixed

  • CSV-/Formel-Injection im Aufgaben-Export (detail/io.js exportCsv): Task-Felder wie Titel oder Beschreibung, die mit =, +, - oder @ beginnen, wurden unverändert übernommen und von Excel/LibreOffice/Google Sheets als Formel ausgewertet. Die Absicherung aus ReportView.vue liegt jetzt in einer gemeinsamen Utility (src/utils/csv.js, escCsvCell) und wird an beiden Export-Stellen verwendet
  • Viewer sahen im Frontend dieselbe Oberfläche wie Editor/Admin (Add Task/Subproject/Milestone, Share, Delete Project, Drag/Resize im Gantt-Chart, volle Bearbeitungsformulare), obwohl das Backend Schreibversuche ohnehin korrekt ablehnte – kein Least-Privilege an der UI. ProjectService::getAccessibleProjects()/getProject()/createProject()/updateProject() liefern jetzt das effektive permission-Feld (AccessService::getEffectivePermission()) mit; ProjectList.vue, GanttChart.vue (inkl. Drag/Resize-Sperre je Projekt) und das Detail-Modal (detail/detailModal.js) blenden Schreib-Aktionen für Viewer aus bzw. schalten Formulare read-only
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureBUyDeI9y7iKD1wQJLHrW6IFq0zuXOJQ1Zv/x+0RryIIQ0fAGAUjwQyLDYLYpRzPg
6ITDPfY9bftVlwkB8w9LqZiFETkH8mgc6l5XB7F6NKzFrdaSnNw21CIVJjWyHpkR
mxDq+vQepZd+YtB9jMz39kbFk9BNHrpKIwIXXZVqEqj1U54NmT+5XnT892m9mY6o
RWQNf3Mn5WcH3vmoDi/UAOgDaO30GFCRJePryurVpK7stkub8K6fYsWIkS5NeJlP
YHdb4nBlkhUzQFjo0ZDSkCSiWjMdyCrtEanX6m6Ffhr+j0jpd+J9soMSjrzdzt4T
5mETo8xc61IQIVFWMD6fZ3/oCmbx2TFDZsJjRpFKxoPA08AkdC7xjxHoaKYZHvi4
+tzowxPzMfyjQ/hEj2dwq22doM2lXK1Y13VvV8kkaomrAQjB97gf+ODrYZNDgNvc
2ijU08B4cAB0HbEveDpDRjCJj8D5OwCMafRMa4Ul/nm0+RiBFOhIjDYdVAnCp7Ql
IEc4UQZM9WYLQlouwGPk83POpbqkbc8vKAucGBXvHAbxNpUSOGbssMYFGU/e9pOg
+oT2gcJrC3MYPGIWnS8iLn75PK1H063KFJv5yqC+h/rqwX/FxyTzKvofJi68GpLs
WtG3y67W8Ju4y1I9iQ9raJxxhFUJrStibGy9gc7L0DM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.3.0
Release Details
UpdatedJuly 9, 2026, 5:23 a.m.
Changelog

Fixed

  • Baseline-Toggle im Gantt-Toolbar zeigte nie Baseline-Balken und PUT baseline/active warf einen SQL-Fehler: baseline_id auf nc_gantt_projects wurde mit der 3-Ebenen-Migration versehentlich zusammen mit den tatsächlich berechneten Spalten entfernt (Migration Version1025 stellt die Spalte wieder her). BaselineService::create() aktiviert eine frisch eingefrorene Baseline jetzt automatisch fürs Projekt; renderBaselineBars() (GanttChart.vue) und baselineOverlay.js lesen Baseline-Items dafür über task_id statt des seit der Umstellung auf das 3-Ebenen-Modell nicht mehr existierenden subproject_id-Felds
  • OCS-API-Fehlerantworten (400/404/500 …) lieferten für alle OCSController-Endpunkte einen leeren text/html-Body statt des erwarteten JSON-Envelopes mit message; ExceptionMiddleware wirft jetzt passende OCP\AppFramework\OCS\OCSException-Subklassen statt einer rohen DataResponse, die Nextcloud-Core nur für 401/403 automatisch formatiert. Betroffene Controller (ProjectController, ReportController, ShareController, ChangeEventController, WorkScheduleController, WorkCalendarController, HolidayAdminController, SettingsController) wurden zusätzlich auf die bestehende ApiException-Hierarchie umgestellt

Removed

  • Nie ausgewertete Gruppen-Freigabe-Option entfernt: Share::TYPE_GROUP, principal_type-Parameter in ShareController sowie die DB-Spalte principal_type (Migration Version1024) wurden gestrichen; Freigaben sind jetzt ausschließlich benutzerbezogen

Changed

  • Dashboard-Summary (DashboardController::summary) lädt Baselines und Aufgaben-KPIs jetzt über gruppierte SQL-Aggregat-Queries statt pro Projekt einzeln (N+1-Fix, gilt auch für den Admin-Fall mit allen Instanz-Projekten)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureNJfbRJEXzKGipUjUW9tUKayHoY6ltSU0ZeCQXcDx6XVDY/naLK0dVY9ciofXU7oy
40sJIOsjxcUZbalDwqncPn0vjGoqmk3BFUT7KotEpLLf8/ZmIjdHEbQbJHzEpdQV
y5YedjqRLKB7/Ul35JWVFxY8eutCsYkonfof7v6AGMGB/RjQ7GDB6jWunEEwqUGV
3Y1isvdq5N3oo9NDY/QR0C2C7jiMnB9Kon0KzZ2yp0oF5euOpA/qrtmqxG3L9PoZ
DW1ppwAuARWtRDu4tcDAAQAkF1Mrg5YyYgRoKm7uVazlKEP7DxX56g/g4RS2otEE
rKsA/ER9yYiHnNyGcZuK9Jkfe2Ua6/R7gzJilRvHZ7CBPkhY+XNPcrjlsHbCJEJJ
cX/b0B56p7FyAFy6XjMY9PYFhxy/ubHE7Sk8ixX88uxgM4vf/sSFQaN84CcG/qqA
Nq/OEytBjZP82TsFFYBRcPKEPskF4ejjhNVC4bJpiuCIpo51nIxjeFGtDpeQiDG7
0OWc/GCvsz5W3eG7ShmQsRf0DoivL8tjgDUlMWO9boTpUy2Vnm1rDMKu6nFGKZ8o
TWTZR6u4zGZW1OBERdlU5NQmqxqXrsuGlT6r6DuQnWsWiscjXOyIFeHz+EOKhQOk
wUuN6xN8QES1CDFB27PYV0Sz2KhYhM78GKLCc9B10Ic=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.2.0
Release Details
UpdatedJuly 5, 2026, 9:21 a.m.
Changelog

Added

  • Löschen-Buttons im Detail-Modal für Teilprojekt, Aufgabe und Meilenstein
  • Deutsche App-Beschreibung in info.xml ergänzt

Fixed

  • Baseline-Datum und Kommentar im Report werden untereinander angezeigt
  • Dashboard-Widget zeigt Baseline-Datum und KPI-Werte korrekt an
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureXuYTZMxTlGNJVrGvU/GcIjSlBTYreXdvF5FilCmsi+l7MBvFlyeW1DsnxAsao3pu
HyhvaKXRnkraVQNT2ULgX4BmjUnhsELROrK03gtY88Odzqzh7RIXYkNkRcy92ara
56HIP8BBRD3m1c8pYPfpZfLAzkuurAzVqbJ6qbxw1AebdlPCFEq2g6C+IOcTon0T
q9ZD2I2XJmWd42EXXqva+NMrcx1jfjmHWVtl7xHKhwPndFCtHPMMAdoDS0Xpbh1V
3Ns4h/DphDpC8/ZYZ5sbpMCBekHw4VTZDGxNAuXJ5DMPhkqg2MxVplkS19PuBHLx
r74sgsz611Gjg55gjKOqCb5ZZEvqZTrwKTEYIbu8HicWtq/HxKRZS3FZN9MThTTX
Hesv65vsq9fH0UhEM6MVJjE5Phnw8Wb5ivtAiaUA+NzPrDfrHZAsSfR9NFL3rhFC
7wOmnXtzK40NjmqyMWJu/UP9UVbz3SeEiHiQO9GwBc2krzmXzcmLZFgEjty4CGoJ
SzXAA1QGpUGO4n0b3Y/5zSY4UxogGWybW+mOs27KDLytI915wNYGvBtcdAKCj6Ws
1uVA98npwMid/WSJJ04BXHX8LbowrDeTezSFJyGh+u/KnhlzkA7fqEuu3nQGT5rA
a9qeMmd5kmLBIVcG9RVVmw1kc0AK0qIqZDmlk9dWGJs=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.1.1
Release Details
UpdatedMay 27, 2026, 6:43 p.m.
Changelog

Added

  • Glossar-Button in der Navigation (über den Einstellungen) mit interaktivem Nachschlagewerk
  • Dreispaltige Glossar-Tabelle: Begriff/Abkürzung, Bedeutung/Englisch, Erklärung mit Berechnungsformeln
  • 30 Einträge in 6 Abschnitten: Allgemein, Terminplanung, Baseline & Berichtswesen, Earned Value Management, Ressourcen & Kapazität, Budget

Fixed

  • Fehlende deutsche Übersetzungen für englische UI-Strings ergänzt (Add dependency, Baseline, Dependencies, Remove, Work, No projects yet, Open Gantt Projects, u.a.)
  • Leere Übersetzung für Deck-Fortschritt-Hinweis befüllt
  • de.js vollständig mit de.json synchronisiert (war ~70 Einträge veraltet)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureF1RHJx15J/N8tWNrDlAX1MFE/9tsct4PViEcBDeo8U/V2qJ/tezL7Xk0BVmYxjWw
pB+J685mcHjikh93/aZUqG8C6y0mR3TTJfaa7dLCIRMc1034x6Xj9Nd7Q9YVH4yi
RLTcRhrG2pN1Iqc23kwId995GJXHnCBEyuQuzo9m1VtA7GoFa8W2nqhXVT94khDS
8ZHQrixDfv63d4GfA5N2x4+phaiyObdskvCmVSuKrmouYvCGpPevtKG5YxzOrHid
aL48Kod0YgOCAD8nAqOhEmioP0m+wP2e/NC4Z5svSKT3vdlE67W1M68ipQQfnhPI
txui+2X8zFvoe/M5sE3DaXbLnOVNGQ7YRpyXFI5GsQmQ0cPSSO/94Mw15hLZfwMf
TDOrrvzf+Vu05sUTZ6CFh4FrSl4e5Q6Xjv6uH4BZtyOpPxl+ajgW4OkZvQDbt4KC
8aTZodMcDpXlRMDdBSxT1bT9tD05KUKmEZYtpxHiARrHDuQQCRSuxtjitQD9lbla
CMxKrBiO0YgdUb3FuczYkWEH+y8gW5egU6TDMnjAVbuUecGuGZN1Cc6tarcFWRu2
+V7Qn+aNoXEwP5e/0TM4Ig8ETAYseZRiTPHxeWiSg3RnU3HuT6kPVWw8LERACDT4
6F4WU9t2+4kESMLMjeV0/2UBQSykR/42Idsg0PtvpyQ=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.1.1 (nightly)
Release Details
UpdatedMay 27, 2026, 5:24 p.m.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureF4W7QJB8rVJ2xARdnhUbEouzRZMKcowz/ToDwr0oVFrVUbInFvHAMqXFTOVD1a5N
kDTb0pOhv+hCStTh70bN+aapjbdtp7SdQ3SbP5VoXBKLhUii41OqN/i4yM7itdSs
M8d5PVo9TJYVnfaij2xwWghMqZEyzxgOw4Q98dYIysf2BxsjjCtxGEMo/pISS90G
OE2RaVEFbwUcvu1XKszLP5X/k/onOchengURYVuzHP7VgVuomZpPSZ9VEIRKITyL
GpgSDrdqm5AXdQc7l/2OqprW6G+MxsuVzChbyPGslIYYXYsP9HLc/FfwVxaCJjh2
Nsiqfd+dMwnf7f9yrrBuZjbNwNa5x++IynrwaU01jVISkl9pgkbUYRaPSMTGFDAd
lsEEqlgs9KdzGoTFjDXNdTwDOsUMiu/ag8tPo7YxsxLFbVGa7laRAUhlGUT9QGPr
IOAAWvKqivsYnU5iwTCY/5HGza3SDfZc/e5upPfB+lTQTYijp1aAYRBAsoOLmuga
f0aP45pnfnYBJkT1kMsthjbGMdlL46wLiNHKRct9OlFwx74IRIyZdcs5Q3pC0aNN
DSLvsCSmY8/9PtTLzcOJKXTqqDVupCqq82bUlGRn7NR6xsinzv74MuOVnGY21tBm
iB5ceYpgiEukUz6YtS2quIIiMTnYmM+HBFnkXgBV0/Y=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32

Nextcloud 28

Gantt Projects 1.5.4
Release Details
UpdatedAug. 27, 2026, 7:06 p.m.
Changelog

Fixed

  • appinfo/info.xml wurde vom Nextcloud App Store abgelehnt: der Sprachcode pt_BR in <name>, <summary> und <description> ist im Schema nicht enthalten — die Enumeration kennt nur BCP-47-Schreibweise in Kleinbuchstaben mit Bindestrich. Alle drei Vorkommen heißen jetzt pt-br
  • Die Kindelemente von <info> sind im Schema eine feste Sequenz; <settings> stand vor <dependencies> und wäre nach dem Sprachcode-Fix als nächster Validierungsfehler aufgeschlagen. Der Block steht jetzt an der vom Schema vorgesehenen Position hinter <dependencies>. xmllint --schema gegen https://apps.nextcloud.com/schema/apps/info.xsd läuft damit sauber durch
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureYbjiEkGYW1s8Xg9Jvrt4nNo/67zkrQDA16yfK2MzVa58R982qrLUupNbvUE/FscP
pFg9nlqxd81cpyH1ZhWOM7fMq98mPyjSUsJZ7xjYzNccF13xvDpBXFlfX4UyCknc
50Rmw9a8RxiCH0mEpH9zWjdanX194R8cUIMDY+BcymCgyBVRQub9yaL5iiHH3hNA
OOD+UOiSUNHns9R6sgZ+tF4OeoTufWR5//AfRmuL5qC5spyuP1iKr7FnzPar+/sS
pHKojfUyi0sAjlrThVZDo8fvVPqkkH4jgvVmNE41t1UOlVdajIRd2yhbHX0h0SSs
rmt4CQqNXAjLE/Wlq2lu9Viw4M2BhhPIfVb5YJFzaxjhB8RRy53rquXRL64f7vGa
agq0ri3eD+0ZWmMOlJmHaMv6AXYd0ZG8myb3PAyNC0NYXzrw2PAVL8jDfzmq2cNY
Q3rIh101vtGPytqanNS2VmtfZ8BX63rd4SLR4PJdRYrm3Wbqanx8WZa20eLgYF8S
M9xhxl5Jf8+TnYLwHi1sGm1ID2XJ4krfgOxiUlB8lGeSweUK1uueC0bmUDsrXyhJ
RMGST41TU1HqXx/3Eeh91JKq/Jbx15kPuxu7WNKyuSOj4vKbgFwBUSmHKDU6lvEZ
L/bnxZi965/4K3kvyJ8o2j5e4xUmJLeusi9Fg0yrRqE=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.2
Release Details
UpdatedAug. 26, 2026, 5:18 p.m.
Changelog

Changed

  • Teilen-Dialog: das Eingabefeld für den einzuladenden Nutzer ist jetzt ein Suchfeld statt eines reinen Textfelds für die Benutzer-ID (Issue #144). Getippt wird nach Anzeigename, Benutzer-ID oder E-Mail-Adresse; ein neuer, admin-unabhängiger Endpunkt GET /api/v1/users/search (UserController::search(), IUserManager::search(), max. 20 Treffer, der eigene Account wird ausgeblendet) liefert dazu Anzeigename, Benutzer-ID und E-Mail als Vorschlagsliste. Gespeichert wird weiterhin die Benutzer-ID als principal_id – für Umgebungen mit LDAP/AD-Benutzerverwaltung war die zufällig generierte ID zuvor nicht ohne Umweg über die Benutzerverwaltung in Erfahrung zu bringen. Die Liste bereits geteilter Zugriffe zeigt ebenfalls den Anzeigenamen statt der rohen ID (ShareController::index() reichert die Antwort um display_name an, Fallback auf principal_id falls der Account inzwischen gelöscht wurde)
  • Übersetzungen für alle sechs Sprachen ergänzt
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureyLn/jlYbk3gIYfgIcjON0z467/xL9L6QNcmfgOa/4zhTJjLknXq7eu1UJddWWlLJ
NG2U9d/OEFO9wLHPYPGNiWgQMRIk+TGYlQVTXcZH3WpBxdJOm3XMnk5hq2kNB2FN
TJemqr/dxafGB2hTIgivPMXMnemdrtxWN1RAdzCxZIg9HwJWjG5JxdqHmURHwske
p/Ki/iZghKjrxbPIghbqtrvkCJRImbgVWY8AmUNUPLgotNIthiWFnkTDVhYWcreP
pWleWHxEn57UOtehff1aJa+hRI+8WVkx9iXArx0SThmOCYYgJ/HeG8dOOtmr9jSm
1nzETAL87YLxL/+qM6DyBIgNWhrq1oj9Q12bBm1+la477z6fpOgUlMjWkPEYRQi/
vhxirXwB4BZBYvaMEkNlN2U3+7BqgigGoaTcbN2rG/TP1JuOjdj9jEjMMRye0JbT
35XOoM/VPYGovrT9slHg8r3Wolyd8ioXVOu4IcMImvC5OrTzpKY7NLEc/S+cOKwz
ijOKcnoV0j++KxtQKKgEO96HJpEM0jteQVOGCoPbghjS3OFzkiB1bUVJAlu1jn54
38Q2zw8rZ0EMm1rEPmIrl72DIIXionbWKatREgy7QPwuL/WKZ2c+J1UIUTKck5eO
7M2VHh6P3FnIg/UsOCMu3U7ja0Y8vQ3YUo3tazLfob0=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.1
Release Details
UpdatedAug. 25, 2026, 1:28 p.m.
Changelog

Added

  • Screenshot des gerenderten Gantt-Charts als PNG, SVG oder PDF (Issue #116): ein neuer „Screenshot"-Eintrag in der Chart-Toolbar öffnet ein Menü mit den drei Formaten, derselbe Export steht im Bearbeiten-Dialog des Projekts neben JSON und CSV bereit (dort mit vorgeschalteter Formatwahl statt Menü, openScreenshotFormatDialog()). Exportiert wird stets das gesamte Chart, nicht nur der sichtbare Scroll-Ausschnitt — frappe-gantt rendert die volle Breite und Höhe ohnehin als eine SVG. PNG und SVG klonen die aktuell gerenderte SVG und schreiben getComputedStyle() als Inline-Attribute (löst auch CSS-Variablen auf), sodass die Datei ohne das App-Stylesheet eigenständig darstellbar ist; sie folgen dem eingestellten UI-Theme, ein hinterlegtes Rechteck in --color-main-background deckt dabei auch die Fläche unterhalb der Aufgabenzeilen (Workload-Chart, Leerraum) ab, die sonst transparent bliebe. PNG rastert per Canvas mit doppelter Auflösung
  • Zeitraum-Auswahl für den PDF-/Druck-Export (Issue #116): vor dem Drucken fragt ein Dialog, welchen Zeitraum die PDF abdecken soll — gesamter Projektzeitraum (Vorbelegung), laufendes Kalenderjahr, „aktives Quartal" (Vormonat bis einschließlich übernächstem Monat) oder ein frei eingegebener Bereich. Der Vorschlag ist der tatsächlich von Balken belegte Zeitraum, nicht gantt_start/gantt_end — frappe-gantt legt darum großzügig Puffer, der andernfalls mitgedruckt würde. Umgesetzt wird der Zuschnitt als viewBox auf dem SVG-Klon; die dafür nötige Skala (Chart-Start, Pixel pro Millisekunde) schreibt GanttChart.vue nach jedem Render als data-Attribute an den Chart-Container, sodass auch Aufrufer ohne Zugriff auf die frappe-Instanz (Bearbeiten-Dialog) sie lesen können. Die Zeitraum-Logik steckt isoliert testbar in src/gantt/printRange.js (src/gantt/printRange.test.js)

Changed

  • Der PDF-Export druckt nicht mehr den Live-Container, sondern einen gestylten, selbst gerasterten Klon des Charts (Issue #116). Bisher wurde das Inline-SVG direkt gedruckt — wie fein die Browser-Engine das rastert, ist nicht steuerbar und fiel je nach Browser sichtbar grob aus. Jetzt wird der Klon mit 300 dpi bezogen auf die bedruckbare Fläche (A4 quer, 10 mm Rand → 277 × 190 mm) in ein Canvas gerastert und als Bild mit fest vorgegebener physischer Größe in den Druck gegeben; schlägt die Rasterung fehl, bleibt der SVG-Klon als Druckinhalt übrig und skaliert per CSS auf die Seitenbreite. Der Klon wird immer im hellen Theme berechnet (Papier ist weiß, ein dunkles UI-Theme ergäbe sonst dunkelgraue Flächen und helle Schrift) — dafür genügt ein ausgelagerter Container mit gesetztem data-theme-light, da Nextcloud die Stylesheets aller Theme-Varianten lädt und nur über dieses Attribut umschaltet. Das Ausblenden der übrigen Seite läuft über display: none statt visibility: hidden, sonst blieb die Fläche der App als Leerseiten erhalten; Nextclouds Hintergrundbild auf html/body wird für den Druck abgeschaltet. Aufgeräumt wird über afterprint mit Timeout-Fallback für Browser, die das Event nicht feuern
  • Der Toolbar-Eintrag heißt „Screenshot" (Icon MonitorScreenshot) statt „Export" (Icon ExportVariant) — „Export" ist im Projekt bereits für den Daten-Export nach JSON/CSV belegt, der Chart-Export ist demgegenüber eine reine Abbildung der aktuellen Darstellung
  • Übersetzungen für alle sechs Sprachen ergänzt
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
Signaturek6kpvF53IR8tnkOFXyoSPFPGlwVzO/RUTgI1p1ppRcFmoFPUyFeIokOqWA1OtD9q
wdo+qkQQPyJGph0Uwp+hwP9oGmeKWErnlv8HMdA5I5iaXIN7afGvdfxWfKgqWetw
tGmCF7l2IzMmT2Ol/3pKgCnFkXTDPCVeNINNbUdi7EjeRpbcbOGWt3+5UVwZgVTX
Z9/kEEPvjMV98s1zT5yBXcFvyqZA7bhhezmBkfzaLa0DAIczFJbhyFtR06WuS7bP
CWBCs/xvSRuCwo61oyXRAWLohz/2GsrMSa5jvPvnEG1XEHpGPVorCijAvsBm4sX5
yAZTrBm3zbNYObqVE2idxTH/eqP8xXtE38JFjpG5IahpeFNb9V2EbH1nrjfRKYcH
NVvXcXFREAmvorShKDE0ymFN+/BCjvU1vnJCnRD5RMsoSGUzXSVHPrF1emtusLHj
ltP22eYOCpraEpZheTkFftqvpbiQKVXsZ+8wY4dJnh5Ymi71loxZhggoH8s/pmp+
WbSx6MZwSPBqJ0HOJWckFiZXur2OQYOVLfXt8uPYNU/EZSoYDqm81GVMglQXxyM6
YDh0xXqwJ7Qft7k0O/3Fa5YLJGP4B4RvjU29N3/WDsfjuk7PeCSTPhRlTOfV/Fbn
jS83WVBavmyklhu0rNYuCYfdYvUxemIO3VuGmYzFXgI=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.5.0
Release Details
UpdatedAug. 24, 2026, 5:26 p.m.
Changelog

Added

  • Editierbare Vorgänger-Spalte in der Tabellenansicht, Teilschritt F von #117 (Issue #124): eine neue, über das Spaltenmenü einblendbare Spalte „Vorgänger“ zeigt die Abhängigkeiten einer Aufgabe in der aus MS Project bekannten Kurznotation (12EA+2d = Vorgänger Aufgabe 12, Ende-Anfang, zwei Arbeitstage Abstand; mehrere durch ; getrennt) und nimmt sie dort auch entgegen. Typ (EA/AA/EE/AE, englische Kürzel FS/SS/FF/SF werden beim Eingeben mit akzeptiert) und Abstand sind optional, 12 allein bedeutet also EA ohne Abstand. Geprüft wird beim Verlassen der Zelle: Syntax, Existenz der Aufgabe im selben Projekt, Selbstbezug, Dubletten und Kreisschluss über die gesamte Abhängigkeitskette – bei einem Fehler bleibt die Zelle im Bearbeitungsmodus und nennt den Grund im Klartext, die bisherigen Abhängigkeiten bleiben unangetastet. Gespeichert wird über dieselbe PUT /tasks/{id}-Route wie der Detail-Dialog (inkl. dep_mode), sodass der Server die Termine anwendet und durch die Nachfolgerkette propagiert; Balken, Pfeile und Typ-Labels im Chart zeichnen sich mit der Antwort neu. Bewusst ohne Undo-Toast, da ein Zurücknehmen nur der Termine (nicht der Abhängigkeit) beim nächsten Neuberechnen wieder überschrieben würde. Nur Aufgaben haben eine editierbare Zelle – Meilensteine hängen über task_id an genau einer Aufgabe, Projekte und Teilprojekte sind berechnete Strukturebenen. Notation und Prüfungen stecken isoliert testbar in src/gantt/dependencyNotation.js (src/gantt/dependencyNotation.test.js)
  • Zeitabstand (Lag/Lead) je Aufgaben-Abhängigkeit (Issue #124): neue Spalte lag_days in nc_gantt_task_deps (Version1032; der Name vermeidet das seit MySQL 8.0 reservierte Wort LAG und nennt die Einheit). Der Abstand zählt in Arbeitstagen über den Ressourcenkalender wie die übrige Terminberechnung, wirkt bei allen vier Abhängigkeitstypen auf deren Ankertag und darf negativ sein (Lead: der Nachfolger beginnt früher). Bestandsabhängigkeiten bekommen 0 und verhalten sich unverändert. TaskService::update() weist eine gesendete Vorgängerliste jetzt vollständig zurück (invalid_dependency, dependency_cycle), bevor die bisherigen Abhängigkeiten dafür gelöscht werden, statt Vorgänger aus fremden Projekten oder Zyklen zu speichern – letztere hätten die topologische Sortierung in recalculateProject() stillschweigend Aufgaben überspringen lassen

  • Konfigurierbare Spalten in der Tabellenansicht, Teilschritt E von #117 (Issue #122): ein Menü in der Tabellenkopfzeile blendet Spalten ein und aus, die Reihenfolge lässt sich per Drag & Drop der Kopfzellen ändern (barrierefreie Alternative: Strg+Pfeil links/rechts auf der fokussierten Kopfzelle), die Breiten per Ziehen am Spaltentrenner (Doppelklick setzt auf die Standardbreite zurück). Zusätzlich zu den bisherigen Spalten (Titel, Start, Ende, Fortschritt) stehen ID, Dauer (Kalendertage inkl. Start- und Endtag, bei Meilensteinen 0), Status (Issue #78, nur Aufgaben/Teilprojekte) und Ressource (Issue #103, zugeordnete Ressourcennamen einer Aufgabe) bereit – alle vier als reine Anzeigespalten, die das Inline-Editing und die Tastaturnavigation daher überspringen. Auswahl, Reihenfolge und Breiten werden pro Nutzer über den in Teilschritt B angelegten UI-Preferences-Endpunkt persistiert (neuer Key gantt_table_columns, kein Schema- oder Endpunktwechsel nötig); eine gespeicherte Konfiguration wird beim Laden validiert, sodass entfernte Spalten oder unplausible Breiten die Ansicht nicht beschädigen können. Die Tastaturnavigation folgt jetzt der sichtbaren Spaltenreihenfolge statt einer festen Liste. Reicht die Tabellenbreite für die gewählten Spalten nicht aus, scrollen Kopfzeile und Zeilen gemeinsam horizontal; die Obergrenze des Splitters steigt dafür von 560 auf 900 px. Die Spaltenlogik steckt isoliert testbar in src/gantt/tableColumns.js (src/gantt/tableColumns.test.js). Ein Sortieren der Zeilen nach Spaltenwert ist bewusst nicht enthalten – es kollidiert mit der Hierarchie Projekt → Teilprojekt → Aufgabe und der sort_order, die das Chart für dieselbe Zeilenreihenfolge braucht

  • Tastatur-Navigation in der Tabellenansicht, Teilschritt D von #117 (Issue #121): Tab/Shift+Tab springen zur nächsten bzw. vorigen editierbaren Zelle (überspringt Zeilen ohne Schreibrecht, springt am Zeilenende zur nächsten/vorigen Zeile), Enter speichert und springt in dieselbe Spalte der nächsten Zeile, Esc bricht ab und stellt den vorigen Wert wieder her. Pfeiltasten bewegen die Zellauswahl, wenn gerade keine Zelle im Editiermodus ist (innerhalb einer Zelle bleiben sie für Cursor-/Wertänderung nutzbar). Die reine Traversierungslogik steckt isoliert testbar in src/gantt/tableNav.js (src/gantt/tableNav.test.js). Die ausgewählte Zelle bekommt einen sichtbaren Fokusrahmen und wird per scrollIntoView() ins Sichtfeld gescrollt – über den bestehenden bidirektionalen Scroll-Sync (Issue #119) folgt das Gantt-Chart automatisch mit. Neue ARIA-Rollen (grid/row/columnheader/gridcell, aria-readonly je Zelle) machen die Tabelle für Screenreader als Grid erkennbar
  • Read-only Tabellenansicht links vom Zeitstrahl, Teilschritt B von #117 (Issue #119): neue Komponente GanttTable.vue zeigt dieselben Zeilen wie das Chart (Titel mit Einrückung nach depth, Startdatum, Enddatum, Fortschritt), gespeist aus buildRowModel()/buildTableRows() (siehe Teilschritt A, Issue #118) – Reihenfolge, Filter-Dimming, kritischer Pfad und Projektfarben bleiben so exakt konsistent zum Chart. Zeilenhöhen sind fest an frappe-gantt gekoppelt (40 px = bar_height 22 + padding 18, Kopfzeile 52 px = header_height). Ein Toolbar-Button blendet die Tabelle ein/aus, ein Splitter macht die Breite verstellbar (160–560 px), vertikales Scrollen ist bidirektional mit .nc-gantt-container synchronisiert. Sichtbarkeit und Breite werden pro Nutzer über einen neuen, generischen UI-Preferences-Endpunkt (GET/PUT /api/v1/ui-preferences, SettingsController über IConfig::get/setUserValue() als JSON-Blob) persistiert, damit Teilschritt E (Editieren) das Schema nur noch um weitere Keys erweitern muss, ohne Endpunkt oder Speicherformat anzupassen. Rein lesend – Editieren folgt in Teilschritt C
  • Projekt-Export/-Import (JSON, format_version: 2) kann jetzt optional die von den Aufgaben referenzierten Ressourcen inkl. Gruppe, Wochenmodell, Arbeitskalender+Feiertagen und Tageskapazitäten mitnehmen, statt wie bisher nur die rohe resource_id in eine Zieldatei zu schreiben, die dort ungeprüft übernommen wurde – auf einem System ohne identische Ressourcen-IDs ging die Zuordnung damit verloren oder landete schlimmstenfalls bei einer fremden Ressource (Issue #115). Vor dem JSON-Download entscheidet ein Options-Dialog, was mitexportiert wird (Ressourcen / Verfügbarkeiten / Kalender, gestaffelt); vor dem JSON-Import zeigt ein passender Dialog, wie viele Ressourcen die Datei enthält, und lässt auswählen, was übernommen wird sowie ob bei Namensgleichheit die vorhandene Ressource wiederverwendet (Default) oder immer neu angelegt wird. Referenzen werden ausschließlich über eine Mapping-Tabelle aufgelöst und nie roh durchgereicht; nicht auflösbare Referenzen werden verworfen (Regressionsschutz zu #112/#113). Neu angelegte Ressourcen/Gruppen/Kapazitäten gehören stets dem importierenden Nutzer. Wochenmodelle/Kalender/Feiertage sind weiterhin admin-only anlegbar – ohne Adminrechte werden nur namensgleiche vorhandene Einträge gemappt. CSV bleibt unverändert aufgabenzentriert mit Ressourcen nur als ID-Referenz; der volle Ressourcenumfang ist JSON-only. Alt-Exporte ohne resources-Schlüssel importieren unverändert wie bisher, ohne Options-Dialog
  • Inline-Editing der Basisfelder in der Tabellenansicht, Teilschritt C von #117 (Issue #120): die Zellen für Titel, Start, Ende und Fortschritt sind direkt editierbar und aktualisieren die Balken im Chart sofort. Gespeichert wird über die bestehenden Store-Actions (updateTask/updateSubproject/updateMilestone/updateProject) inkl. Terminpropagation und dem vorhandenen Undo-Toast für Aufgaben (analog Drag & Drop im Chart); ein lokaler pendingEdits-Overlay zeigt die Änderung optimistisch an und rollt sie bei einem fehlgeschlagenen Request mit Fehlermeldung zurück. Die Schreibrechte löst tableRows.js je Feld über store.canEditProject() auf (titleEditable/startEditable/endEditable/progressEditable) – Projekte und Teilprojekte bleiben bei Datum und Fortschritt read-only, da diese Werte aus den Aufgaben berechnet werden. Geprüft wird: Titel nicht leer, Enddatum nicht vor Startdatum (Meilensteine ausgenommen, deren Start- und Endspalte dasselbe milestone_date zeigen) und Fortschritt 0–100. Im Simulationsmodus rufen Datumsänderungen an Aufgaben simulateTaskChange() statt einer echten Speicherung auf
  • Ressourcen-Überbuchungswarnung (Issue #82): die Kapazitätsplanung war bisher reine Datenerfassung ohne Abgleich mit dem tatsächlich verplanten Aufwand. Der neue Endpunkt GET /api/v1/resources/{id}/utilization?from=&to=&group= (ResourceUtilizationService/ResourceUtilizationController) stellt den geplanten Aufwand aus den Aufgaben-Ressourcen-Zuordnungen – gleichmäßig auf die Arbeitstage der Aufgabe verteilt, über WorkCalendarService mit ressourcenspezifischen Arbeitstagen und Feiertagen – der erfassten Tageskapazität gegenüber. Mehrfach-Ressourcen-Zuordnungen (Issue #103) samt Alt-Aufgaben werden berücksichtigt, ohne gepflegte Tageskapazität gilt ein Fallback von 1 PT/Tag. Im Ressourcen-Raster färben sich die Zellen nach Auslastungsgrad (> 90 % gelb, > 100 % rot) und der Tooltip zeigt geplante Stunden gegen Kapazität samt Aufschlüsselung nach Projekt und Aufgabe; das Workload-Chart im Gantt markiert überbuchte Perioden jetzt rot. Übersetzungen für alle sechs Sprachen ergänzt
  • Nachgetragen – beide Funktionen wurden bereits mit 1.4.2 ausgeliefert, waren dort aber nicht im Changelog dokumentiert:
  • Einheitliches Statusmodell für Teilprojekte und Aufgaben (Issue #78): neues Feld status (not_started/in_progress/blocked/done) auf nc_gantt_subprojects und nc_gantt_tasks ergänzend zum numerischen Fortschritt, Bestandsdaten leitet Migration Version1030 daraus ab. Validierung per StatusValidator (Whitelist analog ColorValidator), Status-Dropdown in den Detailformularen, blockierte Balken im Gantt schraffiert und mit Warnsymbol, blocked_count je Projekt im Rollup sowie ein Badge in der Projektliste
  • Mehrere Ressourcen mit individuellem Aufwand je Aufgabe (Issue #103): bis zu vier Ressourcen je Aufgabe mit eigener Aufwandsschätzung in der Einheit der Ressource (neue Tabelle nc_gantt_task_resources, Migration Version1029, Backfill aus den vorhandenen resource_id/work-Werten). Das manuelle Work-Feld entfällt: TaskService::resolveResources() summiert die Einzel-Aufwände zur Gesamt-Work (1 PT = 8 h) und übernimmt die erste Zuordnung als primäre resource_id, die weiterhin für Arbeitskalender und CPM maßgeblich ist. Ressourcen-Filter sowie CSV-/JSON-Export und -Import berücksichtigen alle Zuordnungen statt nur der primären

Changed

  • buildFrappeRows() (src/gantt/frappeRows.js) mischte bisher Datenmodell und frappe-gantt-Formatierung: die Einrückungstiefe steckte als Leerzeichen im name, Zustände (Dimming, kritischer Pfad, Summenbalken) hingen in custom_class – eine geplante Tabellenansicht neben dem Gantt-Chart (Issue #117) hätte dieselbe Logik duplizieren müssen (Teilschritt A, Issue #118). Neue Funktion buildRowModel() (src/gantt/rowModel.js) liefert dieselbe Zeilenliste jetzt als neutrales Modell (id, type, entityId, depth, title, start, end, progress, parentId, editable, matched, critical), resolveMilestoneDate() wandert mit ins Modell. buildFrappeRows() ist nur noch ein dünner Adapter darüber, der name/custom_class/dependencies wie bisher erzeugt. Reines Refactoring ohne sichtbare Änderung, per Fixture-Vergleich gegen die alte Implementierung geprüft; neue Unit-Tests (src/gantt/rowModel.test.js, npm run test:unit, via neu eingeführtem vitest) decken Hierarchie, Einrückungstiefe, Meilenstein-Datumsauflösung und Filter-Dimming ab

Fixed

  • Abhängigkeitsfortschreibung bei Aufgaben lieferte für alle vier Abhängigkeitstypen (EA/AA/EE/AE) einen um einen Arbeitstag zu langen Nachfolger-Termin – bei EA zusätzlich mit falschem Anschlusstag, da der Nachfolger auf dem Endtag des Vorgängers statt am folgenden Arbeitstag begann und dadurch mit dem Vorgänger überlappte (Issue #114). Ursache war eine Off-by-one-Vermischung zwischen der inklusiven Arbeitstagszählung und der exklusiven Datumsfortschreibung in TaskService::applyConstraint()/computeMultiConstraint(). Betroffen sind sowohl das direkte Setzen einer Abhängigkeit als auch die Terminpropagation nach Drag & Drop und die What-if-Simulation. Verhaltensänderung: Bestehende Pläne mit EA-Abhängigkeiten verschieben sich beim nächsten Speichern/Neuberechnen um einen Arbeitstag nach vorne (auf den korrekten Anschlusstag); bei AA/EE/AE verkürzt sich der zuvor fälschlich verlängerte Nachfolger-Zeitraum um einen Arbeitstag, die ursprüngliche Dauer bleibt jetzt garantiert erhalten. Abhängige Meilensteine (Dauer 0) sind unverändert korrekt und von diesem Fix nicht betroffen

  • Security: jeder Nutzer mit Schreibrecht auf ein eigenes Projekt konnte jede in der Instanz existierende resource_id einer eigenen Aufgabe zuordnen – unabhängig vom Eigentümer und ohne jede Share-Beziehung (Cross-Tenant-IDOR, Issue #112). TaskService::resolveResources() lud die vom Client gesendeten IDs bisher nur über ResourceMapper::findByIds(), also als reine Existenzprüfung ohne Berechtigungscheck; da die IDs fortlaufende Integer sind, waren sie trivial zu erraten. Der Listen- wie der Legacy-Einzelfeld-Pfad in create()/update() filtern referenzierte IDs jetzt über ResourceMapper::findVisibleToUser(), nicht sichtbare IDs werden wie unbekannte verworfen (Liste) bzw. nicht übernommen (Einzelfeld, der bestehende Wert bleibt erhalten). Regressionstests decken beide Pfade für create() und update() ab

  • Feiertage ließen sich nicht in mehreren Regionskalendern führen: POST /admin/holidays lief in einen HTTP 500, sobald dasselbe Datum in einem zweiten Kalender angelegt wurde, weil der Unique-Index aus Version1006 allein auf holiday_date lag, obwohl Feiertage seit Version1013 über calendar_id kalenderbezogen sind. Version1031 verschiebt den Index auf (holiday_date, calendar_id); die Eindeutigkeit globaler Feiertage sichert weiterhin der Upsert in HolidayAdminController::create(). Betroffen war neben der Feiertagsverwaltung auch der Kalender-Import aus einem Projekt-Export, wo der Fehler still verschluckt wurde. Zweitens war GET /admin/holidays admin-only, während work-calendars und work-schedules lesend für alle offen sind – für normale Nutzer blieb der Store deshalb immer leer (keine Feiertage im Projekt-Export, keine Markierung arbeitsfreier Tage im Ressourcen-Raster); der Lese-Endpunkt zieht nach dem Muster der übrigen Stammdaten auf /api/v1/holidays um (NoAdminRequired), Anlegen und Löschen bleiben unter /api/v1/admin/holidays. Ergänzend werden Feiertage jetzt mit ihrem Kalender gelöscht (WorkCalendarController::destroy(), HolidayMapper::deleteByCalendar()) und Bestandswaisen bereits gelöschter Kalender in Version1031 aufgeräumt – über verweisende Ressourcen haben sie bis dahin weiter als arbeitsfreie Tage gewirkt
  • Die Installation der Tabelle nc_gantt_task_resources scheiterte auf Instanzen, deren Tabellenpräfix die von Nextcloud aus Oracle-Kompatibilität erzwungene 30-Zeichen-Grenze für Bezeichner reizt: der von Doctrine automatisch vergebene Primary-Key-Name (Tabellenname + _pkey) wird mit Präfix oc_ zu lang (Issue #132). Die Primärschlüssel-Definition bekommt – analog zu den bestehenden Migrationen für nc_gantt_resource_capacity und nc_gantt_resource_groups – einen expliziten kurzen Namen
  • Der absolut positionierte Toggle-Button der Nextcloud-App-Navigation ragte in den App-Content hinein und verdeckte dort den Titel des ersten Eintrags in der Projekt-Rollup-Leiste (Issue #134); der linke Innenabstand reserviert jetzt Platz für den Button
  • Ein leerer Balken in Höhe der Kopfzeile erschien oberhalb des App-Inhalts, weil der CSS-Reset für den Nextcloud-Content-Wrapper an main#content.app-nc_gantt gekoppelt war (Issue #126). Ändert sich das Markup zwischen Nextcloud-Versionen (Klasse oder Tag), griff der Reset nicht mehr und der von NcContent (#content-vue) selbst gesetzte margin-top: var(--header-height) addierte sich zum Rand des Cores. Der Reset hängt jetzt robust an #content mit !important, ohne Abhängigkeit vom app-spezifischen Klassennamen
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturegO8Qmtdwg8LOBKr5G+mq4co374hsqqSN6oCIRV9atUx0KqogPxisJiIExkPoSIbu
e4EeIaUzg2alhZsKBLWOwR3Ab3fNm5vvd2DzJn6Hei7A70woz9m/LXkVlcx3vALW
bwolClUX1XCZOBVo/kSS5AOVwak3/huzT1iF9xH9BnpdzVuOjZ563LYwSayfb2Gq
SkWNfLZlKlDkTTF2PIszrNmaa89GmyqTbraxSP16/9nYdIj8ZU0zrhC3HtpihgAT
wya2lwnMf6I73HU0xxgT/+ITTmurx4eHwKWH80P4tjg/Y9mnHODIpAslbW3351mc
qdTHXIBW1MB1YGCQ+JPt11v1X2ccn29kEF9d1nkizKZ1+Du+LJQhPhwHiQxPWSwAUlTlQ4tj1lbe3+FJ1jsVTCqWbDUN02EoV7ZwtN15/HLJfM6w4drUi8ThJ1aLG3v6
cIwMJjYgWeepxR2gv4YgBf4u7txodm5bAWuzySk4rfAG1dBxmie/bfNnWmQ9LrYy
spwKc73gsPhg03ll+jp0b27fJfNF4IpOysz3i+r1ExVfeNIWWO91JPatO2pXZh4O
q0rczM8wYvctvcEkKQIL67HoIrKw4GVIXfqM9Oc8e/Ay7d/NPL+BjpCO6zvoFBY+
SRmjit15YmGW4EQwweQfKXuZ2YeySj+7OjhKHpKfvfg=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.2
Release Details
UpdatedAug. 20, 2026, 4:41 a.m.
Changelog

Changed

  • release.sh fragt die Versionsnummer jetzt interaktiv ab, statt sie nur aus appinfo/info.xml zu lesen: zu Beginn werden die aktuelle Version und das letzte Release-Tag angezeigt und es wird gefragt, ob eine neue Nummer vergeben werden soll (Vorschlag: nächster Patch-Level). Die Eingabe wird auf das Format X.Y.Z, auf einen echten Versionssprung und auf ein noch nicht vergebenes Tag geprüft und dann nach appinfo/info.xml, package.json und package-lock.json geschrieben. Fehlt ein Changelog-Abschnitt zur neuen Version, warnt das Skript; anschließend bietet es an, den Bump als chore: Version X.Y.Z zu committen — nötig, weil der Tag-Name den Commit-Hash enthält. Für nicht-interaktive Läufe gibt es --version=X.Y.Z und --no-bump; ohne TTY wird nie gefragt, make release bleibt also unverändert nutzbar
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturepoVHZxteU3AR2cpRRV98jNfv4j7rWnLEd3kbpn5Dp4T1ubAI+0QlRf9jxi0BaYz1
+1dg+3Yt25uN6Slp1FHiw7kyqt5HJ60XgnOWo+Zt0YBHSnWqLDhF8zxPEnQCkF+v
nUvscpcoQY2bRiIBZhVWVgeAD592uvOA4gfRDrUyLVDKjOrzBu3ScbNvCqTqE9IC
vs8qZkRLIcaD6tKoSLT2pZqmwBoCdClvEw5D5v40WSvLq232BZnXpQ4ogG3QvJdL
mYO8HlPZKVOxANp0MGnWle4IFRMbMt22Ebpkjc18Q9Q4AIv/Sd3zTsc+uMONTM95
s0GXvLSm95o0UCFZ1CL7fCEq7NwlprjVrTeWGmlJNVjHJuIyRKHEz5DR12s0lAGm
/rKGWjoVP+Wvk3upRizR/5y2fpWoiwuDqCtz9gQN6+HHYLaqLvYqsAJ/SxmtLtP7
8B2rK61ClKowz4phbTZdrCaF8w3IWnFFBTFquIVFuN2jUoHvdCMtd0910sLAMY5M
Xs9nk0FVsP23zKXlQpOojq7ouCQagRhsnBJDLxWRR+NIq582f7SDgcrkBqxlGJX4
/Ql9V+2iFx61QANCTjdJIO3LbvbK60vGos+ency0GfvSDbPovDAVyJzt8ZUh5BNw
UXQ4XOHJZAagAr36rKttk1DQbZZ/2bUEq231c96m83g=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.1
Release Details
UpdatedAug. 17, 2026, 7:43 p.m.
Changelog

Fixed

  • Die Meilenstein-Raute hatte eine fest verdrahtete Farbe (#fbbf24) statt der Projektfarbe zu folgen, obwohl Balken für Aufgaben und Teilprojekte bereits korrekt eingefärbt wurden (Issue #102). Zusätzlich wurden die separaten – und wirkungslosen – Farbwähler bei Teilprojekt und Aufgabe entfernt, da deren Anzeige ohnehin immer der Projektfarbe folgt
  • „Meilenstein hinzufügen" im Drei-Punkte-Menü der Projektliste nutzte zwei aufeinanderfolgende window.prompt()-Dialoge (Name, dann Datum als Freitext) statt des regulären Detail-Dialogs (Issue #101). Der Klick emittiert jetzt add-milestone analog zu „Aufgabe hinzufügen" (Issue #91) und öffnet denselben Meilenstein-Dialog wie beim Bearbeiten, mit vorbelegtem Projekt
  • Im festen Datumsmodus des Aufgaben-Detaildialogs konnte ein Enddatum vor dem Startdatum eingegeben und gespeichert werden (Issue #100). Jetzt zieht ein über das Enddatum hinaus verschobenes Startdatum das Enddatum mit; ein zu frühes Enddatum erzeugt ein rotes Fehler-Icon am Feld, hält den Fokus dort und deaktiviert den Speichern-Button, bis ein gültiges Datum eingetragen ist (dateField() in fields.js mit neuer setError()-Methode)
  • Eine Aufgabe mit Abhängigkeit behielt trotzdem die manuell eingegebenen Start-/Enddatumsfelder, die beim Speichern durch die Abhängigkeitsberechnung überschrieben wurden – für Nutzer nicht nachvollziehbar (Issue #99). Der Aufgaben-Detaildialog hat jetzt denselben Fixed-date/Dependency-Umschalter wie Meilensteine (Issue #90): im Dependency-Modus ersetzt eine Dauer (Tage) die Datumsfelder, die Abhängigkeit bestimmt den Termin. Serverseitig wendet TaskService::create() neu hinzugefügte Abhängigkeiten sofort an (bisher nur update()), damit auch neu angelegte Aufgaben keinen die Abhängigkeit ignorierenden Platzhaltertermin behalten
  • Der Speichern-Button des Detail-Dialogs blieb nach dem Hinzufügen einer Abhängigkeit deaktiviert: die Gültigkeitsprüfung hing allein am input-Event, das bei einem <select> vor dem change-Event feuert – zu diesem Zeitpunkt war die Abhängigkeit noch nicht in der Liste. detailModal.js wertet jetzt zusätzlich change aus, der Abhängigkeits-Editor (fields.js) meldet jede Mutation (Hinzufügen, Entfernen, Typwechsel) und der Fixed-date/Dependency-Umschalter in taskForm.js den Moduswechsel über ein eigenes bubbelndes change-Event

Added

  • CONTRIBUTE.md und setup-dev.sh für neue Mitwirkende (Issue #98): Projekt-Leitlinien (FOSS, Datensparsamkeit, Security), VIBE Coding ausdrücklich erlaubt, sowie der komplette lokale Dev-Setup-Weg (Docker-only, Nextcloud + MariaDB unter localhost:8088, optionales E2E-Setup, Git-/Bot-Auth). setup-dev.sh automatisiert diese Schritte, konfigurierbar über --workdir/--no-e2e/--no-docker-install
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturetYcUvVtDEQrAakG32EQF1atSOmz91/8XudCUh60A9r/AxMv+AA5AX2rIvNYDkEn0
OuTmXA6Iz0DoVkdij11MPDhfLaUy0mXeLbwB5fj/xF/cFYcNeCFGKD3k2jyRwOTo
2n1sEp0r8sn0fitHzLfhcB/By0VJkZyhaO/NctP01XfcSQM7lGEOeY/uagtGaDTI
JnPLoQTHo0nUOv4y7jUMZuurEgBOc4yeUxTKv4A/m642hvNQIS0q6K9ON41JHKIO
UtI7DbDWSboVhct1Go3zoj5XcaAGG9ZiwSkJDt/BXT5tWH4SOnSn7mys0j1F6Y0g
vIJWjz6S2RlekwIrIxgyaeEVBOeQ4OM1ilJGWKXDyYJM/0IBxqnqRXDkAFlOopDo
xezlcFdWTkYL5OBKMFJhKuTy7dEQ9hxx5Nz4+vLbNV8gDJZBI+5yI5m8W+809WIH
iKUpIda1ShOblvYH6Ek5AzBdTmoFQ6T4f7iWT7j1i4uUP2DsgehjGVl8yDIT/wyx
nV9t7koXapu1WeXrunSa++mXsi3lceNpthdz5/cUEOe9yWvc1rrulRhiWzePga8H
zjVQYGAIPvwYkWa47U6Zh7HBsQaS+9yQ8NDnD49SS4jUWTGlwNqfM+q9fZ16/G9d
7l4chZUPPbBv+xWfdxmFw+MC5zdkAq27isHToTqnm+w=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.4.0
Release Details
UpdatedAug. 13, 2026, 6:41 a.m.
Changelog

Added

  • Meilensteine werden jetzt immer direkt unter ihrem übergeordneten Objekt angezeigt statt gesammelt am Projektende (Issue #90): Meilensteine lassen sich neu auch einer Aufgabe zuordnen (bisher nur Projekt/Teilprojekt, Spalte task_id war bereits vorhanden, es fehlte nur die UI), das Auswahlfeld im Detail-Dialog heißt entsprechend „Übergeordnetes Objekt" statt „Teilprojekt". Zusätzlich können Meilensteine ihr Datum jetzt statt eines fixen Werts aus einer Abhängigkeit zum übergeordneten Objekt beziehen (EA/AA/EE/AE, analog zu Aufgaben-Abhängigkeiten; neue Spalte dependency_type, Migration Version1028) – da ein Meilenstein keine Dauer hat, bestimmen EA/EE das Ende und AA/AE den Start des Zielobjekts. Die Berechnung übernimmt der neue MilestoneDateService (serverseitig live bei jedem Abruf sowie im ICS-Feed neu aufgelöst, nicht persistiert propagiert) sowie clientseitig in frappeRows.js für sofortige Reaktivität ohne Neuladen
  • Undo für Drag-&-Drop-Verschiebungen inkl. Propagationskette (Issue #85, Umsetzung der einstufigen Empfehlung: letzte eigene Operation, kein Redo, zunächst nur Drag & Drop): Migration Version1027Date20260810020000 ergänzt nc_gantt_change_events um op_id (UUID) – alle Change-Events einer zusammenhängenden Operation (Drag + gesamte Propagationskette B→C→D) erhalten dieselbe op_id, erzeugt in TaskService::update()/propagateDates() und über ChangeEventService::log() protokolliert (dieses Change-Tracking war bisher tote Scaffolding-Logik ohne Aufrufer). Neuer Endpoint POST /api/v1/changes/{opId}/revert (ChangeEventController::revert, ChangeEventService::revertOperation) wendet alle Change-Events der Operation invers an, in einer DB-Transaktion mit Rechteprüfung über AccessService::canEditOrOwn(). Konfliktschutz: Revert wird mit HTTP 409 abgelehnt, sobald der aktuelle Feldwert nicht mehr dem protokollierten new_value entspricht (jemand hat zwischenzeitlich erneut geändert); der Revert selbst erzeugt wiederum neue Change-Events, die Audit-Historie bleibt lückenlos. Frontend: nach jedem gespeicherten Drag zeigt GanttChart.vue einen Toast „N Termine verschoben — Rückgängig" (showUndo aus @nextcloud/dialogs, 10 s sichtbar) sowie ein globales Ctrl+Z für die letzte eigene Operation der Session (stores/projects.js: lastOperation, revertOperation(), undoLastOperation())
  • Kalender-Export als abonnierbarer ICS-Feed pro Projekt (Issue #83, Variante A aus dem Umsetzungsvorschlag): neue öffentliche Route GET /apps/nc_gantt/projects/{id}/calendar.ics?token=… (regulärer, unauthentifizierter CalendarFeedController, damit externe Clients wie Thunderbird, Nextcloud Kalender oder mobile Apps ohne Nextcloud-Login abonnieren können) liefert Meilensteine als ganztägige VEVENTs (◆-Präfix), den aus den Aufgaben abgeleiteten Projektzeitraum sowie optional Teilprojekt-Zeiträume (Schalter „Auch Teilprojekt-Zeiträume einschließen", standardmäßig aus, um den Feed bei großen Projekten nicht zu überladen). Zugriff erfolgt über einen pro Projekt generierten, 256-Bit-zufälligen Token in der URL (CalendarFeedService, neue Spalte calendar_token auf nc_gantt_projects, Migration Version1026), der über einen neuen „Kalender-Feed"-Bereich im Freigabe-Dialog angezeigt, kopiert und jederzeit widerrufen/neu generiert werden kann (CalendarTokenController, nur für Projekt-Admins/-Eigentümer). ICS-Generierung ohne neue Abhängigkeit, RFC-5545-konform (Escaping, Zeilenfaltung)
  • What-if-Simulationsmodus für Terminverschiebungen (Issue #84): neuer Endpunkt POST /api/v1/projects/{id}/simulate führt Terminpropagation und CPM rein im Speicher aus (kein DB-Schreibzugriff) – TaskService::simulate() nutzt die neu extrahierte, stateless propagateDatesCore()-Kernlogik, die auch der persistierende update()-Pfad verwendet, CriticalPathService::computeFromTasks() erlaubt CPM auf einem hypothetisch veränderten Task-Datensatz. Frontend: „Simulation"-Toggle in der Gantt-Toolbar mit Banner inkl. Projektende-Delta in Arbeitstagen, Geisterbalken für die Ist-Termine (analog Baseline-Overlay) sowie Verwerfen/Übernehmen. Drag & Drop ruft im Simulationsmodus simulate() statt einer echten Speicherung auf. Szenarien bleiben bewusst flüchtig (kein Speichern benannter Szenarien), „Übernehmen" wendet die Änderungen als einzelne Task-Updates an, Simulation läuft pro Projekt
  • Neuer Eintrag „Aufgabe hinzufügen" im Drei-Punkte-Menü der Projektliste (Issue #91): legt wie der „Neu"-Button eine Aufgabe an, belegt dabei aber das gewählte Projekt direkt vor, sodass der Projekt-Auswahlschritt in der Maske entfällt
  • Such-/Filterleiste für Projekte, Teilprojekte und Aufgaben (Issue #81, Stufe 1: rein clientseitig auf Basis der bereits geladenen Daten aktivierter Projekte): Freitextsuche im Titel, Risiko, „überfällig" (Ende < heute und Fortschritt < 100 %), „über Budget" (Ist-Kosten > geplantes Budget), Ressource und „ohne Deck-Verknüpfung". Neuer Pinia-Store stores/filters.js (Zustand pro Nutzer in localStorage persistiert) und reine Matching-Logik in gantt/filterMatch.js. Nicht passende Balken werden in GanttChart.vue gedimmt statt ausgeblendet (Abhängigkeitspfeile und Zeitkontext bleiben lesbar), Projekte/Teilprojekte gelten als Treffer, sobald ein Nachfahre passt. Dieselbe Filterleiste (components/FilterBar.vue) dimmt in ProjectList.vue nicht passende Projekte; für nicht aktivierte Projekte sind nur Titel-Treffer zuverlässig auswertbar, da deren Aufgaben/Teilprojekte nicht geladen sind

Changed

  • Freigabe für Nextcloud 34 (Issue #94): max-version in appinfo/info.xml von 33 auf 34 angehoben, unterstützter Bereich damit NC 28–34. Verifiziert gegen Nextcloud 34.0.2 mit PHP 8.5 und MariaDB 11.4 (148 Unit-Tests, 39 E2E-Tests)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignaturerdYQI+Semnk0cWtKqUZinVDHk0KpxyqB5Ox4NBL9pyf5nrpK8xZpe9lBxc6zhDfW
8adLfVIwQtX+bI7S1O05xm0hwrUHQQ2ii6ADD8mlAxnZjdhKSCAhZ0NcaqT7Em0X
nD7yRP2B8zAAQMJNjzeBsLbzveNrXMoGzFrvm/jFxskUIUS01ykfWEg2C5+5/IAf
7jBAM8x2Qj92b8zyBFpLjfJQw9aTE/trtCsmZXQFmkJjGS0anrJc9dXKfqnHxknX
8jmLOv4Yq4Qtk3UF35HTiIGcA2W0UKfVyFb4XcrIMeSmLXXcagJWjeH5nB18UUNn
JyCgE/qY4v/SnrNQU92mIdMOQGuvYg7xbaz226lgNdwM2HuM9U8nc2juqJxAO+Wp
xs85yl82qIviZ5YY39HK371MZ/ufMsaVsVy3Nfn3PjqqkzGLmtAL6KJDcKHZWdDw
ugEPwO61DxnERZsNGeFpXfzCxjMpZc/qwUIfGw85idmU2vdedtrxHBkDGoqu1IP7
xZOO8uSYrzbXM6g1gs3WPBOY51CmZLs5pIQTN1tVl5ifGw4uOuzDBUCKiR5oA2MI
352HbA7wwWFgwoN9W5t4MRTowmaYpM8AB+nh9f1A5q9S8SelfMpXOqGew9VZb2jd
AuiJK/LEPjRgs5s3/FfC4Sb1MSsXDr1N1jziaF4MomM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<35.0.0
Minimum Integer bits32
Gantt Projects 1.3.1
Release Details
UpdatedAug. 6, 2026, 12:57 p.m.
Changelog

Added

  • Regressionstests für die Rollentrennung Viewer/Editor/Admin: ForbiddenException-Tests für TaskService::create/update/delete/syncProgress und ProjectService::updateProject/deleteProject (inkl. „Editor darf nicht löschen") sowie erstmalige Testabdeckung für SubProjectService und MilestoneService

Fixed

  • CSV-/Formel-Injection im Aufgaben-Export (detail/io.js exportCsv): Task-Felder wie Titel oder Beschreibung, die mit =, +, - oder @ beginnen, wurden unverändert übernommen und von Excel/LibreOffice/Google Sheets als Formel ausgewertet. Die Absicherung aus ReportView.vue liegt jetzt in einer gemeinsamen Utility (src/utils/csv.js, escCsvCell) und wird an beiden Export-Stellen verwendet
  • Viewer sahen im Frontend dieselbe Oberfläche wie Editor/Admin (Add Task/Subproject/Milestone, Share, Delete Project, Drag/Resize im Gantt-Chart, volle Bearbeitungsformulare), obwohl das Backend Schreibversuche ohnehin korrekt ablehnte – kein Least-Privilege an der UI. ProjectService::getAccessibleProjects()/getProject()/createProject()/updateProject() liefern jetzt das effektive permission-Feld (AccessService::getEffectivePermission()) mit; ProjectList.vue, GanttChart.vue (inkl. Drag/Resize-Sperre je Projekt) und das Detail-Modal (detail/detailModal.js) blenden Schreib-Aktionen für Viewer aus bzw. schalten Formulare read-only
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureBUyDeI9y7iKD1wQJLHrW6IFq0zuXOJQ1Zv/x+0RryIIQ0fAGAUjwQyLDYLYpRzPg
6ITDPfY9bftVlwkB8w9LqZiFETkH8mgc6l5XB7F6NKzFrdaSnNw21CIVJjWyHpkR
mxDq+vQepZd+YtB9jMz39kbFk9BNHrpKIwIXXZVqEqj1U54NmT+5XnT892m9mY6o
RWQNf3Mn5WcH3vmoDi/UAOgDaO30GFCRJePryurVpK7stkub8K6fYsWIkS5NeJlP
YHdb4nBlkhUzQFjo0ZDSkCSiWjMdyCrtEanX6m6Ffhr+j0jpd+J9soMSjrzdzt4T
5mETo8xc61IQIVFWMD6fZ3/oCmbx2TFDZsJjRpFKxoPA08AkdC7xjxHoaKYZHvi4
+tzowxPzMfyjQ/hEj2dwq22doM2lXK1Y13VvV8kkaomrAQjB97gf+ODrYZNDgNvc
2ijU08B4cAB0HbEveDpDRjCJj8D5OwCMafRMa4Ul/nm0+RiBFOhIjDYdVAnCp7Ql
IEc4UQZM9WYLQlouwGPk83POpbqkbc8vKAucGBXvHAbxNpUSOGbssMYFGU/e9pOg
+oT2gcJrC3MYPGIWnS8iLn75PK1H063KFJv5yqC+h/rqwX/FxyTzKvofJi68GpLs
WtG3y67W8Ju4y1I9iQ9raJxxhFUJrStibGy9gc7L0DM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.3.0
Release Details
UpdatedJuly 9, 2026, 5:23 a.m.
Changelog

Fixed

  • Baseline-Toggle im Gantt-Toolbar zeigte nie Baseline-Balken und PUT baseline/active warf einen SQL-Fehler: baseline_id auf nc_gantt_projects wurde mit der 3-Ebenen-Migration versehentlich zusammen mit den tatsächlich berechneten Spalten entfernt (Migration Version1025 stellt die Spalte wieder her). BaselineService::create() aktiviert eine frisch eingefrorene Baseline jetzt automatisch fürs Projekt; renderBaselineBars() (GanttChart.vue) und baselineOverlay.js lesen Baseline-Items dafür über task_id statt des seit der Umstellung auf das 3-Ebenen-Modell nicht mehr existierenden subproject_id-Felds
  • OCS-API-Fehlerantworten (400/404/500 …) lieferten für alle OCSController-Endpunkte einen leeren text/html-Body statt des erwarteten JSON-Envelopes mit message; ExceptionMiddleware wirft jetzt passende OCP\AppFramework\OCS\OCSException-Subklassen statt einer rohen DataResponse, die Nextcloud-Core nur für 401/403 automatisch formatiert. Betroffene Controller (ProjectController, ReportController, ShareController, ChangeEventController, WorkScheduleController, WorkCalendarController, HolidayAdminController, SettingsController) wurden zusätzlich auf die bestehende ApiException-Hierarchie umgestellt

Removed

  • Nie ausgewertete Gruppen-Freigabe-Option entfernt: Share::TYPE_GROUP, principal_type-Parameter in ShareController sowie die DB-Spalte principal_type (Migration Version1024) wurden gestrichen; Freigaben sind jetzt ausschließlich benutzerbezogen

Changed

  • Dashboard-Summary (DashboardController::summary) lädt Baselines und Aufgaben-KPIs jetzt über gruppierte SQL-Aggregat-Queries statt pro Projekt einzeln (N+1-Fix, gilt auch für den Admin-Fall mit allen Instanz-Projekten)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureNJfbRJEXzKGipUjUW9tUKayHoY6ltSU0ZeCQXcDx6XVDY/naLK0dVY9ciofXU7oy
40sJIOsjxcUZbalDwqncPn0vjGoqmk3BFUT7KotEpLLf8/ZmIjdHEbQbJHzEpdQV
y5YedjqRLKB7/Ul35JWVFxY8eutCsYkonfof7v6AGMGB/RjQ7GDB6jWunEEwqUGV
3Y1isvdq5N3oo9NDY/QR0C2C7jiMnB9Kon0KzZ2yp0oF5euOpA/qrtmqxG3L9PoZ
DW1ppwAuARWtRDu4tcDAAQAkF1Mrg5YyYgRoKm7uVazlKEP7DxX56g/g4RS2otEE
rKsA/ER9yYiHnNyGcZuK9Jkfe2Ua6/R7gzJilRvHZ7CBPkhY+XNPcrjlsHbCJEJJ
cX/b0B56p7FyAFy6XjMY9PYFhxy/ubHE7Sk8ixX88uxgM4vf/sSFQaN84CcG/qqA
Nq/OEytBjZP82TsFFYBRcPKEPskF4ejjhNVC4bJpiuCIpo51nIxjeFGtDpeQiDG7
0OWc/GCvsz5W3eG7ShmQsRf0DoivL8tjgDUlMWO9boTpUy2Vnm1rDMKu6nFGKZ8o
TWTZR6u4zGZW1OBERdlU5NQmqxqXrsuGlT6r6DuQnWsWiscjXOyIFeHz+EOKhQOk
wUuN6xN8QES1CDFB27PYV0Sz2KhYhM78GKLCc9B10Ic=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.2.0
Release Details
UpdatedJuly 5, 2026, 9:21 a.m.
Changelog

Added

  • Löschen-Buttons im Detail-Modal für Teilprojekt, Aufgabe und Meilenstein
  • Deutsche App-Beschreibung in info.xml ergänzt

Fixed

  • Baseline-Datum und Kommentar im Report werden untereinander angezeigt
  • Dashboard-Widget zeigt Baseline-Datum und KPI-Werte korrekt an
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureXuYTZMxTlGNJVrGvU/GcIjSlBTYreXdvF5FilCmsi+l7MBvFlyeW1DsnxAsao3pu
HyhvaKXRnkraVQNT2ULgX4BmjUnhsELROrK03gtY88Odzqzh7RIXYkNkRcy92ara
56HIP8BBRD3m1c8pYPfpZfLAzkuurAzVqbJ6qbxw1AebdlPCFEq2g6C+IOcTon0T
q9ZD2I2XJmWd42EXXqva+NMrcx1jfjmHWVtl7xHKhwPndFCtHPMMAdoDS0Xpbh1V
3Ns4h/DphDpC8/ZYZ5sbpMCBekHw4VTZDGxNAuXJ5DMPhkqg2MxVplkS19PuBHLx
r74sgsz611Gjg55gjKOqCb5ZZEvqZTrwKTEYIbu8HicWtq/HxKRZS3FZN9MThTTX
Hesv65vsq9fH0UhEM6MVJjE5Phnw8Wb5ivtAiaUA+NzPrDfrHZAsSfR9NFL3rhFC
7wOmnXtzK40NjmqyMWJu/UP9UVbz3SeEiHiQO9GwBc2krzmXzcmLZFgEjty4CGoJ
SzXAA1QGpUGO4n0b3Y/5zSY4UxogGWybW+mOs27KDLytI915wNYGvBtcdAKCj6Ws
1uVA98npwMid/WSJJ04BXHX8LbowrDeTezSFJyGh+u/KnhlzkA7fqEuu3nQGT5rA
a9qeMmd5kmLBIVcG9RVVmw1kc0AK0qIqZDmlk9dWGJs=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.1.1
Release Details
UpdatedMay 27, 2026, 6:43 p.m.
Changelog

Added

  • Glossar-Button in der Navigation (über den Einstellungen) mit interaktivem Nachschlagewerk
  • Dreispaltige Glossar-Tabelle: Begriff/Abkürzung, Bedeutung/Englisch, Erklärung mit Berechnungsformeln
  • 30 Einträge in 6 Abschnitten: Allgemein, Terminplanung, Baseline & Berichtswesen, Earned Value Management, Ressourcen & Kapazität, Budget

Fixed

  • Fehlende deutsche Übersetzungen für englische UI-Strings ergänzt (Add dependency, Baseline, Dependencies, Remove, Work, No projects yet, Open Gantt Projects, u.a.)
  • Leere Übersetzung für Deck-Fortschritt-Hinweis befüllt
  • de.js vollständig mit de.json synchronisiert (war ~70 Einträge veraltet)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureF1RHJx15J/N8tWNrDlAX1MFE/9tsct4PViEcBDeo8U/V2qJ/tezL7Xk0BVmYxjWw
pB+J685mcHjikh93/aZUqG8C6y0mR3TTJfaa7dLCIRMc1034x6Xj9Nd7Q9YVH4yi
RLTcRhrG2pN1Iqc23kwId995GJXHnCBEyuQuzo9m1VtA7GoFa8W2nqhXVT94khDS
8ZHQrixDfv63d4GfA5N2x4+phaiyObdskvCmVSuKrmouYvCGpPevtKG5YxzOrHid
aL48Kod0YgOCAD8nAqOhEmioP0m+wP2e/NC4Z5svSKT3vdlE67W1M68ipQQfnhPI
txui+2X8zFvoe/M5sE3DaXbLnOVNGQ7YRpyXFI5GsQmQ0cPSSO/94Mw15hLZfwMf
TDOrrvzf+Vu05sUTZ6CFh4FrSl4e5Q6Xjv6uH4BZtyOpPxl+ajgW4OkZvQDbt4KC
8aTZodMcDpXlRMDdBSxT1bT9tD05KUKmEZYtpxHiARrHDuQQCRSuxtjitQD9lbla
CMxKrBiO0YgdUb3FuczYkWEH+y8gW5egU6TDMnjAVbuUecGuGZN1Cc6tarcFWRu2
+V7Qn+aNoXEwP5e/0TM4Ig8ETAYseZRiTPHxeWiSg3RnU3HuT6kPVWw8LERACDT4
6F4WU9t2+4kESMLMjeV0/2UBQSykR/42Idsg0PtvpyQ=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32
Gantt Projects 1.1.1 (nightly)
Release Details
UpdatedMay 27, 2026, 5:24 p.m.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhNMMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYwNTI3MTAzNzU4WhcNMzYwOTAxMTAzNzU4WjATMREwDwYD
VQQDDAhuY19nYW50dDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMm9
oP6vDlGpTxTBBnAJjbz2Sv0wAf5dyLr73SLX2nXmidKACWjAkuq7CiU9qHfJaxJC
n5gXVjhV4QQKUTaK2Y5bOPGf9VBLwX9zDC1gwlVHFlG7HA+tlXZyL96Zw/qB1ghe
Ykk95n4Ahx7FNHvZwHbAqhoxejWQIo6mwJna9I+x3gyUsURfmaNKo0ZHckMP2fpj
4HKAwSTbzWqytYgbV8efQP6mAF6JWoBOIyi0Y/Z/zd2YIJ6ZVal0UmxpfTexSgfN
ZPoJWYLQGjqFxAZWLad4XTsJ3kHC4uSJf4LPE3Fde/B+/a15/Xi1uhkIzG38+I0L
EcOsobkGkgiVU8BFe5NF39Ld8oKTpV+DNaWTAXSzC+qxhM4O15etll/cN8hP1rSb
nxppA6diiiZ1D788feYvnU0bFMDjG1AxAtiO7su0m+VrqqQcKd/9oyNouZXAG0VH
LAsTL2kp78EW9yD3UxdgJ8C1j5XEApOAiILt4j0rsRK40u7AGVGD6zwKVPUoOMKZ
kdiKOHIU31AdMJj3K9ovgXk9ecIOaU+r2UHmP5mH7d7M8pHLwp5elj4rmgx+He69
2ShNAt0FECTm3yiay30qDuT2IIvRxVrn0qHUE8OWRgtzJnV0WXe2GMvASN86JQM9
DGhtam1lDw+X44c7LEFawVN/AUesvxv1BrbEezjLAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAGXZO3ifTRL+r9p3iZ8AmTlcdjfYeZLQT/VDio5Zo1fbu1vQRuVXZ4YJ
ye9PFBwLjCXU/Wr2bXdFoMi/L1+o/kZmfEiLmEv7GA6GP88OhozJeNx/+6myhUX6
0oLbVDJresaO8dguSwc1BkQ1TPO5P2Pihtg6Jz+SE1IG4fhoMCrKwMdmzySZkqeL
XTgBLp6GTaGGd8Z5jXZvvBTEDwRaVeNMte3UmR2ON2B4zsR8eVD+PAoDobM+HR7q
x9N8zOlBqkdJUcS/KodgNfXH0o/ZOgqzhHIbD5XnnQpMT1yG0qM98PtelqDURCi9
qzfIPzlCodnTkS/VWiq16iR9q4kwjRg=
-----END CERTIFICATE-----
SignatureF4W7QJB8rVJ2xARdnhUbEouzRZMKcowz/ToDwr0oVFrVUbInFvHAMqXFTOVD1a5N
kDTb0pOhv+hCStTh70bN+aapjbdtp7SdQ3SbP5VoXBKLhUii41OqN/i4yM7itdSs
M8d5PVo9TJYVnfaij2xwWghMqZEyzxgOw4Q98dYIysf2BxsjjCtxGEMo/pISS90G
OE2RaVEFbwUcvu1XKszLP5X/k/onOchengURYVuzHP7VgVuomZpPSZ9VEIRKITyL
GpgSDrdqm5AXdQc7l/2OqprW6G+MxsuVzChbyPGslIYYXYsP9HLc/FfwVxaCJjh2
Nsiqfd+dMwnf7f9yrrBuZjbNwNa5x++IynrwaU01jVISkl9pgkbUYRaPSMTGFDAd
lsEEqlgs9KdzGoTFjDXNdTwDOsUMiu/ag8tPo7YxsxLFbVGa7laRAUhlGUT9QGPr
IOAAWvKqivsYnU5iwTCY/5HGza3SDfZc/e5upPfB+lTQTYijp1aAYRBAsoOLmuga
f0aP45pnfnYBJkT1kMsthjbGMdlL46wLiNHKRct9OlFwx74IRIyZdcs5Q3pC0aNN
DSLvsCSmY8/9PtTLzcOJKXTqqDVupCqq82bUlGRn7NR6xsinzv74MuOVnGY21tBm
iB5ceYpgiEukUz6YtS2quIIiMTnYmM+HBFnkXgBV0/Y=
Signature digestsha512
Dependencies
Required Nextcloud versions >=28.0.0,<34.0.0
Minimum Integer bits32