Found while closing #13957 in #14936, which converged the five Python copies of this rule onto UserCore.full_name / resolve_display_name(). The frontend half was out of that issue's stated scope.
Gap
"Show display_name, fall back to username" is re-implemented in the frontend too, with two more fallback depths than the backend had:
| file |
expression |
terminus |
components/collaboration/InviteUserDialog.vue |
user.display_name || user.username |
username |
views/llc/MembersView.vue |
u.display_name || u.username |
username |
views/llc/MembersView.vue |
member.display_name || member.user_id |
raw id |
composables/llc/useCompanyPeople.ts |
m.display_name || m.user_id |
raw id |
components/knowledge/ShareKnowledgeDialog.vue |
userData.display_name || userData.email || userData.username || id |
email rung, unique to this site |
views/AdminUsersView.vue |
user.display_name || '—' |
em-dash, no username fallback |
Root cause worth fixing first
The || m.user_id rungs exist because the two LLC endpoints disagree about who owns the last rung:
list_members can return display_name: null for a membership whose user row is gone, so the client has to invent a label.
_compose_human_nodes already resolves that case server-side to str(user_id).
So the frontend compensates for one endpoint and duplicates the other. Aligning the two endpoints removes the reason for two of the six copies, and should happen before a shared frontend helper is written — otherwise the helper just encodes the inconsistency.
AdminUsersView's em-dash terminus is a separate divergence: it renders a blank-looking cell where every other surface renders a username.
Ask
- Decide the single fallback ladder and which side owns each rung.
- Make the LLC endpoints agree, then one shared frontend helper for the render-time rule.
- No hardcoded UI strings — the em-dash terminus needs an i18n key across all 11 locales if it survives.
Related
Found while closing #13957 in #14936, which converged the five Python copies of this rule onto
UserCore.full_name/resolve_display_name(). The frontend half was out of that issue's stated scope.Gap
"Show
display_name, fall back tousername" is re-implemented in the frontend too, with two more fallback depths than the backend had:components/collaboration/InviteUserDialog.vueuser.display_name || user.usernameviews/llc/MembersView.vueu.display_name || u.usernameviews/llc/MembersView.vuemember.display_name || member.user_idcomposables/llc/useCompanyPeople.tsm.display_name || m.user_idcomponents/knowledge/ShareKnowledgeDialog.vueuserData.display_name || userData.email || userData.username || idviews/AdminUsersView.vueuser.display_name || '—'Root cause worth fixing first
The
|| m.user_idrungs exist because the two LLC endpoints disagree about who owns the last rung:list_memberscan returndisplay_name: nullfor a membership whose user row is gone, so the client has to invent a label._compose_human_nodesalready resolves that case server-side tostr(user_id).So the frontend compensates for one endpoint and duplicates the other. Aligning the two endpoints removes the reason for two of the six copies, and should happen before a shared frontend helper is written — otherwise the helper just encodes the inconsistency.
AdminUsersView's em-dash terminus is a separate divergence: it renders a blank-looking cell where every other surface renders a username.Ask
Related