Skip to content

Commit 34e1730

Browse files
author
Joseph Atkins-Turkish
committed
Improved error handling and added save button
1 parent 36990d0 commit 34e1730

File tree

6 files changed

+63
-28
lines changed

6 files changed

+63
-28
lines changed

ide/migrations/0051_auto__add_publishedmedia__add_unique_publishedmedia_project_name.py renamed to ide/migrations/0052_auto__add_publishedmedia__add_unique_publishedmedia_project_name__add_.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,14 @@ def forwards(self, orm):
2525
# Adding unique constraint on 'PublishedMedia', fields ['project', 'name']
2626
db.create_unique(u'ide_publishedmedia', ['project_id', 'name'])
2727

28+
# Adding unique constraint on 'PublishedMedia', fields ['project', 'media_id']
29+
db.create_unique(u'ide_publishedmedia', ['project_id', 'media_id'])
30+
2831

2932
def backwards(self, orm):
33+
# Removing unique constraint on 'PublishedMedia', fields ['project', 'media_id']
34+
db.delete_unique(u'ide_publishedmedia', ['project_id', 'media_id'])
35+
3036
# Removing unique constraint on 'PublishedMedia', fields ['project', 'name']
3137
db.delete_unique(u'ide_publishedmedia', ['project_id', 'name'])
3238

@@ -78,7 +84,7 @@ def backwards(self, orm):
7884
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'builds'", 'to': "orm['ide.Project']"}),
7985
'started': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
8086
'state': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
81-
'uuid': ('django.db.models.fields.CharField', [], {'default': "'8b836ddd-8bc8-4884-bdda-824481f7f05c'", 'max_length': '36'})
87+
'uuid': ('django.db.models.fields.CharField', [], {'default': "'ff465b46-f0da-429e-85ac-6e3fa3ed20e5'", 'max_length': '36'})
8288
},
8389
'ide.buildsize': {
8490
'Meta': {'object_name': 'BuildSize'},
@@ -111,7 +117,7 @@ def backwards(self, orm):
111117
'app_modern_multi_js': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
112118
'app_platforms': ('django.db.models.fields.TextField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
113119
'app_short_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
114-
'app_uuid': ('django.db.models.fields.CharField', [], {'default': "'488507d8-f7d8-449e-b2d9-36c05ba88d4c'", 'max_length': '36', 'null': 'True', 'blank': 'True'}),
120+
'app_uuid': ('django.db.models.fields.CharField', [], {'default': "'0c6dc2fb-3305-4418-9bac-3661c4773ca9'", 'max_length': '36', 'null': 'True', 'blank': 'True'}),
115121
'app_version_label': ('django.db.models.fields.CharField', [], {'default': "'1.0'", 'max_length': '40', 'null': 'True', 'blank': 'True'}),
116122
'github_branch': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
117123
'github_hook_build': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
@@ -129,7 +135,7 @@ def backwards(self, orm):
129135
'sdk_version': ('django.db.models.fields.CharField', [], {'default': "'2'", 'max_length': '6'})
130136
},
131137
'ide.publishedmedia': {
132-
'Meta': {'unique_together': "(('project', 'name'),)", 'object_name': 'PublishedMedia'},
138+
'Meta': {'unique_together': "(('project', 'name'), ('project', 'media_id'))", 'object_name': 'PublishedMedia'},
133139
'glance': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
134140
'has_timeline': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
135141
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
@@ -158,7 +164,7 @@ def backwards(self, orm):
158164
'resource_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
159165
'space_optimisation': ('django.db.models.fields.CharField', [], {'max_length': '7', 'null': 'True', 'blank': 'True'}),
160166
'storage_format': ('django.db.models.fields.CharField', [], {'max_length': '3', 'null': 'True', 'blank': 'True'}),
161-
'target_platforms': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '30', 'null': 'True', 'blank': 'True'}),
167+
'target_platforms': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '100', 'null': 'True', 'blank': 'True'}),
162168
'tracking': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
163169
},
164170
'ide.resourcevariant': {
@@ -199,7 +205,7 @@ def backwards(self, orm):
199205
'theme': ('django.db.models.fields.CharField', [], {'default': "'cloudpebble'", 'max_length': '50'}),
200206
'use_spaces': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
201207
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
202-
'whats_new': ('django.db.models.fields.PositiveIntegerField', [], {'default': '23'})
208+
'whats_new': ('django.db.models.fields.PositiveIntegerField', [], {'default': '24'})
203209
}
204210
}
205211

ide/models/published_media.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@ def clean(self):
5050
raise ValidationError(_("If glance and timeline.tiny are both used, they must be identical."))
5151
if self.has_timeline and not (self.timeline_tiny and self.timeline_small and self.timeline_large):
5252
raise ValidationError(_("If timeline icons are enabled, they must all be set."))
53+
if not self.glance and not self.has_timeline:
54+
raise ValidationError(_("Glance and Timeline cannot both be unset."))
5355
if self.media_id < 0:
5456
raise ValidationError(_("Published Media IDs cannot be negative."))
5557

5658
class Meta(IdeModel.Meta):
57-
unique_together = (('project', 'name'),)
59+
unique_together = (('project', 'name'), ('project', 'media_id'))

ide/static/ide/css/ide.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,7 @@ table.build-results tr.pending .build-state {
690690

691691
.media-tool-buttons button {
692692
width: initial;
693+
min-width: 130px;
693694
margin-right: 10px;
694695
}
695696

ide/static/ide/js/live_settings_form.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,8 @@ function make_live_settings_form(options) {
234234
init: function() {
235235
init();
236236
},
237-
save: function(element) {
238-
return save(element);
237+
save: function(element, event) {
238+
return save(element, event);
239239
}
240240
};
241241
}

ide/static/ide/js/published_media.js

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ CloudPebble.PublishedMedia = (function() {
2424
var pane;
2525
this.show_error = function show_error(error) {
2626
pane.find('.alert-error').removeClass('hide').text(error);
27+
$('#main-pane').animate({scrollTop: 0})
2728
};
2829
this.hide_error = function hide_error() {
2930
pane.find('.alert-error').addClass('hide');
@@ -59,7 +60,7 @@ CloudPebble.PublishedMedia = (function() {
5960
function MediaItem() {
6061
var self = this;
6162
var deleting = false;
62-
var item_form = media_template.find('form');
63+
var item_form = media_template.find('#media-items');
6364
var item = item_template.clone().appendTo(item_form).data('item', this);
6465
var name_input = item.find('.edit-media-name');
6566
var id_input = item.find('.edit-media-id');
@@ -201,7 +202,9 @@ CloudPebble.PublishedMedia = (function() {
201202
});
202203
// Set up the delete button
203204
delete_btn.click(function() {
204-
self.delete();
205+
CloudPebble.Prompts.Confirm(gettext("Do you want to delete this Published Media entry?"), gettext("This cannot be undone."), function() {
206+
self.delete();
207+
});
205208
});
206209

207210
this.setupOptions();
@@ -226,10 +229,6 @@ CloudPebble.PublishedMedia = (function() {
226229
if (!_.every(names)) {
227230
throw new Error(gettext('Identifiers cannot be blank'));
228231
}
229-
// Check that all IDs are unique
230-
if (_.max(_.countBy(data, 'id')) > 1) {
231-
throw new Error(gettext('Numeric IDs must be unique'));
232-
}
233232
// Check that all identifiers are valid
234233
_.each(names, function(name) {
235234
if (!REGEXES.c_identifier.test(name)) {
@@ -238,33 +237,50 @@ CloudPebble.PublishedMedia = (function() {
238237
});
239238
return Ajax.Post('/ide/project/' + PROJECT_ID + '/save_published_media', {
240239
'published_media': JSON.stringify(data)
241-
}).then(function(result) {
242-
// TODO: use 'result' or not?
240+
}).then(function() {
243241
CloudPebble.ProjectInfo.published_media = data;
244242
sync_with_ycm();
245243
return null;
246244
});
247245
}
248246

249247
/** Save the whole form. If any names are incomplete or resources are invalid, it simply refuses to save without error. */
250-
function save_forms() {
251-
var items = get_media_items();
248+
function save_forms(event) {
252249
var data = get_form_data();
250+
var do_cancel = !event || event.type != 'submit';
251+
var items = get_media_items();
253252
var identifiers = get_eligible_identifiers();
253+
function maybe_error(text) {
254+
if (do_cancel) return {incomplete: true};
255+
throw new Error(text);
256+
}
254257
// If not all items have names, cancel saving without displaying an error
255258
if (!_.every(_.pluck(data, 'name'))) {
256-
return {incomplete: true};
259+
return maybe_error(gettext("Published Media must have non-empty identifiers."))
260+
}
261+
262+
// Cancel if there are any incomplete items
263+
if (!_.every(_.map(data, function(item) {
264+
return !!item.timeline || !!item.glance;
265+
}))) {
266+
return maybe_error(gettext("Published Media items must specify glance, timeline icons, or both."))
267+
}
268+
269+
// Check that all IDs are unique
270+
if (_.max(_.countBy(data, 'id')) > 1) {
271+
return maybe_error(gettext("Published Media IDs must be unique."))
257272
}
258-
// Raise an error if there are any invalid selections
273+
274+
// Cancel (and show the 'invalid items' icon in the sidebar) if there are any invalid values
259275
var validity = _.map(items, function(item) {return item.is_valid(identifiers);});
260276
if (!_.every(validity)) {
261277
toggle_sidebar_error(true);
262-
return {incomplete: true};
278+
return maybe_error(gettext("You cannot save Published Media items with references to resuorces which do not exist."))
263279
}
264280

265-
// If we successfully saved, it implies that there were no invalid references
266-
// so we can get rid of the sidebar error notification.
267281
return save_pubished_media(data).then(function() {
282+
// If we successfully saved, it implies that there were no invalid references
283+
// so we can get rid of the sidebar error notification.
268284
toggle_sidebar_error(false);
269285
});
270286
}
@@ -274,12 +290,17 @@ CloudPebble.PublishedMedia = (function() {
274290
if (media_pane_setup) return false;
275291
media_pane_setup = true;
276292

277-
var initial_data = CloudPebble.ProjectInfo.published_media;
278-
_.each(initial_data, function(data) {
293+
// Set up the data
294+
_.each(CloudPebble.ProjectInfo.published_media, function(data) {
279295
var item = new MediaItem();
280296
item.setData(data);
281297
});
282298

299+
media_template.find('form').submit(function(e) {
300+
live_form.save(null, e);
301+
return false;
302+
});
303+
283304
media_template.find('#add-published-media').click(function() {
284305
new MediaItem();
285306
});
@@ -290,7 +311,7 @@ CloudPebble.PublishedMedia = (function() {
290311
error_function: alerts.show_error,
291312
on_progress_started: alerts.show_progress,
292313
on_progress_complete: alerts.hide_progress,
293-
form: media_template.find('form')
314+
form: media_template.find('#media-items')
294315
});
295316
media_template.find('.media-tool-buttons').removeClass('hide');
296317
media_template.find('.media-pane-loading').remove();

ide/templates/ide/project/published_media.html

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,23 @@
22
<!-- Compilation pane -->
33
<div id="media-pane-template" class="hide media-pane resource-pane">
44
<div class="well alert alert-error hide"></div>
5-
<form class="form-horizontal">
6-
</form>
5+
<form>
6+
<div id="media-items" class="form-horizontal">
77

8+
</div>
89
<div class="well media-pane-loading">
910
<h2>{% trans 'Loading...' %}</h2>
1011
</div>
1112

1213
<div class="well hide media-tool-buttons">
14+
<button type="submit" class="btn btn-affirmative" id="save-published-media">
15+
{% trans 'Save' %}
16+
</button>
1317
<button type="button" class="btn" id="add-published-media">
1418
{% trans 'Add New Published Media' %}
1519
</button>
1620
</div>
21+
</form>
1722
</div>
1823

1924
<div class="well hide media-item" id="media-item-template" >

0 commit comments

Comments
 (0)