Skip to content

feat: add localized user guide links to popup and inline helper#85

Merged
hoangsvit merged 22 commits into
devfrom
feat/add-user-guide-links
Jul 24, 2026
Merged

feat: add localized user guide links to popup and inline helper#85
hoangsvit merged 22 commits into
devfrom
feat/add-user-guide-links

Conversation

@hoangsvit

@hoangsvit hoangsvit commented Jul 24, 2026

Copy link
Copy Markdown
Member

Summary

  • add a help icon beside the theme and settings actions in the main popup header;
  • add the same localized help action beside the disable-site and close controls in the inline helper popup;
  • open the public Gmail Alias Toolkit guide in a new browser tab;
  • add UTM parameters for extension-origin traffic;
  • define userGuide through WXT locale files under public/_locales/*/messages.json for all 14 supported locales;
  • consume the label through the existing t("userGuide") helper in both extension surfaces;
  • handle unavailable browser APIs with a safe window fallback;
  • add unit coverage for Store-tab navigation, fallback navigation, failure paths, and locale-key completeness.

Guide

https://ext.eplus.dev/gmail-alias-toolkit/introduction

Localization

The extension uses the standard WXT/WebExtension localization structure:

"userGuide": {
  "message": "User guide"
}

The custom TypeScript translation map was removed. A regression test scans every directory in public/_locales and fails when userGuide is missing or empty.

UX

Both extension surfaces use a compact question-mark icon. The tooltip and aria-label are resolved by browser.i18n.getMessage() through the existing t() helper.

The inline helper uses a regular secure external link (target="_blank", rel="noopener noreferrer") so it works from a content script without adding any new permission.

Testing

  • GitHub Actions workflow validation
  • TypeScript compile
  • Unit tests
  • Production extension build
  • Production manifest-scope verification
  • Website build
  • CodeRabbit
  • Qodo findings addressed

Notes

This PR targets dev and is intentionally separate from release PR #78.

@eplus-bot

Copy link
Copy Markdown
Contributor

Thank you for creating this pull request and helping make the project better.

We will review / merge it when we are online.

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 82cce4f8-631e-44d7-812f-86e46f7d6ab0

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/add-user-guide-links

Comment @coderabbitai help to get the list of available commands.

@eplus-bot eplus-bot added needs-review Pull request is ready for maintainer review app Application or extension source code ui User interface or visual changes tests Test coverage or test tooling changes labels Jul 24, 2026
@eplus-bot
eplus-bot self-requested a review July 24, 2026 08:23
@qodo-code-review

qodo-code-review Bot commented Jul 24, 2026

Copy link
Copy Markdown

PR Summary by Qodo

Add localized User Guide help links to popup and inline helper

✨ Enhancement 🧪 Tests ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Add a localized “User guide” help action to the extension popup header.
• Add a localized help link to the inline helper popup without new permissions.
• Centralize tracked guide URL + safe navigation fallback, with unit coverage.
Diagram

graph TD
  PH["Popup header (React)"] --> EL["externalLinks.ts"] --> Tabs["browser.tabs.create"] --> Site{{"User guide site"}}
  EL --> Win["window.open fallback"] --> Site
  CS["Inline helper (content)"] --> Site
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Route all guide opens through a background/service worker
  • ➕ Single navigation implementation for popup + content scripts
  • ➕ Centralized logging/telemetry and consistent error handling
  • ➕ Can enforce tab-opening behavior uniformly
  • ➖ Requires messaging plumbing and background availability
  • ➖ More moving parts than a simple content-script anchor
  • ➖ May require revisiting permissions depending on implementation
2. Host an in-extension guide page (chrome-extension://) that links out
  • ➕ Offline-friendly landing page and easier versioning
  • ➕ Can provide contextual deep links by surface
  • ➖ More UI/content to maintain
  • ➖ Still ultimately links to external docs for canonical guide

Recommendation: Current approach is well-balanced: the popup uses a centralized helper with tabs-first navigation and a safe window fallback, while the inline helper intentionally uses a standard external link to avoid adding permissions or cross-context messaging. Keep this design unless you later need unified analytics/error reporting across surfaces, in which case a background-routed open would be the next step.

Files changed (20) +232 / -8

Enhancement (4) +87 / -2
email-helper.cssStyle inline helper User Guide icon and tooltip behavior +28/-0

Style inline helper User Guide icon and tooltip behavior

• Adds a new '.gmail-alias-popup-user-guide' control styled to match existing header actions. Shares tooltip pseudo-element behavior with the existing disable-site button and aligns box sizing.

entrypoints/content/email-helper.css

index.tsAdd localized User Guide link to inline helper popup header +9/-0

Add localized User Guide link to inline helper popup header

• Imports the tracked 'USER_GUIDE_URL' and injects a help icon link into the inline helper header. Uses localized tooltip/aria-label text via 't("userGuide")' and opens via a normal external anchor ('target=_blank', 'rel=noopener noreferrer').

entrypoints/content/index.ts

PopupHeader.tsxAdd popup header help button that opens the User Guide safely +23/-2

Add popup header help button that opens the User Guide safely

• Adds a question-mark help icon next to theme/settings actions and localizes its tooltip/aria-label via 't("userGuide")'. Wraps guide navigation in a handler that catches and logs unexpected failures.

src/components/alias/PopupHeader.tsx

externalLinks.tsCentralize tracked User Guide URL and tab/window navigation fallback +27/-0

Centralize tracked User Guide URL and tab/window navigation fallback

• Introduces 'USER_GUIDE_URL' with UTM parameters and an 'openUserGuide()' helper. Attempts 'browser.tabs.create' first and falls back to 'globalThis.open' with noopener/noreferrer hardening.

src/utils/externalLinks.ts

Tests (2) +85 / -0
userGuideLocales.test.tsVerify 'userGuide' translation coverage across all locale bundles +35/-0

Verify 'userGuide' translation coverage across all locale bundles

• Adds a Vitest suite that enumerates 'public/_locales/*/messages.json' and asserts 'userGuide.message' exists and is non-empty for every locale directory.

tests/i18n/userGuideLocales.test.ts

externalLinks.test.tsTest user guide navigation success, fallback, and failure modes +50/-0

Test user guide navigation success, fallback, and failure modes

• Adds unit tests covering tab navigation via 'browser.tabs.create', fallback to 'window.open' when tabs API rejects, and returning 'false' when neither method succeeds. Also validates that the URL includes expected UTM tracking parameters.

tests/utils/externalLinks.test.ts

Other (14) +60 / -6
messages.jsonAdd 'userGuide' locale string (de) +3/-0

Add 'userGuide' locale string (de)

• Introduces the 'userGuide' message key for German UI localization.

public/_locales/de/messages.json

messages.jsonAdd 'userGuide' locale string and reformat nearby keys (en) +21/-6

Add 'userGuide' locale string and reformat nearby keys (en)

• Adds the 'userGuide' message key for English and expands several adjacent inline-helper message entries into multi-line JSON objects.

public/_locales/en/messages.json

messages.jsonAdd 'userGuide' locale string (es) +3/-0

Add 'userGuide' locale string (es)

• Introduces the 'userGuide' message key for Spanish UI localization.

public/_locales/es/messages.json

messages.jsonAdd 'userGuide' locale string (fr) +3/-0

Add 'userGuide' locale string (fr)

• Introduces the 'userGuide' message key for French UI localization.

public/_locales/fr/messages.json

messages.jsonAdd 'userGuide' locale string (hi) +3/-0

Add 'userGuide' locale string (hi)

• Introduces the 'userGuide' message key for Hindi UI localization.

public/_locales/hi/messages.json

messages.jsonAdd 'userGuide' locale string (it) +3/-0

Add 'userGuide' locale string (it)

• Introduces the 'userGuide' message key for Italian UI localization.

public/_locales/it/messages.json

messages.jsonAdd 'userGuide' locale string (ja) +3/-0

Add 'userGuide' locale string (ja)

• Introduces the 'userGuide' message key for Japanese UI localization.

public/_locales/ja/messages.json

messages.jsonAdd 'userGuide' locale string (ko) +3/-0

Add 'userGuide' locale string (ko)

• Introduces the 'userGuide' message key for Korean UI localization.

public/_locales/ko/messages.json

messages.jsonAdd 'userGuide' locale string (pl) +3/-0

Add 'userGuide' locale string (pl)

• Introduces the 'userGuide' message key for Polish UI localization.

public/_locales/pl/messages.json

messages.jsonAdd 'userGuide' locale string (pt_BR) +3/-0

Add 'userGuide' locale string (pt_BR)

• Introduces the 'userGuide' message key for Brazilian Portuguese UI localization.

public/_locales/pt_BR/messages.json

messages.jsonAdd 'userGuide' locale string (ru) +3/-0

Add 'userGuide' locale string (ru)

• Introduces the 'userGuide' message key for Russian UI localization.

public/_locales/ru/messages.json

messages.jsonAdd 'userGuide' locale string (tr) +3/-0

Add 'userGuide' locale string (tr)

• Introduces the 'userGuide' message key for Turkish UI localization.

public/_locales/tr/messages.json

messages.jsonAdd 'userGuide' locale string (vi) +3/-0

Add 'userGuide' locale string (vi)

• Introduces the 'userGuide' message key for Vietnamese UI localization.

public/_locales/vi/messages.json

messages.jsonAdd 'userGuide' locale string (zh_CN) +3/-0

Add 'userGuide' locale string (zh_CN)

• Introduces the 'userGuide' message key for Simplified Chinese UI localization.

public/_locales/zh_CN/messages.json

@eplus-bot eplus-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved by @eplus-bot after all pull request checks passed.

CI run: https://github.com/ePlus-DEV/gmail-alias-toolkit/actions/runs/30078727586

@eplus-bot

eplus-bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

CI passed

Approved by @eplus-bot after all pull request checks passed.

Approval refresh: #6
CI updated: 2026-07-24T09:30:05Z
CI attempt: #1
Approval workflow: #396.1

CI run: https://github.com/ePlus-DEV/gmail-alias-toolkit/actions/runs/30082747530

@hoangsvit
hoangsvit requested a review from eplus-bot July 24, 2026 08:24
@qodo-code-review

qodo-code-review Bot commented Jul 24, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Test callbacks missing JSDoc ✓ Resolved 📘 Rule violation ⚙ Maintainability ⭐ New JS-D1001
Description
tests/i18n/userGuideLocales.test.ts introduces multiple arrow functions (e.g., describe,
.filter, it) without JSDoc comments, which violates the requirement that all functions/arrow
functions include at least a one-line JSDoc purpose description. This can trigger DeepSource
documentation warnings and block the PR from meeting zero-issues expectations.
Code

tests/i18n/userGuideLocales.test.ts[R5-11]

+describe("WXT user guide translations", () => {
+  const localesRoot = resolve(process.cwd(), "public/_locales");
+  const localeDirectories = readdirSync(localesRoot, {
+    withFileTypes: true,
+  }).filter((entry) => entry.isDirectory());
+
+  it("defines a non-empty userGuide message for every locale", () => {
Evidence
PR Compliance ID 1 requires JSDoc on every function/arrow function. The added `describe(..., () =>
{...}), .filter((entry) => ...), and it(..., () => {...})` callbacks in the new test file have
no preceding JSDoc comments, which violates that requirement.

Rule JS-D1001: All Functions and Exported Components Must Have JSDoc Comments
tests/i18n/userGuideLocales.test.ts[5-11]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new test file adds several arrow function callbacks without JSDoc (e.g., the `describe` callback, the `.filter()` predicate, and the `it` callback). The compliance checklist requires every function/arrow function to have at least a one-line JSDoc.

## Issue Context
DeepSource rule JS-D1001 is expected to flag missing function documentation; this new file should not introduce documentation violations.

## Fix Focus Areas
- tests/i18n/userGuideLocales.test.ts[5-11]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Unchecked replace then delete ✓ Resolved 🐞 Bug ≡ Correctness
Description
The migration script uses exact string replace() operations to edit TS files and then
unconditionally deletes src/i18n/userGuide.ts and tests/i18n/userGuide.test.ts; if any replace
doesn’t match (formatting/import differences), the workflow can push a commit that still references
deleted modules and fails to build. The unconditional unlink() also makes reruns/non-happy-path
recovery fail with FileNotFoundError if the files were already removed.
Code

.github/workflows/migrate-user-guide-locales.yml[R54-80]

+          popup_path = Path("src/components/alias/PopupHeader.tsx")
+          popup = popup_path.read_text(encoding="utf-8")
+          popup = popup.replace(
+              'import { getUserGuideLabel } from "src/i18n/userGuide";\n',
+              "",
+          )
+          popup = popup.replace(
+              "  const userGuideLabel = getUserGuideLabel();",
+              '  const userGuideLabel = t("userGuide");',
+          )
+          popup_path.write_text(popup, encoding="utf-8")
+
+          content_path = Path("entrypoints/content/index.ts")
+          content = content_path.read_text(encoding="utf-8")
+          content = content.replace(
+              'import { getUserGuideLabel } from "src/i18n/userGuide";\n',
+              "",
+          )
+          content = content.replace(
+              "    userGuide: escapeHtml(getUserGuideLabel()),",
+              '    userGuide: escapeHtml(t("userGuide")),',
+          )
+          content_path.write_text(content, encoding="utf-8")
+
+          Path("src/i18n/userGuide.ts").unlink()
+          Path("tests/i18n/userGuide.test.ts").unlink()
+
Evidence
The workflow performs fixed-string replacements for imports/usages and then unconditionally unlinks
the referenced module and test file; there is no check that replacements occurred before deletion.

.github/workflows/migrate-user-guide-locales.yml[54-80]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The workflow mutates source files via brittle string replacements and then deletes files regardless of whether the replacements succeeded. This can create a broken commit (deleted module still imported) and makes reruns fail.

## Issue Context
The script:
- removes an import line only if it matches exactly
- replaces a specific callsite string only if it matches exactly
- unconditionally unlinks the underlying module/test files

## Fix Focus Areas
- .github/workflows/migrate-user-guide-locales.yml[54-80]

## Suggested fix
- After each `replace()`, validate that the expected before-text existed (e.g., check `if old_text not in popup: raise RuntimeError(...)`) and/or verify the replacement count.
- Before `unlink()`, either:
 - check existence (`if path.exists(): path.unlink()`), or
 - catch `FileNotFoundError`.
- Optionally, after modifications, grep/assert that `getUserGuideLabel` no longer appears in the edited files before deleting the module.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. gmail-alias-popup-user-guide CSS unindented ✓ Resolved 📘 Rule violation ⚙ Maintainability CI-Gates
Description
The newly added .gmail-alias-popup-user-guide CSS rules in email-helper.css are not
indented/formatted consistently with the surrounding stylesheet, which reduces readability and can
cause Prettier/formatting CI gates to fail. This inconsistency appears only in the new block and
could block merges when CI enforces formatting compliance.
Code

entrypoints/content/email-helper.css[R266-289]

+.gmail-alias-popup-user-guide {
+position: relative;
+display: flex;
+width: 28px;
+height: 28px;
+box-sizing: border-box;
+align-items: center;
+justify-content: center;
+padding: 0;
+border: 1px solid #bfdbfe;
+border-radius: 7px;
+background: #eff6ff;
+color: #2563eb;
+cursor: pointer;
+text-decoration: none;
+}
+
+.gmail-alias-popup-user-guide:hover,
+.gmail-alias-popup-user-guide:focus-visible {
+border-color: #93c5fd;
+background: #dbeafe;
+color: #1d4ed8;
+outline: none;
+}
Evidence
PR Compliance ID 5 requires code to pass CI gates including Prettier formatting, and the added
.gmail-alias-popup-user-guide block shows unindented declarations (e.g., position, display,
etc.) compared to the file’s normal indentation style. The immediately following
.gmail-alias-popup-disable-site block uses the expected indentation, demonstrating that the new
block deviates from the established formatting and would likely be flagged by Prettier/format
checks.

Rule CI-Gates: Code Must Pass CI Quality Gates: Tests, Coverage, TypeScript Strict Checks, and Prettier Formatting
entrypoints/content/email-helper.css[266-289]
entrypoints/content/email-helper.css[266-309]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `.gmail-alias-popup-user-guide` CSS block was added with inconsistent indentation/formatting compared to the rest of `email-helper.css`, which hurts maintainability and risks failing Prettier/formatting CI gates.

## Issue Context
- This repository’s CI gate requires Prettier formatting compliance.
- Neighboring rules in this stylesheet consistently indent declarations (e.g., the adjacent `.gmail-alias-popup-disable-site` block), but the new `.gmail-alias-popup-user-guide` declarations (including its `:hover/:focus-visible` block) are not indented.
- Re-indenting to match the surrounding convention (or running the project formatter, if available) should resolve the inconsistency and avoid CI failures.

## Fix Focus Areas
- entrypoints/content/email-helper.css[266-289]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (2)
4. openUserGuide() lacks error test ✓ Resolved 📘 Rule violation ☼ Reliability Test Standards 2
Description
openUserGuide() relies on browser.tabs.create() but the new unit test only covers the success
path and never exercises a failure/rejection scenario. This violates the requirement to cover both
success and error paths with appropriate mocking for browser APIs.
Code

tests/utils/externalLinks.test.ts[R13-24]

+  it("opens the tracked user guide URL in a browser tab", async () => {
+    const create = vi.fn().mockResolvedValue(undefined);
+    vi.stubGlobal("browser", { tabs: { create } });
+
+    await openUserGuide();
+
+    expect(create).toHaveBeenCalledWith({ url: USER_GUIDE_URL });
+    expect(USER_GUIDE_URL).toContain(
+      "https://ext.eplus.dev/gmail-alias-toolkit/introduction",
+    );
+    expect(USER_GUIDE_URL).toContain("utm_medium=extension");
+  });
Evidence
PR Compliance ID 4 requires unit tests to cover both success and error paths and to mock browser
APIs. The added test only asserts browser.tabs.create is called successfully, while
openUserGuide() directly awaits browser.tabs.create and has no corresponding rejection-path
test.

Rule Test Standards 2: Unit Tests Must Follow Required Organization and Coverage of Paths
tests/utils/externalLinks.test.ts[13-24]
src/utils/externalLinks.ts[4-7]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The unit tests for `openUserGuide()` only validate the success path and do not cover the error/rejection path from `browser.tabs.create()`, which is required by the test standards.

## Issue Context
`openUserGuide()` awaits `browser.tabs.create({ url: USER_GUIDE_URL })`. Browser APIs can reject (permissions, runtime errors), and the test suite should include an error-path test that mocks and asserts the behavior.

## Fix Focus Areas
- tests/utils/externalLinks.test.ts[13-24]
- src/utils/externalLinks.ts[4-7]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. getUserGuideLabel() browser path untested ✓ Resolved 📘 Rule violation ☼ Reliability Test Standards 2
Description
The popup calls getUserGuideLabel() with no argument (browser-locale path), but the new unit test
suite only calls it with an explicit locale and never mocks browser.i18n.getUILanguage. This
violates the requirement to cover relevant execution paths and mock external dependencies such as
browser APIs.
Code

tests/i18n/userGuide.test.ts[R4-14]

+describe("user guide labels", () => {
+  it("resolves supported base and regional locales", () => {
+    expect(getUserGuideLabel("vi-VN")).toBe("Hướng dẫn sử dụng");
+    expect(getUserGuideLabel("pt-BR")).toBe("Guia do usuário");
+    expect(getUserGuideLabel("zh-CN")).toBe("用户指南");
+    expect(getUserGuideLabel("ja-JP")).toBe("ユーザーガイド");
+  });
+
+  it("falls back to English for unsupported locales", () => {
+    expect(getUserGuideLabel("unknown")).toBe("User guide");
+  });
Evidence
PR Compliance ID 4 requires tests to cover relevant paths and mock external dependencies (browser
APIs). The production code calls getUserGuideLabel() without a locale, which uses
browser.i18n.getUILanguage, but the new tests only pass explicit locale strings and never
stub/mock the browser API branch.

Rule Test Standards 2: Unit Tests Must Follow Required Organization and Coverage of Paths
src/components/alias/PopupHeader.tsx[53-54]
src/i18n/userGuide.ts[18-28]
tests/i18n/userGuide.test.ts[4-14]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`getUserGuideLabel()` has a code path that depends on `browser.i18n.getUILanguage`, and production code calls it without arguments, but the unit tests only cover the explicit-parameter path and do not mock the browser API.

## Issue Context
In `PopupHeader`, `getUserGuideLabel()` is invoked with no parameters, which exercises the browser-locale resolution branch. The test standards require coverage of relevant paths and mocking external dependencies.

## Fix Focus Areas
- src/components/alias/PopupHeader.tsx[53-54]
- src/i18n/userGuide.ts[18-28]
- tests/i18n/userGuide.test.ts[4-14]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

6. Migration workflow won't run ✓ Resolved 🐞 Bug ☼ Reliability
Description
The migration workflow only triggers on pull_request reopened and is additionally gated to PR
#85 + a specific head_ref, so it can easily never execute (e.g., PR merged without reopening) and
therefore never performs the migration or self-deletes. This can leave the branch (and potentially
the merged repo) with an unintended, confusing workflow that never ran.
Code

.github/workflows/migrate-user-guide-locales.yml[R3-13]

+on:
+  pull_request:
+    types: [reopened]
+
+permissions:
+  contents: write
+
+jobs:
+  migrate:
+    if: github.event.pull_request.number == 85 && github.head_ref == 'feat/add-user-guide-links'
+    runs-on: ubuntu-latest
Evidence
The trigger is restricted to only pull_request events of type reopened, and the job itself is
further restricted to a specific PR number and head branch, which makes execution dependent on a
narrow PR lifecycle event.

.github/workflows/migrate-user-guide-locales.yml[3-13]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The workflow is designed to run once, migrate translations, then delete itself. As written it only triggers on `pull_request.reopened` and is further restricted by a hard-coded PR number/branch condition, so it can easily never run.

## Issue Context
If the PR is merged without a reopen event, the workflow will not execute, meaning:
- the migration won’t happen
- the workflow won’t self-delete

## Fix Focus Areas
- .github/workflows/migrate-user-guide-locales.yml[3-13]

## Suggested fix
- Add `workflow_dispatch` so it can be run intentionally once, and/or broaden the event to include `pull_request: [opened, synchronize]` while keeping the strict `if:` guard.
- Alternatively, avoid committing this workflow at all: run the migration locally and commit the results, keeping CI workflows free of one-off mutations.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Pushes without build validation ✓ Resolved 🐞 Bug ☼ Reliability
Description
After modifying locale JSON and rewriting TS sources, the workflow only validates that locale files
are parseable JSON and then immediately commits/pushes, so it can push a migration commit that fails
typecheck/tests (especially given the brittle string replacement approach). This increases the
chance of breaking the PR branch and requiring manual recovery.
Code

.github/workflows/migrate-user-guide-locales.yml[R122-135]

+      - name: Validate generated locale files
+        shell: bash
+        run: |
+          node -e 'const fs=require("fs"); for (const locale of fs.readdirSync("public/_locales")) JSON.parse(fs.readFileSync(`public/_locales/${locale}/messages.json`, "utf8"));'
+
+      - name: Commit migration and remove temporary workflow
+        shell: bash
+        run: |
+          git rm .github/workflows/migrate-user-guide-locales.yml
+          git config user.name "github-actions[bot]"
+          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
+          git add public/_locales src/components/alias/PopupHeader.tsx entrypoints/content/index.ts tests/i18n src/i18n
+          git commit -m "refactor: use WXT locales for user guide labels"
+          git push origin HEAD:${{ github.head_ref }}
Evidence
The only validation step parses JSON files, and the workflow proceeds directly to commit and push
without any TS/build/test validation.

.github/workflows/migrate-user-guide-locales.yml[122-135]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The workflow pushes code changes after only JSON parsing validation, without verifying the refactor compiles/tests.

## Issue Context
Given the script’s use of exact string replacements, a small mismatch can leave broken TS imports/usages that won’t be caught before `git push`.

## Fix Focus Areas
- .github/workflows/migrate-user-guide-locales.yml[122-135]

## Suggested fix
- Add a lightweight sanity check before committing, such as:
 - searching for stale references (`grep -R "getUserGuideLabel" ...` and fail if found), and/or
 - running the repo’s existing typecheck/test command(s) (whatever CI uses) before `git commit`.
- If running full tests is too heavy, at least ensure both edited TS files still parse/compile via the project’s standard check step.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Inconsistent action box-sizing ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
The new .gmail-alias-popup-user-guide explicitly sets box-sizing: border-box while the adjacent
.gmail-alias-popup-disable-site does not, so the two fixed-size (28px) header actions can end up
with different rendered sizes depending on browser/user-agent defaults. This can misalign the header
action row and produce inconsistent hit areas across browsers.
Code

entrypoints/content/email-helper.css[R266-281]

+.gmail-alias-popup-user-guide {
+position: relative;
+display: flex;
+width: 28px;
+height: 28px;
+box-sizing: border-box;
+align-items: center;
+justify-content: center;
+padding: 0;
+border: 1px solid #bfdbfe;
+border-radius: 7px;
+background: #eff6ff;
+color: #2563eb;
+cursor: pointer;
+text-decoration: none;
+}
Evidence
The user-guide action sets box-sizing: border-box while the disable-site action does not declare
box-sizing, and both are rendered adjacent in the header actions row with fixed 28px
dimensions—making their computed outer sizes potentially divergent across browsers.

entrypoints/content/email-helper.css[266-303]
entrypoints/content/index.ts[248-265]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new user-guide header action forces `box-sizing: border-box`, but the neighboring disable-site action does not. Because both controls set fixed `width/height` and borders, leaving `box-sizing` implicit on one control makes final sizing depend on browser defaults.

## Issue Context
In the content-script popup header, the user guide `<a>` and disable-site `<button>` are rendered side-by-side. Styling should be deterministic across browsers.

## Fix Focus Areas
- entrypoints/content/email-helper.css[266-303]

## Suggested fix
Apply `box-sizing: border-box;` consistently to both header action controls (e.g., add it to `.gmail-alias-popup-disable-site`, or move it to a shared selector covering both actions).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (2)
9. Unguarded i18n API access ✓ Resolved 🐞 Bug ☼ Reliability
Description
getUserGuideLabel() dereferences browser.i18n without guarding browser/i18n existence, so
calling it without an explicit locale can throw at render time in environments where
browser.i18n isn’t present (e.g., unit tests). This is inconsistent with the existing t()
helper, which defensively wraps browser.i18n access to avoid runtime crashes.
Code

src/i18n/userGuide.ts[R19-22]

+export function getUserGuideLabel(locale?: string): string {
+  const browserLocale = locale ?? browser.i18n.getUILanguage?.() ?? "en";
+  const normalizedLocale = browserLocale.toLowerCase().replaceAll("-", "_");
+  const baseLocale = normalizedLocale.split("_")[0];
Evidence
The new helper assumes browser.i18n exists, while the test environment’s browser stub does not
define i18n, and the existing translation helper already defensively catches browser.i18n access
failures—indicating this crash scenario is expected/handled elsewhere.

src/i18n/userGuide.ts[18-22]
src/components/alias/PopupHeader.tsx[42-55]
tests/setup.ts[4-19]
lib/i18n.ts[3-12]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`getUserGuideLabel()` directly reads `browser.i18n.getUILanguage?.()`; optional chaining only guards the function, not `browser` or `browser.i18n`. In non-extension contexts (notably unit tests), this can throw before the function can fall back to English.

## Issue Context
The repo already treats `browser.i18n` as potentially unavailable (see `lib/i18n.ts` try/catch), and the test setup stubs `globalThis.browser` without `i18n`.

## Fix Focus Areas
- src/i18n/userGuide.ts[18-28]
- tests/setup.ts[4-19]
- lib/i18n.ts[3-12]

## Suggested fix
- Make locale detection resilient, e.g.:
 - Prefer the passed `locale` when provided.
 - Otherwise attempt `globalThis.browser?.i18n?.getUILanguage?.()` inside a try/catch.
 - Fall back to `'en'` if anything is missing/throws.
- Optionally add `i18n.getUILanguage` to the test `browser` stub (or keep the function guard so tests don’t need to).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


10. Unhandled user-guide open errors ✓ Resolved 🐞 Bug ☼ Reliability
Description
handleOpenUserGuide() discards the openUserGuide() promise (void openUserGuide()), so any
failure from browser.tabs.create() can become an unhandled promise rejection and the click
provides no fallback behavior. This can make the help action fail without controlled
logging/handling.
Code

src/components/alias/PopupHeader.tsx[R42-45]

+/** Opens the public user guide without blocking the popup event handler. */
+function handleOpenUserGuide() {
+  void openUserGuide();
+}
Evidence
The popup handler explicitly discards the async operation, and the underlying implementation awaits
a browser API call that can reject; with no catch, failures aren’t handled in a controlled way.

src/components/alias/PopupHeader.tsx[42-45]
src/utils/externalLinks.ts[4-6]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`handleOpenUserGuide()` ignores the promise returned by `openUserGuide()`. If `browser.tabs.create` rejects, this can trigger unhandled promise rejection behavior and provides no controlled handling/logging.

## Issue Context
`openUserGuide()` awaits `browser.tabs.create({ url })`, which can reject (runtime/API availability issues). Since the click handler drops the promise, there is no error path.

## Fix Focus Areas
- src/components/alias/PopupHeader.tsx[42-83]
- src/utils/externalLinks.ts[1-7]

## Suggested fix
- Add explicit rejection handling in the click handler, e.g.:
 - `void openUserGuide().catch((err) => console.error('Failed to open user guide', err));`
 - or make the handler `async` and wrap in `try/catch`.
- (Optional) Provide UI feedback if opening fails (toast/snackbar) if the app has a pattern for it.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread tests/utils/externalLinks.test.ts
Comment thread tests/i18n/userGuide.test.ts Outdated
Comment thread src/i18n/userGuide.ts Outdated
Comment thread src/components/alias/PopupHeader.tsx Outdated
@eplus-bot eplus-bot added the build-ci Build, CI, release, or project configuration label Jul 24, 2026
@hoangsvit hoangsvit closed this Jul 24, 2026
@hoangsvit hoangsvit reopened this Jul 24, 2026
@hoangsvit hoangsvit closed this Jul 24, 2026
@hoangsvit hoangsvit reopened this Jul 24, 2026

@eplus-bot eplus-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved by @eplus-bot after all pull request checks passed.

CI run: https://github.com/ePlus-DEV/gmail-alias-toolkit/actions/runs/30080098482

Comment thread entrypoints/content/email-helper.css
Comment thread entrypoints/content/email-helper.css
@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit ef95855

@hoangsvit hoangsvit reopened this Jul 24, 2026

@eplus-bot eplus-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved by @eplus-bot after all pull request checks passed.

CI run: https://github.com/ePlus-DEV/gmail-alias-toolkit/actions/runs/30080709748

@hoangsvit hoangsvit changed the title feat: add localized user guide link to popup header feat: add localized user guide links to popup and inline helper Jul 24, 2026
@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 7387184

@eplus-bot
eplus-bot self-requested a review July 24, 2026 09:10
@hoangsvit hoangsvit closed this Jul 24, 2026
@hoangsvit hoangsvit reopened this Jul 24, 2026
Comment thread .github/workflows/migrate-user-guide-locales.yml Outdated
Comment thread .github/workflows/migrate-user-guide-locales.yml Outdated
Comment thread .github/workflows/migrate-user-guide-locales.yml Outdated
@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 88f95c9

@hoangsvit hoangsvit closed this Jul 24, 2026
@hoangsvit hoangsvit reopened this Jul 24, 2026
@hoangsvit hoangsvit closed this Jul 24, 2026
@hoangsvit hoangsvit reopened this Jul 24, 2026
@eplus-bot eplus-bot added the i18n Translation or localization changes label Jul 24, 2026

@eplus-bot eplus-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved by @eplus-bot after all pull request checks passed.

CI run: https://github.com/ePlus-DEV/gmail-alias-toolkit/actions/runs/30082218729

Comment thread tests/i18n/userGuideLocales.test.ts Outdated
@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 5b36146

@eplus-bot
eplus-bot self-requested a review July 24, 2026 09:29

@eplus-bot eplus-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved by @eplus-bot after all pull request checks passed.

CI run: https://github.com/ePlus-DEV/gmail-alias-toolkit/actions/runs/30082747530

@hoangsvit
hoangsvit merged commit a4dca27 into dev Jul 24, 2026
5 checks passed
@hoangsvit
hoangsvit deleted the feat/add-user-guide-links branch July 24, 2026 09:47
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for helping make Gmail Alias Toolkit better!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app Application or extension source code build-ci Build, CI, release, or project configuration i18n Translation or localization changes needs-review Pull request is ready for maintainer review tests Test coverage or test tooling changes ui User interface or visual changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants