Channel cards have no edit option #137

Closed
opened 2026-08-13 00:52:28 +02:00 by myrmidex · 1 comment
Owner

Channel cards on /channels offer an active/inactive toggle and account attach/detach, but no way to edit the channel itself. Language and description cannot be changed after creation — the only recourse is deleting the channel and recreating it, which makes managing channels painful.

app/Livewire/Channels.php currently exposes toggle(), the create-modal methods, and the account-management methods (openAccountModal(), attachAccount(), detachAccount()). No edit path for the channel's own attributes exists.

Expected

Each channel card has an edit action that opens a modal prefilled with the channel's current values, allowing them to be updated and saved.

Implementation reference

app/Livewire/Routes.php already implements this pattern — openEditModal() / closeEditModal() / updateRoute() with dedicated editing* properties. Follow the same shape here.

Open question — scope of what is editable

Resolved: the safer default was taken. The community/instance pairing is immutable.

  • Editable: display_name, language_id, description
  • Immutable: name, channel_id, platform_instance_id

That triplet is the channel's remote identity. platform_channels carries unique(['platform_instance_id', 'name']), name and channel_id come from the remote community via CommunityDirectory, and re-pointing a channel would change where every route already attached to it publishes. Leaving it immutable also avoids needing the instance-selection and community-refresh flow inside the edit modal.

The modal shows the community and instance read-only with a note explaining why.

This matches the precedent set by #136 "Feed cards have no edit option", where provider and language were left immutable because they derive the unique feeds.url. One deliberate asymmetry: language is editable here. On PlatformChannel it is a plain nullable FK that derives nothing; on Feed it feeds the URL derivation.

Acceptance criteria

  • Channel cards show an edit action
  • Modal opens prefilled with the channel's current values
  • Saving persists the changes and closes the modal
  • Scope of editable fields decided and documented in the implementation
  • Feature tests cover opening the modal, a successful update, and validation failures
Channel cards on `/channels` offer an active/inactive toggle and account attach/detach, but no way to edit the channel itself. Language and description cannot be changed after creation — the only recourse is deleting the channel and recreating it, which makes managing channels painful. `app/Livewire/Channels.php` currently exposes `toggle()`, the create-modal methods, and the account-management methods (`openAccountModal()`, `attachAccount()`, `detachAccount()`). No edit path for the channel's own attributes exists. ## Expected Each channel card has an edit action that opens a modal prefilled with the channel's current values, allowing them to be updated and saved. ## Implementation reference `app/Livewire/Routes.php` already implements this pattern — `openEditModal()` / `closeEditModal()` / `updateRoute()` with dedicated `editing*` properties. Follow the same shape here. ## Open question — scope of what is editable **Resolved: the safer default was taken.** The community/instance pairing is immutable. - **Editable:** `display_name`, `language_id`, `description` - **Immutable:** `name`, `channel_id`, `platform_instance_id` That triplet is the channel's remote identity. `platform_channels` carries `unique(['platform_instance_id', 'name'])`, `name` and `channel_id` come from the remote community via `CommunityDirectory`, and re-pointing a channel would change where every route already attached to it publishes. Leaving it immutable also avoids needing the instance-selection and community-refresh flow inside the edit modal. The modal shows the community and instance read-only with a note explaining why. This matches the precedent set by #136 "Feed cards have no edit option", where provider and language were left immutable because they derive the unique `feeds.url`. **One deliberate asymmetry:** language *is* editable here. On `PlatformChannel` it is a plain nullable FK that derives nothing; on `Feed` it feeds the URL derivation. ## Acceptance criteria - [x] Channel cards show an edit action - [x] Modal opens prefilled with the channel's current values - [x] Saving persists the changes and closes the modal - [x] Scope of editable fields decided and documented in the implementation - [x] Feature tests cover opening the modal, a successful update, and validation failures
myrmidex added this to the v1.4.0 milestone 2026-08-13 00:52:28 +02:00
myrmidex added the
bug
label 2026-08-13 00:52:28 +02:00
myrmidex self-assigned this 2026-08-13 00:52:28 +02:00
Author
Owner

Delivered in 0163fa5.

What shipped

  • Edit button on each channel card, opening an x-form-modal prefilled with display name, language and description
  • Channels::openEditModal() / closeEditModal() / updateChannel() with editingChannelId / editDisplayName / editLanguageId / editDescription, following the Routes.php shape
  • Community and instance rendered read-only in the modal with a note explaining that every attached route publishes there
  • Blank description saves as null; the language select offers "No language" and clearing it is supported

Scope

Resolved in the ticket body above. The immutability is enforced in code rather than only in the UI: updateChannel() builds an explicit three-key array instead of reusing CreateChannelAction, so a replayed Livewire request cannot reach name, channel_id or platform_instance_id. ChannelsTest::test_update_channel_leaves_the_community_pairing_untouched snapshots that triplet before and after an edit.

Pre-existing bugs found and fixed

PlatformChannel's docblock was wrong in three ways, all verified against 2024_01_01_000003_create_platforms.php:

  • display_name (NOT NULL) — missing from the docblock entirely
  • description (nullable) — missing entirely
  • language_id — declared int, but the column is ->nullable()

A phpstan-baseline.neon entry was suppressing an assertNull() in CreateChannelActionTest that only failed because of the wrong language_id type. Correcting the docblock made the entry stale, so it was removed.

This is the second occurrence of that pattern#136 fixed the identical defect on Feed::$description. Two of two models touched carried it, so it is likely systemic. Every remaining entry in phpstan-baseline.neon that names a model property is worth treating as a bug report about that property.

Also noted, not fixed: platform_channels.display_name is NOT NULL, so the display_name ?? name fallbacks in channels.blade.php (card header and account-modal title) are dead code. Pre-existing and out of scope here.

Verification

12 new feature tests: edit action present, prefill (including a null description prefilling blank), successful update across all three fields, blank-to-null coercion, required and max-length validation on display name, unknown-language rejection, clearing the language, discard on close, no-op without an open modal, and community-pairing immutability.

1165 tests / 2865 assertions green, Pint clean (338 files), PHPStan clean. code-reviewer returned no critical issues and no recommendations. Confirmed working in a browser.

Delivered in `0163fa5`. **What shipped** - Edit button on each channel card, opening an `x-form-modal` prefilled with display name, language and description - `Channels::openEditModal()` / `closeEditModal()` / `updateChannel()` with `editingChannelId` / `editDisplayName` / `editLanguageId` / `editDescription`, following the `Routes.php` shape - Community and instance rendered read-only in the modal with a note explaining that every attached route publishes there - Blank description saves as `null`; the language select offers "No language" and clearing it is supported **Scope** Resolved in the ticket body above. The immutability is enforced in code rather than only in the UI: `updateChannel()` builds an explicit three-key array instead of reusing `CreateChannelAction`, so a replayed Livewire request cannot reach `name`, `channel_id` or `platform_instance_id`. `ChannelsTest::test_update_channel_leaves_the_community_pairing_untouched` snapshots that triplet before and after an edit. **Pre-existing bugs found and fixed** `PlatformChannel`'s docblock was wrong in three ways, all verified against `2024_01_01_000003_create_platforms.php`: - `display_name` (NOT NULL) — missing from the docblock entirely - `description` (nullable) — missing entirely - `language_id` — declared `int`, but the column is `->nullable()` A `phpstan-baseline.neon` entry was suppressing an `assertNull()` in `CreateChannelActionTest` that only failed *because of* the wrong `language_id` type. Correcting the docblock made the entry stale, so it was removed. **This is the second occurrence of that pattern** — #136 fixed the identical defect on `Feed::$description`. Two of two models touched carried it, so it is likely systemic. Every remaining entry in `phpstan-baseline.neon` that names a model property is worth treating as a bug report about that property. **Also noted, not fixed:** `platform_channels.display_name` is NOT NULL, so the `display_name ?? name` fallbacks in `channels.blade.php` (card header and account-modal title) are dead code. Pre-existing and out of scope here. **Verification** 12 new feature tests: edit action present, prefill (including a null description prefilling blank), successful update across all three fields, blank-to-null coercion, required and max-length validation on display name, unknown-language rejection, clearing the language, discard on close, no-op without an open modal, and community-pairing immutability. 1165 tests / 2865 assertions green, Pint clean (338 files), PHPStan clean. `code-reviewer` returned no critical issues and no recommendations. Confirmed working in a browser.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lvl0/fedi-feed-router#137
No description provided.