diff --git a/app/adapters/crate-owner-invite.js b/app/adapters/crate-owner-invite.js new file mode 100644 index 00000000000..79acd1a0ffc --- /dev/null +++ b/app/adapters/crate-owner-invite.js @@ -0,0 +1,8 @@ +import DS from 'ember-data'; + +export default DS.RESTAdapter.extend({ + namespace: 'api/v1/me', + pathForType() { + return 'crate_owner_invitations'; + } +}); diff --git a/app/models/crate-owner-invite.js b/app/models/crate-owner-invite.js new file mode 100644 index 00000000000..c3103b49708 --- /dev/null +++ b/app/models/crate-owner-invite.js @@ -0,0 +1,8 @@ +import DS from 'ember-data'; + +export default DS.Model.extend({ + invited_by_username: DS.attr('string'), + crate_name: DS.attr('string'), + crate_id: DS.attr('number'), + created_at: DS.attr('date') +}); diff --git a/app/router.js b/app/router.js index 13a021ea994..d5d0a4d698a 100644 --- a/app/router.js +++ b/app/router.js @@ -28,6 +28,7 @@ Router.map(function() { this.route('me', function() { this.route('crates'); this.route('following'); + this.route('pending-invites'); }); this.route('user', { path: '/users/:user_id' }); this.route('install'); diff --git a/app/routes/me/pending-invites.js b/app/routes/me/pending-invites.js new file mode 100644 index 00000000000..1e3c6960bd2 --- /dev/null +++ b/app/routes/me/pending-invites.js @@ -0,0 +1,9 @@ +import Ember from 'ember'; + +import AuthenticatedRoute from '../../mixins/authenticated-route'; + +export default Ember.Route.extend(AuthenticatedRoute, { + model() { + return this.get('store').findAll('crate-owner-invite'); + } +}); diff --git a/app/serializers/crate-owner-invite.js b/app/serializers/crate-owner-invite.js new file mode 100644 index 00000000000..652db050a4c --- /dev/null +++ b/app/serializers/crate-owner-invite.js @@ -0,0 +1,8 @@ +import DS from 'ember-data'; + +export default DS.RESTSerializer.extend({ + primaryKey: 'crate_id', + modelNameFromPayloadKey() { + return 'crate-owner-invite'; + } +}); diff --git a/app/styles/me.scss b/app/styles/me.scss index 57e21e2a75c..7396eb2e931 100644 --- a/app/styles/me.scss +++ b/app/styles/me.scss @@ -97,6 +97,7 @@ #my-crates, #my-following { margin: 0; } } } + #my-feed { @include flex-grow(5); h2 { font-size: 105%; } @@ -129,6 +130,23 @@ } } +#my-invites { + @include flex-grow(5); + + .row { + @include display-flex; + @include flex-direction(column); + } + + .info { + @include display-flex; + @include align-items(baseline); + @include justify-content(space-between); + + .date { @include flex-grow(2); text-align: right; } + } +} + #stats { margin-left: auto; padding: 10px; diff --git a/app/templates/me/pending-invites.hbs b/app/templates/me/pending-invites.hbs new file mode 100644 index 00000000000..df6f0e8e985 --- /dev/null +++ b/app/templates/me/pending-invites.hbs @@ -0,0 +1,38 @@ +{{ title 'Pending Invites' }} + +
+ {{svg-jar "gear"}} +

Pending Owner Invites

+
+ +
+
+ {{#each model as |invite|}} +
+
+
+

+ {{#link-to 'crate' invite.crate_name}} + {{invite.crate_name}} + {{/link-to}} +

+
+
+

Invited by: + {{#link-to 'user' invite.invited_by_username}} + {{invite.invited_by_username}} + {{/link-to}} +

+
+
+ {{moment-from-now invite.created_at}} +
+
+ + +
+
+
+ {{/each}} +
+
diff --git a/src/crate_owner_invitation.rs b/src/crate_owner_invitation.rs index 9a47aa6066d..085fa84f3ec 100644 --- a/src/crate_owner_invitation.rs +++ b/src/crate_owner_invitation.rs @@ -67,7 +67,7 @@ pub fn list(req: &mut Request) -> CargoResult { let conn = &*req.db_conn()?; let user_id = req.user()?.id; - let invitations = crate_owner_invitations::table + let crate_owner_invitations = crate_owner_invitations::table .filter(crate_owner_invitations::invited_user_id.eq(user_id)) .load::(&*conn)? .into_iter() @@ -76,7 +76,7 @@ pub fn list(req: &mut Request) -> CargoResult { #[derive(Serialize)] struct R { - invitations: Vec, + crate_owner_invitations: Vec, } - Ok(req.json(&R { invitations })) + Ok(req.json(&R { crate_owner_invitations })) } diff --git a/src/tests/owners.rs b/src/tests/owners.rs index d2a5d56adfd..b19c59fae50 100644 --- a/src/tests/owners.rs +++ b/src/tests/owners.rs @@ -301,7 +301,7 @@ fn check_ownership_one_crate() { fn invitations_are_empty_by_default() { #[derive(Deserialize)] struct R { - invitations: Vec, + crate_owner_invitations: Vec, } let (_b, app, middle) = ::app(); @@ -322,14 +322,14 @@ fn invitations_are_empty_by_default() { let mut response = ok_resp!(middle.call(&mut req)); let json: R = ::json(&mut response); - assert_eq!(json.invitations.len(), 0); + assert_eq!(json.crate_owner_invitations.len(), 0); } #[test] fn invitations_list() { #[derive(Deserialize)] struct R { - invitations: Vec, + crate_owner_invitations: Vec, } let (_b, app, middle) = ::app(); @@ -362,8 +362,11 @@ fn invitations_list() { let mut response = ok_resp!(middle.call(&mut req)); let json: R = ::json(&mut response); - assert_eq!(json.invitations.len(), 1); - assert_eq!(json.invitations[0].invited_by_username, "inviting_user"); - assert_eq!(json.invitations[0].crate_name, "invited_crate"); - assert_eq!(json.invitations[0].crate_id, krate.id); + assert_eq!(json.crate_owner_invitations.len(), 1); + assert_eq!( + json.crate_owner_invitations[0].invited_by_username, + "inviting_user" + ); + assert_eq!(json.crate_owner_invitations[0].crate_name, "invited_crate"); + assert_eq!(json.crate_owner_invitations[0].crate_id, krate.id); }