bk
This commit is contained in:
parent
35c75cdc5c
commit
a1420f590e
11 changed files with 182 additions and 41 deletions
|
@ -1,5 +1,6 @@
|
|||
pub mod home;
|
||||
pub mod login;
|
||||
pub mod projects;
|
||||
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::Response;
|
||||
|
|
|
@ -10,12 +10,14 @@ pub async fn home_page(State(ctx): State<Context>, auth_session: AuthSession<Con
|
|||
id: 1,
|
||||
owner_id: 1,
|
||||
name: "Blog posts".to_owned(),
|
||||
description: "Planning and publication schedule for my blog".to_owned(),
|
||||
key: "BLOG".to_owned(),
|
||||
},
|
||||
Project {
|
||||
id: 2,
|
||||
owner_id: 1,
|
||||
name: "Bugs (Pique)".to_owned(),
|
||||
description: "The bugs we've found so far in Pique".to_owned(),
|
||||
key: "BUG".to_owned(),
|
||||
},
|
||||
];
|
||||
|
|
50
src/handler/projects.rs
Normal file
50
src/handler/projects.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
use axum::response::Redirect;
|
||||
use axum_login::AuthSession;
|
||||
|
||||
use crate::{models::Project, prelude::*};
|
||||
|
||||
pub async fn projects_page(
|
||||
State(ctx): State<Context>,
|
||||
auth_session: AuthSession<Context>,
|
||||
) -> Response {
|
||||
if let Some(user) = auth_session.user {
|
||||
let projects: Vec<Project> = vec![
|
||||
Project {
|
||||
id: 1,
|
||||
owner_id: 1,
|
||||
name: "Blog posts".to_owned(),
|
||||
description: "Planning and publication schedule for my blog".to_owned(),
|
||||
key: "BLOG".to_owned(),
|
||||
},
|
||||
Project {
|
||||
id: 2,
|
||||
owner_id: 1,
|
||||
name: "Bugs (Pique)".to_owned(),
|
||||
description: "The bugs we've found so far in Pique".to_owned(),
|
||||
key: "BUG".to_owned(),
|
||||
},
|
||||
];
|
||||
|
||||
let values = context! {
|
||||
user => user,
|
||||
projects => projects,
|
||||
};
|
||||
|
||||
ctx.render_resp("projects/list_projects.html", values)
|
||||
} else {
|
||||
Redirect::to("/login").into_response()
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn create_project(
|
||||
State(ctx): State<Context>,
|
||||
auth_session: AuthSession<Context>,
|
||||
) -> Response {
|
||||
if let Some(_user) = auth_session.user {
|
||||
let values = context! {};
|
||||
|
||||
ctx.render_resp("projects/create_project.html", values)
|
||||
} else {
|
||||
Redirect::to("/login").into_response()
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ pub struct Project {
|
|||
pub owner_id: i32,
|
||||
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
|
||||
// The key is the short code, like BUG, which is used to refer to a project
|
||||
// quickly and to display it more compactly. This must be unique across the
|
||||
|
|
|
@ -10,7 +10,7 @@ use tower_sessions::SessionManagerLayer;
|
|||
use tower_sessions_sqlx_store::{sqlx::SqlitePool, SqliteStore};
|
||||
use tracing::Level;
|
||||
|
||||
use crate::{config::CommandLineOptions, context::Context, handler::{home::home_page, login::logout, login_page, login_submit}, logging::setup_logging, templates::make_template_loader};
|
||||
use crate::{config::CommandLineOptions, context::Context, handler::{home::home_page, login::logout, login_page, login_submit, projects::{create_project, projects_page}}, logging::setup_logging, templates::make_template_loader};
|
||||
|
||||
pub async fn run() -> Result<()> {
|
||||
dotenvy::dotenv()?;
|
||||
|
@ -40,6 +40,8 @@ pub async fn run() -> Result<()> {
|
|||
.route("/login", get(login_page))
|
||||
.route("/login", post(login_submit))
|
||||
.route("/logout", get(logout))
|
||||
.route("/projects", get(projects_page))
|
||||
.route("/projects/new", get(create_project))
|
||||
.layer(trace_layer)
|
||||
.layer(session_layer)
|
||||
.layer(auth_layer)
|
||||
|
|
17
templates/components/nav/main_item.html
Normal file
17
templates/components/nav/main_item.html
Normal file
|
@ -0,0 +1,17 @@
|
|||
<li>
|
||||
{% if selected %}
|
||||
<a href="{{ path }}" class="bg-gray-100 text-gray-900 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold">
|
||||
<svg class="h-6 w-6 shrink-0 text-gray-900" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="{{ svg }}" />
|
||||
</svg>
|
||||
{{ text }}
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{{ path }}" class="text-gray-700 hover:text-gray-900 hover:bg-gray-100 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold">
|
||||
<svg class="h-6 w-6 shrink-0 text-gray-400 group-hover:text-gray-900" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="{{ svg }}" />
|
||||
</svg>
|
||||
{{ text }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</li>
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
<div class="fixed inset-y-0 z-50 flex w-72 flex-col">
|
||||
<div class="flex grow flex-col gap-y-5 overflow-y-auto border-r border-gray-20 bg-white px-6">
|
||||
|
||||
|
@ -10,41 +11,22 @@
|
|||
|
||||
<li>
|
||||
<ul role="list" class="-mx-2 space-y-1">
|
||||
<li>
|
||||
<!-- Current: "bg-gray-50 text-indigo-600", Default: "text-gray-700 hover:text-indigo-600 hover:bg-gray-50" -->
|
||||
<a href="#" class="bg-gray-50 text-indigo-600 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold">
|
||||
<svg class="h-6 w-6 shrink-0 text-indigo-600" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" />
|
||||
</svg>
|
||||
Dashboard
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#" class="text-gray-700 hover:text-indigo-600 hover:bg-gray-50 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold">
|
||||
<svg class="h-6 w-6 shrink-0 text-gray-400 group-hover:text-indigo-600" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12.75V12A2.25 2.25 0 014.5 9.75h15A2.25 2.25 0 0121.75 12v.75m-8.69-6.44l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z" />
|
||||
</svg>
|
||||
Projects
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="text-gray-700 hover:text-indigo-600 hover:bg-gray-50 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold">
|
||||
<svg class="h-6 w-6 shrink-0 text-gray-400 group-hover:text-indigo-600" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 01-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 011.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 00-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 01-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 00-3.375-3.375h-1.5a1.125 1.125 0 01-1.125-1.125v-1.5a3.375 3.375 0 00-3.375-3.375H9.75" />
|
||||
</svg>
|
||||
Documents
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="text-gray-700 hover:text-indigo-600 hover:bg-gray-50 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold">
|
||||
<svg class="h-6 w-6 shrink-0 text-gray-400 group-hover:text-indigo-600" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M20.25 8.511c.884.284 1.5 1.128 1.5 2.097v4.286c0 1.136-.847 2.1-1.98 2.193-.34.027-.68.052-1.02.072v3.091l-3-3c-1.354 0-2.694-.055-4.02-.163a2.115 2.115 0 0 1-.825-.242m9.345-8.334a2.126 2.126 0 0 0-.476-.095 48.64 48.64 0 0 0-8.048 0c-1.131.094-1.976 1.057-1.976 2.192v4.286c0 .837.46 1.58 1.155 1.951m9.345-8.334V6.637c0-1.621-1.152-3.026-2.76-3.235A48.455 48.455 0 0 0 11.25 3c-2.115 0-4.198.137-6.24.402-1.608.209-2.76 1.614-2.76 3.235v6.226c0 1.621 1.152 3.026 2.76 3.235.577.075 1.157.14 1.74.194V21l4.155-4.155" />
|
||||
</svg>
|
||||
Chats
|
||||
</a>
|
||||
</li>
|
||||
{% with path = "/", text = "Dashboard", selected = (current_page == "home"), svg = "M2.25 12.75V12A2.25 2.25 0 014.5 9.75h15A2.25 2.25 0 0121.75 12v.75m-8.69-6.44l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z" %}
|
||||
{% include "components/nav/main_item.html" %}
|
||||
{% endwith %}
|
||||
|
||||
{% with path = "/projects", text = "Projects", selected = (current_page == "projects"), svg = "M2.25 12.75V12A2.25 2.25 0 014.5 9.75h15A2.25 2.25 0 0121.75 12v.75m-8.69-6.44l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z" %}
|
||||
{% include "components/nav/main_item.html" %}
|
||||
{% endwith %}
|
||||
|
||||
{% with path = "/documents", text = "Documents", selected = (current_page == "documents"), svg = "M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 01-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 011.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 00-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 01-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 00-3.375-3.375h-1.5a1.125 1.125 0 01-1.125-1.125v-1.5a3.375 3.375 0 00-3.375-3.375H9.75" %}
|
||||
{% include "components/nav/main_item.html" %}
|
||||
{% endwith %}
|
||||
|
||||
{% with path = "/chats", text = "Chats", selected = (current_page == "chats"), svg = "M20.25 8.511c.884.284 1.5 1.128 1.5 2.097v4.286c0 1.136-.847 2.1-1.98 2.193-.34.027-.68.052-1.02.072v3.091l-3-3c-1.354 0-2.694-.055-4.02-.163a2.115 2.115 0 0 1-.825-.242m9.345-8.334a2.126 2.126 0 0 0-.476-.095 48.64 48.64 0 0 0-8.048 0c-1.131.094-1.976 1.057-1.976 2.192v4.286c0 .837.46 1.58 1.155 1.951m9.345-8.334V6.637c0-1.621-1.152-3.026-2.76-3.235A48.455 48.455 0 0 0 11.25 3c-2.115 0-4.198.137-6.24.402-1.608.209-2.76 1.614-2.76 3.235v6.226c0 1.621 1.152 3.026 2.76 3.235.577.075 1.157.14 1.74.194V21l4.155-4.155" %}
|
||||
{% include "components/nav/main_item.html" %}
|
||||
{% endwith %}
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
@ -60,13 +42,18 @@
|
|||
<span class="truncate">{{ project.name }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<div class="text-gray-500 p-2 text-xs leading-6 italic">
|
||||
No projects.
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="-mx-6 mt-auto">
|
||||
<a href="/profile" class="flex items-center gap-x-4 px-6 py-3 text-sm font-semibold leading-6 text-gray-900 hover:bg-gray-50">
|
||||
<div class="w-auto flex justify-around items-center text-sm font-semibold leading-6 text-gray-900">
|
||||
<a href="/profile" class="flex items-center gap-x-4 px-6 py-3 hover:bg-gray-50 rounded-md">
|
||||
<div class="h-8 w-8 rounded-full bg-gray-50">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-8 h-8">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
|
@ -74,7 +61,11 @@
|
|||
</div>
|
||||
|
||||
<span class="sr-only">Your profile</span>
|
||||
<span aria-hidden="true">{{ user.full_name }}</span>
|
||||
<span aria-hidden="true" class="">Profile</span>
|
||||
</a>
|
||||
|
||||
<a href="/logout" class="flex px-6 py-3 hover:bg-gray-50 rounded-md">
|
||||
<span>Log out</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<body class="h-full">
|
||||
|
||||
<div>
|
||||
{% set current_page = "home" %}
|
||||
{% include "components/sidebar.html" %}
|
||||
|
||||
<main class="py-10 pl-72">
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" class="h-full bg-purple-100">
|
||||
<html lang="en" class="h-full bg-secondary">
|
||||
{% include "head.html" %}
|
||||
<body class="h-full">
|
||||
|
||||
<div class="flex min-h-full flex-col justify-center py-12 sm:px-6 lg:px-8">
|
||||
<div class="sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<h2 class="mt-6 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">Sign in to Pique</h2>
|
||||
<h2 class="mt-6 text-center text-2xl font-bold leading-9 tracking-tight text-secondary-content">Sign in to Pique</h2>
|
||||
</div>
|
||||
|
||||
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-[480px]">
|
||||
|
@ -14,19 +14,19 @@
|
|||
<div>
|
||||
<label for="username" class="block text-sm font-medium leading-6 text-gray-900">Username</label>
|
||||
<div class="">
|
||||
<input id="username" name="username" type="username" autocomplete="username" required class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-emerald-600 sm:text-sm sm:leading-6">
|
||||
<input id="username" name="username" type="username" autocomplete="username" required class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-accent sm:text-sm sm:leading-6">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password" class="block text-sm font-medium leading-6 text-gray-900">Password</label>
|
||||
<div class="">
|
||||
<input id="password" name="password" type="password" autocomplete="current-password" required class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-emerald-600 sm:text-sm sm:leading-6">
|
||||
<input id="password" name="password" type="password" autocomplete="current-password" required class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-accent sm:text-sm sm:leading-6">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button type="submit" class="flex w-full justify-center rounded-md bg-emerald-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-emerald-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-emerald-600">Sign in</button>
|
||||
<button type="submit" class="btn btn-primary w-full">Sign in</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
|
31
templates/projects/create_project.html
Normal file
31
templates/projects/create_project.html
Normal file
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" class="h-full bg-white">
|
||||
{% include "head.html" %}
|
||||
<body class="h-full">
|
||||
|
||||
<div class="h-full">
|
||||
{% set current_page = "projects" %}
|
||||
{% include "components/sidebar.html" %}
|
||||
|
||||
<main class="pl-72 bg-gray-50 h-full">
|
||||
<div class="navbar bg-accent text-accent-content">
|
||||
<div class="navbar-start">
|
||||
<a class="btn" href="/projects/new">New Project</a>
|
||||
</div>
|
||||
<div class="navbar-end">
|
||||
<div class="btn">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 3c2.755 0 5.455.232 8.083.678.533.09.917.556.917 1.096v1.044a2.25 2.25 0 0 1-.659 1.591l-5.432 5.432a2.25 2.25 0 0 0-.659 1.591v2.927a2.25 2.25 0 0 1-1.244 2.013L9.75 21v-6.568a2.25 2.25 0 0 0-.659-1.591L3.659 7.409A2.25 2.25 0 0 1 3 5.818V4.774c0-.54.384-1.006.917-1.096A48.32 48.32 0 0 1 12 3Z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-8 py-8 flex flex-col gap-y-4">
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
<script type="text/javascript" src="/static/main.js"></script>
|
||||
</body>
|
||||
</html>
|
45
templates/projects/list_projects.html
Normal file
45
templates/projects/list_projects.html
Normal file
|
@ -0,0 +1,45 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" class="h-full bg-white">
|
||||
{% include "head.html" %}
|
||||
<body class="h-full">
|
||||
|
||||
<div class="h-full">
|
||||
{% set current_page = "projects" %}
|
||||
{% include "components/sidebar.html" %}
|
||||
|
||||
<main class="pl-72 bg-gray-50 h-full">
|
||||
<div class="navbar bg-accent text-accent-content">
|
||||
<div class="navbar-start">
|
||||
<a class="btn" href="/projects/new">New Project</a>
|
||||
</div>
|
||||
<div class="navbar-end">
|
||||
<div class="btn">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 3c2.755 0 5.455.232 8.083.678.533.09.917.556.917 1.096v1.044a2.25 2.25 0 0 1-.659 1.591l-5.432 5.432a2.25 2.25 0 0 0-.659 1.591v2.927a2.25 2.25 0 0 1-1.244 2.013L9.75 21v-6.568a2.25 2.25 0 0 0-.659-1.591L3.659 7.409A2.25 2.25 0 0 1 3 5.818V4.774c0-.54.384-1.006.917-1.096A48.32 48.32 0 0 1 12 3Z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-8 py-8 flex flex-col gap-y-4">
|
||||
|
||||
|
||||
{% for project in projects %}
|
||||
<div class="card w-96 bg-base-100 shadow-md border-2 border-solid">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">{{ project.key }} - {{ project.name }}</h2>
|
||||
<p>{{ project.description }}</p>
|
||||
<div class="card-actions justify-end">
|
||||
<button class="btn btn-primary">View</button>
|
||||
<button class="btn">Edit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
<script type="text/javascript" src="/static/main.js"></script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue