feat: Improve registration UI in first-run mode

This commit is contained in:
Ginger
2026-05-26 14:27:09 -04:00
parent 91923d0afa
commit 6a9123baf1
3 changed files with 40 additions and 11 deletions
+10 -2
View File
@@ -37,6 +37,7 @@ pub(crate) fn build() -> Router<crate::State> {
template! { template! {
struct Register use "register.html.j2" { struct Register use "register.html.j2" {
server_name: OwnedServerName, server_name: OwnedServerName,
is_first_run: bool,
body: RegisterBody body: RegisterBody
} }
} }
@@ -171,6 +172,7 @@ async fn route_register(
return response!(Register::new( return response!(Register::new(
context, context,
services.globals.server_name().to_owned(), services.globals.server_name().to_owned(),
services.firstrun.is_first_run(),
RegisterBody::Unavailable RegisterBody::Unavailable
)); ));
} }
@@ -195,6 +197,7 @@ async fn route_register(
return response!(Register::new( return response!(Register::new(
context, context,
services.globals.server_name().to_owned(), services.globals.server_name().to_owned(),
services.firstrun.is_first_run(),
RegisterBody::UsernamePrompt { RegisterBody::UsernamePrompt {
allow_federation: services.config.allow_federation, allow_federation: services.config.allow_federation,
trusted_flow_status, trusted_flow_status,
@@ -245,7 +248,12 @@ async fn route_register(
} }
}; };
response!(Register::new(context, services.globals.server_name().to_owned(), body)) response!(Register::new(
context,
services.globals.server_name().to_owned(),
services.firstrun.is_first_run(),
body
))
} }
template! { template! {
@@ -555,7 +563,7 @@ pub(super) async fn registration_flow_status(
.as_ref() .as_ref()
.is_some_and(|smtp| smtp.require_email_for_registration); .is_some_and(|smtp| smtp.require_email_for_registration);
if !allow_registration { if !allow_registration || services.firstrun.is_first_run() {
UntrustedFlowStatus::Unavailable UntrustedFlowStatus::Unavailable
} else if services.config.recaptcha_private_site_key.is_some() || require_email { } else if services.config.recaptcha_private_site_key.is_some() || require_email {
UntrustedFlowStatus::Available { require_email } UntrustedFlowStatus::Available { require_email }
+8 -1
View File
@@ -13,7 +13,7 @@ use crate::{
extract::{Expect, PostForm}, extract::{Expect, PostForm},
pages::{ pages::{
GET_POST, Result, TemplateContext, GET_POST, Result, TemplateContext,
account::register::RegisterQuery, account::register::{RegisterQuery, RequestedRegistrationFlow},
components::{Avatar, AvatarType, ClientScopes}, components::{Avatar, AvatarType, ClientScopes},
}, },
response, response,
@@ -49,17 +49,24 @@ async fn route_authorization_code(
let user_id = if let Some(user) = user.into_session() { let user_id = if let Some(user) = user.into_session() {
user.user_id user.user_id
} else { } else {
let is_first_run = services.firstrun.is_first_run();
let next = LoginTarget::AuthorizationCode(query.clone()); let next = LoginTarget::AuthorizationCode(query.clone());
let uri = if query let uri = if query
.prompt .prompt
.is_some_and(|prompt| matches!(prompt, Prompt::Create)) .is_some_and(|prompt| matches!(prompt, Prompt::Create))
|| is_first_run
{ {
format!( format!(
"{}/account/register/?{}", "{}/account/register/?{}",
ROUTE_PREFIX, ROUTE_PREFIX,
serde_urlencoded::to_string(RegisterQuery { serde_urlencoded::to_string(RegisterQuery {
next: Some(next), next: Some(next),
flow: if is_first_run {
Some(RequestedRegistrationFlow::Trusted)
} else {
None
},
..Default::default() ..Default::default()
}) })
.unwrap() .unwrap()
+22 -8
View File
@@ -12,7 +12,9 @@ Sign up
{%- block content -%} {%- block content -%}
<div class="panel narrow"> <div class="panel narrow">
<h1 class="with-matrix-icon"> <h1 class="with-matrix-icon">
{% if let RegisterBody::UsernamePrompt { next, .. } = body && next.is_some() %} {% if is_first_run %}
Finish setting up
{% else if let RegisterBody::UsernamePrompt { next, .. } = body && next.is_some() %}
Sign up to continue Sign up to continue
{% else %} {% else %}
Sign up Sign up
@@ -80,6 +82,11 @@ Sign up
{% let validation_errors = validation_errors.clone() %} {% let validation_errors = validation_errors.clone() %}
{% let field_errors = validation_errors.field_errors() %} {% let field_errors = validation_errors.field_errors() %}
<form method="post"> <form method="post">
{% if is_first_run %}
<p>
To finish setting up your server, choose a username and password for your account.
</p>
{% endif %}
<p> <p>
<label for="username">Username</label> <label for="username">Username</label>
<span class="username-input"> <span class="username-input">
@@ -94,9 +101,11 @@ Sign up
{{ form::errors(field_errors, std::borrow::Cow::Borrowed("username")) }} {{ form::errors(field_errors, std::borrow::Cow::Borrowed("username")) }}
<small><b>Note:</b> Your username cannot be changed after you create your account.</small> <small><b>Note:</b> Your username cannot be changed after you create your account.</small>
</p> </p>
<p> {% if !is_first_run %}
Just a few more details to finish creating your account. <p>
</p> Just a few more details to finish creating your account.
</p>
{% endif %}
<p> <p>
<label for="password">Password</label> <label for="password">Password</label>
<input type="password" name="password" autocomplete="new-password" required> <input type="password" name="password" autocomplete="new-password" required>
@@ -140,6 +149,9 @@ Sign up
<p> <p>
<label for="username">Registration token</label> <label for="username">Registration token</label>
<input type="text" name="registration_token" autocomplete="none" required> <input type="text" name="registration_token" autocomplete="none" required>
{% if is_first_run %}
<small>Check the server console to find the registration token.</small>
{% endif %}
{{ form::errors(field_errors, std::borrow::Cow::Borrowed("registration_token")) }} {{ form::errors(field_errors, std::borrow::Cow::Borrowed("registration_token")) }}
</p> </p>
{% endif %} {% endif %}
@@ -157,14 +169,16 @@ Sign up
I agree to the <a target="_blank" href="{{ document.url }}">{{ document.name }}</a> I agree to the <a target="_blank" href="{{ document.url }}">{{ document.name }}</a>
</label> </label>
{% endfor %} {% endfor %}
<small><i>All policy links will open in a new tab.</i></small> <small>All policy links will open in a new tab.</small>
</p> </p>
{% endif %} {% endif %}
<button type="submit">Continue</button> <button type="submit">Continue</button>
</form> </form>
{% endmatch %} {% endmatch %}
<div class="centered-links"> {% if !is_first_run %}
<a href="{{ crate::ROUTE_PREFIX }}/account/login">I already have an account</a> <div class="centered-links">
</div> <a href="{{ crate::ROUTE_PREFIX }}/account/login">I already have an account</a>
</div>
{% endif %}
</div> </div>
{%- endblock -%} {%- endblock -%}