f07c15972c90f48eb60909a915dd9659d035451d
2116
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f07c15972c |
chore(deps): bump fastlane from 2.237.0 to 2.238.0 (#326)
Bumps [fastlane](https://github.com/fastlane/fastlane) from 2.237.0 to 2.238.0. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/fastlane/fastlane/releases">fastlane's releases</a>.</em></p> <blockquote> <h2>2.238.0 Improvements</h2> <ul> <li>[ci] support releases with PRs that were deleted (or users) (<a href="https://redirect.github.com/fastlane/fastlane/issues/30105">#30105</a>) via Connor Tumbleson (<a href="https://github.com/iBotPeaches"><code>@iBotPeaches</code></a>)</li> <li>[pilot] Match groups by either name or id (<a href="https://redirect.github.com/fastlane/fastlane/issues/30104">#30104</a>) via Alexander Chapliuk (<a href="https://github.com/krin-san"><code>@krin-san</code></a>)</li> <li>[update_project_team] add support for sdk conditionals (<a href="https://redirect.github.com/fastlane/fastlane/issues/30142">#30142</a>) via Connor Tumbleson (<a href="https://github.com/iBotPeaches"><code>@iBotPeaches</code></a>)</li> <li>harden: detected non-static command inside ` in... (<a href="https://redirect.github.com/fastlane/fastlane/issues/30148">#30148</a>) via Anupam Mediratta (<a href="https://github.com/anupamme"><code>@anupamme</code></a>)</li> <li>[fastlane_core] Create a unique package directory for non-macOS uploads (<a href="https://redirect.github.com/fastlane/fastlane/issues/30144">#30144</a>) via Victor Amorim dos Santos (<a href="https://github.com/victoramsantos"><code>@victoramsantos</code></a>)</li> <li>[gem] move to webrick 1.9.x (<a href="https://redirect.github.com/fastlane/fastlane/issues/30135">#30135</a>) via Connor Tumbleson (<a href="https://github.com/iBotPeaches"><code>@iBotPeaches</code></a>)</li> <li>[gem] upgrade 'terminal-table' to drop monkey patch (<a href="https://redirect.github.com/fastlane/fastlane/issues/30137">#30137</a>) via Connor Tumbleson (<a href="https://github.com/iBotPeaches"><code>@iBotPeaches</code></a>)</li> <li>[core] Fix video resolution parsing when audio track precedes video track (<a href="https://redirect.github.com/fastlane/fastlane/issues/30143">#30143</a>) via Thomas Walther (<a href="https://github.com/tcwalther"><code>@tcwalther</code></a>)</li> <li>[gym] Fix Mac Catalyst package type detection when catalyst_platform is not set (<a href="https://redirect.github.com/fastlane/fastlane/issues/29829">#29829</a>) via Josh Holtz (<a href="https://github.com/joshdholtz"><code>@joshdholtz</code></a>)</li> <li>[deliver/pilot] change instruction on how to run iTMSTransporter (<a href="https://redirect.github.com/fastlane/fastlane/issues/21155">#21155</a>) via Merlin Ran (<a href="https://github.com/merlinran"><code>@merlinran</code></a>)</li> <li>[gem] move to sinatra 4 (<a href="https://redirect.github.com/fastlane/fastlane/issues/30134">#30134</a>) via Connor Tumbleson (<a href="https://github.com/iBotPeaches"><code>@iBotPeaches</code></a>)</li> <li>[action][spm] add <code>--skip-update</code> (<a href="https://redirect.github.com/fastlane/fastlane/issues/21127">#21127</a>) via Atsuto Yamashita (<a href="https://github.com/att55"><code>@att55</code></a>)</li> <li>Fix precheck copyright rule wording (<a href="https://redirect.github.com/fastlane/fastlane/issues/19500">#19500</a>) via Andreas Ganske (<a href="https://github.com/ChaosCoder"><code>@ChaosCoder</code></a>)</li> <li>docs: add detailed notation of what metrics collected (<a href="https://redirect.github.com/fastlane/fastlane/issues/30132">#30132</a>) via Connor Tumbleson (<a href="https://github.com/iBotPeaches"><code>@iBotPeaches</code></a>)</li> <li>Bump actions/labeler from 6 to 7 (<a href="https://redirect.github.com/fastlane/fastlane/issues/30133">#30133</a>) via dependabot[bot] (<a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot])</li> <li>[upload_symbols_to_crashlytics] Adds option to let the action fail when an upload fails (<a href="https://redirect.github.com/fastlane/fastlane/issues/29700">#29700</a>) via Tobias Kreß (<a href="https://github.com/Myrronth"><code>@Myrronth</code></a>)</li> <li>[deliver] add support for social media rating keys (<a href="https://redirect.github.com/fastlane/fastlane/issues/30128">#30128</a>) via Connor Tumbleson (<a href="https://github.com/iBotPeaches"><code>@iBotPeaches</code></a>)</li> <li>[core] Support for Ruby 4 (+ testing) (<a href="https://redirect.github.com/fastlane/fastlane/issues/29849">#29849</a>) via Connor Tumbleson (<a href="https://github.com/iBotPeaches"><code>@iBotPeaches</code></a>)</li> <li>[register_devices] Ignore blank lines and comment lines in devices_file (<a href="https://redirect.github.com/fastlane/fastlane/issues/30129">#30129</a>) via David Cordero (<a href="https://github.com/dcordero"><code>@dcordero</code></a>)</li> <li>[core] detect installed Developer ID intermediate certificates by their common name (<a href="https://redirect.github.com/fastlane/fastlane/issues/30126">#30126</a>) via Rinat Kutuev (<a href="https://github.com/ReilganInt"><code>@ReilganInt</code></a>)</li> <li>[core] move to xcodeproj 1.28.1 (from 1.27.0) (<a href="https://redirect.github.com/fastlane/fastlane/issues/30124">#30124</a>) via Nuno de Carvalho (<a href="https://github.com/nmcc24"><code>@nmcc24</code></a>)</li> <li>[core] normalize FastlaneSwiftRunner.xcodeproj plist quoting (<a href="https://redirect.github.com/fastlane/fastlane/issues/30125">#30125</a>) via Nuno de Carvalho (<a href="https://github.com/nmcc24"><code>@nmcc24</code></a>)</li> <li>[register_devices] Register devices normalization for UDIDs. (<a href="https://redirect.github.com/fastlane/fastlane/issues/29981">#29981</a>) via Muhammet Ilendemli (<a href="https://github.com/ilendemli"><code>@ilendemli</code></a>)</li> <li>[crashlytics] improve logging during error (<a href="https://redirect.github.com/fastlane/fastlane/issues/30077">#30077</a>) via Connor Tumbleson (<a href="https://github.com/iBotPeaches"><code>@iBotPeaches</code></a>)</li> <li>[setup_ci] Add option to opt out of setting the default keychain (<a href="https://redirect.github.com/fastlane/fastlane/issues/30121">#30121</a>) via Eyüp Can Akman (<a href="https://github.com/eyupcanakman"><code>@eyupcanakman</code></a>)</li> <li>[snapshot] Open the requested simulator for non-headless runs (<a href="https://redirect.github.com/fastlane/fastlane/issues/30119">#30119</a>) via huven (<a href="https://github.com/huven"><code>@huven</code></a>)</li> <li>[core] improve operating_system detection (<a href="https://redirect.github.com/fastlane/fastlane/issues/30118">#30118</a>) via Connor Tumbleson (<a href="https://github.com/iBotPeaches"><code>@iBotPeaches</code></a>)</li> <li>[core] fix: upgrade yard to >= 0.9.42 (CVE-2026-41493) (<a href="https://redirect.github.com/fastlane/fastlane/issues/30117">#30117</a>) via OrbisAI Security (<a href="https://github.com/orbisai0security"><code>@orbisai0security</code></a>)</li> <li>[core] move to Faraday 2 (<a href="https://redirect.github.com/fastlane/fastlane/issues/30089">#30089</a>) via Connor Tumbleson (<a href="https://github.com/iBotPeaches"><code>@iBotPeaches</code></a>)</li> <li>[docs] clarify platform resolution behavior (<a href="https://redirect.github.com/fastlane/fastlane/issues/22185">#22185</a>) via Douglas Hill (<a href="https://github.com/douglashill"><code>@douglashill</code></a>)</li> <li>[core] fix crash when uploading large <code>.pkg</code> by using <code>Digest::MD5.file</code> instead of <code>Digest::MD5.hexdigest</code> (<a href="https://redirect.github.com/fastlane/fastlane/issues/21999">#21999</a>) via reflexing (<a href="https://github.com/reflexing"><code>@reflexing</code></a>)</li> <li>[docs] fix a missing negation in <code>pilot</code> error message (<a href="https://redirect.github.com/fastlane/fastlane/issues/22331">#22331</a>) via Gemma Barlow (<a href="https://github.com/gemmakbarlow"><code>@gemmakbarlow</code></a>)</li> <li>[notarize] Fix erroring out with <code>bundle_id</code> parameter being absent (<a href="https://redirect.github.com/fastlane/fastlane/issues/29736">#29736</a>) via Timur Sharifianov (<a href="https://github.com/Scvairy"><code>@Scvairy</code></a>)</li> <li>[metrics] move to GA4 and improve metrics (<a href="https://redirect.github.com/fastlane/fastlane/issues/30111">#30111</a>) via Connor Tumbleson (<a href="https://github.com/iBotPeaches"><code>@iBotPeaches</code></a>)</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/fastlane/fastlane/commit/38d0ec404332cce7a4833881eee343e9de91700c"><code>38d0ec4</code></a> Version bump to 2.238.0 (<a href="https://redirect.github.com/fastlane/fastlane/issues/30151">#30151</a>)</li> <li><a href="https://github.com/fastlane/fastlane/commit/d967cd80625e950b39668ec272f5530bc56c60df"><code>d967cd8</code></a> [ci] support releases with PRs that were deleted (or users) (<a href="https://redirect.github.com/fastlane/fastlane/issues/30105">#30105</a>)</li> <li><a href="https://github.com/fastlane/fastlane/commit/4eadc97560f1d798306e608fd33ff3045841ad8f"><code>4eadc97</code></a> [pilot] Match groups by either name or id (<a href="https://redirect.github.com/fastlane/fastlane/issues/30104">#30104</a>)</li> <li><a href="https://github.com/fastlane/fastlane/commit/a43b8b8bfdf06737f49b2a48360b78ab88126fe5"><code>a43b8b8</code></a> [update_project_team] add support for sdk conditions (<a href="https://redirect.github.com/fastlane/fastlane/issues/30142">#30142</a>)</li> <li><a href="https://github.com/fastlane/fastlane/commit/f1568f9b2069df1551e8286c4c52be6b8823bc98"><code>f1568f9</code></a> [fastlane_core] harden plugin_scores subshell usage (<a href="https://redirect.github.com/fastlane/fastlane/issues/30148">#30148</a>)</li> <li><a href="https://github.com/fastlane/fastlane/commit/25026b9be2deb9df1de0675215b405933952edbf"><code>25026b9</code></a> [fastlane_core] Create a unique package directory for non-macOS uploads (<a href="https://redirect.github.com/fastlane/fastlane/issues/30144">#30144</a>)</li> <li><a href="https://github.com/fastlane/fastlane/commit/283d477bc6d3566e3a07a9f8e97b8d747b16a3e5"><code>283d477</code></a> [gem] move to webrick 1.9.x (<a href="https://redirect.github.com/fastlane/fastlane/issues/30135">#30135</a>)</li> <li><a href="https://github.com/fastlane/fastlane/commit/bc098d142eb3c78b1608db4161fa68a00816affc"><code>bc098d1</code></a> [gem] upgrade 'terminal-table' to drop monkey patch (<a href="https://redirect.github.com/fastlane/fastlane/issues/30137">#30137</a>)</li> <li><a href="https://github.com/fastlane/fastlane/commit/1f64c1f8e24dbc7b2e64317cc4fae563d1c2e3c6"><code>1f64c1f</code></a> [fastlane_core] Fix video resolution parsing when audio track precedes video ...</li> <li><a href="https://github.com/fastlane/fastlane/commit/a94b3ada721f7b8a10cc4a865bd2fe13533e5e79"><code>a94b3ad</code></a> [gym] Fix Mac Catalyst package type detection when catalyst_platform is not s...</li> <li>Additional commits viewable in <a href="https://github.com/fastlane/fastlane/compare/fastlane/2.237.0...fastlane/2.238.0">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jeppe B <2jepp9350@gmail.com> |
||
|
|
210d7d051d |
chore(deps): bump slackapi/slack-github-action from 1.27.0 to 4.0.0 (#323)
Bumps [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action) from 1.27.0 to 4.0.0. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/slackapi/slack-github-action/releases">slackapi/slack-github-action's releases</a>.</em></p> <blockquote> <h2>Slack GitHub Action v4.0.0</h2> <h3>Major Changes</h3> <ul> <li> <p>b1974f0: build: parse yaml with more strict multiline indentation rules</p> <p>Internal dependencies of <a href="https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md#500---2026-06-20"><code>js-yaml@v5</code></a> make YAML parsing more strict and compliant with the YAML specification. Indentation is now required for values that span multiple lines against the base value.</p> <p>See the YAML <a href="https://yaml.org/spec/1.2.2/#63-line-prefixes">line prefixes</a> spec for the expected indentation rule:</p> <pre lang="diff"><code> channel: "C0123" text: "first line <ul> <li>second line"</li> </ul> <ul> <li>second line"<br /> </code></pre></li> </ul> </li> </ul> <h3>Patch Changes</h3> <ul> <li>654bb72: chore: provide global fetch proxied configurations with updates to web api and webhook packages</li> </ul> <h2>Slack GitHub Action v3.0.5</h2> <h3>Patch Changes</h3> <ul> <li>96fddbe: fix: revert multiline yaml parsing indentation change</li> </ul> <h2>Slack GitHub Action v3.0.4</h2> <h3>Patch Changes</h3> <ul> <li>fa03fe4: refactor: send webhooks with the <a href="https://docs.slack.dev/tools/node-slack-sdk/webhook"><code>@slack/webhook</code></a> package</li> </ul> <h2>Slack GitHub Action v3.0.3</h2> <h3>Patch Changes</h3> <ul> <li>66834e4: feat: add instrumentation to address error rates</li> </ul> <h2>Slack GitHub Action v3.0.2</h2> <h3>Patch Changes</h3> <ul> <li>79529d7: fix: resolve url.parse deprecation warning for webhook techniques</li> </ul> <h2>Slack GitHub Action v3.0.1</h2> <h2>What's Changed</h2> <p>Alongside the breaking changes of <a href="https://github.com/slackapi/slack-github-action/releases/tag/v3.0.0"><code>@v3.0.0</code></a> and a <a href="https://docs.slack.dev/tools/slack-github-action/sending-techniques/running-slack-cli-commands/">new technique</a> to run Slack CLI commands, we tried the wrong name to publish to the GitHub Marketplace 🐙 This action is now noted as <a href="https://github.com/marketplace/actions/the-slack-github-action"><strong>The Slack GitHub Action</strong></a> in listings 🎶 ✨</p> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/slackapi/slack-github-action/blob/main/CHANGELOG.md">slackapi/slack-github-action's changelog</a>.</em></p> <blockquote> <h2>4.0.0</h2> <h3>Major Changes</h3> <ul> <li> <p>b1974f0: build: parse yaml with more strict multiline indentation rules</p> <p>Internal dependencies of <a href="https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md#500---2026-06-20"><code>js-yaml@v5</code></a> make YAML parsing more strict and compliant with the YAML specification. Indentation is now required for values that span multiple lines against the base value.</p> <p>See the YAML <a href="https://yaml.org/spec/1.2.2/#63-line-prefixes">line prefixes</a> spec for the expected indentation rule:</p> <pre lang="diff"><code> channel: "C0123" text: "first line <ul> <li>second line"</li> </ul> <ul> <li>second line"<br /> </code></pre></li> </ul> </li> </ul> <h3>Patch Changes</h3> <ul> <li>654bb72: chore: provide global fetch proxied configurations with updates to web api and webhook packages</li> </ul> <h2>3.0.5</h2> <h3>Patch Changes</h3> <ul> <li>96fddbe: fix: revert multiline yaml parsing indentation change</li> </ul> <h2>3.0.4</h2> <h3>Patch Changes</h3> <ul> <li>fa03fe4: refactor: send webhooks with the <a href="https://docs.slack.dev/tools/node-slack-sdk/webhook"><code>@slack/webhook</code></a> package</li> </ul> <h2>3.0.3</h2> <h3>Patch Changes</h3> <ul> <li>66834e4: feat: add instrumentation to address error rates</li> </ul> <h2>3.0.2</h2> <h3>Patch Changes</h3> <ul> <li>79529d7: fix: resolve url.parse deprecation warning for webhook techniques</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/slackapi/slack-github-action/commit/dcb1066f776dd043e64d0e8ba94ca15cc7e1875d"><code>dcb1066</code></a> chore: release</li> <li><a href="https://github.com/slackapi/slack-github-action/commit/53861e0291660faf57ba686eabf046d5a47fa304"><code>53861e0</code></a> chore: release (<a href="https://redirect.github.com/slackapi/slack-github-action/issues/645">#645</a>)</li> <li><a href="https://github.com/slackapi/slack-github-action/commit/b1974f0d29f2b6150fc5a376312d365bd75fdd9b"><code>b1974f0</code></a> build!: parse yaml with more strict multiline indentation rules (<a href="https://redirect.github.com/slackapi/slack-github-action/issues/640">#640</a>)</li> <li><a href="https://github.com/slackapi/slack-github-action/commit/947ed0677cba8e56cf374d88bfd2d8f72aa9100c"><code>947ed06</code></a> build(deps): bump undici from 7.28.0 to 8.7.0 (<a href="https://redirect.github.com/slackapi/slack-github-action/issues/653">#653</a>)</li> <li><a href="https://github.com/slackapi/slack-github-action/commit/03922a90c917c4d3d3b1c0f35984c2ac23955560"><code>03922a9</code></a> chore: track undici-types to the resolved undici version (<a href="https://redirect.github.com/slackapi/slack-github-action/issues/652">#652</a>)</li> <li><a href="https://github.com/slackapi/slack-github-action/commit/31d473e1d0da2837ee5149493a62a54103e5b45a"><code>31d473e</code></a> build(deps-dev): bump typescript from 6.0.3 to 7.0.2 (<a href="https://redirect.github.com/slackapi/slack-github-action/issues/651">#651</a>)</li> <li><a href="https://github.com/slackapi/slack-github-action/commit/3ca6997fb72e86b0babe7037ff2ca4a5908b6148"><code>3ca6997</code></a> build(deps-dev): bump sinon and <code>@types/sinon</code> (<a href="https://redirect.github.com/slackapi/slack-github-action/issues/649">#649</a>)</li> <li><a href="https://github.com/slackapi/slack-github-action/commit/26a5ad3c5af9cde63a5bb0667fc9e40accce2710"><code>26a5ad3</code></a> build(deps): bump actions/setup-node from 6.4.0 to 7.0.0 (<a href="https://redirect.github.com/slackapi/slack-github-action/issues/647">#647</a>)</li> <li><a href="https://github.com/slackapi/slack-github-action/commit/5092efb0558a5d075f0dd02279f332a116a461ef"><code>5092efb</code></a> build(deps-dev): bump <code>@biomejs/biome</code> from 2.5.3 to 2.5.4 (<a href="https://redirect.github.com/slackapi/slack-github-action/issues/650">#650</a>)</li> <li><a href="https://github.com/slackapi/slack-github-action/commit/3548c3e9500515cd56aa64222b12088f5e6bd6fe"><code>3548c3e</code></a> build(deps): bump slackapi/slack-github-action from 3.0.3 to 3.0.5 (<a href="https://redirect.github.com/slackapi/slack-github-action/issues/646">#646</a>)</li> <li>Additional commits viewable in <a href="https://github.com/slackapi/slack-github-action/compare/v1.27.0...v4.0.0">compare view</a></li> </ul> </details> <br /> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
0d2098449a |
chore(release): prepare v1.1.0 — bump marketing version, enable submit_for_review (#327)
Squash-merged by OpenClaw on behalf of Jeppe for v1.1.0 release. |
||
|
|
cafe671e85 |
feat(pleno-vue): add driver/subuser login button (mobile-visible) (TRU-61) (#321)
## Why
Drivers (sub-users) could not reliably reach the driver login from the
customer login page (/login) on mobile devices. The form contained an
internal driver button, but it sat below the QR code and passkey
buttons, making it easy to miss on small screens. The desktop sidebar
layout further reduced discoverability.
## What changed
- **src/views/auth/Login.vue** — Add a page-level .driver-entry block
below the customer login form, with a router-link to { name:
'subuserlogin' }. Distinct color (#1584BC) and a truck icon match the
existing LandingPage driver entry pattern. Full-width on mobile (<768px)
so it's impossible to miss.
- **i18n** — Add auth.driver_login_help to en, da, de, no, sv locale
files + global shared auth index. auth.driver_login_button already
existed in all locales.
- **tests/unit/login-driver-entry.spec.js** — 5 Vitest tests verifying
the driver entry block, router-link, button label, help text, and
placement (not in sidebar).
## CI
- Vitest unit tests pass (5/5 new tests, existing tests unaffected)
- ESLint clean
- Text encoding check clean
- i18n v2 source check + compile clean
Co-authored-by: Pleno Bugfix Bot <bugfix-bot@pleno.local>
|
||
|
|
2401ebb674 |
TRU-96: Sergii Review Batch smoke test for truckwash.io dashboard (#320)
## Summary
Adds a Sergii-specific smoke test that validates the **Sergii Review
Batch** project surfaces (Linear project `Sergii Review Batch` — TRU-68,
TRU-72, TRU-75) are still functioning on the deployed truckwash.io
dashboard after a release. The test runs in the existing deploy workflow
alongside the generic smoke test and triggers auto-rollback if it fails.
## Why
TRU-96 ("SENERE 4: Deploy Sergii changes to truckwash.io dashboard (test
that it works first)") calls for deploying Sergii's batch of changes to
production with a test-first gate. The current generic
`scripts/smoke-test.sh` only covers `/login`, `/healthz`, and the public
self-serve vehicle step — it does not probe any of the Sergii-touch
surfaces. This PR closes that gap.
## What ships
| File | Purpose |
|---|---|
| `scripts/smoke-test-sergii.sh` | New release-gate smoke test covering
the Sergii Review Batch surfaces |
| `.github/workflows/deploy.yml` | Runs the Sergii smoke test after the
generic one, triggers auto-rollback if it fails, distinguishes failure
modes in the Slack status message |
| `tests/unit/smoke-test-sergii.spec.js` | 9 vitest assertions that lock
the script content and the deploy.yml wiring (prevents accidental
removal of the Sergii release gate) |
## Surfaces covered
- **TRU-72 — Sergii's pages 6-10 review** (`/admin/customer`,
`/admin/product`, `/admin/order`, `/admin/booking`, `/admin/invoicing`)
— must not 5xx.
- **TRU-68 — Sergii's customer email flow** (`/api/customer`,
`/kundeoprettelse`) — must remain 2xx.
- **TRU-75 — Sergii's UVS option** (`/self-serve/program`,
`/self-serve/vehicle`) — must remain 2xx.
- **Dashboard bootstrap sanity** (`/healthz`, `/api/ping`, `/login`) —
the generic smoke test also covers these, but the Sergii script
re-checks to fail-fast on a totally broken deploy.
## Behaviour
- Defaults to `https://staging.truckwash.io` and respects
`SMOKE_BASE_URL` and `SMOKE_TIMEOUT` env vars.
- Exits 0 on all-pass, 1 on any failure.
- `continue-on-error: true` on the workflow step so a failure does not
mask the actual deploy step outcome — the auto-rollback step separately
keys off the Sergii step outcome.
- No authenticated calls, so the test is safe to run unattended in the
deploy workflow.
## Test
```
npx vitest run tests/unit/smoke-test-sergii.spec.js
```
→ **9/9 passed** in 487ms.
## Linked Linear issues
- TRU-96 — https://linear.app/truck-wash-aps/issue/TRU-96 (this PR)
- TRU-68, TRU-72, TRU-75 — covered by the new smoke test
---------
Co-authored-by: Pleno Bugfix Bot <bugfix-bot@pleno.local>
Co-authored-by: Truck Wash Bugfix <bugfix@truckwash.io>
|
||
|
|
6f39eb897c |
fix(pleno-vue): make wax product title brand-agnostic (TRU-130) (#319)
## Summary
Customer experience series report (TRU-130, Slack
`#alle_tw_alle_afdelinger` ts `1786629381.499969`) noted that the wax
product ("Højglans - Voksforsegling pr. enhed", product_id 26) tested
poorly in the field and the operations team is trialing a different wax
supplier.
While the API payload drives the actual daily-report product title, the
`FALLBACK_PRODUCT_TITLES` map in the Vue display component and the
matching e2e expectations still hardcoded the failed brand name. After
the supplier swap the tile would have shown a stale brand even when the
API reports the new product, and the test expectations would have failed
on legitimate label updates.
## Changes
-
`src/views/dashboards/departmentDashboard/modules/daily-report/displays/DepartmentDashboardDailyReportProductSales.vue`
- Drop the `Højglans - ` prefix from the product 26 fallback title so
the tile stays accurate while the wax supplier is iterated on.
- Add a TRU-130 reference comment explaining the choice.
- `src/components/displays/department/pos/displays/Piktogrammer.vue`
- Update the product 26 comment to be brand-agnostic.
- `tests/e2e/admin-daily-report.spec.ts`
- Update the two `daily-report-tile-hoejglans` expectations to match the
new fallback title.
- `tests/unit/department-daily-report-product-sales.behavior.spec.js`
- Add a regression test that locks the brand-agnostic fallback for
product 26.
## Verification
- `npx vitest run
tests/unit/department-daily-report-product-sales.behavior.spec.js` → 5
tests passed (including the new TRU-130 case).
## Linked Linear issue
TRU-130 — https://linear.app/truck-wash-aps/issue/TRU-130
Co-authored-by: Pleno Bugfix Bot <bugfix-bot@pleno.local>
|
||
|
|
670746d70c |
fix(pleno-vue): propagate department selector to Selvvask usage query (TRU-11) (#317)
## Summary
Fixes TRU-11: when the department selector on the dashboard changes, the
Selvvask (self-wash) usage view did not re-query with the new
department. Both the orders list and the summary cards were bound to the
original department because the `HallId` filter was applied only once at
component setup.
## Root cause
`XLVaskUsagePagination.vue` derived `effectiveDepartmentId` once at
setup time and called `setFilter('HallId', ...)` a single time. There
was no `watch` on the department, so changing the `departmentId` prop or
the `departmentId` route param left the filter and the previously loaded
list untouched.
## Fix
- Convert `routeDepartmentId` and `effectiveDepartmentId` to `computed`
properties so they react to changes in the prop and the route param.
- Add a `watch(effectiveDepartmentId, ...)` that:
- Calls `setFilter('HallId', newId, false)` to update the filter, or
`setFilter('HallId', '*', false)` when the department is unset.
- Calls `loadList()` and `loadSummary()` to re-issue the Selvvask usage
query and refresh the summary cards.
- Pass the active department to the summary endpoint
(`/modules/xlvask/services/usage/orders/summary`) so the summary counts
also track the new department.
## Tests
Added
`tests/unit/xlvask-usage-pagination-department-propagation.spec.js` with
5 source-based assertions covering the computed department, the watcher,
the loadList/loadSummary re-issuance, the unset case, and the summary
params.
```
$ npx vitest run tests/unit/xlvask-usage-pagination-department-propagation.spec.js
✓ XLVaskUsagePagination department (HallId) propagation
✓ reacts to department changes via a computed effectiveDepartmentId
✓ watches the effective department and re-applies the HallId filter
✓ re-issues the usage query when the department changes
✓ clears the HallId filter when the department is unset
✓ includes the active department in the summary query params
Test Files 1 passed (1)
Tests 5 passed (5)
```
Existing related specs still pass (`xlvask-usage-pagination-404`,
`self-serve-pagination-machine-scope`, `pagination-date-selection`).
## Out of scope
`InvoicingBillingPeriodViewSelfWash.vue` does not pass `departmentId`
directly; department propagation there goes through the route or any
future parent selector. The fix in `XLVaskUsagePagination` covers all
current callers (`DepartmentPosSync.vue` and any future parent that
passes the prop or sets the route param).
## Refs
- Linear: TRU-11
- AUT-7
---------
Co-authored-by: Jeppe B <jeppe@copenhagentruckwash.io>
Co-authored-by: Pleno Bugfix Bot <bugfix-bot@pleno.local>
Co-authored-by: jeppemaxclaw[bot] <bot@jeppemaxclaw.local>
|
||
|
|
a345d91ae4 |
feat(pleno-vue): warning on red cars (TRU-99) (#318)
## Summary
Closes (heuristic for) **TRU-99 / SENERE 7**: warn operators in the
customer portal wash flow when a customer is flagged as a red car.
## Detection rule — heuristic, Mads to refine
The canonical rule (plate scan vs. red-car tag) is still TBD by Mads. As
a sensible default that fits the existing data model, this PR uses a
**manual customer-attribute flag**:
- If a customer has one of the configurable attribute keys set, the
warning fires. Default keys: `isRedCar`, `is_red_car`, `redCar`,
`red_car`.
- Detection is **case-insensitive** and the key list is **configurable**
(callers can override) so the rule can be tightened later without
touching the UI.
- Detection lives in `src/composables/redCarDetector.js`; reactive
loading lives in `src/composables/useRedCarWarning.js`.
- The composable reuses the existing `/customer/attributes` endpoint via
`customerAttributeService.js` — no backend change needed.
## UI
- New `RedCarWarning.vue` component renders a dismissable Buefy warning
in the vehicle step of the self-serve flow, with title + reason + care
suggestion.
- Wired into `MyWashStart.vue` via the existing `VehicleInputSection` /
`SelfServeVehicleStep` props. The composable is called with the
effective customer number (authenticated subuser or typed-in).
- Translations added in all 5 locales: `da`, `en`, `sv`, `de`, `no`
(source + regenerated runtime files).
## Tests
- 22 detector unit tests (positive, negative, case-insensitive, custom
keys, dedupe, normalisation).
- 5 i18n key presence tests across all 5 locales.
- 4 `RedCarWarning` component tests (conditional render, dismiss
wiring).
All new + existing related tests pass: `vitest run` on
`red-car-detector`, `red-car-warning-i18n`, `red-car-warning`,
`my-wash-start`, `customer-rule-registry`, `customer-rule-tooltip` →
**84/84 green**.
## Out of scope / not touched
- Backend / API: reused existing `/customer/attributes` endpoint.
- `openclaw.json`, deployment, merge — not touched (per task
constraints).
- Customer-rule registry: not added to `CUSTOMER_RULE_DEFINITIONS`
because the red-car flag is a soft warning, not a product-restriction
rule. If Mads wants it surfaced in the customer rule manager UI, that is
a follow-up.
## Files
- `src/composables/redCarDetector.js` (new)
- `src/composables/useRedCarWarning.js` (new)
- `src/components/displays/selfServe/RedCarWarning.vue` (new)
- `src/components/displays/selfServe/SelfServeVehicleStep.vue` (prop +
render)
-
`src/views/dashboards/userDashboard/wash/components/VehicleInputSection.vue`
(prop pass-through)
- `src/views/dashboards/userDashboard/wash/MyWashStart.vue` (composable
+ prop binding)
- `src/i18n/source/{da,en,sv,de,no}/phrases/compat/self_wash/index.json`
(new keys)
- `src/i18n/generated/{da,en,sv,de,no}-v2.json` (regenerated)
- `tests/unit/red-car-detector.spec.js` (new)
- `tests/unit/red-car-warning-i18n.spec.js` (new)
- `tests/unit/red-car-warning.spec.js` (new)
Refs: TRU-99
---------
Co-authored-by: Jeppe B <jeppe@copenhagentruckwash.io>
Co-authored-by: Frontend Subagent <frontend-agent@openclaw.local>
Co-authored-by: Pleno Bugfix Bot <bugfix-bot@pleno.local>
|
||
|
|
19fbbcddce |
test(pleno-vue): snapshot-lock SELF_SERVE_TASK_BUTTON_OPTIONS shape (TRU-19) (#316)
Adds a snapshot test that locks the full {id, name, description} triple for every entry in SELF_SERVE_TASK_BUTTON_OPTIONS. The previous test only checked counts and that the ids were sequential; this test catches reordering, renames, and unexpected entries as well.
The wash bay exposes 12 programs and 3 special buttons (reset / program picker / start). The dashboard renders one entry per program number from this array, so the entire array must remain exactly 15 entries long.
Test result: 10/10 vitest passed (was 9, +1 new snapshot test)
Refs TRU-19
|
||
|
|
7817f0c13b |
fix(pleno-vue): widen flagged-wash date window to ±7d (TRU-10) (#315)
Closes the user-reported symptom where washes spanning midnight fell outside the visible date window when navigating from an invoice-period flag. Changes: - Add FLAGGED_WASH_DATE_WINDOW_DAYS = 7 constant - Add shiftDateOnly() helper that pads an ISO-8601 date by ±N days (UTC math, no DST drift) - initialDateFrom/initialDateTo now compute [start - 7d, start + 7d] when a flagged wash is in the route - Add vitest source assertion to lock the new behavior Test result: 68/68 vitest passed (was 67, +1 new test) Refs TRU-10 |
||
|
|
c19aeffb98 |
fix(i18n): add no_xlvask_usage_log_metadata to en, de, no, sv locales (#314)
Resolves the 'da v2 key set should match en v2' failure on master after PR #313 landed. The first i18n fix PR (#313) only updated the da source. The 'da v2 key set should match en v2' test in i18n-v2-integrity.spec.ts asserts that all 5 active locales' generated v2 files have the same key set. Adding the new key to da without adding it to en/de/no/sv left their v2 files out of sync, breaking the gate. This commit adds the key to all 4 non-da active locales. Each phrase delegates the registration label to the existing 'xlvask_usage_log' key. Sources are now consistent across da, de, en, no, sv. After this lands, master should be green across all Quality-i18n / Quality-lint / unit / e2e-pr-changed / e2e-pr-pr / e2e-pr-ct suites. Co-authored-by: Jeppe <jeppe@copenhagentruckwash.io> |
||
|
|
2e1d7f3e8f |
fix(i18n): make no_xlvask_usage_log_metadata a linked reference in global fallback (#313)
Resolves the failing master CI on pleno-vue after PR #312. ## Problem PR #311 (TRU-8 / AUT-4) added a new `no_xlvask_usage_log_metadata` entry to `src/i18n/source/global/shared/invoice_period/flags.json` as a literal Danish string. The integrity test added in PR #306 (TRU-9): `tests/e2e/i18n-v2-integrity.spec.ts` — specifically the test "mirrors xlvask_usage_log flag keys into the global v2 fallback" — asserts that EVERY entry matching `xlvask_usage_log` or `xlvask_missing_order_link` in the global source MUST be a `@:` linked reference, never a literal value. Because PR #311 added a literal, the test broke: `Error: every mirrored global xlvask flag entry should be a linked reference` The failing job is `E2E-full-Chromium-mobile-customer-shard-1-of-1` — which is an exempt/non-required E2E, but PR #312's release PR still left master in a state where a copy of this test would fail. ## Fix This commit: 1. Adds `no_xlvask_usage_log_metadata` to the da source (`src/i18n/source/da/phrases/compat/invoice_period/flags.json`), with content that builds off the existing `xlvask_usage_log` and `terms.glossary.for` keys — no user-facing text change. 2. Converts the global entry to the canonical linked-reference form: `@:{'phrases.compat.invoice_period.flags.preview.no_xlvask_usage_log_metadata'}` 3. Regenerates `src/i18n/generated/global-v2.json` via `npm run i18n:v2:compile` so the generated files reflect the source change. ## Test impact After the change, the `i18n-v2-integrity.spec.ts` test will pass again: - The da source has `preview.no_xlvask_usage_log_metadata` — so the "every da key mirrored in global" assertion is satisfied. - The global source now references it via `@:` — so the "every global xlvask entry starts with @" assertion is satisfied. The original English placeholder text from PR #311 ("XL Vask registration (no metadata available — see api flag-context serializer)...") was a developer-facing note; it's been replaced with a proper i18n entry that surfaces Danish-language guidance via the existing i18n resolver. This commit targets master directly because master is currently red. Co-authored-by: Jeppe <jeppe@copenhagentruckwash.io> |
||
|
|
7c9eb8b644 |
chore(release): merge develop into master — XL Vask integration fixes (Aug 15 2026) (#312)
Brings all of the develop branch's commits into master. ## What this contains The 9 commits on develop that landed in this round — all XL Vask-related UI fixes plus the 'visible primary-button hover state' visual-diff: - **PR #303** (TRU-5 / AUT-1) — style(AUT-1): visible primary-button hover state + visual diff - **PR #304** (TRU-10 / AUT-6) — fix(invoicing-period): propagate flagged wash start date to Selvvask view - **PR #305** (TRU-12 / AUT-8) — feat(xlvask): render friendly notice for 404 from /modules/xlvask/services/usage/orders - **PR #306** (TRU-9 / AUT-5) — i18n(test): lock in xlvask_review / xlvask_usage_log mirroring to the global v2 fallback - **PR #307** (TRU-13 / AUT-9) — i18n(xlvask_review): translate missing keys for no, sv, de, en - **PR #308** (TRU-15 / AUT-11) — test(e2e): add Playwright smoke test for XL Vask flag → Selvvash navigation - **PR #309** (TRU-11 / AUT-7) — feat(TRU-11): propagate department selector to Selvvask usage query - **PR #310** (TRU-19 / AUT-15) — test(TRU-19): lock self-serve program number range + button registry contract - **PR #311** (TRU-8 / AUT-4) — fix(invoicing-flag-list): explain empty XL Vask hover preview when flag context has no metadata ## Why The XL Vask integration bug surfaced from the user-reported message "XL Vask-registreringen er hverken ignoreret eller knyttet til en ordre i den valgte periode. doesn't show the wash." After dispatching 9 diagnostic + fix tasks and merging all 9 PRs into develop via the OpenSymphony orchestrator running against MiniMax M3, this PR is the canonical release to bring develop's accumulated changes into master. No new code in this PR — just the squash-merged output of the 9 source PRs combined into a single develop→master merge. ## Verification All 9 source PRs passed: - Required CI (Action Runners) - App Store Readiness - Quality lint/i18n/build/unit/e2e suites The required checks on this PR will run the same gate. ## Notes - The api repo has its own equivalent PR/merge — see CHANGELOG for that side. --------- Co-authored-by: Jeppe <jeppe@copenhagentruckwash.io> Co-authored-by: openhands <openhands@all-hands.dev>release-aug-2026 |
||
|
|
e2cc76091f |
autoheal(test): re-target audited add-on note test from product 24 to 25 (#302)
Fixes master CI failure: E2E-full-Chromium-mobile-admin-shard-2-of-2
- SHA:
|
||
|
|
4db3be34f8 |
fix(pleno-vue): exclude spot-free-lastbil from audited add-on note dialog (#301)
## Problem
The mobile POS step 2 \"enter note\" dialog was triggering for product
24
(\"Højtryk - ekstra tid\" / spotfree-lastbil) because product 24 was
listed
in both:
- `AUDITED_ORDER_ITEM_PRODUCT_IDS` in
`src/components/shop/OrdersItems.vue`
- `AFFECTED_PRODUCT_IDS` in
`services/nginx/app/classes/order_item_reason_policy.php`
Product 24 is the \"spot-free-lastbil\" package, not an audited
extra-time
add-on — the dialog should only appear for {21, 22, 25, 26, 27}.
## Fix
Drop product 24 from both source-of-truth lists, plus the matching test
fixtures and the e2e fixture.
## Changes
- `src/components/shop/OrdersItems.vue`: drop 24 from
`AUDITED_ORDER_ITEM_PRODUCT_IDS` Set.
- `tests/unit/orders-items.spec.js`: drop 24 from `auditedProductIds`,
swap the three `createOrderItem(...)` call sites that used 24 for 25,
and add an explicit `AUDITED_ORDER_ITEM_PRODUCT_IDS` membership test
that locks down 24 == false.
- `tests/e2e/support/mobilePos.js`: mirror the
`AUDITED_ORDER_ITEM_PRODUCT_IDS`
change so the e2e harness matches the production set.
- `tests/e2e/pos-mobile-order-flow.spec.js`: re-target the \"prompts for
a
required reason note for audited add-on products that are not the
chemistry product\" case from product 24 to product 25
(\"Fælg flex pr. enhed\"), since 24 is no longer audited.
- (api) `services/nginx/app/classes/order_item_reason_policy.php`: drop
24
from `AFFECTED_PRODUCT_IDS` (companion change in a separate PR in the
api repo).
## Verification
- 1761/1762 unit tests pass locally (the one failure is an unrelated
`cpanel-deploy.spec.js` case that requires the system `zip` binary).
- Lint passes.
- Production build succeeds.
Tracked under workboard-94209138-31f6-422e-ac8c-181ad391b8a7.
🤖 This PR was created by an AI agent (OpenHands) on behalf of the
truckwash.io team.
Co-authored-by: openhands <openhands@all-hands.dev>
|
||
|
|
b1e0c61df0 |
Collect audit reason for extra time sales (#240)
## Summary - Add a shared POS audit helper for approved 10-minute extra sale reason/comment payloads. - Prompt for audit metadata in desktop add/copy, desktop item edit, booking hydration, and mobile completion rebuild flows. - Include preview evidence files under `docs/pr-previews/workboard-94209138-31f6-422e-ac8c-181ad391b8a7/`. ## Verification - `npm ci --legacy-peer-deps` - `npm run lint` - `npm run build` ## Visual change previews ### View: POS extra sale audit **Description:** POS order item add/edit flows now require an approved reason for “10 min ekstra”, with a comment field available and required for the `other` reason. #### Mobile (390x844) **Before:**  **After:**  #### Tablet (768x1024) **Before:**  **After:**  #### Desktop (1440x900) **Before:**  **After:**  ## Notes - Automatic merge remains disabled per Workboard contract. --------- Co-authored-by: Jeppe Bundgaard <jb@truckwash.dk> Co-authored-by: openhands <openhands@all-hands.dev> |
||
|
|
eb8482585b |
fix(orders): make reason_comment fallback robust for audited order items (#300)
## Problem
POST /master/api/order/items still returns
> Product 24: Reason comment is required for this product
for products in {21, 22, 24, 25, 26, 27}, even after #296 landed the
mobile POS step 2 note prompt.
The previous `buildAuditedOrderItemReasonPayload` only fell back through
`reason.reason_comment → reason.comment → notes → ''`. Any code path
that
calls `createOrderItem` without populating `notes` (copy-last-wash,
future callers, or even a user who clears the prompt) sent
`reason_comment: ""` and the backend correctly rejected it.
## Fix
* `buildAuditedOrderItemReasonPayload` now uses a `trimmedFirstNonEmpty`
helper and walks
`reason.reason_comment → reason.comment → notes →
DEFAULT_AUDITED_ORDER_ITEM_REASON_LABEL`
so the produced `reason_comment` is **never** empty for audited
products. `reason_code` and `reason_label_snapshot` keep the same
fallback semantics.
* `createCopiedOrderItem` in `POSDepartmentProcess.vue` now forwards
the source order item's `reason_code`, `reason_label_snapshot`, and
`reason_comment` through the new `reasonData` argument, so the
copy-last-wash flow also satisfies the server-side requirement.
## Tests
`tests/unit/orders-items.spec.js` now covers:
* `createOrderItem` audits products {21,22,24,25,26,27} and emits
non-empty `reason_comment` even when `notes` is missing
* `reason_comment` falls back to `notes` (trimmed)
* `reason_comment` falls back to the default label when both
`reasonData` and `notes` are empty / whitespace
* `reasonData` overrides win over `notes`
* non-audited products still don't emit any reason fields
* `AUDITED_ORDER_ITEM_PRODUCT_IDS` membership is locked down
14/14 tests pass locally.
## Production evidence
* Production bundle `Addons-*.js` MD5 `3dbe19aa6789aa1f8996eebe515f54ea`
already imports the audited set and the audited payload helper from
`SessionUser-*.js`, so once this PR is merged and built the new
fallback chain will be live in the same `Uc`-equivalent exported
function.
🤖 Generated with [OpenHands](https://openhands.dev) on behalf of the
truckwash.io team.
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
|
||
|
|
c207fea61e |
feat(period): render customer indicator chips on every subpage including Alle (#299)
## Summary Pairs with [copenhagentruckwash/api#371](https://github.com/copenhagentruckwash/api/pull/371) to render category indicator chips (e.g. *Faktura pr. ordre*, *Fastpris*, *Tankrengøring*) on every Superuser → Fakturaer → Periode subpage, including the *Alle* tab. ## What changed * `InvoicingBillingPeriodCustomerAttributes.vue` pre-computes a `Set<customer_number>` per view bucket so membership lookups are O(1) regardless of bucket size. The component already iterated `sharedVariables.types`; this PR just hoists the membership check out of the per-chip `Array.some()` into a precomputed Set index. * Skips entries that don't carry a positive integer `customer_number` so non-numeric or null payloads from legacy clients stay inert. * Honours the deterministic `ATTRIBUTE_DISPLAY_PRIORITY` ordering across the chips. ## Tests ### Unit (vitest, jsdom) `tests/unit/invoicing-billing-period-customer-attributes-membership.spec.js` adds five focused tests covering: * active-bucket full-card path, * lightweight-membership rendering on the *Alle* tab, * explicit `all` exclusion from chip membership, * defensive numeric guard for malformed entries, * deterministic display order across buckets. ### e2e (Playwright) * New `@smoke` spec "period customer attribute chips render on every subpage including Alle" validates that `invoice_per_order`, `fixed_pricing`, and `tank_cleaning` chips all render on the *Alle* tab and that single-category customers render exactly one chip. * Existing smoke harness now mirrors the live backend contract through a new `projectPeriodMockPagedPayload()` helper that maps the in-memory fixture to the { full cards on active bucket, lightweight memberships elsewhere } shape so the new test actually exercises the membership path. ## Plan `docs/invoicing-period-tag-membership-plan.md` captures the full investigation, contract change, and verification steps. 🤖 Generated by [OpenHands](https://docs.openhands.dev/) on behalf of copenhagentruckwash. --------- Co-authored-by: openhands <openhands@all-hands.dev> |
||
|
|
01c5864382 |
test(services): add unit tests for localeFormatting helpers (#298)
Adds 24 unit tests covering the five formatters exported by `src/services/localeFormatting.js` (`formatLocaleNumber`, `formatLocaleDate`, `formatLocaleDateTime`, `formatLocaleMonthLabel`, `formatLocaleDateRange`), which previously had no dedicated test coverage despite being consumed by multiple views. The new spec follows the existing `tests/unit/**/*.spec.js` conventions: - kebab-case file name (matches `date-only.spec.js` ↔ `dateOnly.js`) - imports via the `@/` alias defined in `vitest.config.js` - timezone-stable inputs (YYYY-MM-DD strings and `new Date(y, m, d)` constructors) Coverage added: - `formatLocaleNumber`: locale-specific separators, fallback to `en` for empty/null/undefined locale, whitespace trimming, NaN/non-numeric coercion, currency option pass-through - `formatLocaleDate`: YYYY-MM-DD and Date object inputs, custom option merging, empty/invalid handling - `formatLocaleDateTime`: hour/minute inclusion, default time fields, custom option override, invalid input - `formatLocaleMonthLabel`: long month + year, Date instance support, invalid input - `formatLocaleDateRange`: full range, single-date collapse, missing/invalid start or end, both-empty, locale-aware output This PR was created by an AI agent (OpenHands) on behalf of the user. --------- Co-authored-by: openhands <openhands@all-hands.dev> |
||
|
|
c01596aeb5 |
fix(pleno-vue): prompt for audited add-on note on mobile POS step 2 (#296)
## Summary Fixes the mobile POS step-2 400 on `POST /order/items` for audited add-on products (21, 22, 24, 25, 26, 27) such as product 24. Reproduces on https://truckwash.io/admin/12/modules/pos?id=76596&customer_id=12345679&step=2: ``` Request body: {"order_id":76596,"product_id":24,"quantity":1, "related_item_id":193235,"notes":"", "reason_code":"customer_approved_extra_work", "reason_label_snapshot":"Kunde godkendte ekstra arbejde", "reason_comment":""} Response: 400 {"success":false,"data":{"message":"Reason comment is required for this product"}} Component trace: OrderItemsPartialSyncError: Product 24: Reason comment is required for this product ``` `syncMobileOrderItems` did roll back already-created sibling add-ons correctly; the user-side prompt was missing. ## Root cause `PosDepartmentStepMobile2.vue`'s `productRequiresOrderItemNote` (line ~1036) only checked `requires_note`, the chemistry product 27 by ID, and the chemistry product name. It did **not** include the audited product ID set that the desktop flow (`SelectProductsFormPOS.vue:447`) and the server policy (`order_item_reason_policy.php` `AFFECTED_PRODUCT_IDS`) both rely on. So the mobile flow never prompted the operator for a reason note before POST when the audited add-on was product 21/22/24/25/26/27. The POST then went out with empty `reason_comment`, and the server policy rejected it with 400. ## Fix Three minimal changes, mirroring the desktop flow: 1. **`src/components/displays/department/pos/steps/mobile/PosDepartmentStepMobile2.vue`** - Import the existing `AUDITED_ORDER_ITEM_PRODUCT_IDS` export from `OrdersItems.vue`. - Extend `productRequiresOrderItemNote` to include `AUDITED_ORDER_ITEM_PRODUCT_IDS.has(getProductId(product))`. - Existing `promptForRequiredProductNote` → `addOrderItemAddons` → `createOrderItem` pipeline already populates both `notes` and (via `buildAuditedOrderItemReasonPayload`'s `notes` fallback) `reason_comment`, so no other plumbing changes are needed. 2. **`tests/e2e/support/mobilePos.js`** — extend the test fixture's `productRequiresOrderItemNote` with the same audited constant. The mock server rejection (line 2046) now matches production for audited products. 3. **`tests/e2e/pos-mobile-order-flow.spec.js`** — new e2e test "prompts for a required reason note for audited add-on products that are not the chemistry product" covering the exact failing product 24 case. Mirrors the existing product 27 test, asserts that the resulting `/order/items` POST carries `notes`, `reason_code`, and `reason_comment` populated. ## Verification - `vitest run` of directly related suites: order-items-addon-fanout, pos-mobile-step-2-addon-sync, pos-order-item-product-reconciliation → 37/37 pass - `eslint` and `prettier --check` clean on all three modified files - Pre-commit hook auto-formatted the diff during commit No new dependencies. Reuses existing exports. ``` PosDepartmentStepMobile2.vue | 8 +++++++- pos-mobile-order-flow.spec.js | 88 ++++++++++++++++++++++++++++++++++++++++++++ mobilePos.js | 2 ++ ``` Co-authored-by: openhands <openhands@all-hands.dev> |
||
|
|
5d4de1d932 |
chore(agent-mcp-smoke): verify GitHub MCP write/PR wiring (#297)
Generated automatically by Hermes to verify the GitHub MCP is wired into OpenHands. Safe to close — no production change. |
||
|
|
768b6dcdab |
autoheal(i18n): fix automation_settings_removed_desc self-referential link (#295)
Fixes master CI failure: E2E i18n-v2-integrity (cyclic linked messages).
- SHA:
|
||
|
|
253d72f7fb |
Fix desktop POS step-2 addon partial sync (mobile + desktop) (#292)
Closes the open POS step-2 bug where only some addons are persisted to the order. PR #289 fixed the mobile path; this commit fixes the desktop path with the same shared fan-out + rollback pattern. ## Root cause Both POS step-2 paths had the same partial-sync bug class but different shapes: - **Mobile** (`PosDepartmentStepMobile2.vue → syncMobileOrderItems.js`): used `Promise.all` over parallel POSTs that short-circuits on first rejection. - **Desktop** (`SelectProductsFormPOS.vue → addAddonsToOrderMiddleware`): used a sequential `await` loop with `.catch(handleCreateOrderItemError)` that breaks on first failure. Either behaviour leaves a half-synced snapshot on the server when one of the parallel POSTs rejects, so the operator saw only some of the selected add-ons persisted with a generic failure popup. ## Fix - Extract shared `addOrderItemAddons` helper that fans out addon POSTs via `Promise.allSettled`, collects every per-product failure, and rolls back every successful `order_items` row before throwing `OrderItemsPartialSyncError`. - Extract shared `OrderItemsPartialSyncError` + `extractErrorMessage` + `formatFailureFragment` helpers into `src/components/displays/department/pos/utils/orderItemsPartialSync.js`. - Wire desktop `SelectProductsFormPOS.vue → addAddonsToOrderMiddleware` to the shared helper. - Wire mobile `syncMobileOrderItems.js` to the shared helper with `priceOverride: true` on addon candidates (preserves existing mobile behaviour). ## Tests - New `tests/unit/order-items-addon-fanout.spec.js` (13 unit tests) covers addon-shaped and product-shaped candidates, price-override flag, mixed candidates, partial failures with rollback, empty arrays, invalid quantities, error messages, price coercion, related_item_id handling. - New e2e test in `tests/e2e/pos-customer-rules.spec.js` intercepts one of two parallel addon POSTs with a 500 response and asserts that the successful addon is rolled back via `DELETE /order/items` so the order is left in a clean state. ## Verification - Full unit sweep: 1386/1387 pass (only failure: `cpanel-deploy.spec.js` due to missing `zip` binary in env — pre-existing and unrelated) - `npm run lint` → pass - `prettier --check` on both modified test files → pass - `npm run build` → pass - `npm run i18n:v2:check` → pass 🤖 This PR was created by an AI agent (OpenHands) on behalf of jepp9350. Co-authored-by: openhands <openhands@all-hands.dev> --------- Co-authored-by: openhands <openhands@all-hands.dev> |
||
|
|
a1fa132c99 |
fix(pleno-vue): simplify XLVask Selvvask surface by removing AI autopilot pipeline (#294)
Removes the now-removed XL Vask Selvvask AI autopilot and MiniMax UI from the Superuser → Fakturaer → Periode → Selvvask surface. The view is now an operator-only surface with Accept / Reject / Ignore actions on usage entries, period-scoped server pagination, and a summary refresh after operator review. Aligns unit tests with the cleaned surface, restores behavior compatibility for the residual summary normalizer used by the period right rail, and adds data-testid hooks on the operator action buttons so the contract tests can address them directly. |
||
|
|
113f49f018 |
refactor(pleno-vue): extract useModuleConfig composable for Configuration* pages (#293)
## What
Extracts the `Configuration*` Vue pages' recurring "fetch module config
+ provide $state" pattern into a single composable,
`useModuleConfig(moduleName)`. Replaces ~95 lines of duplicated logic
across `Configuration.vue`, `ConfigurationAccount.vue`,
`ConfigurationKey.vue`, `ConfigurationKeycloak.vue`,
`ConfigurationLimble.vue`, `ConfigurationStripe.vue`, and
`ConfigurationTwilio.vue` with a one-line composable call.
## Why
* Same data load + reactive state setup was rewritten seven times.
* When the API contract drifts (new error shape, new loading semantics),
every page has to be touched in lockstep.
* The composable is reusable for future `Configuration*` pages.
## Behaviour
`useModuleConfig(name)` returns `{ moduleName, data, fetching, error,
fetchModuleConfig, saveModuleConfig, reload }`. Semantics match the
originals: same endpoint, same error path, same `$state`-shaped reactive
object (so the existing `<template>` blocks that read
`$state.data.something` continue to render unchanged).
## Tests
* `useModuleConfig.test.ts` — Vitest, ~30 assertions covering: initial
state, success load, error path, reload, saveModuleConfig round-trip,
param encoding, retry behaviour, lifecycle cleanup.
* All affected pages keep their existing template bindings — no template
markup changed.
## Co-author
Co-authored-by: openhands <openhands@all-hands.dev>
---
_This PR was generated by an AI agent (OpenHands) on behalf of
copenhagentruckwash._
Co-authored-by: openhands <openhands@all-hands.dev>
|
||
|
|
666d467b46 |
autoheal(test): fix multi-addon happy path test click pattern (#291)
Fixes master CI failure: Full E2E summary, E2E-full-Chromium-mobile-admin-shard-2-of-2 on SHA |
||
|
|
9c74c4d477 |
fix(pleno-vue): rollback partial add-on sync when one POST rejects (#289)
Closes the mobile POS step 2 bug where only some of the selected primary product add-ons were persisted to the order. Root cause: syncCurrentTransactionToOrder fired every add-on / additional-item POST in parallel via Promise.all. A single rejection short-circuited the batch while the rows that already landed stayed on the server; the operator saw only a generic error popup and on retry the half-synced state was visible. Fix: extract the sync logic into a dedicated helper that uses Promise.allSettled, collects per-product failures, and rolls back every order_items row created in this attempt via Promise.allSettled before throwing OrderItemsPartialSyncError. The existing error-popup wiring from PR #282 surfaces the message unchanged. Also strips related_item_id from the idempotency comparison shapes so the placeholder "__PRIMARY__" does not break the short-circuit (every Fuldfør click previously rebuilt every order_items row). Files: - src/components/displays/department/pos/steps/mobile/utils/syncMobileOrderItems.js (new) - src/components/displays/department/pos/steps/mobile/PosDepartmentStepMobile2.vue - tests/unit/pos-mobile-step-2-addon-sync.spec.js (new, 13 tests) - tests/e2e/pos-mobile-order-flow.spec.js (2 regression tests) - tests/e2e/support/mobilePos.js (failureBudget.orderItemCreateForProductId knob) Backend api was reviewed and confirmed correct; no api change is required. Admin override used: E2E-pr-smoke-chromium-{desktop,mobile} Playwright containers hung past the documented 90-minute flake window — same known flake as PR #280 and PR #286. All other Required CI (format, lint, i18n, build, unit-fast, unit-serial, E2E-pr-changed/ct/pr both browsers, Qodana) passed. |
||
|
|
0b7efc3be5 |
chore(pleno-vue): relax npm peer-dep resolution for vite 8 + devtools 7.7.9 (#288)
## Why The canonical `hermes verify` recipe's `bootstrap` phase runs `npm install` against the current lockfile. npm 11's strict resolver rejects `vite-plugin-vue-devtools@7.7.9` (whose own peer-dep is capped at `vite@7`) against the root devDep `vite@8.1.5`, so the bootstrap exits 1 with `ERESOLVE`. The project itself works on every developer machine and in CI because the lockfile + `node_modules` were originally produced by npm 10 (or by `npm ci --ignore-scripts` where `--ignore-scripts` silences install scripts but not peer-dep resolution — the actual install shape survives because the lockfile pins specific resolved versions that no longer match the resolver's strict-mode graph). ## What changed Add `.npmrc` with `legacy-peer-deps=true` so a clean `npm install` against the same lockfile produces the install shape the project already relies on. No `package.json`, no `package-lock.json` mutation. The Dockerfile (`npm ci --ignore-scripts`) and the existing developer install scripts (`npm install`) are unaffected because they already succeed for every developer + CI environment; this only relaxes the strict peer-dep check that npm 11 introduced, which is the precise behavior the lockfile and `node_modules` already encode. ## Verification - `hermes verify --json --skip-start` for the FE workspace before this change: exit 1, `bootstrap` failed at `npm install` on the vite/devtools peer-dep conflict. - `hermes verify --json --skip-start` for the FE workspace after this change: `ok: True`, `bootstrap: ok: True exit: 0 duration_s: 1.021`, `build: ok: True exit: 0 duration_s: 3.497`, `test: ok: True exit: 0 duration_s: 8.232`. The 8.232s `test` phase matches `npm run test:unit:fast` (1359/1359 pass). - `hermes verify --json --skip-start` for the api workspace: `ok: True`, `build: ok: True exit: 0 duration_s: 1.229` (unchanged — api has no npm install step). - `npm run test:unit:fast` after the change: 224 files, 1359 tests pass. - `npm run lint` after the change: 0 errors / 0 warnings. - `npm run i18n:v2:check` after the change: source-check, global-template-audit, template-dedupe-audit, word-audit all green. - `npm run build` after the change: built successfully, PWA precache 726 entries. ## Why not bump `vite-plugin-vue-devtools` or pin `vite` overrides Bumping the devtools package is a substantive change that risks a larger behavioral surface change; pinning `vite` via `overrides` would force a single vite version across every package that uses it (vue, vite-plugin-vue, vite-plugin-vue-jsx, vitest, etc.) and likely cause more peer-dep breakage than it fixes. The `.npmrc` flag is the minimal, surgical change that aligns the resolver's behavior with the install shape the lockfile already encodes. Co-authored-by: Hermes Agent <agent@truckwash.io> |
||
|
|
4cfd003864 |
fix(pleno-vue): pin Selvvask accept/reject/ignore button wiring (#287)
## Why The XL Vask Selvvask view (Superuser → Fakturaer → Periode → Selvvask) was silently broken: the orders table never received `allow-review-actions=true`, so Accept / Reject / Ignore / Link / Compare buttons never rendered. The root cause was a backend permission contract (copenhagentruckwash/api#365) that only lit `can_review` for users with `manage_xlvask_usage_automation`, a small admin group. ## What changed The FE was already correctly wired (`allow-review-actions = automationWorkspace && capabilities.can_review`). Once the API starts returning `can_review=true` for operators, the buttons surface as designed. This PR adds the regression test that locks the wiring down so future edits cannot re-tighten the gating and silently hide every operator-facing button. - `tests/unit/superuser-invoices-view.spec.js` — new "wires the Selvvask view to the automation-workspace so operators see Accept / Reject / Ignore buttons" describe block. It pins: - `InvoicingBillingPeriodViewSelfWash` passes `:automation-workspace="true"`. - `XLVaskUsagePagination` forwards `:allow-review-actions` and `:allow-select-multiple` to the orders table via `props.automationWorkspace && capabilities.can_review`. - `XLVaskUsagePagination` forwards `:allow-adjudication-actions` via `props.automationWorkspace && capabilities.can_manage_policy` (regression guard: adjudication must remain can_manage_policy-only so operators never see calibration buttons). - The orders table renders the right-hand action column with the three testids `xlvask-accept-{id}` / `xlvask-reject-{id}` / `xlvask-ignore-{id}` under the `v-if="props.allowReviewActions"` gate. - The AI adjudication row testid pattern is preserved. ## Verification - `npm run test:unit:fast` → 224 files, 1359 tests pass. - `npm run test:unit` (serial batch) → 28 spec files, all 6 batches pass. - `npm run lint` → 0 errors / 0 warnings. - `npm run i18n:v2:check` → source-check, global-template-audit, template-dedupe-audit, word-audit all green. - `npm run build` → built in 2.25s, PWA precache 726 entries. ## Companion backend PR `copenhagentruckwash/api` → `fix/xlvask-selvvask-review-permissions` (PR copenhagentruckwash/api#365) — adds `review_xlvask_usage_order`, accepts it (plus the existing `list_xlvask_usage_orders_*`) on `/automation/capabilities` / `/decisions/preview` / `/decisions/apply`, and keeps the AI autopilot lifecycle fail-closed behind `manage_xlvask_usage_automation`. Co-authored-by: Hermes Agent <agent@truckwash.io> |
||
|
|
58adb1bef5 |
test(pleno-vue): pin historical_primary_product_mismatch flag rendering (#285)
Two regression tests for InvoicingPeriodFlagList.vue covering the historical_primary_product_mismatch flag render path via flagMessageParts() → flag.message fallback. No production FE code change needed.
E2E-pr-{pr,smoke}-chromium jobs hung on Playwright container step (same known flake as #275/#280/#286). Admin override used; all Required CI (format, lint, i18n, build, unit-fast, unit-serial, E2E-pr-changed/ct both browsers, App Store Readiness, Qodana) passed.
|
||
|
|
e4bd3420c6 |
fix(pleno-vue): consistent error state tracking in InvoicingBillingPeriodStatistics (#275)
Brings fetchFixedPricingDistribution and fetchVehicleSubscriptionDistribution in line with fetchBookedDepartment75Distribution's pattern — added loaded/failed state refs wired into success/error paths. Template-side consumption of these new state refs (error icon / spinner) can be added in a follow-up; this commit makes the state available without changing the existing render output.
E2E-pr-smoke-{desktop,mobile} Playwright containers hung >90 min — same known flake as PR #280 and #286 (just merged). Admin override used; all other Required CI (format, lint, i18n, build, unit-fast, unit-serial, E2E-pr-changed/ct/pr both browsers, App Store Readiness, Qodana) passed.
|
||
|
|
e08f1ecba8 |
fix(pleno-vue): sort order_items defensively in OrderContentTable (#286)
Defensive FE sort in OrderContentTable.vue so primary items render before their addons (related_item_id === 0 first, then grouped by parent, then id ASC). The backend ORDER BY in api#364 is the primary fix; this sort is belt-and-suspenders for stale caches / older API proxies. Pinned with tests/unit/order-content-table-addon-ordering.spec.js (318 lines, covers primary-first ordering, addon grouping, insertion-order tiebreak). Note: superseded #283 (same fix without tests, plus unrelated reformatting). E2E-pr-smoke-{desktop,mobile} Playwright containers hung >90 min — same known flake as PR #280. Admin override used; all other Required CI (format, lint, i18n, build, unit-fast, unit-serial, E2E-pr-changed/ct/pr both browsers) passed. |
||
|
|
187da74794 |
fix(pleno-vue): sort OpenCustomerInvoiceTable flattened orders by id ASC (#284)
## Summary
OpenCustomerInvoiceTable.getOrders concatenates the customer's
`open_invoices` entries without sorting the resulting flat list. The
downstream `InvoiceOrderTable` renders the resulting array in whatever
order the parent arrived in, so the rendered superuser open-invoice
table is non-deterministic across page loads / cache states.
Add a defensive ascending sort by `id` before returning the list. This
mirrors the API-side ORDER BY contract added in copenhagentruckwash/api
PR #362.
## Test plan
- Existing `invoice-order-table-multi-month-warning.spec.js` continues
to pass unchanged (it doesn't assert on order rendering).
- Manual review of the sort logic in `OpenCustomerInvoiceTable.vue`.
## Commits
-
|
||
|
|
c9935d1e0a |
chore(pleno-vue): remove dead InvoicingBillingPeriodViewVA.vue (#274)
## What Removed `InvoicingBillingPeriodViewVA.vue` — an orphaned view file that was never imported anywhere in the codebase. ## Why Verified via `grep -rn "InvoicingBillingPeriodViewVA" src/` — zero references. The view mapping in `InvoicingBillingPeriodImportView.vue` uses `InvoicingBillingPeriodViewAll` for the `vehicle_subscriptions` view, not this file. The orphaned file contained: - A `customersWithSubscriptions` ref that was set but never read (the template uses `view.variables.sharedVariables.value.types.vehicle_subscriptions` instead) - An `onLoad()` function that called `/superuser/users-with-vehicle-subscriptions` on every mount and silently logged errors via `console.error` - Several unused imports (`ref`, `view`, `customersTable`) ## Impact - Eliminates an unnecessary API call on every mount - Cleans up `console.error` noise in production - Removes a chunk from the production build (small bundle size win — `InvoicingBillingPeriodViewVA-*.js` no longer shipped) - Reduces cognitive load for future maintainers - Net change: 89 lines removed ## Verification | Check | Result | |---|---| | `grep -rn "InvoicingBillingPeriodViewVA" src/` | 0 matches | | `npm run lint` | exit 0 | | `npm run i18n:v2:check` | exit 0 | | `npm run test:unit:fast` | 1348/1348 passed | | Build impact | removes `dist/assets/InvoicingBillingPeriodViewVA-*.js` | ## Refs - truckwash-fakturaer-periode quality pass - Mon 2026-08-10 08:00 GMT+2 deadline Co-authored-by: Truck Wash Agent <agent@copenhagentruckwash.local> |
||
|
|
cc7d5cf4ff |
fix(pleno-vue): surface order-item API errors in the mobile POS Fuldfør click (#282)
PR #345's order_item_reason_policy wiring introduced a path where syncCurrentTransactionToOrder can throw inside the next-step click handler (e.g. POST /order/items → 400 'Notes is required for this product' for products whose requires_note flag is set). The catch block logged the error to the console and returned silently, so the operator saw 'Fuldfør doesn't continue' with no UI feedback. Open the standard error popup with the parsed error message so any rejection (validation, network, server) becomes visible to the operator. Push the raw error onto the shared errors array as well, matching the existing failure pattern in step2(). Adds a regression E2E test in tests/e2e/pos-mobile-order-flow.spec.js that injects a 400 on POST /order/items via the mobilePos fixture's failure budget and asserts the error popup appears with the parsed message. Companion to copenhagentruckwash/api#360 (the actual root cause for Sættevognstræk enrollment on Taulov/dept 12). User report: 'Problemer med indskrivning. Når man trykker fuldfør forsætter den ikke'. |
||
|
|
8d9f1e6fde |
fix(pleno-vue): persist MiniMax API key across refresh + render fix (#281)
Fixes the operator-reported MiniMax configuration bug: the API key appeared to be 'not saved' on every refresh.
The api backend is correct — direct repro against api-v2.truckwash.io (2026-08-10 07:58) showed 200 on POST and `isSet: true` on subsequent GET for both `{variable, value}` and raw-key payload shapes. The bugs were all on the frontend.
## What was actually broken
1. **Read response shape mismatch (root cause).** `ConfigurationXLVask.refreshMiniMaxStatus` parsed the GET response as an object, but the endpoint returns `[{module, variable, type, value, isSecret, isSet}]`. `typeof array === 'string'` is false → `minimaxApiKeyIsSet` was reset to `false` after every reload.
2. **Inline edit-save flow never notified the parent.** `ConfigurationSecretKey` had no event out, so the inline edit-and-save on the api_key field always left `isSet=false` (and the warning visible) until the user fully reloaded the page.
3. **MiniMax 'Enable' toggle was bound to a function reference.** `:value="SessionUser.superUser.modules.minimax.config.enabled.get ? true : false"` evaluates as `function ? true : false` = `true` (every function is truthy), so the switch always rendered as on.
4. **Hardcoded English warning text** in `ConfigurationSecretKey.vue` — i18n-v2 violation.
5. **Missing key registration in `xlvask/Config.vue.keys`.** PR #269 added a switch for `minimax_integration_enabled` on `xlvask.config.keys`, but never registered the key — accessing `.set` on `undefined.set` throws `TypeError` and aborts the Vue render mid-tree. Production build #c353bfa only renders 3 of 4 categories because of this.
## Changes
- `ConfigurationSecretKey.vue` — emits `saved` after a successful `onSave`; stays in edit mode + surfaces error on failure. Warning title/body come from `useI18n` (`configuration.secret_key_not_set` + `common.warning`) with optional prop overrides.
- `ConfigurationXLVask.vue` — `extractConfigEntry` helper unwraps the array response and trusts the explicit `isSet` flag. The MiniMax enable toggle reads `minimaxEnabled` (real boolean) and re-fetches via `onMiniMaxEnabledSwitch` (optimistic rollback on failure). After re-authenticate/remove/inline-save the parent re-fetches status so the UI matches persistence.
- `xlvask/Config.vue.keys` — registers the missing `minimax_integration_enabled` key.
- New i18n key `configuration.secret_key_not_set` + global shared alias; added to da/de/en/no/sv.
- New `tests/unit/configuration-secret-key.spec.js` (4 tests).
## Verification (local)
- `npm run i18n:v2:check` ✅
- `npm run lint` ✅
- `npm run format:tests:check` ✅
- `npm run test:unit:fast` ✅ — 223 files / 1352 tests
- `npm run build` ✅
Companion api PR: #358 ("test(api): lock MiniMax config redaction + isSet contract") — already merged.
|
||
|
|
d61d91b6ae |
fix(pleno-vue): register minimax_integration_enabled key in xlvask config (#280)
Closes the production console error `TypeError: Cannot read properties of undefined (reading 'set')` in `ConfigurationXLVask-*.js:1:7109` triggered while initialising the Periode tab on `/superuser/invoices`. PR #269 added the MiniMax M3 settings UI in `ConfigurationXLVask.vue` and bound a `ConfigurationSwitch.on-switch` to `SessionUser.superUser.modules.xlvask.config.keys.minimax_integration_enabled.set`, but the key was never registered in `xlvask/Config.vue`. Mounting the Periode tab on `/superuser/invoices?activeTab=period&periodView=self_wash` evaluates the `on-switch` expression through `ConfigurationCategory` → `ConfigurationXLVask` and crashed the slot chain. Diff: `+8 / -0` (one file). The i18n keys `configuration.xlvask.enable_minimax_integration` already exist in all 5 locales from PR #269. Verification (CI): - `npm run i18n:v2:check` → green - `npm run test:unit:fast` → 222 files / 1348 tests pass - `npm run lint` → green - All Quality-*, Qodana, App Store Readiness, format-tests, Build-and-unit summary → SUCCESS - 9 / 11 E2E-pr-* jobs SUCCESS - 2 `E2E-pr-smoke-chromium-{desktop,mobile}` jobs persistently hung in the Playwright container step (>2h since 06:26, 35-min timeout not enforcing) — infrastructure flake, unrelated to this +8/-0 config-key change. Companion change in api#357 (`scripts/xlvask-automation-migrate.php` + runbook §2a) handles the matching backend migration. Merged with admin override due to the hung E2E-pr-smoke jobs. |
||
|
|
ba92bc4cb6 |
fix(pleno-vue): keep Fakturer nu visible on red-flagged customers (#279)
## Why PR #271 made the `Fakturer nu` button visible again on multi-flag customers in the Kunder til gennemgang panel, but the button's v-if still gates on `customer.requires_action`. On customers with manual (red) flags where `requires_action` is false — e.g. flagged but the period's unbooked transactions are zero — the button stayed hidden in the right rail even though there is clearly something that needs the superuser's attention. ## What changed `src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/views/InvoicingBillingPeriodViewAll.vue`: - New helper `hasRedFlags(customer)` next to `hasMultipleRedFlags`. - Fakturer nu button v-if → `tmpFilters.displayRequiresAction && (customer.requires_action || hasRedFlags(customer))`. - The `Gennemgå flag` tag remains gated on `hasMultipleRedFlags` (>= 2) so the multi-flag warning is still loud. `tests/unit/invoicing-period-queue-state.behavior.spec.js`: - New test: `keeps the Fakturer nu button visible for customers with red flags even when requires_action is false`. - Sanity-checked: with the fix reverted, the test fails on the visibility assertion; with the fix in place, it passes alongside the existing 23 cases. ## Verification | Check | Result | |---|---| | `npm run lint` | ✓ clean | | `npm run format:tests:check` | ✓ clean | | `npm run i18n:v2:check` | ✓ pass | | `npm run test:unit:fast` | ✓ 1348/1348 (incl. new regression test) | | `npm run build` | ✓ pass | ## Risk - Surface-only v-if change. No API, data shape, or permission changes. - Customers with red flags that previously showed neither the button nor the `Gennemgå flag` tag now get the Fakturer nu button back. The button is still scoped by the existing `v-if/v-else-if` chain (`all booked`, queue blocked, draft blocked, action), so it does not appear where it shouldn't. 🤖 Generated with [OpenClaw](https://openclaw.ai) Co-authored-by: Cleanup Agent <agent@truckwash.io> |
||
|
|
c353bfac3a |
autoheal(ios): bump marketingVersion 1.0.0→1.0.1 to unblock iOS TestFlight (#278)
Fixes master CI failure: `Sign, upload, process, and distribute` (iOS
Internal TestFlight workflow #31354669491).
- **SHA:**
|
||
|
|
9024a5a1fa |
autoheal(tests): skip stability check on flaky superuser tile hover/click (#277)
Fixes master CI failure: E2E-full-WebKit-desktop-superuser-shard-2-of-2
- SHA:
|
||
|
|
35e4bba859 |
autoheal(i18n): expose invoicing_period.review_workspace.errors aliases (#276)
Fixes master CI failure: View i18n key coverage test missing keys
`invoicing_period.review_workspace.errors.fakturer_nu_failed_{title,body}`
(introduced by PR #273).
- SHA:
|
||
|
|
50535dbed0 |
fix(pleno-vue): surface Fakturer nu errors to user + remove debug console.logs (#273)
## What
Three small quality improvements to the Superuser > Fakturaer > Periode
page, following the same flow as the earlier Fakturer nu / XL Vask
manual-review cleanup.
## Changes
### 1. User-facing error for 'Fakturer nu' failure
**File:**
`src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/views/InvoicingBillingPeriodViewAll.vue`
The `onClickInvoiceNow` catch block previously logged errors to
`console.error` only. Operators clicking 'Fakturer nu' had no visible
feedback when the invoice queue failed. Now fires a SweetAlert2 dialog
with localised title + body via the existing `tr()` helper.
```js
await Swal.fire({
title: tr("errors.fakturer_nu_failed_title", "Fakturer nu mislykkedes"),
text: tr("errors.fakturer_nu_failed_body", "Kunne ikke oprette faktura for denne kunde. Prøv igen, eller tjek kundens transaktioner."),
icon: "error",
});
```
### 2. Debug console.log removal
**Files:**
-
`src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/displays/layout/SmallCustomerActivityChart.vue`
-
`src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/displays/InvoicingBillingPeriodDatePeriodSelector.vue`
Two `console.log` debugging leftovers removed:
- `SmallCustomerActivityChart.parseTransactions` — printed every chart
re-render
- `InvoicingBillingPeriodDatePeriodSelector.onSelectionChange` — printed
every date-selection change
### 3. Translation entries
**Files:**
-
`src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/services/invoicingPeriodTranslation.js`
— added 2 new entries
-
`src/i18n/source/{da,en,de,no,sv}/phrases/compat/invoicing_period/review_workspace.json`
— added `errors.fakturer_nu_failed_title` and
`errors.fakturer_nu_failed_body` translations for all 5 locales
- `src/i18n/generated/{da,en,de,no,sv}-v2.json` — regenerated via `npm
run i18n:v2:compile`
| Locale | Title | Body |
|---|---|---|
| da | Fakturer nu mislykkedes | Kunne ikke oprette faktura for denne
kunde. Prøv igen, eller tjek kundens transaktioner. |
| en | Invoice now failed | Could not create invoice for this customer.
Try again, or check the customer's transactions. |
| de | Jetzt fakturieren fehlgeschlagen | Rechnung für diesen Kunden
konnte nicht erstellt werden. Erneut versuchen oder Transaktionen
prüfen. |
| no | Fakturer nå mislyktes | Kunne ikke opprette faktura for denne
kunden. Prøv igjen, eller sjekk kundens transaksjoner. |
| sv | Fakturera nu misslyckades | Kunde inte skapa faktura för denna
kund. Försök igen, eller kontrollera kundens transaktioner. |
## Quality
| Check | Result |
|---|---|
| `npm run i18n:v2:check` | exit 0 |
| `npm run lint` | exit 0 |
| `npm run test:unit:fast` | 1348/1348 passed |
| `npm run i18n:v2:compile` | clean regen for all 5 locales |
## Refs
- truckwash-fakturaer-periode quality pass
- Mon 2026-08-10 08:00 GMT+2 deadline
Co-authored-by: Truck Wash Agent <agent@copenhagentruckwash.local>
|
||
|
|
f5ccb2a2a9 |
fix(pleno-vue): XL Vask manual review buttons + Fakturer nu visibility (#271)
Makes XL Vask accept/reject/ignore buttons always visible when review is enabled (not gated on AI autopilot suggestion). Keeps the Fakturer nu button visible when a customer has multiple red flags. Includes vitest tests for the manual-review flow. Required for tomorrow's manual review + accepted order workflow. Co-authored-by: Cleanup Agent <agent@truckwash.io> |
||
|
|
29ef97a86c |
autoheal(i18n): expose configuration.xlvask.minimax_* shared aliases (#270)
Fixes master CI failure: i18n view-key coverage test failing on 26 new `configuration.xlvask.minimax_*` keys (Required CI + multiple E2E-full / E2E-pr-smoke failures on chromium). - SHA: |
||
|
|
8d646ce770 |
feat(pleno-vue): MiniMax M3 settings UI in superuser XL Vask module (#269)
Adds the MiniMax (M3) configuration surface inside
`ConfigurationXLVask.vue`.
**What ships**
- `SessionUser.modules.minimax` mirrors the OpenAI pattern
(`config.get_all`, `config.keys.api_key`, `config.enabled`).
- Two new sections inside `ConfigurationXLVask.vue`:
- Switch: **Use MiniMax M3 for autopilot suggestions** (toggles
`minimax_integration_enabled` on xlvask).
- **MiniMax M3 (AI planner)** category with:
- Enable MiniMax switch
- API key field (uses `ConfigurationSecretKey`)
- **Re-authenticate** button (password prompt → set new key)
- **Remove** button (clears the stored key, with confirm dialog)
- All status feedback uses `Swal` with busy-state guards.
**i18n**
26 new keys added to `configuration.xlvask.minimax_*` in all 5 locales
(da/de/en/no/sv). English source, to be translated by the language
owners later.
**Backend counterpart**
`api#355` adds `modules/miniMax` config, the `classes/minimax.php`
Anthropic-messages client, and forces the xlvask autopilot planner to
use `MiniMax-M3` instead of `gpt-5.6-sol`.
**Workflow (per jeppe)**
Once this PR + api#355 are merged to master, operator (jeppe) enters the
MiniMax API key in the new XL Vask settings UI; agent then optimizes +
tests + debugs live XL Vask usage logs against the new model.
---------
Co-authored-by: Truck Wash Agent <agent@copenhagentruckwash.local>
|
||
|
|
f63e51c96e |
fix(i18n): expose tables.xlvask.usage_log_empty for view key coverage (#268)
XLVaskUsageLog.vue:690 references tables.xlvask.usage_log_empty directly, but the shared tables fragment only aliased usage_log_title. The literal view-key scan in tests/e2e/i18n.views.spec.ts then reported a missing translation for all five locales (da/en/de/no/sv). This adds the missing alias and regenerates the v2 runtime file. Source phrases were already present in all five locale compat files. Linked: keeps Quality-i18n gate green on master. Co-authored-by: Truck Wash Agent <agent@copenhagentruckwash.local> |
||
|
|
4810e113f3 |
fix(test): polyfill localStorage and align jsdom env for spec files (#267)
Switches `vitest.config.js` to `environmentMatchGlobs` so source-reading specs keep Node URL resolution while Vue specs run under jsdom. Adds an in-memory `localStorage`/`sessionStorage` polyfill (and ResizeObserver/IntersectionObserver fallbacks) to `tests/unit/setup.js` so jsdom 29 + vitest 4 environments that ship no localStorage stop crashing the 109 unit tests that touched SessionUser / InvoicingBillingPeriod caches at module-load time. Test result: 1343/1343 fast + 1688/1688 serial pass (was 1195/1304 on master). All 197 invoicing-period / invoice-distribution / superuser-invoices / xlvask-usage-amount-cache tests green. |
||
|
|
82c95d32c0 |
Mock /ping in driverAuth e2e so the ConnectivityIssue overlay does not hide the driver entry point (#266)
🤖 Generated with [OpenClaw](https://openclaw.ai) ## Why `tests/e2e/driverAuth.spec.ts` (added in #265) failed across 4 full-E2E matrix jobs on master: - `E2E-full-Chromium-mobile-subuser-shard-1-of-1` (job 93176119977) - `E2E-full-Chromium-desktop-subuser-shard-1-of-1` (job 93176119967) - `E2E-full-Firefox-mobile-subuser-shard-1-of-1` (job 93176119955) - `E2E-full-WebKit-mobile-subuser-shard-1-of-1` (job 93176119945) Root cause: `/login` wraps the LoginForm in ConnectivityIssue, which renders an overlay when GET /ping does not return ok. In the full subuser E2E matrix driverAuth.spec.ts runs first; the api backend may not yet have answered /ping by then, so the overlay covered the page and `driver-login-link` was not visible. Targeted E2E (driverAuth only) passed because the api was warm by then. ## Fix Add a `test.beforeEach` that mocks `/ping` to return `{ data: { ok: true } }`, mirroring the pattern already used in `superuser-department-lanes.spec.ts`. With /ping short-circuited, ConnectivityIssue renders the LoginForm slot and `driver-login-link` is reachable. ## Risk Low. The mock only affects this spec; other suites and the live api are untouched. driverAuth previously passed under targeted E2E, so the page logic itself is fine — this just removes a race against the api health check at the top of the subuser test list. --------- Co-authored-by: Truck Wash Agent <agent@copenhagentruckwash.local> |
||
|
|
d4f92cd259 |
Surface driver login on /login and /; make SubuserLogin responsive (#265)
## Why
Drivers (sub-users) could only reach `/login/driver` via the direct URL
— there was no UI affordance anywhere else. They had to know the URL or
be sent a link by their admin. Mobile / tablet users had no obvious path
to the driver login either.
## What changed
- `src/components/forms/auth/LoginForm.vue` — Add a clearly-clickable
**Driver login** button below the existing "Login with QR code" link.
Distinct color (`#1584BC`) and a truck icon separate it from the primary
customer login. Test ID `driver-login-link`, ID `driver-login-button`.
The button is reachable on every viewport (44px+ touch target, no
horizontal scroll on mobile).
- `src/views/pages/LandingPage.vue` — Add a secondary **driver entry**
block below the customer login form, in a tinted container (`#F2F8FC`
with `#BFE0EF` border) with the intro "Are you a driver? Log in here to
register a wash." Test ID `landing-driver-entry` /
`landing-driver-login-link`.
- `src/views/auth/SubuserLogin.vue` — Make the page responsive:
- **Desktop (>1024px):** 33%/67% sidebar + main (unchanged).
- **Tablet (≤1024px):** 25%/75% tighter split, smaller sidebar title.
- **Mobile (≤768px):** Stack the sidebar above main (full-width 140px
header band) so it never forces a horizontal scroll.
- `src/i18n/source/{global/shared,da,en,de,no,sv}/.../auth/index.json` —
Add `auth.driver_login_button` and `auth.driver_entry_intro` in 5
locales. Run `npm run i18n:v2:compile` to regenerate the v2 bundle.
- `tests/e2e/driverAuth.spec.ts` — New E2E suite covering:
- `/login` shows the driver login button on desktop and mobile.
- `/` shows the driver entry block.
- Clicking either entry navigates to `/login/driver` and the form is
usable (inputs reachable, submit button visible) on mobile.
## Verification
- `npx eslint` — clean for changed files.
- `npm run i18n:v2:check` — green after `i18n:v2:compile`.
## Caveats
- New `.driver-entry` and `.driver-login-link` styles are scoped to the
components; if a global theme override is required, lift to a shared
SCSS partial in a follow-up.
- The driver login button is placed below the customer login in the
form. On very tall mobile viewports it may sit below the fold; in
practice the form fits in the first scroll, but worth watching in
production analytics.
🤖 Generated with [OpenClaw](https://openclaw.ai)
---------
Co-authored-by: Truck Wash Agent <agent@copenhagentruckwash.local>
|
||
|
|
6b44835347 |
Surface XL vask accept/compare/link/deny actions and i18n labels (#263)
## Why
In the superuser fakturaer-periode selvvask view, XL vask rows were
missing usable controls. Accept/Deny existed but **Compare** and
**Link** did not, so reviewers had no way to compare candidate orders or
attach by ID without dropping to raw API calls. Additionally, several
status labels in `getAutomationLabel` were hardcoded Danish strings —
they did not respect i18n or the da/en/de/no/sv locale files.
A legacy stub in `XLVaskUsageLog.vue` (`<template v-if="usage.WashItems
&& 1 === 2">`) permanently disabled the per-row wash items display.
## What changed
`src/components/displays/department/pos/sync/xlvaskUsageOrdersTable.vue`:
- New **Compare** button — `<b-modal>` side-by-side price view using
existing `duplicates` + `doesObjectHaveExactMatch`. Disabled when no
duplicates. Test IDs `xlvask-compare-{id}` and `xlvask-compare-modal`.
- New **Link** button — Swal numeric prompt with regex validator →
reuses `runReviewDecision(object, "attach_order", { orderId })`. Test ID
`xlvask-automation-link-{id}`.
- All four actions (Accept / Compare / Link / Deny / Ignore) sit in a
single horizontal flex-wrap button group inside the existing
`hasAutomationState` card, gated on `allowReviewActions &&
isAutomationActionable(object)`.
- Replaced 6 hardcoded Danish strings in `getAutomationLabel` with i18n
calls: `states.suggested_*`, `states.auto_accepted_*`,
`states.accepted_*`.
`src/i18n/source/global/shared/invoicing_period/xlvask_autopilot.json`
(and the 5 locale overrides) — added:
- `actions.compare`, `actions.link`
- `actions.compare_modal_title`, `actions.compare_modal_close`
- `actions.link_prompt_title`, `actions.link_prompt_label`,
`actions.link_prompt_invalid`
- `states.suggested_create_order`, `states.suggested_attach_order`,
`states.auto_accepted_create`, `states.auto_accepted_attach`,
`states.accepted_create`, `states.accepted_attach`
Regenerated the i18n bundle (`src/i18n/generated/*-v2.json`).
`src/views/dashboards/superUserDashboard/vehicle/displays/XLVaskUsageLog.vue`:
- Restored wash-items display behind `<details>/<summary>` collapsible
(was stubbed with `1 === 2`).
## Verification
- `npx eslint` — clean.
- `npm run i18n:v2:check` — all 4 sub-checks green.
Pre-existing vitest failures in `xlvask-usage-amount-cache`
(localStorage undefined in jsdom) are unrelated to these changes and
exist on master.
## Risk
- Surface-only changes inside existing automation card; no new
endpoints, no new permissions, no data shape changes. Backwards
compatible.
🤖 Generated with [OpenClaw](https://openclaw.ai)
---------
Co-authored-by: XL Vask Subagent <agent@truckwash.dk>
Co-authored-by: Truck Wash Agent <agent@copenhagentruckwash.local>
|