Skip to content

Commit b22910b

Browse files
committed
Use build-tchap in frontend pipeline (#22)
add comments Include tchap resources in the build package (#26) * test build templates * fix cp * lint
1 parent 03cccdb commit b22910b

File tree

13 files changed

+1510
-13
lines changed

13 files changed

+1510
-13
lines changed

.github/actions/build-frontend/action.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ runs:
2020
shell: sh
2121

2222
- name: Build the frontend assets
23-
run: npm run build
23+
#:tchap:
24+
# run: npm run build
25+
run: npm run build-tchap
26+
#:tchap:
2427
working-directory: ./frontend
2528
shell: sh

.github/workflows/build.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ jobs:
8181
cp -r frontend/dist/ assets-dist/share/assets
8282
cp -r templates/ assets-dist/share/templates
8383
cp -r translations/ assets-dist/share/translations
84+
#:tchap:
85+
cp -r tchap/resources/templates/* assets-dist/share/templates/
86+
cp -r tchap/resources/translations/* assets-dist/share/translations/
87+
#:tchap: end
8488
cp LICENSE assets-dist/LICENSE
8589
chmod -R u=rwX,go=rX assets-dist/
8690

frontend/tchap/components/Footer/Footer.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,20 @@
2323
// USE OR OTHER DEALINGS IN THE SOFTWARE.
2424
//
2525

26-
import React from "react";
26+
import type React from "react";
2727
import "@gouvfr-lasuite/integration/dist/css/homepage-full.css";
2828

2929
const Footer: React.FC = () => (
30-
<footer className="lasuite fr-footer" role="contentinfo">
30+
<footer className="lasuite fr-footer">
3131
<div className="fr-container lasuite-container">
3232
<div className="fr-footer__body">
3333
<div className="fr-footer__brand fr-enlarge-link">
34-
<a
35-
href="/"
36-
title="Retour à l'accueil - Tchap"
37-
>
38-
<p className="fr-logo">République<br />Française</p>
34+
<a href="/" title="Retour à l'accueil - Tchap">
35+
<p className="fr-logo">
36+
République
37+
<br />
38+
Française
39+
</p>
3940
</a>
4041
</div>
4142
</div>

frontend/tchap/components/Header/Header.module.css

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737

3838
.logo {
3939
width: 32px;
40-
width: 32px;
4140
}
4241

4342
.title {

frontend/tchap/components/Header/Header.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@
2323
// USE OR OTHER DEALINGS IN THE SOFTWARE.
2424
//
2525

26-
import React from "react";
26+
import type React from "react";
2727
import styles from "./Header.module.css";
2828

2929
const Header: React.FC = () => (
3030
<header className={styles.headerTchap}>
3131
<div className={styles.logoContainer}>
32-
<img
33-
className={styles.logo}
32+
<img
33+
className={styles.logo}
3434
src="https://www.tchap.gouv.fr/themes/tchap/img/logos/tchap-logo.svg"
3535
alt="Logo Tchap"
3636
/>

frontend/tchap/css/tchap.css

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tchap/README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Tchap customizations
2+
3+
All customization in the upstream codebase are to be surrounded with `:tchap:` tag
4+
5+
## Server side logic
6+
7+
Tchap customization in the Rust server codebase are located in the [tchap crate](../crates/tchap).
8+
9+
## Building templates with Tchap customization
10+
11+
[Tchap customizations](resources/templates) override some of the default templates.
12+
13+
MAS templates relies on static resources from the frontend app (mainly css), therefore some Tchap resources have been added there via the default manifest.json
14+
15+
The manifest.json is extended for Tchap in the vite config [vite.tchap.config.ts](../frontend/tchap/vite.tchap.config.ts)
16+
17+
18+
## Customizations in the frontend app
19+
20+
Tchap custom React components are located in a [subdirectory](../frontend/tchap) of the frontend app.
21+
22+
## Custom pipeline
23+
24+
For building the Docker image, the [`build` github action](../.github/workflows/build.yaml) packages all MAS resources enhanced with Tchap customizations.
25+
26+
27+
# Important knowledge
28+
29+
Serve directory is defined in the config.yaml, by default it is `path: "./frontend/dist/"`
30+
31+
```
32+
http:
33+
listeners:
34+
- name: web
35+
resources:
36+
- name: assets
37+
path: "/resources/manifest.json"
38+
39+
```
40+
41+
See in the logs
42+
43+
```
44+
2025-06-03T12:28:33.967776Z INFO mas_cli::commands::server:297 Listening on http://[::]:8080 with resources [Discovery, Human, OAuth, Compat, GraphQL { playground: false, undocumented_oauth2_access: false }, Assets { path: "./frontend/dist/" }, AdminApi]
45+
46+
```
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{#
2+
Copyright 2024 New Vector Ltd.
3+
Copyright 2021-2024 The Matrix.org Foundation C.I.C.
4+
5+
SPDX-License-Identifier: AGPL-3.0-only
6+
Please see LICENSE in the repository root for full details.
7+
-#}
8+
9+
{% set _ = translator(lang) %}
10+
11+
{% import "components/button.html" as button %}
12+
{% import "components/field.html" as field %}
13+
{% import "components/back_to_client.html" as back_to_client %}
14+
{% import "components/logout.html" as logout %}
15+
{% import "components/errors.html" as errors %}
16+
{% import "components/icon.html" as icon %}
17+
{% import "components/scope.html" as scope %}
18+
{% import "components/captcha.html" as captcha %}
19+
20+
21+
<!DOCTYPE html>
22+
<html lang="{{ lang }}">
23+
<head>
24+
<meta charset="utf-8">
25+
<title>{% block title %}{{ _("app.name") }}{% endblock title %}</title>
26+
<meta name="viewport" content="width=device-width, initial-scale=1">
27+
{{ include_asset('src/shared.css') | indent(4) | safe }}
28+
{{ include_asset('src/templates.css') | indent(4) | safe }}
29+
30+
<!-- :tchap: -->
31+
{{ include_asset('tchap/css/tchap.css') | indent(4) | safe }}
32+
{{ include_asset('node_modules/@gouvfr-lasuite/integration/dist/css/homepage-full.css') | indent(4) | safe }}
33+
<script id="lasuite-gaufre-script" async defer src="https://integration.lasuite.numerique.gouv.fr/api/v1/gaufre.js"></script>
34+
<!-- :tchap: -->
35+
{{ captcha.head() }}
36+
</head>
37+
<body>
38+
<!-- :tchap: add lasuite header -->
39+
{% include "tchap/header.html" %}
40+
41+
<div class="layout-container{% if consent_page %} consent{% endif %}">
42+
{% block content %}{% endblock content %}
43+
44+
<!-- :tchap: remove default footer {% include "components/footer.html" %} -->
45+
</div>
46+
47+
<!-- :tchap: add lasuite footer -->
48+
{% include "tchap/footer.html" %}
49+
</body>
50+
</html>
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
{#
2+
Copyright 2024 New Vector Ltd.
3+
Copyright 2021-2024 The Matrix.org Foundation C.I.C.
4+
5+
SPDX-License-Identifier: AGPL-3.0-only
6+
Please see LICENSE in the repository root for full details.
7+
-#}
8+
9+
{% extends "base.html" %}
10+
11+
{% from "components/idp_brand.html" import logo %}
12+
13+
{% block content %}
14+
<form method="POST" class="flex flex-col gap-10">
15+
<header class="page-heading">
16+
<!--
17+
<div class="icon">
18+
{{ icon.user_profile_solid() }}
19+
</div>
20+
-->
21+
{% if next and next.kind == "link_upstream" %}
22+
<div class="header">
23+
<h1 class="title">{{ _("mas.login.link.headline") }}</h1>
24+
{% set name = provider.human_name or (provider.issuer | simplify_url(keep_path=True)) or provider.id %}
25+
<p class="text">{{ _("mas.login.link.description", provider=name) }}</p>
26+
</div>
27+
{% else %}
28+
<div class="header">
29+
<h1 class="title">{{ _("mas.login.headline") }}</h1>
30+
<!-- <p class="text">{{ _("mas.login.description") }}</p> -->
31+
</div>
32+
{% endif %}
33+
</header>
34+
35+
<!-- #tchap# -->
36+
{% set params = next["params"] | default({}) | to_params(prefix="?") %}
37+
{% for provider in providers %}
38+
{% set name = provider.human_name or (provider.issuer | simplify_url(keep_path=True)) or provider.id %}
39+
40+
<!-- #tchap# add .lasuite class to add lasuite fonts -->
41+
<div class="cpd-form-root lasuite">
42+
<button class="proconnect-button" onclick="window.location.href = '{{ ('/upstream/authorize/' ~ provider.id ~ params) | prefix_url }}';">
43+
<span class="proconnect-sr-only">S'identifier avec ProConnect</span>
44+
</button>
45+
<p>
46+
<a
47+
href="https://www.proconnect.gouv.fr/"
48+
target="_blank"
49+
rel="noopener noreferrer"
50+
title="Qu’est-ce que ProConnect ? - nouvelle fenêtre"
51+
>
52+
Qu’est-ce que ProConnect ?
53+
</a>
54+
</p>
55+
</div>
56+
{% endfor %}
57+
<!-- #tchap# end -->
58+
<!--
59+
{% if providers %}
60+
{% set params = next["params"] | default({}) | to_params(prefix="?") %}
61+
{% for provider in providers %}
62+
{% set name = provider.human_name or (provider.issuer | simplify_url(keep_path=True)) or provider.id %}
63+
64+
<a class="cpd-button {%- if provider.brand_name %} has-icon {%- endif %}" data-kind="secondary" data-size="lg" href="{{ ('/upstream/authorize/' ~ provider.id ~ params) | prefix_url }}">
65+
{{ logo(provider.brand_name) }}
66+
{{ _("mas.login.continue_with_provider", provider=name) }}
67+
</a>
68+
{% endfor %}
69+
{% endif %}
70+
-->
71+
72+
73+
{{ field.separator() }}
74+
75+
76+
<div class="cpd-form-root">
77+
{% if form.errors is not empty %}
78+
{% for error in form.errors %}
79+
<div class="text-critical font-medium">
80+
{{ errors.form_error_message(error=error) }}
81+
</div>
82+
{% endfor %}
83+
{% endif %}
84+
85+
<input type="hidden" name="csrf" value="{{ csrf_token }}" />
86+
87+
{% if features.login_with_email_allowed %}
88+
{% call(f) field.field(label=_("mas.login.username_or_email"), name="username", form_state=form) %}
89+
<input {{ field.attributes(f) }} class="cpd-text-control" type="text" autocomplete="username" autocorrect="off" autocapitalize="off" required />
90+
{% endcall %}
91+
{% else %}
92+
{% call(f) field.field(label=_("common.username"), name="username", form_state=form) %}
93+
<input {{ field.attributes(f) }} class="cpd-text-control" type="text" autocomplete="username" autocorrect="off" autocapitalize="off" required />
94+
{% endcall %}
95+
{% endif %}
96+
97+
{% if features.password_login %}
98+
{% call(f) field.field(label=_("common.password"), name="password", form_state=form) %}
99+
<input {{ field.attributes(f) }} class="cpd-text-control" type="password" autocomplete="password" required />
100+
{% endcall %}
101+
102+
{% if features.account_recovery %}
103+
{{ button.link_text(text=_("mas.login.forgot_password"), href="/recover", class="self-center") }}
104+
{% endif %}
105+
{% endif %}
106+
</div>
107+
108+
<div class="cpd-form-root">
109+
{% if features.password_login %}
110+
{{ button.button(text=_("action.continue")) }}
111+
{% endif %}
112+
113+
114+
115+
116+
</div>
117+
118+
{% if (not next or next.kind != "link_upstream") and features.password_registration %}
119+
<div class="flex gap-1 justify-center items-center cpd-text-body-md-regular">
120+
<p class="cpd-text-secondary">
121+
{{ _("mas.login.call_to_register") }}
122+
</p>
123+
124+
125+
{% set params = next["params"] | default({}) | to_params(prefix="?") %}
126+
{{ button.link_text(text=_("action.create_account"), href="/register" ~ params) }}
127+
</div>
128+
{% endif %}
129+
130+
{% if not providers and not features.password_login %}
131+
<div class="text-center">
132+
{{ _("mas.login.no_login_methods") }}
133+
</div>
134+
{% endif %}
135+
</form>
136+
{% endblock content %}

0 commit comments

Comments
 (0)