Skip to content

feat: add global copy ID button to all resources#3309

Open
Baluduvamsi2006 wants to merge 4 commits intoapache:masterfrom
Baluduvamsi2006:feat/add-global-copy-id
Open

feat: add global copy ID button to all resources#3309
Baluduvamsi2006 wants to merge 4 commits intoapache:masterfrom
Baluduvamsi2006:feat/add-global-copy-id

Conversation

@Baluduvamsi2006
Copy link
Contributor

@Baluduvamsi2006 Baluduvamsi2006 commented Mar 1, 2026

Why submit this pull request?

  • Bugfix
  • New feature provided
  • Improve performance
  • Backport patches

What changes will this PR take into?

This PR introduces a global one-click copy-to-clipboard functionality for Resource IDs across all list pages to significantly improve user experience. It also resolves persistent E2E test timeout and file path issues when running locally on Windows.


Detailed Implementation

✨ Feature: Global Copy-to-Clipboard Support

image
  • Replaces generic text IDs with Ant Design’s native Typography.Text copyable component across 11 list views:

    • Services
    • Routes
    • Upstreams
    • SSLs
    • Consumers
    • Global Rules
    • Plugin Configs
    • Protos
    • Secrets
    • Consumer Groups
    • Credentials
  • Explicitly casts underlying IDs and usernames to string to ensure reliable behavior with Typography.Text.

  • Adds full i18n support for:

    • copy (hover tooltip)
    • copy_success (success message)

    Supported locales:

    • English (en)
    • Chinese (zh)
    • Spanish (es)
    • German (de)
    • Turkish (tr)
  • Integrates copyable behavior consistently into PluginCard components.


🐛 Bugfix (E2E): Windows Path Resolution

  • Fixes an incorrect path resolution issue in e2e/utils/common.ts.
  • new URL('.').pathname prepended an extra slash on Windows, causing duplicated drive letters (e.g. D:\D:\) and breaking apisix_conf.yml Playwright lookups.
  • Replaced with Node.js native fileURLToPath() for correct, cross-platform path handling.

🐛 Bugfix (E2E): Monaco Editor Race Condition

  • Fixes TypeError: Cannot read properties of undefined (reading 'getModel') occurring across multiple Playwright tests.
  • Root cause: window.__monacoEditor__ was not reliably available during test execution.
  • Resolution:
    • Explicitly exposes the Monaco editor during component mounting.
    • Adds a physical keystroke fallback (Ctrl + A → Backspace) inside uiClearMonacoEditor to safely clear editor content during form interactions.

This eliminates flaky E2E failures and stabilizes Playwright execution.

@Baluduvamsi2006
Copy link
Contributor Author

@Baoyuantop @SkyeYoung Could you please take a moment to review this PR when you have some time? Let me know if you'd like any adjustments or have any feedback! Thank you! 🚀

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds consistent copy-to-clipboard support for resource identifiers across list views, plus E2E stability improvements (Windows path resolution + Monaco editor flake fixes).

Changes:

  • Replace ID/username cells in multiple ProTable list pages with Ant Design Typography.Text copyable and add copy/copy_success i18n keys.
  • Stabilize Monaco editor E2E interactions by always exposing the editor instance and adding a keyboard-based clearing fallback.
  • Fix Windows E2E path resolution by switching URL pathname handling to fileURLToPath, and relax list assertions to account for extra rendered text.

Reviewed changes

Copilot reviewed 29 out of 29 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/routes/upstreams/index.tsx Make upstream ID column copyable with localized tooltips.
src/routes/stream_routes/index.tsx Make stream route ID column copyable with localized tooltips.
src/routes/ssls/index.tsx Make SSL ID column copyable with localized tooltips.
src/routes/services/index.tsx Make service ID column copyable with localized tooltips.
src/routes/secrets/index.tsx Make secret ID column copyable with localized tooltips.
src/routes/routes/index.tsx Make route ID column copyable with localized tooltips.
src/routes/protos/index.tsx Make proto ID column copyable with localized tooltips.
src/routes/plugin_configs/index.tsx Make plugin config ID column copyable with localized tooltips.
src/routes/global_rules/index.tsx Make global rule ID column copyable with localized tooltips.
src/routes/consumers/index.tsx Make consumer username column copyable with localized tooltips.
src/routes/consumers/detail.$username/credentials/index.tsx Make credential ID column copyable with localized tooltips.
src/routes/consumer_groups/index.tsx Make consumer group ID column copyable with localized tooltips.
src/routeTree.gen.ts Regenerated TanStack Router route tree/types.
src/locales/en/common.json Add copy and copy_success translations (EN).
src/locales/zh/common.json Add copy and copy_success translations (ZH).
src/locales/es/common.json Add copy and copy_success translations (ES).
src/locales/de/common.json Add copy and copy_success translations (DE).
src/locales/tr/common.json Add copy and copy_success translations (TR).
src/components/form/Editor.tsx Always expose Monaco editor instance on window for E2E.
src/components/form-slice/FormItemPlugins/PluginCard.tsx Make plugin name copyable in PluginCard header.
e2e/utils/ui/index.ts Add robust Monaco clear helper with fallback keystrokes; update call site.
e2e/utils/common.ts Use fileURLToPath to make E2E config path resolution cross-platform.
e2e/tests/stream_routes.show-disabled-error.spec.ts Fix Windows path resolution with fileURLToPath.
e2e/tests/stream_routes.list.spec.ts Adjust pagination assertions to tolerate extra cell text.
e2e/tests/secrets.list.spec.ts Adjust pagination assertions to tolerate extra cell text.
e2e/tests/protos.list.spec.ts Adjust pagination assertions to tolerate extra cell text.
e2e/tests/global_rules.list.spec.ts Adjust pagination assertions to tolerate extra cell text.
e2e/tests/consumer_groups.list.spec.ts Adjust pagination assertions to tolerate extra cell text.
e2e/server/apisix_conf.yml Simplify/normalize APISIX test config formatting.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +148 to 149
window.__monacoEditor__ = editor;
}}
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

window.__monacoEditor__ is now assigned unconditionally. Since this creates a long-lived global reference, it can keep disposed editors/models from being garbage-collected and can leave a stale instance around after unmount. Consider either (a) clearing the global on unmount (if @monaco-editor/react's onUnmount is available) or (b) guarding the assignment behind an explicit E2E/dev flag so production doesn’t retain this global reference.

Suggested change
window.__monacoEditor__ = editor;
}}
(window as any).__monacoEditor__ = editor;
}}
onUnmount={(editor) => {
const w = window as any;
if (w.__monacoEditor__ === editor) {
w.__monacoEditor__ = undefined;
}
}}

Copilot uses AI. Check for mistakes.
Comment on lines +68 to +73
const isSet = await page.evaluate(() => window.__monacoEditor__ !== undefined).catch(() => false);
if (isSet) {
await page.evaluate(() => {
const editor = window.__monacoEditor__;
editor?.getModel()?.setValue('');
});
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

uiClearMonacoEditor currently performs two separate page.evaluate calls (one to check presence, one to clear). This can be simplified into a single evaluate (attempt to clear if present and return a success flag), which reduces round-trips and makes it easier to fall back to the keyboard-based clearing when the evaluate fails.

Suggested change
const isSet = await page.evaluate(() => window.__monacoEditor__ !== undefined).catch(() => false);
if (isSet) {
await page.evaluate(() => {
const editor = window.__monacoEditor__;
editor?.getModel()?.setValue('');
});
const clearedViaMonaco = await page
.evaluate(() => {
try {
const editor = (window as any).__monacoEditor__;
if (!editor || typeof editor.getModel !== 'function') {
return false;
}
const model = editor.getModel();
if (!model || typeof model.setValue !== 'function') {
return false;
}
model.setValue('');
return true;
} catch {
return false;
}
})
.catch(() => false);
if (clearedViaMonaco) {

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants