ZIm/crates
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
..
activity_indicator debugger: Add spinners while session is starting up (#31548) 2025-05-29 01:58:40 +00:00
agent inline assistant: Allow to attach images from clipboard (#32087) 2025-06-04 16:43:52 +00:00
agent_settings Add support for OpenRouter as a language model provider (#29496) 2025-06-03 15:59:46 +00:00
anthropic anthropic: Fix Claude 4 model display names to match official order (#31218) 2025-05-22 21:00:54 +00:00
askpass askpass: Workaround rust lang 69343 (#30774) 2025-05-16 05:04:36 -04:00
assets Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
assistant_context_editor Make completions menu stay open after after it's manually requested (#32015) 2025-06-03 20:33:52 +00:00
assistant_slash_command chore: Make terminal_view own the TerminalSlashCommand (#31070) 2025-05-21 09:27:54 +00:00
assistant_slash_commands zlog: Replace usages of env_logger in tests with zlog (#31436) 2025-05-26 11:48:50 -04:00
assistant_tool assistant_tools: Disallow extra tool parameters by default (#32081) 2025-06-04 16:11:40 +00:00
assistant_tools assistant_tools: Disallow extra tool parameters by default (#32081) 2025-06-04 16:11:40 +00:00
audio agent: Add sound notification when done generating (#31472) 2025-05-26 21:20:41 -03:00
auto_update Show version info when downloading and installing updates (#31568) 2025-05-28 11:51:21 -04:00
auto_update_helper Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
auto_update_ui markdown_preview: Fix release notes title being overridden (#31703) 2025-05-30 08:29:52 +00:00
aws_http_client Add workspace-hack (#27277) 2025-04-02 13:26:34 -07:00
bedrock bedrock: Fix ci failure due model enum and model name mismatch (#32049) 2025-06-04 10:41:12 +03:00
breadcrumbs breadcrumbs: Stylize filename in breadcrumbs when tab-bar is off and file is dirty (#30507) 2025-05-30 08:32:54 -07:00
buffer_diff zlog: Replace usages of env_logger in tests with zlog (#31436) 2025-05-26 11:48:50 -04:00
call Use read-only access methods for read-only entity operations (#31479) 2025-05-26 23:04:31 -04:00
channel Add channel reordering functionality (#31833) 2025-06-04 16:56:33 +00:00
cli Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
client Use read-only access methods for read-only entity operations (#31479) 2025-05-26 23:04:31 -04:00
clock Add the ability to follow the agent as it makes edits (#29839) 2025-05-04 08:28:39 +00:00
collab Add channel reordering functionality (#31833) 2025-06-04 16:56:33 +00:00
collab_ui Add channel reordering functionality (#31833) 2025-06-04 16:56:33 +00:00
collections Add workspace-hack (#27277) 2025-04-02 13:26:34 -07:00
command_palette Use read-only access methods for read-only entity operations (#31479) 2025-05-26 23:04:31 -04:00
command_palette_hooks Add workspace-hack (#27277) 2025-04-02 13:26:34 -07:00
component component: Replace linkme with inventory (#30705) 2025-05-14 23:29:11 +02:00
context_server context_server: Fix casing of mimeType in tool responses (#30703) 2025-05-26 10:29:45 +02:00
copilot Revert "copilot: Fix vision request detection for follow-up messages" (#31776) 2025-05-30 21:28:31 +02:00
credentials_provider Add workspace-hack (#27277) 2025-04-02 13:26:34 -07:00
dap debugger: Fix issues with running Zed-installed debugpy + hangs when downloading (#32034) 2025-06-04 01:37:25 +02:00
dap_adapters debugger: Fix issues with running Zed-installed debugpy + hangs when downloading (#32034) 2025-06-04 01:37:25 +02:00
db Add end of service notifications (#30982) 2025-05-20 00:20:00 +00:00
debug_adapter_extension debugger beta: Fix dap_schema for DAP extensions (#31173) 2025-05-22 07:24:46 -04:00
debugger_tools Rename debug: commands to dev: (#30675) 2025-05-14 11:15:27 +02:00
debugger_ui Do not activate inactive tabs when pinning or unpinning 2025-06-03 17:43:06 -04:00
deepseek Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
diagnostics Use read-only access methods for read-only entity operations (#31479) 2025-05-26 23:04:31 -04:00
docs_preprocessor docs_preprocessor: Ensure keybind is found for actions with arguments (#27224) 2025-05-27 16:56:03 +00:00
editor Don't show invisibles from inlays (#32088) 2025-06-04 10:33:22 -06:00
eval agent: Generate a notification when reaching tool use limit (#31894) 2025-06-02 21:57:42 -03:00
extension extension: Update to wasm32-wasip2 target (#30953) 2025-05-26 16:06:38 +02:00
extension_api extension: Update to wasm32-wasip2 target (#30953) 2025-05-26 16:06:38 +02:00
extension_cli Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
extension_host Avoid re-querying language server completions when possible (#31872) 2025-06-02 22:19:09 +00:00
extensions_ui Improve Zed prompts for file path selection (#32014) 2025-06-03 20:35:25 +00:00
feature_flags Add a picker for jj bookmark list (#30883) 2025-05-17 16:42:45 +00:00
feedback Use shortened SHA when displaying version to install (#31281) 2025-05-23 14:53:53 +00:00
file_finder Improve Zed prompts for file path selection (#32014) 2025-06-03 20:35:25 +00:00
file_icons Add workspace-hack (#27277) 2025-04-02 13:26:34 -07:00
fs Better log canonicalization errors (#32030) 2025-06-03 22:30:59 +00:00
fsevent Add workspace-hack (#27277) 2025-04-02 13:26:34 -07:00
fuzzy Fix out-of-bounds panic in fuzzy matcher with Unicode/multibyte characters (#30546) 2025-05-12 14:43:14 +00:00
git Allow configuring custom git hosting providers in project settings (#31929) 2025-06-03 12:23:01 -04:00
git_hosting_providers Allow configuring custom git hosting providers in project settings (#31929) 2025-06-03 12:23:01 -04:00
git_ui Pass up intent with completion requests (#31710) 2025-05-29 20:43:12 +00:00
go_to_line go_to_line: Show position relative to current excerpt in a multi-buffer (#31947) 2025-06-03 09:41:45 +02:00
google_ai Add thinking budget for Gemini custom models (#31251) 2025-06-03 13:40:20 +02:00
gpui editor: Stabilize IME candidate box position during pre-edit on Wayland (#28429) 2025-06-04 09:14:01 +00:00
gpui_macros Add a live Rust style editor to inspector to edit a sequence of no-argument style modifiers (#31443) 2025-05-26 17:43:57 +00:00
gpui_tokio Add workspace-hack (#27277) 2025-04-02 13:26:34 -07:00
html_to_markdown Add workspace-hack (#27277) 2025-04-02 13:26:34 -07:00
http_client Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
http_client_tls Add workspace-hack (#27277) 2025-04-02 13:26:34 -07:00
icons agent: Allow to accept and reject all via the panel (#31971) 2025-06-03 15:20:25 -03:00
image_viewer Option to auto-close deleted files with no unsaved edits (#31920) 2025-06-03 13:18:29 +02:00
indexed_docs Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
inline_completion Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
inline_completion_button inline_completion_button: Fix links to account page (#31558) 2025-05-27 21:52:42 +00:00
inspector_ui Make completions menu stay open after after it's manually requested (#32015) 2025-06-03 20:33:52 +00:00
install_cli Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
jj Add a picker for jj bookmark list (#30883) 2025-05-17 16:42:45 +00:00
jj_ui Add a picker for jj bookmark list (#30883) 2025-05-17 16:42:45 +00:00
journal VSCode Settings import (#29018) 2025-04-23 20:54:09 +00:00
language Don't show invisibles from inlays (#32088) 2025-06-04 10:33:22 -06:00
language_extension debugger/extensions: Revert changes to extension store related to language config (#30225) 2025-05-08 14:01:39 +02:00
language_model Remove unused load_model method from LanguageModelProvider (#32070) 2025-06-04 14:07:01 +00:00
language_models Remove unused load_model method from LanguageModelProvider (#32070) 2025-06-04 14:07:01 +00:00
language_selector Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
language_tools Add newlines between messages in LSP RPC logs for more navigability (#31863) 2025-06-03 02:12:58 +00:00
languages Fix aggressive indent in shell scripts (#31973) 2025-06-03 10:50:58 -04:00
livekit_api Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
livekit_client Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
lmstudio Remove unused load_model method from LanguageModelProvider (#32070) 2025-06-04 14:07:01 +00:00
lsp zlog: Replace usages of env_logger in tests with zlog (#31436) 2025-05-26 11:48:50 -04:00
markdown gpui: Support hitbox blocking mouse interaction except scrolling (#31712) 2025-05-29 21:41:15 +00:00
markdown_preview markdown_preview: Fix release notes title being overridden (#31703) 2025-05-30 08:29:52 +00:00
media Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
menu agent: Add new panel navigation dropdown (#29539) 2025-04-29 21:58:45 -03:00
migrator agent: Add Burn Mode setting migrator (#31718) 2025-05-30 08:10:12 -03:00
mistral mistral: Add DevstralSmallLatest model to Mistral and Ollama (#31099) 2025-05-22 14:22:35 -04:00
multi_buffer multi_buffer: Merge adjacent matches into a single excerpt when separated by only one line (#31708) 2025-06-03 10:07:59 +00:00
node_runtime Fix unzipping clangd and codelldb on Windows (#31080) 2025-05-21 21:17:14 +03:00
notifications component: Replace linkme with inventory (#30705) 2025-05-14 23:29:11 +02:00
ollama Remove unused load_model method from LanguageModelProvider (#32070) 2025-06-04 14:07:01 +00:00
open_ai open_ai: Fix parallel tools issue (#30467) 2025-05-26 11:46:35 +00:00
open_router Add support for OpenRouter as a language model provider (#29496) 2025-06-03 15:59:46 +00:00
outline Use read-only access methods for read-only entity operations (#31479) 2025-05-26 23:04:31 -04:00
outline_panel Use read-only access methods for read-only entity operations (#31479) 2025-05-26 23:04:31 -04:00
panel Add workspace-hack (#27277) 2025-04-02 13:26:34 -07:00
paths Simplify debug launcher UI (#31928) 2025-06-02 21:24:08 +00:00
picker Allow to reuse PickerPopoverMenu outside of the model selector (#31684) 2025-05-29 12:55:47 +00:00
prettier Change default formatter settings for LaTeX (#28727) 2025-06-03 19:51:30 +00:00
project Properly register buffers with reused language servers (#32057) 2025-06-04 09:59:57 +00:00
project_panel project_panel: When initiating a drag the highlight selection should jump to the item you've picked up (#32044) 2025-06-04 08:30:51 +05:30
project_symbols Use read-only access methods for read-only entity operations (#31479) 2025-05-26 23:04:31 -04:00
prompt_store Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
proto Add channel reordering functionality (#31833) 2025-06-04 16:56:33 +00:00
recent_projects Improve Zed prompts for file path selection (#32014) 2025-06-03 20:35:25 +00:00
refineable Add a live Rust style editor to inspector to edit a sequence of no-argument style modifiers (#31443) 2025-05-26 17:43:57 +00:00
release_channel Use shortened SHA when displaying version to install (#31281) 2025-05-23 14:53:53 +00:00
remote Make it possible to use cargo-zigbuild for ZED_BUILD_REMOTE_SERVER (#31467) 2025-05-27 16:56:27 +00:00
remote_server Avoid re-querying language server completions when possible (#31872) 2025-06-02 22:19:09 +00:00
repl python: Re-land usage of source file path in toolchain picker (#31893) 2025-06-02 16:29:06 +00:00
reqwest_client Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
rich_text Add workspace-hack (#27277) 2025-04-02 13:26:34 -07:00
rope zlog: Replace usages of env_logger in tests with zlog (#31436) 2025-05-26 11:48:50 -04:00
rpc zlog: Replace usages of env_logger in tests with zlog (#31436) 2025-05-26 11:48:50 -04:00
rules_library agent: Refine rules library window design (#31994) 2025-06-03 14:59:17 -03:00
schema_generator Add workspace-hack (#27277) 2025-04-02 13:26:34 -07:00
search Use read-only access methods for read-only entity operations (#31479) 2025-05-26 23:04:31 -04:00
semantic_index Pass up intent with completion requests (#31710) 2025-05-29 20:43:12 +00:00
semantic_version Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
session Avoid unnecessary DB writes (#29417) 2025-04-25 17:41:49 +03:00
settings Allow configuring custom git hosting providers in project settings (#31929) 2025-06-03 12:23:01 -04:00
settings_ui Cursor settings import (#31424) 2025-05-27 14:14:25 -04:00
snippet Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
snippet_provider Use read-only access methods for read-only entity operations (#31479) 2025-05-26 23:04:31 -04:00
snippets_ui snippets: Add icons and file names to snippet scope selector (#30212) 2025-05-26 13:44:09 +00:00
sqlez Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
sqlez_macros Add workspace-hack (#27277) 2025-04-02 13:26:34 -07:00
story gpui: Add a standard text example (#30747) 2025-05-16 17:35:44 +02:00
storybook Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
streaming_diff Introduce a new StreamingEditFileTool (#29733) 2025-05-01 17:37:43 +02:00
sum_tree zlog: Replace usages of env_logger in tests with zlog (#31436) 2025-05-26 11:48:50 -04:00
supermaven Add workspace-hack (#27277) 2025-04-02 13:26:34 -07:00
supermaven_api Keep file permissions when extracting zip archives on Unix (#31304) 2025-05-23 20:45:32 +00:00
tab_switcher tab_switcher: Add placeholder text (#31697) 2025-05-29 16:09:07 +00:00
task Revert "debugger beta: Fix bug where debug Rust main running action f… (#31743) 2025-05-30 14:32:59 +02:00
tasks_ui Use better fallback for empty rerun action (#32031) 2025-06-03 22:45:37 +00:00
telemetry Add workspace-hack (#27277) 2025-04-02 13:26:34 -07:00
telemetry_events Add new action to run agent eval (#29158) 2025-04-21 21:30:21 -07:00
terminal terminal: Match trait bounds with terminal input (#31441) 2025-06-02 21:12:28 -06:00
terminal_view Do not activate inactive tabs when pinning or unpinning 2025-06-03 17:43:06 -04:00
text Add #[track_caller] to test utilities that involve marked text (#32043) 2025-06-04 02:37:27 +00:00
theme theme: Add colors for minimap thumb and border (#30785) 2025-05-26 18:23:41 +00:00
theme_extension Add workspace-hack (#27277) 2025-04-02 13:26:34 -07:00
theme_importer theme: Add colors for minimap thumb and border (#30785) 2025-05-26 18:23:41 +00:00
theme_selector Icon theme selector: Don't select last list item when fuzzy searching (#29560) 2025-05-30 20:37:38 +00:00
time_format agent: Add date separators to Thread History (#29961) 2025-05-06 10:18:48 +00:00
title_bar Support macOS Sequoia titlebar double-click action (#30468) 2025-05-30 17:13:50 +00:00
toolchain_selector python: Re-land usage of source file path in toolchain picker (#31893) 2025-06-02 16:29:06 +00:00
ui gpui: Support hitbox blocking mouse interaction except scrolling (#31712) 2025-05-29 21:41:15 +00:00
ui_input component: Replace linkme with inventory (#30705) 2025-05-14 23:29:11 +02:00
ui_macros Update syn crate from 1.0.109 to 2.0.101 (#31301) 2025-05-23 19:31:25 +00:00
ui_prompt gpui: Improve window.prompt to support ESC with non-English cancel text on macOS (#29538) 2025-05-30 15:26:27 +00:00
util Add #[track_caller] to test utilities that involve marked text (#32043) 2025-06-04 02:37:27 +00:00
util_macros Fix license symlinks (#29758) 2025-05-01 19:24:14 +00:00
vim Add Helix implementation for Motion::FindForward and Motion::FindBackward (#31547) 2025-06-02 22:15:21 -06:00
vim_mode_setting VSCode Settings import (#29018) 2025-04-23 20:54:09 +00:00
web_search agent: Expose web search tool to beta users (#29273) 2025-04-23 15:30:20 +00:00
web_search_providers Use anyhow more idiomatically (#31052) 2025-05-20 23:06:07 +00:00
welcome Cursor keymap (#31702) 2025-05-29 15:20:58 -04:00
workspace Do not activate inactive tabs when pinning or unpinning 2025-06-03 17:43:06 -04:00
worktree Better log canonicalization errors (#32030) 2025-06-03 22:30:59 +00:00
zed Bump Zed to v0.191 (#32073) 2025-06-04 14:34:01 +00:00
zed_actions debugger: Add keyboard navigation for breakpoint list (#31221) 2025-05-26 19:40:07 +00:00
zeta zlog: Replace usages of env_logger in tests with zlog (#31436) 2025-05-26 11:48:50 -04:00
zlog zlog: Check crate name against filters if scope empty (#31892) 2025-06-02 13:22:32 +00:00
zlog_settings VSCode Settings import (#29018) 2025-04-23 20:54:09 +00:00