Define data types for the new contacts model

Antonio Scandurra and Nathan Sobo created

Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

assets/themes/cave-dark.json                                | 11 ++
assets/themes/cave-light.json                               | 11 ++
assets/themes/dark.json                                     | 11 ++
assets/themes/light.json                                    | 11 ++
assets/themes/solarized-dark.json                           | 11 ++
assets/themes/solarized-light.json                          | 11 ++
assets/themes/sulphurpool-dark.json                         | 11 ++
assets/themes/sulphurpool-light.json                        | 11 ++
crates/collab/migrations/20220506130724_create_contacts.sql | 10 ++
crates/collab/src/rpc.rs                                    |  2 
crates/contacts_panel/src/contacts_panel.rs                 |  8 +
crates/rpc/proto/zed.proto                                  | 32 ++++++
crates/theme/src/theme.rs                                   |  1 
styles/src/styleTree/contactsPanel.ts                       |  6 +
14 files changed, 143 insertions(+), 4 deletions(-)

Detailed changes

assets/themes/cave-dark.json 🔗

@@ -1255,6 +1255,17 @@
         "left": 8
       }
     },
+    "edit_contact": {
+      "family": "Zed Mono",
+      "color": "#e2dfe7",
+      "size": 14,
+      "background": "#26232a",
+      "corner_radius": 12,
+      "padding": {
+        "left": 7,
+        "right": 7
+      }
+    },
     "header": {
       "family": "Zed Mono",
       "color": "#8b8792",

assets/themes/cave-light.json 🔗

@@ -1255,6 +1255,17 @@
         "left": 8
       }
     },
+    "edit_contact": {
+      "family": "Zed Mono",
+      "color": "#26232a",
+      "size": 14,
+      "background": "#e2dfe7",
+      "corner_radius": 12,
+      "padding": {
+        "left": 7,
+        "right": 7
+      }
+    },
     "header": {
       "family": "Zed Mono",
       "color": "#585260",

assets/themes/dark.json 🔗

@@ -1255,6 +1255,17 @@
         "left": 8
       }
     },
+    "edit_contact": {
+      "family": "Zed Mono",
+      "color": "#f1f1f1",
+      "size": 14,
+      "background": "#2b2b2b",
+      "corner_radius": 12,
+      "padding": {
+        "left": 7,
+        "right": 7
+      }
+    },
     "header": {
       "family": "Zed Mono",
       "color": "#9c9c9c",

assets/themes/light.json 🔗

@@ -1255,6 +1255,17 @@
         "left": 8
       }
     },
+    "edit_contact": {
+      "family": "Zed Mono",
+      "color": "#2b2b2b",
+      "size": 14,
+      "background": "#eaeaea",
+      "corner_radius": 12,
+      "padding": {
+        "left": 7,
+        "right": 7
+      }
+    },
     "header": {
       "family": "Zed Mono",
       "color": "#474747",

assets/themes/solarized-dark.json 🔗

@@ -1255,6 +1255,17 @@
         "left": 8
       }
     },
+    "edit_contact": {
+      "family": "Zed Mono",
+      "color": "#eee8d5",
+      "size": 14,
+      "background": "#073642",
+      "corner_radius": 12,
+      "padding": {
+        "left": 7,
+        "right": 7
+      }
+    },
     "header": {
       "family": "Zed Mono",
       "color": "#93a1a1",

assets/themes/solarized-light.json 🔗

@@ -1255,6 +1255,17 @@
         "left": 8
       }
     },
+    "edit_contact": {
+      "family": "Zed Mono",
+      "color": "#073642",
+      "size": 14,
+      "background": "#eee8d5",
+      "corner_radius": 12,
+      "padding": {
+        "left": 7,
+        "right": 7
+      }
+    },
     "header": {
       "family": "Zed Mono",
       "color": "#586e75",

assets/themes/sulphurpool-dark.json 🔗

@@ -1255,6 +1255,17 @@
         "left": 8
       }
     },
+    "edit_contact": {
+      "family": "Zed Mono",
+      "color": "#dfe2f1",
+      "size": 14,
+      "background": "#293256",
+      "corner_radius": 12,
+      "padding": {
+        "left": 7,
+        "right": 7
+      }
+    },
     "header": {
       "family": "Zed Mono",
       "color": "#979db4",

assets/themes/sulphurpool-light.json 🔗

@@ -1255,6 +1255,17 @@
         "left": 8
       }
     },
+    "edit_contact": {
+      "family": "Zed Mono",
+      "color": "#293256",
+      "size": 14,
+      "background": "#dfe2f1",
+      "corner_radius": 12,
+      "padding": {
+        "left": 7,
+        "right": 7
+      }
+    },
     "header": {
       "family": "Zed Mono",
       "color": "#5e6687",

crates/collab/migrations/20220506130724_create_contacts.sql 🔗

@@ -0,0 +1,10 @@
+CREATE TABLE IF NOT EXISTS "contacts" (
+    "id" SERIAL PRIMARY KEY,
+    "requesting_user_id" INTEGER REFERENCES users (id) NOT NULL,
+    "receiving_user_id" INTEGER REFERENCES users (id) NOT NULL,
+    "accepted" BOOLEAN NOT NULL,
+    "blocked" BOOLEAN NOT NULL
+);
+
+CREATE UNIQUE INDEX "index_org_contacts_requesting_user_id_and_receiving_user_id" ON "contacts" ("requesting_user_id", "receiving_user_id");
+CREATE UNIQUE INDEX "index_org_contacts_receiving_user" ON "contacts" ("receiving_user_id");

crates/collab/src/rpc.rs 🔗

@@ -905,6 +905,8 @@ impl Server {
                         connection_id,
                         proto::UpdateContacts {
                             contacts: contacts.clone(),
+                            pending_requests_from_user_ids: Default::default(),
+                            pending_requests_to_user_ids: Default::default(),
                         },
                     )
                     .trace_err();

crates/contacts_panel/src/contacts_panel.rs 🔗

@@ -298,6 +298,14 @@ impl ContactsPanel {
                 .left()
                 .boxed(),
             )
+            .with_child(
+                Label::new("+".to_string(), theme.edit_contact.text.clone())
+                    .contained()
+                    .with_style(theme.edit_contact.container)
+                    .aligned()
+                    .flex_float()
+                    .boxed(),
+            )
             .constrained()
             .with_height(theme.row_height)
             .boxed()

crates/rpc/proto/zed.proto 🔗

@@ -89,11 +89,13 @@ message Envelope {
         GetUsers get_users = 76;
         FuzzySearchUsers fuzzy_search_users = 77;
         UsersResponse users_response = 78;
+        RequestContact request_contact = 79;
+        RespondToContactRequest respond_to_contact_request = 80;
 
-        Follow follow = 79;
-        FollowResponse follow_response = 80;
-        UpdateFollowers update_followers = 81;
-        Unfollow unfollow = 82;
+        Follow follow = 81;
+        FollowResponse follow_response = 82;
+        UpdateFollowers update_followers = 83;
+        Unfollow unfollow = 84;
     }
 }
 
@@ -547,6 +549,21 @@ message UsersResponse {
     repeated User users = 1;
 }
 
+message RequestContact {
+    uint64 to_user_id = 1;
+}
+
+message RespondToContactRequest {
+    uint64 requesting_user_id = 1;
+    ContactRequestResponse response = 2;
+}
+
+enum ContactRequestResponse {
+    Accept = 0;
+    Reject = 1;
+    Block = 2;
+}
+
 message SendChannelMessage {
     uint64 channel_id = 1;
     string body = 2;
@@ -574,6 +591,13 @@ message GetChannelMessagesResponse {
 
 message UpdateContacts {
     repeated Contact contacts = 1;
+    repeated IncomingContactRequest pending_requests_from_user_ids = 2;
+    repeated uint64 pending_requests_to_user_ids = 3;
+}
+
+message IncomingContactRequest {
+    uint64 user_id = 1;
+    bool show_notification = 2;
 }
 
 message UpdateDiagnostics {

crates/theme/src/theme.rs 🔗

@@ -239,6 +239,7 @@ pub struct ContactsPanel {
     pub row_height: f32,
     pub contact_avatar: ImageStyle,
     pub contact_username: ContainedText,
+    pub edit_contact: ContainedText,
     pub tree_branch_width: f32,
     pub tree_branch_color: Color,
     pub shared_project: ProjectRow,

styles/src/styleTree/contactsPanel.ts 🔗

@@ -60,6 +60,12 @@ export default function(theme: Theme) {
         left: 8,
       },
     },
+    editContact: {
+      ...text(theme, "mono", "primary", { size: "sm" }),
+      background: backgroundColor(theme, 100),
+      cornerRadius: 12,
+      padding: { left: 7, right: 7 }
+    },
     header: {
       ...text(theme, "mono", "secondary", { size: "sm" }),
       // padding: {