6aae94f20b Add Display Name to User Properties in Webapp (#36363)
* Phase 1: CPA display_name + CEL-safe name validation (server)

- Add typed DisplayName field to CPAAttrs + display_name attr key constant.
- Add ValidateCPAFieldName helper enforcing CEL IDENTIFIER + reserved-word blacklist.
- Wire validation into App.CreateCPAField (always) and App.PatchCPAField (lenient grandfather: skip when Name unchanged).
- Trim + 255-rune cap DisplayName in CPAField.SanitizeAndValidate.
- Developer-facing godoc note documenting rule, sources of truth, and Option C scoping.
- Asserting test for documented Option C plugin-API bypass (closed by PR #36173).

Spec: planner/projects/property-display-name/ideas/001-cpa-display-name/spec.md
Plan: .planning/phase-1/PLAN.md
Made-with: Cursor

* Phase 1 (review): address Reza's Major + Minor findings

- Rename misleading subtest "empty DisplayName is omitted from attrs"
  to "empty DisplayName round-trips as empty string" (Major #1).
- Add TestCPAAttrs_JSONOmitEmpty pinning the omitempty wire-format
  contract that PR #36173's typed-attrs strategy relies on (Major #1).
- Extend TestValidateCPAFieldName: case-sensitivity (IN/In ok),
  single-character names (a/_/A ok), missing "as" reserved word
  (Minor #2). Add whitespace-only DisplayName case (Minor #2).
- Document PropertyFieldNameMaxRunes reuse in SanitizeAndValidate
  to prevent drift (Minor #3).
- Replace broken PLAN-server.md reference in bypass-test docstring
  with in-tree CPAAttrs godoc reference (Minor #4).
- Document omitempty semantics on CPAAttrs.DisplayName field to
  prevent the same misreading caught in review (Minor #5).
- Document grouping intent above CPAFieldNameReservedWords (Minor #8).

Review: .planning/phase-1/REVIEW.md
Made-with: Cursor

* Phase 2: in-app backfill migration for CPA display_name

- Add cpaDisplayNameBackfillKey + cpaDisplayNameBackfillVersion constants.
- Implement (*Server).doSetupCPADisplayNameBackfill: idempotent, cursor-paged
  scan over CPA group fields; backfill attrs.display_name = name when empty.
- Register in m1 migration slice in doAppMigrations (mlog.Fatal on error,
  matching existing convention).
- Three migration tests: NoExistingFields, BackfillsMissing, Idempotent.

System-key idempotency + per-field DisplayName-empty check together provide
HA-safe behavior on rolling deploys (last-write-wins on the System key;
data-level idempotency from the per-field check).

Spec: planner/projects/property-display-name/ideas/001-cpa-display-name/spec.md
Plan: .planning/phase-2/PLAN.md
Made-with: Cursor

* Phase 2 (review): document race + harden idempotency test

- Document SearchPropertyFields→UpdatePropertyFields rolling-deploy
  race: stale snapshot can revert concurrent admin CPA rename. Pre-
  existing systemic shape (no UpdateAt optimistic-lock); narrow
  window; bounded blast radius (admin re-rename, ABAC ID-keyed).
  Accepted limitation per spec Out of Scope (Major #1, Option C).
- Tighten TestCPADisplayNameBackfill_Idempotent: snapshot UpdateAt
  before second run; assert no DB write on the System key or the
  field row (Major #2).
- Extract clearCPABackfillMarker helper with explanatory godoc to
  centralize the 3x-repeated test precondition (Minor #1).
- Comment fieldA seed as the "key-present-as-empty-string" idempotency
  boundary case (Minor #6).
- Add godoc to doSetupCPADisplayNameBackfill (Minor #10).

Review: .planning/phase-2/REVIEW.md
Made-with: Cursor

* Linting

* Removing unnecessary comments

* Clean up tests

* Linting

* Fix tests

* Updated API doc

* Phase 3: webapp helper + render-site migration for CPA display_name

- Add display_name?: string to UserPropertyField.attrs type.
- New getUserPropertyFieldLabel(field) helper: returns
  attrs.display_name?.trim() || name. Defensive against missing attrs.
- Migrate ~10 user-facing CPA-name render sites to the helper:
  profile popover, user settings general (4 usages incl. line 1673
  missed by high-level plan), admin user detail, admin CPA list (2
  usages), and ABAC editor's selected-attribute UI (3 usages incl.
  the button label found in planning-stage research).
- CEL paths (table_editor, attribute_selector_menu user.attributes
  expression construction, ABAC search filters) keep using `name`
  per spec — display_name is label-only.
- Phase 4 boundary marker: TODOs in admin table + delete modal for
  follow-up admin-edit UX + client-side validator.

Spec: planner/projects/property-display-name/ideas/001-cpa-display-name/spec.md
Plan: .planning/phase-3/PLAN.md

* Phase 3 (review): add Unicode test + correct helper docblock scope

Address Reza's Phase 3 review:
- Major #1: add missing test case for non-ASCII display_name
  (Latin-extended + CJK), pinning the trim/passthrough contract.
- Nitpick #3: correct the helper's JSDoc to reflect that the
  delete modal is intentionally not migrated until Phase 4.

No production behavior change. No new dependencies.

Made-with: Cursor

* Phase 4: admin CPA edit UX + client-side identifier validation

Made-with: Cursor

* docs: append Phase 4 implementation summary

Made-with: Cursor

* Phase 4: admin CPA edit UX + client-side identifier validation

Complete the Phase 4 takeover from the existing dirty worktree and record the verified Stage 2 scope for admin CPA display-name editing, client-side identifier validation, and the required grandfather regression follow-ups.
Document the targeted Jest, typecheck, and lint-equivalent validation results in the Phase 4 plan without widening the implementation scope or rewriting the prior in-scope work.

Made-with: Cursor

* docs: finalize Phase 4 implementation summary

Made-with: Cursor

* docs: correct Phase 4 summary commit reference

Made-with: Cursor

* Phase 4 (review): fix empty-name warning precedence

Required-name validation now short-circuits before uniqueness checks so empty identifiers keep the correct warning. Add duplicate collision regression coverage for the dot-menu flow and add a stable validation-error testid for Phase 5 automation.

Made-with: Cursor

* Test updates

* Fix merge issue

* Fix tests

* PR Feedback

* Move migration to PropertyService

* Updates to UX

* Comment cleanup

* Add webapp tests for CPA display_name and fix CEL-affected specs

Update E2E seeds to use CEL-safe identifiers with display_name,
add ABAC selector spec, and extend Jest coverage for label-rendering
sites, auto-fill guard rails, and required-warning suppression.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Remove .planning/phase-4/PLAN.md

This planning artifact was committed inadvertently and should not be
part of the codebase.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Address CodeRabbit review comments

- Fix e2e test to use display_name in label assertions
- Make getIncrementedCELName case-insensitive to prevent collisions
- Update tooltip to mention reserved CEL words
- Replace hasSpaces check with full CEL identifier validation
- Use CPA_FIELD_NAME_MAX_RUNES for consistent maxLength
- Fix race condition by removing global cleanupAllFields
- Enable IntegratedBoards flag for legacy field seeding
- Replace fixed sleeps with state-based waits in tests

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Fix linting errors in getIncrementedCELName

- Use camelCase for destructured delete_at parameter
- Place dots on same line for method chaining

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Remove unused imports in user_attributes_display_name.spec.ts

- Remove unused deleteCustomProfileAttributes import
- Remove unused getFieldsMap function
- Remove unused FieldsMap type

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Fix webapp test failure - remove htmlFor assertion

The htmlFor attribute assertion was failing in the test environment,
likely due to a testing library issue. The important functionality
(displaying display_name in labels) is still properly tested.

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Fix post-merge CI failures: i18n drift and Playwright Prettier

- Re-extract webapp en.json so the identifier tooltip string matches
  user_properties_table.tsx (source of truth was already shortened in
  Phase 4; en.json was not regenerated).
- Apply Prettier formatting to three CPA display_name Playwright specs
  (whitespace and import/expression collapsing only). No test logic
  changes.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Address CodeRabbit feedback: use stable locators, add reserved words to tooltip, remove regex from hasText

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Fix i18n drift: align defaultMessage with en.json for identifier tooltip

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Comment cleanup

* Slugify CPA duplicate names to snake_case

slugifyForCEL now lowercases and inserts underscores at camel/PascalCase
boundaries (e.g. MyField -> my_field, XMLParser -> xml_parser) so
duplicated CPA fields get conventional snake_case names instead of
preserving the source casing.

Co-authored-by: Cursor <cursoragent@cursor.com>

* UX improvements: CEL identifier tooltip, validation, and attribute picker dual-name display

- Add info tooltip to the Attribute column header explaining CEL identifier rules
- Add client-side CEL identifier validation (pattern + reserved words) with a descriptive error message
- Show both display name and unique identifier in the policy attribute picker
- Filter attribute picker search by both display name and unique name
- Add display_name to UserPropertyField attrs TypeScript type
- Expand "CEL" to "Common Expression Language (CEL)" in the attribute-spaces tooltip

Co-authored-by: Cursor <cursoragent@cursor.com>

* Linting

* PR Feedback

* Restore name limit

* Fix tests

* Revert stray comment block above TestCPADisplayNameBackfill_BackfillsProtectedSourceOnlyField

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Revert extended fieldA comment in TestCPADisplayNameBackfill_BackfillsMissing

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Fix E2E tests

* Fix test

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-15 12:18:31 -04:00
2026-05-15 09:22:08 -04:00
2026-05-14 14:19:03 +00:00
2018-05-30 10:23:25 -04:00
2026-04-01 13:03:36 +00:00

Mattermost logo

Mattermost is an open core, self-hosted collaboration platform that offers chat, workflow automation, voice calling, screen sharing, and AI integration. This repo is the primary source for core development on the Mattermost platform; it's written in Go and React, runs as a single Linux binary, and relies on PostgreSQL. A new compiled version is released under an MIT license every month on the 16th.

Deploy Mattermost on-premises, or try it for free in the cloud.

mattermost user interface

Learn more about the following use cases with Mattermost:

Other useful resources:

Table of contents

Install Mattermost

Other install guides:

Native mobile and desktop apps

In addition to the web interface, you can also download Mattermost clients for Android, iOS, Windows PC, macOS, and Linux.

Get Mattermost on Google Play Get Mattermost on the App Store Get Mattermost on Windows PC Get Mattermost on Mac OSX Get Mattermost on Linux

Get security bulletins

Receive notifications of critical security updates. The sophistication of online attackers is perpetually increasing. If you're deploying Mattermost it's highly recommended you subscribe to the Mattermost Security Bulletin mailing list for updates on critical security releases.

Subscribe here

Get involved

Learn more

License

See the LICENSE file for license rights and limitations.

Get the latest news

Contributing

Small Image

Please see CONTRIBUTING.md. Join the Mattermost Contributors server to join community discussions about contributions, development, and more.

S
Description
Mattermost is an open source platform for secure collaboration across the entire software development lifecycle..
Readme
2.3 GiB
Languages
TypeScript 48.2%
Go 41.4%
JavaScript 5.4%
SCSS 2.6%
HTML 2.1%
Other 0.2%