A number of webapp / CI / docs fixes - #1254
Merged
Merged
Conversation
peterthomassen
marked this pull request as ready for review
September 1, 2026 19:51
peterthomassen
force-pushed
the
20260901_misc
branch
from
September 2, 2026 20:37
329776b to
eda551c
Compare
The /auth/account/ endpoint requires the perm_manage_tokens permission for both GET and PATCH, which was not documented anywhere.
Django's duration parser only accepts hours when both minutes and seconds follow, so "5:30" is 5 minutes 30 seconds, not 5 hours 30 seconds. The notation is thus [DD] [[HH:]MM:]ss, not [DD] [HH:[MM:]]ss. Fix it in the API docs and in the web UI form hint, which also gains an example.
The Content column was capped at 45vw by CSS targeting the Vuetify 2 data table markup (.theme--light.v-data-table > .v-data-table__wrapper). Those selectors match nothing in Vuetify 3, so the cell grew to the width of the hidden mirror element that RecordItem uses to size its inputs, pushing TTL, Last touched and Actions out of view for long values such as DKIM keys. Cap the column with the data table's own maxWidth instead, which restores scrolling inside the cell, and drop the remaining dead Vuetify 2 rules. Fixes #1216
The rules used ::v-deep in an unscoped style block, where it ships as an invalid selector, so none of them applied. Anchor them on the .crud-item row class that the data table puts on every item row, restoring top-aligned cells, the green flash after saving, the highlighted save button on dirty rows and the white background of focused inputs in the domain and token lists. Also drop the rules for .text-disabled, a class no longer applied anywhere, and the copies of these rules in CrudListRecord.
Track the rows to highlight in component state and let itemClass emit the successFade class, so the highlight survives the re-render that follows a save, and start it once the server has confirmed the update. Highlight rows on hover in all lists, not just where rows are clickable.
App.vue gives every field a white background, which put white boxes into colored table rows. Make the fields transparent inside table rows, so the dirty and error colorings, the hover tint and the save flash cover the row evenly.
Home and End place the caret with setSelectionRange, which does not scroll the cell that record values are scrolled in, so in a record with a single long value, such as a DKIM key, the caret ends up outside the visible area. Measure the text before the caret and scroll the cell accordingly, which also covers the other places that set the caret, such as deleting across a field boundary. The measuring mirror takes its font from the input, including the letter spacing that Vuetify sets there, and is absolutely positioned so that it shrinks to its text; the sizing mirror takes the same font, as it otherwise makes the field too narrow for its text, which then scrolls its own content beyond the reach of the cell's scroll position.
Picking a domain type validates the domain field, and a type is picked when the page opens, so the field showed its error message before anything could be entered. Reset the validation instead while the field is empty. Fixes #1204
Put the captcha and its buttons at the right end of the form row, so that they line up with the right border of the input fields, and lay the buttons out across the captcha's width in a compact size. The solution field is centered next to the block and takes the width the captcha leaves, which is more in image mode than in audio mode.
nils-wisiol
approved these changes
Sep 4, 2026
Autofocus the first digit, so that the code can be typed as soon as the dialog opens. In the 2FA dialog, this applies when the account has a single TOTP token, which is preselected. With several tokens, focus stays on the dialog, where the token is picked first.
Dependabot never grouped the api pip updates: the `pip-api` group used `update-types`, which dependabot-core only evaluates when it knows the dependency's current version. For a plain requirements.txt that is the case only for `==` pins, so every `~=` requirement failed the check and got its own PR. Use `patterns: "*"` instead, and split the group by dependency type. For pip, dependabot derives the type from the file name (anything containing "dev" is a development dependency), so move the two test-only packages to requirements-dev.txt. Django and Django REST framework are excluded from the production group so that their updates keep coming as separate PRs.
The npm ecosystem was dropped from the dependabot configuration in 9c67472, leaving www/webapp unwatched. Track it again, at a monthly interval, with updates collated into one group PR for runtime dependencies and one for development dependencies. The `sass` ignore from 8a6bb2c is dropped: it was added because sass warned about the then-current Vue 2 era vuetify, which no longer applies. The `eslint` ignore stays, as eslint 9 requires migrating .eslintrc.cjs to flat config first.
eslint 8 is out of support since October 2024, but dependabot was told to ignore it in a75ced2 because eslint 9 has breaking changes and the plugins were not compatible at the time. The plugins are ready now (eslint-plugin-vue, -import, -vuetify and -vue-scoped-css all declare eslint 9 support and ship flat configs), so the config format was the only thing left. Translate .eslintrc.cjs to eslint.config.js, and take the opportunity to lint against the Vue 3 rule sets. The eslintrc `extends` referred to `plugin:vue/essential` and `plugin:vue-scoped-css/recommended`, which are the Vue 2 variants (58 and 4 rules) even though the webapp has been on Vue 3 for a while; the flat config uses `flat/essential` and `flat/recommended` instead (82 and 9 rules). The three "Preparation for vue3" rule overrides and the deep combinator override are dropped, as the Vue 3 sets enable all four as errors. eslint-plugin-vue is bumped to ^10 because eslint-plugin-vuetify depends on ^10.8 and registers it under the `vue` plugin key; with our ^9 the two copies collide as "Cannot redefine plugin". @eslint/js and globals become direct dependencies, as flat config imports them. `--ignore-path .gitignore` is gone in eslint 9, so the ignores move into the config, and the lint globs lose the `json` extension: the only JSON file under src/ sits in the ignored vendored module directory. Two code changes fall out of the stricter setup. eslint 9 flipped the `no-unused-vars` `caughtErrors` default from "none" to "all", which surfaces two unused catch bindings; both catch blocks ignore the error, so they lose the binding. And the Vue 3 scoped-css rules reject the argument-less `::v-deep` in CrudListRecord.vue, which becomes `:deep(...)` and compiles to the same `[data-v-*] <selector>` output. Verified with node 24: `npm run lint` covers 73 files without findings, `npm test` and `npm run build` pass.
`npm run lint` was not run anywhere in CI, so nothing caught the broken lint invocation fixed in b23ee08, and nothing guards the eslint flat config now. Run it in the test-webapp job, which already has the dependencies installed.
Vuetify styles alerts with `flex: 1 1 0`, which makes an alert that sits directly inside a card a shrinkable flex item. Once a dialog wants more height than the viewport offers, the flex algorithm takes it out of the alert, laying it out shorter than its own content: in the domain creation confirmation, the success message's 16px padding drops to 6px on a narrow window, and in a short window the text is clipped by the bottom edge. DomainSetupDialog, TOTPVerifyDialog and MFA put alerts directly inside the card and are affected; the CrudList dialogs wrap theirs in a v-form, whose children are not flex items.
Vuetify teleports overlays into a .v-overlay-container that it appends next to .v-application rather than inside it, so rules written as `.v-application p` stop at the dialog boundary: paragraphs in dialogs lose their bottom margin and run together, and `.text-primary` falls back to vuetify's amber instead of ours. Name both containers, as the vuetify 3 migration in f8dd7bb already did for links. With the list rules reaching into dialogs, the scoped rule for the DNSSEC list is redundant and goes: its padding-left now comes from the app-wide rule in both contexts, and list-style-position: outside was always the initial value.
`limit_domains` started out as 0 and was replaced only once the request to auth/account/ came back, so until then -- or forever, if that request failed -- the create dialog said "You have 0 of 0 domains left", disabled the Save button and warned that the maximum number of domains had been reached. A user with one of one domain used reported exactly this. null is already the component's value for "no limit applies", so starting there costs the quota hint instead of locking the user out of domain creation, and the server still enforces the actual limit.
Align the domain list with desecapi.permissions.WithinDomainLimit.
peterthomassen
force-pushed
the
20260901_misc
branch
2 times, most recently
from
September 4, 2026 16:41
ab3b00c to
7af2137
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.