mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-08 18:35:06 +03:00
Merge branch 'collab-panel' of github.com:zed-industries/zed into collab-panel
This commit is contained in:
commit
707e41ce1f
@ -58,16 +58,20 @@ impl ChannelStore {
|
||||
client.add_message_handler(cx.handle(), Self::handle_update_channels);
|
||||
|
||||
let mut current_user = user_store.read(cx).watch_current_user();
|
||||
let maintain_user = cx.spawn(|this, mut cx| async move {
|
||||
let maintain_user = cx.spawn_weak(|this, mut cx| async move {
|
||||
while let Some(current_user) = current_user.next().await {
|
||||
if current_user.is_none() {
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.channels.clear();
|
||||
this.channel_invitations.clear();
|
||||
this.channel_participants.clear();
|
||||
this.outgoing_invites.clear();
|
||||
cx.notify();
|
||||
});
|
||||
if let Some(this) = this.upgrade(&cx) {
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.channels.clear();
|
||||
this.channel_invitations.clear();
|
||||
this.channel_participants.clear();
|
||||
this.outgoing_invites.clear();
|
||||
cx.notify();
|
||||
});
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -192,11 +192,11 @@ CREATE TABLE "channels" (
|
||||
"created_at" TIMESTAMP NOT NULL DEFAULT now
|
||||
);
|
||||
|
||||
CREATE TABLE "channel_parents" (
|
||||
"child_id" INTEGER NOT NULL REFERENCES channels (id) ON DELETE CASCADE,
|
||||
"parent_id" INTEGER NOT NULL REFERENCES channels (id) ON DELETE CASCADE,
|
||||
PRIMARY KEY(child_id, parent_id)
|
||||
CREATE TABLE "channel_paths" (
|
||||
"id_path" TEXT NOT NULL PRIMARY KEY,
|
||||
"channel_id" INTEGER NOT NULL REFERENCES channels (id) ON DELETE CASCADE
|
||||
);
|
||||
CREATE INDEX "index_channel_paths_on_channel_id" ON "channel_paths" ("channel_id");
|
||||
|
||||
CREATE TABLE "channel_members" (
|
||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
|
@ -10,11 +10,11 @@ CREATE TABLE "channels" (
|
||||
"created_at" TIMESTAMP NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE "channel_parents" (
|
||||
"child_id" INTEGER NOT NULL REFERENCES channels (id) ON DELETE CASCADE,
|
||||
"parent_id" INTEGER NOT NULL REFERENCES channels (id) ON DELETE CASCADE,
|
||||
PRIMARY KEY(child_id, parent_id)
|
||||
CREATE TABLE "channel_paths" (
|
||||
"id_path" VARCHAR NOT NULL PRIMARY KEY,
|
||||
"channel_id" INTEGER NOT NULL REFERENCES channels (id) ON DELETE CASCADE
|
||||
);
|
||||
CREATE INDEX "index_channel_paths_on_channel_id" ON "channel_paths" ("channel_id");
|
||||
|
||||
CREATE TABLE "channel_members" (
|
||||
"id" SERIAL PRIMARY KEY,
|
||||
|
@ -1,7 +1,7 @@
|
||||
mod access_token;
|
||||
mod channel;
|
||||
mod channel_member;
|
||||
mod channel_parent;
|
||||
mod channel_path;
|
||||
mod contact;
|
||||
mod follower;
|
||||
mod language_server;
|
||||
@ -3169,12 +3169,34 @@ impl Database {
|
||||
.insert(&*tx)
|
||||
.await?;
|
||||
|
||||
let channel_paths_stmt;
|
||||
if let Some(parent) = parent {
|
||||
channel_parent::ActiveModel {
|
||||
child_id: ActiveValue::Set(channel.id),
|
||||
parent_id: ActiveValue::Set(parent),
|
||||
}
|
||||
.insert(&*tx)
|
||||
let sql = r#"
|
||||
INSERT INTO channel_paths
|
||||
(id_path, channel_id)
|
||||
SELECT
|
||||
id_path || $1 || '/', $2
|
||||
FROM
|
||||
channel_paths
|
||||
WHERE
|
||||
channel_id = $3
|
||||
"#;
|
||||
channel_paths_stmt = Statement::from_sql_and_values(
|
||||
self.pool.get_database_backend(),
|
||||
sql,
|
||||
[
|
||||
channel.id.to_proto().into(),
|
||||
channel.id.to_proto().into(),
|
||||
parent.to_proto().into(),
|
||||
],
|
||||
);
|
||||
tx.execute(channel_paths_stmt).await?;
|
||||
} else {
|
||||
channel_path::Entity::insert(channel_path::ActiveModel {
|
||||
channel_id: ActiveValue::Set(channel.id),
|
||||
id_path: ActiveValue::Set(format!("/{}/", channel.id)),
|
||||
})
|
||||
.exec(&*tx)
|
||||
.await?;
|
||||
}
|
||||
|
||||
@ -3213,9 +3235,9 @@ impl Database {
|
||||
// Don't remove descendant channels that have additional parents.
|
||||
let mut channels_to_remove = self.get_channel_descendants([channel_id], &*tx).await?;
|
||||
{
|
||||
let mut channels_to_keep = channel_parent::Entity::find()
|
||||
let mut channels_to_keep = channel_path::Entity::find()
|
||||
.filter(
|
||||
channel_parent::Column::ChildId
|
||||
channel_path::Column::ChannelId
|
||||
.is_in(
|
||||
channels_to_remove
|
||||
.keys()
|
||||
@ -3223,15 +3245,15 @@ impl Database {
|
||||
.filter(|&id| id != channel_id),
|
||||
)
|
||||
.and(
|
||||
channel_parent::Column::ParentId
|
||||
.is_not_in(channels_to_remove.keys().copied()),
|
||||
channel_path::Column::IdPath
|
||||
.not_like(&format!("%/{}/%", channel_id)),
|
||||
),
|
||||
)
|
||||
.stream(&*tx)
|
||||
.await?;
|
||||
while let Some(row) = channels_to_keep.next().await {
|
||||
let row = row?;
|
||||
channels_to_remove.remove(&row.child_id);
|
||||
channels_to_remove.remove(&row.channel_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3631,40 +3653,21 @@ impl Database {
|
||||
channel_id: ChannelId,
|
||||
tx: &DatabaseTransaction,
|
||||
) -> Result<Vec<ChannelId>> {
|
||||
let sql = format!(
|
||||
r#"
|
||||
WITH RECURSIVE channel_tree(child_id, parent_id) AS (
|
||||
SELECT CAST(NULL as INTEGER) as child_id, root_ids.column1 as parent_id
|
||||
FROM (VALUES ({})) as root_ids
|
||||
UNION
|
||||
SELECT channel_parents.child_id, channel_parents.parent_id
|
||||
FROM channel_parents, channel_tree
|
||||
WHERE channel_parents.child_id = channel_tree.parent_id
|
||||
)
|
||||
SELECT DISTINCT channel_tree.parent_id
|
||||
FROM channel_tree
|
||||
"#,
|
||||
channel_id
|
||||
);
|
||||
|
||||
#[derive(FromQueryResult, Debug, PartialEq)]
|
||||
pub struct ChannelParent {
|
||||
pub parent_id: ChannelId,
|
||||
}
|
||||
|
||||
let stmt = Statement::from_string(self.pool.get_database_backend(), sql);
|
||||
|
||||
let mut channel_ids_stream = channel_parent::Entity::find()
|
||||
.from_raw_sql(stmt)
|
||||
.into_model::<ChannelParent>()
|
||||
.stream(&*tx)
|
||||
let paths = channel_path::Entity::find()
|
||||
.filter(channel_path::Column::ChannelId.eq(channel_id))
|
||||
.all(tx)
|
||||
.await?;
|
||||
|
||||
let mut channel_ids = vec![];
|
||||
while let Some(channel_id) = channel_ids_stream.next().await {
|
||||
channel_ids.push(channel_id?.parent_id);
|
||||
let mut channel_ids = Vec::new();
|
||||
for path in paths {
|
||||
for id in path.id_path.trim_matches('/').split('/') {
|
||||
if let Ok(id) = id.parse() {
|
||||
let id = ChannelId::from_proto(id);
|
||||
if let Err(ix) = channel_ids.binary_search(&id) {
|
||||
channel_ids.insert(ix, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(channel_ids)
|
||||
}
|
||||
|
||||
@ -3687,38 +3690,38 @@ impl Database {
|
||||
|
||||
let sql = format!(
|
||||
r#"
|
||||
WITH RECURSIVE channel_tree(child_id, parent_id) AS (
|
||||
SELECT root_ids.column1 as child_id, CAST(NULL as INTEGER) as parent_id
|
||||
FROM (VALUES {values}) as root_ids
|
||||
UNION
|
||||
SELECT channel_parents.child_id, channel_parents.parent_id
|
||||
FROM channel_parents, channel_tree
|
||||
WHERE channel_parents.parent_id = channel_tree.child_id
|
||||
)
|
||||
SELECT channel_tree.child_id, channel_tree.parent_id
|
||||
FROM channel_tree
|
||||
ORDER BY child_id, parent_id IS NOT NULL
|
||||
"#,
|
||||
SELECT
|
||||
descendant_paths.*
|
||||
FROM
|
||||
channel_paths parent_paths, channel_paths descendant_paths
|
||||
WHERE
|
||||
parent_paths.channel_id IN ({values}) AND
|
||||
descendant_paths.id_path LIKE (parent_paths.id_path || '%')
|
||||
"#
|
||||
);
|
||||
|
||||
#[derive(FromQueryResult, Debug, PartialEq)]
|
||||
pub struct ChannelParent {
|
||||
pub child_id: ChannelId,
|
||||
pub parent_id: Option<ChannelId>,
|
||||
}
|
||||
|
||||
let stmt = Statement::from_string(self.pool.get_database_backend(), sql);
|
||||
|
||||
let mut parents_by_child_id = HashMap::default();
|
||||
let mut parents = channel_parent::Entity::find()
|
||||
let mut paths = channel_path::Entity::find()
|
||||
.from_raw_sql(stmt)
|
||||
.into_model::<ChannelParent>()
|
||||
.stream(tx)
|
||||
.await?;
|
||||
|
||||
while let Some(parent) = parents.next().await {
|
||||
let parent = parent?;
|
||||
parents_by_child_id.insert(parent.child_id, parent.parent_id);
|
||||
while let Some(path) = paths.next().await {
|
||||
let path = path?;
|
||||
let ids = path.id_path.trim_matches('/').split('/');
|
||||
let mut parent_id = None;
|
||||
for id in ids {
|
||||
if let Ok(id) = id.parse() {
|
||||
let id = ChannelId::from_proto(id);
|
||||
if id == path.channel_id {
|
||||
break;
|
||||
}
|
||||
parent_id = Some(id);
|
||||
}
|
||||
}
|
||||
parents_by_child_id.insert(path.channel_id, parent_id);
|
||||
}
|
||||
|
||||
Ok(parents_by_child_id)
|
||||
|
@ -2,12 +2,11 @@ use super::ChannelId;
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "channel_parents")]
|
||||
#[sea_orm(table_name = "channel_paths")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub child_id: ChannelId,
|
||||
#[sea_orm(primary_key)]
|
||||
pub parent_id: ChannelId,
|
||||
pub id_path: String,
|
||||
pub channel_id: ChannelId,
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
@ -1103,9 +1103,12 @@ impl CollabPanel {
|
||||
enum AddContact {}
|
||||
let button = match section {
|
||||
Section::ActiveCall => Some(
|
||||
MouseEventHandler::<AddContact, Self>::new(0, cx, |_, _| {
|
||||
MouseEventHandler::<AddContact, Self>::new(0, cx, |state, _| {
|
||||
render_icon_button(
|
||||
theme.collab_panel.leave_call_button.in_state(is_selected),
|
||||
theme
|
||||
.collab_panel
|
||||
.leave_call_button
|
||||
.style_for(is_selected, state),
|
||||
"icons/radix/exit.svg",
|
||||
)
|
||||
})
|
||||
@ -1122,9 +1125,12 @@ impl CollabPanel {
|
||||
),
|
||||
),
|
||||
Section::Contacts => Some(
|
||||
MouseEventHandler::<LeaveCallContactList, Self>::new(0, cx, |_, _| {
|
||||
MouseEventHandler::<LeaveCallContactList, Self>::new(0, cx, |state, _| {
|
||||
render_icon_button(
|
||||
theme.collab_panel.add_contact_button.in_state(is_selected),
|
||||
theme
|
||||
.collab_panel
|
||||
.add_contact_button
|
||||
.style_for(is_selected, state),
|
||||
"icons/plus_16.svg",
|
||||
)
|
||||
})
|
||||
@ -1141,9 +1147,12 @@ impl CollabPanel {
|
||||
),
|
||||
),
|
||||
Section::Channels => Some(
|
||||
MouseEventHandler::<AddChannel, Self>::new(0, cx, |_, _| {
|
||||
MouseEventHandler::<AddChannel, Self>::new(0, cx, |state, _| {
|
||||
render_icon_button(
|
||||
theme.collab_panel.add_contact_button.in_state(is_selected),
|
||||
theme
|
||||
.collab_panel
|
||||
.add_contact_button
|
||||
.style_for(is_selected, state),
|
||||
"icons/plus_16.svg",
|
||||
)
|
||||
})
|
||||
|
@ -226,9 +226,9 @@ pub struct CollabPanel {
|
||||
pub channel_modal: ChannelModal,
|
||||
pub user_query_editor: FieldEditor,
|
||||
pub user_query_editor_height: f32,
|
||||
pub leave_call_button: Toggleable<IconButton>,
|
||||
pub add_contact_button: Toggleable<IconButton>,
|
||||
pub add_channel_button: Toggleable<IconButton>,
|
||||
pub leave_call_button: Toggleable<Interactive<IconButton>>,
|
||||
pub add_contact_button: Toggleable<Interactive<IconButton>>,
|
||||
pub add_channel_button: Toggleable<Interactive<IconButton>>,
|
||||
pub header_row: ContainedText,
|
||||
pub subheader_row: Toggleable<Interactive<ContainedText>>,
|
||||
pub leave_call: Interactive<ContainedText>,
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
import { interactive, toggleable } from "../element"
|
||||
import { useTheme } from "../theme"
|
||||
import channel_modal from "./channel_modal"
|
||||
import { icon_button, toggleable_icon_button } from "../component/icon_button"
|
||||
|
||||
|
||||
export default function contacts_panel(): any {
|
||||
@ -51,19 +52,7 @@ export default function contacts_panel(): any {
|
||||
},
|
||||
}
|
||||
|
||||
const headerButton = toggleable({
|
||||
base: {
|
||||
color: foreground(layer, "on"),
|
||||
button_width: 28,
|
||||
icon_width: 16,
|
||||
},
|
||||
state: {
|
||||
active: {
|
||||
background: background(layer, "active"),
|
||||
corner_radius: 8,
|
||||
}
|
||||
}
|
||||
})
|
||||
const headerButton = toggleable_icon_button(theme, {})
|
||||
|
||||
return {
|
||||
channel_modal: channel_modal(),
|
||||
|
Loading…
Reference in New Issue
Block a user