parent
2d16d2d036
commit
ffe36c9beb
15 changed files with 8 additions and 459 deletions
|
@ -3,7 +3,7 @@ mod channel_index;
|
||||||
use crate::{channel_buffer::ChannelBuffer, channel_chat::ChannelChat, ChannelMessage};
|
use crate::{channel_buffer::ChannelBuffer, channel_chat::ChannelChat, ChannelMessage};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use channel_index::ChannelIndex;
|
use channel_index::ChannelIndex;
|
||||||
use client::{ChannelId, Client, ClientSettings, ProjectId, Subscription, User, UserId, UserStore};
|
use client::{ChannelId, Client, ClientSettings, Subscription, User, UserId, UserStore};
|
||||||
use collections::{hash_map, HashMap, HashSet};
|
use collections::{hash_map, HashMap, HashSet};
|
||||||
use futures::{channel::mpsc, future::Shared, Future, FutureExt, StreamExt};
|
use futures::{channel::mpsc, future::Shared, Future, FutureExt, StreamExt};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
|
@ -33,30 +33,11 @@ struct NotesVersion {
|
||||||
version: clock::Global,
|
version: clock::Global,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct HostedProject {
|
|
||||||
project_id: ProjectId,
|
|
||||||
channel_id: ChannelId,
|
|
||||||
name: SharedString,
|
|
||||||
_visibility: proto::ChannelVisibility,
|
|
||||||
}
|
|
||||||
impl From<proto::HostedProject> for HostedProject {
|
|
||||||
fn from(project: proto::HostedProject) -> Self {
|
|
||||||
Self {
|
|
||||||
project_id: ProjectId(project.project_id),
|
|
||||||
channel_id: ChannelId(project.channel_id),
|
|
||||||
_visibility: project.visibility(),
|
|
||||||
name: project.name.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub struct ChannelStore {
|
pub struct ChannelStore {
|
||||||
pub channel_index: ChannelIndex,
|
pub channel_index: ChannelIndex,
|
||||||
channel_invitations: Vec<Arc<Channel>>,
|
channel_invitations: Vec<Arc<Channel>>,
|
||||||
channel_participants: HashMap<ChannelId, Vec<Arc<User>>>,
|
channel_participants: HashMap<ChannelId, Vec<Arc<User>>>,
|
||||||
channel_states: HashMap<ChannelId, ChannelState>,
|
channel_states: HashMap<ChannelId, ChannelState>,
|
||||||
hosted_projects: HashMap<ProjectId, HostedProject>,
|
|
||||||
|
|
||||||
outgoing_invites: HashSet<(ChannelId, UserId)>,
|
outgoing_invites: HashSet<(ChannelId, UserId)>,
|
||||||
update_channels_tx: mpsc::UnboundedSender<proto::UpdateChannels>,
|
update_channels_tx: mpsc::UnboundedSender<proto::UpdateChannels>,
|
||||||
opened_buffers: HashMap<ChannelId, OpenedModelHandle<ChannelBuffer>>,
|
opened_buffers: HashMap<ChannelId, OpenedModelHandle<ChannelBuffer>>,
|
||||||
|
@ -85,7 +66,6 @@ pub struct ChannelState {
|
||||||
observed_notes_version: NotesVersion,
|
observed_notes_version: NotesVersion,
|
||||||
observed_chat_message: Option<u64>,
|
observed_chat_message: Option<u64>,
|
||||||
role: Option<ChannelRole>,
|
role: Option<ChannelRole>,
|
||||||
projects: HashSet<ProjectId>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Channel {
|
impl Channel {
|
||||||
|
@ -216,7 +196,6 @@ impl ChannelStore {
|
||||||
channel_invitations: Vec::default(),
|
channel_invitations: Vec::default(),
|
||||||
channel_index: ChannelIndex::default(),
|
channel_index: ChannelIndex::default(),
|
||||||
channel_participants: Default::default(),
|
channel_participants: Default::default(),
|
||||||
hosted_projects: Default::default(),
|
|
||||||
outgoing_invites: Default::default(),
|
outgoing_invites: Default::default(),
|
||||||
opened_buffers: Default::default(),
|
opened_buffers: Default::default(),
|
||||||
opened_chats: Default::default(),
|
opened_chats: Default::default(),
|
||||||
|
@ -316,19 +295,6 @@ impl ChannelStore {
|
||||||
self.channel_index.by_id().get(&channel_id)
|
self.channel_index.by_id().get(&channel_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn projects_for_id(&self, channel_id: ChannelId) -> Vec<(SharedString, ProjectId)> {
|
|
||||||
let mut projects: Vec<(SharedString, ProjectId)> = self
|
|
||||||
.channel_states
|
|
||||||
.get(&channel_id)
|
|
||||||
.map(|state| state.projects.clone())
|
|
||||||
.unwrap_or_default()
|
|
||||||
.into_iter()
|
|
||||||
.flat_map(|id| Some((self.hosted_projects.get(&id)?.name.clone(), id)))
|
|
||||||
.collect();
|
|
||||||
projects.sort();
|
|
||||||
projects
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn has_open_channel_buffer(&self, channel_id: ChannelId, _cx: &AppContext) -> bool {
|
pub fn has_open_channel_buffer(&self, channel_id: ChannelId, _cx: &AppContext) -> bool {
|
||||||
if let Some(buffer) = self.opened_buffers.get(&channel_id) {
|
if let Some(buffer) = self.opened_buffers.get(&channel_id) {
|
||||||
if let OpenedModelHandle::Open(buffer) = buffer {
|
if let OpenedModelHandle::Open(buffer) = buffer {
|
||||||
|
@ -1102,9 +1068,7 @@ impl ChannelStore {
|
||||||
let channels_changed = !payload.channels.is_empty()
|
let channels_changed = !payload.channels.is_empty()
|
||||||
|| !payload.delete_channels.is_empty()
|
|| !payload.delete_channels.is_empty()
|
||||||
|| !payload.latest_channel_message_ids.is_empty()
|
|| !payload.latest_channel_message_ids.is_empty()
|
||||||
|| !payload.latest_channel_buffer_versions.is_empty()
|
|| !payload.latest_channel_buffer_versions.is_empty();
|
||||||
|| !payload.hosted_projects.is_empty()
|
|
||||||
|| !payload.deleted_hosted_projects.is_empty();
|
|
||||||
|
|
||||||
if channels_changed {
|
if channels_changed {
|
||||||
if !payload.delete_channels.is_empty() {
|
if !payload.delete_channels.is_empty() {
|
||||||
|
@ -1161,34 +1125,6 @@ impl ChannelStore {
|
||||||
.or_default()
|
.or_default()
|
||||||
.update_latest_message_id(latest_channel_message.message_id);
|
.update_latest_message_id(latest_channel_message.message_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
for hosted_project in payload.hosted_projects {
|
|
||||||
let hosted_project: HostedProject = hosted_project.into();
|
|
||||||
if let Some(old_project) = self
|
|
||||||
.hosted_projects
|
|
||||||
.insert(hosted_project.project_id, hosted_project.clone())
|
|
||||||
{
|
|
||||||
self.channel_states
|
|
||||||
.entry(old_project.channel_id)
|
|
||||||
.or_default()
|
|
||||||
.remove_hosted_project(old_project.project_id);
|
|
||||||
}
|
|
||||||
self.channel_states
|
|
||||||
.entry(hosted_project.channel_id)
|
|
||||||
.or_default()
|
|
||||||
.add_hosted_project(hosted_project.project_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
for hosted_project_id in payload.deleted_hosted_projects {
|
|
||||||
let hosted_project_id = ProjectId(hosted_project_id);
|
|
||||||
|
|
||||||
if let Some(old_project) = self.hosted_projects.remove(&hosted_project_id) {
|
|
||||||
self.channel_states
|
|
||||||
.entry(old_project.channel_id)
|
|
||||||
.or_default()
|
|
||||||
.remove_hosted_project(old_project.project_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
@ -1295,12 +1231,4 @@ impl ChannelState {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_hosted_project(&mut self, project_id: ProjectId) {
|
|
||||||
self.projects.insert(project_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_hosted_project(&mut self, project_id: ProjectId) {
|
|
||||||
self.projects.remove(&project_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -617,7 +617,6 @@ pub struct ChannelsForUser {
|
||||||
pub channels: Vec<Channel>,
|
pub channels: Vec<Channel>,
|
||||||
pub channel_memberships: Vec<channel_member::Model>,
|
pub channel_memberships: Vec<channel_member::Model>,
|
||||||
pub channel_participants: HashMap<ChannelId, Vec<UserId>>,
|
pub channel_participants: HashMap<ChannelId, Vec<UserId>>,
|
||||||
pub hosted_projects: Vec<proto::HostedProject>,
|
|
||||||
pub invited_channels: Vec<Channel>,
|
pub invited_channels: Vec<Channel>,
|
||||||
|
|
||||||
pub observed_buffer_versions: Vec<proto::ChannelBufferVersion>,
|
pub observed_buffer_versions: Vec<proto::ChannelBufferVersion>,
|
||||||
|
|
|
@ -10,7 +10,6 @@ pub mod contacts;
|
||||||
pub mod contributors;
|
pub mod contributors;
|
||||||
pub mod embeddings;
|
pub mod embeddings;
|
||||||
pub mod extensions;
|
pub mod extensions;
|
||||||
pub mod hosted_projects;
|
|
||||||
pub mod messages;
|
pub mod messages;
|
||||||
pub mod notifications;
|
pub mod notifications;
|
||||||
pub mod processed_stripe_events;
|
pub mod processed_stripe_events;
|
||||||
|
|
|
@ -615,15 +615,10 @@ impl Database {
|
||||||
.observed_channel_messages(&channel_ids, user_id, tx)
|
.observed_channel_messages(&channel_ids, user_id, tx)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let hosted_projects = self
|
|
||||||
.get_hosted_projects(&channel_ids, &roles_by_channel_id, tx)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(ChannelsForUser {
|
Ok(ChannelsForUser {
|
||||||
channel_memberships,
|
channel_memberships,
|
||||||
channels,
|
channels,
|
||||||
invited_channels,
|
invited_channels,
|
||||||
hosted_projects,
|
|
||||||
channel_participants,
|
channel_participants,
|
||||||
latest_buffer_versions,
|
latest_buffer_versions,
|
||||||
latest_channel_messages,
|
latest_channel_messages,
|
||||||
|
|
|
@ -1,85 +0,0 @@
|
||||||
use rpc::{proto, ErrorCode};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
impl Database {
|
|
||||||
pub async fn get_hosted_projects(
|
|
||||||
&self,
|
|
||||||
channel_ids: &[ChannelId],
|
|
||||||
roles: &HashMap<ChannelId, ChannelRole>,
|
|
||||||
tx: &DatabaseTransaction,
|
|
||||||
) -> Result<Vec<proto::HostedProject>> {
|
|
||||||
let projects = hosted_project::Entity::find()
|
|
||||||
.find_also_related(project::Entity)
|
|
||||||
.filter(hosted_project::Column::ChannelId.is_in(channel_ids.iter().map(|id| id.0)))
|
|
||||||
.all(tx)
|
|
||||||
.await?
|
|
||||||
.into_iter()
|
|
||||||
.flat_map(|(hosted_project, project)| {
|
|
||||||
if hosted_project.deleted_at.is_some() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
match hosted_project.visibility {
|
|
||||||
ChannelVisibility::Public => {}
|
|
||||||
ChannelVisibility::Members => {
|
|
||||||
let is_visible = roles
|
|
||||||
.get(&hosted_project.channel_id)
|
|
||||||
.map(|role| role.can_see_all_descendants())
|
|
||||||
.unwrap_or(false);
|
|
||||||
if !is_visible {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Some(proto::HostedProject {
|
|
||||||
project_id: project?.id.to_proto(),
|
|
||||||
channel_id: hosted_project.channel_id.to_proto(),
|
|
||||||
name: hosted_project.name.clone(),
|
|
||||||
visibility: hosted_project.visibility.into(),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(projects)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_hosted_project(
|
|
||||||
&self,
|
|
||||||
hosted_project_id: HostedProjectId,
|
|
||||||
user_id: UserId,
|
|
||||||
tx: &DatabaseTransaction,
|
|
||||||
) -> Result<(hosted_project::Model, ChannelRole)> {
|
|
||||||
let project = hosted_project::Entity::find_by_id(hosted_project_id)
|
|
||||||
.one(tx)
|
|
||||||
.await?
|
|
||||||
.ok_or_else(|| anyhow!(ErrorCode::NoSuchProject))?;
|
|
||||||
let channel = channel::Entity::find_by_id(project.channel_id)
|
|
||||||
.one(tx)
|
|
||||||
.await?
|
|
||||||
.ok_or_else(|| anyhow!(ErrorCode::NoSuchChannel))?;
|
|
||||||
|
|
||||||
let role = match project.visibility {
|
|
||||||
ChannelVisibility::Public => {
|
|
||||||
self.check_user_is_channel_participant(&channel, user_id, tx)
|
|
||||||
.await?
|
|
||||||
}
|
|
||||||
ChannelVisibility::Members => {
|
|
||||||
self.check_user_is_channel_member(&channel, user_id, tx)
|
|
||||||
.await?
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok((project, role))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn is_hosted_project(&self, project_id: ProjectId) -> Result<bool> {
|
|
||||||
self.transaction(|tx| async move {
|
|
||||||
Ok(project::Entity::find_by_id(project_id)
|
|
||||||
.one(&*tx)
|
|
||||||
.await?
|
|
||||||
.map(|project| project.hosted_project_id.is_some())
|
|
||||||
.ok_or_else(|| anyhow!(ErrorCode::NoSuchProject))?)
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -68,7 +68,6 @@ impl Database {
|
||||||
connection.owner_id as i32,
|
connection.owner_id as i32,
|
||||||
))),
|
))),
|
||||||
id: ActiveValue::NotSet,
|
id: ActiveValue::NotSet,
|
||||||
hosted_project_id: ActiveValue::Set(None),
|
|
||||||
}
|
}
|
||||||
.insert(&*tx)
|
.insert(&*tx)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -536,39 +535,6 @@ impl Database {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds the given connection to the specified hosted project
|
|
||||||
pub async fn join_hosted_project(
|
|
||||||
&self,
|
|
||||||
id: ProjectId,
|
|
||||||
user_id: UserId,
|
|
||||||
connection: ConnectionId,
|
|
||||||
) -> Result<(Project, ReplicaId)> {
|
|
||||||
self.transaction(|tx| async move {
|
|
||||||
let (project, hosted_project) = project::Entity::find_by_id(id)
|
|
||||||
.find_also_related(hosted_project::Entity)
|
|
||||||
.one(&*tx)
|
|
||||||
.await?
|
|
||||||
.ok_or_else(|| anyhow!("hosted project is no longer shared"))?;
|
|
||||||
|
|
||||||
let Some(hosted_project) = hosted_project else {
|
|
||||||
return Err(anyhow!("project is not hosted"))?;
|
|
||||||
};
|
|
||||||
|
|
||||||
let channel = channel::Entity::find_by_id(hosted_project.channel_id)
|
|
||||||
.one(&*tx)
|
|
||||||
.await?
|
|
||||||
.ok_or_else(|| anyhow!("no such channel"))?;
|
|
||||||
|
|
||||||
let role = self
|
|
||||||
.check_user_is_channel_participant(&channel, user_id, &tx)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
self.join_project_internal(project, user_id, connection, role, &tx)
|
|
||||||
.await
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_project(&self, id: ProjectId) -> Result<project::Model> {
|
pub async fn get_project(&self, id: ProjectId) -> Result<project::Model> {
|
||||||
self.transaction(|tx| async move {
|
self.transaction(|tx| async move {
|
||||||
Ok(project::Entity::find_by_id(id)
|
Ok(project::Entity::find_by_id(id)
|
||||||
|
|
|
@ -18,7 +18,6 @@ pub mod extension;
|
||||||
pub mod extension_version;
|
pub mod extension_version;
|
||||||
pub mod feature_flag;
|
pub mod feature_flag;
|
||||||
pub mod follower;
|
pub mod follower;
|
||||||
pub mod hosted_project;
|
|
||||||
pub mod language_server;
|
pub mod language_server;
|
||||||
pub mod notification;
|
pub mod notification;
|
||||||
pub mod notification_kind;
|
pub mod notification_kind;
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
use crate::db::{ChannelId, ChannelVisibility, HostedProjectId};
|
|
||||||
use sea_orm::entity::prelude::*;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
|
|
||||||
#[sea_orm(table_name = "hosted_projects")]
|
|
||||||
pub struct Model {
|
|
||||||
#[sea_orm(primary_key)]
|
|
||||||
pub id: HostedProjectId,
|
|
||||||
pub channel_id: ChannelId,
|
|
||||||
pub name: String,
|
|
||||||
pub visibility: ChannelVisibility,
|
|
||||||
pub deleted_at: Option<DateTime>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
|
||||||
pub enum Relation {
|
|
||||||
#[sea_orm(has_one = "super::project::Entity")]
|
|
||||||
Project,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Related<super::project::Entity> for Entity {
|
|
||||||
fn to() -> RelationDef {
|
|
||||||
Relation::Project.def()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::db::{HostedProjectId, ProjectId, Result, RoomId, ServerId, UserId};
|
use crate::db::{ProjectId, Result, RoomId, ServerId, UserId};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use rpc::ConnectionId;
|
use rpc::ConnectionId;
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
@ -12,7 +12,6 @@ pub struct Model {
|
||||||
pub host_user_id: Option<UserId>,
|
pub host_user_id: Option<UserId>,
|
||||||
pub host_connection_id: Option<i32>,
|
pub host_connection_id: Option<i32>,
|
||||||
pub host_connection_server_id: Option<ServerId>,
|
pub host_connection_server_id: Option<ServerId>,
|
||||||
pub hosted_project_id: Option<HostedProjectId>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Model {
|
impl Model {
|
||||||
|
@ -50,12 +49,6 @@ pub enum Relation {
|
||||||
Collaborators,
|
Collaborators,
|
||||||
#[sea_orm(has_many = "super::language_server::Entity")]
|
#[sea_orm(has_many = "super::language_server::Entity")]
|
||||||
LanguageServers,
|
LanguageServers,
|
||||||
#[sea_orm(
|
|
||||||
belongs_to = "super::hosted_project::Entity",
|
|
||||||
from = "Column::HostedProjectId",
|
|
||||||
to = "super::hosted_project::Column::Id"
|
|
||||||
)]
|
|
||||||
HostedProject,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Related<super::user::Entity> for Entity {
|
impl Related<super::user::Entity> for Entity {
|
||||||
|
@ -88,10 +81,4 @@ impl Related<super::language_server::Entity> for Entity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Related<super::hosted_project::Entity> for Entity {
|
|
||||||
fn to() -> RelationDef {
|
|
||||||
Relation::HostedProject.def()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
|
@ -287,7 +287,6 @@ impl Server {
|
||||||
.add_request_handler(share_project)
|
.add_request_handler(share_project)
|
||||||
.add_message_handler(unshare_project)
|
.add_message_handler(unshare_project)
|
||||||
.add_request_handler(join_project)
|
.add_request_handler(join_project)
|
||||||
.add_request_handler(join_hosted_project)
|
|
||||||
.add_message_handler(leave_project)
|
.add_message_handler(leave_project)
|
||||||
.add_request_handler(update_project)
|
.add_request_handler(update_project)
|
||||||
.add_request_handler(update_worktree)
|
.add_request_handler(update_worktree)
|
||||||
|
@ -1795,11 +1794,6 @@ impl JoinProjectInternalResponse for Response<proto::JoinProject> {
|
||||||
Response::<proto::JoinProject>::send(self, result)
|
Response::<proto::JoinProject>::send(self, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl JoinProjectInternalResponse for Response<proto::JoinHostedProject> {
|
|
||||||
fn send(self, result: proto::JoinProjectResponse) -> Result<()> {
|
|
||||||
Response::<proto::JoinHostedProject>::send(self, result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn join_project_internal(
|
fn join_project_internal(
|
||||||
response: impl JoinProjectInternalResponse,
|
response: impl JoinProjectInternalResponse,
|
||||||
|
@ -1923,11 +1917,6 @@ async fn leave_project(request: proto::LeaveProject, session: Session) -> Result
|
||||||
let sender_id = session.connection_id;
|
let sender_id = session.connection_id;
|
||||||
let project_id = ProjectId::from_proto(request.project_id);
|
let project_id = ProjectId::from_proto(request.project_id);
|
||||||
let db = session.db().await;
|
let db = session.db().await;
|
||||||
if db.is_hosted_project(project_id).await? {
|
|
||||||
let project = db.leave_hosted_project(project_id, sender_id).await?;
|
|
||||||
project_left(&project, &session);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let (room, project) = &*db.leave_project(project_id, sender_id).await?;
|
let (room, project) = &*db.leave_project(project_id, sender_id).await?;
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
|
@ -1943,24 +1932,6 @@ async fn leave_project(request: proto::LeaveProject, session: Session) -> Result
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn join_hosted_project(
|
|
||||||
request: proto::JoinHostedProject,
|
|
||||||
response: Response<proto::JoinHostedProject>,
|
|
||||||
session: Session,
|
|
||||||
) -> Result<()> {
|
|
||||||
let (mut project, replica_id) = session
|
|
||||||
.db()
|
|
||||||
.await
|
|
||||||
.join_hosted_project(
|
|
||||||
ProjectId(request.project_id as i32),
|
|
||||||
session.user_id(),
|
|
||||||
session.connection_id,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
join_project_internal(response, session, &mut project, &replica_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Updates other participants with changes to the project
|
/// Updates other participants with changes to the project
|
||||||
async fn update_project(
|
async fn update_project(
|
||||||
request: proto::UpdateProject,
|
request: proto::UpdateProject,
|
||||||
|
@ -4202,7 +4173,6 @@ fn build_channels_update(channels: ChannelsForUser) -> proto::UpdateChannels {
|
||||||
update.channel_invitations.push(channel.to_proto());
|
update.channel_invitations.push(channel.to_proto());
|
||||||
}
|
}
|
||||||
|
|
||||||
update.hosted_projects = channels.hosted_projects;
|
|
||||||
update
|
update
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use self::channel_modal::ChannelModal;
|
||||||
use crate::{channel_view::ChannelView, chat_panel::ChatPanel, CollaborationPanelSettings};
|
use crate::{channel_view::ChannelView, chat_panel::ChatPanel, CollaborationPanelSettings};
|
||||||
use call::ActiveCall;
|
use call::ActiveCall;
|
||||||
use channel::{Channel, ChannelEvent, ChannelStore};
|
use channel::{Channel, ChannelEvent, ChannelStore};
|
||||||
use client::{ChannelId, Client, Contact, ProjectId, User, UserStore};
|
use client::{ChannelId, Client, Contact, User, UserStore};
|
||||||
use contact_finder::ContactFinder;
|
use contact_finder::ContactFinder;
|
||||||
use db::kvp::KEY_VALUE_STORE;
|
use db::kvp::KEY_VALUE_STORE;
|
||||||
use editor::{Editor, EditorElement, EditorStyle};
|
use editor::{Editor, EditorElement, EditorStyle};
|
||||||
|
@ -182,10 +182,6 @@ enum ListEntry {
|
||||||
ChannelEditor {
|
ChannelEditor {
|
||||||
depth: usize,
|
depth: usize,
|
||||||
},
|
},
|
||||||
HostedProject {
|
|
||||||
id: ProjectId,
|
|
||||||
name: SharedString,
|
|
||||||
},
|
|
||||||
Contact {
|
Contact {
|
||||||
contact: Arc<Contact>,
|
contact: Arc<Contact>,
|
||||||
calling: bool,
|
calling: bool,
|
||||||
|
@ -566,7 +562,6 @@ impl CollabPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let hosted_projects = channel_store.projects_for_id(channel.id);
|
|
||||||
let has_children = channel_store
|
let has_children = channel_store
|
||||||
.channel_at_index(mat.candidate_id + 1)
|
.channel_at_index(mat.candidate_id + 1)
|
||||||
.map_or(false, |next_channel| {
|
.map_or(false, |next_channel| {
|
||||||
|
@ -600,10 +595,6 @@ impl CollabPanel {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, id) in hosted_projects {
|
|
||||||
self.entries.push(ListEntry::HostedProject { id, name });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1029,40 +1020,6 @@ impl CollabPanel {
|
||||||
.tooltip(move |cx| Tooltip::text("Open Chat", cx))
|
.tooltip(move |cx| Tooltip::text("Open Chat", cx))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_channel_project(
|
|
||||||
&self,
|
|
||||||
id: ProjectId,
|
|
||||||
name: &SharedString,
|
|
||||||
is_selected: bool,
|
|
||||||
cx: &mut ViewContext<Self>,
|
|
||||||
) -> impl IntoElement {
|
|
||||||
ListItem::new(ElementId::NamedInteger(
|
|
||||||
"channel-project".into(),
|
|
||||||
id.0 as usize,
|
|
||||||
))
|
|
||||||
.indent_level(2)
|
|
||||||
.indent_step_size(px(20.))
|
|
||||||
.selected(is_selected)
|
|
||||||
.on_click(cx.listener(move |this, _, cx| {
|
|
||||||
if let Some(workspace) = this.workspace.upgrade() {
|
|
||||||
let app_state = workspace.read(cx).app_state().clone();
|
|
||||||
workspace::join_hosted_project(id, app_state, cx).detach_and_prompt_err(
|
|
||||||
"Failed to open project",
|
|
||||||
cx,
|
|
||||||
|_, _| None,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
.start_slot(
|
|
||||||
h_flex()
|
|
||||||
.relative()
|
|
||||||
.gap_1()
|
|
||||||
.child(IconButton::new(0, IconName::FileTree)),
|
|
||||||
)
|
|
||||||
.child(Label::new(name.clone()))
|
|
||||||
.tooltip(move |cx| Tooltip::text("Open Project", cx))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_subchannels(&self, ix: usize) -> bool {
|
fn has_subchannels(&self, ix: usize) -> bool {
|
||||||
self.entries.get(ix).map_or(false, |entry| {
|
self.entries.get(ix).map_or(false, |entry| {
|
||||||
if let ListEntry::Channel { has_children, .. } = entry {
|
if let ListEntry::Channel { has_children, .. } = entry {
|
||||||
|
@ -1538,12 +1495,6 @@ impl CollabPanel {
|
||||||
ListEntry::ChannelChat { channel_id } => {
|
ListEntry::ChannelChat { channel_id } => {
|
||||||
self.join_channel_chat(*channel_id, cx)
|
self.join_channel_chat(*channel_id, cx)
|
||||||
}
|
}
|
||||||
ListEntry::HostedProject {
|
|
||||||
id: _id,
|
|
||||||
name: _name,
|
|
||||||
} => {
|
|
||||||
// todo()
|
|
||||||
}
|
|
||||||
ListEntry::OutgoingRequest(_) => {}
|
ListEntry::OutgoingRequest(_) => {}
|
||||||
ListEntry::ChannelEditor { .. } => {}
|
ListEntry::ChannelEditor { .. } => {}
|
||||||
}
|
}
|
||||||
|
@ -2157,10 +2108,6 @@ impl CollabPanel {
|
||||||
ListEntry::ChannelChat { channel_id } => self
|
ListEntry::ChannelChat { channel_id } => self
|
||||||
.render_channel_chat(*channel_id, is_selected, cx)
|
.render_channel_chat(*channel_id, is_selected, cx)
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
|
|
||||||
ListEntry::HostedProject { id, name } => self
|
|
||||||
.render_channel_project(*id, name, is_selected, cx)
|
|
||||||
.into_any_element(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2898,11 +2845,6 @@ impl PartialEq for ListEntry {
|
||||||
return channel_1.id == channel_2.id;
|
return channel_1.id == channel_2.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ListEntry::HostedProject { id, .. } => {
|
|
||||||
if let ListEntry::HostedProject { id: other_id, .. } = other {
|
|
||||||
return id == other_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ListEntry::ChannelNotes { channel_id } => {
|
ListEntry::ChannelNotes { channel_id } => {
|
||||||
if let ListEntry::ChannelNotes {
|
if let ListEntry::ChannelNotes {
|
||||||
channel_id: other_id,
|
channel_id: other_id,
|
||||||
|
|
|
@ -24,9 +24,7 @@ mod yarn;
|
||||||
|
|
||||||
use anyhow::{anyhow, Context as _, Result};
|
use anyhow::{anyhow, Context as _, Result};
|
||||||
use buffer_store::{BufferStore, BufferStoreEvent};
|
use buffer_store::{BufferStore, BufferStoreEvent};
|
||||||
use client::{
|
use client::{proto, Client, Collaborator, PendingEntitySubscription, TypedEnvelope, UserStore};
|
||||||
proto, Client, Collaborator, PendingEntitySubscription, ProjectId, TypedEnvelope, UserStore,
|
|
||||||
};
|
|
||||||
use clock::ReplicaId;
|
use clock::ReplicaId;
|
||||||
use collections::{BTreeSet, HashMap, HashSet};
|
use collections::{BTreeSet, HashMap, HashSet};
|
||||||
use debounced_delay::DebouncedDelay;
|
use debounced_delay::DebouncedDelay;
|
||||||
|
@ -154,7 +152,6 @@ pub struct Project {
|
||||||
remotely_created_models: Arc<Mutex<RemotelyCreatedModels>>,
|
remotely_created_models: Arc<Mutex<RemotelyCreatedModels>>,
|
||||||
terminals: Terminals,
|
terminals: Terminals,
|
||||||
node: Option<NodeRuntime>,
|
node: Option<NodeRuntime>,
|
||||||
hosted_project_id: Option<ProjectId>,
|
|
||||||
search_history: SearchHistory,
|
search_history: SearchHistory,
|
||||||
search_included_history: SearchHistory,
|
search_included_history: SearchHistory,
|
||||||
search_excluded_history: SearchHistory,
|
search_excluded_history: SearchHistory,
|
||||||
|
@ -678,7 +675,6 @@ impl Project {
|
||||||
local_handles: Vec::new(),
|
local_handles: Vec::new(),
|
||||||
},
|
},
|
||||||
node: Some(node),
|
node: Some(node),
|
||||||
hosted_project_id: None,
|
|
||||||
search_history: Self::new_search_history(),
|
search_history: Self::new_search_history(),
|
||||||
environment,
|
environment,
|
||||||
remotely_created_models: Default::default(),
|
remotely_created_models: Default::default(),
|
||||||
|
@ -796,7 +792,6 @@ impl Project {
|
||||||
local_handles: Vec::new(),
|
local_handles: Vec::new(),
|
||||||
},
|
},
|
||||||
node: Some(node),
|
node: Some(node),
|
||||||
hosted_project_id: None,
|
|
||||||
search_history: Self::new_search_history(),
|
search_history: Self::new_search_history(),
|
||||||
environment,
|
environment,
|
||||||
remotely_created_models: Default::default(),
|
remotely_created_models: Default::default(),
|
||||||
|
@ -993,7 +988,6 @@ impl Project {
|
||||||
local_handles: Vec::new(),
|
local_handles: Vec::new(),
|
||||||
},
|
},
|
||||||
node: None,
|
node: None,
|
||||||
hosted_project_id: None,
|
|
||||||
search_history: Self::new_search_history(),
|
search_history: Self::new_search_history(),
|
||||||
search_included_history: Self::new_search_history(),
|
search_included_history: Self::new_search_history(),
|
||||||
search_excluded_history: Self::new_search_history(),
|
search_excluded_history: Self::new_search_history(),
|
||||||
|
@ -1045,47 +1039,6 @@ impl Project {
|
||||||
Ok(this)
|
Ok(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn hosted(
|
|
||||||
remote_id: ProjectId,
|
|
||||||
user_store: Model<UserStore>,
|
|
||||||
client: Arc<Client>,
|
|
||||||
languages: Arc<LanguageRegistry>,
|
|
||||||
fs: Arc<dyn Fs>,
|
|
||||||
cx: AsyncAppContext,
|
|
||||||
) -> Result<Model<Self>> {
|
|
||||||
client.authenticate_and_connect(true, &cx).await?;
|
|
||||||
|
|
||||||
let subscriptions = [
|
|
||||||
EntitySubscription::Project(client.subscribe_to_entity::<Self>(remote_id.0)?),
|
|
||||||
EntitySubscription::BufferStore(
|
|
||||||
client.subscribe_to_entity::<BufferStore>(remote_id.0)?,
|
|
||||||
),
|
|
||||||
EntitySubscription::WorktreeStore(
|
|
||||||
client.subscribe_to_entity::<WorktreeStore>(remote_id.0)?,
|
|
||||||
),
|
|
||||||
EntitySubscription::LspStore(client.subscribe_to_entity::<LspStore>(remote_id.0)?),
|
|
||||||
EntitySubscription::SettingsObserver(
|
|
||||||
client.subscribe_to_entity::<SettingsObserver>(remote_id.0)?,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
let response = client
|
|
||||||
.request_envelope(proto::JoinHostedProject {
|
|
||||||
project_id: remote_id.0,
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
Self::from_join_project_response(
|
|
||||||
response,
|
|
||||||
subscriptions,
|
|
||||||
client,
|
|
||||||
true,
|
|
||||||
user_store,
|
|
||||||
languages,
|
|
||||||
fs,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_search_history() -> SearchHistory {
|
fn new_search_history() -> SearchHistory {
|
||||||
SearchHistory::new(
|
SearchHistory::new(
|
||||||
Some(MAX_PROJECT_SEARCH_HISTORY_SIZE),
|
Some(MAX_PROJECT_SEARCH_HISTORY_SIZE),
|
||||||
|
@ -1290,10 +1243,6 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hosted_project_id(&self) -> Option<ProjectId> {
|
|
||||||
self.hosted_project_id
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn supports_terminal(&self, _cx: &AppContext) -> bool {
|
pub fn supports_terminal(&self, _cx: &AppContext) -> bool {
|
||||||
if self.is_local() {
|
if self.is_local() {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -196,8 +196,6 @@ message Envelope {
|
||||||
GetImplementation get_implementation = 162;
|
GetImplementation get_implementation = 162;
|
||||||
GetImplementationResponse get_implementation_response = 163;
|
GetImplementationResponse get_implementation_response = 163;
|
||||||
|
|
||||||
JoinHostedProject join_hosted_project = 164;
|
|
||||||
|
|
||||||
CountLanguageModelTokens count_language_model_tokens = 230;
|
CountLanguageModelTokens count_language_model_tokens = 230;
|
||||||
CountLanguageModelTokensResponse count_language_model_tokens_response = 231;
|
CountLanguageModelTokensResponse count_language_model_tokens_response = 231;
|
||||||
GetCachedEmbeddings get_cached_embeddings = 189;
|
GetCachedEmbeddings get_cached_embeddings = 189;
|
||||||
|
@ -292,6 +290,7 @@ message Envelope {
|
||||||
|
|
||||||
reserved 87 to 88;
|
reserved 87 to 88;
|
||||||
reserved 158 to 161;
|
reserved 158 to 161;
|
||||||
|
reserved 164;
|
||||||
reserved 166 to 169;
|
reserved 166 to 169;
|
||||||
reserved 177 to 185;
|
reserved 177 to 185;
|
||||||
reserved 188;
|
reserved 188;
|
||||||
|
@ -523,11 +522,6 @@ message JoinProject {
|
||||||
uint64 project_id = 1;
|
uint64 project_id = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message JoinHostedProject {
|
|
||||||
uint64 project_id = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
message ListRemoteDirectory {
|
message ListRemoteDirectory {
|
||||||
uint64 dev_server_id = 1;
|
uint64 dev_server_id = 1;
|
||||||
string path = 2;
|
string path = 2;
|
||||||
|
@ -1294,13 +1288,7 @@ message UpdateChannels {
|
||||||
repeated ChannelMessageId latest_channel_message_ids = 8;
|
repeated ChannelMessageId latest_channel_message_ids = 8;
|
||||||
repeated ChannelBufferVersion latest_channel_buffer_versions = 9;
|
repeated ChannelBufferVersion latest_channel_buffer_versions = 9;
|
||||||
|
|
||||||
repeated HostedProject hosted_projects = 10;
|
reserved 10 to 15;
|
||||||
repeated uint64 deleted_hosted_projects = 11;
|
|
||||||
|
|
||||||
reserved 12;
|
|
||||||
reserved 13;
|
|
||||||
reserved 14;
|
|
||||||
reserved 15;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message UpdateUserChannels {
|
message UpdateUserChannels {
|
||||||
|
@ -1329,13 +1317,6 @@ message ChannelParticipants {
|
||||||
repeated uint64 participant_user_ids = 2;
|
repeated uint64 participant_user_ids = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message HostedProject {
|
|
||||||
uint64 project_id = 1;
|
|
||||||
uint64 channel_id = 2;
|
|
||||||
string name = 3;
|
|
||||||
ChannelVisibility visibility = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
message JoinChannel {
|
message JoinChannel {
|
||||||
uint64 channel_id = 1;
|
uint64 channel_id = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,7 +228,6 @@ messages!(
|
||||||
(JoinChannelChat, Foreground),
|
(JoinChannelChat, Foreground),
|
||||||
(JoinChannelChatResponse, Foreground),
|
(JoinChannelChatResponse, Foreground),
|
||||||
(JoinProject, Foreground),
|
(JoinProject, Foreground),
|
||||||
(JoinHostedProject, Foreground),
|
|
||||||
(JoinProjectResponse, Foreground),
|
(JoinProjectResponse, Foreground),
|
||||||
(JoinRoom, Foreground),
|
(JoinRoom, Foreground),
|
||||||
(JoinRoomResponse, Foreground),
|
(JoinRoomResponse, Foreground),
|
||||||
|
@ -411,7 +410,6 @@ request_messages!(
|
||||||
(JoinChannel, JoinRoomResponse),
|
(JoinChannel, JoinRoomResponse),
|
||||||
(JoinChannelBuffer, JoinChannelBufferResponse),
|
(JoinChannelBuffer, JoinChannelBufferResponse),
|
||||||
(JoinChannelChat, JoinChannelChatResponse),
|
(JoinChannelChat, JoinChannelChatResponse),
|
||||||
(JoinHostedProject, JoinProjectResponse),
|
|
||||||
(JoinProject, JoinProjectResponse),
|
(JoinProject, JoinProjectResponse),
|
||||||
(JoinRoom, JoinRoomResponse),
|
(JoinRoom, JoinRoomResponse),
|
||||||
(LeaveChannelBuffer, Ack),
|
(LeaveChannelBuffer, Ack),
|
||||||
|
|
|
@ -16,7 +16,7 @@ use anyhow::{anyhow, Context as _, Result};
|
||||||
use call::{call_settings::CallSettings, ActiveCall};
|
use call::{call_settings::CallSettings, ActiveCall};
|
||||||
use client::{
|
use client::{
|
||||||
proto::{self, ErrorCode, PanelId, PeerId},
|
proto::{self, ErrorCode, PanelId, PeerId},
|
||||||
ChannelId, Client, ErrorExt, ProjectId, Status, TypedEnvelope, UserStore,
|
ChannelId, Client, ErrorExt, Status, TypedEnvelope, UserStore,
|
||||||
};
|
};
|
||||||
use collections::{hash_map, HashMap, HashSet};
|
use collections::{hash_map, HashMap, HashSet};
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
|
@ -5469,58 +5469,6 @@ pub fn create_and_open_local_file(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn join_hosted_project(
|
|
||||||
hosted_project_id: ProjectId,
|
|
||||||
app_state: Arc<AppState>,
|
|
||||||
cx: &mut AppContext,
|
|
||||||
) -> Task<Result<()>> {
|
|
||||||
cx.spawn(|mut cx| async move {
|
|
||||||
let existing_window = cx.update(|cx| {
|
|
||||||
cx.windows().into_iter().find_map(|window| {
|
|
||||||
let workspace = window.downcast::<Workspace>()?;
|
|
||||||
workspace
|
|
||||||
.read(cx)
|
|
||||||
.is_ok_and(|workspace| {
|
|
||||||
workspace.project().read(cx).hosted_project_id() == Some(hosted_project_id)
|
|
||||||
})
|
|
||||||
.then_some(workspace)
|
|
||||||
})
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let workspace = if let Some(existing_window) = existing_window {
|
|
||||||
existing_window
|
|
||||||
} else {
|
|
||||||
let project = Project::hosted(
|
|
||||||
hosted_project_id,
|
|
||||||
app_state.user_store.clone(),
|
|
||||||
app_state.client.clone(),
|
|
||||||
app_state.languages.clone(),
|
|
||||||
app_state.fs.clone(),
|
|
||||||
cx.clone(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let window_bounds_override = window_bounds_env_override();
|
|
||||||
cx.update(|cx| {
|
|
||||||
let mut options = (app_state.build_window_options)(None, cx);
|
|
||||||
options.window_bounds = window_bounds_override.map(WindowBounds::Windowed);
|
|
||||||
cx.open_window(options, |cx| {
|
|
||||||
cx.new_view(|cx| {
|
|
||||||
Workspace::new(Default::default(), project, app_state.clone(), cx)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})??
|
|
||||||
};
|
|
||||||
|
|
||||||
workspace.update(&mut cx, |_, cx| {
|
|
||||||
cx.activate(true);
|
|
||||||
cx.activate_window();
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn open_ssh_project(
|
pub fn open_ssh_project(
|
||||||
window: WindowHandle<Workspace>,
|
window: WindowHandle<Workspace>,
|
||||||
connection_options: SshConnectionOptions,
|
connection_options: SshConnectionOptions,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue