|
| 1 | +# Glossary Term Permanent Link - Implementation Complete ✅ |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +Implemented a permanent link feature for Glossary Terms that provides stable URLs based on UUID, solving the link breakage issue when terms are renamed. |
| 6 | + |
| 7 | +--- |
| 8 | + |
| 9 | +## What Changed |
| 10 | + |
| 11 | +### User-Facing Changes |
| 12 | + |
| 13 | +**New Copy Link Dropdown Menu:** |
| 14 | + |
| 15 | +Users can now click the copy button (📋) next to the glossary term title to access two link options: |
| 16 | + |
| 17 | +``` |
| 18 | +Term Name [📋▼] [⭐ Follow] |
| 19 | + ↓ Click to expand |
| 20 | + ┌────────────────────────────┐ |
| 21 | + │ 🔗 Copy URL based on FQN │ ← 12px font |
| 22 | + │ 📋 Copy URL based on ID │ ← 12px font |
| 23 | + └────────────────────────────┘ |
| 24 | + ↑ |
| 25 | + Appears bottom-right |
| 26 | + 180px min width |
| 27 | +``` |
| 28 | + |
| 29 | +**Two Link Types:** |
| 30 | + |
| 31 | +| Type | Menu Text | URL Format | Stability | |
| 32 | +|------|-----------|------------|-----------| |
| 33 | +| FQN Link | Copy URL based on FQN | `/glossary/Glossary.Term` | ❌ Breaks on rename | |
| 34 | +| ID Link | Copy URL based on ID | `/glossary/{uuid}` | ✅ Permanent | |
| 35 | + |
| 36 | +--- |
| 37 | + |
| 38 | +## Modified Files |
| 39 | + |
| 40 | +### Core Code (3 files) |
| 41 | + |
| 42 | +1. **EntityHeaderTitle.component.tsx** ⭐ Main change |
| 43 | + - Added dropdown menu logic for copy button |
| 44 | + - Implemented FQN and ID link copying |
| 45 | + - Font size: 12px |
| 46 | + - Dropdown width: 180px min |
| 47 | + - Position: bottomRight |
| 48 | + |
| 49 | +2. **EntityHeaderTitle.interface.ts** |
| 50 | + - Added `entityId?: string` prop |
| 51 | + - Added `entityFqn?: string` prop |
| 52 | + |
| 53 | +3. **EntityHeader.component.tsx** |
| 54 | + - Pass `entityData.id` and `entityData.fullyQualifiedName` to EntityHeaderTitle |
| 55 | + |
| 56 | +### Translation Files (1 file - English only) |
| 57 | + |
| 58 | +4. **en-us.json** |
| 59 | + - `copy-fqn-link`: "Copy URL based on FQN" |
| 60 | + - `copy-permanent-link`: "Copy URL based on ID" |
| 61 | + - `copy-link`: "Copy Link" |
| 62 | + |
| 63 | +**Note:** Chinese translations were removed per user request. The feature uses existing generic messages: |
| 64 | +- Success: `message.copied-to-clipboard` |
| 65 | +- Error: `server.unexpected-error` |
| 66 | + |
| 67 | +--- |
| 68 | + |
| 69 | +## Technical Implementation |
| 70 | + |
| 71 | +### Key Features |
| 72 | + |
| 73 | +1. **Backward Compatible** |
| 74 | + - If `entityId` and `entityFqn` are not provided → Original single copy button |
| 75 | + - If both are provided → New dropdown menu with two options |
| 76 | + |
| 77 | +2. **Smart URL Construction** |
| 78 | + ```typescript |
| 79 | + // FQN Link - Always rebuilt from entity data |
| 80 | + const fqnUrl = `${window.location.origin}/glossary/${encodeURIComponent(entityFqn)}`; |
| 81 | + |
| 82 | + // ID Link - Always uses UUID |
| 83 | + const permanentUrl = `${window.location.origin}/glossary/${entityId}`; |
| 84 | + ``` |
| 85 | + |
| 86 | +3. **Leverages Existing Backend** |
| 87 | + - No backend changes needed |
| 88 | + - Uses existing API: `GET /v1/glossaryTerms/{id}` |
| 89 | + - Frontend route `/glossary/{fqn}` already supports UUID |
| 90 | + |
| 91 | +--- |
| 92 | + |
| 93 | +## Testing |
| 94 | + |
| 95 | +### Quick Test |
| 96 | + |
| 97 | +```bash |
| 98 | +# 1. Build frontend |
| 99 | +cd /workspace/openmetadata-ui/src/main/resources/ui |
| 100 | +yarn build |
| 101 | + |
| 102 | +# 2. Start server |
| 103 | +cd /workspace |
| 104 | +./bin/openmetadata-server-start.sh |
| 105 | + |
| 106 | +# 3. Open browser |
| 107 | +open http://localhost:8585 |
| 108 | +``` |
| 109 | + |
| 110 | +### Test Cases |
| 111 | + |
| 112 | +**Test 1: Menu Display** |
| 113 | +- Open any glossary term page |
| 114 | +- Click copy button (📋) next to title |
| 115 | +- ✅ Verify dropdown appears bottom-right |
| 116 | +- ✅ Verify menu shows: |
| 117 | + - "Copy URL based on FQN" |
| 118 | + - "Copy URL based on ID" |
| 119 | +- ✅ Verify font size is 12px (smaller than title) |
| 120 | + |
| 121 | +**Test 2: Copy FQN Link** |
| 122 | +- Click "Copy URL based on FQN" |
| 123 | +- ✅ Toast shows: "Copied to the clipboard" |
| 124 | +- Paste in new tab |
| 125 | +- ✅ URL format: `/glossary/Glossary.Term` |
| 126 | +- ✅ Page loads correctly |
| 127 | + |
| 128 | +**Test 3: Copy ID Link** |
| 129 | +- Click "Copy URL based on ID" |
| 130 | +- ✅ Toast shows: "Copied to the clipboard" |
| 131 | +- Paste in new tab |
| 132 | +- ✅ URL format: `/glossary/{uuid}` |
| 133 | +- ✅ Page loads correctly |
| 134 | + |
| 135 | +**Test 4: Rename Stability (Core Test) 🔥** |
| 136 | +1. Create term "TestTerm" |
| 137 | +2. Copy "Copy URL based on ID" → Save as Link A |
| 138 | +3. Rename term to "RenamedTerm" |
| 139 | +4. Visit Link A |
| 140 | +5. ✅ **Expected: Link A still works, shows "RenamedTerm"** |
| 141 | + |
| 142 | +**Comparison:** |
| 143 | +1. Copy "Copy URL based on FQN" → Save as Link B |
| 144 | +2. After rename, visit Link B |
| 145 | +3. ❌ **Expected: Link B returns 404** |
| 146 | + |
| 147 | +--- |
| 148 | + |
| 149 | +## Code Quality |
| 150 | + |
| 151 | +- ✅ No TypeScript errors |
| 152 | +- ✅ No Linter warnings |
| 153 | +- ✅ JSON syntax valid |
| 154 | +- ✅ Backward compatible |
| 155 | +- ✅ No dead code |
| 156 | + |
| 157 | +**Stats:** |
| 158 | +``` |
| 159 | +Modified files: 3 code + 1 translation = 4 files |
| 160 | +Lines added: ~60 lines |
| 161 | +Lines removed: ~90 lines |
| 162 | +Net change: -30 lines (cleaner!) |
| 163 | +``` |
| 164 | + |
| 165 | +--- |
| 166 | + |
| 167 | +## User Requirements Checklist |
| 168 | + |
| 169 | +| Requirement | Implementation | Status | |
| 170 | +|-------------|----------------|--------| |
| 171 | +| 1. Text: "Copy URL based on FQN/ID" | Updated en-us.json | ✅ | |
| 172 | +| 2. English only, remove Chinese | Deleted Chinese translations | ✅ | |
| 173 | +| 3. Smaller font size | fontSize: 12px | ✅ | |
| 174 | +| 3. Bottom-right dropdown | placement="bottomRight" | ✅ | |
| 175 | + |
| 176 | +--- |
| 177 | + |
| 178 | +## Next Steps |
| 179 | + |
| 180 | +### For Testing |
| 181 | +1. Build: `yarn build` |
| 182 | +2. Start server |
| 183 | +3. Test on browser |
| 184 | +4. Verify core test: Rename stability |
| 185 | + |
| 186 | +### For Production |
| 187 | +1. Ensure all tests pass |
| 188 | +2. Get code review |
| 189 | +3. Merge to main branch |
| 190 | +4. Deploy to production |
| 191 | + |
| 192 | +--- |
| 193 | + |
| 194 | +## Documentation |
| 195 | + |
| 196 | +This is the final documentation. Previous interim documents have been cleaned up. |
| 197 | + |
| 198 | +For detailed test cases, see the Testing section above. |
| 199 | + |
| 200 | +--- |
| 201 | + |
| 202 | +## Summary |
| 203 | + |
| 204 | +✅ **Feature Complete** |
| 205 | +- Stable UUID-based links for glossary terms |
| 206 | +- Located next to term title (better UX) |
| 207 | +- Compact 12px font |
| 208 | +- English-only implementation |
| 209 | +- No backend changes required |
| 210 | + |
| 211 | +✅ **Solves Core Problem** |
| 212 | +- External references (Confluence, Notion, Wiki) won't break |
| 213 | +- Links remain valid after renaming |
| 214 | +- Knowledge base link integrity preserved |
| 215 | + |
| 216 | +--- |
| 217 | + |
| 218 | +**Implementation Date:** 2025-10-28 |
| 219 | +**Status:** ✅ Ready for Testing |
| 220 | +**Risk Level:** 🟢 Low (UI-only changes) |
0 commit comments