ZIm/crates/collab/migrations
Nathan Sobo 0a2186c87b
Add channel reordering functionality (#31833)
Release Notes:

- Added channel reordering for administrators (use `cmd-up` and
`cmd-down` on macOS or `ctrl-up` `ctrl-down` on Linux to move channels
up or down within their parent)

## Summary

This PR introduces the ability for channel administrators to reorder
channels within their parent context, providing better organizational
control over channel hierarchies. Users can now move channels up or down
relative to their siblings using keyboard shortcuts.

## Problem

Previously, channels were displayed in alphabetical order with no way to
customize their arrangement. This made it difficult for teams to
organize channels in a logical order that reflected their workflow or
importance, forcing users to prefix channel names with numbers or
special characters as a workaround.

## Solution

The implementation adds a persistent `channel_order` field to channels
that determines their display order within their parent. Channels with
the same parent are sorted by this field rather than alphabetically.

## Implementation Details

### Database Schema

Added a new column and index to support efficient ordering:

```sql
-- crates/collab/migrations/20250530175450_add_channel_order.sql
ALTER TABLE channels ADD COLUMN channel_order INTEGER NOT NULL DEFAULT 1;

CREATE INDEX CONCURRENTLY "index_channels_on_parent_path_and_order" ON "channels" ("parent_path", "channel_order");
```

### RPC Protocol

Extended the channel proto with ordering support:

```proto
// crates/proto/proto/channel.proto
message Channel {
    uint64 id = 1;
    string name = 2;
    ChannelVisibility visibility = 3;
    int32 channel_order = 4;
    repeated uint64 parent_path = 5;
}

message ReorderChannel {
    uint64 channel_id = 1;
    enum Direction {
        Up = 0;
        Down = 1;
    }
    Direction direction = 2;
}
```

### Server-side Logic

The reordering is handled by swapping `channel_order` values between
adjacent channels:

```rust
// crates/collab/src/db/queries/channels.rs
pub async fn reorder_channel(
    &self,
    channel_id: ChannelId,
    direction: proto::reorder_channel::Direction,
    user_id: UserId,
) -> Result<Vec<Channel>> {
    // Find the sibling channel to swap with
    let sibling_channel = match direction {
        proto::reorder_channel::Direction::Up => {
            // Find channel with highest order less than current
            channel::Entity::find()
                .filter(
                    channel::Column::ParentPath
                        .eq(&channel.parent_path)
                        .and(channel::Column::ChannelOrder.lt(channel.channel_order)),
                )
                .order_by_desc(channel::Column::ChannelOrder)
                .one(&*tx)
                .await?
        }
        // Similar logic for Down...
    };
    
    // Swap the channel_order values
    let temp_order = channel.channel_order;
    channel.channel_order = sibling_channel.channel_order;
    sibling_channel.channel_order = temp_order;
}
```

### Client-side Sorting

Optimized the sorting algorithm to avoid O(n²) complexity:

```rust
// crates/collab/src/db/queries/channels.rs
// Pre-compute sort keys for efficient O(n log n) sorting
let mut channels_with_keys: Vec<(Vec<i32>, Channel)> = channels
    .into_iter()
    .map(|channel| {
        let mut sort_key = Vec::with_capacity(channel.parent_path.len() + 1);
        
        // Build sort key from parent path orders
        for parent_id in &channel.parent_path {
            sort_key.push(channel_order_map.get(parent_id).copied().unwrap_or(i32::MAX));
        }
        sort_key.push(channel.channel_order);
        
        (sort_key, channel)
    })
    .collect();

channels_with_keys.sort_by(|a, b| a.0.cmp(&b.0));
```

### User Interface

Added keyboard shortcuts and proper context handling:

```json
// assets/keymaps/default-macos.json
{
  "context": "CollabPanel && not_editing",
  "bindings": {
    "cmd-up": "collab_panel::MoveChannelUp",
    "cmd-down": "collab_panel::MoveChannelDown"
  }
}
```

The CollabPanel now properly sets context to distinguish between editing
and navigation modes:

```rust
// crates/collab_ui/src/collab_panel.rs
fn dispatch_context(&self, window: &Window, cx: &Context<Self>) -> KeyContext {
    let mut dispatch_context = KeyContext::new_with_defaults();
    dispatch_context.add("CollabPanel");
    dispatch_context.add("menu");
    
    let identifier = if self.channel_name_editor.focus_handle(cx).is_focused(window) {
        "editing"
    } else {
        "not_editing"
    };
    
    dispatch_context.add(identifier);
    dispatch_context
}
```

## Testing

Comprehensive tests were added to verify:
- Basic reordering functionality (up/down movement)
- Boundary conditions (first/last channels)
- Permission checks (non-admins cannot reorder)
- Ordering persistence across server restarts
- Correct broadcasting of changes to channel members

## Migration Strategy

Existing channels are assigned initial `channel_order` values based on
their current alphabetical sorting to maintain the familiar order users
expect:

```sql
UPDATE channels
SET channel_order = (
    SELECT ROW_NUMBER() OVER (
        PARTITION BY parent_path
        ORDER BY name, id
    )
    FROM channels c2
    WHERE c2.id = channels.id
);
```

## Future Enhancements

While this PR provides basic reordering functionality, potential future
improvements could include:
- Drag-and-drop reordering in the UI
- Bulk reordering operations
- Custom sorting strategies (by activity, creation date, etc.)

## Checklist

- [x] Database migration included
- [x] Tests added for new functionality
- [x] Keybindings work on macOS and Linux
- [x] Permissions properly enforced
- [x] Error handling implemented throughout
- [x] Manual testing completed
- [x] Documentation updated

---------

Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com>
2025-06-04 16:56:33 +00:00
..
20210527024318_initial_schema.sql Add bootstrap script, avoid hard-coding zed team members 2022-08-15 13:25:31 -07:00
20210607190313_create_access_tokens.sql Rename zed-server to collab 2022-04-09 08:30:42 -06:00
20210805175147_create_chat_tables.sql Rename zed-server to collab 2022-04-09 08:30:42 -06:00
20210916123647_add_nonce_to_channel_messages.sql Rename zed-server to collab 2022-04-09 08:30:42 -06:00
20210920192001_add_interests_to_signups.sql Rename zed-server to collab 2022-04-09 08:30:42 -06:00
20220421165757_drop_signups.sql Drop signups table 2022-04-21 10:59:13 -06:00
20220505144506_add_trigram_index_to_users.sql Add fuzzy_search_users to Db trait, PostgresDb 2022-05-05 09:58:18 -06:00
20220506130724_create_contacts.sql Start work on RPC endpoints for dealing with contact requests 2022-05-06 15:44:47 -07:00
20220518151305_add_invites_to_users.sql Accept an optional email address when creating new users 2022-05-20 20:25:21 -06:00
20220523232954_allow_user_deletes.sql Update foreign key constraints to allow users to be deleted 2022-05-23 17:46:06 -06:00
20220620211403_create_projects.sql Register projects in the database and record worktree extensions 2022-06-21 10:29:26 +02:00
20220913211150_create_signups.sql Identify users in amplitude via a separate 'metrics_id' UUID 2022-09-29 13:15:21 -07:00
20220929182110_add_metrics_id.sql Identify users in amplitude via a separate 'metrics_id' UUID 2022-09-29 13:15:21 -07:00
20221111092550_reconnection_support.sql Don't drop unregistered column in reconnection support migration 2022-12-09 08:11:18 +01:00
20221125192125_add_added_to_mailing_list_to_signups.sql Add "added_to_mailing_list" column on signups table 2022-11-29 02:13:13 -05:00
20221207165001_add_connection_lost_to_room_participants.sql Move creation of room_id index into its own migration 2022-12-13 13:57:41 +01:00
20221213125710_index_room_participants_on_room_id.sql Move creation of room_id index into its own migration 2022-12-13 13:57:41 +01:00
20221214144346_change_epoch_from_uuid_to_integer.sql Allow nulls in projects.host_connection_{id,server_id} 2022-12-15 11:30:51 +01:00
20221219181850_project_reconnection_support.sql WIP 2022-12-19 20:05:00 +01:00
20230103200902_replace_is_completed_with_completed_scan_id.sql Avoid dropping is_complete column for backward compatibility 2023-01-11 13:25:02 -08:00
20230202155735_followers.sql Begin tracking follow states on collab server 2023-02-22 11:21:23 -05:00
20230508211523_add-repository-entries.sql Add postgres migration 2023-05-08 14:33:59 -07:00
20230511004019_add_repository_statuses.sql Add postgres migration 2023-05-10 17:50:35 -07:00
20230529164700_add_worktree_settings_files.sql Replicate project-specific settings when collaborating 2023-05-30 18:08:03 -07:00
20230605191135_remove_repository_statuses.sql Avoid dropping the worktree_repository_statuses table for now 2023-06-09 11:37:39 -07:00
20230616134535_add_is_external_to_worktree_entries.sql Add a bit to each entry indicating if it's outside of the worktree root 2023-06-22 10:34:28 -07:00
20230727150500_add_channels.sql Represent channel relationships using paths table 2023-08-09 10:36:27 -07:00
20230819154600_add_channel_buffers.sql Simplify buffer_operations schema 2023-08-23 18:37:01 -07:00
20230825190322_add_server_feature_flags.sql Update database and RPC to provide configured feature flags 2023-08-25 14:34:32 -07:00
20230907114200_add_channel_messages.sql Start work on restoring server-side code for chat messages 2023-09-07 16:32:49 -07:00
20230925210437_add_channel_changes.sql Avoid N+1 query for channels with notes changes 2023-10-02 15:58:34 -07:00
20230926102500_add_participant_index_to_room_participants.sql Rename color_index to participant_index 2023-09-28 11:37:22 -07:00
20231004130100_create_notifications.sql Index notifications to allow faster lookup by kind, entity id 2023-10-19 13:03:27 -07:00
20231009181554_add_release_channel_to_rooms.sql Rename release channel to enviroment 2023-10-10 13:23:03 -07:00
20231010114600_add_unique_index_on_rooms_channel_id.sql Update channel rooms to be ephemeral 2023-10-10 12:39:16 -07:00
20231011214412_add_guest_role.sql fix migration 2023-10-13 15:08:09 -06:00
20231017185833_projects_room_id_fkey_on_delete_cascade.sql update sidebar for public channels 2023-10-17 13:30:09 -06:00
20231018102700_create_mentions.sql Fix possibility of extra mention insertion on nonce collision 2023-10-18 18:04:56 -07:00
20231024085546_move_channel_paths_to_channels_table.sql Remove logic for multiple channel parents 2023-10-24 17:29:23 +02:00
20240103025509_add_role_to_room_participants.sql Plumbing to pass role for room participants 2024-01-03 19:30:32 -07:00
20240111085546_fix_column_name.sql Switch to non-destructive migration 2024-01-11 10:33:33 -08:00
20240117150300_add_impersonator_to_access_tokens.sql For impersonating access tokens, store impersonatee in the new column 2024-01-17 18:06:16 -08:00
20240122174606_add_contributors.sql Add REST APIs for getting and adding contributors 2024-01-22 10:48:33 -08:00
20240122224506_add_requires_zed_cla_column_to_channels.sql Add requires_zed_cla column to channels table 2024-01-22 16:41:24 -08:00
20240129193601_fix_parent_path_index.sql Fix slow query for fetching descendants of channels (#7008) 2024-01-29 13:24:59 -08:00
20240203113741_add_reply_to_message.sql Add the ability to reply to a message (#7170) 2024-02-06 13:22:54 -07:00
20240207041417_add_in_call_column_to_room_participants.sql single click channel (#7596) 2024-02-09 14:18:27 -07:00
20240213200201_remove_unused_room_columns.sql drop columns (#7742) 2024-02-14 14:30:48 -07:00
20240214102900_add_extensions.sql Add an extensions API to the collaboration server (#7807) 2024-02-15 12:53:57 -08:00
20240220234826_add_rate_buckets.sql Allow AI interactions to be proxied through Zed's server so you don't need an API key (#7367) 2024-03-19 19:22:26 +01:00
20240221151017_add_edited_at_field_to_channel_message.sql Channel chat: Add edit message (#9035) 2024-03-19 19:49:04 -06:00
20240226163408_hosted_projects.sql channel projects (#8456) 2024-02-26 22:15:11 -07:00
20240226164505_unique_channel_names.sql fix migration (#8451) 2024-02-26 13:50:26 -07:00
20240227215556_hosted_projects_in_projects.sql hosted projects (#8627) 2024-03-04 19:17:40 -07:00
20240307163119_denormalize_buffer_ops.sql Denormalize buffer operations (#9026) 2024-03-07 11:35:47 -07:00
20240315182903_non_null_channel_role.sql Finish migration to role instead of is_admin (#9414) 2024-03-15 13:04:48 -06:00
20240315183903_channel_parent_path_not_null.sql Finish migration to role instead of is_admin (#9414) 2024-03-15 13:04:48 -06:00
20240320124800_add_extension_schema_version.sql Add a schema to extensions, to prevent installing extensions on too old of a Zed version (#9599) 2024-03-20 17:33:26 -04:00
20240321162658_add_devservers.sql remoting (#9680) 2024-03-22 08:44:56 -06:00
20240335123500_add_extension_wasm_api_version.sql Add telemetry events for loading extensions (#9793) 2024-03-25 17:30:48 -04:00
20240402155003_add_dev_server_projects.sql WIP: remoting (#10085) 2024-04-11 15:36:35 -06:00
20240409082755_create_embeddings.sql Semantic Index (#10329) 2024-04-12 11:40:59 -06:00
20240412165156_dev_servers_per_user.sql remote projects per user (#10594) 2024-04-23 15:33:09 -06:00
20240417192746_unique_remote_projects_by_paths.sql remote projects per user (#10594) 2024-04-23 15:33:09 -06:00
20240502150229_rename_to_dev_server_projects.sql Rename RemoteProject -> DevServerProject (#11301) 2024-05-02 11:00:08 -06:00
20240502180204_remove_old_remote_projects.sql Slicker remote project creation (#11309) 2024-05-02 12:46:52 -06:00
20240514164510_store_ssh_connect_string.sql Support terminals with ssh in remote projects (#11913) 2024-05-17 17:48:07 +03:00
20240715230940_add_worktrees_to_dev_server_projects.sql remoting: Allow Add/Remove remote folder (#14532) 2024-07-16 12:01:59 -06:00
20240729170526_add_billing_subscription.sql collab: Add billing_subscriptions table (#15448) 2024-07-29 14:32:13 -04:00
20240730014107_add_billing_customer.sql collab: Add separate billing_customers table (#15457) 2024-07-29 22:48:21 -04:00
20240730122654_add_last_stripe_event_id.sql collab: Keep track of last seen Stripe event for each record (#15480) 2024-07-30 10:00:16 -04:00
20240730182554_add_processed_stripe_events.sql collab: Rework Stripe event processing (#15510) 2024-07-30 16:35:11 -04:00
20240731120800_add_stripe_cancel_at_to_billing_subscriptions.sql Allow users to stop a previously scheduled cancelation of their Zed Pro plan (#15562) 2024-07-31 16:36:46 -04:00
20240812073542_add_accepted_tos_at.sql assistant: Require user to accept TOS for cloud provider (#16111) 2024-08-12 17:43:35 +02:00
20240812204045_add_github_user_created_at_to_users.sql collab: Restrict usage of the LLM service to accounts older than 30 days (#16133) 2024-08-12 17:27:21 -04:00
20240816181658_add_enabled_for_all_to_feature_flags.sql collab: Allow enabling feature flags for all users (#16372) 2024-08-16 15:17:03 -04:00
20240822215737_add_unique_constraint_on_github_user_id_on_users.sql collab: Make users.github_user_id required and unique (#16704) 2024-08-22 18:27:22 -04:00
20240823155956_add_is_fifo_to_worktree_entries.sql Fix fifo files hanging the project wide search (#16039) 2024-08-26 10:40:20 -06:00
20241002120231_add_local_settings_kind.sql Prepare to sync other kinds of settings (#18616) 2024-10-02 22:00:40 +03:00
20241009190639_add_billing_preferences.sql collab: Add billing preferences for maximum LLM monthly spend (#18948) 2024-10-09 16:29:07 -04:00
20241019184824_adjust_symlink_data.sql Show project panel symlink icons for remote clients (#19464) 2024-10-19 19:44:47 +03:00
20241021202606_add_custom_llm_monthly_allowance_in_cents_to_users.sql collab: Add support for a custom monthly allowance for LLM usage (#19525) 2024-10-21 17:12:33 -04:00
20241023201725_remove_dev_servers.sql Migration to remove dev servers (#19639) 2024-10-30 11:55:55 -06:00
20241121185750_add_breakpoints.sql Debugger implementation (#13433) 2025-03-18 12:55:25 -04:00
20250108184547_add_stripe_cancellation_reason_to_billing_subscriptions.sql collab: Record cancellation reason on billing subscriptions (#22853) 2025-01-08 19:38:10 +00:00
20250113230049_expand_git_status_information.sql Represent git statuses more faithfully (#23082) 2025-01-16 00:01:38 +00:00
20250117100620_add_user_name.sql Allow filling co-authors in the git panel's commit input (#23329) 2025-01-18 22:57:17 +02:00
20250204224004_add_has_overdue_invoices_to_billing_customers.sql collab: Add has_overdue_invoices to billing_customers (#24239) 2025-02-04 18:12:35 -05:00
20250205192813_add_provides_fields_to_extension_versions.sql collab: Store features provided by extensions in the database (#24303) 2025-02-05 19:50:24 +00:00
20250205232017_add_conflicts_to_repositories.sql Split conflicts into their own section (#24324) 2025-02-05 18:34:14 -07:00
20250210223746_add_branch_summary.sql Add an undo button to the git panel (#24593) 2025-02-12 15:57:08 -07:00
20250212060936_add_worktree_branch_summary.sql Add an undo button to the git panel (#24593) 2025-02-12 15:57:08 -07:00
20250319182812_create_project_repositories.sql Separate repository state synchronization from worktree synchronization (#27140) 2025-03-20 18:07:03 -04:00
20250415164141_add_kind_and_period_to_billing_subscriptions.sql collab: Add kind and period start/end timestamps to billing_subscriptions (#28796) 2025-04-15 13:48:03 -04:00
20250422194500_add_trial_started_at_to_billing_customers.sql collab: Limit customers to one free trial (#29232) 2025-04-22 20:41:17 +00:00
20250423150129_add_head_commit_details_to_project_repositories.sql collab: Add head_commit_details column to project_repositories (#29284) 2025-04-23 15:35:49 +00:00
20250425201930_add_model_request_overages_to_billing_preferences.sql collab: Add LLM request overage columns to billing_preferences (#29446) 2025-04-25 20:43:43 +00:00
20250530175450_add_channel_order.sql Add channel reordering functionality (#31833) 2025-06-04 16:56:33 +00:00