Skip to content

Commit 1314f6b

Browse files
merge branch v2 (release 2.0.0-beta.29)
2 parents a8d385b + ed60ffd commit 1314f6b

39 files changed

Lines changed: 1370 additions & 485 deletions

CHANGELOG.md

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,25 @@
11
# Changelog
22

3-
## [v2.0.0-beta.28](https://github.com/marcantondahmen/automad/commit/4ff284fe9dd5e38c014dfba0018bac5eac0e91d1)
3+
## [v2.0.0-beta.29](https://github.com/marcantondahmen/automad/commit/5e6d78703e35536fb4773c88f9ce51bc11a25da2)
44

5-
Thu, 30 Apr 2026 10:23:59 +0200
5+
Fri, 8 May 2026 04:38:22 +0200
6+
7+
### New Features
8+
9+
- create cache directory if needed ([c5b673cb](https://github.com/marcantondahmen/automad/commit/c5b673cbb3df64988068ff8d34c51bf007e20a83))
10+
- improve invitation and account recovery flow ([3e12340f](https://github.com/marcantondahmen/automad/commit/3e12340f00c7b7bf125e64dbd9bdc640d005e654))
11+
- improve user invitation flow ([c32aa631](https://github.com/marcantondahmen/automad/commit/c32aa631b6e3e46bb591adb5599bfd61a2d87d25))
12+
- update design of configuration test emails ([77793120](https://github.com/marcantondahmen/automad/commit/7779312090ac8cad26368979d762915b2666a6b0))
13+
- update design of email templates ([52f316e1](https://github.com/marcantondahmen/automad/commit/52f316e130563dfbeca4f87eb933611079e53264))
14+
15+
### Bugfixes
16+
17+
- fix formatting of multiline messages that are sent via mail forms ([0d555e5e](https://github.com/marcantondahmen/automad/commit/0d555e5eea852b88240f5148aaecebc6a4916d99))
18+
- properly encode mailer dsn components ([4fb08ad5](https://github.com/marcantondahmen/automad/commit/4fb08ad55dd69865110b75b7db531bd4300492d1))
19+
20+
## [v2.0.0-beta.28](https://github.com/marcantondahmen/automad/commit/a8d385b6fe4a97ae6014d7651b063df6cee7f126)
21+
22+
Thu, 30 Apr 2026 10:30:28 +0200
623

724
### Bugfixes
825

automad/assets/logo-email.png

1.02 KB
Loading

automad/lang/english.json

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@
33
"aboutAutomad": "About Automad",
44
"accountRecovery": "Account Recovery",
55
"accountRecoveryCancel": "I don't want recover my account.",
6+
"accountRecoveryInvalidButton": "Recover account",
7+
"accountRecoveryInvalidHeading": "Verification has failed",
8+
"accountRecoveryInvalidText": "The verification link you used is invalid or has already expired.",
69
"accountRecoveryNewPasswordHeading": "Create a new password",
7-
"accountRecoveryNewPasswordText": "An email with a verification code has been sent to you. Please enter the code below and set a new password.",
8-
"accountRecoveryStartButton": "Start account recovery",
9-
"accountRecoveryStartHeading": "Recover your account",
10-
"accountRecoveryStartText": "Enter your username or email address to start account recovery. You’ll be able to set a new password during this process. Two-factor authentication will be disabled.",
10+
"accountRecoveryNewPasswordText": "You can now set a new password in order to complete account recovery.",
11+
"accountRecoveryRequestTokenButton": "Recover account",
12+
"accountRecoveryRequestTokenHeading": "Recover your account",
13+
"accountRecoveryRequestTokenText": "Enter your username or email address to start account recovery. You’ll be able to set a new password during this process. Two-factor authentication will be disabled.",
1114
"accountRecoverySuccessHeading": "Account recovered",
1215
"accountRecoverySuccessText": "Your password has been updated and two-factor authentication has been disabled. You can now sign in and set up 2FA again.",
16+
"accountRecoveryTokenSentHeading": "Check your email",
17+
"accountRecoveryTokenSentText": "A verification email has been sent to your inbox. Click the link in the email to set a new password and complete account recovery.",
1318
"add": "Add",
1419
"addImage": "Add image",
1520
"addPage": "Add Page",
@@ -70,6 +75,19 @@
7075
"collapsibleSectionBlockTitle": "Collapsible Section",
7176
"collapsibleTooltipGroup": "Elements sharing the same group name behave like a typical accordion menu where opening one item closes all others.",
7277
"color": "Color",
78+
"completeAccountSetup": "Complete Account Setup",
79+
"completeAccountSetupInvalidButton": "Recover account",
80+
"completeAccountSetupInvalidHeading": "Verification has failed",
81+
"completeAccountSetupInvalidText": "The verification link you used is invalid or has already expired.",
82+
"completeAccountSetupNewPasswordHeading": "Create your password",
83+
"completeAccountSetupNewPasswordText": "Almost done. You can now set a password for your account and complete the setup process.",
84+
"completeAccountSetupRequestTokenButton": "Continue",
85+
"completeAccountSetupRequestTokenHeading": "Complete your account setup",
86+
"completeAccountSetupRequestTokenText": "To complete your account setup, please create a password. Click the button below to receive a verification email and start the process.",
87+
"completeAccountSetupSuccessHeading": "Password created",
88+
"completeAccountSetupSuccessText": "Your password has been created successfully and your account is ready. You can now sign in to the dashboard.",
89+
"completeAccountSetupTokenSentHeading": "Check your email",
90+
"completeAccountSetupTokenSentText": "A verification email has been sent to your inbox. Click the link in the email to set a password and complete your account setup.",
7391
"componentBlockTitle": "Component",
7492
"componentConfirmRemoval": "Do you really want to delete this component?",
7593
"componentCopy": "Copy",
@@ -159,16 +177,23 @@
159177
"ellipse": "Ellipse",
160178
"ellipseTool": "Ellipse",
161179
"email": "Email address",
180+
"emailAccountRecoveryButton": "Reset password",
181+
"emailAccountRecoverySubject": "Account recovery",
182+
"emailAccountRecoveryTextBottom": "In case you did not initiate this request yourself, you can safely ignore this message.",
183+
"emailAccountRecoveryTextTop": "you recently started the account recovery process for your account on {}. Click the button below to reset your password.",
184+
"emailAccountSetupButton": "Create password",
185+
"emailAccountSetupSubject": "Your account is almost ready",
186+
"emailAccountSetupTextTop": "great, your account on {} is almost ready. Click the button below to set your password and complete the setup process.",
162187
"emailAutomatic": "This email has been sent automatically. Please do not reply to this email.",
163188
"emailFrom": "Email sender address",
164189
"emailHello": "Hello",
165-
"emailInviteButton": "Create password now",
166-
"emailInviteSubject": "You have been added as a new user!",
167-
"emailInviteText": "a new user account on {} has been created for you. You can use the button below to create your password.",
190+
"emailInviteButton": "Complete account setup",
191+
"emailInviteSubject": "You have been invited as a new collaborator",
192+
"emailInviteText": "a new user account on {1} has been created for you with the username {2}. You can use the button below to complete your account setup.",
168193
"emailRequiredError": "Please enter a valid email address",
169-
"emailResetPasswordSubject": "Your authentication token",
170-
"emailResetPasswordTextBottom": "In case you did not initiate this request yourself, you can safely ignore this message.",
171-
"emailResetPasswordTextTop": "the requested authentication token for your account on {} can be found below. You can use that token in order to create a new password for you now.",
194+
"emailTestSuccessHeading": "Awesome",
195+
"emailTestSuccessSubject": "Mail configuration test",
196+
"emailTestSuccessText": "it seems that your email configuration is working correctly.",
172197
"enable": "Enable",
173198
"extension": "Extension",
174199
"feedDisabled": "The RSS feed is disabled",
@@ -393,9 +418,8 @@
393418
"passwordChangedSuccess": "Your password has been changed successfully!",
394419
"passwordRepeatError": "Please enter twice the same new password!",
395420
"passwordRequirementsError": "A password must at least contain one character of {1} and has a minimum length of {2} characters.",
396-
"passwordResetSave": "Save new password",
421+
"passwordResetSave": "Save password",
397422
"passwordResetToken": "Authentication token",
398-
"passwordResetVerificationError": "The authentication token is invalid or has expired already!",
399423
"passwordReuseError": "Don't reuse your old password!",
400424
"penTool": "Pen",
401425
"permissionsDeniedError": "Permissions denied",
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
/*
2+
* ....
3+
* .: '':.
4+
* :::: ':..
5+
* ::. ''..
6+
* .:'.. ..':.:::' . :. '':.
7+
* :. '' '' '. ::::.. ..:
8+
* ::::. ..':.. .'''::::: .
9+
* :::::::.. '..:::: :. :::: :
10+
* ::'':::::::. ':::.'':.:::: :
11+
* :.. ''::::::....': '':: :
12+
* :::::. '::::: : .. '' .
13+
* .''::::::::... ':::.'' ..'' :.''''.
14+
* :..:::''::::: :::::...:'' :..:
15+
* ::::::. ':::: :::::::: ..:: .
16+
* ::::::::.:::: :::::::: :'':.:: .''
17+
* ::: '::::::::.' ''::::: :.' '': :
18+
* ::: :::::::::..' :::: ::...' .
19+
* ::: .:::::::::: :::: :::: .:'
20+
* '::' ''::::::: :::: : :: :
21+
* ':::: :::: :'' .:
22+
* :::: :::: ..''
23+
* :::: ..:::: .:''
24+
* '''' '''''
25+
*
26+
*
27+
* AUTOMAD
28+
*
29+
* Copyright (c) 2026 by Marc Anton Dahmen
30+
* https://marcdahmen.de
31+
*
32+
* See LICENSE.md for license information.
33+
*/
34+
35+
import {
36+
App,
37+
Attr,
38+
CSS,
39+
getSearchParam,
40+
html,
41+
isInvite,
42+
Route,
43+
} from '@/admin/core';
44+
import { KeyValueMap } from '@/admin/types';
45+
import { FormComponent } from './Form';
46+
47+
const text = () => {
48+
return isInvite()
49+
? {
50+
startButton: App.text('completeAccountSetupRequestTokenButton'),
51+
startHeading: App.text(
52+
'completeAccountSetupRequestTokenHeading'
53+
),
54+
startText: App.text('completeAccountSetupRequestTokenText'),
55+
successHeading: App.text(
56+
'completeAccountSetupTokenSentHeading'
57+
),
58+
successText: App.text('completeAccountSetupTokenSentText'),
59+
}
60+
: {
61+
startButton: App.text('accountRecoveryRequestTokenButton'),
62+
startHeading: App.text('accountRecoveryRequestTokenHeading'),
63+
startText: App.text('accountRecoveryRequestTokenText'),
64+
successHeading: App.text('accountRecoveryTokenSentHeading'),
65+
successText: App.text('accountRecoveryTokenSentText'),
66+
};
67+
};
68+
69+
const cancel = () => {
70+
return isInvite()
71+
? ''
72+
: html`
73+
<p>
74+
<am-link
75+
class="${CSS.link}"
76+
${Attr.target}="${Route.login}"
77+
>
78+
${App.text('accountRecoveryCancel')}
79+
</am-link>
80+
</p>
81+
`;
82+
};
83+
84+
/**
85+
* The token request form.
86+
*
87+
* @extends FormComponent
88+
*/
89+
export class RequestPasswordResetTokenFormComponent extends FormComponent {
90+
/**
91+
* Process the response that is received after submitting the form.
92+
*
93+
* @param response
94+
* @async
95+
*/
96+
protected async processResponse(response: KeyValueMap): Promise<void> {
97+
if (response.data?.success) {
98+
this.renderSuccess();
99+
}
100+
}
101+
102+
/**
103+
* Render the initial form.
104+
*/
105+
protected init(): void {
106+
const inputInvite = isInvite()
107+
? html`
108+
<input
109+
type="hidden"
110+
name="name-or-email"
111+
value="$${getSearchParam('username')}"
112+
/>
113+
`
114+
: '';
115+
116+
const inputReset = isInvite()
117+
? ''
118+
: html`
119+
<input
120+
type="text"
121+
class="${CSS.input}"
122+
name="name-or-email"
123+
placeholder="${App.text('usernameOrEmail')}"
124+
required
125+
/>
126+
`;
127+
128+
this.innerHTML = html`
129+
<h2>${text().startHeading}</h2>
130+
<am-form-error></am-form-error>
131+
<div class="${CSS.card}">
132+
<div class="${CSS.cardBody} ${CSS.cardBodyLarge}">
133+
${text().startText}
134+
</div>
135+
<input
136+
type="hidden"
137+
name="type"
138+
value="${getSearchParam('type')}"
139+
/>
140+
${inputInvite}
141+
<div class="${CSS.cardForm}">
142+
${inputReset}
143+
<div class="${CSS.cardFormButtons}">
144+
<am-submit class="${CSS.button} ${CSS.buttonPrimary}">
145+
${text().startButton}
146+
</am-submit>
147+
</div>
148+
</div>
149+
</div>
150+
${cancel()}
151+
`;
152+
}
153+
154+
/**
155+
* Render the success message.
156+
*/
157+
private renderSuccess(): void {
158+
this.innerHTML = html`
159+
<h2>${text().successHeading}</h2>
160+
<div class="${CSS.card}">
161+
<div class="${CSS.cardIcon}">
162+
<i class="bi bi-envelope-paper"></i>
163+
</div>
164+
<div class="${CSS.cardBody} ${CSS.cardBodyLarge}">
165+
${text().successText}
166+
</div>
167+
</div>
168+
`;
169+
}
170+
}
171+
172+
customElements.define(
173+
'am-request-password-reset-token-form',
174+
RequestPasswordResetTokenFormComponent
175+
);

0 commit comments

Comments
 (0)