fix: Show project documents in workspace #26
@@ -1,299 +1,329 @@
|
||||
use cynic::{MutationBuilder, QueryBuilder};
|
||||
|
||||
use crate::graphql::collab_schema as schema;
|
||||
use crate::graphql::typed_collab_graphql;
|
||||
|
||||
#[derive(Clone, cynic::Enum, PartialEq, Eq)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub enum OwnerKind {
|
||||
User,
|
||||
Organization,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::Enum, PartialEq, Eq)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub enum RepositoryRole {
|
||||
Source,
|
||||
Infra,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::Enum, PartialEq, Eq)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub enum ProjectKind {
|
||||
Continuous,
|
||||
Finite,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::Enum, PartialEq, Eq)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub enum IssuePriority {
|
||||
None,
|
||||
Low,
|
||||
Normal,
|
||||
High,
|
||||
Urgent,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::QueryFragment)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub struct Workspace {
|
||||
pub id: cynic::Id,
|
||||
pub name: String,
|
||||
pub slug: String,
|
||||
pub default_environment: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::QueryFragment)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub struct CheckoutRepository {
|
||||
pub owner: String,
|
||||
pub name: String,
|
||||
pub role: RepositoryRole,
|
||||
pub branch: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::QueryFragment)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub struct Checkout {
|
||||
pub repositories: Vec<CheckoutRepository>,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::QueryFragment)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub struct Environment {
|
||||
pub name: String,
|
||||
pub default_source_branch: String,
|
||||
pub infra_branch: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::QueryFragment)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub struct Project {
|
||||
pub id: cynic::Id,
|
||||
pub key: String,
|
||||
pub name: String,
|
||||
pub slug: String,
|
||||
pub description: String,
|
||||
pub lifecycle: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::QueryFragment)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub struct Document {
|
||||
pub path: String,
|
||||
pub revision_id: cynic::Id,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::QueryFragment)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub struct Issue {
|
||||
pub number: i32,
|
||||
pub title: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::QueryFragment)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub struct Version {
|
||||
pub name: String,
|
||||
pub slug: String,
|
||||
pub state: String,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment)]
|
||||
#[cynic(schema_path = "collab-schema.graphql", graphql_type = "Query")]
|
||||
struct WorkspacesResponse {
|
||||
workspaces: Vec<Workspace>,
|
||||
}
|
||||
|
||||
pub async fn workspaces() -> Result<Vec<Workspace>, String> {
|
||||
let response: WorkspacesResponse = typed_collab_graphql(QueryBuilder::build(())).await?;
|
||||
Ok(response.workspaces)
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryVariables)]
|
||||
struct WorkspaceVariables {
|
||||
id: cynic::Id,
|
||||
workspace_id: cynic::Id,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment)]
|
||||
#[cynic(
|
||||
schema_path = "collab-schema.graphql",
|
||||
graphql_type = "Query",
|
||||
variables = "WorkspaceVariables"
|
||||
)]
|
||||
struct WorkspaceResponse {
|
||||
#[arguments(id: $id)]
|
||||
workspace: Workspace,
|
||||
#[arguments(workspaceId: $workspace_id)]
|
||||
checkout: Checkout,
|
||||
#[arguments(workspaceId: $workspace_id)]
|
||||
environments: Vec<Environment>,
|
||||
#[arguments(workspaceId: $workspace_id)]
|
||||
projects: Vec<Project>,
|
||||
#[arguments(workspaceId: $workspace_id)]
|
||||
documents: Vec<Document>,
|
||||
}
|
||||
|
||||
pub async fn workspace(
|
||||
id: cynic::Id,
|
||||
) -> Result<
|
||||
(
|
||||
Workspace,
|
||||
Vec<CheckoutRepository>,
|
||||
Vec<Environment>,
|
||||
Vec<Project>,
|
||||
Vec<Document>,
|
||||
),
|
||||
String,
|
||||
> {
|
||||
let response: WorkspaceResponse =
|
||||
typed_collab_graphql(QueryBuilder::build(WorkspaceVariables {
|
||||
id: id.clone(),
|
||||
workspace_id: id,
|
||||
}))
|
||||
.await?;
|
||||
Ok((
|
||||
response.workspace,
|
||||
response.checkout.repositories,
|
||||
response.environments,
|
||||
response.projects,
|
||||
response.documents,
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryVariables)]
|
||||
struct IssuesVariables {
|
||||
project_id: cynic::Id,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment)]
|
||||
#[cynic(
|
||||
schema_path = "collab-schema.graphql",
|
||||
graphql_type = "Query",
|
||||
variables = "IssuesVariables"
|
||||
)]
|
||||
struct IssuesResponse {
|
||||
#[arguments(projectId: $project_id)]
|
||||
issues: Vec<Issue>,
|
||||
}
|
||||
|
||||
pub async fn issues(project_id: cynic::Id) -> Result<Vec<Issue>, String> {
|
||||
let response: IssuesResponse =
|
||||
typed_collab_graphql(QueryBuilder::build(IssuesVariables { project_id })).await?;
|
||||
Ok(response.issues)
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryVariables)]
|
||||
struct VersionsVariables {
|
||||
project_id: cynic::Id,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment)]
|
||||
#[cynic(
|
||||
schema_path = "collab-schema.graphql",
|
||||
graphql_type = "Query",
|
||||
variables = "VersionsVariables"
|
||||
)]
|
||||
struct VersionsResponse {
|
||||
#[arguments(projectId: $project_id)]
|
||||
versions: Vec<Version>,
|
||||
}
|
||||
|
||||
pub async fn versions(project_id: cynic::Id) -> Result<Vec<Version>, String> {
|
||||
let response: VersionsResponse =
|
||||
typed_collab_graphql(QueryBuilder::build(VersionsVariables { project_id })).await?;
|
||||
Ok(response.versions)
|
||||
}
|
||||
|
||||
#[derive(cynic::InputObject)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
struct CreateWorkspaceInput {
|
||||
owner_kind: OwnerKind,
|
||||
owner_id: cynic::Id,
|
||||
name: String,
|
||||
slug: String,
|
||||
default_environment: String,
|
||||
default_source_branch: String,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryVariables)]
|
||||
struct CreateWorkspaceVariables {
|
||||
input: CreateWorkspaceInput,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment)]
|
||||
#[cynic(
|
||||
schema_path = "collab-schema.graphql",
|
||||
graphql_type = "Mutation",
|
||||
variables = "CreateWorkspaceVariables"
|
||||
)]
|
||||
struct CreateWorkspaceResponse {
|
||||
#[arguments(input: $input)]
|
||||
create_workspace: Workspace,
|
||||
}
|
||||
|
||||
pub async fn create_workspace(owner_id: &str, name: &str, slug: &str) -> Result<Workspace, String> {
|
||||
let response: CreateWorkspaceResponse =
|
||||
typed_collab_graphql(MutationBuilder::build(CreateWorkspaceVariables {
|
||||
input: CreateWorkspaceInput {
|
||||
owner_kind: OwnerKind::User,
|
||||
owner_id: cynic::Id::new(owner_id),
|
||||
name: name.to_owned(),
|
||||
slug: slug.to_owned(),
|
||||
default_environment: "development".to_owned(),
|
||||
default_source_branch: "main".to_owned(),
|
||||
},
|
||||
}))
|
||||
.await?;
|
||||
Ok(response.create_workspace)
|
||||
}
|
||||
|
||||
#[derive(cynic::InputObject)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
struct CreateProjectInput {
|
||||
workspace_id: cynic::Id,
|
||||
key: String,
|
||||
name: String,
|
||||
slug: String,
|
||||
description: String,
|
||||
kind: ProjectKind,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryVariables)]
|
||||
struct CreateProjectVariables {
|
||||
input: CreateProjectInput,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment)]
|
||||
#[cynic(
|
||||
schema_path = "collab-schema.graphql",
|
||||
graphql_type = "Mutation",
|
||||
variables = "CreateProjectVariables"
|
||||
)]
|
||||
struct CreateProjectResponse {
|
||||
#[arguments(input: $input)]
|
||||
create_project: Project,
|
||||
}
|
||||
|
||||
pub async fn create_project(
|
||||
workspace_id: &str,
|
||||
key: &str,
|
||||
name: &str,
|
||||
slug: &str,
|
||||
) -> Result<Project, String> {
|
||||
let response: CreateProjectResponse =
|
||||
typed_collab_graphql(MutationBuilder::build(CreateProjectVariables {
|
||||
input: CreateProjectInput {
|
||||
workspace_id: cynic::Id::new(workspace_id),
|
||||
key: key.to_owned(),
|
||||
name: name.to_owned(),
|
||||
slug: slug.to_owned(),
|
||||
description: String::new(),
|
||||
kind: ProjectKind::Continuous,
|
||||
},
|
||||
}))
|
||||
.await?;
|
||||
Ok(response.create_project)
|
||||
}
|
||||
use cynic::{MutationBuilder, QueryBuilder};
|
||||
|
||||
use crate::graphql::collab_schema as schema;
|
||||
use crate::graphql::typed_collab_graphql;
|
||||
|
||||
#[derive(Clone, cynic::Enum, PartialEq, Eq)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub enum OwnerKind {
|
||||
User,
|
||||
Organization,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::Enum, PartialEq, Eq)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub enum RepositoryRole {
|
||||
Source,
|
||||
Infra,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::Enum, PartialEq, Eq)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub enum ProjectKind {
|
||||
Continuous,
|
||||
Finite,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::Enum, PartialEq, Eq)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub enum IssuePriority {
|
||||
None,
|
||||
Low,
|
||||
Normal,
|
||||
High,
|
||||
Urgent,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::QueryFragment)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub struct Workspace {
|
||||
pub id: cynic::Id,
|
||||
pub name: String,
|
||||
pub slug: String,
|
||||
pub default_environment: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::QueryFragment)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub struct CheckoutRepository {
|
||||
pub owner: String,
|
||||
pub name: String,
|
||||
pub role: RepositoryRole,
|
||||
pub branch: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::QueryFragment)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub struct Checkout {
|
||||
pub repositories: Vec<CheckoutRepository>,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::QueryFragment)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub struct Environment {
|
||||
pub name: String,
|
||||
pub default_source_branch: String,
|
||||
pub infra_branch: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::QueryFragment)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub struct Project {
|
||||
pub id: cynic::Id,
|
||||
pub key: String,
|
||||
pub name: String,
|
||||
pub slug: String,
|
||||
pub description: String,
|
||||
pub lifecycle: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::QueryFragment)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub struct Document {
|
||||
pub path: String,
|
||||
pub revision_id: cynic::Id,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::QueryFragment)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub struct Issue {
|
||||
pub number: i32,
|
||||
pub title: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, cynic::QueryFragment)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
pub struct Version {
|
||||
pub name: String,
|
||||
pub slug: String,
|
||||
pub state: String,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment)]
|
||||
#[cynic(schema_path = "collab-schema.graphql", graphql_type = "Query")]
|
||||
struct WorkspacesResponse {
|
||||
workspaces: Vec<Workspace>,
|
||||
}
|
||||
|
||||
pub async fn workspaces() -> Result<Vec<Workspace>, String> {
|
||||
let response: WorkspacesResponse = typed_collab_graphql(QueryBuilder::build(())).await?;
|
||||
Ok(response.workspaces)
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryVariables)]
|
||||
struct WorkspaceVariables {
|
||||
id: cynic::Id,
|
||||
workspace_id: cynic::Id,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment)]
|
||||
#[cynic(
|
||||
schema_path = "collab-schema.graphql",
|
||||
graphql_type = "Query",
|
||||
variables = "WorkspaceVariables"
|
||||
)]
|
||||
struct WorkspaceResponse {
|
||||
#[arguments(id: $id)]
|
||||
workspace: Workspace,
|
||||
#[arguments(workspaceId: $workspace_id)]
|
||||
checkout: Checkout,
|
||||
#[arguments(workspaceId: $workspace_id)]
|
||||
environments: Vec<Environment>,
|
||||
#[arguments(workspaceId: $workspace_id)]
|
||||
projects: Vec<Project>,
|
||||
#[arguments(workspaceId: $workspace_id)]
|
||||
documents: Vec<Document>,
|
||||
}
|
||||
|
||||
pub async fn workspace(
|
||||
id: cynic::Id,
|
||||
) -> Result<
|
||||
(
|
||||
Workspace,
|
||||
Vec<CheckoutRepository>,
|
||||
Vec<Environment>,
|
||||
Vec<Project>,
|
||||
Vec<Document>,
|
||||
),
|
||||
String,
|
||||
> {
|
||||
let response: WorkspaceResponse =
|
||||
typed_collab_graphql(QueryBuilder::build(WorkspaceVariables {
|
||||
id: id.clone(),
|
||||
workspace_id: id,
|
||||
}))
|
||||
.await?;
|
||||
Ok((
|
||||
response.workspace,
|
||||
response.checkout.repositories,
|
||||
response.environments,
|
||||
response.projects,
|
||||
response.documents,
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryVariables)]
|
||||
struct DocumentsVariables {
|
||||
workspace_id: cynic::Id,
|
||||
project_id: Option<cynic::Id>,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment)]
|
||||
#[cynic(
|
||||
schema_path = "collab-schema.graphql",
|
||||
graphql_type = "Query",
|
||||
variables = "DocumentsVariables"
|
||||
)]
|
||||
struct DocumentsResponse {
|
||||
#[arguments(workspaceId: $workspace_id, projectId: $project_id)]
|
||||
documents: Vec<Document>,
|
||||
}
|
||||
|
||||
pub async fn project_documents(
|
||||
workspace_id: cynic::Id,
|
||||
project_id: cynic::Id,
|
||||
) -> Result<Vec<Document>, String> {
|
||||
let response: DocumentsResponse =
|
||||
typed_collab_graphql(QueryBuilder::build(DocumentsVariables {
|
||||
workspace_id,
|
||||
project_id: Some(project_id),
|
||||
}))
|
||||
.await?;
|
||||
Ok(response.documents)
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryVariables)]
|
||||
struct IssuesVariables {
|
||||
project_id: cynic::Id,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment)]
|
||||
#[cynic(
|
||||
schema_path = "collab-schema.graphql",
|
||||
graphql_type = "Query",
|
||||
variables = "IssuesVariables"
|
||||
)]
|
||||
struct IssuesResponse {
|
||||
#[arguments(projectId: $project_id)]
|
||||
issues: Vec<Issue>,
|
||||
}
|
||||
|
||||
pub async fn issues(project_id: cynic::Id) -> Result<Vec<Issue>, String> {
|
||||
let response: IssuesResponse =
|
||||
typed_collab_graphql(QueryBuilder::build(IssuesVariables { project_id })).await?;
|
||||
Ok(response.issues)
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryVariables)]
|
||||
struct VersionsVariables {
|
||||
project_id: cynic::Id,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment)]
|
||||
#[cynic(
|
||||
schema_path = "collab-schema.graphql",
|
||||
graphql_type = "Query",
|
||||
variables = "VersionsVariables"
|
||||
)]
|
||||
struct VersionsResponse {
|
||||
#[arguments(projectId: $project_id)]
|
||||
versions: Vec<Version>,
|
||||
}
|
||||
|
||||
pub async fn versions(project_id: cynic::Id) -> Result<Vec<Version>, String> {
|
||||
let response: VersionsResponse =
|
||||
typed_collab_graphql(QueryBuilder::build(VersionsVariables { project_id })).await?;
|
||||
Ok(response.versions)
|
||||
}
|
||||
|
||||
#[derive(cynic::InputObject)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
struct CreateWorkspaceInput {
|
||||
owner_kind: OwnerKind,
|
||||
owner_id: cynic::Id,
|
||||
name: String,
|
||||
slug: String,
|
||||
default_environment: String,
|
||||
default_source_branch: String,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryVariables)]
|
||||
struct CreateWorkspaceVariables {
|
||||
input: CreateWorkspaceInput,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment)]
|
||||
#[cynic(
|
||||
schema_path = "collab-schema.graphql",
|
||||
graphql_type = "Mutation",
|
||||
variables = "CreateWorkspaceVariables"
|
||||
)]
|
||||
struct CreateWorkspaceResponse {
|
||||
#[arguments(input: $input)]
|
||||
create_workspace: Workspace,
|
||||
}
|
||||
|
||||
pub async fn create_workspace(owner_id: &str, name: &str, slug: &str) -> Result<Workspace, String> {
|
||||
let response: CreateWorkspaceResponse =
|
||||
typed_collab_graphql(MutationBuilder::build(CreateWorkspaceVariables {
|
||||
input: CreateWorkspaceInput {
|
||||
owner_kind: OwnerKind::User,
|
||||
owner_id: cynic::Id::new(owner_id),
|
||||
name: name.to_owned(),
|
||||
slug: slug.to_owned(),
|
||||
default_environment: "development".to_owned(),
|
||||
default_source_branch: "main".to_owned(),
|
||||
},
|
||||
}))
|
||||
.await?;
|
||||
Ok(response.create_workspace)
|
||||
}
|
||||
|
||||
#[derive(cynic::InputObject)]
|
||||
#[cynic(schema_path = "collab-schema.graphql")]
|
||||
struct CreateProjectInput {
|
||||
workspace_id: cynic::Id,
|
||||
key: String,
|
||||
name: String,
|
||||
slug: String,
|
||||
description: String,
|
||||
kind: ProjectKind,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryVariables)]
|
||||
struct CreateProjectVariables {
|
||||
input: CreateProjectInput,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment)]
|
||||
#[cynic(
|
||||
schema_path = "collab-schema.graphql",
|
||||
graphql_type = "Mutation",
|
||||
variables = "CreateProjectVariables"
|
||||
)]
|
||||
struct CreateProjectResponse {
|
||||
#[arguments(input: $input)]
|
||||
create_project: Project,
|
||||
}
|
||||
|
||||
pub async fn create_project(
|
||||
workspace_id: &str,
|
||||
key: &str,
|
||||
name: &str,
|
||||
slug: &str,
|
||||
) -> Result<Project, String> {
|
||||
let response: CreateProjectResponse =
|
||||
typed_collab_graphql(MutationBuilder::build(CreateProjectVariables {
|
||||
input: CreateProjectInput {
|
||||
workspace_id: cynic::Id::new(workspace_id),
|
||||
key: key.to_owned(),
|
||||
name: name.to_owned(),
|
||||
slug: slug.to_owned(),
|
||||
description: String::new(),
|
||||
kind: ProjectKind::Continuous,
|
||||
},
|
||||
}))
|
||||
.await?;
|
||||
Ok(response.create_project)
|
||||
}
|
||||
+28
-6
@@ -1,105 +1,127 @@
|
||||
use leptos::prelude::*;
|
||||
use leptos_router::components::A;
|
||||
use leptos_router::hooks::use_params_map;
|
||||
|
||||
use crate::collab::{issues, versions, workspace, Issue, Project, Version};
|
||||
use crate::components::nav::Nav;
|
||||
|
||||
use super::workspace_forms::{
|
||||
AttachRepositoryForm, DocumentForm, EnvironmentForm, IssueForm, ProjectForm, VersionForm,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
struct WorkspaceData {
|
||||
workspace: crate::collab::Workspace,
|
||||
repositories: Vec<crate::collab::CheckoutRepository>,
|
||||
environments: Vec<crate::collab::Environment>,
|
||||
projects: Vec<(Project, Vec<Issue>, Vec<Version>)>,
|
||||
documents: Vec<crate::collab::Document>,
|
||||
}
|
||||
|
||||
async fn load_workspace(id: &str) -> Result<WorkspaceData, String> {
|
||||
let (workspace, repositories, environments, projects, documents) =
|
||||
workspace(cynic::Id::new(id)).await?;
|
||||
let mut projects_with_issues = Vec::with_capacity(projects.len());
|
||||
for project in projects {
|
||||
let project_issues = issues(project.id.clone()).await?;
|
||||
let project_versions = versions(project.id.clone()).await?;
|
||||
projects_with_issues.push((project, project_issues, project_versions));
|
||||
}
|
||||
Ok(WorkspaceData {
|
||||
workspace,
|
||||
repositories,
|
||||
environments,
|
||||
projects: projects_with_issues,
|
||||
documents,
|
||||
})
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn WorkspacePage() -> impl IntoView {
|
||||
let params = use_params_map();
|
||||
let refresh = RwSignal::new(0_u64);
|
||||
let data = LocalResource::new(move || {
|
||||
refresh.get();
|
||||
let id = params.read().get("id").unwrap_or_default();
|
||||
async move { load_workspace(&id).await }
|
||||
});
|
||||
|
||||
view! {
|
||||
<div class="flex min-h-screen flex-col bg-paper text-ink">
|
||||
<Nav>
|
||||
<A href="/workspaces" attr:class="text-sm font-medium hover:text-primary">"Workspaces"</A>
|
||||
<A href="/account" attr:class="text-sm font-medium hover:text-primary">"Account"</A>
|
||||
</Nav>
|
||||
<main class="mx-auto w-full max-w-6xl flex-1 px-6 py-12">
|
||||
<Suspense fallback=|| view! { <p class="text-ink/60">"Loading workspace…"</p> }>
|
||||
{move || data.get().map(|result| match &*result {
|
||||
Ok(data) => {
|
||||
let workspace = data.workspace.clone();
|
||||
let workspace_id = workspace.id.inner().to_owned();
|
||||
let projects = data.projects.clone();
|
||||
let documents = data.documents.clone();
|
||||
let repositories = data.repositories.clone();
|
||||
let environments = data.environments.clone();
|
||||
view! {
|
||||
<header class="flex flex-wrap items-end justify-between gap-4 border-b border-ink/10 pb-8">
|
||||
<div><p class="font-mono text-sm text-ink/50">{workspace.slug}</p><h1 class="mt-1 text-3xl font-semibold">{workspace.name}</h1></div>
|
||||
<span class="rounded-full bg-tertiary/20 px-3 py-1 text-xs font-medium">{workspace.default_environment}</span>
|
||||
</header>
|
||||
<div class="mt-8 grid gap-8 lg:grid-cols-[1fr_22rem]">
|
||||
<div class="space-y-10">
|
||||
<section>
|
||||
<div class="flex items-center justify-between"><h2 class="text-xl font-semibold">"Projects"</h2><span class="text-sm text-ink/50">{projects.len()}</span></div>
|
||||
<ul class="mt-4 space-y-4">{projects.clone().into_iter().map(|(project, issues, versions)| view! {
|
||||
<li class="rounded-xl border border-ink/10 bg-white p-5">
|
||||
<div class="flex items-center justify-between gap-4"><div><h3 class="font-semibold">{format!("{} · {}", project.key, project.name)}</h3><p class="mt-1 text-sm text-ink/55">{project.description}</p><p class="mt-1 font-mono text-xs text-ink/40">{project.slug}</p></div><span class="text-xs uppercase text-ink/45">{project.lifecycle}</span></div>
|
||||
<ul class="mt-4 divide-y divide-ink/10 border-t border-ink/10">{issues.into_iter().map(|issue| view! { <li class="flex items-center gap-3 py-3 text-sm"><span class="font-mono text-ink/45">{format!("#{}", issue.number)}</span><span>{issue.title}</span></li> }).collect_view()}</ul>
|
||||
<IssueForm project_id=project.id.inner().to_owned() refresh=refresh/>
|
||||
<div class="mt-5 border-t border-ink/10 pt-4"><h4 class="text-xs font-semibold uppercase tracking-wide text-ink/45">"Versions"</h4><ul class="mt-2 flex flex-wrap gap-2">{versions.into_iter().map(|version| view! { <li class="rounded-full bg-ink/5 px-3 py-1 text-xs">{format!("{} ({}) · {}", version.name, version.slug, version.state)}</li> }).collect_view()}</ul><VersionForm project_id=project.id.inner().to_owned() refresh=refresh/></div>
|
||||
</li>
|
||||
}).collect_view()}</ul>
|
||||
</section>
|
||||
<section>
|
||||
<div class="flex items-center justify-between"><h2 class="text-xl font-semibold">"Docs"</h2><span class="text-sm text-ink/50">{documents.len()}</span></div>
|
||||
<ul class="mt-4 space-y-3">{documents.into_iter().map(|document| view! { <li class="rounded-xl border border-ink/10 bg-white p-5"><div class="flex items-center justify-between gap-4"><p class="font-mono text-sm font-semibold">{document.path}</p><span class="font-mono text-xs text-ink/35">{document.revision_id.inner().to_owned()}</span></div><pre class="mt-3 whitespace-pre-wrap text-sm text-ink/70">{document.content}</pre></li> }).collect_view()}</ul>
|
||||
</section>
|
||||
</div>
|
||||
<aside class="space-y-5">
|
||||
<section class="rounded-xl border border-ink/10 bg-white p-5"><div class="flex items-center justify-between"><h2 class="font-semibold">"Environments"</h2><span class="text-sm text-ink/50">{environments.len()}</span></div><ul class="mt-3 space-y-2">{environments.into_iter().map(|environment| view! { <li class="rounded border border-ink/10 px-3 py-2 text-sm"><p class="font-medium">{environment.name}</p><p class="mt-1 font-mono text-xs text-ink/45">{format!("source: {} · infra: {}", environment.default_source_branch, environment.infra_branch.unwrap_or_else(|| "not configured".to_owned()))}</p></li> }).collect_view()}</ul></section>
|
||||
<EnvironmentForm workspace_id=workspace_id.clone() refresh=refresh/>
|
||||
<section class="rounded-xl border border-ink/10 bg-white p-5"><div class="flex items-center justify-between"><h2 class="font-semibold">"Repositories"</h2><span class="text-sm text-ink/50">{repositories.len()}</span></div><ul class="mt-3 space-y-2">{repositories.into_iter().map(|repository| { let role = match repository.role { crate::collab::RepositoryRole::Source => "source", crate::collab::RepositoryRole::Infra => "infra" }; view! { <li class="rounded border border-ink/10 px-3 py-2 text-sm"><p class="font-medium">{format!("{}/{}", repository.owner, repository.name)}</p><p class="mt-1 font-mono text-xs text-ink/45">{format!("{} · {role}", repository.branch)}</p></li> } }).collect_view()}</ul></section>
|
||||
<ProjectForm workspace_id=workspace_id.clone() refresh=refresh/>
|
||||
<DocumentForm workspace_id=workspace_id.clone() refresh=refresh/>
|
||||
<AttachRepositoryForm workspace_id=workspace_id refresh=refresh/>
|
||||
</aside>
|
||||
</div>
|
||||
}.into_any()
|
||||
}
|
||||
Err(message) => view! { <p class="text-red-600">{message.clone()}</p> }.into_any(),
|
||||
})}
|
||||
</Suspense>
|
||||
</main>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
use leptos::prelude::*;
|
||||
use leptos_router::components::A;
|
||||
use leptos_router::hooks::use_params_map;
|
||||
|
||||
use crate::collab::{
|
||||
issues, project_documents, versions, workspace, Document, Issue, Project, Version,
|
||||
};
|
||||
use crate::components::nav::Nav;
|
||||
|
||||
use super::workspace_forms::{
|
||||
AttachRepositoryForm, DocumentForm, EnvironmentForm, IssueForm, ProjectForm, VersionForm,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
struct WorkspaceData {
|
||||
workspace: crate::collab::Workspace,
|
||||
repositories: Vec<crate::collab::CheckoutRepository>,
|
||||
environments: Vec<crate::collab::Environment>,
|
||||
projects: Vec<ProjectData>,
|
||||
documents: Vec<Document>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ProjectData {
|
||||
project: Project,
|
||||
issues: Vec<Issue>,
|
||||
versions: Vec<Version>,
|
||||
documents: Vec<Document>,
|
||||
}
|
||||
|
||||
async fn load_workspace(id: &str) -> Result<WorkspaceData, String> {
|
||||
let (workspace, repositories, environments, projects, documents) =
|
||||
workspace(cynic::Id::new(id)).await?;
|
||||
let mut projects_with_issues = Vec::with_capacity(projects.len());
|
||||
for project in projects {
|
||||
let project_issues = issues(project.id.clone()).await?;
|
||||
let project_versions = versions(project.id.clone()).await?;
|
||||
let documents = project_documents(workspace.id.clone(), project.id.clone()).await?;
|
||||
projects_with_issues.push(ProjectData {
|
||||
project,
|
||||
issues: project_issues,
|
||||
versions: project_versions,
|
||||
documents,
|
||||
});
|
||||
}
|
||||
Ok(WorkspaceData {
|
||||
workspace,
|
||||
repositories,
|
||||
environments,
|
||||
projects: projects_with_issues,
|
||||
documents,
|
||||
})
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn WorkspacePage() -> impl IntoView {
|
||||
let params = use_params_map();
|
||||
let refresh = RwSignal::new(0_u64);
|
||||
let data = LocalResource::new(move || {
|
||||
refresh.get();
|
||||
let id = params.read().get("id").unwrap_or_default();
|
||||
async move { load_workspace(&id).await }
|
||||
});
|
||||
|
||||
view! {
|
||||
<div class="flex min-h-screen flex-col bg-paper text-ink">
|
||||
<Nav>
|
||||
<A href="/workspaces" attr:class="text-sm font-medium hover:text-primary">"Workspaces"</A>
|
||||
<A href="/account" attr:class="text-sm font-medium hover:text-primary">"Account"</A>
|
||||
</Nav>
|
||||
<main class="mx-auto w-full max-w-6xl flex-1 px-6 py-12">
|
||||
<Suspense fallback=|| view! { <p class="text-ink/60">"Loading workspace…"</p> }>
|
||||
{move || data.get().map(|result| match &*result {
|
||||
Ok(data) => {
|
||||
let workspace = data.workspace.clone();
|
||||
let workspace_id = workspace.id.inner().to_owned();
|
||||
let projects = data.projects.clone();
|
||||
let documents = data.documents.clone();
|
||||
let repositories = data.repositories.clone();
|
||||
let environments = data.environments.clone();
|
||||
view! {
|
||||
<header class="flex flex-wrap items-end justify-between gap-4 border-b border-ink/10 pb-8">
|
||||
<div><p class="font-mono text-sm text-ink/50">{workspace.slug}</p><h1 class="mt-1 text-3xl font-semibold">{workspace.name}</h1></div>
|
||||
<span class="rounded-full bg-tertiary/20 px-3 py-1 text-xs font-medium">{workspace.default_environment}</span>
|
||||
</header>
|
||||
<div class="mt-8 grid gap-8 lg:grid-cols-[1fr_22rem]">
|
||||
<div class="space-y-10">
|
||||
<section>
|
||||
<div class="flex items-center justify-between"><h2 class="text-xl font-semibold">"Projects"</h2><span class="text-sm text-ink/50">{projects.len()}</span></div>
|
||||
<ul class="mt-4 space-y-4">{projects.clone().into_iter().map(|data| {
|
||||
let project = data.project;
|
||||
let issues = data.issues;
|
||||
let versions = data.versions;
|
||||
let documents = data.documents;
|
||||
view! {
|
||||
<li class="rounded-xl border border-ink/10 bg-white p-5">
|
||||
<div class="flex items-center justify-between gap-4"><div><h3 class="font-semibold">{format!("{} · {}", project.key, project.name)}</h3><p class="mt-1 text-sm text-ink/55">{project.description}</p><p class="mt-1 font-mono text-xs text-ink/40">{project.slug}</p></div><span class="text-xs uppercase text-ink/45">{project.lifecycle}</span></div>
|
||||
<ul class="mt-4 divide-y divide-ink/10 border-t border-ink/10">{issues.into_iter().map(|issue| view! { <li class="flex items-center gap-3 py-3 text-sm"><span class="font-mono text-ink/45">{format!("#{}", issue.number)}</span><span>{issue.title}</span></li> }).collect_view()}</ul>
|
||||
<IssueForm project_id=project.id.inner().to_owned() refresh=refresh/>
|
||||
<div class="mt-5 border-t border-ink/10 pt-4"><h4 class="text-xs font-semibold uppercase tracking-wide text-ink/45">"Versions"</h4><ul class="mt-2 flex flex-wrap gap-2">{versions.into_iter().map(|version| view! { <li class="rounded-full bg-ink/5 px-3 py-1 text-xs">{format!("{} ({}) · {}", version.name, version.slug, version.state)}</li> }).collect_view()}</ul><VersionForm project_id=project.id.inner().to_owned() refresh=refresh/></div>
|
||||
<div class="mt-5 border-t border-ink/10 pt-4"><div class="flex items-center justify-between"><h4 class="text-xs font-semibold uppercase tracking-wide text-ink/45">"Project docs"</h4><span class="text-xs text-ink/40">{documents.len()}</span></div><ul class="mt-2 space-y-2">{documents.into_iter().map(|document| view! { <li class="rounded border border-ink/10 p-3"><div class="flex items-center justify-between gap-4"><p class="font-mono text-xs font-semibold">{document.path}</p><span class="font-mono text-[0.65rem] text-ink/35">{document.revision_id.inner().to_owned()}</span></div><pre class="mt-2 whitespace-pre-wrap text-xs text-ink/65">{document.content}</pre></li> }).collect_view()}</ul></div>
|
||||
</li>
|
||||
}}).collect_view()}</ul>
|
||||
</section>
|
||||
<section>
|
||||
<div class="flex items-center justify-between"><h2 class="text-xl font-semibold">"Docs"</h2><span class="text-sm text-ink/50">{documents.len()}</span></div>
|
||||
<ul class="mt-4 space-y-3">{documents.into_iter().map(|document| view! { <li class="rounded-xl border border-ink/10 bg-white p-5"><div class="flex items-center justify-between gap-4"><p class="font-mono text-sm font-semibold">{document.path}</p><span class="font-mono text-xs text-ink/35">{document.revision_id.inner().to_owned()}</span></div><pre class="mt-3 whitespace-pre-wrap text-sm text-ink/70">{document.content}</pre></li> }).collect_view()}</ul>
|
||||
</section>
|
||||
</div>
|
||||
<aside class="space-y-5">
|
||||
<section class="rounded-xl border border-ink/10 bg-white p-5"><div class="flex items-center justify-between"><h2 class="font-semibold">"Environments"</h2><span class="text-sm text-ink/50">{environments.len()}</span></div><ul class="mt-3 space-y-2">{environments.into_iter().map(|environment| view! { <li class="rounded border border-ink/10 px-3 py-2 text-sm"><p class="font-medium">{environment.name}</p><p class="mt-1 font-mono text-xs text-ink/45">{format!("source: {} · infra: {}", environment.default_source_branch, environment.infra_branch.unwrap_or_else(|| "not configured".to_owned()))}</p></li> }).collect_view()}</ul></section>
|
||||
<EnvironmentForm workspace_id=workspace_id.clone() refresh=refresh/>
|
||||
<section class="rounded-xl border border-ink/10 bg-white p-5"><div class="flex items-center justify-between"><h2 class="font-semibold">"Repositories"</h2><span class="text-sm text-ink/50">{repositories.len()}</span></div><ul class="mt-3 space-y-2">{repositories.into_iter().map(|repository| { let role = match repository.role { crate::collab::RepositoryRole::Source => "source", crate::collab::RepositoryRole::Infra => "infra" }; view! { <li class="rounded border border-ink/10 px-3 py-2 text-sm"><p class="font-medium">{format!("{}/{}", repository.owner, repository.name)}</p><p class="mt-1 font-mono text-xs text-ink/45">{format!("{} · {role}", repository.branch)}</p></li> } }).collect_view()}</ul></section>
|
||||
<ProjectForm workspace_id=workspace_id.clone() refresh=refresh/>
|
||||
<DocumentForm workspace_id=workspace_id.clone() refresh=refresh/>
|
||||
<AttachRepositoryForm workspace_id=workspace_id refresh=refresh/>
|
||||
</aside>
|
||||
</div>
|
||||
}.into_any()
|
||||
}
|
||||
Err(message) => view! { <p class="text-red-600">{message.clone()}</p> }.into_any(),
|
||||
})}
|
||||
</Suspense>
|
||||
</main>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user