Skip to content

Commit

Permalink
Add export restore point button
Browse files Browse the repository at this point in the history
  • Loading branch information
GarboMuffin committed Jan 18, 2025
1 parent afe00d5 commit 869f1c6
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 18 deletions.
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
},
"dependencies": {
"@microbit/microbit-universal-hex": "0.2.2",
"@turbowarp/jszip": "^3.11.1",
"@turbowarp/nanolog": "^0.2.0",
"@turbowarp/scratch-l10n": "^3.1001.0-202401241456-994097a5",
"@turbowarp/scratch-storage": "^0.0.202403251715",
Expand Down
2 changes: 2 additions & 0 deletions src/components/tw-restore-point-modal/export.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 14 additions & 5 deletions src/components/tw-restore-point-modal/restore-point-modal.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
@import "../../css/filters.css";

.modal-content {
max-width: 550px;
max-width: 600px;
margin-top: 50px;
}

Expand Down Expand Up @@ -96,25 +96,34 @@
font-size: 2em;
}

.delete-button {
.restore-point-buttons {
margin-left: auto;
display: flex;
flex-direction: row;
gap: 0.5rem;
}

.restore-point-button {
appearance: none;
background: none;
border: none;
border-radius: 100%;
width: 2rem;
height: 2rem;
margin-left: auto;
display: flex;
align-items: center;
justify-content: center;
}
.delete-button img {
.restore-point-button[disabled] {
opacity: 0.5;
}
.restore-point-button img {
display: block;
width: 75%;
height: 75%;
filter: $filter-icon-gray;
}
.delete-button:hover {
.restore-point-button:not([disabled]):hover {
background-color: $ui-black-transparent;
}

Expand Down
4 changes: 4 additions & 0 deletions src/components/tw-restore-point-modal/restore-point-modal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,9 @@ const RestorePointModal = props => (
<RestorePoint
key={restorePoint.id}
onClickDelete={props.onClickDelete}
onClickExport={props.onClickExport}
onClickLoad={props.onClickLoad}
isExporting={props.isExporting(restorePoint.id)}
{...restorePoint}
/>
))}
Expand Down Expand Up @@ -221,7 +223,9 @@ RestorePointModal.propTypes = {
onClickCreate: PropTypes.func.isRequired,
onClickDelete: PropTypes.func.isRequired,
onClickDeleteAll: PropTypes.func.isRequired,
onClickExport: PropTypes.func.isRequired,
onClickLoad: PropTypes.func.isRequired,
isExporting: PropTypes.func.isRequired,
isLoading: PropTypes.bool.isRequired,
totalSize: PropTypes.number.isRequired,
restorePoints: PropTypes.arrayOf(PropTypes.shape({})),
Expand Down
44 changes: 34 additions & 10 deletions src/components/tw-restore-point-modal/restore-point.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import styles from './restore-point-modal.css';
import {formatBytes} from '../../lib/tw-bytes-utils';
import RestorePointAPI from '../../lib/tw-restore-point-api';
import log from '../../lib/log';
import exportIcon from './export.svg';
import deleteIcon from './delete.svg';

// Browser support is not perfect yet
Expand All @@ -16,6 +17,7 @@ class RestorePoint extends React.Component {
super(props);
bindAll(this, [
'handleClickDelete',
'handleClickExport',
'handleClickLoad'
]);
this.state = {
Expand Down Expand Up @@ -69,6 +71,11 @@ class RestorePoint extends React.Component {
this.props.onClickDelete(this.props.id);
}

handleClickExport (e) {
e.stopPropagation();
this.props.onClickExport(this.props.id);
}

handleClickLoad () {
this.props.onClickLoad(this.props.id);
}
Expand Down Expand Up @@ -129,16 +136,31 @@ class RestorePoint extends React.Component {
</div>
</div>

<button
className={styles.deleteButton}
onClick={this.handleClickDelete}
>
<img
src={deleteIcon}
alt="Delete"
draggable={false}
/>
</button>
<div className={styles.restorePointButtons}>
<button
className={styles.restorePointButton}
onClick={this.handleClickExport}
disabled={this.props.isExporting}
>
<img
src={exportIcon}
alt="Export"
draggable={false}
/>
</button>

<button
className={styles.restorePointButton}
onClick={this.handleClickDelete}
disabled={this.props.isExporting}
>
<img
src={deleteIcon}
alt="Delete"
draggable={false}
/>
</button>
</div>
</div>
);
}
Expand All @@ -151,7 +173,9 @@ RestorePoint.propTypes = {
projectSize: PropTypes.number.isRequired,
thumbnailSize: PropTypes.number.isRequired,
assets: PropTypes.shape({}).isRequired, // Record<string, number>
isExporting: PropTypes.bool.isRequired,
onClickDelete: PropTypes.func.isRequired,
onClickExport: PropTypes.func.isRequired,
onClickLoad: PropTypes.func.isRequired
};

Expand Down
48 changes: 46 additions & 2 deletions src/containers/tw-restore-point-manager.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {setFileHandle} from '../reducers/tw';
import TWRestorePointModal from '../components/tw-restore-point-modal/restore-point-modal.jsx';
import RestorePointAPI from '../lib/tw-restore-point-api';
import log from '../lib/log';
import downloadBlob from '../lib/download-blob.js';

/* eslint-disable no-alert */

Expand Down Expand Up @@ -38,6 +39,11 @@ const messages = defineMessages({
defaultMessage: 'Error loading restore point: {error}',
description: 'Error message when a restore point could not be loaded',
id: 'tw.restorePoints.error'
},
exportError: {
defaultMessage: 'Error exporting restore point: {error}',
description: 'Error message when a restore point could not be exported',
id: 'tw.restorePoints.exportError'
}
});

Expand All @@ -50,14 +56,17 @@ class TWRestorePointManager extends React.Component {
'handleClickDelete',
'handleClickDeleteAll',
'handleChangeInterval',
'handleClickLoad'
'handleClickExport',
'handleClickLoad',
'isExportingRestorePoint'
]);
this.state = {
loading: true,
totalSize: 0,
restorePoints: [],
error: null,
interval: RestorePointAPI.readInterval()
interval: RestorePointAPI.readInterval(),
exportingRestorePoints: []
};
this.timeout = null;
}
Expand Down Expand Up @@ -148,6 +157,39 @@ class TWRestorePointManager extends React.Component {
return true;
}

handleClickExport (id) {
if (this.isExportingRestorePoint(id)) {
return;
}

this.setState(oldState => ({
exportingRestorePoints: [...oldState.exportingRestorePoints, id]
}));

const removeFromExportingList = () => {
this.setState(oldState => ({
exportingRestorePoints: oldState.exportingRestorePoints.filter(i => i !== id)
}));
};

RestorePointAPI.exportRestorePoint(id)
.then(result => {
downloadBlob(`${result.title}.sb3`, result.blob);
removeFromExportingList();
})
.catch(error => {
log.error(error);
alert(this.props.intl.formatMessage(messages.exportError, {
error
}));
removeFromExportingList();
});
}

isExportingRestorePoint (id) {
return this.state.exportingRestorePoints.includes(id);
}

handleClickLoad (id) {
if (!this.canLoadProject()) {
return;
Expand Down Expand Up @@ -271,9 +313,11 @@ class TWRestorePointManager extends React.Component {
onClickCreate={this.handleClickCreate}
onClickDelete={this.handleClickDelete}
onClickDeleteAll={this.handleClickDeleteAll}
onClickExport={this.handleClickExport}
onClickLoad={this.handleClickLoad}
interval={this.state.interval}
onChangeInterval={this.handleChangeInterval}
isExporting={this.isExportingRestorePoint}
isLoading={this.state.loading}
totalSize={this.state.totalSize}
restorePoints={this.state.restorePoints}
Expand Down
Loading

0 comments on commit 869f1c6

Please sign in to comment.