Skip to content

Commit 8db091a

Browse files
authored
Show notifications upon success or failure of save and delete objects (#718)
1 parent 107e87c commit 8db091a

File tree

3 files changed

+108
-16
lines changed

3 files changed

+108
-16
lines changed

src/dashboard/Data/Browser/Browser.react.js

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export default class Browser extends DashboardView {
3939
this.section = 'Core';
4040
this.subsection = 'Browser'
4141
this.action = new SidebarAction('Create a class', this.showCreateClass.bind(this));
42+
this.noteTimeout = null;
4243

4344
this.state = {
4445
showCreateClassDialog: false,
@@ -62,6 +63,8 @@ export default class Browser extends DashboardView {
6263
newObject: null,
6364

6465
lastError: null,
66+
lastNote: null,
67+
6568
relationCount: 0,
6669
};
6770

@@ -225,7 +228,8 @@ export default class Browser extends DashboardView {
225228
if (msg) {
226229
msg = msg[0].toUpperCase() + msg.substr(1);
227230
}
228-
this.setState({ lastError: msg });
231+
232+
this.showNote(msg, true);
229233
});
230234
}
231235

@@ -480,8 +484,13 @@ export default class Browser extends DashboardView {
480484
} else {
481485
obj.set(attr, value);
482486
}
483-
obj.save(null, { useMasterKey: true }).then(() => {
484-
const state = { data: this.state.data, lastError: null };
487+
obj.save(null, { useMasterKey: true }).then((objectSaved) => {
488+
const createdOrUpdated = isNewObject ? "created" : "updated";
489+
let msg = objectSaved.className + " with id '" + objectSaved.id + "' " + createdOrUpdated;
490+
this.showNote(msg, false);
491+
492+
const state = { data: this.state.data };
493+
485494
if (isNewObject) {
486495
const relation = this.state.relation;
487496
if (relation) {
@@ -508,7 +517,8 @@ export default class Browser extends DashboardView {
508517
msg = msg[0].toUpperCase() + msg.substr(1);
509518
}
510519
obj.set(attr, prev);
511-
this.setState({ data: this.state.data, lastError: msg });
520+
this.setState({ data: this.state.data });
521+
this.showNote(msg, true);
512522
});
513523
} else {
514524
state.newObject = null;
@@ -526,10 +536,10 @@ export default class Browser extends DashboardView {
526536
}
527537
if (!isNewObject) {
528538
obj.set(attr, prev);
529-
this.setState({ data: this.state.data, lastError: msg });
530-
} else {
531-
this.setState({ lastError: msg });
539+
this.setState({ data: this.state.data });
532540
}
541+
542+
this.showNote(msg, true);
533543
});
534544
}
535545

@@ -561,6 +571,10 @@ export default class Browser extends DashboardView {
561571
toDelete.push(this.state.data[i]);
562572
}
563573
}
574+
575+
const toDeleteObjectIds = [];
576+
toDelete.forEach((obj) => { toDeleteObjectIds.push(obj.id); });
577+
564578
let relation = this.state.relation;
565579
if (relation && toDelete.length) {
566580
relation.remove(toDelete);
@@ -576,13 +590,43 @@ export default class Browser extends DashboardView {
576590
});
577591
} else if (toDelete.length) {
578592
Parse.Object.destroyAll(toDelete, { useMasterKey: true }).then(() => {
593+
let deletedNote;
594+
595+
if (toDeleteObjectIds.length == 1) {
596+
deletedNote = className + " with id '" + toDeleteObjectIds[0] + "' deleted";
597+
} else {
598+
deletedNote = toDeleteObjectIds.length + " " + className + " objects deleted";
599+
}
600+
601+
this.showNote(deletedNote, false);
602+
579603
if (this.props.params.className === className) {
580604
for (let i = 0; i < indexes.length; i++) {
581605
this.state.data.splice(indexes[i] - i, 1);
582606
}
583607
this.state.counts[className] -= indexes.length;
584608
this.forceUpdate();
585609
}
610+
}, (error) => {
611+
let errorDeletingNote = null;
612+
613+
if (error.code === Parse.Error.AGGREGATE_ERROR) {
614+
if (error.errors.length == 1) {
615+
errorDeletingNote = "Error deleting " + className + " with id '" + error.errors[0].object.id + "'";
616+
} else if (error.errors.length < toDeleteObjectIds.length) {
617+
errorDeletingNote = "Error deleting " + error.errors.length + " out of " + toDeleteObjectIds.length + " " + className + " objects";
618+
} else {
619+
errorDeletingNote = "Error deleting all " + error.errors.length + " " + className + " objects";
620+
}
621+
} else {
622+
if (toDeleteObjectIds.length == 1) {
623+
errorDeletingNote = "Error deleting " + className + " with id '" + toDeleteObjectIds[0] + "'";
624+
} else {
625+
errorDeletingNote = "Error deleting " + toDeleteObjectIds.length + " " + className + " objects";
626+
}
627+
}
628+
629+
this.showNote(errorDeletingNote, true);
586630
});
587631
}
588632
}
@@ -748,6 +792,24 @@ export default class Browser extends DashboardView {
748792
);
749793
}
750794

795+
showNote(message, isError) {
796+
if (!message) {
797+
return;
798+
}
799+
800+
clearTimeout(this.noteTimeout);
801+
802+
if (isError) {
803+
this.setState({ lastError: message, lastNote: null });
804+
} else {
805+
this.setState({ lastNote: message, lastError: null });
806+
}
807+
808+
this.noteTimeout = setTimeout(() => {
809+
this.setState({ lastError: null, lastNote: null });
810+
}, 3500);
811+
}
812+
751813
renderContent() {
752814
let browser = null;
753815
let className = this.props.params.className;
@@ -886,6 +948,7 @@ export default class Browser extends DashboardView {
886948
onCancel={() => this.setState({
887949
showDropClassDialog: false,
888950
lastError: null,
951+
lastNote: null,
889952
})}
890953
onConfirm={() => this.dropClass(className)} />
891954
);
@@ -915,10 +978,22 @@ export default class Browser extends DashboardView {
915978
/>
916979
);
917980
}
981+
982+
let notification = null;
983+
984+
if (this.state.lastError) {
985+
notification = (
986+
<Notification note={this.state.lastError} isErrorNote={true}/>
987+
);
988+
} else if (this.state.lastNote) {
989+
notification = (
990+
<Notification note={this.state.lastNote} isErrorNote={false}/>
991+
);
992+
}
918993
return (
919994
<div>
920995
{browser}
921-
<Notification note={this.state.lastError} />
996+
{notification}
922997
{extras}
923998
</div>
924999
);

src/dashboard/Data/Browser/Browser.scss

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,21 +138,29 @@
138138
}
139139
}
140140

141-
.notification {
141+
.notificationMessage, .notificationError {
142142
@include animation('fade-in 0.2s ease-out');
143143
position: absolute;
144144
bottom: 20px;
145145
right: 20px;
146146
opacity: 1;
147147
background: white;
148148
padding: 10px;
149-
border: 2px solid $red;
150-
color: $red;
151149
font-size: 14px;
152150
border-radius: 5px;
153151
width: 260px;
154152
}
155153

154+
.notificationError {
155+
border: 2px solid $red;
156+
color: $red;
157+
}
158+
159+
.notificationMessage {
160+
border: 2px solid $blue;
161+
color: $blue;
162+
}
163+
156164
.notificationHide {
157165
@include animation('fade-out 0.2s ease-out');
158166
}

src/dashboard/Data/Browser/Notification.react.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ import React from 'react';
1111
import styles from 'dashboard/Data/Browser/Browser.scss';
1212

1313
export default class Notification extends React.Component {
14-
constructor() {
14+
constructor(props) {
1515
super();
1616

1717
this.state = {
18-
lastNote: null,
18+
lastNote: props.note,
19+
isErrorNote: props.isErrorNote,
1920
hiding: false,
2021
};
2122

@@ -30,9 +31,9 @@ export default class Notification extends React.Component {
3031
if (this.state.lastNote !== nextProps.note) {
3132
clearTimeout(this.timeout);
3233
if (this.state.hiding) {
33-
this.setState({ lastNote: nextProps.note, hiding: false })
34+
this.setState({ lastNote: nextProps.note, isErrorNote: nextProps.isErrorNote, hiding: false })
3435
} else {
35-
this.setState({ lastNote: nextProps.note });
36+
this.setState({ lastNote: nextProps.note, isErrorNote: nextProps.isErrorNote });
3637
}
3738
}
3839
if (!nextProps.note) {
@@ -50,8 +51,16 @@ export default class Notification extends React.Component {
5051
if (!this.state.lastNote) {
5152
return null;
5253
}
54+
5355
let bottomRight = new Position(window.innerWidth, window.innerHeight);
54-
let classes = [styles.notification];
56+
let classes = [];
57+
58+
if (this.state.isErrorNote) {
59+
classes.push(styles.notificationError);
60+
} else {
61+
classes.push(styles.notificationMessage);
62+
}
63+
5564
if (this.state.hiding) {
5665
classes.push(styles.notificationHide);
5766
}

0 commit comments

Comments
 (0)