v0.2.0
7
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
131ef2e938 |
Surface dead filters, and name board and stacks in the moved-card mail
Build package / package (push) Successful in 55s
Build package / php-lint (8.2) (push) Successful in 41s
Build package / php-lint (8.3) (push) Successful in 34s
Build package / php-lint (8.4) (push) Successful in 40s
Build package / xml-lint (push) Successful in 11s
Build package / unit-tests (push) Successful in 42s
A filter whose entries have all been deleted from the board was the one failure mode of this app that was completely invisible: the workflow kept running, kept updating last_run and matched nothing, forever. It happens with deleted labels and just as easily when a filtered user loses board access, because Deck's BoardService::deleteAcl() calls assignedUsersMapper->deleteByParticipantOnBoard() and wipes that user's card assignments. Two low-stakes signals, no new column and no migration: - WorkflowRunner::warnAboutDeadFilters() logs a warning on every run. - workflowIssues in PersonalSettings.vue marks the row red. Deliberately no mail and no `enabled = false`. One deleted label out of three is harmless, and even a fully dead filter can be one board edit away from being live again. Both obey the rule the disable path already follows: only positive knowledge. DeckIntegrationService::findFilterOptions() therefore throws instead of degrading to [], unlike listLabels()/listParticipants(), where an empty list only means an empty dropdown. That also fixes an existing false positive of the same family: loadStacksFor() stored [] when the request failed, so a single failed fetch reported "Quell-Stapel und Ziel-Stapel nicht mehr vorhanden" for an untouched board. Failed requests now store null and are read as "unknown". The comparison itself lives in WorkflowRunner::findDeadFilters(), static and side-effect free like cardMatchesFilters(), with unit tests -- notably that an empty filter is never dead, which would otherwise flag every unfiltered workflow. Separately, the moved-card mail now names the board and both stacks. DeckIntegrationService::describeTargets() resolves the titles at most once per workflow run, and only when a card actually moved and the workflow wants a mail; unreadable titles degrade to #<id> rather than costing the user their notification. |
||
|
|
0eff367268 |
Handle workflows whose board or stack was deleted
Build package / php-lint (8.2) (push) Successful in 49s
Build package / php-lint (8.3) (push) Successful in 45s
Build package / php-lint (8.4) (push) Successful in 44s
Build package / xml-lint (push) Successful in 13s
Build package / unit-tests (push) Successful in 45s
Build package / package (push) Successful in 1m3s
Deleting a board or stack left the workflow row pointing at nothing: Deck keeps the orphaned cards readable until its DeleteCron purges them, so the run kept failing on the move every few minutes, silently and forever. - The controller now rejects boards and stacks that do not exist (or are not the user's) on create and update, so no new broken row can be stored. - The settings list marks affected workflows in red instead of showing a row that looks healthy. - The background job disables such a workflow and mails its owner once. The mail ignores the notifyEmail flag: that one is about moved cards, this is a notice that the automation stopped. It stays a one-off because a disabled workflow is no longer picked up. The check deliberately goes through StackService::findAll() rather than BoardService::getUserBoards(): Deck injects the current user into BoardService as a string frozen at construction, so in the job -- one process, many users, a cached BoardService -- it would answer for the wrong user or for none, and every workflow on the instance would have been disabled. findStackIds() returns null only for a genuinely missing or forbidden board and throws for anything else, so a Deck outage skips the workflow instead of killing it. |
||
|
|
01fdd51b5a |
Keep the stored stacks and filters when editing a workflow
Build package / php-lint (8.2) (push) Successful in 43s
Build package / php-lint (8.3) (push) Successful in 40s
Build package / php-lint (8.4) (push) Successful in 39s
Build package / xml-lint (push) Successful in 11s
Build package / unit-tests (push) Successful in 37s
Build package / package (push) Successful in 58s
editWorkflow() filled the form and then called onBoardChange() to populate the dependent dropdowns -- but that function exists to *reset* them, so it immediately nulled sourceStackId, targetStackId and both filter lists again. The board stayed selected because it is not one of the fields it clears. Split the two responsibilities: loadBoardOptions() only fetches the stack/label/user lists, onBoardChange() clears the dependent selection and then delegates to it. Editing now calls loadBoardOptions() directly. onBoardChange() additionally ignores re-picking the board that is already loaded, so selecting the same entry again no longer wipes the form. |
||
|
|
13903f8137 |
Hide inactive boards, keep source and target stack apart, make the interval configurable
Build package / php-lint (8.2) (push) Successful in 46s
Build package / php-lint (8.3) (push) Successful in 40s
Build package / php-lint (8.4) (push) Successful in 35s
Build package / xml-lint (push) Successful in 13s
Build package / unit-tests (push) Successful in 46s
Build package / package (push) Successful in 1m3s
- Boards: BoardService::getUserBoards() defaults to $includeArchived = true,
and that flag also gates the `deleted_at = 0` condition, so archived and
trashed boards showed up in the dropdown. Request the filtered query
instead, with a fallback to the no-arg call if the signature ever changes.
Stacks need nothing: StackMapper::findAll() always filters deleted_at.
- Each stack dropdown now hides whatever the other one holds, so source and
target can no longer be set to the same stack. The save-time check stays
as the backstop for rows stored before this rule.
- RunWorkflowsJob reads its interval from config.php
('workflow_deck_automation.interval', seconds, default 300, clamped to a
60s minimum). TimedJob re-reads the interval on every cron pass, so a
changed value takes effect without any occ command.
|
||
|
|
85b42d84c9 |
Fix unusable personal settings form: v8 Vue idioms and Deck relations
Build package / package (push) Successful in 50s
Lint info.xml / xml-lint (push) Successful in 20s
Lint PHP / php-lint (8.2) (push) Successful in 58s
Lint PHP / php-lint (8.3) (push) Successful in 57s
Lint PHP / php-lint (8.4) (push) Successful in 55s
PHPUnit / unit-tests (push) Successful in 1m7s
The settings page rendered, but nothing in it worked: - All NcSelect dropdowns showed "undefined" for every option. In @nextcloud/vue 9 the `label` prop is vue-select's option display *key*, not a caption, so `label="Board"` read `option.Board`. Use `input-label`. - Saving always failed with "Bitte einen Titel angeben". Vue 3 dropped `.sync`; NcTextField and NcCheckboxRadioSwitch bind via `modelValue`, so `:value.sync` / `:checked.sync` never wrote back. Use `v-model`. - NcButton's style prop is now `variant`, `type` is the native button type and `native-type` is gone. `type="tertiary"` rendered `<button type="tertiary">`, which HTML falls back to `submit` for, making the cancel button submit the form. - The user dropdown was always empty. Deck's RelationalEntity replaces resolved relations with a RelationalObject once an entity is enriched, so `$acl->getParticipant()` returns that wrapper and the uid lives in `getPrimaryKey()` -- probing for `getUID()` yielded null. This also broke the background job's assigned-user filter, which shares the extractor. - A board's ACL never contains its owner (a private board has an empty ACL), so participants are now seeded with the owner, group ACL entries are expanded via IGroupManager and display names resolved via IUserManager. - One board appeared twice: getUserBoards() merges own/group/circle boards and includes archived and trashed ones. Deduplicate by id and drop those. Also keep one failing lookup in onBoardChange from taking the other two dropdowns down with it, and document all of the above in CLAUDE.md. |
||
|
|
d5ce1b3017 |
Fix @nextcloud/vue component imports for v9 exports map
Lint info.xml / xml-lint (push) Successful in 22s
Lint PHP / php-lint (8.2) (push) Successful in 52s
Lint PHP / php-lint (8.4) (push) Successful in 1m1s
PHPUnit / unit-tests (push) Successful in 42s
Build release artifact / package (push) Failing after 1m46s
Lint PHP / php-lint (8.3) (push) Successful in 45s
v9 restricts subpath imports via package.json "exports" to @nextcloud/vue/components/Xxx; the old dist/Components/Xxx.js deep import path used throughout PersonalSettings.vue is no longer resolvable under Node's ESM export map and failed the build. |
||
|
|
300acde27e |
Add Deck workflow automation Nextcloud app
Ports the standalone due-date cron script into a proper Nextcloud 34 app with a personal-settings UI, per-user workflow configuration (source/target stack, assigned-user and label filters, email notification), a TimedJob background runner, and Gitea CI pipelines. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |