From 5d5d1f94d78248283d35035f8a5f12dcb852694d Mon Sep 17 00:00:00 2001 From: Olivier Auverlot Date: Sat, 18 Oct 2025 12:19:15 +0200 Subject: [PATCH 01/15] The login component is an authentication form for users of an application. --- .../sqlpage/migrations/68_login.sql | 52 +++++++++++ .../99_shared_id_class_attributes.sql | 6 +- sqlpage/templates/login.handlebars | 89 +++++++++++++++++++ 3 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 examples/official-site/sqlpage/migrations/68_login.sql create mode 100644 sqlpage/templates/login.handlebars diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql new file mode 100644 index 00000000..7230f759 --- /dev/null +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -0,0 +1,52 @@ +INSERT INTO component(name, icon, description, introduced_in_version) VALUES + ('login', 'password-user', ' +The login component is an authentication form for users of an application. + +It allows the entry of a user account consisting of a username and a password. + +It offers additional features such as the ability to request session persistence or to reset the password.', '0.39.0'); + +INSERT INTO parameter(component, name, description, type, top_level, optional) SELECT 'login', * FROM (VALUES + ('title','Title of the authentication form.','TEXT',TRUE,TRUE), + ('enctype','Form data encoding.','TEXT',TRUE,TRUE), + ('action','An optional link to a target page that will handle the results of the form. ','TEXT',TRUE,TRUE), + ('username','User account identifier.','TEXT',TRUE,FALSE), + ('password','User password.','TEXT',TRUE,FALSE), + ('image','The URL of an centered image displayed before the title.','URL',TRUE,TRUE), + ('forgot_password_text','A text for the link allowing the user to reset their password. If the text is empty, the link is not displayed.','TEXT',TRUE,TRUE), + ('forgot_password_link','The link to the page allowing the user to reset their password.','TEXT',TRUE,TRUE), + ('remember_me_text','A text for the option allowing the user to request the preservation of their work session. The name of the field is remember. If the text is empty, the option is not displayed.','TEXT',TRUE,TRUE), + ('footer','A text placed at the bottom of the authentication form.','TEXT',TRUE,TRUE), + ('footer_md','A markdown text placed at the bottom of the authentication form. Useful for creating links to other pages (creating a new account, contacting technical support, etc.).','TEXT',TRUE,TRUE), + ('validate','The text to display in the button at the bottom of the form that submits the values.','TEXT',TRUE,FALSE), + ('validate_color','The color of the button at the bottom of the form that submits the values. Omit this property to use the default color.','COLOR',TRUE,TRUE), + ('validate_shape','The shape of the validation button.','TEXT',TRUE,TRUE), + ('validate_outline','A color to outline the validation button.','COLOR',TRUE,TRUE), + ('validate_size','The size of the validation button.','TEXT',TRUE,TRUE) +) x; + +-- Insert example(s) for the component +INSERT INTO example(component, description, properties) +VALUES ( + 'login', + 'Using the main options of the login component', + JSON( + '[ + { + "component": "login", + "action": "login.sql", + "image": "../assets/icon.webp", + "title": "Please login to your account", + "username": "Username", + "password": "Password", + "forgot_password_text": "Forgot your password?", + "forgot_password_link": "reset_password.sql", + "remember_me_text": "Remember me", + "footer_md": "Don''t have an account? [Register here](register.sql)", + "validate": "Sign in" + } + ]' + ) + ); + +-- 265707.png \ No newline at end of file diff --git a/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql b/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql index 47e66576..df054541 100644 --- a/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql +++ b/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql @@ -18,7 +18,8 @@ FROM (VALUES ('title', TRUE), ('tracking', TRUE), ('text', TRUE), - ('carousel', TRUE) + ('carousel', TRUE), + ('login', TRUE) ); INSERT INTO parameter(component, top_level, name, description, type, optional) @@ -49,6 +50,7 @@ FROM (VALUES ('timeline', FALSE), ('title', TRUE), ('tracking', TRUE), - ('carousel', TRUE) + ('carousel', TRUE), + ('login', TRUE) ); diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars new file mode 100644 index 00000000..f292a18d --- /dev/null +++ b/sqlpage/templates/login.handlebars @@ -0,0 +1,89 @@ +
+
+
+
+ {{#if image}} +
+ +
+ {{/if}} + {{#if title}} +

{{title}}

+ {{/if}} + +
+ + + + + + + + +
+ +
+ + + + + + + + + +
+ {{#if remember_me_text}} + + {{/if}} +
+ +
+ {{#if (or footer footer_md)}} +
+
+ + {{#if footer}} + {{footer}} + {{else}} + {{#if footer_md}} + {{{markdown footer_md}}} + {{/if}} + {{/if}} + +
+ {{/if}} +
+
+
+
From b356cc8904d94ea6f9c462a92f66646c8b480a82 Mon Sep 17 00:00:00 2001 From: Olivier Auverlot Date: Fri, 24 Oct 2025 08:04:39 +0200 Subject: [PATCH 02/15] username_icon and password_icon attributes --- .../sqlpage/migrations/68_login.sql | 6 ++-- sqlpage/templates/login.handlebars | 28 +++++-------------- 2 files changed, 11 insertions(+), 23 deletions(-) diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql index 7230f759..dad03a8e 100644 --- a/examples/official-site/sqlpage/migrations/68_login.sql +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -12,6 +12,8 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S ('action','An optional link to a target page that will handle the results of the form. ','TEXT',TRUE,TRUE), ('username','User account identifier.','TEXT',TRUE,FALSE), ('password','User password.','TEXT',TRUE,FALSE), + ('username_icon','Icon to display on the left side of the input field, on the same line.','ICON',TRUE,TRUE), + ('password_icon','Icon to display on the left side of the input field, on the same line.','ICON',TRUE,TRUE), ('image','The URL of an centered image displayed before the title.','URL',TRUE,TRUE), ('forgot_password_text','A text for the link allowing the user to reset their password. If the text is empty, the link is not displayed.','TEXT',TRUE,TRUE), ('forgot_password_link','The link to the page allowing the user to reset their password.','TEXT',TRUE,TRUE), @@ -39,6 +41,8 @@ VALUES ( "title": "Please login to your account", "username": "Username", "password": "Password", + "username_icon": "user", + "password_icon": "lock", "forgot_password_text": "Forgot your password?", "forgot_password_link": "reset_password.sql", "remember_me_text": "Remember me", @@ -48,5 +52,3 @@ VALUES ( ]' ) ); - --- 265707.png \ No newline at end of file diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars index f292a18d..258622a8 100644 --- a/sqlpage/templates/login.handlebars +++ b/sqlpage/templates/login.handlebars @@ -1,4 +1,4 @@ -
+
{{username}}
- - - - - - - + {{#if username_icon}} + {{icon_img username_icon}} + {{/if}}
- - - - - - - - + {{#if password_icon}} + {{~icon_img password_icon~}} + {{/if}}
{{#if remember_me_text}} From cb8fa2dc16e454e7068e6723912ed3c34267a3bc Mon Sep 17 00:00:00 2001 From: Olivier Auverlot Date: Fri, 24 Oct 2025 08:09:32 +0200 Subject: [PATCH 03/15] Fixing a regression with the class attribute. --- sqlpage/templates/login.handlebars | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars index 258622a8..a664e0cc 100644 --- a/sqlpage/templates/login.handlebars +++ b/sqlpage/templates/login.handlebars @@ -1,4 +1,4 @@ -
+
Date: Fri, 24 Oct 2025 08:29:35 +0200 Subject: [PATCH 04/15] Documentation improved --- .../official-site/sqlpage/migrations/68_login.sql | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql index dad03a8e..1cbed299 100644 --- a/examples/official-site/sqlpage/migrations/68_login.sql +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -1,10 +1,15 @@ INSERT INTO component(name, icon, description, introduced_in_version) VALUES ('login', 'password-user', ' -The login component is an authentication form for users of an application. +The login component is an authentication form with numerous customization options. +It offers the main functionalities for this type of form. +The user can enter their username and password. +There are many optional attributes such as the use of icons on input fields, the insertion of a link to a page to reset the password, an option for the application to maintain the user''s session via a cookie. +It is also possible to set the title of the form, display the company logo, or customize the appearance of the form submission button. -It allows the entry of a user account consisting of a username and a password. +This component should be used in conjunction with other components such as [authentication](component.sql?component=authentication) and [cookie](component.sql?component=cookie). +It does not implement any logic and simply collects the username and password to pass them to the code responsible for authentication. -It offers additional features such as the ability to request session persistence or to reset the password.', '0.39.0'); +', '0.39.0'); INSERT INTO parameter(component, name, description, type, top_level, optional) SELECT 'login', * FROM (VALUES ('title','Title of the authentication form.','TEXT',TRUE,TRUE), From ce4ffd33940362efa2da07d6e87282adff149827 Mon Sep 17 00:00:00 2001 From: Olivier Auverlot Date: Fri, 24 Oct 2025 08:45:57 +0200 Subject: [PATCH 05/15] Documentation improved --- examples/official-site/sqlpage/migrations/68_login.sql | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql index 1cbed299..6d906ae5 100644 --- a/examples/official-site/sqlpage/migrations/68_login.sql +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -3,12 +3,17 @@ INSERT INTO component(name, icon, description, introduced_in_version) VALUES The login component is an authentication form with numerous customization options. It offers the main functionalities for this type of form. The user can enter their username and password. -There are many optional attributes such as the use of icons on input fields, the insertion of a link to a page to reset the password, an option for the application to maintain the user''s session via a cookie. +There are many optional attributes such as the use of icons on input fields, the insertion of a link to a page to reset the password, an option for the application to maintain the user''s identity via a cookie. It is also possible to set the title of the form, display the company logo, or customize the appearance of the form submission button. This component should be used in conjunction with other components such as [authentication](component.sql?component=authentication) and [cookie](component.sql?component=cookie). It does not implement any logic and simply collects the username and password to pass them to the code responsible for authentication. +A few things to know : +- The form uses the POST method to transmit information to the destination page, +- The user''s username and password are entered into fields with the names `username` and `password`, +- To obtain the values of username and password, you must use the variables `:username` and `:password`, +- To know if the user wants their identity to be remembered, you must read the value of the variable `:remember`. ', '0.39.0'); INSERT INTO parameter(component, name, description, type, top_level, optional) SELECT 'login', * FROM (VALUES @@ -22,7 +27,7 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S ('image','The URL of an centered image displayed before the title.','URL',TRUE,TRUE), ('forgot_password_text','A text for the link allowing the user to reset their password. If the text is empty, the link is not displayed.','TEXT',TRUE,TRUE), ('forgot_password_link','The link to the page allowing the user to reset their password.','TEXT',TRUE,TRUE), - ('remember_me_text','A text for the option allowing the user to request the preservation of their work session. The name of the field is remember. If the text is empty, the option is not displayed.','TEXT',TRUE,TRUE), + ('remember_me_text','A text for the option allowing the user to request the preservation of their identity. If the text is empty, the option is not displayed.','TEXT',TRUE,TRUE), ('footer','A text placed at the bottom of the authentication form.','TEXT',TRUE,TRUE), ('footer_md','A markdown text placed at the bottom of the authentication form. Useful for creating links to other pages (creating a new account, contacting technical support, etc.).','TEXT',TRUE,TRUE), ('validate','The text to display in the button at the bottom of the form that submits the values.','TEXT',TRUE,FALSE), From 722dc740fa9df5cd34b8d5e2b2907d2cf8776a45 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Mon, 27 Oct 2025 23:07:57 +0100 Subject: [PATCH 06/15] add an error_message property to the login component - Updated SQL queries in `create_session_token.sql` and `login.sql` to use consistent parameter naming conventions. - Enhanced the login form in `login.sql` to include an error message for failed login attempts. - Added a new parameter `error_message` in the migration file for better user feedback. - Modified the Handlebars template to display the error message when applicable, improving user experience during authentication. --- .../authentication/create_session_token.sql | 6 +++--- .../examples/authentication/login.sql | 17 +++++++++++------ .../sqlpage/migrations/68_login.sql | 1 + sqlpage/templates/login.handlebars | 12 +++++++++++- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/examples/official-site/examples/authentication/create_session_token.sql b/examples/official-site/examples/authentication/create_session_token.sql index 645fedc4..8ea8cd19 100644 --- a/examples/official-site/examples/authentication/create_session_token.sql +++ b/examples/official-site/examples/authentication/create_session_token.sql @@ -4,12 +4,12 @@ delete from user_sessions where created_at < datetime('now', '-1 day'); -- check that the SELECT 'authentication' AS component, 'login.sql?failed' AS link, -- redirect to the login page on error - (SELECT password_hash FROM users WHERE username = :Username) AS password_hash, -- this is a hash of the password 'admin' - :Password AS password; -- this is the password that the user sent through our form in 'index.sql' + (SELECT password_hash FROM users WHERE username = :username) AS password_hash, -- this is a hash of the password 'admin' + :password AS password; -- this is the password that the user sent through our form in 'index.sql' -- if we haven't been redirected, then the password is correct -- create a new session -insert into user_sessions (session_token, username) values (sqlpage.random_string(32), :Username) +insert into user_sessions (session_token, username) values (sqlpage.random_string(32), :username) returning 'cookie' as component, 'session_token' as name, session_token as value; -- redirect to the authentication example home page diff --git a/examples/official-site/examples/authentication/login.sql b/examples/official-site/examples/authentication/login.sql index b634de30..264bbc4a 100644 --- a/examples/official-site/examples/authentication/login.sql +++ b/examples/official-site/examples/authentication/login.sql @@ -1,10 +1,15 @@ select 'dynamic' as component, properties FROM example WHERE component = 'shell' LIMIT 1; -select 'form' as component, 'Authentication' as title, 'Log in' as validate, 'create_session_token.sql' as action; -select 'Username' as name, 'user' as prefix_icon, 'admin' as placeholder; -select 'Password' as name, 'lock' as prefix_icon, 'admin' as placeholder, 'password' as type; - -select 'alert' as component, 'danger' as color, 'Invalid username or password' as title where $failed is not null; +select + 'login' as component, + 'create_session_token.sql' as action, + '/assets/icon.webp' as image, + 'Demo Login Form' as title, + 'Username' as username, + 'Password' as password, + case when $failed is not null then 'Invalid username or password. In this demo, you can log in with admin / admin.' end as error_message, + 'In this demo, the username is "admin" and the password is "admin".' as footer_md, + 'Sign in' as validate; select 'text' as component, ' @@ -12,7 +17,7 @@ select 'text' as component, ' This is a simple example of an authentication form. It uses - - the [`form`](/documentation.sql?component=form#component) component to create a login form + - the [`login`](/documentation.sql?component=login#component) component to create a login form - the [`authentication`](/documentation.sql?component=authentication#component) component to check the user password - the [`cookie`](/documentation.sql?component=cookie#component) component to store a unique session token in the user browser - the [`redirect`](/documentation.sql?component=redirect#component) component to redirect the user to the login page if they are not logged in diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql index 6d906ae5..522c8672 100644 --- a/examples/official-site/sqlpage/migrations/68_login.sql +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -20,6 +20,7 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S ('title','Title of the authentication form.','TEXT',TRUE,TRUE), ('enctype','Form data encoding.','TEXT',TRUE,TRUE), ('action','An optional link to a target page that will handle the results of the form. ','TEXT',TRUE,TRUE), + ('error_message','An error message to display above the form, typically shown after a failed login attempt.','TEXT',TRUE,TRUE), ('username','User account identifier.','TEXT',TRUE,FALSE), ('password','User password.','TEXT',TRUE,FALSE), ('username_icon','Icon to display on the left side of the input field, on the same line.','ICON',TRUE,TRUE), diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars index a664e0cc..54808bfa 100644 --- a/sqlpage/templates/login.handlebars +++ b/sqlpage/templates/login.handlebars @@ -13,13 +13,23 @@ {{/if}} > {{#if image}} -
+
{{/if}} {{#if title}}

{{title}}

{{/if}} + {{#if error_message}} + + {{/if}}
{{#if username_icon}} From cfea904e5d30d50494c100515b744802501b883d Mon Sep 17 00:00:00 2001 From: Olivier Auverlot Date: Sat, 18 Oct 2025 12:19:15 +0200 Subject: [PATCH 07/15] The login component is an authentication form for users of an application. --- .../sqlpage/migrations/68_login.sql | 52 +++++++++++ .../99_shared_id_class_attributes.sql | 6 +- sqlpage/templates/login.handlebars | 89 +++++++++++++++++++ 3 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 examples/official-site/sqlpage/migrations/68_login.sql create mode 100644 sqlpage/templates/login.handlebars diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql new file mode 100644 index 00000000..7230f759 --- /dev/null +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -0,0 +1,52 @@ +INSERT INTO component(name, icon, description, introduced_in_version) VALUES + ('login', 'password-user', ' +The login component is an authentication form for users of an application. + +It allows the entry of a user account consisting of a username and a password. + +It offers additional features such as the ability to request session persistence or to reset the password.', '0.39.0'); + +INSERT INTO parameter(component, name, description, type, top_level, optional) SELECT 'login', * FROM (VALUES + ('title','Title of the authentication form.','TEXT',TRUE,TRUE), + ('enctype','Form data encoding.','TEXT',TRUE,TRUE), + ('action','An optional link to a target page that will handle the results of the form. ','TEXT',TRUE,TRUE), + ('username','User account identifier.','TEXT',TRUE,FALSE), + ('password','User password.','TEXT',TRUE,FALSE), + ('image','The URL of an centered image displayed before the title.','URL',TRUE,TRUE), + ('forgot_password_text','A text for the link allowing the user to reset their password. If the text is empty, the link is not displayed.','TEXT',TRUE,TRUE), + ('forgot_password_link','The link to the page allowing the user to reset their password.','TEXT',TRUE,TRUE), + ('remember_me_text','A text for the option allowing the user to request the preservation of their work session. The name of the field is remember. If the text is empty, the option is not displayed.','TEXT',TRUE,TRUE), + ('footer','A text placed at the bottom of the authentication form.','TEXT',TRUE,TRUE), + ('footer_md','A markdown text placed at the bottom of the authentication form. Useful for creating links to other pages (creating a new account, contacting technical support, etc.).','TEXT',TRUE,TRUE), + ('validate','The text to display in the button at the bottom of the form that submits the values.','TEXT',TRUE,FALSE), + ('validate_color','The color of the button at the bottom of the form that submits the values. Omit this property to use the default color.','COLOR',TRUE,TRUE), + ('validate_shape','The shape of the validation button.','TEXT',TRUE,TRUE), + ('validate_outline','A color to outline the validation button.','COLOR',TRUE,TRUE), + ('validate_size','The size of the validation button.','TEXT',TRUE,TRUE) +) x; + +-- Insert example(s) for the component +INSERT INTO example(component, description, properties) +VALUES ( + 'login', + 'Using the main options of the login component', + JSON( + '[ + { + "component": "login", + "action": "login.sql", + "image": "../assets/icon.webp", + "title": "Please login to your account", + "username": "Username", + "password": "Password", + "forgot_password_text": "Forgot your password?", + "forgot_password_link": "reset_password.sql", + "remember_me_text": "Remember me", + "footer_md": "Don''t have an account? [Register here](register.sql)", + "validate": "Sign in" + } + ]' + ) + ); + +-- 265707.png \ No newline at end of file diff --git a/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql b/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql index 47e66576..df054541 100644 --- a/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql +++ b/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql @@ -18,7 +18,8 @@ FROM (VALUES ('title', TRUE), ('tracking', TRUE), ('text', TRUE), - ('carousel', TRUE) + ('carousel', TRUE), + ('login', TRUE) ); INSERT INTO parameter(component, top_level, name, description, type, optional) @@ -49,6 +50,7 @@ FROM (VALUES ('timeline', FALSE), ('title', TRUE), ('tracking', TRUE), - ('carousel', TRUE) + ('carousel', TRUE), + ('login', TRUE) ); diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars new file mode 100644 index 00000000..f292a18d --- /dev/null +++ b/sqlpage/templates/login.handlebars @@ -0,0 +1,89 @@ +
+
+
+ + {{#if image}} +
+ +
+ {{/if}} + {{#if title}} +

{{title}}

+ {{/if}} + +
+ + + + + + + + +
+ +
+ + + + + + + + + +
+ {{#if remember_me_text}} + + {{/if}} +
+ +
+ {{#if (or footer footer_md)}} +
+
+ + {{#if footer}} + {{footer}} + {{else}} + {{#if footer_md}} + {{{markdown footer_md}}} + {{/if}} + {{/if}} + +
+ {{/if}} + +
+
+
From eb1f43c6e1567104a4ce81d605404c37c78b7177 Mon Sep 17 00:00:00 2001 From: Olivier Auverlot Date: Fri, 24 Oct 2025 08:04:39 +0200 Subject: [PATCH 08/15] username_icon and password_icon attributes --- .../sqlpage/migrations/68_login.sql | 6 ++-- sqlpage/templates/login.handlebars | 28 +++++-------------- 2 files changed, 11 insertions(+), 23 deletions(-) diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql index 7230f759..dad03a8e 100644 --- a/examples/official-site/sqlpage/migrations/68_login.sql +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -12,6 +12,8 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S ('action','An optional link to a target page that will handle the results of the form. ','TEXT',TRUE,TRUE), ('username','User account identifier.','TEXT',TRUE,FALSE), ('password','User password.','TEXT',TRUE,FALSE), + ('username_icon','Icon to display on the left side of the input field, on the same line.','ICON',TRUE,TRUE), + ('password_icon','Icon to display on the left side of the input field, on the same line.','ICON',TRUE,TRUE), ('image','The URL of an centered image displayed before the title.','URL',TRUE,TRUE), ('forgot_password_text','A text for the link allowing the user to reset their password. If the text is empty, the link is not displayed.','TEXT',TRUE,TRUE), ('forgot_password_link','The link to the page allowing the user to reset their password.','TEXT',TRUE,TRUE), @@ -39,6 +41,8 @@ VALUES ( "title": "Please login to your account", "username": "Username", "password": "Password", + "username_icon": "user", + "password_icon": "lock", "forgot_password_text": "Forgot your password?", "forgot_password_link": "reset_password.sql", "remember_me_text": "Remember me", @@ -48,5 +52,3 @@ VALUES ( ]' ) ); - --- 265707.png \ No newline at end of file diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars index f292a18d..258622a8 100644 --- a/sqlpage/templates/login.handlebars +++ b/sqlpage/templates/login.handlebars @@ -1,4 +1,4 @@ -
+
{{username}}
- - - - - - - + {{#if username_icon}} + {{icon_img username_icon}} + {{/if}}
- - - - - - - - + {{#if password_icon}} + {{~icon_img password_icon~}} + {{/if}}
{{#if remember_me_text}} From 36ab34f827fe7cfaf761f86c8752e861539eca2c Mon Sep 17 00:00:00 2001 From: Olivier Auverlot Date: Fri, 24 Oct 2025 08:09:32 +0200 Subject: [PATCH 09/15] Fixing a regression with the class attribute. --- sqlpage/templates/login.handlebars | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars index 258622a8..a664e0cc 100644 --- a/sqlpage/templates/login.handlebars +++ b/sqlpage/templates/login.handlebars @@ -1,4 +1,4 @@ -
+
Date: Fri, 24 Oct 2025 08:29:35 +0200 Subject: [PATCH 10/15] Documentation improved --- .../official-site/sqlpage/migrations/68_login.sql | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql index dad03a8e..1cbed299 100644 --- a/examples/official-site/sqlpage/migrations/68_login.sql +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -1,10 +1,15 @@ INSERT INTO component(name, icon, description, introduced_in_version) VALUES ('login', 'password-user', ' -The login component is an authentication form for users of an application. +The login component is an authentication form with numerous customization options. +It offers the main functionalities for this type of form. +The user can enter their username and password. +There are many optional attributes such as the use of icons on input fields, the insertion of a link to a page to reset the password, an option for the application to maintain the user''s session via a cookie. +It is also possible to set the title of the form, display the company logo, or customize the appearance of the form submission button. -It allows the entry of a user account consisting of a username and a password. +This component should be used in conjunction with other components such as [authentication](component.sql?component=authentication) and [cookie](component.sql?component=cookie). +It does not implement any logic and simply collects the username and password to pass them to the code responsible for authentication. -It offers additional features such as the ability to request session persistence or to reset the password.', '0.39.0'); +', '0.39.0'); INSERT INTO parameter(component, name, description, type, top_level, optional) SELECT 'login', * FROM (VALUES ('title','Title of the authentication form.','TEXT',TRUE,TRUE), From 3d7f780fbd3002b930745b229f0b78bcb6768e2f Mon Sep 17 00:00:00 2001 From: Olivier Auverlot Date: Fri, 24 Oct 2025 08:45:57 +0200 Subject: [PATCH 11/15] Documentation improved --- examples/official-site/sqlpage/migrations/68_login.sql | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql index 1cbed299..6d906ae5 100644 --- a/examples/official-site/sqlpage/migrations/68_login.sql +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -3,12 +3,17 @@ INSERT INTO component(name, icon, description, introduced_in_version) VALUES The login component is an authentication form with numerous customization options. It offers the main functionalities for this type of form. The user can enter their username and password. -There are many optional attributes such as the use of icons on input fields, the insertion of a link to a page to reset the password, an option for the application to maintain the user''s session via a cookie. +There are many optional attributes such as the use of icons on input fields, the insertion of a link to a page to reset the password, an option for the application to maintain the user''s identity via a cookie. It is also possible to set the title of the form, display the company logo, or customize the appearance of the form submission button. This component should be used in conjunction with other components such as [authentication](component.sql?component=authentication) and [cookie](component.sql?component=cookie). It does not implement any logic and simply collects the username and password to pass them to the code responsible for authentication. +A few things to know : +- The form uses the POST method to transmit information to the destination page, +- The user''s username and password are entered into fields with the names `username` and `password`, +- To obtain the values of username and password, you must use the variables `:username` and `:password`, +- To know if the user wants their identity to be remembered, you must read the value of the variable `:remember`. ', '0.39.0'); INSERT INTO parameter(component, name, description, type, top_level, optional) SELECT 'login', * FROM (VALUES @@ -22,7 +27,7 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S ('image','The URL of an centered image displayed before the title.','URL',TRUE,TRUE), ('forgot_password_text','A text for the link allowing the user to reset their password. If the text is empty, the link is not displayed.','TEXT',TRUE,TRUE), ('forgot_password_link','The link to the page allowing the user to reset their password.','TEXT',TRUE,TRUE), - ('remember_me_text','A text for the option allowing the user to request the preservation of their work session. The name of the field is remember. If the text is empty, the option is not displayed.','TEXT',TRUE,TRUE), + ('remember_me_text','A text for the option allowing the user to request the preservation of their identity. If the text is empty, the option is not displayed.','TEXT',TRUE,TRUE), ('footer','A text placed at the bottom of the authentication form.','TEXT',TRUE,TRUE), ('footer_md','A markdown text placed at the bottom of the authentication form. Useful for creating links to other pages (creating a new account, contacting technical support, etc.).','TEXT',TRUE,TRUE), ('validate','The text to display in the button at the bottom of the form that submits the values.','TEXT',TRUE,FALSE), From cc95ae25dee3e671c6f604268d9bd1ebe7e90c98 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Mon, 27 Oct 2025 18:13:52 +0100 Subject: [PATCH 12/15] Improve login component documentation and usability Add complete example with database schema, credential processing, and page protection. Update authentication migration to reference new login component. Enhance login template with default icons and autocomplete attributes. Make validate parameter optional with sensible default. --- .../sqlpage/migrations/07_authentication.sql | 8 +- .../sqlpage/migrations/68_login.sql | 78 +++++++++++++++---- sqlpage/templates/login.handlebars | 14 ++-- 3 files changed, 71 insertions(+), 29 deletions(-) diff --git a/examples/official-site/sqlpage/migrations/07_authentication.sql b/examples/official-site/sqlpage/migrations/07_authentication.sql index fd342fc6..c759dee8 100644 --- a/examples/official-site/sqlpage/migrations/07_authentication.sql +++ b/examples/official-site/sqlpage/migrations/07_authentication.sql @@ -14,7 +14,7 @@ you have two main options: - does not require any external service - gives you fine-grained control over - which pages and actions are protected - - the look of the login form + - the look of the [login form](?component=login) - the duration of the session - the permissions of each user 2. [**Single sign-on**](/sso) @@ -128,12 +128,10 @@ Then, in all the pages that require authentication, you check if the cookie is p You can check if the user has sent the correct password in a form, and if not, redirect them to a login page. -Create a login form in a file called `login.sql`: +Create a login form in a file called `login.sql` that uses the [login component](?component=login): ```sql -select ''form'' as component, ''Authentication'' as title, ''Log in'' as validate, ''create_session_token.sql'' as action; -select ''Username'' as name, ''admin'' as placeholder; -select ''Password'' as name, ''admin'' as placeholder, ''password'' as type; +select ''login'' as component; ``` And then, in `create_session_token.sql` : diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql index 6d906ae5..a8a18c60 100644 --- a/examples/official-site/sqlpage/migrations/68_login.sql +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -1,13 +1,15 @@ INSERT INTO component(name, icon, description, introduced_in_version) VALUES ('login', 'password-user', ' The login component is an authentication form with numerous customization options. -It offers the main functionalities for this type of form. -The user can enter their username and password. +The user enters their username and password, +and is then redirected to another page, where you can use the [authentication](?component=authentication) component +to check the credentials. + There are many optional attributes such as the use of icons on input fields, the insertion of a link to a page to reset the password, an option for the application to maintain the user''s identity via a cookie. It is also possible to set the title of the form, display the company logo, or customize the appearance of the form submission button. -This component should be used in conjunction with other components such as [authentication](component.sql?component=authentication) and [cookie](component.sql?component=cookie). -It does not implement any logic and simply collects the username and password to pass them to the code responsible for authentication. +This component does not implement any logic. It simply collects the username and password to pass them to the code responsible for authentication. +It should be used in conjunction with other components such as [authentication](component.sql?component=authentication) and [cookie](component.sql?component=cookie) to actually allow or deny access. A few things to know : - The form uses the POST method to transmit information to the destination page, @@ -20,8 +22,8 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S ('title','Title of the authentication form.','TEXT',TRUE,TRUE), ('enctype','Form data encoding.','TEXT',TRUE,TRUE), ('action','An optional link to a target page that will handle the results of the form. ','TEXT',TRUE,TRUE), - ('username','User account identifier.','TEXT',TRUE,FALSE), - ('password','User password.','TEXT',TRUE,FALSE), + ('username','Label and placeholder for the user account identifier text field.','TEXT',TRUE,FALSE), + ('password','Label and placeholder for the password field.','TEXT',TRUE,FALSE), ('username_icon','Icon to display on the left side of the input field, on the same line.','ICON',TRUE,TRUE), ('password_icon','Icon to display on the left side of the input field, on the same line.','ICON',TRUE,TRUE), ('image','The URL of an centered image displayed before the title.','URL',TRUE,TRUE), @@ -30,7 +32,7 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S ('remember_me_text','A text for the option allowing the user to request the preservation of their identity. If the text is empty, the option is not displayed.','TEXT',TRUE,TRUE), ('footer','A text placed at the bottom of the authentication form.','TEXT',TRUE,TRUE), ('footer_md','A markdown text placed at the bottom of the authentication form. Useful for creating links to other pages (creating a new account, contacting technical support, etc.).','TEXT',TRUE,TRUE), - ('validate','The text to display in the button at the bottom of the form that submits the values.','TEXT',TRUE,FALSE), + ('validate','The text to display in the button at the bottom of the form that submits the values.','TEXT',TRUE,TRUE), ('validate_color','The color of the button at the bottom of the form that submits the values. Omit this property to use the default color.','COLOR',TRUE,TRUE), ('validate_shape','The shape of the validation button.','TEXT',TRUE,TRUE), ('validate_outline','A color to outline the validation button.','COLOR',TRUE,TRUE), @@ -41,10 +43,57 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S INSERT INTO example(component, description, properties) VALUES ( 'login', - 'Using the main options of the login component', - JSON( - '[ - { + 'This example shows how to implement a complete custom login system in your SQLPage app. + +### Database schema + +`sqlpage/migrations/001_users.sql` + +```sql +create table account ( + username TEXT PRIMARY KEY, + password_hash TEXT NOT NULL +); + +create table session ( + id TEXT PRIMARY KEY, + username TEXT REFERENCES account(username) + -- you could add more fields for session expiration, session metadata tracking... +); +``` + +### Process user credentials + +Create a file named `login.sql`: + +```sql +SELECT ''authentication'' AS component, + ''/'' AS link, -- redirect the user to the homepage if the password is incorrect + (SELECT password_hash FROM account WHERE username = :username) AS password_hash, + :password AS password; + +-- The code after this point is only executed if the user has sent the correct password + +-- Generate a random session token +INSERT INTO session (id, username) +VALUES (sqlpage.random_string(32), :username) +RETURNING ''cookie'' AS component, ''session_token'' AS name, id AS value, +case when :remember is null then 3600*24*365 else 3600*4 end as max_age; + +select ''redirect'' as component, ''protected.sql'' as link; -- once logged in, redirect to the protected page +``` + +### Protect pages + +Start all protected pages with + +```sql +select ''redirect'' as component, ''/'' as link where not exists (select 1 from session where id=sqlpage.cookie(''session_token'')); +``` + +### Login form on the home page +', + JSON('[{ "component": "login", "action": "login.sql", "image": "../assets/icon.webp", @@ -58,7 +107,6 @@ VALUES ( "remember_me_text": "Remember me", "footer_md": "Don''t have an account? [Register here](register.sql)", "validate": "Sign in" - } - ]' - ) - ); + }]') +), + ('login', 'Most basic login form', JSON('[{"component": "login"}]')); diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars index a664e0cc..723fdb87 100644 --- a/sqlpage/templates/login.handlebars +++ b/sqlpage/templates/login.handlebars @@ -22,10 +22,8 @@ {{/if}}
- {{#if username_icon}} - {{icon_img username_icon}} - {{/if}} - + {{icon_img (default username_icon 'user-circle')}} +
- {{#if password_icon}} - {{~icon_img password_icon~}} - {{/if}} - + {{~icon_img (default password_icon 'key')~}} +
{{#if remember_me_text}}
{{#if (or footer footer_md)}}
From d542a8ae79e1ffe7bc83838cf1ea7c5a286c784a Mon Sep 17 00:00:00 2001 From: lovasoa Date: Mon, 27 Oct 2025 23:23:44 +0100 Subject: [PATCH 13/15] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4e00999..ccb59417 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - image - Fixed a memory corruption issue in the builtin odbc driver manager - ODBC: fix using globally installed system drivers by their name in debian-based linux distributions. + - New [login](https://sql-page.com/component.sql?component=table) component. ## v0.38.0 From 5ee781cf40950890f53c94218bde20e4378977fd Mon Sep 17 00:00:00 2001 From: lovasoa Date: Mon, 27 Oct 2025 23:36:29 +0100 Subject: [PATCH 14/15] use the login component in the user auth example --- .../user-authentication/docker-compose.yml | 2 ++ examples/user-authentication/signin.sql | 21 +++++++------------ sqlpage/templates/login.handlebars | 7 ++++--- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/examples/user-authentication/docker-compose.yml b/examples/user-authentication/docker-compose.yml index 5108ac1e..7738221d 100644 --- a/examples/user-authentication/docker-compose.yml +++ b/examples/user-authentication/docker-compose.yml @@ -1,6 +1,8 @@ services: web: image: lovasoa/sqlpage:main # main is cutting edge, use sqlpage/SQLPage:latest for the latest stable version + build: + context: ".." ports: - "8080:8080" volumes: diff --git a/examples/user-authentication/signin.sql b/examples/user-authentication/signin.sql index 4057e44d..bab0e883 100644 --- a/examples/user-authentication/signin.sql +++ b/examples/user-authentication/signin.sql @@ -1,14 +1,9 @@ -SELECT 'form' AS component, +SELECT 'login' AS component, + 'login.sql' AS action, 'Sign in' AS title, - 'Sign in' AS validate, - 'login.sql' AS action; - -SELECT 'username' AS name; -SELECT 'password' AS name, 'password' AS type; - -SELECT 'alert' as component, - 'Sorry' as title, - 'We could not authenticate you. Please log in or [create an account](signup.sql).' as description_md, - 'alert-circle' as icon, - 'red' as color -WHERE $error IS NOT NULL; \ No newline at end of file + 'Username' AS username, + 'Password' AS password, + 'user' AS username_icon, + 'lock' AS password_icon, + case when $error is not null then 'We could not authenticate you. Please log in or [create an account](signup.sql).' end as error_message_md, + 'Sign in' AS validate; \ No newline at end of file diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars index 18c9bbb0..28e1666c 100644 --- a/sqlpage/templates/login.handlebars +++ b/sqlpage/templates/login.handlebars @@ -20,13 +20,14 @@ {{#if title}}

{{title}}

{{/if}} - {{#if error_message}} + {{#if (or error_message error_message_md)}}
{{/if}} - +
{{icon_img (default username_icon 'user-circle')}}
-