From 647c96dcd37a2263dc68cdc9bc3539dd9d93aa3d Mon Sep 17 00:00:00 2001 From: Branson Stephens <branson.stephens@ligo.org> Date: Sun, 10 May 2015 10:45:01 -0500 Subject: [PATCH] Added comment field to EMObservation. Added comment to view logic and form. Added the comment to the EMO display. Moved the EMO display into the log digests section. --- ...1_auto__add_field_emobservation_comment.py | 318 ++++++++++++++++++ gracedb/models.py | 2 + gracedb/view_logic.py | 2 + gracedb/view_utils.py | 3 +- static/css/style.css | 4 + templates/gracedb/emo_form_frag.html | 3 + templates/gracedb/event_detail.html | 2 +- templates/gracedb/event_detail_script.js | 269 +++++++++------ 8 files changed, 495 insertions(+), 108 deletions(-) create mode 100644 gracedb/migrations/0041_auto__add_field_emobservation_comment.py diff --git a/gracedb/migrations/0041_auto__add_field_emobservation_comment.py b/gracedb/migrations/0041_auto__add_field_emobservation_comment.py new file mode 100644 index 000000000..f4b565900 --- /dev/null +++ b/gracedb/migrations/0041_auto__add_field_emobservation_comment.py @@ -0,0 +1,318 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'EMObservation.comment' + db.add_column(u'gracedb_emobservation', 'comment', + self.gf('django.db.models.fields.TextField')(default='', blank=True), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'EMObservation.comment' + db.delete_column(u'gracedb_emobservation', 'comment') + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'gracedb.approval': { + 'Meta': {'object_name': 'Approval'}, + 'approvedEvent': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + 'approver': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'approvingCollaboration': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'gracedb.coincinspiralevent': { + 'Meta': {'ordering': "['-id']", 'object_name': 'CoincInspiralEvent', '_ormbases': [u'gracedb.Event']}, + 'combined_far': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'end_time': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'end_time_ns': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + u'event_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['gracedb.Event']", 'unique': 'True', 'primary_key': 'True'}), + 'false_alarm_rate': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'ifos': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20'}), + 'mass': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'mchirp': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'minimum_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'snr': ('django.db.models.fields.FloatField', [], {'null': 'True'}) + }, + u'gracedb.embbeventlog': { + 'Meta': {'ordering': "['-created', '-N']", 'unique_together': "(('event', 'N'),)", 'object_name': 'EMBBEventLog'}, + 'N': ('django.db.models.fields.IntegerField', [], {}), + 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'dec': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'decList': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'decWidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'decWidthList': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'duration': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'durationList': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'eel_status': ('django.db.models.fields.CharField', [], {'max_length': '2'}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + 'extra_info_dict': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'footprintID': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'gpstime': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'gpstimeList': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.EMGroup']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'instrument': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), + 'obs_status': ('django.db.models.fields.CharField', [], {'max_length': '2'}), + 'ra': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'raList': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'raWidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'raWidthList': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'submitter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'waveband': ('django.db.models.fields.CharField', [], {'max_length': '25'}) + }, + u'gracedb.emfootprint': { + 'Meta': {'ordering': "['-N']", 'unique_together': "(('observation', 'N'),)", 'object_name': 'EMFootprint'}, + 'N': ('django.db.models.fields.IntegerField', [], {}), + 'dec': ('django.db.models.fields.FloatField', [], {}), + 'decWidth': ('django.db.models.fields.FloatField', [], {}), + 'exposure_time': ('django.db.models.fields.PositiveIntegerField', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'observation': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.EMObservation']"}), + 'ra': ('django.db.models.fields.FloatField', [], {}), + 'raWidth': ('django.db.models.fields.FloatField', [], {}), + 'start_time': ('django.db.models.fields.DateTimeField', [], {}) + }, + u'gracedb.emgroup': { + 'Meta': {'object_name': 'EMGroup'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'}) + }, + u'gracedb.emobservation': { + 'Meta': {'ordering': "['-created', '-N']", 'unique_together': "(('event', 'N'),)", 'object_name': 'EMObservation'}, + 'N': ('django.db.models.fields.IntegerField', [], {}), + 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'dec': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'decWidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.EMGroup']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ra': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'raWidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'submitter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) + }, + u'gracedb.event': { + 'Meta': {'ordering': "['-id']", 'object_name': 'Event'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'far': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'gpstime': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '16', 'decimal_places': '6'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'instruments': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20'}), + 'labels': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['gracedb.Label']", 'through': u"orm['gracedb.Labelling']", 'symmetrical': 'False'}), + 'likelihood': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'nevents': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'perms': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'pipeline': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Pipeline']"}), + 'search': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Search']", 'null': 'True'}), + 'submitter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) + }, + u'gracedb.eventlog': { + 'Meta': {'ordering': "['-created', '-N']", 'unique_together': "(('event', 'N'),)", 'object_name': 'EventLog'}, + 'N': ('django.db.models.fields.IntegerField', [], {}), + 'comment': ('django.db.models.fields.TextField', [], {}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + 'file_version': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'issuer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) + }, + u'gracedb.grbevent': { + 'Meta': {'ordering': "['-id']", 'object_name': 'GrbEvent', '_ormbases': [u'gracedb.Event']}, + 'author_ivorn': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'author_shortname': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'coord_system': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'dec': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'error_radius': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + u'event_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['gracedb.Event']", 'unique': 'True', 'primary_key': 'True'}), + 'how_description': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'how_reference_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}), + 'ivorn': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'observatory_location_id': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'ra': ('django.db.models.fields.FloatField', [], {'null': 'True'}) + }, + u'gracedb.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '20'}) + }, + u'gracedb.label': { + 'Meta': {'object_name': 'Label'}, + 'defaultColor': ('django.db.models.fields.CharField', [], {'default': "'black'", 'max_length': '20'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'}) + }, + u'gracedb.labelling': { + 'Meta': {'object_name': 'Labelling'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Label']"}) + }, + u'gracedb.multiburstevent': { + 'Meta': {'ordering': "['-id']", 'object_name': 'MultiBurstEvent', '_ormbases': [u'gracedb.Event']}, + 'amplitude': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'bandwidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'central_freq': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'confidence': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + u'event_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['gracedb.Event']", 'unique': 'True', 'primary_key': 'True'}), + 'false_alarm_rate': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'ifos': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20'}), + 'ligo_angle': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'ligo_angle_sig': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'ligo_axis_dec': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'ligo_axis_ra': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'peak_time': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'peak_time_ns': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'snr': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'start_time': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'start_time_ns': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}) + }, + u'gracedb.pipeline': { + 'Meta': {'object_name': 'Pipeline'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'gracedb.search': { + 'Meta': {'object_name': 'Search'}, + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'gracedb.singleinspiral': { + 'Gamma0': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma1': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma2': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma3': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma4': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma5': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma6': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma7': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma8': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Gamma9': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'Meta': {'object_name': 'SingleInspiral'}, + 'alpha': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'alpha1': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'alpha2': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'alpha3': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'alpha4': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'alpha5': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'alpha6': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'amplitude': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'bank_chisq': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'bank_chisq_dof': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'beta': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'channel': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'chi': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'chisq': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'chisq_dof': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'coa_phase': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'cont_chisq': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'cont_chisq_dof': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'eff_distance': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'end_time': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'end_time_gmst': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'end_time_ns': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'eta': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + 'event_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'f_final': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ifo': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True'}), + 'impulse_time': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'impulse_time_ns': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'kappa': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'mass1': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'mass2': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'mchirp': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'mtotal': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'psi0': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'psi3': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'rsqveto_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'search': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True'}), + 'sigmasq': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'snr': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'spin1x': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'spin1y': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'spin1z': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'spin2x': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'spin2y': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'spin2z': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'tau0': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'tau2': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'tau3': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'tau4': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'tau5': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'template_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'ttotal': ('django.db.models.fields.FloatField', [], {'null': 'True'}) + }, + u'gracedb.tag': { + 'Meta': {'object_name': 'Tag'}, + 'displayName': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'eventlogs': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['gracedb.EventLog']", 'symmetrical': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'gracedb.voevent': { + 'Meta': {'ordering': "['-created', '-N']", 'unique_together': "(('event', 'N'),)", 'object_name': 'VOEvent'}, + 'N': ('django.db.models.fields.IntegerField', [], {}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}), + 'file_version': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'issuer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'ivorn': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200'}), + 'voevent_type': ('django.db.models.fields.CharField', [], {'max_length': '2'}) + } + } + + complete_apps = ['gracedb'] \ No newline at end of file diff --git a/gracedb/models.py b/gracedb/models.py index 2d7daa84c..5987b11fb 100644 --- a/gracedb/models.py +++ b/gracedb/models.py @@ -427,6 +427,8 @@ class EMObservation(models.Model): raWidth = models.FloatField(null=True) decWidth = models.FloatField(null=True) + comment = models.TextField(blank=True) + # We overload the 'save' method to avoid race conditions, since the Eels are numbered. def save(self, *args, **kwargs): success = False diff --git a/gracedb/view_logic.py b/gracedb/view_logic.py index ee96a5515..4583fab11 100644 --- a/gracedb/view_logic.py +++ b/gracedb/view_logic.py @@ -382,6 +382,8 @@ def create_emobservation(d, event, user): except: raise ValueError('Please specify an EM followup MOU group') + emo.comment = d.get('comment', '') + # Assign RA and Dec, plus widths try: raList = d.get('raList') diff --git a/gracedb/view_utils.py b/gracedb/view_utils.py index 463238380..ccb832b22 100644 --- a/gracedb/view_utils.py +++ b/gracedb/view_utils.py @@ -306,6 +306,7 @@ def emObservationToDict(emo, request=None): "created" : emo.created.isoformat(), "submitter" : emo.submitter.username, "group" : emo.group.name, + "comment" : emo.comment, "ra" : emo.ra, "dec" : emo.dec, @@ -382,7 +383,7 @@ def skymapViewerEMObservationToDict(emo, request=None): "self" : uri, "created" : emo.created.isoformat(), "submitter" : emo.submitter.username, - "comment" : '', + "comment" : emo.comment, "footprintID" : avg_time_string, "group" : emo.group.name, diff --git a/static/css/style.css b/static/css/style.css index 1ae24e134..04a418022 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -441,6 +441,10 @@ td.title { cursor: pointer; } +div.expandFormButton { + cursor: pointer; +} + div.expandGlyph { background-image: url('/bower-static/dijit/themes/tundra/images/spriteArrows.png'); background-repeat: no-repeat; diff --git a/templates/gracedb/emo_form_frag.html b/templates/gracedb/emo_form_frag.html index 2908114cc..0c71c65f8 100644 --- a/templates/gracedb/emo_form_frag.html +++ b/templates/gracedb/emo_form_frag.html @@ -48,6 +48,9 @@ StartTime</a></td> <tr><td><a href=# onclick="alert('Duration is the number of seconds in the time interval during which the observation was taken.');return false;"> Duration (seconds)</a></td> <td><input type="text" name="durationList" value=""/></td></tr> +<tr><td><a href=# onclick="alert('A natural language report.');return false;"> +Report as text</a></td> <td colspan=2><textarea name="comment" rows="8" cols="50"></textarea></td></tr> + </table> <input type="submit" value="Submit EMBB Observation Report"/> </form> diff --git a/templates/gracedb/event_detail.html b/templates/gracedb/event_detail.html index 8adb07f5c..5727645c1 100644 --- a/templates/gracedb/event_detail.html +++ b/templates/gracedb/event_detail.html @@ -145,7 +145,7 @@ {% include "gracedb/neighbors_frag.html" %} -{% include "gracedb/eel_form_frag.html" %} +{# include "gracedb/eel_form_frag.html" #} {% include "gracedb/emo_form_frag.html" %} </div> <!-- end event_detail_content div --> diff --git a/templates/gracedb/event_detail_script.js b/templates/gracedb/event_detail_script.js index 60ff77417..00e9d27f2 100644 --- a/templates/gracedb/event_detail_script.js +++ b/templates/gracedb/event_detail_script.js @@ -354,122 +354,29 @@ require([ // Section for EMBB //---------------------------------------------------------------------------------------- var eventDetailContainer = dom.byId('event_detail_content'); - var embbDiv = put(eventDetailContainer, 'div.content-area#embb_container'); - var embbTitleDiv = put(embbDiv, 'div#embb_title_expander'); - var embbContentDiv = put(embbDiv, 'div#embb_content'); + //var embbDiv = put(eventDetailContainer, 'div.content-area#embb_container'); + //var embbTitleDiv = put(embbDiv, 'div#embb_title_expander'); + //var embbContentDiv = put(embbDiv, 'div#embb_content'); // Put the EEL form into the content div // FIXME This needs to be cleaned up. Empty div for now. //var oldEelFormDiv = dom.byId('eelFormContainer'); //var eelFormContents = oldEelFormDiv.innerHTML; - var oldEmoFormDiv = dom.byId('emoFormContainer'); - var emoFormContents = oldEmoFormDiv.innerHTML; - domConstruct.destroy('eelFormContainer'); - domConstruct.destroy('emoFormContainer'); + //var oldEmoFormDiv = dom.byId('emoFormContainer'); + //var emoFormContents = oldEmoFormDiv.innerHTML; + // domConstruct.destroy('eelFormContainer'); + //domConstruct.destroy('emoFormContainer'); // var embbAddDiv = put(embbContentDiv, 'div#add_eel_container'); /* var embbAddFormDiv = put(embbAddDiv, 'div#add_eel_form_container'); embbAddFormDiv.innerHTML = eelFormContents; */ - var emoAddDiv = put(embbContentDiv, 'div#add_emo_container'); - var emoAddFormDiv = put(emoAddDiv, 'div#add_emo_form_container'); - emoAddFormDiv.innerHTML = emoFormContents; + //var emoAddDiv = put(embbContentDiv, 'div#add_emo_container'); + //var emoAddFormDiv = put(emoAddDiv, 'div#add_emo_form_container'); + //emoAddFormDiv.innerHTML = emoFormContents; - createExpandingSection(embbTitleDiv, embbContentDiv, emoAddFormDiv, 'Electromagnetic Bulletin Board'); + //createExpandingSection(embbTitleDiv, embbContentDiv, emoAddFormDiv, 'Electromagnetic Bulletin Board'); // Append the div that will hold our dgrid - put(embbContentDiv, 'div#emo-grid'); - - emoStore = new declare([Rest, RequestMemory])({target: emObservationListUrl}); - emoStore.get('').then(function(content) { - // Pull the EELs out of the rest content and create a new simple store from them. - var emos = content.observations; - - if (emos.length == 0) { - emoDiv = dom.byId('emo-grid'); - emoDiv.innerHTML = '<p> (No EM observation entries.) </p>'; - } else { - - var columns = [ - { field: 'created', label: 'Time Created (UTC)' }, - { field: 'submitter', label: 'Submitter' }, - { field: 'group', label: 'MOU Group' }, - { field: 'footprint_count', label: 'N_regions' }, - { field: 'radec', - label: 'Covering (ra, dec)', - get: function(object){ - var raLoc = Math.round10(object.ra, -2); - var raHalfWidthLoc = Math.round10(object.raWidth/2.0, -2); - var decLoc = Math.round10(object.dec, -2); - var decHalfWidthLoc = Math.round10(object.decWidth/2.0, -2); - var rastring = raLoc + " \xB1 " + raHalfWidthLoc; - var decstring = decLoc + " \xB1 " + decHalfWidthLoc; - return "(" + rastring + ',' + decstring + ")"; - }, - } - ]; - - var subRowColumns = [ - { field: 'start_time', label: 'Start Time (UTC)' }, - { field: 'exposure_time', label: 'Exposure Time (s)' }, - { field: 'ra', label: 'ra'}, - { field: 'raWidth', label: 'ra width'}, - { field: 'dec', label: 'dec'}, - { field: 'decWidth', label: 'dec width'} - ]; - - // Add extra class names to our grid cells so we can style them separately - for (i = 0; i < columns.length; i++) { - columns[i].className = 'supergrid-cell'; - } - for (i = 0; i < subRowColumns.length; i++) { - subRowColumns[i].className = 'subgrid-cell'; - } - - var grid = new Grid({ - columns: columns, - className: 'dgrid-autoheight', - - renderRow: function (object, options) { - // Add the supergrid-row class to the row so we can style it separately from the subrows. - var div = put('div.collapsed.supergrid-row', Grid.prototype.renderRow.call(this, object, options)); - - // Add the subdiv table which will expand and contract. - var t = put(div, 'div.expando table'); - // I'm finding that the table needs to be 100% of the available width, otherwise - // Firefox doesn't like it. Hence the extra empty column. - var subGridNode = put(t, 'tr td[style="width: 5%"]+td div'); - var sg = new Grid({ - columns: subRowColumns, - className: 'dgird-subgrid', - }, subGridNode); - sg.renderArray(object.footprints); - // Add the text comment - //put(t, 'tr td[style="width: 5%"]+td div.subrid-text', object.comment); - - return div; - } - }, 'emo-grid'); - grid.renderArray(emos); - grid.set("sort", 'N', descending=true); - - var expandedNode = null; - - // listen for clicks to trigger expand/collapse in table view mode - var expandoListener = on(grid.domNode, '.dgrid-row:click', function (event) { - var node = grid.row(event).element; - var collapsed = node.className.indexOf('collapsed') >= 0; - - // toggle state of node which was clicked - put(node, (collapsed ? '!' : '.') + 'collapsed'); - - // if clicked row wasn't expanded, collapse any previously-expanded row - collapsed && expandedNode && put(expandedNode, '.collapsed'); - - // if the row clicked was previously expanded, nothing is expanded now - expandedNode = collapsed ? node : null; - }); - } // endif on whether we have any emos or not. - }); - + //put(embbContentDiv, 'div#emo-grid'); //---------------------------------------------------------------------------------------- // Section for log entries @@ -773,6 +680,47 @@ require([ } + // Create the EMObservations title pane + // XXX Branson fixme + var pane_contents_id = 'emobservations_pane_div'; + + // Create the title pane with a placeholder div + var emo_tp = new TitlePane({ + title: 'EM Observations', + content: '<div id="' + pane_contents_id + '"></div>', + open: true + }); + logContentDiv.appendChild(emo_tp.domNode); + + var emoDiv = dom.byId(pane_contents_id); + // Create the section for adding EMObservation records. First an outer container: + var emoAddDiv = put(emoDiv, 'div#add_emo_container'); + // The order is important. First the toggling form display button, then the form. + // FIXME: Such a sad way of putting in vertical space. + put(emoDiv, 'br') + var addEmoButtonNode = put(emoAddDiv, 'div.expandFormButton', '(add observation record)'); + var emoAddFormDiv = put(emoAddDiv, 'div#add_emo_form_container'); + domStyle.set(emoAddFormDiv, 'display', 'none'); + + on(addEmoButtonNode, "click", function() { + if (domStyle.get(emoAddFormDiv, 'display') == 'none') { + domStyle.set(emoAddFormDiv, 'display', 'block'); + addEmoButtonNode.innerHTML = '(cancel)'; + } else { + domStyle.set(emoAddFormDiv, 'display', 'none'); + addEmoButtonNode.innerHTML = '(add observation record)'; + } + }); + + // Grab the form fragment and put it in the right place. + var oldEmoFormDiv = dom.byId('emoFormContainer'); + var emoFormContents = oldEmoFormDiv.innerHTML; + domConstruct.destroy('emoFormContainer'); + emoAddFormDiv.innerHTML = emoFormContents; + + // Create the div for our grid to attach to + put(emoDiv, 'div#emo-grid'); + // Create the full event-log title pane var columns = [ { field: 'N', label: 'No.' }, @@ -857,7 +805,8 @@ require([ var tp = new TitlePane({ title: 'Full Event Log', content: '<div id="' + pane_contents_id + '"></div>', - open: false + //open: false + open: true }); logContentDiv.appendChild(tp.domNode); @@ -872,11 +821,18 @@ require([ grid.renderArray(logs); grid.set("sort", 'N', descending=true); + // Now that we've constructed it, let's close the title pane. + tp.toggle() + } else { // Not doing title panes, just put up the usual log message section. // Will have the full eventlog section. Same as above, except that it // won't be in a title pane. What is the best way to do this. + // If we're not doing title panes, we still need to remember to destroy + // the emoFormContainer. Otherwise it shows up! + domConstruct.destroy('emoFormContainer'); + var columns = [ { field: 'N', label: 'No.' }, { field: 'created', label: 'Log Entry Created (UTC)' }, @@ -948,6 +904,107 @@ require([ } + //------------------------------------------------------------------- + // Finally, let's see if we can get those EMOs in + //------------------------------------------------------------------- + emoStore = new declare([Rest, RequestMemory])({target: emObservationListUrl}); + emoStore.get('').then(function(content) { + // Pull the EELs out of the rest content and create a new simple store from them. + var emos = content.observations; + + if (emos.length == 0) { + emoDiv = dom.byId('emo-grid'); + emoDiv.innerHTML = '<p> No EM observation entries so far. </p>'; + + // Let's try toggling the emo title pane closed. + if (emo_tp.open) { emo_tp.toggle(); } + } else { + + var columns = [ + { field: 'created', label: 'Time Created (UTC)' }, + { field: 'submitter', label: 'Submitter' }, + { field: 'group', label: 'MOU Group' }, + { field: 'footprint_count', label: 'N_regions' }, + { field: 'radec', + label: 'Covering (ra, dec)', + get: function(object){ + var raLoc = Math.round10(object.ra, -2); + var raHalfWidthLoc = Math.round10(object.raWidth/2.0, -2); + var decLoc = Math.round10(object.dec, -2); + var decHalfWidthLoc = Math.round10(object.decWidth/2.0, -2); + var rastring = raLoc + " \xB1 " + raHalfWidthLoc; + var decstring = decLoc + " \xB1 " + decHalfWidthLoc; + return "(" + rastring + ',' + decstring + ")"; + }, + } + ]; + + var subRowColumns = [ + { field: 'start_time', label: 'Start Time (UTC)' }, + { field: 'exposure_time', label: 'Exposure Time (s)' }, + { field: 'ra', label: 'ra'}, + { field: 'raWidth', label: 'ra width'}, + { field: 'dec', label: 'dec'}, + { field: 'decWidth', label: 'dec width'} + ]; + + // Add extra class names to our grid cells so we can style them separately + for (i = 0; i < columns.length; i++) { + columns[i].className = 'supergrid-cell'; + } + for (i = 0; i < subRowColumns.length; i++) { + subRowColumns[i].className = 'subgrid-cell'; + } + + var grid = new Grid({ + columns: columns, + className: 'dgrid-autoheight', + + renderRow: function (object, options) { + // Add the supergrid-row class to the row so we can style it separately from the subrows. + var div = put('div.collapsed.supergrid-row', Grid.prototype.renderRow.call(this, object, options)); + + // Add the subdiv table which will expand and contract. + var t = put(div, 'div.expando table'); + // I'm finding that the table needs to be 100% of the available width, otherwise + // Firefox doesn't like it. Hence the extra empty column. + var subGridNode = put(t, 'tr td[style="width: 5%"]+td div'); + var sg = new Grid({ + columns: subRowColumns, + className: 'dgird-subgrid', + }, subGridNode); + sg.renderArray(object.footprints); + // Add the text comment div as long as the comment is not an empty string. + if (object.comment !== "") { + put(t, 'tr td[style="width: 5%"]+td div.subrid-text', object.comment); + } + + return div; + } + }, 'emo-grid'); + grid.renderArray(emos); + grid.set("sort", 'N', descending=true); + + var expandedNode = null; + + // listen for clicks to trigger expand/collapse in table view mode + var expandoListener = on(grid.domNode, '.dgrid-row:click', function (event) { + var node = grid.row(event).element; + var collapsed = node.className.indexOf('collapsed') >= 0; + + // toggle state of node which was clicked + put(node, (collapsed ? '!' : '.') + 'collapsed'); + + // if clicked row wasn't expanded, collapse any previously-expanded row + collapsed && expandedNode && put(expandedNode, '.collapsed'); + + // if the row clicked was previously expanded, nothing is expanded now + expandedNode = collapsed ? node : null; + }); + } // endif on whether we have any emos or not. + }); + + //------------------------------------------------------------------- // Now that the annotations section has been added to the dom, we // can work on its functionality. -- GitLab