Skip to content

Commit 4f5360a

Browse files
christianalfoniCompuIves
authored andcommitted
Typescript and Overmind refactor (#2039)
* refactored sandboxPageMounted with related stuff * more sequences refactored * Added some more actions, not tested * initial refactor of root singals * a lot of refactoring * more refactoring * more refactor * More refactor * jup, more refactor * finished first iteration on editor domain * Files done * live refactored * profile refactored * server and user notifications refactored * Whoo, all done * update overmind
1 parent 5f14f25 commit 4f5360a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+6168
-377
lines changed

packages/app/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,9 +217,9 @@
217217
"normalizr": "^3.2.3",
218218
"onigasm": "^2.2.1",
219219
"ot": "^0.0.15",
220-
"overmind": "^18.0.0-1557824735814",
221-
"overmind-devtools": "^19.0.0-1557824735814",
222-
"overmind-react": "^19.0.0-1557824735814",
220+
"overmind": "^19.0.1",
221+
"overmind-devtools": "^19.0.0",
222+
"overmind-react": "^19.0.0",
223223
"phoenix": "^1.3.0",
224224
"postcss": "^6.0.9",
225225
"postcss-selector-parser": "^2.2.3",

packages/app/src/app/components/CodeEditor/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type ModuleTab = {
3030
};
3131

3232
type DiffTab = {
33+
id: string;
3334
type: 'DIFF';
3435
codeA: string;
3536
codeB: string;
Lines changed: 183 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,190 @@
1-
import { Action } from '.';
1+
import { Action, AsyncAction } from '.';
22
import * as internalActions from './internalActions';
33
import { withLoadApp } from './factories';
4+
import { NotificationType } from '@codesandbox/common/lib/utils/notifications';
45

56
export const internal = internalActions;
67

7-
export const appUnmounted: Action = async ({ effects, actions }) => {
8-
effects.connection.removeListener(actions.internal.onConnectionChange);
8+
export const appUnmounted: AsyncAction = async ({ effects, actions }) => {
9+
effects.connection.removeListener(actions.connectionChanged);
910
};
1011

11-
export const sandboxPageMounted: Action = withLoadApp(() => {});
12+
export const sandboxPageMounted: AsyncAction = withLoadApp();
13+
14+
export const searchMounted: AsyncAction = withLoadApp();
15+
16+
export const cliMounted: AsyncAction = withLoadApp(
17+
async ({ state, actions }) => {
18+
if (state.user) {
19+
await actions.internal.authorize();
20+
}
21+
}
22+
);
23+
24+
export const forceRender: Action = ({ state }) => {
25+
state.editor.forceRender++;
26+
};
27+
28+
export const cliInstructionsMounted: AsyncAction = withLoadApp();
29+
30+
export const githubPageMounted: AsyncAction = withLoadApp();
31+
32+
export const connectionChanged: Action<boolean> = ({ state }, connected) => {
33+
state.connected = connected;
34+
};
35+
36+
export const modalOpened: Action<{ modal: string; message: string }> = (
37+
{ state, effects },
38+
{ modal, message }
39+
) => {
40+
effects.analytics.track('Open Modal', { modal });
41+
state.currentModalMessage = message;
42+
state.currentModal = modal;
43+
};
44+
45+
export const modalClosed: Action = ({ state }) => {
46+
state.currentModal = null;
47+
};
48+
49+
export const signInClicked: AsyncAction<{ useExtraScopes: boolean }> = (
50+
{ actions },
51+
options
52+
) => actions.internal.signIn(options);
53+
54+
export const signInCliClicked: AsyncAction = async ({ state, actions }) => {
55+
await actions.internal.signIn({
56+
useExtraScopes: false,
57+
});
58+
59+
if (state.user) {
60+
await actions.internal.authorize();
61+
}
62+
};
63+
64+
export const userMenuOpened: Action = ({ state }) => {
65+
state.userMenuOpen = true;
66+
};
67+
68+
export const userMenuClosed: Action = ({ state }) => {
69+
state.userMenuOpen = false;
70+
};
71+
72+
export const addNotification: Action<{
73+
message: string;
74+
type: NotificationType;
75+
timeAlive: number;
76+
}> = ({ effects }, { message, type, timeAlive }) => {
77+
effects.notificationToast.add({
78+
message,
79+
status: effects.notificationToast.convertTypeToStatus(type),
80+
timeAlive: timeAlive * 1000,
81+
});
82+
};
83+
84+
export const removeNotification: Action<number> = ({ state }, id) => {
85+
const notificationToRemoveIndex = state.notifications.findIndex(
86+
notification => notification.id === id
87+
);
88+
89+
state.notifications.splice(notificationToRemoveIndex, 1);
90+
};
91+
92+
export const signInZeitClicked: AsyncAction = async ({
93+
state,
94+
effects: { browser, api, notificationToast },
95+
actions,
96+
}) => {
97+
state.isLoadingZeit = true;
98+
99+
const popup = browser.openPopup('/auth/zeit', 'sign in');
100+
const data: { code: string } = await browser.waitForMessage('signin');
101+
102+
popup.close();
103+
104+
if (data && data.code) {
105+
try {
106+
state.user = await api.post(`/users/current_user/integrations/zeit`, {
107+
code: data.code,
108+
});
109+
await actions.internal.getZeitUserDetails();
110+
} catch (error) {
111+
notificationToast.add({
112+
message: 'Could not authorize with ZEIT',
113+
status: notificationToast.convertTypeToStatus('error'),
114+
});
115+
}
116+
} else {
117+
notificationToast.add({
118+
message: 'Could not authorize with ZEIT',
119+
status: notificationToast.convertTypeToStatus('error'),
120+
});
121+
}
122+
123+
state.isLoadingZeit = false;
124+
};
125+
126+
export const signOutZeitClicked: AsyncAction = async ({ state, effects }) => {
127+
await effects.http.delete(`/users/current_user/integrations/zeit`);
128+
state.user.integrations.zeit = null;
129+
};
130+
131+
export const authTokenRequested: AsyncAction = async ({ actions }) => {
132+
await actions.internal.authorize();
133+
};
134+
135+
export const requestAuthorisation: AsyncAction = async ({ actions }) => {
136+
await actions.internal.authorize();
137+
};
138+
139+
export const signInGithubClicked: AsyncAction = async ({ state, actions }) => {
140+
state.isLoadingGithub = true;
141+
await actions.internal.signIn({ useExtraScopes: false });
142+
state.isLoadingGithub = false;
143+
};
144+
145+
export const signOutClicked: AsyncAction = async ({
146+
state,
147+
effects,
148+
actions,
149+
}) => {
150+
effects.analytics.track('Sign Out', {});
151+
state.workspace.openedWorkspaceItem = 'files';
152+
if (state.live.isLive) {
153+
actions.live.internal.disconnect();
154+
}
155+
await effects.api.delete(`/users/signout`);
156+
actions.internal.removeJwtFromStorage();
157+
state.user = null;
158+
await actions.refetchSandboxInfo();
159+
};
160+
161+
export const signOutGithubIntegration: AsyncAction = async ({
162+
state,
163+
effects,
164+
}) => {
165+
await effects.api.delete(`/users/current_user/integrations/github`);
166+
state.user.integrations.github = null;
167+
};
168+
169+
export const setUpdateStatus: Action<string> = ({ state }, status) => {
170+
state.updateStatus = status;
171+
};
172+
173+
export const refetchSandboxInfo: AsyncAction = async ({ state, actions }) => {
174+
if (state.editor.currentId) {
175+
const id = state.editor.currentId;
176+
const sandbox = await actions.internal.getSandbox(id);
177+
178+
state.editor.sandboxes[id].collection = sandbox.collection;
179+
state.editor.sandboxes[id].owned = sandbox.owned;
180+
state.editor.sandboxes[id].userLiked = sandbox.userLiked;
181+
state.editor.sandboxes[id].title = sandbox.title;
182+
}
183+
};
184+
185+
export const track: Action<{ name: string; data: any }> = (
186+
{ effects },
187+
{ name, data }
188+
) => {
189+
effects.analytics.track(name, data);
190+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const NetlifyBaseURL = 'https://netlify.deploy.codesandbox.io/site';
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import track, {
2+
identify,
3+
setUserId,
4+
} from '@codesandbox/common/lib/utils/analytics';
5+
6+
export default (() => {
7+
const trackedEvents = {};
8+
9+
return {
10+
track,
11+
trackOnce(event: string, data: any) {
12+
if (trackedEvents[event]) {
13+
return;
14+
}
15+
trackedEvents[event] = true;
16+
track(event, data);
17+
},
18+
identify,
19+
setUserId,
20+
};
21+
})();

packages/app/src/app/overmind/effects/api.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,11 @@ export default (() => {
9797
initialize(options: Options) {
9898
_options = options;
9999
},
100-
get(path: string, params?: { [key: string]: string }, options?: {}) {
100+
get<T>(
101+
path: string,
102+
params?: { [key: string]: string },
103+
options?: {}
104+
): Promise<T> {
101105
return axios
102106
.get(API_ROOT + path, {
103107
params,
@@ -106,31 +110,31 @@ export default (() => {
106110
.then(response => handleResponse(response, options))
107111
.catch(e => handleError(e));
108112
},
109-
post(path, body, options) {
113+
post<T>(path, body, options?): Promise<T> {
110114
return axios
111115
.post(API_ROOT + path, decamelizeKeys(body), {
112116
headers: createHeaders(_options.provideJwtToken()),
113117
})
114118
.then(response => handleResponse(response, options))
115119
.catch(e => handleError(e));
116120
},
117-
patch(path, body, options) {
121+
patch<T>(path, body, options?): Promise<T> {
118122
return axios
119123
.patch(API_ROOT + path, decamelizeKeys(body), {
120124
headers: createHeaders(_options.provideJwtToken()),
121125
})
122126
.then(response => handleResponse(response, options))
123127
.catch(e => handleError(e));
124128
},
125-
put(path, body, options) {
129+
put<T>(path, body, options?): Promise<T> {
126130
return axios
127131
.put(API_ROOT + path, decamelizeKeys(body), {
128132
headers: createHeaders(_options.provideJwtToken()),
129133
})
130134
.then(response => handleResponse(response, options))
131135
.catch(e => handleError(e));
132136
},
133-
delete(path, params, options) {
137+
delete<T>(path, params?, options?): Promise<T> {
134138
return axios
135139
.delete(API_ROOT + path, {
136140
params,

packages/app/src/app/overmind/effects/browser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export default {
4545
close: () => popup.close(),
4646
};
4747
},
48-
waitForMessage(type) {
48+
waitForMessage<T>(type): Promise<T> {
4949
return new Promise(resolve => {
5050
window.addEventListener('message', function onMessage(event) {
5151
if (event.data.type === type) {

packages/app/src/app/overmind/effects/connection.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ export default {
88
listeners.set(listener, disposer);
99
},
1010
removeListener(listener: (connected: boolean) => void) {
11-
listeners.get(listener)();
12-
listeners.delete(listener);
11+
if (listeners.has(listener)) {
12+
listeners.get(listener)();
13+
listeners.delete(listener);
14+
}
1315
},
1416
};
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
export default {
2-
get<T>(url: string): Promise<T> {
3-
return window.fetch(url).then(response => response.json());
4-
},
5-
};
1+
import axios from 'axios';
2+
3+
export default axios;

packages/app/src/app/overmind/effects/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,6 @@ export { default as settingsStore } from './settingsStore';
1616
export { default as socket } from './socket';
1717
export { default as sse } from './sse';
1818
export { default as http } from './http';
19+
export { default as analytics } from './analytics';
20+
export { default as notificationToast } from './notificationToast';
21+
export { default as vscode } from './vscode';

0 commit comments

Comments
 (0)