Skip to content

Commit

Permalink
feat(cargo-shuttle): adaptive page hints
Browse files Browse the repository at this point in the history
  • Loading branch information
x04 committed Oct 14, 2023
1 parent 7ef6395 commit 25b382d
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 42 deletions.
4 changes: 2 additions & 2 deletions cargo-shuttle/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ impl Client {
self.get(path).await
}

pub async fn get_projects_list(&self, page: u32, limit: u32) -> Result<Vec<project::Response>> {
pub async fn get_projects_list(&self, page: u32, limit: u32) -> Result<project::Page> {
let path = format!("/projects?page={}&limit={}", page.saturating_sub(1), limit);

self.get(path).await
Expand Down Expand Up @@ -233,7 +233,7 @@ impl Client {
project: &ProjectName,
page: u32,
limit: u32,
) -> Result<Vec<deployment::Response>> {
) -> Result<deployment::Page> {
let path = format!(
"/projects/{}/deployments?page={}&limit={}",
project.as_str(),
Expand Down
2 changes: 1 addition & 1 deletion cargo-shuttle/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,7 @@ impl Shuttle {
"Fetching the latest deployment failed",
)
})?;
let most_recent = deployments.first().context(format!(
let most_recent = deployments.data.first().context(format!(
"Could not find any deployments for '{proj_name}'. Try passing a deployment ID manually",
))?;

Expand Down
39 changes: 25 additions & 14 deletions common/src/models/deployment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ pub const GIT_STRINGS_MAX_LENGTH: usize = 80;
pub const CREATE_SERVICE_BODY_LIMIT: usize = 50_000_000;
const GIT_OPTION_NONE_TEXT: &str = "N/A";

#[derive(Deserialize, Serialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[cfg_attr(feature = "openapi", schema(as = shuttle_common::models::deployment::Page))]
pub struct Page {
pub data: Vec<Response>,
pub has_next_page: bool,
}

#[derive(Deserialize, Serialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[cfg_attr(feature = "openapi", schema(as = shuttle_common::models::deployment::Response))]
Expand Down Expand Up @@ -67,9 +75,9 @@ impl State {
}
}

pub fn get_deployments_table(deployments: &Vec<Response>, service_name: &str, page: u32) -> String {
if deployments.is_empty() {
if page <= 1 {
pub fn get_deployments_table(page: &Page, service_name: &str, page_num: u32) -> String {
if page.data.is_empty() {
if page_num <= 1 {
format!(
"{}\n",
"No deployments are linked to this service".yellow().bold()
Expand Down Expand Up @@ -110,7 +118,7 @@ pub fn get_deployments_table(deployments: &Vec<Response>, service_name: &str, pa
.add_attribute(Attribute::Bold),
]);

for deploy in deployments.iter() {
for deploy in page.data.iter() {
let truncated_commit_id = deploy
.git_commit_id
.as_ref()
Expand Down Expand Up @@ -150,18 +158,21 @@ pub fn get_deployments_table(deployments: &Vec<Response>, service_name: &str, pa
]);
}

format!(
r#"
Most recent {} for {}
{}
{}
"#,
let formatted_table = format!(
"Most recent {} for {}\n{}\n\n",
"deployments".bold(),
service_name,
table,
"More projects might be available on the next page using --page.".bold()
)
table
);

if page.has_next_page {
format!(
"{formatted_table}{notice}",
notice = "More deployments available on the next page using --page.".bold()
)
} else {
formatted_table
}
}
}

Expand Down
34 changes: 21 additions & 13 deletions common/src/models/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ pub const fn default_idle_minutes() -> u64 {
DEFAULT_IDLE_MINUTES
}

#[derive(Deserialize, Serialize, Clone)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[cfg_attr(feature = "openapi", schema(as = shuttle_common::models::project::Page))]
pub struct Page {
pub data: Vec<Response>,
pub has_next_page: bool,
}

#[derive(Deserialize, Serialize, Clone)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[cfg_attr(feature = "openapi", schema(as = shuttle_common::models::project::Response))]
Expand Down Expand Up @@ -190,10 +198,10 @@ pub struct AdminResponse {
pub account_name: String,
}

pub fn get_table(projects: &Vec<Response>, page: u32) -> String {
if projects.is_empty() {
pub fn get_table(page: &Page, page_num: u32) -> String {
if page.data.is_empty() {
// The page starts at 1 in the CLI.
if page <= 1 {
if page_num <= 1 {
format!(
"{}\n",
"No projects are linked to this account".yellow().bold()
Expand All @@ -215,7 +223,7 @@ pub fn get_table(projects: &Vec<Response>, page: u32) -> String {
Cell::new("Status").set_alignment(CellAlignment::Center),
]);

for project in projects.iter() {
for project in page.data.iter() {
table.add_row(vec![
Cell::new(&project.name),
Cell::new(&project.state)
Expand All @@ -224,14 +232,14 @@ pub fn get_table(projects: &Vec<Response>, page: u32) -> String {
]);
}

format!(
r#"
These projects are linked to this account
{table}
{}
"#,
"More projects might be available on the next page using --page.".bold()
)
let formatted_table = format!("These projects are linked to this account\n{table}");
if page.has_next_page {
format!(
"{formatted_table}\n\n{notice}",
notice = "More projects available on the next page using --page.".bold()
)
} else {
formatted_table
}
}
}
29 changes: 21 additions & 8 deletions deployer/src/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ use utoipa::{IntoParams, OpenApi};
use utoipa_swagger_ui::SwaggerUi;
use uuid::Uuid;

use shuttle_common::backends::{
auth::{AdminSecretLayer, ScopedLayer},
headers::XShuttleAccountName,
};
use shuttle_common::backends::{
auth::{AuthPublicKey, JwtAuthenticationLayer},
metrics::{Metrics, TraceLayer},
Expand All @@ -37,6 +33,13 @@ use shuttle_common::models::deployment::{
};
use shuttle_common::models::secret;
use shuttle_common::project::ProjectName;
use shuttle_common::{
backends::{
auth::{AdminSecretLayer, ScopedLayer},
headers::XShuttleAccountName,
},
models::deployment,
};
use shuttle_common::{request_span, LogItem};
use shuttle_proto::logger::LogsRequest;
use shuttle_service::builder::clean_crate;
Expand Down Expand Up @@ -525,18 +528,28 @@ pub async fn get_deployments(
Extension(persistence): Extension<Persistence>,
Path(project_name): Path<String>,
Query(PaginationDetails { page, limit }): Query<PaginationDetails>,
) -> Result<Json<Vec<shuttle_common::models::deployment::Response>>> {
) -> Result<Json<deployment::Page>> {
if let Some(service) = persistence.get_service_by_name(&project_name).await? {
let limit = limit.unwrap_or(u32::MAX);
let limit = limit.unwrap_or(u32::MAX - 1) + 1;
let page = page.unwrap_or(0);
let deployments = persistence
let mut deployments: Vec<deployment::Response> = persistence
.get_deployments(&service.id, page * limit, limit)
.await?
.into_iter()
.map(Into::into)
.collect();

Ok(Json(deployments))
let has_next_page = deployments.len() == limit as usize;
if has_next_page {
deployments.pop();
}

let page = deployment::Page {
data: deployments,
has_next_page,
};

Ok(Json(page))
} else {
Err(Error::NotFound("service not found".to_string()))
}
Expand Down
18 changes: 14 additions & 4 deletions gateway/src/api/latest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,10 @@ async fn get_projects_list(
State(RouterState { service, .. }): State<RouterState>,
User { name, .. }: User,
Query(PaginationDetails { page, limit }): Query<PaginationDetails>,
) -> Result<AxumJson<Vec<project::Response>>, Error> {
let limit = limit.unwrap_or(u32::MAX);
) -> Result<AxumJson<project::Page>, Error> {
let limit = limit.unwrap_or(u32::MAX - 1) + 1;
let page = page.unwrap_or(0);
let projects = service
let mut projects: Vec<project::Response> = service
// The `offset` is page size * amount of pages
.iter_user_projects_detailed(&name, limit * page, limit)
.await?
Expand All @@ -179,7 +179,17 @@ async fn get_projects_list(
})
.collect();

Ok(AxumJson(projects))
let has_next_page = projects.len() == limit as usize;
if has_next_page {
projects.pop();
}

let page = project::Page {
data: projects,
has_next_page,
};

Ok(AxumJson(page))
}

#[instrument(skip_all, fields(%project_name))]
Expand Down

0 comments on commit 25b382d

Please sign in to comment.