From 0809f8259f75c0476ca5ab392447a0a85c0f8ec1 Mon Sep 17 00:00:00 2001 From: Esteban Borai Date: Fri, 2 Sep 2022 12:42:45 -0400 Subject: [PATCH 01/17] chore(mirage): provide fixtures for mocking invites --- mirage/fixtures/crate-owner-invitations.js | 32 ++++++++++++++++++++++ mirage/route-handlers/me.js | 3 ++ 2 files changed, 35 insertions(+) create mode 100644 mirage/fixtures/crate-owner-invitations.js diff --git a/mirage/fixtures/crate-owner-invitations.js b/mirage/fixtures/crate-owner-invitations.js new file mode 100644 index 0000000000..770fbd2413 --- /dev/null +++ b/mirage/fixtures/crate-owner-invitations.js @@ -0,0 +1,32 @@ +export default [ + { + inviteeId: 1, + inviterId: 2, + crateId: 'nanomsg', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'mock-build-deps', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'libc', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nanomsg-sys', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rust-crypto', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rust_mixin', + } +] \ No newline at end of file diff --git a/mirage/route-handlers/me.js b/mirage/route-handlers/me.js index 2f13002203..13aa355a1f 100644 --- a/mirage/route-handlers/me.js +++ b/mirage/route-handlers/me.js @@ -104,6 +104,9 @@ export function register(server) { return new Response(403, {}, { errors: [{ detail: 'must be logged in to perform that action' }] }); } + console.log(schema.crateOwnerInvitations.all()); + console.log(schema.crates.all()); + return schema.crateOwnerInvitations.where({ inviteeId: user.id }); }); From 8c60753b6d802ddaf8271c99a795882422b78291 Mon Sep 17 00:00:00 2001 From: Esteban Borai Date: Fri, 2 Sep 2022 13:40:48 -0400 Subject: [PATCH 02/17] fix: comment parsing for `crate_id` on serializer Currently the `crate_id` which is a `string` with the crate's name is attempted to be parsed on serialization, causing trouble at the moment of fetching crates in fixtures db. --- mirage/fixtures/crate-owner-invitations.js | 52 ++++++++++---------- mirage/route-handlers/me.js | 3 -- mirage/serializers/crate-owner-invitation.js | 4 +- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/mirage/fixtures/crate-owner-invitations.js b/mirage/fixtures/crate-owner-invitations.js index 770fbd2413..f723f302e1 100644 --- a/mirage/fixtures/crate-owner-invitations.js +++ b/mirage/fixtures/crate-owner-invitations.js @@ -4,29 +4,29 @@ export default [ inviterId: 2, crateId: 'nanomsg', }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'mock-build-deps', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'libc', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nanomsg-sys', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rust-crypto', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rust_mixin', - } -] \ No newline at end of file + // { + // inviteeId: 1, + // inviterId: 2, + // crateId: 'mock-build-deps', + // }, + // { + // inviteeId: 1, + // inviterId: 2, + // crateId: 'libc', + // }, + // { + // inviteeId: 1, + // inviterId: 2, + // crateId: 'nanomsg-sys', + // }, + // { + // inviteeId: 1, + // inviterId: 2, + // crateId: 'rust-crypto', + // }, + // { + // inviteeId: 1, + // inviterId: 2, + // crateId: 'rust_mixin', + // } +]; diff --git a/mirage/route-handlers/me.js b/mirage/route-handlers/me.js index 13aa355a1f..2f13002203 100644 --- a/mirage/route-handlers/me.js +++ b/mirage/route-handlers/me.js @@ -104,9 +104,6 @@ export function register(server) { return new Response(403, {}, { errors: [{ detail: 'must be logged in to perform that action' }] }); } - console.log(schema.crateOwnerInvitations.all()); - console.log(schema.crates.all()); - return schema.crateOwnerInvitations.where({ inviteeId: user.id }); }); diff --git a/mirage/serializers/crate-owner-invitation.js b/mirage/serializers/crate-owner-invitation.js index 85ec23bef0..3e356b0207 100644 --- a/mirage/serializers/crate-owner-invitation.js +++ b/mirage/serializers/crate-owner-invitation.js @@ -24,7 +24,9 @@ export default BaseSerializer.extend({ delete hash.id; delete hash.token; - hash.crate_id = Number(hash.crate_id); + // TODO: Check this further, `crate_id` are strings in the current fixtures + // when attempting to parse into number we will get `NaN`s here. + // hash.crate_id = Number(hash.crate_id); let crate = this.schema.crates.find(hash.crate_id); hash.crate_name = crate.name; From 712abe10c547ad0f9cf4becd30e4e717b281902c Mon Sep 17 00:00:00 2001 From: Esteban Borai Date: Fri, 2 Sep 2022 14:02:23 -0400 Subject: [PATCH 03/17] feat: render pagination component --- app/controllers/me/pending-invites.js | 30 + app/routes/me/pending-invites.js | 5 + app/styles/me/pending-invites.module.css | 1 + app/templates/me/pending-invites.hbs | 2 + mirage/fixtures/crate-owner-invitations.js | 720 ++++++++++++++++++++- mirage/route-handlers/crates.js | 5 +- mirage/route-handlers/me.js | 8 +- 7 files changed, 743 insertions(+), 28 deletions(-) create mode 100644 app/controllers/me/pending-invites.js diff --git a/app/controllers/me/pending-invites.js b/app/controllers/me/pending-invites.js new file mode 100644 index 0000000000..8294aa2ffb --- /dev/null +++ b/app/controllers/me/pending-invites.js @@ -0,0 +1,30 @@ +import Controller from '@ember/controller'; +import { tracked } from '@glimmer/tracking'; + +import { reads } from 'macro-decorators'; + +import { pagination } from '../../utils/pagination'; + +export default class PendingInvitesController extends Controller { + queryParams = ['page', 'per_page', 'sort']; + @tracked page = '1'; + @tracked per_page = 50; + @tracked sort = 'alpha'; + + @reads('model.meta.total') totalItems; + @pagination() pagination; + + get currentSortBy() { + if (this.sort === 'downloads') { + return 'All-Time Downloads'; + } else if (this.sort === 'recent-downloads') { + return 'Recent Downloads'; + } else if (this.sort === 'recent-updates') { + return 'Recent Updates'; + } else if (this.sort === 'new') { + return 'Newly Added'; + } else { + return 'Alphabetical'; + } + } +} diff --git a/app/routes/me/pending-invites.js b/app/routes/me/pending-invites.js index af51d27432..a88e6ba608 100644 --- a/app/routes/me/pending-invites.js +++ b/app/routes/me/pending-invites.js @@ -5,6 +5,11 @@ import AuthenticatedRoute from '../-authenticated-route'; export default class PendingInvitesRoute extends AuthenticatedRoute { @service store; + queryParams = { + page: { refreshModel: true }, + sort: { refreshModel: true }, + }; + model() { return this.store.findAll('crate-owner-invite'); } diff --git a/app/styles/me/pending-invites.module.css b/app/styles/me/pending-invites.module.css index 19813a7a86..9c5d3d4379 100644 --- a/app/styles/me/pending-invites.module.css +++ b/app/styles/me/pending-invites.module.css @@ -1,5 +1,6 @@ .list { background: white; + margin-bottom: 2rem; } .row { diff --git a/app/templates/me/pending-invites.hbs b/app/templates/me/pending-invites.hbs index 7fcd2d84d5..ec21dbdf50 100644 --- a/app/templates/me/pending-invites.hbs +++ b/app/templates/me/pending-invites.hbs @@ -9,3 +9,5 @@

You don't seem to have any pending invitations.

{{/each}} + + diff --git a/mirage/fixtures/crate-owner-invitations.js b/mirage/fixtures/crate-owner-invitations.js index f723f302e1..6336ff7285 100644 --- a/mirage/fixtures/crate-owner-invitations.js +++ b/mirage/fixtures/crate-owner-invitations.js @@ -4,29 +4,699 @@ export default [ inviterId: 2, crateId: 'nanomsg', }, - // { - // inviteeId: 1, - // inviterId: 2, - // crateId: 'mock-build-deps', - // }, - // { - // inviteeId: 1, - // inviterId: 2, - // crateId: 'libc', - // }, - // { - // inviteeId: 1, - // inviterId: 2, - // crateId: 'nanomsg-sys', - // }, - // { - // inviteeId: 1, - // inviterId: 2, - // crateId: 'rust-crypto', - // }, - // { - // inviteeId: 1, - // inviterId: 2, - // crateId: 'rust_mixin', - // } + { + inviteeId: 1, + inviterId: 2, + crateId: 'external_mixin', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustless', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'serde', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustful', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'quickcheck', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'mock-dev-deps', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'postgres', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nom', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rusted_cypher', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nanomsg', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'external_mixin', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustless', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'serde', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustful', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'quickcheck', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'mock-dev-deps', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'postgres', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nom', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rusted_cypher', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nanomsg', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'external_mixin', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustless', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'serde', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustful', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'quickcheck', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'mock-dev-deps', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'postgres', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nom', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rusted_cypher', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nanomsg', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'external_mixin', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustless', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'serde', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustful', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'quickcheck', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'mock-dev-deps', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'postgres', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nom', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rusted_cypher', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nanomsg', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'external_mixin', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustless', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'serde', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustful', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'quickcheck', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'mock-dev-deps', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'postgres', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nom', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rusted_cypher', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nanomsg', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'external_mixin', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustless', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'serde', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustful', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'quickcheck', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'mock-dev-deps', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'postgres', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nom', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rusted_cypher', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nanomsg', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'external_mixin', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustless', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'serde', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustful', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'quickcheck', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'mock-dev-deps', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'postgres', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nom', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rusted_cypher', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nanomsg', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'external_mixin', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustless', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'serde', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustful', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'quickcheck', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'mock-dev-deps', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'postgres', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nom', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rusted_cypher', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nanomsg', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'external_mixin', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustless', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'serde', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustful', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'quickcheck', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'mock-dev-deps', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'postgres', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nom', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rusted_cypher', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nanomsg', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'external_mixin', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustless', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'serde', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustful', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'quickcheck', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'mock-dev-deps', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'postgres', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nom', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rusted_cypher', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nanomsg', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'external_mixin', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustless', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'serde', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustful', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'quickcheck', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'mock-dev-deps', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'postgres', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nom', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rusted_cypher', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nanomsg', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'external_mixin', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustless', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'serde', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustful', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'quickcheck', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'mock-dev-deps', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'postgres', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nom', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rusted_cypher', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nanomsg', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'external_mixin', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustless', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'serde', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustful', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'quickcheck', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'mock-dev-deps', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'postgres', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nom', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rusted_cypher', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nanomsg', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'external_mixin', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustless', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'serde', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rustful', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'quickcheck', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'mock-dev-deps', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'postgres', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'nom', + }, + { + inviteeId: 1, + inviterId: 2, + crateId: 'rusted_cypher', + }, ]; diff --git a/mirage/route-handlers/crates.js b/mirage/route-handlers/crates.js index 99f017d3cd..ac5b1a12e1 100644 --- a/mirage/route-handlers/crates.js +++ b/mirage/route-handlers/crates.js @@ -5,7 +5,10 @@ import { compareIsoDates, compareStrings, notFound, pageParams } from './-utils' export function list(schema, request) { const { start, end } = pageParams(request); - + console.log({ + start, + end, + }); let crates = schema.crates.all(); if (request.queryParams.following === '1') { diff --git a/mirage/route-handlers/me.js b/mirage/route-handlers/me.js index 2f13002203..ff48470929 100644 --- a/mirage/route-handlers/me.js +++ b/mirage/route-handlers/me.js @@ -1,5 +1,6 @@ import { Response } from 'miragejs'; +import { pageParams } from './-utils'; import { getSession } from '../utils/session'; export function register(server) { @@ -98,13 +99,16 @@ export function register(server) { return { ok: true }; }); - server.get('/api/v1/me/crate_owner_invitations', function (schema) { + server.get('/api/v1/me/crate_owner_invitations', function (schema, request) { let { user } = getSession(schema); if (!user) { return new Response(403, {}, { errors: [{ detail: 'must be logged in to perform that action' }] }); } - return schema.crateOwnerInvitations.where({ inviteeId: user.id }); + const { start, end } = pageParams(request); + const invites = schema.crateOwnerInvitations.where({ inviteeId: user.id }); + + return { ...this.serialize(invites.slice(start, end)), meta: { total: invites.length } }; }); server.put('/api/v1/me/crate_owner_invitations/:crate_id', (schema, request) => { From cd922371ddae1e22a50c8b2dd6b43bc320c5f318 Mon Sep 17 00:00:00 2001 From: Esteban Borai Date: Fri, 2 Sep 2022 14:08:07 -0400 Subject: [PATCH 04/17] fix: remove dead code --- app/controllers/me/pending-invites.js | 18 +----------------- app/routes/me/pending-invites.js | 1 - mirage/route-handlers/crates.js | 5 +---- 3 files changed, 2 insertions(+), 22 deletions(-) diff --git a/app/controllers/me/pending-invites.js b/app/controllers/me/pending-invites.js index 8294aa2ffb..0ed61198be 100644 --- a/app/controllers/me/pending-invites.js +++ b/app/controllers/me/pending-invites.js @@ -6,25 +6,9 @@ import { reads } from 'macro-decorators'; import { pagination } from '../../utils/pagination'; export default class PendingInvitesController extends Controller { - queryParams = ['page', 'per_page', 'sort']; + queryParams = ['page']; @tracked page = '1'; - @tracked per_page = 50; - @tracked sort = 'alpha'; @reads('model.meta.total') totalItems; @pagination() pagination; - - get currentSortBy() { - if (this.sort === 'downloads') { - return 'All-Time Downloads'; - } else if (this.sort === 'recent-downloads') { - return 'Recent Downloads'; - } else if (this.sort === 'recent-updates') { - return 'Recent Updates'; - } else if (this.sort === 'new') { - return 'Newly Added'; - } else { - return 'Alphabetical'; - } - } } diff --git a/app/routes/me/pending-invites.js b/app/routes/me/pending-invites.js index a88e6ba608..a8cca5a726 100644 --- a/app/routes/me/pending-invites.js +++ b/app/routes/me/pending-invites.js @@ -7,7 +7,6 @@ export default class PendingInvitesRoute extends AuthenticatedRoute { queryParams = { page: { refreshModel: true }, - sort: { refreshModel: true }, }; model() { diff --git a/mirage/route-handlers/crates.js b/mirage/route-handlers/crates.js index ac5b1a12e1..99f017d3cd 100644 --- a/mirage/route-handlers/crates.js +++ b/mirage/route-handlers/crates.js @@ -5,10 +5,7 @@ import { compareIsoDates, compareStrings, notFound, pageParams } from './-utils' export function list(schema, request) { const { start, end } = pageParams(request); - console.log({ - start, - end, - }); + let crates = schema.crates.all(); if (request.queryParams.following === '1') { From 9855ff567372b5f1b373027adbc749a72e4d5286 Mon Sep 17 00:00:00 2001 From: Esteban Borai Date: Tue, 6 Sep 2022 00:42:40 -0400 Subject: [PATCH 05/17] feat: provide support for pagination --- app/controllers/me/pending-invites.js | 3 +- app/routes/me/pending-invites.js | 4 +- app/utils/pagination.js | 5 + mirage/fixtures/crate-owner-invitations.js | 600 --------------------- mirage/route-handlers/me.js | 6 +- 5 files changed, 14 insertions(+), 604 deletions(-) diff --git a/app/controllers/me/pending-invites.js b/app/controllers/me/pending-invites.js index 0ed61198be..c0deefeb23 100644 --- a/app/controllers/me/pending-invites.js +++ b/app/controllers/me/pending-invites.js @@ -6,8 +6,9 @@ import { reads } from 'macro-decorators'; import { pagination } from '../../utils/pagination'; export default class PendingInvitesController extends Controller { - queryParams = ['page']; + queryParams = ['page', 'per_page']; @tracked page = '1'; + @tracked per_page = 10; @reads('model.meta.total') totalItems; @pagination() pagination; diff --git a/app/routes/me/pending-invites.js b/app/routes/me/pending-invites.js index a8cca5a726..a1792ebeea 100644 --- a/app/routes/me/pending-invites.js +++ b/app/routes/me/pending-invites.js @@ -9,7 +9,7 @@ export default class PendingInvitesRoute extends AuthenticatedRoute { page: { refreshModel: true }, }; - model() { - return this.store.findAll('crate-owner-invite'); + model(params) { + return this.store.query('crate-owner-invite', params); } } diff --git a/app/utils/pagination.js b/app/utils/pagination.js index c075452853..8674192a0d 100644 --- a/app/utils/pagination.js +++ b/app/utils/pagination.js @@ -5,6 +5,11 @@ const VIEWABLE_PAGES = 9; export function pagination() { return macro(function () { let { page, per_page: perPage, totalItems } = this; + console.log({ + page, + perPage, + totalItems, + }); return _pagination(page, perPage, totalItems); }); } diff --git a/mirage/fixtures/crate-owner-invitations.js b/mirage/fixtures/crate-owner-invitations.js index 6336ff7285..faaa369ff2 100644 --- a/mirage/fixtures/crate-owner-invitations.js +++ b/mirage/fixtures/crate-owner-invitations.js @@ -1,534 +1,4 @@ export default [ - { - inviteeId: 1, - inviterId: 2, - crateId: 'nanomsg', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'external_mixin', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustless', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'serde', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustful', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'quickcheck', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'mock-dev-deps', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'postgres', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nom', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rusted_cypher', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nanomsg', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'external_mixin', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustless', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'serde', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustful', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'quickcheck', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'mock-dev-deps', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'postgres', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nom', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rusted_cypher', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nanomsg', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'external_mixin', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustless', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'serde', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustful', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'quickcheck', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'mock-dev-deps', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'postgres', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nom', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rusted_cypher', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nanomsg', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'external_mixin', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustless', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'serde', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustful', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'quickcheck', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'mock-dev-deps', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'postgres', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nom', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rusted_cypher', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nanomsg', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'external_mixin', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustless', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'serde', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustful', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'quickcheck', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'mock-dev-deps', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'postgres', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nom', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rusted_cypher', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nanomsg', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'external_mixin', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustless', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'serde', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustful', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'quickcheck', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'mock-dev-deps', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'postgres', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nom', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rusted_cypher', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nanomsg', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'external_mixin', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustless', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'serde', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustful', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'quickcheck', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'mock-dev-deps', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'postgres', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nom', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rusted_cypher', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nanomsg', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'external_mixin', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustless', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'serde', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustful', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'quickcheck', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'mock-dev-deps', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'postgres', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nom', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rusted_cypher', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nanomsg', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'external_mixin', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustless', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'serde', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustful', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'quickcheck', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'mock-dev-deps', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'postgres', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nom', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rusted_cypher', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nanomsg', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'external_mixin', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustless', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'serde', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustful', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'quickcheck', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'mock-dev-deps', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'postgres', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nom', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rusted_cypher', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nanomsg', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'external_mixin', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustless', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'serde', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustful', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'quickcheck', - }, { inviteeId: 1, inviterId: 2, @@ -554,36 +24,6 @@ export default [ inviterId: 2, crateId: 'nanomsg', }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'external_mixin', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustless', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'serde', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustful', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'quickcheck', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'mock-dev-deps', - }, { inviteeId: 1, inviterId: 2, @@ -594,11 +34,6 @@ export default [ inviterId: 2, crateId: 'nom', }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rusted_cypher', - }, { inviteeId: 1, inviterId: 2, @@ -629,31 +64,11 @@ export default [ inviterId: 2, crateId: 'quickcheck', }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'mock-dev-deps', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'postgres', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nom', - }, { inviteeId: 1, inviterId: 2, crateId: 'rusted_cypher', }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nanomsg', - }, { inviteeId: 1, inviterId: 2, @@ -684,19 +99,4 @@ export default [ inviterId: 2, crateId: 'mock-dev-deps', }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'postgres', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nom', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rusted_cypher', - }, ]; diff --git a/mirage/route-handlers/me.js b/mirage/route-handlers/me.js index ff48470929..c93af5d1df 100644 --- a/mirage/route-handlers/me.js +++ b/mirage/route-handlers/me.js @@ -108,7 +108,11 @@ export function register(server) { const { start, end } = pageParams(request); const invites = schema.crateOwnerInvitations.where({ inviteeId: user.id }); - return { ...this.serialize(invites.slice(start, end)), meta: { total: invites.length } }; + let response = this.serialize(invites.slice(start, end)); + + response.meta = { total: invites.length }; + + return response; }); server.put('/api/v1/me/crate_owner_invitations/:crate_id', (schema, request) => { From 6eb4a456c6ae77e8b70ce23b2427813cf4c5d225 Mon Sep 17 00:00:00 2001 From: Esteban Borai Date: Tue, 6 Sep 2022 00:47:23 -0400 Subject: [PATCH 06/17] fix: linting issues improvements --- app/utils/pagination.js | 5 ----- mirage/route-handlers/me.js | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/app/utils/pagination.js b/app/utils/pagination.js index 8674192a0d..c075452853 100644 --- a/app/utils/pagination.js +++ b/app/utils/pagination.js @@ -5,11 +5,6 @@ const VIEWABLE_PAGES = 9; export function pagination() { return macro(function () { let { page, per_page: perPage, totalItems } = this; - console.log({ - page, - perPage, - totalItems, - }); return _pagination(page, perPage, totalItems); }); } diff --git a/mirage/route-handlers/me.js b/mirage/route-handlers/me.js index c93af5d1df..3749a8ad55 100644 --- a/mirage/route-handlers/me.js +++ b/mirage/route-handlers/me.js @@ -1,7 +1,7 @@ import { Response } from 'miragejs'; -import { pageParams } from './-utils'; import { getSession } from '../utils/session'; +import { pageParams } from './-utils'; export function register(server) { server.get('/api/v1/me', function (schema) { From c6644936e9341c6226e6801d874fe7e571a96d66 Mon Sep 17 00:00:00 2001 From: Esteban Borai Date: Tue, 6 Sep 2022 00:54:46 -0400 Subject: [PATCH 07/17] fix: update tests to support `meta` field --- tests/mirage/me/crate-owner-invitations/list-test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/mirage/me/crate-owner-invitations/list-test.js b/tests/mirage/me/crate-owner-invitations/list-test.js index 6e4116819f..84c8f84c7c 100644 --- a/tests/mirage/me/crate-owner-invitations/list-test.js +++ b/tests/mirage/me/crate-owner-invitations/list-test.js @@ -15,7 +15,7 @@ module('Mirage | GET /api/v1/me/crate_owner_invitations', function (hooks) { let response = await fetch('/api/v1/me/crate_owner_invitations'); assert.equal(response.status, 200); - assert.deepEqual(await response.json(), { crate_owner_invitations: [] }); + assert.deepEqual(await response.json(), { crate_owner_invitations: [], meta: { total: 0 } }); }); test('returns the list of invitations for the authenticated user', async function (assert) { @@ -47,6 +47,7 @@ module('Mirage | GET /api/v1/me/crate_owner_invitations', function (hooks) { let response = await fetch('/api/v1/me/crate_owner_invitations'); assert.equal(response.status, 200); assert.deepEqual(await response.json(), { + meta: { total: 0 }, crate_owner_invitations: [ { crate_id: Number(nanomsg.id), From c99229b98ea3a49d56d29b90754c0d19a7c75273 Mon Sep 17 00:00:00 2001 From: Esteban Borai Date: Thu, 8 Sep 2022 15:32:32 -0400 Subject: [PATCH 08/17] feat: provide pagination --- src/controllers/crate_owner_invitation.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/controllers/crate_owner_invitation.rs b/src/controllers/crate_owner_invitation.rs index 35ec3642fc..ffd458650a 100644 --- a/src/controllers/crate_owner_invitation.rs +++ b/src/controllers/crate_owner_invitation.rs @@ -139,7 +139,16 @@ fn prepare_list( ) .load(&*conn)? } - Page::Numeric(_) => unreachable!("page-based pagination is disabled"), + Page::Numeric(_) => query + .pages_pagination(pagination) + .filter( + crate_owner_invitations::crate_id.gt(seek_key.0).or( + crate_owner_invitations::crate_id + .eq(seek_key.0) + .and(crate_owner_invitations::invited_user_id.gt(seek_key.1)), + ), + ) + .load(&*conn)?, }; let next_page = if raw_invitations.len() > pagination.per_page as usize { // We fetch `per_page + 1` to check if there are records for the next page. Since the last From 539fb30ea1a234348969e6045056684c3b2d71e8 Mon Sep 17 00:00:00 2001 From: Esteban Borai Date: Fri, 9 Sep 2022 18:34:39 -0400 Subject: [PATCH 09/17] fix: remove fixtures for crate owner invitations --- mirage/fixtures/crate-owner-invitations.js | 102 --------------------- 1 file changed, 102 deletions(-) delete mode 100644 mirage/fixtures/crate-owner-invitations.js diff --git a/mirage/fixtures/crate-owner-invitations.js b/mirage/fixtures/crate-owner-invitations.js deleted file mode 100644 index faaa369ff2..0000000000 --- a/mirage/fixtures/crate-owner-invitations.js +++ /dev/null @@ -1,102 +0,0 @@ -export default [ - { - inviteeId: 1, - inviterId: 2, - crateId: 'mock-dev-deps', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'postgres', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nom', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rusted_cypher', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nanomsg', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'postgres', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nom', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'nanomsg', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'external_mixin', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustless', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'serde', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustful', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'quickcheck', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rusted_cypher', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'external_mixin', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustless', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'serde', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'rustful', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'quickcheck', - }, - { - inviteeId: 1, - inviterId: 2, - crateId: 'mock-dev-deps', - }, -]; From 6a44750b405031a50545788fadde76f31cd07ffb Mon Sep 17 00:00:00 2001 From: Esteban Borai Date: Fri, 9 Sep 2022 18:45:55 -0400 Subject: [PATCH 10/17] fix: remove numeric based pagination Refer: https://github.com/rust-lang/crates.io/pull/5185#discussion_r967294899 --- src/controllers/crate_owner_invitation.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/controllers/crate_owner_invitation.rs b/src/controllers/crate_owner_invitation.rs index ffd458650a..35ec3642fc 100644 --- a/src/controllers/crate_owner_invitation.rs +++ b/src/controllers/crate_owner_invitation.rs @@ -139,16 +139,7 @@ fn prepare_list( ) .load(&*conn)? } - Page::Numeric(_) => query - .pages_pagination(pagination) - .filter( - crate_owner_invitations::crate_id.gt(seek_key.0).or( - crate_owner_invitations::crate_id - .eq(seek_key.0) - .and(crate_owner_invitations::invited_user_id.gt(seek_key.1)), - ), - ) - .load(&*conn)?, + Page::Numeric(_) => unreachable!("page-based pagination is disabled"), }; let next_page = if raw_invitations.len() > pagination.per_page as usize { // We fetch `per_page + 1` to check if there are records for the next page. Since the last From 78d249bb080dcbcbf61cefc6979056bee2053b87 Mon Sep 17 00:00:00 2001 From: Esteban Borai Date: Mon, 12 Sep 2022 22:17:38 -0300 Subject: [PATCH 11/17] feat: seek pagination support --- app/controllers/me/pending-invites.js | 7 +++---- app/utils/seek.js | 15 +++++++++++++++ src/controllers/crate_owner_invitation.rs | 12 ++++++++++-- 3 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 app/utils/seek.js diff --git a/app/controllers/me/pending-invites.js b/app/controllers/me/pending-invites.js index c0deefeb23..84fb01091f 100644 --- a/app/controllers/me/pending-invites.js +++ b/app/controllers/me/pending-invites.js @@ -3,12 +3,11 @@ import { tracked } from '@glimmer/tracking'; import { reads } from 'macro-decorators'; -import { pagination } from '../../utils/pagination'; +import { pagination } from '../../utils/seek'; export default class PendingInvitesController extends Controller { - queryParams = ['page', 'per_page']; - @tracked page = '1'; - @tracked per_page = 10; + queryParams = ['seek']; + @tracked seek = 'WzEsIDFd'; @reads('model.meta.total') totalItems; @pagination() pagination; diff --git a/app/utils/seek.js b/app/utils/seek.js new file mode 100644 index 0000000000..592c33c501 --- /dev/null +++ b/app/utils/seek.js @@ -0,0 +1,15 @@ +import macro from 'macro-decorators'; + +const VIEWABLE_PAGES = 9; + +export function pagination() { + return macro(function () { + let { page, per_page: perPage, totalItems } = this; + + return { + page, + perPage, + totalItems, + } + }); +} diff --git a/src/controllers/crate_owner_invitation.rs b/src/controllers/crate_owner_invitation.rs index 35ec3642fc..69eb3ab7c6 100644 --- a/src/controllers/crate_owner_invitation.rs +++ b/src/controllers/crate_owner_invitation.rs @@ -20,7 +20,9 @@ pub fn list(req: &mut dyn RequestExt) -> EndpointResult { let user_id = auth.user_id(); let PrivateListResponse { - invitations, users, .. + invitations, + users, + meta, } = prepare_list(req, auth, ListFilter::InviteeId(user_id))?; // The schema for the private endpoints is converted to the schema used by v1 endpoints. @@ -47,6 +49,7 @@ pub fn list(req: &mut dyn RequestExt) -> EndpointResult { Ok(req.json(&json!({ "crate_owner_invitations": crate_owner_invitations, "users": users, + "meta": meta, }))) } @@ -123,6 +126,10 @@ fn prepare_list( )) // We fetch one element over the page limit to then detect whether there is a next page. .limit(pagination.per_page as i64 + 1); + let total = crate_owner_invitations::table + .count() + .get_result(&*conn) + .unwrap(); // Load and paginate the results. let mut raw_invitations: Vec = match pagination.page { @@ -225,7 +232,7 @@ fn prepare_list( Ok(PrivateListResponse { invitations, users: users.into_iter().map(|(_, user)| user.into()).collect(), - meta: ResponseMeta { next_page }, + meta: ResponseMeta { next_page, total }, }) } @@ -239,6 +246,7 @@ struct PrivateListResponse { #[derive(Serialize)] struct ResponseMeta { next_page: Option, + total: i64, } #[derive(Deserialize)] From 80db2b49805e2ec28c2f2e24cafa58399a1ebccc Mon Sep 17 00:00:00 2001 From: Esteban Borai Date: Wed, 14 Sep 2022 16:36:56 -0300 Subject: [PATCH 12/17] feat: provide a seek pagination component --- app/components/seek-pagination.hbs | 7 +++++++ app/components/seek-pagination.module.css | 5 +++++ app/controllers/me/pending-invites.js | 8 ++------ app/routes/me/pending-invites.js | 2 +- app/templates/me/pending-invites.hbs | 2 +- app/utils/seek-pagination.js | 12 ++++++++++++ app/utils/seek.js | 15 --------------- src/controllers/crate_owner_invitation.rs | 16 +++++++--------- 8 files changed, 35 insertions(+), 32 deletions(-) create mode 100644 app/components/seek-pagination.hbs create mode 100644 app/components/seek-pagination.module.css create mode 100644 app/utils/seek-pagination.js delete mode 100644 app/utils/seek.js diff --git a/app/components/seek-pagination.hbs b/app/components/seek-pagination.hbs new file mode 100644 index 0000000000..4ae6e0a165 --- /dev/null +++ b/app/components/seek-pagination.hbs @@ -0,0 +1,7 @@ +{{#if @pagination.nextPage}} + +{{/if}} diff --git a/app/components/seek-pagination.module.css b/app/components/seek-pagination.module.css new file mode 100644 index 0000000000..76cebb05f1 --- /dev/null +++ b/app/components/seek-pagination.module.css @@ -0,0 +1,5 @@ +.seek-pagination { + text-align: center; + font-size: 90%; + margin-bottom: 20px; +} diff --git a/app/controllers/me/pending-invites.js b/app/controllers/me/pending-invites.js index 84fb01091f..19efd238c7 100644 --- a/app/controllers/me/pending-invites.js +++ b/app/controllers/me/pending-invites.js @@ -1,14 +1,10 @@ import Controller from '@ember/controller'; -import { tracked } from '@glimmer/tracking'; import { reads } from 'macro-decorators'; -import { pagination } from '../../utils/seek'; +import { pagination } from '../../utils/seek-pagination'; export default class PendingInvitesController extends Controller { - queryParams = ['seek']; - @tracked seek = 'WzEsIDFd'; - - @reads('model.meta.total') totalItems; + @reads('model.meta.next_page') nextPage; @pagination() pagination; } diff --git a/app/routes/me/pending-invites.js b/app/routes/me/pending-invites.js index a1792ebeea..1cb57350c0 100644 --- a/app/routes/me/pending-invites.js +++ b/app/routes/me/pending-invites.js @@ -6,7 +6,7 @@ export default class PendingInvitesRoute extends AuthenticatedRoute { @service store; queryParams = { - page: { refreshModel: true }, + seek: { refreshModel: true }, }; model(params) { diff --git a/app/templates/me/pending-invites.hbs b/app/templates/me/pending-invites.hbs index ec21dbdf50..b1c9c76284 100644 --- a/app/templates/me/pending-invites.hbs +++ b/app/templates/me/pending-invites.hbs @@ -10,4 +10,4 @@ {{/each}} - + diff --git a/app/utils/seek-pagination.js b/app/utils/seek-pagination.js new file mode 100644 index 0000000000..01ff59de65 --- /dev/null +++ b/app/utils/seek-pagination.js @@ -0,0 +1,12 @@ +import macro from 'macro-decorators'; + +export function pagination() { + return macro(function () { + let { nextPage, totalItems } = this; + + return { + nextPage, + totalItems, + }; + }); +} diff --git a/app/utils/seek.js b/app/utils/seek.js deleted file mode 100644 index 592c33c501..0000000000 --- a/app/utils/seek.js +++ /dev/null @@ -1,15 +0,0 @@ -import macro from 'macro-decorators'; - -const VIEWABLE_PAGES = 9; - -export function pagination() { - return macro(function () { - let { page, per_page: perPage, totalItems } = this; - - return { - page, - perPage, - totalItems, - } - }); -} diff --git a/src/controllers/crate_owner_invitation.rs b/src/controllers/crate_owner_invitation.rs index 69eb3ab7c6..1246620d76 100644 --- a/src/controllers/crate_owner_invitation.rs +++ b/src/controllers/crate_owner_invitation.rs @@ -136,6 +136,7 @@ fn prepare_list( Page::Unspecified => query.load(&*conn)?, Page::Seek(s) => { let seek_key: (i32, i32) = s.decode()?; + println!("{} {}", seek_key.0, seek_key.1); query .filter( crate_owner_invitations::crate_id.gt(seek_key.0).or( @@ -154,15 +155,12 @@ fn prepare_list( raw_invitations.pop(); if let Some(last) = raw_invitations.last() { - let mut params = IndexMap::new(); - params.insert( - "seek".into(), - crate::controllers::helpers::pagination::encode_seek(( - last.crate_id, - last.invited_user_id, - ))?, - ); - Some(req.query_with_params(params)) + let seek_key = crate::controllers::helpers::pagination::encode_seek(( + last.crate_id, + last.invited_user_id, + ))?; + + Some(seek_key) } else { None } From 18ad7b95dc3a25bc0c41be3726468982c5a6d54e Mon Sep 17 00:00:00 2001 From: Esteban Borai Date: Wed, 14 Sep 2022 16:46:32 -0300 Subject: [PATCH 13/17] fix: remove ptintln left behind --- src/controllers/crate_owner_invitation.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllers/crate_owner_invitation.rs b/src/controllers/crate_owner_invitation.rs index 1246620d76..d40f97723d 100644 --- a/src/controllers/crate_owner_invitation.rs +++ b/src/controllers/crate_owner_invitation.rs @@ -136,7 +136,6 @@ fn prepare_list( Page::Unspecified => query.load(&*conn)?, Page::Seek(s) => { let seek_key: (i32, i32) = s.decode()?; - println!("{} {}", seek_key.0, seek_key.1); query .filter( crate_owner_invitations::crate_id.gt(seek_key.0).or( From fee23658007474de4355c6d544e1a00098ac38c6 Mon Sep 17 00:00:00 2001 From: Esteban Borai Date: Wed, 14 Sep 2022 16:47:29 -0300 Subject: [PATCH 14/17] fix: remove unused `total` field --- src/controllers/crate_owner_invitation.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/controllers/crate_owner_invitation.rs b/src/controllers/crate_owner_invitation.rs index d40f97723d..2fec4b152e 100644 --- a/src/controllers/crate_owner_invitation.rs +++ b/src/controllers/crate_owner_invitation.rs @@ -126,10 +126,6 @@ fn prepare_list( )) // We fetch one element over the page limit to then detect whether there is a next page. .limit(pagination.per_page as i64 + 1); - let total = crate_owner_invitations::table - .count() - .get_result(&*conn) - .unwrap(); // Load and paginate the results. let mut raw_invitations: Vec = match pagination.page { @@ -229,7 +225,7 @@ fn prepare_list( Ok(PrivateListResponse { invitations, users: users.into_iter().map(|(_, user)| user.into()).collect(), - meta: ResponseMeta { next_page, total }, + meta: ResponseMeta { next_page }, }) } @@ -243,7 +239,6 @@ struct PrivateListResponse { #[derive(Serialize)] struct ResponseMeta { next_page: Option, - total: i64, } #[derive(Deserialize)] From eb93218fc27c6b65192143716cd9cb9821c43bb0 Mon Sep 17 00:00:00 2001 From: Esteban Borai Date: Sun, 18 Sep 2022 20:46:16 -0300 Subject: [PATCH 15/17] revert: `src/controllers/crate_owner_invitation.rs` --- src/controllers/crate_owner_invitation.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/controllers/crate_owner_invitation.rs b/src/controllers/crate_owner_invitation.rs index 2fec4b152e..35ec3642fc 100644 --- a/src/controllers/crate_owner_invitation.rs +++ b/src/controllers/crate_owner_invitation.rs @@ -20,9 +20,7 @@ pub fn list(req: &mut dyn RequestExt) -> EndpointResult { let user_id = auth.user_id(); let PrivateListResponse { - invitations, - users, - meta, + invitations, users, .. } = prepare_list(req, auth, ListFilter::InviteeId(user_id))?; // The schema for the private endpoints is converted to the schema used by v1 endpoints. @@ -49,7 +47,6 @@ pub fn list(req: &mut dyn RequestExt) -> EndpointResult { Ok(req.json(&json!({ "crate_owner_invitations": crate_owner_invitations, "users": users, - "meta": meta, }))) } @@ -150,12 +147,15 @@ fn prepare_list( raw_invitations.pop(); if let Some(last) = raw_invitations.last() { - let seek_key = crate::controllers::helpers::pagination::encode_seek(( - last.crate_id, - last.invited_user_id, - ))?; - - Some(seek_key) + let mut params = IndexMap::new(); + params.insert( + "seek".into(), + crate::controllers::helpers::pagination::encode_seek(( + last.crate_id, + last.invited_user_id, + ))?, + ); + Some(req.query_with_params(params)) } else { None } From 1b140b57194cd67011e549b2c653151299e18df4 Mon Sep 17 00:00:00 2001 From: Esteban Borai Date: Sun, 18 Sep 2022 21:12:48 -0300 Subject: [PATCH 16/17] fix: parse `seek` from meta next_page --- app/controllers/me/pending-invites.js | 2 ++ app/utils/seek-pagination.js | 6 +++--- src/controllers/crate_owner_invitation.rs | 5 ++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/controllers/me/pending-invites.js b/app/controllers/me/pending-invites.js index 19efd238c7..4c104ab8ec 100644 --- a/app/controllers/me/pending-invites.js +++ b/app/controllers/me/pending-invites.js @@ -5,6 +5,8 @@ import { reads } from 'macro-decorators'; import { pagination } from '../../utils/seek-pagination'; export default class PendingInvitesController extends Controller { + queryParams = ['page', 'per_page', 'sort']; + @reads('model.meta.next_page') nextPage; @pagination() pagination; } diff --git a/app/utils/seek-pagination.js b/app/utils/seek-pagination.js index 01ff59de65..23423dcccb 100644 --- a/app/utils/seek-pagination.js +++ b/app/utils/seek-pagination.js @@ -2,11 +2,11 @@ import macro from 'macro-decorators'; export function pagination() { return macro(function () { - let { nextPage, totalItems } = this; + const { nextPage } = this; + const nextPageParams = new URLSearchParams(nextPage); return { - nextPage, - totalItems, + nextPage: nextPageParams.get('seek'), }; }); } diff --git a/src/controllers/crate_owner_invitation.rs b/src/controllers/crate_owner_invitation.rs index 35ec3642fc..b2d7c93a74 100644 --- a/src/controllers/crate_owner_invitation.rs +++ b/src/controllers/crate_owner_invitation.rs @@ -20,7 +20,9 @@ pub fn list(req: &mut dyn RequestExt) -> EndpointResult { let user_id = auth.user_id(); let PrivateListResponse { - invitations, users, .. + invitations, + users, + meta, } = prepare_list(req, auth, ListFilter::InviteeId(user_id))?; // The schema for the private endpoints is converted to the schema used by v1 endpoints. @@ -47,6 +49,7 @@ pub fn list(req: &mut dyn RequestExt) -> EndpointResult { Ok(req.json(&json!({ "crate_owner_invitations": crate_owner_invitations, "users": users, + "meta": meta, }))) } From 11fafa7cd58ce5d2754e7200e3283a42b0e3372c Mon Sep 17 00:00:00 2001 From: Esteban Borai Date: Sun, 18 Sep 2022 21:14:23 -0300 Subject: [PATCH 17/17] fix: remove unused `queryParams` --- app/controllers/me/pending-invites.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/controllers/me/pending-invites.js b/app/controllers/me/pending-invites.js index 4c104ab8ec..19efd238c7 100644 --- a/app/controllers/me/pending-invites.js +++ b/app/controllers/me/pending-invites.js @@ -5,8 +5,6 @@ import { reads } from 'macro-decorators'; import { pagination } from '../../utils/seek-pagination'; export default class PendingInvitesController extends Controller { - queryParams = ['page', 'per_page', 'sort']; - @reads('model.meta.next_page') nextPage; @pagination() pagination; }