Skip to content

feat(Login): Migrate login page to frontend#33255

Merged
msyavuz merged 43 commits intotemplate_lessfrom
msyavuz/feat/login-view-to-react
May 29, 2025
Merged

feat(Login): Migrate login page to frontend#33255
msyavuz merged 43 commits intotemplate_lessfrom
msyavuz/feat/login-view-to-react

Conversation

@msyavuz
Copy link
Member

@msyavuz msyavuz commented Apr 28, 2025

SUMMARY

This PR tries to move the Login fab view to the frontend spa.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

AuthDB Login:

Before:
image

After:
image

TESTING INSTRUCTIONS

Follow the instructions on setting up auth methods in flask-appbuilder to see different auth methods working. The configuration should be something like this for different auth methods:

AUTH_TYPE = AUTH_OAUTH
OAUTH_PROVIDERS = [
    {
        "name": "google",
        "icon": "fa-google",
        "token_key": "access_token",
        "remote_app": {
            "client_id": GOOGLE_KEY,
            "client_secret": GOOGLE_SECRET,
            "api_base_url": "https://www.googleapis.com/oauth2/v2/",
            "client_kwargs": {"scope": "email profile"},
            "request_token_url": None,
            "access_token_url": "https://accounts.google.com/o/oauth2/token",
            "authorize_url": "https://accounts.google.com/o/oauth2/auth",
            "project_id": "symbolic-path-413013",
            "auth_uri": "https://accounts.google.com/o/oauth2/auth",
            "token_uri": "https://oauth2.googleapis.com/token",
            "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
            "redirect_uris": ["http://localhost:8088/oauth-authorized/google"],
            "javascript_origins": ["http://localhost:8088"],
            "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
        },
    },
]

AUTH_TYPE = AUTH_OID
OPENID_PROVIDERS = [
    {"name": "Yahoo", "url": "https://me.yahoo.com"},
    {"name": "AOL", "url": "http://openid.aol.com/<username>"},
    {"name": "Flickr", "url": "http://www.flickr.com/<username>"},
    {"name": "MyOpenID", "url": "https://www.myopenid.com"},
]

AUTH_TYPE = AUTH_LDAP
AUTH_LDAP_SERVER = "ldap://ldap.example.org"
AUTH_LDAP_USE_TLS = False

# registration configs
AUTH_USER_REGISTRATION = True  # allow users who are not already in the FAB DB
AUTH_USER_REGISTRATION_ROLE = (
    "Public"  # this role will be given in addition to any AUTH_ROLES_MAPPING
)
AUTH_LDAP_FIRSTNAME_FIELD = "givenName"
AUTH_LDAP_LASTNAME_FIELD = "sn"
AUTH_LDAP_EMAIL_FIELD = (
    "mail"  # if null in LDAP, email is set to: "{username}@email.notfound"
)

# search configs
AUTH_LDAP_SEARCH = "ou=users,dc=example,dc=org"  # the LDAP search base
AUTH_LDAP_UID_FIELD = "uid"  # the username field
AUTH_LDAP_BIND_USER = (
    "uid=admin,dc=example,dc=org"  # the special bind username for search
)
AUTH_LDAP_BIND_PASSWORD = "admin_password"  # the special bind password for search

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

@korbit-ai
Copy link

korbit-ai bot commented Apr 28, 2025

Based on your review schedule, I'll hold off on reviewing this PR until it's marked as ready for review. If you'd like me to take a look now, comment /korbit-review.

Your admin can change your review schedule in the Korbit Console

@github-actions github-actions bot added the api Related to the REST API label Apr 28, 2025
@msyavuz msyavuz changed the title chore: initial commit feat(Login): Migrate login page to frontend Apr 28, 2025
@rusackas
Copy link
Member

Yay!!!! Is this the magic moment we've all been waiting for that kills the little gray close buttons that show up before the React frontend is built/loaded?

@github-actions github-actions bot removed the api Related to the REST API label Apr 29, 2025
@msyavuz msyavuz requested a review from EnxDev May 8, 2025 10:09
Copy link
Contributor

@EnxDev EnxDev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

{ required: true, message: t('Please enter your username') },
]}
>
<Input prefix={<Icons.UserOutlined size={1} />} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be one of these: 'xs', 's', 'm', 'l', 'xl', 'xxl'?

@msyavuz
Copy link
Member Author

msyavuz commented May 8, 2025

Yay!!!! Is this the magic moment we've all been waiting for that kills the little gray close buttons that show up before the React frontend is built/loaded?

Well, i think those will show up anyways until the frontend is loaded. Sorry!

@dosubot dosubot bot added the change:frontend Requires changing the frontend label May 20, 2025
Copy link

@korbit-ai korbit-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review by Korbit AI

Korbit automatically attempts to detect when you fix issues in new commits.
Category Issue Status
Functionality Unused OAuth Provider Parameter ▹ view 🧠 Incorrect
Performance Unmemoized Bootstrap Data Fetch ▹ view 🧠 Incorrect
Design Form Submission Logic Not Separated ▹ view 🧠 Not in standard
Functionality Incorrect Component for Logout Route ▹ view
Error Handling Unhandled URL Generation Error in Redirect ▹ view 🧠 Incorrect
Documentation Missing Interface Documentation ▹ view 🧠 Not in standard
Functionality Potential Circular Import Risk ▹ view ✅ Fix detected
Readability Unexplained Layout Constants ▹ view 🧠 Not in standard
Readability Unclear API Parameter ▹ view 🧠 Incorrect
Performance Unmemoized Form Handler ▹ view 🧠 Incorrect
Files scanned
File Path Reviewed
superset/connectors/sqla/init.py
superset-frontend/cypress-base/cypress/utils/urls.ts
superset/views/alerts.py
superset/views/auth.py
superset-frontend/src/components/Icons/AntdEnhanced.tsx
superset-frontend/src/views/routes.tsx
superset-frontend/src/pages/Register/index.tsx
superset-frontend/src/pages/Login/index.tsx
superset-frontend/cypress-base/cypress/support/e2e.ts
superset/views/base.py
superset/views/utils.py
superset/initialization/init.py
superset/security/manager.py

Explore our documentation to understand the languages and file types we support and the files we ignore.

Check out our docs on how you can make Korbit work best for you and your team.

Loving Korbit!? Share us on LinkedIn Reddit and X

@has_access
@permission_name("read")
def list(self) -> FlaskResponse:
from superset import is_feature_enabled

This comment was marked as resolved.

Comment on lines +165 to +168
{
path: '/logout/',
Component: Login,
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect Component for Logout Route category Functionality

Tell me more
What is the issue?

The logout route is incorrectly using the Login component, which doesn't handle the logout functionality.

Why this matters

Users attempting to logout will be shown the login page without their session being terminated, leading to an inconsistent authentication state.

Suggested change ∙ Feature Preview

Create and use a dedicated Logout component that handles session termination before redirecting to the login page. Example:

const Logout = lazy(
  () => import(/* webpackChunkName: "Logout" */ 'src/pages/Logout'),
);

// In routes array
{
    path: '/logout/',
    Component: Logout,
}
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

@no_cache
def login(self, provider: Optional[str] = None) -> WerkzeugResponse:
if g.user is not None and g.user.is_authenticated:
return redirect(self.appbuilder.get_url_for_index)

This comment was marked as resolved.

conf_password: values.confirmPassword,
'g-recaptcha-response': captchaResponse,
};
SupersetClient.postForm('/register/form', payload, '').finally(() => {

This comment was marked as resolved.


@expose("/")
@no_cache
def login(self, provider: Optional[str] = None) -> WerkzeugResponse:

This comment was marked as resolved.

const [loading, setLoading] = useState(false);
const [captchaResponse, setCaptchaResponse] = useState<string | null>(null);

const bootstrapData = getBootstrapData();

This comment was marked as resolved.

Comment on lines +67 to +77
const onFinish = (values: RegisterForm) => {
setLoading(true);
const payload = {
username: values.username,
first_name: values.firstName,
last_name: values.lastName,
email: values.email,
password: values.password,
conf_password: values.confirmPassword,
'g-recaptcha-response': captchaResponse,
};

This comment was marked as resolved.

Comment on lines +67 to +80
const onFinish = (values: RegisterForm) => {
setLoading(true);
const payload = {
username: values.username,
first_name: values.firstName,
last_name: values.lastName,
email: values.email,
password: values.password,
conf_password: values.confirmPassword,
'g-recaptcha-response': captchaResponse,
};
SupersetClient.postForm('/register/form', payload, '').finally(() => {
setLoading(false);
});

This comment was marked as resolved.

Comment on lines +26 to +33
interface RegisterForm {
username: string;
firstName: string;
lastName: string;
email: string;
password: string;
confirmPassword: string;
}

This comment was marked as resolved.

Comment on lines +46 to +55
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 6 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 24 },
},
};

This comment was marked as resolved.

);

before(() => {
if (Cypress.currentTest.title.toLowerCase().includes('login')) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make a small util for this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

href={`/login/${provider.name}`}
block
iconPosition="start"
icon={AuthIconMap[provider.name]}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can new providers be introduced? What happens if the icon isn't available?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we can get the icon from user config as 'fa-google' etc, I can create an icon map that has all available providers, and maybe we can have fallback to <i> tag for new providers?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that there is a pattern in naming convention for social icons on Ant Design. We can make a util function that gets the provider name, capitalizes it and adds either Outlined or Filled (to check with Kasia) and if it does not exist can fallback to a button or a fallback icon.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

/>
</Form.Item>
<Form.Item label={null}>
<Flex
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have a LoginContainer that is the same as this. I prefer inline, so maybe we can get rid of LoginContainer?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@mistercrunch
Copy link
Member

YES! should the login box be vertical-algin: center;?

@mistercrunch
Copy link
Member

While at it, wondering if we can reduce the width of the login card, and maybe remove the icon at the top-right, the word "Log in" speaks for itself, no need for an icon here. @kasiazjc may have some input here too.


const StyledCard = styled(Card)`
${({ theme }) => css`
width: 40%;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would avoid using percentages as I don't think it would look great on wide screens, let me know what you think

label={t('Email')}
name="email"
rules={[{ required: true, message: t('Please enter your email') }]}
>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
>
>rules={[
{ required: true, message: t('Email is required') },
{
type: 'email',
message: t('Please enter a valid email address'),
},
]}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that it can check if t s valid format for the email adress as well

elif security_manager.is_guest_user(user):
user.roles = (current_app.appbuilder.sm.find_role("Public"),)
elif current_app.appbuilder.sm.is_guest_user(user):
payload = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need to use the current_app.app_builder.sm instead of security_manager

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are correct, these were measures i took to avoid circular imports but they are not necessary anymore

@alexandrusoare
Copy link
Contributor

Great work @msyavuz ! The page is looking good, I just have a few nits here and there.

  • When you hover over the login and register buttons there's a slight difference, the register text gets underlined, maybe we can get rid of that:
image image
  • I think we should either reduce a bit the height of the login card or to give a little bit more padding/margin to buttons on the top so that we can have some better proportions, let me know what you think:
image
  • Maybe center the inputs and labels or at least place them on the left
image

Copy link
Member

@dpgaspar dpgaspar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested AUTH_DB and AUTH_OAUTH,
using OAUTH and AUTH_USER_REGISTRATION = True login breaks, it seems RECAPTCHA_PUBLIC_KEY is now required, although this is a good measure it was not a required config before.
This does not seem specifically related with this PR, but a possible issue

@has_access
@permission_name("read")
def log(self, pk: int) -> FlaskResponse: # pylint: disable=unused-argument
from superset import is_feature_enabled
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: is it possible to move this import to the module level?

@msyavuz
Copy link
Member Author

msyavuz commented May 26, 2025

using OAUTH and AUTH_USER_REGISTRATION = True login breaks, it seems RECAPTCHA_PUBLIC_KEY is now required, although this is a good measure it was not a required config before.

@dpgaspar I think it was required when registration is enabled but it was implicit, Recaptcha would be broken and you couldn't register. I am not sure what was the intended flow with fab as https://flask-appbuilder.readthedocs.io/en/latest/user_registration.html doesn't mention oauth.

@msyavuz
Copy link
Member Author

msyavuz commented May 29, 2025

When you hover over the login and register buttons there's a slight difference, the register text gets underlined, maybe we can get rid of that:

That button is technically a link so not sure about removing the underline

I think we should either reduce a bit the height of the login card or to give a little bit more padding/margin to buttons on the top so that we can have some better proportions, let me know what you think:

I think looks pretty similar to the fab view we had now, we would again need a design input for this if we want to change more stuff.

Maybe center the inputs and labels or at least place them on the left

Thought about maybe having less padding on the left but decided to go with less custom styles

@msyavuz
Copy link
Member Author

msyavuz commented May 29, 2025

YES! should the login box be vertical-algin: center;?

While at it, wondering if we can reduce the width of the login card, and maybe remove the icon at the top-right, the word "Log in" speaks for itself, no need for an icon here. @kasiazjc may have some input here too.

I think input of @kasiazjc is relevant here. I tried to replicate what it was before but if want to change these stuff we can do that as well.

@msyavuz msyavuz merged commit 58435e3 into template_less May 29, 2025
47 checks passed
@msyavuz msyavuz deleted the msyavuz/feat/login-view-to-react branch May 29, 2025 11:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:frontend Requires changing the frontend dependencies:npm global:theming Related to theming Superset size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants