feat: add global copy ID button to all resources#3309
feat: add global copy ID button to all resources#3309Baluduvamsi2006 wants to merge 4 commits intoapache:masterfrom
Conversation
|
@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! 🚀 |
There was a problem hiding this comment.
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.Textcopyableand addcopy/copy_successi18n 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.
| window.__monacoEditor__ = editor; | ||
| }} |
There was a problem hiding this comment.
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.
| window.__monacoEditor__ = editor; | |
| }} | |
| (window as any).__monacoEditor__ = editor; | |
| }} | |
| onUnmount={(editor) => { | |
| const w = window as any; | |
| if (w.__monacoEditor__ === editor) { | |
| w.__monacoEditor__ = undefined; | |
| } | |
| }} |
e2e/utils/ui/index.ts
Outdated
| const isSet = await page.evaluate(() => window.__monacoEditor__ !== undefined).catch(() => false); | ||
| if (isSet) { | ||
| await page.evaluate(() => { | ||
| const editor = window.__monacoEditor__; | ||
| editor?.getModel()?.setValue(''); | ||
| }); |
There was a problem hiding this comment.
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.
| 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) { |
Why submit this pull request?
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
Replaces generic text IDs with Ant Design’s native
Typography.Textcopyablecomponent across 11 list views:Explicitly casts underlying IDs and usernames to
stringto ensure reliable behavior withTypography.Text.Adds full i18n support for:
copy(hover tooltip)copy_success(success message)Supported locales:
Integrates copyable behavior consistently into
PluginCardcomponents.🐛 Bugfix (E2E): Windows Path Resolution
e2e/utils/common.ts.new URL('.').pathnameprepended an extra slash on Windows, causing duplicated drive letters (e.g.D:\D:\) and breakingapisix_conf.ymlPlaywright lookups.fileURLToPath()for correct, cross-platform path handling.🐛 Bugfix (E2E): Monaco Editor Race Condition
TypeError: Cannot read properties of undefined (reading 'getModel')occurring across multiple Playwright tests.window.__monacoEditor__was not reliably available during test execution.Ctrl + A → Backspace) insideuiClearMonacoEditorto safely clear editor content during form interactions.This eliminates flaky E2E failures and stabilizes Playwright execution.