Skip to content

feat(adminless-groups): admin promotion UI when last admin leaves group - WPB-25289#4829

Open
David-Henner wants to merge 30 commits into
developfrom
feat/adminless-groups/admin-promotion-UI
Open

feat(adminless-groups): admin promotion UI when last admin leaves group - WPB-25289#4829
David-Henner wants to merge 30 commits into
developfrom
feat/adminless-groups/admin-promotion-UI

Conversation

@David-Henner

@David-Henner David-Henner commented Jun 9, 2026

Copy link
Copy Markdown
Contributor
TaskWPB-25289 [iOS] Implement admin selection flow

When the last admin of a group tries to leave and the preventAdminlessGroups feature is enabled, the user is presented with a choice: promote another participant as admin before leaving, or delete the group. If no eligible candidates exist, only the delete option is offered.

ScreenRecording_06-09-2026.18-10-40_1.MP4

Changes

Added:

  • AdminSelectionView — SwiftUI sheet for searching and selecting a new admin, with full VoiceOver accessibility support
  • AdminSelectionViewModel@MainActor ObservableObject owning search filtering, selection, and PromotionState (.idle / .inProgress / .succeeded / .failed)
  • LastAdminLeaveAlertUIAlertController factory for the "promote or delete" and "delete only" alert variants
  • UserImageViewRepresentableUIViewRepresentable bridge for UserImageView in SwiftUI
  • AdminPromotionTests — UI test: last admin promotes a new admin and leaves the group
  • AdminSelectionPage — page object for AdminSelectionView
  • AdminSelectionViewModelTests — Swift Testing unit tests for filteredCandidates, canPromote, and promote

Modified:

  • ConversationActionController+LeaverequestLeave checks preventAdminlessGroups flag and last-admin status before showing the new alert; performAdminPromotion calls updateRole then leaves the group
  • ParticipantsSectionControllerconfigure(user:isE2EICertified:conversation:showSeparator:) now takes conversationRole and sets adminCell/memberCell accessibility identifier internally
  • UIAlertAction+Convenience — extended the accessibilityIdentifier convenience init to also accept accessibilityHint
  • ConversationDetailsPage — added tapPromoteNewAdmin(), adminCell(named:), memberCell(named:)
  • WireUITestCase — added additionalDeveloperFlags() override hook for injecting flags before app launch
  • Locators — added LastAdminLeaveAlert, AdminSelectionPage, ConversationDetailsPage.adminCell/.memberCell locators
  • DeveloperFlag — added preventAdminlessGroups developer flag

Architecture note

Aligning with architecture guidelines (e.g. UseCases, repositories) was out of scope and not worth committing to — the legacy code already had the interfaces in place to integrate the feature directly.

Testing

  1. Enable the preventAdminlessGroups developer flag (Settings → Developer)
  2. Create a group with yourself as the only admin and at least one other member
  3. Open conversation details → More options → Leave
  4. Verify the "Promote new admin" / "Delete group" alert appears
  5. Select a participant in the admin selection sheet and tap Promote — verify the participant is now listed as admin and you have left the group
  6. Repeat with no eligible candidates (all federated/external/temporary) — verify only "Delete group" is offered
  7. Run AdminPromotionTests UI test suite

Checklist

  • Title contains a reference JIRA issue number like [WPB-XXX].
  • Description is filled and free of optional paragraphs.
  • Adds/updates automated tests.

UI accessibility checklist

If your PR includes UI changes, please utilize this checklist:

  • Make sure you use the API for UI elements that support large fonts.
  • All colors are taken from WireDesign.ColorTheme or constructed using WireDesign.BaseColorPalette.
  • New UI elements have Accessibility strings for VoiceOver.

@David-Henner David-Henner changed the title feat: admin promotion UI when last admin leaves group - WPB-XXXXX feat: admin promotion UI when last admin leaves group - WPB-25289 Jun 9, 2026
@David-Henner David-Henner requested a review from Copilot June 9, 2026 10:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Implements the “last admin leaving a group” flow behind the preventAdminlessGroups feature: when the final admin tries to leave, they must either promote another eligible participant as admin (via a new SwiftUI selection sheet) or delete the group (with a delete-only variant when no candidates exist).

Changes:

  • Adds LastAdminLeaveAlert plus an AdminSelectionView/AdminSelectionViewModel promotion sheet, and wires the flow into ConversationActionController’s leave action.
  • Extends accessibility identifiers/locators for UI testing and improves participant cell identification (admin vs member).
  • Adds UI test coverage for the promotion-and-leave path and unit tests for the view model filtering/promotion state.

Reviewed changes

Copilot reviewed 17 out of 18 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
WireUI/Sources/WireLocators/Locators.swift Adds locators for admin/member participant cells, last-admin leave alert actions, and the admin selection page.
wire-ios/WireUITests/Pages/ConversationDetailsPage.swift Adds helpers to tap “Promote new admin” and to query admin/member cells by name.
wire-ios/WireUITests/Pages/AdminSelectionPage.swift Introduces a page object for the admin selection sheet (user selection + promote).
wire-ios/WireUITests/Helper/WireUITestCase.swift Adds an override hook to inject additional developer flags before app launch.
wire-ios/WireUITests/AdminPromotionTests.swift Adds UI test that promotes a new admin and verifies the owner leaves the group.
wire-ios/Wire-iOS/Sources/UserInterface/Helpers/UIAlertAction+Convenience.swift Extends the convenience initializer to accept an accessibility hint.
wire-ios/Wire-iOS/Sources/UserInterface/GroupDetails/Sections/ParticipantsSectionController.swift Sets participant cell accessibility identifiers based on section role (admin vs member).
wire-ios/Wire-iOS/Sources/UserInterface/GroupDetails/ConversationActions/LastAdminLeaveAlert.swift Adds alert factory for promote-or-delete and delete-only variants with locators.
wire-ios/Wire-iOS/Sources/UserInterface/GroupDetails/ConversationActions/ConversationActionController+Leave.swift Adds last-admin detection, candidate filtering, admin selection presentation, promotion + leave behavior.
wire-ios/Wire-iOS/Sources/UserInterface/GroupDetails/ConversationActions/ConversationActionController.swift Routes .leave action through the new requestLeave(for:) flow.
wire-ios/Wire-iOS/Sources/UserInterface/GroupDetails/AdminSelection/AdminSelectionViewModel.swift Adds view model for searching, selecting, and promoting candidates (with promotion state).
wire-ios/Wire-iOS/Sources/UserInterface/GroupDetails/AdminSelection/AdminSelectionView.swift Adds SwiftUI sheet UI with search, candidate rows, and promote action.
wire-ios/Wire-iOS/Sources/UserInterface/Components/Views/UserImageViewRepresentable.swift Bridges UserImageView into SwiftUI for candidate rows.
wire-ios/Wire-iOS/Resources/Localization/Base.lproj/Localizable.strings Adds new localized strings for the admin selection and last-admin leave alerts.
wire-ios/Wire-iOS/Resources/Localization/Base.lproj/Accessibility.strings Adds VoiceOver strings for admin selection UI.
wire-ios/Wire-iOS/Generated/Strings+Generated.swift Updates generated string accessors for the newly added localization keys.
wire-ios/Wire-iOS UnitTests/UserInterface/GroupDetails/AdminSelectionViewModelTests.swift Adds Swift Testing unit tests for filtering, canPromote, and promotion state changes.
wire-ios-utilities/Source/DeveloperFlag.swift Adds preventAdminlessGroups developer flag.

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

Comment on lines +28 to +36
@discardableResult
func selectUser(named name: String) -> Self {
let predicate = NSPredicate(format: "label == %@", name)
app.staticTexts
.matching(identifier: Locators.AdminSelectionPage.userCell.rawValue)
.matching(predicate)
.firstMatch
.tap()
return self
Comment on lines +54 to +58
// Self user is no longer a participant
XCTAssertFalse(
conversationDetailsPage.userCell(named: owner.name).exists,
"Owner should not appear in participant list after leaving"
)
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Test Results

164 tests   163 ✅  1m 2s ⏱️
 41 suites    1 💤
  1 files      0 ❌

Results for commit ec0239b.

♻️ This comment has been updated with latest results.

Summary: workflow run #27965030996
Allure report (download zip): html-report-30998-feat_adminless-groups_admin-promotion-UI

@David-Henner David-Henner changed the title feat: admin promotion UI when last admin leaves group - WPB-25289 feat(adminless-groups): admin promotion UI when last admin leaves group - WPB-25289 Jun 10, 2026
@David-Henner David-Henner requested review from netbe and samwyndham June 10, 2026 06:29
Comment thread wire-ios/WireUITests/AdminPromotionTests.swift Outdated

@netbe netbe left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

looks good, left some comments about design

Comment thread wire-ios/WireUITests/AdminPromotionTests.swift Outdated
Comment thread wire-ios/WireUITests/AdminPromotionTests.swift Outdated

@samwyndham samwyndham left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice work

Comment thread wire-ios/WireUITests/AdminPromotionTests.swift
David-Henner and others added 5 commits June 15, 2026 14:03
…ction/AdminSelectionViewModel.swift

Co-authored-by: Sam Wyndham <samwyndham@users.noreply.github.com>
@David-Henner David-Henner force-pushed the feat/adminless-groups/admin-promotion-UI branch from 79ff8ae to 1ff5255 Compare June 16, 2026 08:52
@sonarqubecloud

Copy link
Copy Markdown

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.

4 participants