Skip to content

Commit f9d5d6b

Browse files
authored
Merge pull request #1236 from scottsut/fix
refactor: support auth login in share page
2 parents 8c09351 + bb52e3a commit f9d5d6b

File tree

12 files changed

+215
-54
lines changed

12 files changed

+215
-54
lines changed

frontend/src/app/pages/AuthorizationPage/index.tsx

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { EmptyFiller } from 'app/components/EmptyFiller';
22
import useI18NPrefix from 'app/hooks/useI18NPrefix';
33
import { getUserInfoByToken } from 'app/slice/thunks';
4-
import { useCallback, useEffect } from 'react';
4+
import { StorageKeys } from 'globalConstants';
5+
import { useEffect } from 'react';
56
import { useDispatch } from 'react-redux';
67
import { useHistory, useRouteMatch } from 'react-router';
78
import styled from 'styled-components/macro';
9+
import persistence from 'utils/persistence';
810

911
export const AuthorizationPage = () => {
1012
const dispatch = useDispatch();
@@ -13,15 +15,26 @@ export const AuthorizationPage = () => {
1315
const token = paramsMatch.params.token;
1416
const t = useI18NPrefix('authorization');
1517

16-
const toApp = useCallback(() => {
17-
history.replace('/');
18-
}, [history]);
19-
2018
useEffect(() => {
2119
if (token) {
22-
dispatch(getUserInfoByToken({ token, resolve: toApp }));
20+
dispatch(
21+
getUserInfoByToken({
22+
token,
23+
resolve: () => {
24+
const redirectUrl = persistence.session.get(
25+
StorageKeys.AuthRedirectUrl,
26+
);
27+
if (redirectUrl) {
28+
persistence.session.remove(StorageKeys.AuthRedirectUrl);
29+
window.location.href = redirectUrl;
30+
} else {
31+
history.replace('/');
32+
}
33+
},
34+
}),
35+
);
2336
}
24-
}, [token, dispatch, toApp]);
37+
}, [token, dispatch, history]);
2538
return (
2639
<Wrapper>
2740
<EmptyFiller loading title={t('processing')} />

frontend/src/app/pages/LoginPage/LoginForm.tsx

Lines changed: 65 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -19,66 +19,70 @@
1919
import { Button, Form, Input } from 'antd';
2020
import { AuthForm } from 'app/components';
2121
import usePrefixI18N from 'app/hooks/useI18NPrefix';
22-
import {
23-
selectLoggedInUser,
24-
selectLoginLoading,
25-
selectOauth2Clients,
26-
} from 'app/slice/selectors';
27-
import { getOauth2Clients } from 'app/slice/thunks';
28-
import React, { useCallback, useEffect, useState } from 'react';
29-
import { useDispatch, useSelector } from 'react-redux';
22+
import { User } from 'app/slice/types';
23+
import { StorageKeys } from 'globalConstants';
24+
import React, { useCallback, useState } from 'react';
3025
import { Link, useHistory } from 'react-router-dom';
3126
import styled from 'styled-components/macro';
3227
import {
3328
BORDER_RADIUS,
3429
LINE_HEIGHT_ICON_LG,
30+
LINE_HEIGHT_ICON_XXL,
3531
SPACE_MD,
32+
SPACE_XS,
3633
} from 'styles/StyleConstants';
3734
import { getToken } from 'utils/auth';
35+
import persistence from 'utils/persistence';
36+
import { AUTH_CLIENT_ICON_MAPPING } from './constants';
37+
38+
interface LoginFormProps {
39+
loading: boolean;
40+
loggedInUser?: User | null;
41+
oauth2Clients: Array<{ name: string; value: string }>;
42+
registerEnable?: boolean;
43+
inShare?: boolean;
44+
onLogin?: (value) => void;
45+
}
3846

3947
export function LoginForm({
48+
loading,
49+
loggedInUser,
50+
oauth2Clients,
4051
registerEnable = true,
41-
modal = false,
52+
inShare = false,
4253
onLogin,
43-
}: {
44-
registerEnable?: boolean;
45-
modal?: boolean;
46-
onLogin?: (value) => void;
47-
}) {
54+
}: LoginFormProps) {
4855
const [switchUser, setSwitchUser] = useState(false);
49-
const dispatch = useDispatch();
5056
const history = useHistory();
51-
const loading = useSelector(selectLoginLoading);
52-
const loggedInUser = useSelector(selectLoggedInUser);
5357
const [form] = Form.useForm();
5458
const logged = !!getToken();
5559
const t = usePrefixI18N('login');
5660
const tg = usePrefixI18N('global');
57-
const oauth2Clients = useSelector(selectOauth2Clients);
5861

5962
const toApp = useCallback(() => {
6063
history.replace('/');
6164
}, [history]);
6265

63-
useEffect(() => {
64-
dispatch(getOauth2Clients());
65-
}, [dispatch]);
66-
6766
const onSwitch = useCallback(() => {
6867
setSwitchUser(true);
6968
}, []);
7069

71-
let Oauth2BtnList = oauth2Clients.map(client => {
72-
return (
73-
<Oauth2Button key={client.value} href={client.value}>
74-
{client.name}
75-
</Oauth2Button>
76-
);
77-
});
70+
const toAuthClient = useCallback(
71+
clientUrl => () => {
72+
if (inShare) {
73+
persistence.session.save(
74+
StorageKeys.AuthRedirectUrl,
75+
window.location.href,
76+
);
77+
}
78+
window.location.href = clientUrl;
79+
},
80+
[inShare],
81+
);
7882

7983
return (
8084
<AuthForm>
81-
{logged && !switchUser && !modal ? (
85+
{logged && !switchUser && !inShare ? (
8286
<>
8387
<h2>{t('alreadyLoggedIn')}</h2>
8488
<UserPanel onClick={toApp}>
@@ -132,7 +136,7 @@ export function LoginForm({
132136
</Button>
133137
)}
134138
</Form.Item>
135-
{!modal && (
139+
{!inShare && (
136140
<Links>
137141
<LinkButton to="/forgetPassword">
138142
{t('forgotPassword')}
@@ -142,8 +146,22 @@ export function LoginForm({
142146
)}
143147
</Links>
144148
)}
145-
146-
{Oauth2BtnList}
149+
{oauth2Clients.length > 0 && (
150+
<>
151+
<AuthTitle>{t('authTitle')}</AuthTitle>
152+
{oauth2Clients.map(({ name, value }) => (
153+
<AuthButton
154+
key={value}
155+
size="large"
156+
icon={AUTH_CLIENT_ICON_MAPPING[name.toLowerCase()]}
157+
onClick={toAuthClient(value)}
158+
block
159+
>
160+
{name}
161+
</AuthButton>
162+
))}
163+
</>
164+
)}
147165
</Form>
148166
)}
149167
</AuthForm>
@@ -154,16 +172,6 @@ const Links = styled.div`
154172
display: flex;
155173
`;
156174

157-
const Oauth2Button = styled.a`
158-
display: block;
159-
height: 36px;
160-
font-weight: bold;
161-
line-height: 36px;
162-
color: #fff;
163-
text-align: center;
164-
background-color: blue;
165-
`;
166-
167175
const LinkButton = styled(Link)`
168176
flex: 1;
169177
line-height: ${LINE_HEIGHT_ICON_LG};
@@ -173,6 +181,20 @@ const LinkButton = styled(Link)`
173181
}
174182
`;
175183

184+
const AuthTitle = styled.p`
185+
line-height: ${LINE_HEIGHT_ICON_XXL};
186+
color: ${p => p.theme.textColorLight};
187+
text-align: center;
188+
`;
189+
190+
const AuthButton = styled(Button)`
191+
margin-bottom: ${SPACE_XS};
192+
193+
&:last-child {
194+
margin-bottom: 0;
195+
}
196+
`;
197+
176198
const UserPanel = styled.div`
177199
display: flex;
178200
padding: ${SPACE_MD};
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Datart
3+
*
4+
* Copyright 2021
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
import {
20+
AlipayCircleOutlined,
21+
AliyunOutlined,
22+
CodepenCircleOutlined,
23+
DingdingOutlined,
24+
FacebookOutlined,
25+
GithubOutlined,
26+
GitlabOutlined,
27+
GoogleOutlined,
28+
InstagramOutlined,
29+
QqOutlined,
30+
SlackOutlined,
31+
WeiboCircleOutlined,
32+
ZhihuOutlined,
33+
} from '@ant-design/icons';
34+
35+
export const AUTH_CLIENT_ICON_MAPPING = {
36+
github: <GithubOutlined />,
37+
dingding: <DingdingOutlined />,
38+
qq: <QqOutlined />,
39+
gitlab: <GitlabOutlined />,
40+
weibo: <WeiboCircleOutlined />,
41+
zhihu: <ZhihuOutlined />,
42+
alipay: <AlipayCircleOutlined />,
43+
aliyun: <AliyunOutlined />,
44+
google: <GoogleOutlined />,
45+
facebook: <FacebookOutlined />,
46+
slack: <SlackOutlined />,
47+
instagram: <InstagramOutlined />,
48+
codepen: <CodepenCircleOutlined />,
49+
};

frontend/src/app/pages/LoginPage/index.tsx

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,14 @@
1818

1919
import { Brand } from 'app/components/Brand';
2020
import { Version } from 'app/components/Version';
21-
import { selectSystemInfo } from 'app/slice/selectors';
22-
import { login } from 'app/slice/thunks';
23-
import React, { useCallback } from 'react';
21+
import {
22+
selectLoggedInUser,
23+
selectLoginLoading,
24+
selectOauth2Clients,
25+
selectSystemInfo,
26+
} from 'app/slice/selectors';
27+
import { getOauth2Clients, login } from 'app/slice/thunks';
28+
import React, { useCallback, useEffect } from 'react';
2429
import { useDispatch, useSelector } from 'react-redux';
2530
import { useHistory } from 'react-router-dom';
2631
import styled from 'styled-components/macro';
@@ -30,6 +35,13 @@ export function LoginPage() {
3035
const dispatch = useDispatch();
3136
const history = useHistory();
3237
const systemInfo = useSelector(selectSystemInfo);
38+
const loading = useSelector(selectLoginLoading);
39+
const loggedInUser = useSelector(selectLoggedInUser);
40+
const oauth2Clients = useSelector(selectOauth2Clients);
41+
42+
useEffect(() => {
43+
dispatch(getOauth2Clients());
44+
}, [dispatch]);
3345

3446
const onLogin = useCallback(
3547
values => {
@@ -48,6 +60,9 @@ export function LoginPage() {
4860
<Wrapper>
4961
<Brand />
5062
<LoginForm
63+
loading={loading}
64+
loggedInUser={loggedInUser}
65+
oauth2Clients={oauth2Clients}
5166
registerEnable={systemInfo?.registerEnable}
5267
onLogin={onLogin}
5368
/>

frontend/src/app/pages/SharePage/ShareLoginModal.tsx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,30 @@
1717
*/
1818

1919
import { LoginForm } from 'app/pages/LoginPage/LoginForm';
20+
import { useEffect } from 'react';
21+
import { useDispatch, useSelector } from 'react-redux';
2022
import styled from 'styled-components';
23+
import { selectLoginLoading, selectOauth2Clients } from './slice/selectors';
24+
import { getOauth2Clients } from './slice/thunks';
2125

2226
function ShareLoginModal({ visible, onChange }) {
27+
const dispatch = useDispatch();
28+
const loading = useSelector(selectLoginLoading);
29+
const oauth2Clients = useSelector(selectOauth2Clients);
30+
31+
useEffect(() => {
32+
dispatch(getOauth2Clients());
33+
}, [dispatch]);
34+
2335
return (
2436
visible && (
2537
<LoginWrapper>
26-
<LoginForm modal={true} onLogin={onChange} />
38+
<LoginForm
39+
loading={loading}
40+
oauth2Clients={oauth2Clients}
41+
inShare={true}
42+
onLogin={onChange}
43+
/>
2744
</LoginWrapper>
2845
)
2946
);

frontend/src/app/pages/SharePage/slice/index.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ import { useInjectReducer } from 'utils/@reduxjs/injectReducer';
3131
import {
3232
fetchAvailableSourceFunctions,
3333
fetchShareDataSetByPreviewChartAction,
34+
fetchShareVizInfo,
35+
getOauth2Clients,
3436
} from './thunks';
3537
// import { fetchShareDataSetByPreviewChartAction } from './thunk';
3638
import { ExecuteToken, SharePageState, ShareVizInfo } from './types';
@@ -46,6 +48,8 @@ export const initialState: SharePageState = {
4648
headlessBrowserRenderSign: false,
4749
pageWidthHeight: [0, 0],
4850
shareDownloadPolling: false,
51+
loginLoading: false,
52+
oauth2Clients: [],
4953
availableSourceFunctions: [],
5054
};
5155

@@ -173,6 +177,15 @@ export const slice = createSlice({
173177
},
174178
extraReducers: builder => {
175179
builder
180+
.addCase(fetchShareVizInfo.pending, state => {
181+
state.loginLoading = true;
182+
})
183+
.addCase(fetchShareVizInfo.fulfilled, state => {
184+
state.loginLoading = false;
185+
})
186+
.addCase(fetchShareVizInfo.rejected, state => {
187+
state.loginLoading = false;
188+
})
176189
.addCase(
177190
fetchShareDataSetByPreviewChartAction.fulfilled,
178191
(state, { payload }) => {
@@ -186,6 +199,12 @@ export const slice = createSlice({
186199
.addCase(fetchShareDataSetByPreviewChartAction.rejected, state => {
187200
state.headlessBrowserRenderSign = true;
188201
})
202+
.addCase(getOauth2Clients.fulfilled, (state, action) => {
203+
state.oauth2Clients = action.payload.map(x => ({
204+
name: Object.keys(x)[0],
205+
value: x[Object.keys(x)[0]],
206+
}));
207+
})
189208
.addCase(
190209
fetchAvailableSourceFunctions.fulfilled,
191210
(state, { payload }) => {

0 commit comments

Comments
 (0)