Skip to content

Commit fdc1e2f

Browse files
author
Ives van Hoorne
committed
Authorizing ZEIT
1 parent 537be23 commit fdc1e2f

File tree

11 files changed

+358
-24
lines changed

11 files changed

+358
-24
lines changed

src/app/containers/Preferences/Integrations/Integration.js

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import styled from 'styled-components';
2+
import styled, { css } from 'styled-components';
33

44
import CrossIcon from 'react-icons/lib/md/clear';
55
import ChevronIcon from 'react-icons/lib/md/keyboard-arrow-right';
@@ -10,6 +10,8 @@ const Container = styled.div`
1010
display: inline-flex;
1111
border-radius: 4px;
1212
overflow: hidden;
13+
14+
${props => props.loading && css`opacity: 0.5;`};
1315
`;
1416

1517
const IntegrationBlock = styled.div`
@@ -112,23 +114,39 @@ type Props = {
112114
name: string,
113115
color: string,
114116
description: string,
115-
loggedIn: boolean,
117+
signOut: Function,
118+
signIn: Function,
119+
userInfo: ?{
120+
token: string,
121+
email: string,
122+
[key: string]: string,
123+
},
124+
loading: boolean,
116125
};
117126

118-
export default ({ Icon, name, description, color, loggedIn }: Props) => (
119-
<Container>
127+
export default ({
128+
Icon,
129+
name,
130+
signOut,
131+
signIn,
132+
description,
133+
color,
134+
userInfo,
135+
loading,
136+
}: Props) => (
137+
<Container loading={loading}>
120138
<IntegrationBlock bgColor={color}>
121139
<Icon />
122140
<Name>{name}</Name>
123141
</IntegrationBlock>
124-
{!loggedIn ? (
142+
{userInfo ? (
125143
<DetailInfo
126-
signOut={() => {}}
144+
signOut={signOut}
127145
heading="Signed in as"
128-
146+
info={userInfo.email || 'Loading...'}
129147
/>
130148
) : (
131-
<DetailInfo signIn={() => {}} heading="Enables" info={description} />
149+
<DetailInfo signIn={signIn} heading="Enables" info={description} />
132150
)}
133151
</Container>
134152
);
Lines changed: 83 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,89 @@
11
import React from 'react';
2+
import { bindActionCreators } from 'redux';
3+
import { connect } from 'react-redux';
4+
5+
import type { CurrentUser } from 'common/types';
6+
import { currentUserSelector } from 'app/store/user/selectors';
7+
import userActionCreators from 'app/store/user/actions';
28

39
import ZeitLogo from 'app/components/ZeitLogo';
410

511
import Integration from './Integration';
612

7-
export default () => (
8-
<div>
9-
<Integration
10-
name="ZEIT"
11-
color="black"
12-
description="Deployments"
13-
Icon={ZeitLogo}
14-
/>
15-
</div>
16-
);
13+
type Props = {
14+
user: CurrentUser,
15+
userActions: typeof userActionCreators,
16+
};
17+
type State = {
18+
loading: {
19+
zeit: boolean,
20+
},
21+
};
22+
23+
const mapDispatchToProps = dispatch => ({
24+
userActions: bindActionCreators(userActionCreators, dispatch),
25+
});
26+
const mapStateToProps = state => ({
27+
user: currentUserSelector(state),
28+
});
29+
30+
class Integrations extends React.PureComponent<Props, State> {
31+
state = {
32+
loading: {
33+
zeit: false,
34+
},
35+
};
36+
37+
componentDidMount() {
38+
if (this.props.user.integrations.zeit) {
39+
this.props.userActions.fetchZeitUserDetails();
40+
}
41+
}
42+
43+
addLoading = func => async () => {
44+
this.setState({
45+
loading: {
46+
...this.state.loading,
47+
zeit: true,
48+
},
49+
});
50+
51+
try {
52+
await func();
53+
} catch (e) {
54+
this.setState({
55+
loading: {
56+
...this.state.loading,
57+
zeit: false,
58+
},
59+
});
60+
}
61+
62+
this.setState({
63+
loading: {
64+
...this.state.loading,
65+
zeit: false,
66+
},
67+
});
68+
};
69+
70+
render() {
71+
const { user, userActions } = this.props;
72+
return (
73+
<div>
74+
<Integration
75+
name="ZEIT"
76+
color="black"
77+
description="Deployments"
78+
Icon={ZeitLogo}
79+
userInfo={user.integrations.zeit}
80+
signOut={this.addLoading(userActions.signOutFromZeit)}
81+
signIn={this.addLoading(userActions.signInZeit)}
82+
loading={this.state.loading.zeit}
83+
/>
84+
</div>
85+
);
86+
}
87+
}
88+
89+
export default connect(mapStateToProps, mapDispatchToProps)(Integrations);

src/app/pages/auth/Zeit.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import React from 'react';
2+
3+
import Centered from 'app/components/flex/Centered';
4+
import Title from 'app/components/text/Title';
5+
6+
import {
7+
protocolAndHost,
8+
signInUrl,
9+
newSandboxUrl,
10+
} from 'app/utils/url-generator';
11+
12+
type State = {
13+
code: ?string,
14+
redirect: ?string,
15+
};
16+
17+
export default class ZeitSignIn extends React.PureComponent<State> {
18+
constructor(props) {
19+
super(props);
20+
21+
// eslint-disable-next-line no-unused-vars
22+
const [_, code] = document.location.search.match(/\?code=(.*)/);
23+
console.log('code', code);
24+
if (code) {
25+
if (window.opener) {
26+
this.state = {
27+
code,
28+
};
29+
if (window.opener.location.origin === window.location.origin) {
30+
window.opener.postMessage(
31+
{
32+
type: 'signin',
33+
data: {
34+
code,
35+
},
36+
},
37+
protocolAndHost()
38+
);
39+
}
40+
return;
41+
}
42+
this.state = {
43+
redirect: '/',
44+
};
45+
return;
46+
}
47+
48+
this.state = {
49+
error: 'no message received',
50+
};
51+
}
52+
53+
getMessage = () => {
54+
if (this.state.redirect) {
55+
document.location.href = newSandboxUrl();
56+
return 'Redirecting to sandbox page';
57+
}
58+
if (this.state.error) {
59+
return `Something went wrong while signing in: ${this.state.error}`;
60+
}
61+
if (this.state.jwt) return 'Signing in...';
62+
if (this.state.jwt == null) {
63+
setTimeout(() => {
64+
document.location.href = signInUrl();
65+
}, 2000);
66+
return 'Redirecting to sign in page...';
67+
}
68+
69+
return 'Hey';
70+
};
71+
72+
render() {
73+
return (
74+
<Centered horizontal vertical>
75+
<Title>{this.getMessage()}</Title>
76+
</Centered>
77+
);
78+
}
79+
}

src/app/pages/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ const SignIn = Loadable({
3737
loader: () => import('./SignIn'),
3838
LoadingComponent: Loading,
3939
});
40+
const ZeitSignIn = Loadable({
41+
loader: () => import('./auth/Zeit'),
42+
LoadingComponent: Loading,
43+
});
4044
const NotFound = Loadable({
4145
loader: () => import('./NotFound'),
4246
LoadingComponent: Loading,
@@ -134,6 +138,7 @@ class Routes extends React.PureComponent<Props> {
134138
<Route path="/patron" component={Patron} />
135139
<Route path="/cli/login" component={CLI} />
136140
<Route path="/legal" component={Terms} />
141+
<Route path="/auth/zeit" component={ZeitSignIn} />
137142
<Route component={NotFound} />
138143
</Switch>
139144
</Content>

src/app/store/entities/sandboxes/actions/index.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import { directoriesSelector } from '../directories/selectors';
1313

1414
import { maybeForkSandbox, forkSandbox } from './fork';
1515
import fileActions from './files';
16+
import { currentUserSelector } from '../../../user/selectors';
17+
import { resolve } from 'babel-standalone';
1618

1719
export const SINGLE_SANDBOX_API_ACTIONS = createAPIActions('SANDBOX', 'SINGLE');
1820
export const CREATE_SANDBOX_API_ACTIONS = createAPIActions('SANDBOX', 'CREATE');
@@ -337,11 +339,32 @@ export default {
337339

338340
const deploy = await import('../utils/deploy');
339341

340-
deploy.default(
342+
const apiData = await deploy.default(
341343
sandbox,
342344
sandbox.modules.map(x => modules[x]),
343345
sandbox.directories.map(x => directories[x])
344346
);
347+
348+
const user = currentUserSelector(getState());
349+
350+
const token = user.integrations.zeit.token;
351+
352+
const res = await fetch('https://api.zeit.co/now/deployments', {
353+
method: 'POST',
354+
body: JSON.stringify(apiData),
355+
headers: {
356+
Authorization: `bearer ${token}`,
357+
},
358+
});
359+
360+
const data = await res.json();
361+
362+
if (!res.ok) {
363+
dispatch(notificationActions.addNotification(data.err.mesage, 'error'));
364+
return;
365+
}
366+
367+
console.log(data);
345368
},
346369

347370
deleteSandbox: (id: string) => async (dispatch: Function) => {

src/app/store/entities/sandboxes/utils/deploy/index.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import JSZip from 'jszip';
22

33
import type { Sandbox, Module, Directory } from 'common/types';
44

5+
import getTemplate from 'common/templates';
6+
57
import { createZip } from '../create-zip';
68

79
export default async function deploy(
@@ -14,12 +16,12 @@ export default async function deploy(
1416
const zipFile = await createZip(sandbox, modules, directories);
1517

1618
if (!zipFile) {
17-
return;
19+
return null;
1820
}
1921

2022
const contents = await JSZip.loadAsync(zipFile);
2123

22-
const apiData = {};
24+
let apiData = {};
2325
const filePaths = Object.keys(contents.files);
2426
for (let i = 0; i < filePaths.length; i += 1) {
2527
const filePath = filePaths[i];
@@ -31,6 +33,13 @@ export default async function deploy(
3133
}
3234

3335
apiData.package = JSON.parse(apiData['package.json']);
36+
apiData['package.json'] = null;
37+
38+
const template = getTemplate(sandbox.template);
39+
40+
if (template.alterDeploymentData) {
41+
apiData = template.alterDeploymentData(apiData);
42+
}
3443

35-
console.log(apiData);
44+
return apiData;
3645
}

0 commit comments

Comments
 (0)