diff --git a/streamlit_authenticator/views/authentication_view.py b/streamlit_authenticator/views/authentication_view.py index 0aea1b67..2cd07142 100644 --- a/streamlit_authenticator/views/authentication_view.py +++ b/streamlit_authenticator/views/authentication_view.py @@ -161,7 +161,10 @@ def forgot_username(self, location: Literal['main', 'sidebar'] = 'main', fields: Optional[Dict[str, str]] = None, captcha: bool = False, send_email: bool = False, two_factor_auth: bool = False, clear_on_submit: bool = False, key: str = 'Forgot username', - callback: Optional[Callable]=None) -> Tuple[Optional[str], Optional[str]]: + type: Literal['primary', 'secondary', 'tertiary'] = 'secondary', + icon: Optional[str] = None, use_container_width: bool = False, + callback: Optional[Callable] = None + ) -> Tuple[Optional[str], Optional[str]]: """ Renders a forgot username widget. @@ -181,6 +184,12 @@ def forgot_username(self, location: Literal['main', 'sidebar'] = 'main', If True, clears input fields after form submission. key : str, default='Forgot username' Unique key for the widget to prevent duplicate WidgetID errors. + type : {'primary', 'secondary', 'terciary'}, default='secondary' + Specifies the button type. + icon : str, optional + Optional emoji or icon to display next to the button label. + use_container_width : bool, default=False + Whether to expand the button's width to fill its parent container. callback : Callable, optional Function to be executed after form submission. @@ -212,7 +221,8 @@ def forgot_username(self, location: Literal['main', 'sidebar'] = 'main', forgot_username_form.image(Helpers.generate_captcha('forgot_username_captcha', self.secret_key)) if forgot_username_form.form_submit_button('Submit' if 'Submit' not in fields - else fields['Submit']): + else fields['Submit'], type=type, icon=icon, + use_container_width=use_container_width): result = self.authentication_controller.forgot_username(email, callback, captcha, entered_captcha) if not two_factor_auth: @@ -228,14 +238,15 @@ def forgot_username(self, location: Literal['main', 'sidebar'] = 'main', del st.session_state['2FA_check_forgot_username'] return result return None, email - def experimental_guest_login(self, button_name: str='Guest login', + def experimental_guest_login(self, button_name: str = 'Guest login', location: Literal['main', 'sidebar'] = 'main', provider: Literal['google', 'microsoft'] = 'google', oauth2: Optional[Dict[str, Any]] = None, - max_concurrent_users: Optional[int]=None, - single_session: bool=False, roles: Optional[List[str]]=None, - use_container_width: bool=False, - callback: Optional[Callable]=None) -> None: + max_concurrent_users: Optional[int] = None, + single_session: bool = False, roles: Optional[List[str]] = None, + use_container_width: bool = False, + callback: Optional[Callable] = None + ) -> None: """ Renders a guest login button. @@ -272,14 +283,14 @@ def experimental_guest_login(self, button_name: str='Guest login', if not st.session_state.get('authentication_status'): auth_endpoint = \ self.authentication_controller.guest_login(cookie_controller=\ - self.cookie_controller, - provider=provider, - oauth2=oauth2, - max_concurrent_users=\ - max_concurrent_users, - single_session=single_session, - roles=roles, - callback=callback) + self.cookie_controller, + provider=provider, + oauth2=oauth2, + max_concurrent_users=\ + max_concurrent_users, + single_session=single_session, + roles=roles, + callback=callback) if location == 'main' and auth_endpoint: st.link_button(button_name, url=auth_endpoint, use_container_width=use_container_width) @@ -289,7 +300,9 @@ def experimental_guest_login(self, button_name: str='Guest login', def login(self, location: Literal['main', 'sidebar', 'unrendered'] = 'main', max_concurrent_users: Optional[int] = None, max_login_attempts: Optional[int] = None, fields: Optional[Dict[str, str]] = None, captcha: bool = False, - single_session: bool=False, clear_on_submit: bool = False, key: str = 'Login', + single_session: bool = False, clear_on_submit: bool = False, key: str = 'Login', + type: Literal['primary', 'secondary', 'tertiary'] = 'secondary', + icon: Optional[str] = None, use_container_width: bool = False, callback: Optional[Callable] = None ) -> Optional[Tuple[Optional[str], Optional[bool], Optional[str]]]: """ @@ -313,6 +326,12 @@ def login(self, location: Literal['main', 'sidebar', 'unrendered'] = 'main', If True, clears input fields after form submission. key : str, default='Login' Unique key for the widget to prevent duplicate WidgetID errors. + type : {'primary', 'secondary', 'terciary'}, default='secondary' + Specifies the button type. + icon : str, optional + Optional emoji or icon to display next to the button label. + use_container_width : bool, default=False + Whether to expand the button's width to fill its parent container. callback : Callable, optional Function to execute when the form is submitted. @@ -359,7 +378,8 @@ def login(self, location: Literal['main', 'sidebar', 'unrendered'] = 'main', autocomplete='off') login_form.image(Helpers.generate_captcha('login_captcha', self.secret_key)) if login_form.form_submit_button('Login' if 'Login' not in fields - else fields['Login']): + else fields['Login'], type=type, icon=icon, + use_container_width=use_container_width): if self.authentication_controller.login(username, password, max_concurrent_users, max_login_attempts, @@ -371,8 +391,10 @@ def login(self, location: Literal['main', 'sidebar', 'unrendered'] = 'main', st.rerun() def logout(self, button_name: str = 'Logout', location: Literal['main', 'sidebar', 'unrendered'] = 'main', - key: str = 'Logout', use_container_width: bool = False, - callback: Optional[Callable] = None) -> None: + key: str = 'Logout', type: Literal['primary', 'secondary', 'tertiary'] = 'secondary', + icon: Optional[str] = None, use_container_width: bool = False, + callback: Optional[Callable] = None + ) -> None: """ Renders a logout button. @@ -384,6 +406,10 @@ def logout(self, button_name: str = 'Logout', Location where the logout button is rendered. key : str, default='Logout' Unique key for the widget, useful in multi-page applications. + type : {'primary', 'secondary', 'terciary'}, default='secondary' + Specifies the button type. + icon : str, optional + Optional emoji or icon to display next to the button label. use_container_width : bool, default=False If True, the button width matches the container. callback : Callable, optional @@ -394,11 +420,13 @@ def logout(self, button_name: str = 'Logout', if location not in ['main', 'sidebar', 'unrendered']: raise ValueError("Location must be one of 'main' or 'sidebar' or 'unrendered'") if location == 'main': - if st.button(button_name, key=key, use_container_width=use_container_width): + if st.button(button_name, key=key, type=type, icon=icon, + use_container_width=use_container_width): self.authentication_controller.logout(callback) self.cookie_controller.delete_cookie() elif location == 'sidebar': - if st.sidebar.button(button_name, key=key, use_container_width=use_container_width): + if st.sidebar.button(button_name, key=key, type=type, icon=icon, + use_container_width=use_container_width): self.authentication_controller.logout(callback) self.cookie_controller.delete_cookie() elif location == 'unrendered': @@ -411,7 +439,10 @@ def register_user(self, location: Literal['main', 'sidebar'] = 'main', captcha: bool = True, roles: Optional[List[str]] = None, merge_username_email: bool = False, password_hint: bool = True, two_factor_auth: bool = False, clear_on_submit: bool = False, - key: str = 'Register user', callback: Optional[Callable] = None + key: str = 'Register user', + type: Literal['primary', 'secondary', 'tertiary'] = 'secondary', + icon: Optional[str] = None, use_container_width: bool = False, + callback: Optional[Callable] = None ) -> Tuple[Optional[str], Optional[str], Optional[str]]: """ Renders a register new user widget. @@ -440,6 +471,12 @@ def register_user(self, location: Literal['main', 'sidebar'] = 'main', If True, clears input fields after form submission. key : str, default='Register user' Unique key for the widget to prevent duplicate WidgetID errors. + type : {'primary', 'secondary', 'terciary'}, default='secondary' + Specifies the button type. + icon : str, optional + Optional emoji or icon to display next to the button label. + use_container_width : bool, default=False + Whether to expand the button's width to fill its parent container. callback : Callable, optional Function to execute when the form is submitted. @@ -504,7 +541,8 @@ def register_user(self, location: Literal['main', 'sidebar'] = 'main', register_user_form.image(Helpers.generate_captcha('register_user_captcha', self.secret_key)) if register_user_form.form_submit_button('Register' if 'Register' not in fields - else fields['Register']): + else fields['Register'], type=type, icon=icon, + use_container_width=use_container_width): if two_factor_auth: self.__two_factor_auth(new_email, widget='register', fields=fields) else: @@ -526,7 +564,10 @@ def register_user(self, location: Literal['main', 'sidebar'] = 'main', return None, None, None def reset_password(self, username: str, location: Literal['main', 'sidebar'] = 'main', fields: Optional[Dict[str, str]] = None, clear_on_submit: bool = False, - key: str = 'Reset password', callback: Optional[Callable] = None + key: str = 'Reset password', + type: Literal['primary', 'secondary', 'tertiary'] = 'secondary', + icon: Optional[str] = None, use_container_width: bool = False, + callback: Optional[Callable] = None ) -> Optional[bool]: """ Renders a password reset widget. @@ -543,6 +584,12 @@ def reset_password(self, username: str, location: Literal['main', 'sidebar'] = ' If True, clears input fields after form submission. key : str, default='Reset password' Unique key for the widget to prevent duplicate WidgetID errors. + type : {'primary', 'secondary', 'terciary'}, default='secondary' + Specifies the button type. + icon : str, optional + Optional emoji or icon to display next to the button label. + use_container_width : bool, default=False + Whether to expand the button's width to fill its parent container. callback : Callable, optional Function to execute when the form is submitted. @@ -584,9 +631,10 @@ def reset_password(self, username: str, location: Literal['main', 'sidebar'] = ' type='password', autocomplete='off').strip() if reset_password_form.form_submit_button('Reset' if 'Reset' not in fields - else fields['Reset']): + else fields['Reset'], icon=icon, type=type, + use_container_width=use_container_width): if self.authentication_controller.reset_password(username, password, new_password, - new_password_repeat, callback): + new_password_repeat, callback): return True return None def __two_factor_auth(self, email: str, content: Optional[Dict[str, Any]] = None, @@ -622,7 +670,10 @@ def two_factor_auth_form(): def update_user_details(self, username: str, location: Literal['main', 'sidebar'] = 'main', fields: Optional[Dict[str, str]] = None, clear_on_submit: bool = False, key: str = 'Update user details', - callback: Optional[Callable] = None) -> bool: + type: Literal['primary', 'secondary', 'tertiary'] = 'secondary', + icon: Optional[str] = None, use_container_width: bool = False, + callback: Optional[Callable] = None + ) -> bool: """ Renders an update user details widget. @@ -638,6 +689,12 @@ def update_user_details(self, username: str, location: Literal['main', 'sidebar' If True, clears input fields after form submission. key : str, default='Update user details' Unique key for the widget to prevent duplicate WidgetID errors. + type : {'primary', 'secondary', 'terciary'}, default='secondary' + Specifies the button type. + icon : str, optional + Optional emoji or icon to display next to the button label. + use_container_width : bool, default=False + Whether to expand the button's width to fill its parent container. callback : Callable, optional Function to execute when the form is submitted. @@ -664,7 +721,7 @@ def update_user_details(self, username: str, location: Literal['main', 'sidebar' update_user_details_form_fields = ['First name' if 'First name' not in fields else \ fields['First name'], 'Last name' if 'Last name' not in fields else \ - fields['Last name'], + fields['Last name'], 'Email' if 'Email' not in fields else fields['Email']] field = update_user_details_form.selectbox('Field' if 'Field' not in fields else fields['Field'], @@ -679,7 +736,8 @@ def update_user_details(self, username: str, location: Literal['main', 'sidebar' elif update_user_details_form_fields.index(field) == 2: field = 'email' if update_user_details_form.form_submit_button('Update' if 'Update' not in fields - else fields['Update']): + else fields['Update'], icon=icon, type=type, + use_container_width=use_container_width): if self.authentication_controller.update_user_details(username, field, new_value, callback): # self.cookie_controller.set_cookie()