merge main - #1
Open
ReuschelCGN wants to merge 188 commits into
Open
Conversation
CI installs Node 22 which ships npm 10.9.7. That version's `npm ci` strictly requires the nested `chokidar@4.0.3` / `readdirp@4.1.2` entries that `@angular-devkit/*` packages declare as optional peer deps. Dependabot regenerates `package-lock.json` with a newer npm that prunes those entries, producing lockfiles npm 10.9.7 rejects with EUSAGE — blocking #248, #250, #256, #261, #262. Aligning CI to npm 11 matches Dependabot's resolution so the post-rebase lockfile is accepted.
Bumps Microsoft.AspNetCore.Authentication.JwtBearer from 10.0.5 to 10.0.8 Bumps Microsoft.AspNetCore.Mvc.Testing from 10.0.5 to 10.0.8 Bumps Microsoft.AspNetCore.OpenApi from 10.0.5 to 10.0.8 Bumps Microsoft.EntityFrameworkCore from 10.0.5 to 10.0.8 Bumps Microsoft.EntityFrameworkCore.Design from 10.0.5 to 10.0.8 Bumps Microsoft.EntityFrameworkCore.InMemory from 10.0.5 to 10.0.8 Bumps Microsoft.Extensions.Caching.Memory from 10.0.5 to 10.0.8 Bumps Microsoft.Extensions.Configuration.Abstractions from 10.0.5 to 10.0.8 Bumps Microsoft.Extensions.Http from 10.0.5 to 10.0.8 Bumps Microsoft.Extensions.Logging.Abstractions from 10.0.5 to 10.0.8 Bumps Microsoft.NET.Test.Sdk from 18.4.0 to 18.5.1 --- updated-dependencies: - dependency-name: Microsoft.AspNetCore.Authentication.JwtBearer dependency-version: 10.0.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft - dependency-name: Microsoft.AspNetCore.Mvc.Testing dependency-version: 10.0.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft - dependency-name: Microsoft.AspNetCore.OpenApi dependency-version: 10.0.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft - dependency-name: Microsoft.EntityFrameworkCore dependency-version: 10.0.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft - dependency-name: Microsoft.EntityFrameworkCore dependency-version: 10.0.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft - dependency-name: Microsoft.EntityFrameworkCore.Design dependency-version: 10.0.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft - dependency-name: Microsoft.EntityFrameworkCore.InMemory dependency-version: 10.0.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft - dependency-name: Microsoft.Extensions.Caching.Memory dependency-version: 10.0.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft - dependency-name: Microsoft.Extensions.Logging.Abstractions dependency-version: 10.0.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft - dependency-name: Microsoft.Extensions.Configuration.Abstractions dependency-version: 10.0.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft - dependency-name: Microsoft.Extensions.Http dependency-version: 10.0.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft - dependency-name: Microsoft.NET.Test.Sdk dependency-version: 18.5.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: microsoft ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the angular group with 13 updates in the /Applications/Pgan.PoracleWebNet.App/ClientApp directory: | Package | From | To | | --- | --- | --- | | [@angular/animations](https://github.com/angular/angular/tree/HEAD/packages/animations) | `21.2.8` | `21.2.14` | | [@angular/cdk](https://github.com/angular/components) | `21.2.6` | `21.2.12` | | [@angular/common](https://github.com/angular/angular/tree/HEAD/packages/common) | `21.2.8` | `21.2.14` | | [@angular/compiler](https://github.com/angular/angular/tree/HEAD/packages/compiler) | `21.2.8` | `21.2.14` | | [@angular/core](https://github.com/angular/angular/tree/HEAD/packages/core) | `21.2.8` | `21.2.14` | | [@angular/forms](https://github.com/angular/angular/tree/HEAD/packages/forms) | `21.2.8` | `21.2.14` | | [@angular/material](https://github.com/angular/components) | `21.2.6` | `21.2.12` | | [@angular/platform-browser](https://github.com/angular/angular/tree/HEAD/packages/platform-browser) | `21.2.8` | `21.2.14` | | [@angular/router](https://github.com/angular/angular/tree/HEAD/packages/router) | `21.2.8` | `21.2.14` | | [@angular/build](https://github.com/angular/angular-cli) | `21.2.7` | `21.2.12` | | [@angular/cli](https://github.com/angular/angular-cli) | `21.2.7` | `21.2.12` | | [@angular/compiler-cli](https://github.com/angular/angular/tree/HEAD/packages/compiler-cli) | `21.2.8` | `21.2.14` | | [@angular/platform-browser-dynamic](https://github.com/angular/angular/tree/HEAD/packages/platform-browser-dynamic) | `21.2.8` | `21.2.14` | Updates `@angular/animations` from 21.2.8 to 21.2.14 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/v21.2.14/packages/animations) Updates `@angular/cdk` from 21.2.6 to 21.2.12 - [Release notes](https://github.com/angular/components/releases) - [Changelog](https://github.com/angular/components/blob/main/CHANGELOG.md) - [Commits](angular/components@v21.2.6...v21.2.12) Updates `@angular/common` from 21.2.8 to 21.2.14 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/v21.2.14/packages/common) Updates `@angular/compiler` from 21.2.8 to 21.2.14 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/v21.2.14/packages/compiler) Updates `@angular/core` from 21.2.8 to 21.2.14 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/v21.2.14/packages/core) Updates `@angular/forms` from 21.2.8 to 21.2.14 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/v21.2.14/packages/forms) Updates `@angular/material` from 21.2.6 to 21.2.12 - [Release notes](https://github.com/angular/components/releases) - [Changelog](https://github.com/angular/components/blob/main/CHANGELOG.md) - [Commits](angular/components@v21.2.6...v21.2.12) Updates `@angular/platform-browser` from 21.2.8 to 21.2.14 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/v21.2.14/packages/platform-browser) Updates `@angular/router` from 21.2.8 to 21.2.14 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/v21.2.14/packages/router) Updates `@angular/build` from 21.2.7 to 21.2.12 - [Release notes](https://github.com/angular/angular-cli/releases) - [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md) - [Commits](angular/angular-cli@v21.2.7...v21.2.12) Updates `@angular/cli` from 21.2.7 to 21.2.12 - [Release notes](https://github.com/angular/angular-cli/releases) - [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md) - [Commits](angular/angular-cli@v21.2.7...v21.2.12) Updates `@angular/compiler-cli` from 21.2.8 to 21.2.14 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/v21.2.14/packages/compiler-cli) Updates `@angular/platform-browser-dynamic` from 21.2.8 to 21.2.14 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/v21.2.14/packages/platform-browser-dynamic) --- updated-dependencies: - dependency-name: "@angular/animations" dependency-version: 21.2.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/build" dependency-version: 21.2.8 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/cdk" dependency-version: 21.2.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/cli" dependency-version: 21.2.8 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/common" dependency-version: 21.2.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/compiler" dependency-version: 21.2.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/compiler-cli" dependency-version: 21.2.10 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/core" dependency-version: 21.2.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/forms" dependency-version: 21.2.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/material" dependency-version: 21.2.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/platform-browser" dependency-version: 21.2.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/platform-browser-dynamic" dependency-version: 21.2.10 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/router" dependency-version: 21.2.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: angular ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [@jest/globals](https://github.com/jestjs/jest/tree/HEAD/packages/jest-globals) from 30.3.0 to 30.4.1. - [Release notes](https://github.com/jestjs/jest/releases) - [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md) - [Commits](https://github.com/jestjs/jest/commits/v30.4.1/packages/jest-globals) --- updated-dependencies: - dependency-name: "@jest/globals" dependency-version: 30.4.1 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
) Bumps [jsdom](https://github.com/jsdom/jsdom) from 28.1.0 to 29.1.1. - [Release notes](https://github.com/jsdom/jsdom/releases) - [Commits](jsdom/jsdom@v28.1.0...v29.1.1) --- updated-dependencies: - dependency-name: jsdom dependency-version: 29.1.1 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the jest group with 3 updates in the /Applications/Pgan.PoracleWebNet.App/ClientApp directory: [jest](https://github.com/jestjs/jest/tree/HEAD/packages/jest), [jest-environment-jsdom](https://github.com/jestjs/jest/tree/HEAD/packages/jest-environment-jsdom) and [jest-preset-angular](https://github.com/thymikee/jest-preset-angular). Updates `jest` from 30.3.0 to 30.4.2 - [Release notes](https://github.com/jestjs/jest/releases) - [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md) - [Commits](https://github.com/jestjs/jest/commits/v30.4.2/packages/jest) Updates `jest-environment-jsdom` from 30.3.0 to 30.4.1 - [Release notes](https://github.com/jestjs/jest/releases) - [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md) - [Commits](https://github.com/jestjs/jest/commits/v30.4.1/packages/jest-environment-jsdom) Updates `jest-preset-angular` from 16.1.4 to 16.1.5 - [Release notes](https://github.com/thymikee/jest-preset-angular/releases) - [Changelog](https://github.com/thymikee/jest-preset-angular/blob/main/CHANGELOG.md) - [Commits](thymikee/jest-preset-angular@v16.1.4...v16.1.5) --- updated-dependencies: - dependency-name: jest dependency-version: 30.4.2 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: jest - dependency-name: jest-environment-jsdom dependency-version: 30.4.1 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: jest - dependency-name: jest-preset-angular dependency-version: 16.1.5 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: jest ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the eslint group with 3 updates in the /Applications/Pgan.PoracleWebNet.App/ClientApp directory: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin), [eslint-plugin-perfectionist](https://github.com/azat-io/eslint-plugin-perfectionist) and [prettier](https://github.com/prettier/prettier). Updates `@typescript-eslint/eslint-plugin` from 8.58.1 to 8.59.4 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.59.4/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 8.58.1 to 8.59.4 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.59.4/packages/parser) Updates `@typescript-eslint/utils` from 8.58.1 to 8.59.4 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/utils/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.59.4/packages/utils) Updates `eslint-plugin-perfectionist` from 5.8.0 to 5.9.0 - [Release notes](https://github.com/azat-io/eslint-plugin-perfectionist/releases) - [Changelog](https://github.com/azat-io/eslint-plugin-perfectionist/blob/main/changelog.md) - [Commits](azat-io/eslint-plugin-perfectionist@v5.8.0...v5.9.0) Updates `prettier` from 3.8.2 to 3.8.3 - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md) - [Commits](prettier/prettier@3.8.2...3.8.3) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-version: 8.58.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: eslint - dependency-name: "@typescript-eslint/parser" dependency-version: 8.58.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: eslint - dependency-name: "@typescript-eslint/utils" dependency-version: 8.58.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: eslint - dependency-name: eslint-plugin-perfectionist dependency-version: 5.9.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: eslint - dependency-name: prettier dependency-version: 3.8.3 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: eslint ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: HokiePokeDad <hokiepokedad@pogoalerts.net>
The auto-merge-deps workflow listed both `pull_request_target` and `push:` as triggers. In practice GitHub fired it only on push events — the last 100+ runs were all `push`, zero were `pull_request_target` — even though the sibling `pr-labeler.yml` (only `pull_request_target`) fires correctly. The job-level `if: github.event_name == 'pull_request_target'` then skipped every step on those push runs, recording each as failure with 0 successful steps. Two changes: - Drop the `push:` trigger so only pull_request_target events run. - Drop the job-level gate; gate each step instead and add a sentinel first step so non-Dependabot PRs still record as success rather than 0-step failure. #231 attempted this with job-level if assuming "all-skipped = success", but GitHub treats 0-job runs as failure regardless.
The approval body string contained Auto-approved: — an unquoted colon inside an unquoted YAML scalar. PyYAML rejects this with `mapping values are not allowed here`, and GitHub Actions appears to silently fail to register the workflow's `pull_request_target` trigger as a result (the workflow only ever fires on push events, the friendly name from `name:` never resolves in the API). Sibling `pr-labeler.yml` has no such ambiguity and fires correctly. Dropping the colon from the body resolves both symptoms without needing to nest YAML quoting.
--- updated-dependencies: - dependency-name: coverlet.collector dependency-version: 10.0.1 dependency-type: direct:production update-type: version-update:semver-major dependency-group: test - dependency-name: Microsoft.NET.Test.Sdk dependency-version: 18.5.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: test ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps Microsoft.EntityFrameworkCore from 10.0.5 to 10.0.8 Bumps Microsoft.EntityFrameworkCore.Design from 10.0.5 to 10.0.8 Bumps Microsoft.EntityFrameworkCore.InMemory from 10.0.5 to 10.0.8 Bumps MySql.EntityFrameworkCore from 10.0.1 to 10.0.7 --- updated-dependencies: - dependency-name: Microsoft.EntityFrameworkCore dependency-version: 10.0.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: ef-core - dependency-name: Microsoft.EntityFrameworkCore.Design dependency-version: 10.0.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: ef-core - dependency-name: MySql.EntityFrameworkCore dependency-version: 10.0.7 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: ef-core - dependency-name: Microsoft.EntityFrameworkCore.InMemory dependency-version: 10.0.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: ef-core ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: hokiepokedad2 <38219945+hokiepokedad2@users.noreply.github.com>
Loose .png screenshots from Playwright MCP sessions and the `.playwright-mcp/` output directory keep showing up as untracked at the repo root. None of them belong in the tree (tracked PNGs all live under `Applications/Pgan.PoracleWebNet.App/ClientApp/public/assets/`). Add a root-only `/*.png` rule plus `.playwright-mcp/` so `git status` stays clean.
#260) (#279) LikeEscape (added in #232) used `\` as the SQL LIKE escape character, and ScannerService.SearchGymsAsync passed `\` to EF.Functions.Like via `"\\"`. MariaDB's default mode (`NO_BACKSLASH_ESCAPES=OFF`) also treats `\` as a string-literal escape, so an escaped `\` in the pattern (which LikeEscape itself produces for user-supplied backslashes) left the SQL string literal unbalanced and broke gym search with `near ''\')`. Switch the escape character to `|`, which has no special meaning in MariaDB string literals. The LIKE pattern can no longer interact with quote escaping no matter what the user types. Added a `LikeEscape.EscapeChar` constant so callers stay in sync. Tests updated to match the new escape sequences. Reported by @prof-miles0 in #260.
Bumps the angular group in /Applications/Pgan.PoracleWebNet.App/ClientApp with 13 updates: | Package | From | To | | --- | --- | --- | | [@angular/animations](https://github.com/angular/angular/tree/HEAD/packages/animations) | `21.2.14` | `21.2.15` | | [@angular/cdk](https://github.com/angular/components) | `21.2.12` | `21.2.13` | | [@angular/common](https://github.com/angular/angular/tree/HEAD/packages/common) | `21.2.14` | `21.2.15` | | [@angular/compiler](https://github.com/angular/angular/tree/HEAD/packages/compiler) | `21.2.14` | `21.2.15` | | [@angular/core](https://github.com/angular/angular/tree/HEAD/packages/core) | `21.2.14` | `21.2.15` | | [@angular/forms](https://github.com/angular/angular/tree/HEAD/packages/forms) | `21.2.14` | `21.2.15` | | [@angular/material](https://github.com/angular/components) | `21.2.12` | `21.2.13` | | [@angular/platform-browser](https://github.com/angular/angular/tree/HEAD/packages/platform-browser) | `21.2.14` | `21.2.15` | | [@angular/router](https://github.com/angular/angular/tree/HEAD/packages/router) | `21.2.14` | `21.2.15` | | [@angular/build](https://github.com/angular/angular-cli) | `21.2.12` | `21.2.13` | | [@angular/cli](https://github.com/angular/angular-cli) | `21.2.12` | `21.2.13` | | [@angular/compiler-cli](https://github.com/angular/angular/tree/HEAD/packages/compiler-cli) | `21.2.14` | `21.2.15` | | [@angular/platform-browser-dynamic](https://github.com/angular/angular/tree/HEAD/packages/platform-browser-dynamic) | `21.2.14` | `21.2.15` | Updates `@angular/animations` from 21.2.14 to 21.2.15 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/v21.2.15/packages/animations) Updates `@angular/cdk` from 21.2.12 to 21.2.13 - [Release notes](https://github.com/angular/components/releases) - [Changelog](https://github.com/angular/components/blob/main/CHANGELOG.md) - [Commits](angular/components@v21.2.12...v21.2.13) Updates `@angular/common` from 21.2.14 to 21.2.15 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/v21.2.15/packages/common) Updates `@angular/compiler` from 21.2.14 to 21.2.15 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/v21.2.15/packages/compiler) Updates `@angular/core` from 21.2.14 to 21.2.15 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/v21.2.15/packages/core) Updates `@angular/forms` from 21.2.14 to 21.2.15 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/v21.2.15/packages/forms) Updates `@angular/material` from 21.2.12 to 21.2.13 - [Release notes](https://github.com/angular/components/releases) - [Changelog](https://github.com/angular/components/blob/main/CHANGELOG.md) - [Commits](angular/components@v21.2.12...v21.2.13) Updates `@angular/platform-browser` from 21.2.14 to 21.2.15 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/v21.2.15/packages/platform-browser) Updates `@angular/router` from 21.2.14 to 21.2.15 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/v21.2.15/packages/router) Updates `@angular/build` from 21.2.12 to 21.2.13 - [Release notes](https://github.com/angular/angular-cli/releases) - [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md) - [Commits](angular/angular-cli@v21.2.12...v21.2.13) Updates `@angular/cli` from 21.2.12 to 21.2.13 - [Release notes](https://github.com/angular/angular-cli/releases) - [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md) - [Commits](angular/angular-cli@v21.2.12...v21.2.13) Updates `@angular/compiler-cli` from 21.2.14 to 21.2.15 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/v21.2.15/packages/compiler-cli) Updates `@angular/platform-browser-dynamic` from 21.2.14 to 21.2.15 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/v21.2.15/packages/platform-browser-dynamic) --- updated-dependencies: - dependency-name: "@angular/animations" dependency-version: 21.2.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/cdk" dependency-version: 21.2.13 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/common" dependency-version: 21.2.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/compiler" dependency-version: 21.2.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/core" dependency-version: 21.2.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/forms" dependency-version: 21.2.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/material" dependency-version: 21.2.13 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/platform-browser" dependency-version: 21.2.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/router" dependency-version: 21.2.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/build" dependency-version: 21.2.13 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/cli" dependency-version: 21.2.13 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/compiler-cli" dependency-version: 21.2.15 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: angular - dependency-name: "@angular/platform-browser-dynamic" dependency-version: 21.2.15 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: angular ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
#259) (#280) * feat(raids): redesign level selector with named tiers + custom palette (#259) The raid/egg add dialog had three level-pickers (raid checkboxes, egg checkboxes, boss-level dropdown) all driven by a hardcoded `levels = [1, 2, 3, 4, 5, 6]` array, even though PoracleNG accepts any positive integer. Users with Elite Raids (level 7) or custom server schemes had to configure those via the bot's `!command` interface; the UI silently locked them out. Replace all three sites with a new `<app-level-selector>` shared component — a Material 3 chip listbox in three sections: - STANDARD: T1-T5 - SPECIAL: Mega (6), Elite (7), plus "Any" (9000) when showAny=true - CUSTOM: any user-added integer, persisted per-user in localStorage Power users add a custom level via an inline "+ Add level" affordance that transforms into a numeric input. The chip then persists across dialog opens (one-click selection on subsequent alarms) and seeds itself from saved alarm data on open, so editing an existing level-42 alarm renders the chip pre-selected rather than orphaned. Single source of truth for label resolution lives in `core/models/raid-level.models.ts`. `resolveLevel(value)` maps any integer to the right LevelOption — adopted by raid-list cards too, so the dialog and the cards now speak the same vocabulary ("Elite", not "Level 7" vs "7" on different surfaces). Edge cases: - 0 / negatives / non-integers in custom input -> inline validation error - 9000 in custom input -> snaps to the "Any" chip (no duplicate) - duplicate of built-in -> flashes existing chip + selects, no new entry - 20-entry LRU cap on the localStorage palette i18n: new `RAIDS.LEVEL.*` keys added in all 11 locales with English fallbacks for non-en (translation volunteers can localize later, per discussion #211). Bonus correctness: the boss tab used to default level=0 ("any") but PoracleNG's canonical wildcard sentinel is 9000. New alarms now use 9000; old alarms with 0 continue to work and edit fine. 37 new unit tests across the model, store, pipe, and component. Closes #259, reported by @prof-miles0. * fix(raids): address #259 review — compact layout, per-type palette, unblock save Follow-up on d58752e (the initial #259 redesign), addressing visual, correctness, and backend-validation issues found during testing. UI / UX - Collapse the three-section (Standard/Special/Custom) chip layout into one wrapping row per picker. Categories are encoded in chip content (T1 / "Mega · 6" / "42 ⊗") rather than container labels; cuts dialog height roughly in half. - Replace the heavy mat-form-field "+ Add custom level" with a chip-sized inline numeric input. Enter commits, Esc cancels, blur commits. Help text only renders when the input is open or there's a validation error. - Override Material 3 selected-chip font-weight so the selected state actually pops; bind `hideSingleSelectionIndicator` to `!multiple` so multi-select chips get a leading checkmark. - Cap card star icons to levels 1-7 (was 1-100) — alarms at level 23 no longer render 23 stars in the card. Per-type palette - Adding a custom level on the raid picker was leaking it into the egg and boss pickers. `CustomLevelStore` now keys palettes by `paletteKey` ("raid" / "egg" / "boss"), each persisted to its own localStorage slot. Required `paletteKey` input on `<app-level-selector>`. Any chip surfaced where PoracleNG actually honors it - Raid + boss pickers show the `Any` chip (PoracleNG treats level=9000 as the wildcard sentinel — see trackingRaid.go). - Egg picker deliberately omits Any: PoracleNG's trackingEgg.go only validates level >= 1 with no wildcard semantic, so an "Any egg" alarm at 9000 would simply never fire. Server-side fix that was blocking custom-level alarms - `[Range(0, 10)]` on `RaidCreate.Level`, `RaidUpdate.Level`, `EggCreate.Level`, `EggUpdate.Level` was rejecting custom integers (8+) and the new Any=9000 sentinel with 400 Bad Request before they could reach PoracleNG. Relaxed to `[Range(0, int.MaxValue)]` matching PoracleNG's actual range. Label vocabulary consistency - Edit dialog (raid/egg) now uses the same `resolveLevel` resolver as the cards via the new `LevelLabelPipe` — an alarm at level 7 reads "Elite" on the card AND in the edit dialog (was "Level 7" in the dialog before). Egg image alt-text in the card list now uses the pipe too. Error UX - Removing a custom chip (`⊗`) opens a 3-second snackbar with Undo — accidental click is recoverable; intentional removal still wipes the palette entry. State-machine clarity - `addInputOpen: signal(boolean)` replaced with an explicit `addMode: signal<'closed' | 'open'>` and named `isAddClosed()` / `isAddOpen()` getters in the template — removes the `!` negation pattern that prior renders sometimes appeared to misread. Tests - Updated `custom-level-store.service.spec.ts` for the keyed API. - Updated `level-selector.component.spec.ts` to set `paletteKey` per test and assert per-key isolation. - 697/697 frontend tests pass, 1063/1063 backend tests pass. i18n - Added `RAIDS.LEVEL.REMOVED` and `COMMON.UNDO` keys in all 11 locales (English placeholder text for non-en — translation volunteers per discussion #211). * fix(raids): align level selector with WatWowMap masterfile (19 named levels) Builds on the v2 review-pass (2c2f0aa). Follow-up driven by the issue reporter pointing to the canonical Pokémon GO raid level vocabulary in the WatWowMap masterfile — there are 19 named raid types (1-Star through Coordinated 2), not 7, and the prior UI labeled level 7 as "Elite" when the masterfile says it's "Mega Legendary". Backend - `GET /api/masterdata/raid-levels` returns the canonical list with per-level integer, category, and singular/plural English names. - New `IRaidLevelService` / `RaidLevelService` returns a baked-in snapshot of the masterfile. A TODO documents how to swap the implementation for a live fetch from raw.githubusercontent.com/WatWowMap/Masterfile-Generator without changing the wire contract. - 6 new unit tests cover the service + controller endpoint. Frontend - `RaidLevelService` (Angular) calls the new API on first dialog use, caches the result in a signal. Falls back to `KNOWN_LEVELS` baked-in constants when the network fails or before resolve. - `raid-level.models.ts` rewritten around 19 canonical levels keyed by `RAIDS.LEVEL.RAID_1` through `RAID_19` (plus `_PLURAL` variants). Removed the bogus `T1`-`T5` / `MEGA` / `ELITE` keys. - `LevelSelectorComponent` simplified to a `pickerType` input (`'raid' | 'egg' | 'boss'`). Inputs: • raid → primary chips 1-7, overflow menu for 8-19, Any chip, +Add • egg → star tiers (1-5) only, +Add (no overflow, no Any) • boss → single-select with the same primary + overflow as raid "More raid types…" overlay menu (mat-menu) surfaces the 12 less common levels without crowding the chip row. - i18n: 19 singular + 19 plural keys in all 11 locales, with English placeholders for the 10 non-en locales (volunteers per #211). - Card star icons now render only for the literal 1-5 "N Star Raid" tier (was 1-7, producing ~23 stars for custom-level alarms). - Label vocabulary consistency: alarm at level 7 now reads "Mega Legendary Raid" on the card and in the edit dialog (was "Elite" on the card, "Level 7" in the edit dialog). Forward compatibility - Any positive integer remains addable via the `+ Add` chip. When the WatWowMap masterfile adds raid_20+ in the future, the backend service can pick it up automatically (once the live-fetch path is wired); existing custom alarms at that level continue to work. Tests: 711/711 frontend, 1069/1069 backend. Lint + prettier clean. * fix(raids): shorten labels, ephemeral palette, review fixes Follow-up on 12be778 (v3 masterfile alignment). User feedback + internal PR review revealed several issues; this commit addresses them. User feedback - Custom levels typed via `+ Add` were persisting across modal close AND page refresh because the per-type palette was backed by localStorage. Deleted CustomLevelStore entirely; LevelSelector now tracks the palette in a local `customPalette` signal that lives for the component lifetime only. Refresh or close-and-reopen wipes typed-but-not-saved chips. Existing alarms still seed the palette through the `[value]` input. - Chip labels were too long ("Mega Legendary Raid"), and the same string caused "All Mega Legendary Raid Raids" double-Raid in card titles. Dropped the "Raid" suffix from the 19 RAID_N keys in all 11 locales — chips now read "Mega Legendary", "Legendary", "1 Star", etc. The card-title template (`RAIDS.ALL_LEVEL_RAIDS = "All {{level}} Raids"`) supplies the noun once; result reads natural English. Also dropped the unused `pluralKey` from `LevelOption` and the `_PLURAL` i18n keys (the shortened `RAID_N` strings work in both card and chip contexts). Backend `RaidLevelInfo.Name` is now the modifier form ("Mega Legendary") while `NamePlural` retains the full "Mega Legendary Raids" for any future standalone use. Review fixes (MUST FIX) - Snackbar undo subscription in `LevelSelector.removeCustom` now pipes through `takeUntilDestroyed(this.destroyRef)` so closing the dialog mid-toast can't fire the callback against a destroyed component. - `raid-list.getRaidLevelName` was bypassing the live `RaidLevelService.byValue()` and using the baked-in `KNOWN_LEVELS` constant — cards would drift from the dialog if the API ever extended the canonical list. Cards now consult the service first, fall back to the baked-in resolver. `raid-list.ngOnInit` primes the cache so the list page doesn't depend on a dialog open. - `LevelLabelPipe` now detects ngx-translate's "key not found" pass-through (translated string === key) and falls back to "Level {n}" instead of leaking "RAIDS.LEVEL.RAID_20" into the UI. Graceful degradation for future masterfile additions before locales catch up. Review fixes (SHOULD FIX) - `raid-edit-dialog.formatLevel` deleted — the dialog now injects `LevelLabelPipe` and calls `.transform()`, eliminating the duplicate label-resolution logic. Single source of truth. Analyzers - xUnit2032 in `MasterDataControllerRaidLevelsTests`: switched `Assert.IsAssignableFrom<T>` to `Assert.IsType<T>(..., exactMatch: false)`. - CA1707 in `RaidLevelServiceTests` and the new controller test: test method names renamed to PascalCase to match the project's preferred style and silence the analyzer. Dev workflow - New `proxy.conf.json` forwards `/api/*` and `/auth/*` from the Angular dev server to the API. `environment.development.ts` apiUrl set to `''` so all HTTP calls are same-origin from the browser's view — works identically for `ng serve` + proxy and for the production single-port deployment. OAuth flows survive the proxy because Host is preserved. Tests: 700/700 frontend (+1 fallback test), 1069/1069 backend. Lint + prettier + dotnet format (scoped) all clean. * docs: cover the level-selector redesign + ng-serve proxy workflow - features/alarms.md: replace the generic "tier" wording on Raids/Eggs rows with pointers to a new "Raid level selector" subsection that documents the chip layout, the 19 masterfile-defined raid types, primary vs overflow split per pickerType, the ephemeral custom-add affordance, and the wildcard sentinel. - architecture/backend.md: add a "Raid level service" section documenting IRaidLevelService, GET /api/masterdata/raid-levels, the baked-in fallback + live-fetch upgrade path, and the [Range] relax that lets PoracleNG-accepted custom integers pass validation. Also register the singleton in the service lifetimes table. - architecture/frontend.md: document LevelSelectorComponent + the Angular RaidLevelService consumer (signal cache, baked-in fallback, LevelLabelPipe missing-key fallback), and the ephemeral palette behavior. - getting-started/development-setup.md: the "proxies API requests" claim is now accurate thanks to the committed proxy.conf.json — describe it explicitly (changeOrigin: false to preserve Host for OAuth callbacks), note the empty apiUrl + same-origin dev flow, and document the --port override for matching a non-default Discord OAuth redirect URI.
The standalone `dotnet run` DataProtection fallback writes keys to Applications/Pgan.PoracleWebNet.Api/data/ (Program.cs uses ./data when DATA_DIR is unset), and the published Angular bundle is copied into the API host at Applications/Pgan.PoracleWebNet.Api/wwwroot/. Both are regenerated build/runtime output and were showing up as untracked. The existing Data/dataprotection-keys/ rule only covered the Data project path, not the API host path. Added both so a local build/run leaves a clean working tree.
Poracle's `pvp_ranking_cap` field was never surfaced by PoracleWeb.NET, so
every PvP alarm defaulted to matching all caps (L50 + L51) server-side.
New users got flooded with L51 noise even when admins configured
`tracking.defaultUserTrackingLevelCap = 50` in Poracle.
This wires `pvp_ranking_cap` end-to-end and mirrors the PoracleWeb PHP
passthrough pattern — no new admin setting; the cap list and default
come from Poracle's existing `/api/config/poracleWeb` response
(`pvpCaps`, `defaultPvpCap`).
Backend:
- `Monster` / `MonsterCreate` / `MonsterUpdate` / `MonsterEntity`:
new `PvpRankingCap` field (0 = all caps).
- `AlarmMappingExtensions.ToMonster` + `ApplyUpdate`: mapping + null-skip.
- `PoracleConfig.PvpCaps` (list) and `DefaultPvpCap` (int), parsed in
`PoracleApiProxy.GetConfigAsync`. Accepts number or string caps
(PoracleJS is inconsistent on this).
- `QuickPickService.SafeMonsterFilterKeys`: allow `pvpRankingCap` so
quick-pick authors can pin a cap per definition.
Frontend:
- `Monster.pvpRankingCap`, `PoracleServerConfig` interface.
- New `PoracleConfigService` caches `/api/config` behind a signal.
- `pokemon-add-dialog`: `mat-button-toggle-group` under the PvP league
field with `All` / `L{cap}` options. Pre-fills from `defaultPvpCap`.
Italic "Default · from Poracle config" hint disappears the moment
the user changes the selection. Hidden entirely when Poracle offers
only one cap.
- `pokemon-edit-dialog`: same toggle group; shows stored cap on load.
Tests (+1066 backend, +658 frontend):
- Mapping tests cover `PvpRankingCap` in `ToMonster`, null-skip
`ApplyUpdate`, and explicit-overwrite cases.
- `ConfigControllerTests` verify `PvpCaps` + `DefaultPvpCap` flow
through the controller unmodified.
- `monster.service.spec.ts` fixtures updated with the new field.
) * feat(raids): RSVP notification mode for raid and egg alarms (#233) Surface the existing `rsvpChanges` field as a three-option mode toggle (Matches only / Matches + RSVP / RSVP only) in the raid & egg add/edit dialogs, with a matching pill on alarm cards. The field, mapping, and dialog form binding already exist on main; this adds the missing UI control and the third mode value. - New self-contained shared components: rsvp-toggle (FormControl input) and rsvp-pill (numeric value input). - Widen [Range(0, 1)] -> [Range(0, 2)] on RsvpChanges in RaidCreate, RaidUpdate, EggCreate, EggUpdate so mode 2 isn't rejected with HTTP 400. - Wire rsvp-toggle into both dialogs (raid + egg) bound to the rsvpChanges form control; rsvp-pill onto raid/egg cards. - RSVP i18n keys added to all 11 locales (incl. new pl/sv/da). - RsvpRangeValidationTests covering the 0..2 range and null updates. Salvaged from #235, dropping that branch's raid-dialog section-refactor which conflicted with the #280 level-selector restructure already on main. * feat(raids): set edit-in-place bit when RSVP updates are enabled PoracleNG's `clean` field is a bitmask (bit 1 = auto-delete, bit 2 = edit-in-place). Raid/egg RSVP updates are PoracleNG's first edit-tracking consumer: with the edit bit set, RSVP count changes edit the existing alert in place; without it, each change sends a brand-new message. Verified against PoracleNG main (processor/internal/dts/renderer.go): the per-user editKey is gated on db.IsEdit(user.Clean), so RSVP mode alone is not enough — the edit bit must accompany it. - raid/egg add + edit dialogs: OR in `clean` bit 2 when rsvpChanges >= 1. - edit dialog: read the auto-delete toggle from `clean & 1` (was `clean === 1`) so it round-trips correctly once bit 2 can be set. - raid-list: new isAutoDelete() helper masks bit 1 for the card auto-delete badge (Angular templates can't express bitwise &). - CHANGELOG + docs note the edit-in-place coupling. * style(raids): align RSVP toggle + pill with the app design system The RSVP components were copied from a pre-#280 branch and used a bespoke look (stacked icon+label+description button rows, hardcoded indigo pill) that didn't match the current Material 3 language. rsvp-toggle: rebuilt to mirror the #237 PvP-cap pattern — a <fieldset> with an uppercase <legend> section header, a plain full-width segmented mat-button-toggle-group (no icons/no inline descriptions), and a single hint below that shows the selected mode's description (so the "RSVP only silences without a scanner" caveat stays visible). Uses --text-muted / --text-secondary tokens instead of raw opacity. rsvp-pill: now a .clean-tag-style status badge themed with --mat-sys-primary / --mat-sys-on-primary (was hardcoded #3f51b5). Moved out of the stat grid into card-top-actions so it sits beside the auto-delete tag as a sibling status indicator. Specs updated for the new structure; docs reworded (themed badge, not "indigo pill"). prettier/lint/jest(712)/ng build all green. * chore: keep Dockerfile.local out of the PR (local test artifact) * style(raids): square off the RSVP toggle ends (--mat-button-toggle-shape) M3 defaults the segmented button group to a pill radius; override the shape token to 4px so the end segments read as a crisp Material control rather than a rounded pill. * fix(raids): stop RSVP toggle overflow + vertically center labels - fieldset defaulted to min-inline-size: auto and overflowed its container (right edge clipped); force min-inline-size: 0 / width 100% / border-box. - flex-center the button-toggle label content so single-line options align with the wrapped 'Matches + RSVP updates' segment. * fix(raids): RSVP toggle overflow (drop fieldset, border-box) + drop dead i18n key - Replace the <fieldset>/<legend> with a plain block + border-box group so the segmented control fits the dialog width (right edge was clipped); the toggle group keeps its aria-label for the accessible name. - Remove the now-unused RSVP_HINT key from all 11 locales (the restyle replaced the static hint with the per-mode description). * fix(raids): widen Clean [Range] to bitmask 0-7 so RSVP edit bit saves The RSVP edit-in-place coupling sets clean bit 2 (clean = 2 or 3), but Clean was still [Range(0, 1)] on RaidCreate/RaidUpdate/EggCreate/EggUpdate -> creating/editing an RSVP alarm failed model validation with HTTP 400 ('failed to create alarm'). clean is a PoracleNG bitmask (auto-delete | edit-in-place | summary); widened to [Range(0, 7)]. Added validation tests. * style(raids): hide RSVP toggle selection checkmark for more label room Single-select group, so the M3 checkmark only ate ~24px and pushed labels to wrap. hideSingleSelectionIndicator drops it; the accent fill + bold already signal the selected mode.
node:22-alpine bundles npm 10.9.x, which rejects the npm-11-generated package-lock.json with EUSAGE (pruned chokidar/readdirp optional peers), so docker build / compose up --build failed from source. CI already pins npm 11 for this; mirror it in the Dockerfile's angular-build stage.
…292 PR1) (#294) PoracleNG reads `clean` as a 3-bit bitmask (1=auto-delete, 2=edit-in-place, 4=summary) but PoracleWeb treated it as a boolean for 8 of 10 alarm types, which (a) 400'd bot-set values >1 via [Range(0,1)] and (b) clobbered bits 2/4 on every web edit. This is the invisible correctness fix; the lure-edit and quest-summary user controls follow in PR2. - New CleanFlags helper (Core.Models) + clean-flags.ts twin with Preserve(existing, mask, changes) read-modify-write; unit tests for both. - Widen Clean [Range(0,1)] -> [Range(0,7)] on the 16 Monster/Quest/Invasion/ Lure/Nest/Gym/MaxBattle/FortChange Create+Update models (Raid/Egg already done). - CleaningService: preserve unknown bits on bulk-clean toggle; bit-aware AllClean. - All 10 alarm types' edit dialogs preserve unknown bits on save and read auto-delete via the bit; list cards + profile overview gate the badge via an isAutoDelete() method (Angular templates can't parse bitwise &). - Fix the raid/egg RSVP save dropping bit 4; fix the quick-pick apply clobber. - Tests: CleanFlags, clean-range validation (8 types), CleaningService bit preservation, mapping round-trip. Backend 1324 pass; frontend 743 pass.
…PR2) (#295) * feat(alarms): lure edit-in-place + quest daily-summary controls (#292 PR2) Surfaces the two remaining meaningful clean bits as user controls, building on PR1's CleanFlags helper and preservation fixes. - Lure add+edit dialogs: "Edit message in place" toggle (clean bit 2), default off, edit-dialog inits from isEdit() and save composes via preserve(clean, AUTO_DELETE|EDIT, ...) so the summary bit survives. - Quest add+edit dialogs: "Daily summary" toggle (clean bit 4), default off, same preserve pattern; hint notes it needs a summary schedule on the bot. - Card badges: lure edit (--mat-sys-secondary), quest summary (--mat-sys-tertiary), gated via methods, matching .clean-tag/.rsvp-tag. - i18n: LURES.EDIT_* / QUESTS.SUMMARY_* added + translated in all 11 locales. - Only lure/quest get controls (the only types whose PoracleNG processor reads the bit). New dialog specs cover init-from-bit + save-preserves-bits. Frontend: prettier/eslint/build clean, jest 781 pass. No backend change. * docs(#292): document clean delivery modes (alarms doc, in-app help, CLAUDE.md) - docs/features/alarms.md: new 'Delivery & message modes' section covering the clean bitmask (auto-delete / edit-in-place / daily-summary), which types support each, and that PoracleWeb preserves bot-set bits (gh-pages). - In-app Help (HELP.CONTENT_DELIVERY): appended an 'Edit in place & summaries' block describing the lure edit + quest daily-summary modes, translated in all 11 locales. - CLAUDE.md: dev note on the clean bitmask + CleanFlags helper + the Angular 'templates can't parse &' gotcha. * docs(rsvp): document RSVP notification mode (alarms doc + in-app help, 11 locales) Mirrors the #292 delivery-mode docs for RSVP (#233), authored by a tech-writer swarm: - docs/features/alarms.md: new '### RSVP updates (raids & eggs)' subsection under Delivery & message modes, explaining the 3 modes + edit-in-place coupling + the scanner caveat. - In-app Help (HELP.CONTENT_DELIVERY): appended an 'RSVP updates' block in all 11 locales, alongside the edit/summary block. Jest 781 pass; all 11 i18n files valid JSON.
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 7 to 8. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](peter-evans/create-pull-request@v7...v8) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-version: '8' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [marocchino/sticky-pull-request-comment](https://github.com/marocchino/sticky-pull-request-comment) from 2 to 3. - [Release notes](https://github.com/marocchino/sticky-pull-request-comment/releases) - [Commits](marocchino/sticky-pull-request-comment@v2...v3) --- updated-dependencies: - dependency-name: marocchino/sticky-pull-request-comment dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](actions/upload-artifact@v4...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/github-script](https://github.com/actions/github-script) from 7 to 9. - [Release notes](https://github.com/actions/github-script/releases) - [Commits](actions/github-script@v7...v9) --- updated-dependencies: - dependency-name: actions/github-script dependency-version: '9' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps Microsoft.NET.Test.Sdk from 18.5.1 to 18.6.0 --- updated-dependencies: - dependency-name: Microsoft.NET.Test.Sdk dependency-version: 18.6.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: microsoft ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the eslint group in /Applications/Pgan.PoracleWebNet.App/ClientApp with 5 updates: | Package | From | To | | --- | --- | --- | | [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) | `8.59.4` | `8.60.1` | | [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) | `8.59.4` | `8.60.1` | | [@typescript-eslint/utils](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/utils) | `8.59.4` | `8.60.1` | | [eslint-import-resolver-typescript](https://github.com/import-js/eslint-import-resolver-typescript) | `4.4.4` | `4.4.5` | | [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier) | `5.5.5` | `5.5.6` | Updates `@typescript-eslint/eslint-plugin` from 8.59.4 to 8.60.1 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.60.1/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 8.59.4 to 8.60.1 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.60.1/packages/parser) Updates `@typescript-eslint/utils` from 8.59.4 to 8.60.1 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/utils/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.60.1/packages/utils) Updates `eslint-import-resolver-typescript` from 4.4.4 to 4.4.5 - [Release notes](https://github.com/import-js/eslint-import-resolver-typescript/releases) - [Changelog](https://github.com/import-js/eslint-import-resolver-typescript/blob/master/CHANGELOG.md) - [Commits](import-js/eslint-import-resolver-typescript@v4.4.4...v4.4.5) Updates `eslint-plugin-prettier` from 5.5.5 to 5.5.6 - [Release notes](https://github.com/prettier/eslint-plugin-prettier/releases) - [Changelog](https://github.com/prettier/eslint-plugin-prettier/blob/main/CHANGELOG.md) - [Commits](prettier/eslint-plugin-prettier@v5.5.5...v5.5.6) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-version: 8.60.1 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: eslint - dependency-name: "@typescript-eslint/parser" dependency-version: 8.60.1 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: eslint - dependency-name: "@typescript-eslint/utils" dependency-version: 8.60.1 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: eslint - dependency-name: eslint-import-resolver-typescript dependency-version: 4.4.5 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: eslint - dependency-name: eslint-plugin-prettier dependency-version: 5.5.6 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: eslint ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](actions/setup-node@v4...v6) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
) Surface the Poracle `notes` field on channel-type users in the admin user list so admins can disambiguate channels that share the same name across different servers. PoracleJS/PoracleNG can auto-fill notes with the Discord guild name and channel category; that column already existed on the humans table but was dropped at every layer. Reuses data PoracleNG already provides — no new database queries and no live Discord API calls: - Single-user reads come from the PoracleNG human JSON (HumanService .DeserializeHuman now reads `notes`). - The admin bulk list maps the `notes` column through the existing read (Human model + EntityMappingExtensions); projected by GET /api/admin/users and GET /api/admin/users/by-id. Frontend renders notes as a muted second line under the name with a tooltip, and the admin search box matches against it. A notesLabel() normalizer trims whitespace and strips a surrounding quote layer so PoracleJS/NG's quoted-empty `""` sentinel (and any JSON-quoted note) doesn't render a stray value. Tests: extend HumanEntity.ToModel mapping test and the admin.service spec mock.
) * feat: add admin setting to disable user-submitted geofences (#297) From discussion #214: let operators turn off the custom/user-drawn geofence feature via a new `disable_user_geofences` site setting, reusing the existing `disable_*` feature-gate pattern. Backend - DisableFeatureKeys.UserGeofences constant. - Gate the "provide a geofence" actions on UserGeofenceController (create, submit-for-review, GeoJSON import) with [RequireFeatureEnabled], plus a defense-in-depth IFeatureGate.EnsureEnabledAsync guard in UserGeofenceService .CreateAsync (also covers import, which funnels through it) and .SubmitForReviewAsync. - Reads, delete, activate/deactivate and the admin review queue stay ungated so existing geofences keep working and are still served by /api/geofence-feed. - SettingsMigrationService CategoryMap + BooleanKeys carry the key. Frontend - Hide the My Geofences nav item (disableKey) and guard the /geofences route (disabledFeatureGuard) -> redirect to dashboard with the existing ERROR.FEATURE_DISABLED toast; the 403 interceptor handles direct API hits. - Admin settings toggle in the Features group. - ADMIN_SETTINGS.DISABLE_USER_GEOFENCES_* label/description added and translated across all 11 locales. Tests: UserGeofenceService gate tests for CreateAsync and SubmitForReviewAsync; existing test setup updated for the new IFeatureGate dependency. * feat: hide admin "User Geofences" review queue when disabled Extend disable_user_geofences to also hide the admin-facing geofence review queue: add the disableKey to the /admin/geofence-submissions nav item, make the adminNavItems computed honour isFeatureDisabled (it previously ignored disableKey), and guard the route with disabledFeatureGuard. Enabling the toggle now hides the whole feature end to end. The admin review backend stays ungated so any pre-existing submissions aren't bricked and reappear if the feature is re-enabled.
Companion to poracleng-enhancement-requests.md, which tracks the v1-era workaround gaps. This one evaluates whether v2 (PR #139, "huma") closes them and concludes it does not: the trusted-setAreas hack, admin list-all-humans, batch name resolution and full-purge delete all remain blocked, so PoracleContext and the ten alarm entities cannot be deleted without three explicit upstream asks. Claude-Session: https://claude.ai/code/session_01CYyjpx2HzaZxMnYamkyoXX
…#624, #626) (#635) GenerateTokenWithReplacedProfile ended in the WriteToken overload that applies the configured 24-hour default, so every profile switch and every /api/auth/me profile resync restarted the clock. An OIDC login issues a deliberately short 30-minute access token precisely so revocation propagates within about one lifetime; one profile switch turned it into a day. A user who switched profile once a day never expired at all. The re-issue now carries the principal's own exp through. The isAdmin claim was copied verbatim by the same method, and nothing anywhere revalidates it -- every admin check is a claim read. Removing someone from the admin list therefore had no effect for as long as they kept switching profile. Each re-issue now resolves it live. Resolution moved out of AuthController, where login was the only caller, into IUserRoleResolver. That also fixes the other half: since #601 the admin endpoints resolved delegated webhooks from PoracleWeb's own table alone, while the JWT claim is the union of that table and PoracleNG's delegate list. A delegate configured in PoracleJS saw the My Webhooks nav item, an empty page, and a 403 from impersonate. Both now ask the same question. Claude-Session: https://claude.ai/code/session_01CYyjpx2HzaZxMnYamkyoXX
…#636) storeTokens wrote the refresh token only when the new login supplied one and never removed an existing value, so a Discord or Telegram login on a browser that had held an OIDC session inherited that session's refresh token. The refresh interceptor then saw hasRefreshToken() true, posted the stale token, and replaced the JWT with one minted for the previous user. handleAuthResponse bypassed the store entirely, which is how the Telegram path got there. The 401 path cleared tokens but left AuthService holding a user and an impersonation flag, because an interceptor cannot inject AuthService without constructing it -- and constructing it fires /api/auth/me. Teardown therefore lives on the token store, which announces it; AuthService listens and forgets the user. Without that the app rendered the login page inside the signed-in shell, complete with a "Viewing as" banner whose Stop button entered stopImpersonating(), found no admin token, and returned in silence. The login page also keyed its redirect off currentUser rather than the token, so it sent the user to /dashboard, authGuard sent them back, and because the router reuses the component the OIDC auto-redirect never ran. Claude-Session: https://claude.ai/code/session_01CYyjpx2HzaZxMnYamkyoXX
…637) (#638) Seeding the built-in quick picks has been throwing since #604 added save-time filter validation: all-invasions and invasion-leader carry empty filter sets on purpose, because ApplyInvasionAsync fans them out across grunt types at apply time, and the sample alarm built from those empty filters has no grunt_type. SeedDefaultsAsync goes through the same method, so it aborted at sort order 50 -- both the first-visit auto-seed and Reset to Defaults left a partial preset list. A definition with no filters now has nothing to check. The admin Settings page hid any group whose keys had no row yet, and a fresh install seeds exactly one. Alarm Types, Features, Administration and Analytics were therefore unreachable, and since this page is the only writer, the rows could never appear. Reset to Defaults deleted global definitions without clearing applied state, unlike the single-pick delete, so every user kept a row naming a definition that no longer exists -- never listed, never cleaned, and the alarms it owned lost their Remove button. The quick pick dialog decided scope from who was saving rather than from the pick, so an admin editing their own personal pick republished it to everyone; the admin save also had no ownership guard and would take over anybody's. The admin Users tab kept only Discord accounts, so a Telegram user appeared in neither list and no admin action could reach them. Toggling Discord off and Telegram on in one save raced the anti-lockout guard, which reads the other key from the database. Enables are applied first. Deleting every global quick pick was undone by an auto-reseed on the next visit, with no way to keep an empty list. Claude-Session: https://claude.ai/code/session_01CYyjpx2HzaZxMnYamkyoXX
The template selector's Default option is an empty string, and nine of the ten
edit dialogs sent `values.template || null`. ApplyUpdate skips nulls by
design, so choosing Default was accepted, reported as saved, and thrown away.
max-battle already sent '' and worked, which showed the intent.
MonsterService sent { distance } to an endpoint that binds [FromBody] int, so
"Update Distance (all)" 400'd every time on the Pokemon page while working on
all nine other types. Its own spec asserted the broken shape, which is how it
survived.
Bulk "Update Distance" was an unguarded await on every list: a refusal cleared
nothing, reloaded nothing, and showed nothing -- the same outcome as success.
The server names which alarm a radius would take over; that message was thrown
away twice, since the interceptor has no 409 case either. Three lists had no
failure string at all, so LURES/NESTS/GYMS.SNACK_FAILED_DISTANCE is added in
all eleven locales.
Raids' Select All added every egg key too, while the toolbar sits above the
tab group and shows one count -- so Delete took alarms the user could not see.
The Areas page treated a failed read of the current selection as "no areas
selected", then offered to save. One failed request destroyed every
subscription the user had.
Claude-Session: https://claude.ai/code/session_01CYyjpx2HzaZxMnYamkyoXX
The geofence feed served only active and pending_review rows, so an admin rejecting a submission dropped the polygon out of PoracleJS's view while the name stayed in humans.area and every profiles.area, and the card still read Active. Alerts stopped with no notice, and the fence could not be resubmitted while still consuming one of the owner's ten slots. CLAUDE.md already said rejected "remains private with review notes"; now it does. Rename had no status guard. After approval Koji owns the fence under PromotedName and the area lists hold that name, so renaming rewrote the subscription to a name nothing serves and quietly unsubscribed the owner from a live public area. It also treated the dialog's parentId of 0 as a request to clear the region, rather than as "nothing selected" -- and the dialog always sent 0, because it looked the current region up by `name` when creation had stored `displayName`. POST /api/profiles binds the domain model, where no validation attributes live, and wrote the submitted area list and coordinates straight to the profile row. Coordinates now carry the same bounds as the location endpoint, and another user's private geofence name is dropped from the area list -- PoracleNG's own setAreas filter would have stripped it, but this path does not go through setAreas. The admin UI gated Review on pending_review while ApprovableStatuses has always included rejected, so a mistaken rejection was irreversible from the SPA. The region selector declared a selectedValue input and never read it, so the approval dialog showed an empty picker while submitting the seeded id. Deleting a profile did not refresh the session, leaving the profileNo claim naming a profile that no longer exists. Claude-Session: https://claude.ai/code/session_01CYyjpx2HzaZxMnYamkyoXX
…653) About one in five defects found in the audit sweeps was caused by an earlier fix in the same campaign. They cluster into two shapes. The first is tightening a rule without enumerating who depended on the loose one: #601 locked out PoracleJS-configured delegates, #604 broke seeding on two presets that carry empty filters deliberately, #616 left a Stop button that did nothing, and the alarm collision guard over-refused three times running. An invasion grunt-type allowlist would have joined them -- blanche, npc 0 and player team leader are all live in production -- and was only caught because the database happened to get queried first. That should not be luck, so querying production before tightening is now the written rule. The second is fixing one member of a set of ten and leaving the other nine. Also records why tests written alongside a fix do not prove it: three fixes validated the domain model rather than the DTO the controller binds and passed anyway, and one spec asserted the broken request shape outright. Claude-Session: https://claude.ai/code/session_01CYyjpx2HzaZxMnYamkyoXX
…) (#655) save() rebuilt the filter object from scratch and skipped falsy values, so a stored 0 was lost. The built-in nundo preset is { minIv: 0, maxIv: 0 } -- that is the whole of it -- and an admin changing only its description saved a definition with no IV bounds at all. "Nundo" then meant "any Pokemon" for every user who applied it afterwards, with nothing to show anything had changed. Rebuilding rather than merging also dropped any stored key the dialog has no control for. Nothing in live data hits that today, but quick-pick-apply reads filters['clean'] as its base bitmask and no form exposes it. The obvious fix -- keep every value including 0 -- would have caused the mirror-image bug, because most of these controls default to 0 meaning "not set": every newly created pick would carry an explicit minIv, pokemonId and pvpRankingLeague of 0. So a 0 is kept when it was already stored and skipped when it was not, and the create path behaves exactly as before. Claude-Session: https://claude.ai/code/session_01CYyjpx2HzaZxMnYamkyoXX
) Found by a regression lens -- an audit whose only question is what the last day's merges broke. Every one of these was caused by a fix shipped today. The worst: UserRoleResolver could not tell "resolved: not an admin" from "could not resolve", and #635 wired that into every token re-issue. A momentary PoracleNG outage during a profile switch therefore stripped admin for the rest of the session and cached the answer for a minute. Before #635 the claim was copied forward and an outage could not demote anyone. The resolver now reports unresolved, callers pass null to leave the claim alone, and a degraded answer is never cached. The rename status guard from #652 threw InvalidOperationException past a controller that catches three other types, so it surfaced as a 500 -- and the button was still rendered on every status. The profile-create area filter from the same PR denied approved geofences, which are public Koji areas anyone may select, so a legitimate area silently vanished from the new profile. #638 added an ownership guard to SaveAdminPickAsync and fixed seeding in the same commit, without noticing that seeding goes through that method: one user-scoped pick holding a built-in id aborted the seed partway, which is the failure the same commit had just fixed. Its localStorage seed marker was a per-browser flag for an installation-level fact, so a second admin reseeded anyway and a failed seed latched it forever; it is a site setting now, written by the endpoint that does the seeding. #614 bounded FortChangeCreate.ChangeTypes and left FortChangeUpdate beside it, and set MaxGruntTypeLength to 35 while calling it "the column width upstream" -- the column is varchar(255). An invented limit in the one fix whose whole rationale was refusing the impossible instead. Claude-Session: https://claude.ai/code/session_01CYyjpx2HzaZxMnYamkyoXX
Second run of the regression lens, over the fixes the first run produced. The worst is mine from an hour ago. ProfileController.Create validates the location and the area list AFTER calling AddProfileAsync, so both refusals answer 400 with the profile already created -- and because addProfile ignores `area`, that orphan comes up carrying the active profile's entire area list and location, the inheritance #563 exists to prevent. A retry makes another. So #647 replaced "a 201 that silently dropped areas" with "a 400 plus a profile nobody mentioned". Both checks now run before the create, and the create body carries the filtered list. The quick-pick seed marker moved to a site setting, and the local signal that reads it is only refreshed at app init -- so within the seeding session the key stayed absent and deleting the last pick restored all thirty. That is #634 again, minus the synchronous localStorage write that used to mask it. There was also no backfill, so an installation seeded under the old marker would reseed once after upgrading. Both closed, and the guard finally has the frontend tests it shipped without, which is why this got through. UserRoleResolver tracked two of its three sources, so a poracle_web blip returned a confident answer with an incomplete webhook list and cached it. The new sentinel also rendered in the admin settings page as an editable unknown setting, because that list is maintained separately from the controller's; migration_completed is in both and only one was updated. Claude-Session: https://claude.ai/code/session_01CYyjpx2HzaZxMnYamkyoXX
…672) (#673) Third run of the regression lens. Two findings, both small -- the curve across the three passes is 8, 5, 2, and this is the first pass with no regression of consequence and no missed siblings. The sameType gate added for #669 cleared every stored key on a type change, not just the departing type's filters. `clean` is read by the apply dialog as its base bitmask and is exposed by no form, so changing a pick's type silently reset its auto-delete, edit and summary bits -- the preservation #654 added, undone two commits later by the fix for #669. Type-agnostic keys now survive; `clean` is the only one. The backfill docstring is also corrected. It claimed to spare an admin who had deliberately deleted the presets before upgrading; that admin has no global picks, so there is nothing to infer from and they still get one reseed. The inline comment said so honestly while the docstring above it did not. The behaviour is right -- the old marker lived in a browser the server cannot see -- so only the documentation changes. Claude-Session: https://claude.ai/code/session_01CYyjpx2HzaZxMnYamkyoXX
…674) (#675) Fourth run of the regression lens. One finding, and it is against the comment the third run's fix shipped with rather than against its logic. TYPE_AGNOSTIC_FILTER_KEYS asserted that `clean` was the only key belonging to no alarm type. The codebase says otherwise in its own whitelist -- SafeMonsterFilterKeys lists form, gender, clean, template, distance, ping -- and Ping, Template and Distance are properties of all ten alarm models. They meet the exact test that justified preserving `clean`: read by a consumer, exposed by no per-type form, meaningful everywhere. `ping` is never overridden at apply time, because the apply dialog has no ping control. So changing a pick's type dropped its ping target and template. Not reachable in production today -- all thirty live definitions are the built-in presets and none carries any of the four keys -- but the claim was wrong in the direction that loses a user's settings, and the next definition created outside the admin dialog would have hit it. Claude-Session: https://claude.ai/code/session_01CYyjpx2HzaZxMnYamkyoXX
The lens found sixteen defects across five passes and existed only as an ad-hoc prompt typed each time, plus one sentence of prose in CLAUDE.md. It would have had to be re-derived from scratch next session, and the details that made it work are not obvious: scoping each pass to one batch of fixes, seeding it with the shapes it keeps finding, and telling it explicitly that a clean result is the desired outcome so it does not manufacture findings. .claude/ was ignored wholesale. Now only its contents are, with commands/ re-included -- git cannot re-include anything beneath an excluded directory, so the pattern had to become .claude/* for the negation to take effect. settings.local.json, worktrees/ and the task lock stay local. Claude-Session: https://claude.ai/code/session_01CYyjpx2HzaZxMnYamkyoXX
#677) * fix: the nightly prune was deleting released images, including :latest GHCR currently holds `beta` and 28 `develop-<sha>` tags and nothing else. No `latest`, no `2.13.0`, no version tags at all -- so every documented `docker compose up` fails to pull for anyone not already running an image. docker-publish.yml ran successfully on the v2.13.0 release and pushed those tags; the nightly prune then removed them. Cause: actions/delete-package-versions matches `ignore-versions` against a package version's NAME, and for container packages the name is the digest, never the tag. The ignore list protected nothing, so `min-versions-to-keep: 10` deleted every version older than the ten most recent pushes whatever it was tagged. Twenty merges to develop after a release was enough to take the release with it. The pattern was also written for `v`-prefixed semver while docker/metadata-action strips the `v`, so it would not have matched even if ignore-versions worked on tags. Rewritten as github-script, matching the prune-pr-images job above it: read metadata.container.tags and delete a version only when EVERY tag on it looks like develop-<sha>. A develop push tags one digest both `beta` and `develop-<sha>`, and a release tags one digest `latest`, `X.Y.Z`, `X.Y` and `<sha>` -- checking every tag is what keeps those safe. Ordering is sorted explicitly rather than assumed from the API, since which images get deleted depends entirely on it. Claude-Session: https://claude.ai/code/session_01CYyjpx2HzaZxMnYamkyoXX * docs: changelog entry for the prune fix Claude-Session: https://claude.ai/code/session_01CYyjpx2HzaZxMnYamkyoXX
…elease (#678) A release publishes :latest and redeploys production, so whatever the docs claim at that moment is what self-hosters act on. Auditing the whole surface against the code turned up a lot that had drifted, including several things this session's own fixes had invalidated. Install and setup instructions that did not work: the stable tag is :X.Y.Z, not :vX.Y.Z, because docker/metadata-action strips the leading v; the release page has no prebuilt archives to download, only source; `npm start` was plain `ng serve` with no proxy, so the documented dev workflow 404'd every /api call (fixed in package.json rather than in prose, since the docs described the intent); and the dev Discord redirect URI is the dev server's origin, not the API's, because the callback is built from the incoming Host header. Behaviour this session changed: the By Boss tab no longer has a level picker, a rejected geofence keeps alerting, approved and pending geofences cannot be renamed, telegram_bot is now a fallback for the login widget, and quick_picks_seeded exists. Test alerts were documented for all ten alarm types and support eight. Profile duplication was documented as NOT copying areas when #503 made it copy them -- in two docs and in the in-app help, in eleven locales. The in-app help also still described a Ping / Role Mentions control deleted in #494, listed Fort Changes as cleanable when the API refuses it, and called the admin Users tab Discord-only after #632 made it show every account. All eleven locale files carried each of those. Architecture docs claimed PoracleNG handles the area dual-write (it does not, for user geofences), that direct DB access is only for admin bulk operations (profile rename and the area writer are neither), and documented a ValidateActiveHours method that moved to Core.Models/ActiveHoursValidator. CI/CD docs said docker-publish.yml runs on push to main. It runs on release published and pushes to develop -- and on release it also SSHes to DEPLOY_HOST and redeploys production, which was documented nowhere and contradicts the watchtower note in CLAUDE.md. Contributors were told to clone and had no indication that work happens on develop; the branch table now lives in the docs tree rather than only README, because mkdocs cannot resolve links outside docs_dir. Claude-Session: https://claude.ai/code/session_01CYyjpx2HzaZxMnYamkyoXX
…679) The screenshot dated from April and showed Pause Alerts, Switch Profile, Areas & Location, Cleaning, Accent Theme and Logout. The menu has since gained Alert Defaults and a Language submenu, both of which are documented features -- the language selector is described elsewhere as living in this exact menu. Captured against a local mock API rather than a real instance. The .env on this machine points at production: booting the real API would run MigrateAsync and the settings migration against the production database, and any screenshot would put a real person's name, location and area list into a public repo. The mock serves synthetic demo data matching the original's framing (DocUser, Work Profile, the same viewport), so only the menu differs. Same 1440x900 as every other help image. Two visible differences from the old shot are configuration, not drift: the location card has no map thumbnail because the mock serves no tileserver URL and the img is conditionally rendered, and the toolbar has no custom-link icon because that is an operator-set site setting. The logout section also never mentioned "Sign out everywhere", the single logout entry that appears when the provider supports it. Added in all eleven locales, each quoting its own MENU.LOGOUT_EVERYWHERE label so the help matches the button the reader is looking at. Verified rendering in English and German in a browser, not just in the JSON. Claude-Session: https://claude.ai/code/session_01CYyjpx2HzaZxMnYamkyoXX
I claimed a few hours ago that publishing a release SSHes to DEPLOY_HOST and redeploys prod directly, "not watchtower", and changed CLAUDE.md to match. That was wrong, and it is the exact failure this codebase's own guidance warns about: I read the SSH step in docker-publish.yml and asserted a conclusion wider than the evidence, without checking whether the secret it depends on exists. It does not. `gh secret list` returns only the changelog app credentials, so the step hits its `if [ -z "$DEPLOY_HOST" ] ... exit 0` guard on every release and does nothing. Prod is deployed by watchtower polling :latest every 60 seconds, exactly as the original note said. Verified on the host: the watchtower container is up with WATCHTOWER_SCOPE=poracleweb and a 60s interval. The SSH step is still worth documenting, but as what it is -- an opt-in hook for anyone who prefers a push deploy to a polling agent. Claude-Session: https://claude.ai/code/session_01CYyjpx2HzaZxMnYamkyoXX
release: v2.14.0
Co-authored-by: hokiepokedad2 <38219945+hokiepokedad2@users.noreply.github.com>
* docs: document PROXY_KNOWN_PROXIES/PROXY_KNOWN_NETWORKS The 2.14.0 proxy-trust fix (#583) stopped honouring X-Forwarded-Proto from undeclared proxies. Instances that had never set these variables started building OAuth callback URLs as http://, and Discord rejected sign-in with an invalid redirect_uri. The variables existed but appeared in no example file, guide or reference. Adds them to .env.example, the configuration reference, the reverse-proxy section of standalone-setup, and a troubleshooting entry naming the exact Discord error. * feat: let deployments set the OAuth callback URL with PUBLIC_URL Callback URLs were derived from Request.Scheme/Host at nine sites in AuthController, so the only way to influence them was to declare the reverse proxy -- an indirect lever for a value the identity provider requires you to register anyway. Discord:RedirectUri looked like the setting for this but was read by nothing. PUBLIC_URL names the origin outright, feeding one SelfOrigin() helper used by both callback sites per provider, so the authorize request and the token exchange cannot drift apart. Unset behaviour is byte-identical to before, which keeps multi-hostname installs working -- deriving it from CORS_ORIGIN was considered and rejected, since the SPA calls the API same-origin and that value is never browser-validated, so it can name a host nobody uses. The cookie Secure flag deliberately still follows the actual request: forcing it from an https PUBLIC_URL would silently drop oauth_state for anyone reaching the instance over plain http on a LAN. Adds a warning when a callback is about to go out as http:// while an untrusted X-Forwarded-Proto: https is present -- the exact failing case, named, with both fixes in the message. Startup rejects an unusable PUBLIC_URL rather than emitting a callback the provider refuses without explanation. * docs: reference #689 in the changelog entries
) Bumps [jsdom](https://github.com/jsdom/jsdom) from 29.1.1 to 30.0.1. - [Release notes](https://github.com/jsdom/jsdom/releases) - [Commits](jsdom/jsdom@v29.1.1...v30.0.1) --- updated-dependencies: - dependency-name: jsdom dependency-version: 30.0.1 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
No target-branch was set on any of the four ecosystems, so all of them defaulted to the repository default branch. Dependency bumps therefore landed straight on main -- released code -- without being built as :beta or running on the dev instance first, which contradicts the branching model in CLAUDE.md where main only moves when a release is merged. It had already drifted: 7366906 (jsdom) sits on main and not on develop. It also routed every bump through the merge queue that exists only on main, which is where #683 and #686 are currently stuck despite being approved with all required checks green.
…#691) The Discord and SSO setup pages describe the callback as derived from the incoming request, which stopped being the whole story when PUBLIC_URL landed. Both are where someone registers the URI with their provider, so that is where the reverse-proxy caveat belongs.
Every help screenshot with the toolbar in it read "PoGO Alerts Network", and login.png showed it again as the 32px splash heading. PoracleWeb is self-hosted, so a self-hoster reading Help saw another network's name beside instructions about their own install. They now read "DM Alerts" -- not an invented placeholder but the app's own fallback, the string app.ts and AUTH.SITE_TITLE_DEFAULT produce when custom_title is unset. So the screenshots show what an unbranded install actually shows. Re-capturing was not possible (the shots are of a populated production account), so the title was replaced in place: the gradient behind it is rebuilt by interpolating between clean rows above and below the text, and the replacement glyphs were rendered by the same browser engine that took the screenshots. The two typefaces differ and both were confirmed by measuring the original ink: the toolbar title is Roboto 500 16px (151px wide, Roboto measures 152, Plus Jakarta Sans 164) and the login heading is Plus Jakarta Sans 300 32px with 1px tracking (343px wide, PJS measures 346, Roboto 315). Placement is fitted by minimising residual against the original rather than assumed. sidenav.png is untouched -- it is cropped below the toolbar and has no title in it. The second half: the shots are captured at 1440px and drawn in a ~770px column, so the detail each one exists to point at rendered at half size. Clicking a screenshot now opens it full size in a dialog. The section bodies are injected with [innerHTML] from the translation bundles, so no per-image binding is possible -- click and keydown are delegated from the host, and an afterRenderEffect marks each screenshot focusable with role=button. It re-runs on language change and on search, both of which replace that HTML. Enter and Space open the viewer, so the feature is not mouse-only. Closes #694
The map fitted the bounds of every fence in the geofence feed. On a single-city instance that looks like a sensible default; prod's feed carries 830 fences from Kapolei, Hawaii to Summerland Point, Australia, so the fit is the whole planet. At that zoom no polygon is more than a pixel and none of them can be clicked -- the page's one job. The feed only grows, so no zoom constant fixes this. The opening view is now ranked: the areas you have selected, then your own geofences, then your pinned location at zoom 11, and only then everything. A fit is capped at zoom 13 so a small user-drawn geofence does not open at street level with no context to work against. Two details carry the regression risk, so the ranking lives in a pure function with its own tests: A fit only ever upgrades. The Areas page loads the feed and the selection from independent requests -- the map is routinely on screen before the selection lands -- so without an upgrade the map would fit everything, mark itself done, and never recover, intermittently, depending on which response won. Because a fit only upgrades, a selection changing at the same rank cannot move the map, so toggling an area still only restyles it. Re-fitting on every toggle would yank the map out from under the cursor. Closes #693
The other half of #694. All 41 shots under docs/screenshots/ that show a toolbar read "PoGO Alerts Network", and login.png showed it again as the splash heading, so the documentation illustrated how to host your own instance with pictures of somebody else's. They now read "DM Alerts" -- the app's own fallback when custom_title is unset, so the docs show what a fresh install shows. Same in-place replacement as #696: the gradient behind the text is rebuilt by interpolating between clean rows above and below it, and the glyphs were rendered by the browser engine that took the shots. Three layouts, each measured rather than assumed: - 34 desktop captures at 1440x900 plus the 1440x64 toolbar strip, title at x97-247 y19-30. Nine *-add-dialog.png carry the same title under the dialog scrim; the replacement is drawn in the dimmed colour sampled from the original rather than in white. - 6 mobile captures at 390x844. The toolbar is shorter and drops the subtitle, so the title sits two rows lower at x85-235 y21-32. - login.png, splash heading at x549-891 y350-374. sidenav.png is untouched -- it is cropped below the toolbar. Closes #697
Release 2.15.0
docs: cut changelog for v2.15.0
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.