feat(ui/user): add apps listing

This commit is contained in:
Matthieu Bessat 2024-11-25 09:07:30 +01:00
parent acb96dee39
commit 69af48bb62
8 changed files with 133 additions and 17 deletions

View file

@ -0,0 +1,32 @@
use axum::{extract::State, response::IntoResponse, Extension};
use minijinja::context;
use crate::{
models::{config::AppVisibility, config::Application},
renderer::TemplateRenderer,
server::AppState
};
pub async fn list_apps(
State(app_state): State<AppState>,
Extension(renderer): Extension<TemplateRenderer>,
) -> impl IntoResponse {
// implement app discovery
// for now, we just list all apps in the organization
let apps: Vec<&Application> = app_state.config
.applications
.iter()
.filter(|a|
a.visibility == AppVisibility::Public ||
a.visibility == AppVisibility::Internal
).collect();
renderer.render(
"pages/apps",
context!(
apps => apps
)
)
}

View file

@ -5,3 +5,4 @@ pub mod register;
pub mod me;
pub mod logout;
pub mod user_panel;
pub mod apps;

View file

@ -21,16 +21,31 @@ enum AppAuthorizeFlow {
Implicit
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[fully_pub]
enum AppVisibility {
/// app is public (visible to non-signed in user), useful for app discovery
Public,
/// app is visible to all signed-in users
Internal,
/// app will be only visible when the user reach the login endpoint
Private
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[fully_pub]
struct Application {
slug: String,
name: String,
description: String,
logo_uri: Option<String>,
client_id: String,
client_secret: String,
allowed_redirect_uris: Vec<String>,
authorize_flow: AppAuthorizeFlow
authorize_flow: AppAuthorizeFlow,
visibility: AppVisibility,
login_uri: String
}
#[derive(Debug, Clone, Serialize, Deserialize)]

View file

@ -26,6 +26,7 @@ pub fn build_router(server_config: &ServerConfig, app_state: AppState) -> Router
.route("/logout", get(ui::logout::perform_logout))
.route("/authorize", get(ui::authorize::authorize_form))
.route("/authorize", post(ui::authorize::perform_authorize))
.route("/apps", get(ui::apps::list_apps))
.route("/me", get(ui::me::me_page))
.route("/me/details-form", get(ui::me::me_update_details_form))
.route("/me/details-form", post(ui::me::me_perform_update_details))

View file

@ -9,20 +9,23 @@
</li>
</ul>
<ul class="navbar-nav">
{% if token_claims is none %}
{% if token_claims %}
<li class="nav-item">
<a class="nav-link" href="/login">Login</a>
<a class="nav-link" href="/apps">Apps</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/register">Register</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="/me">Me</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/logout">Logout</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="/login">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/register">Register</a>
</li>
{% endif %}
</ul>
</div>

View file

@ -0,0 +1,34 @@
{% extends "layouts/base.html" %}
{% block body %}
<h1>Available apps</h1>
<p>List of apps you can use with Single-Sign-On in this organization.</p>
<div class="apps-mosaic">
<div class="row">
{% for app in apps %}
<div class="col-xs-12 col-sm-6 col-lg-3 mb-3 mb-sm-0">
<div class="card">
<div class="card-body">
{% if app.logo_uri %}
<img src="{{ app.logo_uri}}" class="card-img-top" alt="{{ app.name }} logo">
{% endif %}
<h5 class="card-title">
{{ app.name }}
</h5>
<p class="card-text">
{{ app.description }}
</p>
<a
href="{{ app.login_uri }}"
class="btn btn-primary"
title="Open the app or login"
>
Open app
</a>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}