Skip to content

Commit 3ad92b3

Browse files
refarerCompuIves
authored andcommitted
Export sandboxes from dashboard (codesandbox#1878)
* exportSandboxes, getSandbox funcs & menu options * move export above trash and add separator
1 parent 5181fc2 commit 3ad92b3

File tree

2 files changed

+82
-26
lines changed

2 files changed

+82
-26
lines changed

packages/app/src/app/pages/Dashboard/Content/SandboxCard/index.tsx

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type Props = {
4545
) => void;
4646
selectedCount: number;
4747
deleteSandboxes: () => void;
48+
exportSandboxes: () => void;
4849
permanentlyDeleteSandboxes: () => void;
4950
collectionPath: string; // eslint-disable-line react/no-unused-prop-types
5051
collectionTeamId: string | undefined;
@@ -208,6 +209,15 @@ class SandboxItem extends React.PureComponent<Props, State> {
208209
}
209210
return [
210211
...items,
212+
[
213+
{
214+
title: `Export ${selectedCount} Sandboxes`,
215+
action: () => {
216+
this.props.exportSandboxes()
217+
return true;
218+
},
219+
},
220+
],
211221
[
212222
{
213223
title: `Move ${selectedCount} Sandboxes To Trash`,
@@ -216,7 +226,7 @@ class SandboxItem extends React.PureComponent<Props, State> {
216226
return true;
217227
},
218228
color: theme.red.darken(0.2)(),
219-
},
229+
}
220230
],
221231
];
222232
}
@@ -229,7 +239,7 @@ class SandboxItem extends React.PureComponent<Props, State> {
229239
if (this.props.collectionTeamId) {
230240
history.push(
231241
`/dashboard/teams/${this.props.collectionTeamId}/sandboxes${
232-
this.props.collectionPath
242+
this.props.collectionPath
233243
}`
234244
);
235245
} else {
@@ -250,31 +260,38 @@ class SandboxItem extends React.PureComponent<Props, State> {
250260
return true;
251261
},
252262
},
263+
{
264+
title: 'Export Sandbox',
265+
action: () => {
266+
this.props.exportSandboxes();
267+
return true;
268+
},
269+
},
253270
],
254271
this.props.isPatron &&
255-
[
256-
this.props.privacy !== 0 && {
257-
title: `Make Sandbox Public`,
258-
action: () => {
259-
this.props.setSandboxesPrivacy(0);
260-
return true;
261-
},
272+
[
273+
this.props.privacy !== 0 && {
274+
title: `Make Sandbox Public`,
275+
action: () => {
276+
this.props.setSandboxesPrivacy(0);
277+
return true;
262278
},
263-
this.props.privacy !== 1 && {
264-
title: `Make Sandbox Unlisted`,
265-
action: () => {
266-
this.props.setSandboxesPrivacy(1);
267-
return true;
268-
},
279+
},
280+
this.props.privacy !== 1 && {
281+
title: `Make Sandbox Unlisted`,
282+
action: () => {
283+
this.props.setSandboxesPrivacy(1);
284+
return true;
269285
},
270-
this.props.privacy !== 2 && {
271-
title: `Make Sandbox Private`,
272-
action: () => {
273-
this.props.setSandboxesPrivacy(2);
274-
return true;
275-
},
286+
},
287+
this.props.privacy !== 2 && {
288+
title: `Make Sandbox Private`,
289+
action: () => {
290+
this.props.setSandboxesPrivacy(2);
291+
return true;
276292
},
277-
].filter(Boolean),
293+
},
294+
].filter(Boolean),
278295
[
279296
{
280297
title: `Rename Sandbox`,
@@ -533,10 +550,10 @@ class SandboxItem extends React.PureComponent<Props, State> {
533550
}}
534551
</Mutation>
535552
) : (
536-
<SandboxTitle>
537-
{title} {this.getPrivacyIcon()}
538-
</SandboxTitle>
539-
)}
553+
<SandboxTitle>
554+
{title} {this.getPrivacyIcon()}
555+
</SandboxTitle>
556+
)}
540557
</div>
541558
<SandboxDetails>{details}</SandboxDetails>
542559
</div>

packages/app/src/app/pages/Dashboard/Content/SandboxGrid/index.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ import { inject, observer } from 'mobx-react';
44
import moment from 'moment';
55
import { uniq } from 'lodash-es';
66
import { basename } from 'path';
7+
import { camelizeKeys } from 'humps';
78

89
import track from '@codesandbox/common/lib/utils/analytics';
10+
import { protocolAndHost } from '@codesandbox/common/lib/utils/url-generator';
911
import Grid from 'react-virtualized/dist/commonjs/Grid';
1012
import Column from 'react-virtualized/dist/commonjs/Table/Column';
1113
import Table from 'react-virtualized/dist/commonjs/Table';
1214
import AutoSizer from 'react-virtualized/dist/commonjs/AutoSizer';
15+
import downloadZip from 'app/store/providers/Utils/create-zip';
1316
import 'react-virtualized/styles.css';
1417

1518
import SandboxItem from '../SandboxCard';
@@ -45,6 +48,8 @@ class SandboxGrid extends React.Component<*, State> {
4548
selection: undefined,
4649
};
4750

51+
loadedSandboxes = {};
52+
4853
setSandboxesSelected = (ids, { additive = false, range = false } = {}) => {
4954
const { store, sandboxes, signals } = this.props;
5055
const selectedSandboxes = store.dashboard.selectedSandboxes;
@@ -116,6 +121,39 @@ class SandboxGrid extends React.Component<*, State> {
116121
setSandboxesPrivacy(this.props.store.dashboard.selectedSandboxes, privacy);
117122
};
118123

124+
getSandbox = async sandboxId => {
125+
if (this.loadedSandboxes[sandboxId]) {
126+
return Promise.resolve(this.loadedSandboxes[sandboxId]);
127+
}
128+
129+
return fetch(`${protocolAndHost()}/api/v1/sandboxes/${sandboxId}`, {
130+
headers: {
131+
'Content-Type': 'application/json',
132+
Authorization: `Bearer ${JSON.parse(localStorage.getItem('jwt'))}`,
133+
},
134+
})
135+
.then(x => x.json())
136+
.then(x => {
137+
const data = camelizeKeys(x.data);
138+
this.loadedSandboxes[data.id] = data;
139+
return data;
140+
});
141+
};
142+
143+
exportSandboxes = async () => {
144+
const sandboxIds = uniq(
145+
this.props.sandboxes
146+
.filter(sandbox => this.selectedSandboxesObject[sandbox.id])
147+
.map(s => s.id)
148+
);
149+
const sandboxes = await Promise.all(
150+
sandboxIds.map(s => this.getSandbox(s))
151+
);
152+
return Promise.all(
153+
sandboxes.map(s => downloadZip(s, s.modules, s.directories))
154+
);
155+
};
156+
119157
onMouseDown = (event: MouseEvent) => {
120158
this.setState({
121159
selection: {
@@ -262,6 +300,7 @@ class SandboxGrid extends React.Component<*, State> {
262300
deleteSandboxes={this.deleteSandboxes}
263301
undeleteSandboxes={this.undeleteSandboxes}
264302
permanentlyDeleteSandboxes={this.permanentlyDeleteSandboxes}
303+
exportSandboxes={this.exportSandboxes}
265304
setSandboxesPrivacy={this.setSandboxesPrivacy}
266305
page={this.props.page}
267306
privacy={item.privacy}

0 commit comments

Comments
 (0)