Skip to content

Commit e077a90

Browse files
committed
Take #2 on rules modeling
1 parent 62ea924 commit e077a90

File tree

8 files changed

+132
-73
lines changed

8 files changed

+132
-73
lines changed

src/sentry/migrations/0101_auto__add_rule.py renamed to src/sentry/migrations/0105_auto__add_rule.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def forwards(self, orm):
1212
db.create_table('sentry_rule', (
1313
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
1414
('project', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['sentry.Project'])),
15-
('rule_id', self.gf('django.db.models.fields.CharField')(max_length=64, db_index=True)),
15+
('label', self.gf('django.db.models.fields.CharField')(max_length=64)),
1616
('data', self.gf('django.db.models.fields.TextField')()),
1717
('date_added', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
1818
))
@@ -177,6 +177,14 @@ def backwards(self, orm):
177177
'key': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
178178
'value': ('django.db.models.fields.TextField', [], {})
179179
},
180+
u'sentry.groupseen': {
181+
'Meta': {'unique_together': "(('user', 'group'),)", 'object_name': 'GroupSeen'},
182+
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['sentry.Group']"}),
183+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
184+
'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
185+
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['sentry.Project']"}),
186+
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'db_index': 'False'})
187+
},
180188
u'sentry.grouptag': {
181189
'Meta': {'unique_together': "(('project', 'key', 'value', 'group'),)", 'object_name': 'GroupTag', 'db_table': "'sentry_messagefiltervalue'"},
182190
'first_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'null': 'True', 'db_index': 'True'}),
@@ -260,8 +268,8 @@ def backwards(self, orm):
260268
'data': ('django.db.models.fields.TextField', [], {}),
261269
'date_added': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
262270
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
263-
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['sentry.Project']"}),
264-
'rule_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'db_index': 'True'})
271+
'label': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
272+
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['sentry.Project']"})
265273
},
266274
u'sentry.searchdocument': {
267275
'Meta': {'unique_together': "(('project', 'group'),)", 'object_name': 'SearchDocument'},

src/sentry/models.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -419,14 +419,14 @@ class Meta:
419419

420420
class Rule(Model):
421421
project = models.ForeignKey(Project)
422-
rule_id = models.CharField(max_length=64, db_index=True)
422+
label = models.CharField(max_length=64)
423423
data = GzippedDictField()
424424
date_added = models.DateTimeField(default=timezone.now)
425425

426426
class Meta:
427427
db_table = 'sentry_rule'
428428

429-
__repr__ = sane_repr('project_id', 'rule_id')
429+
__repr__ = sane_repr('project_id', 'label')
430430

431431

432432
class PendingTeamMember(Model):

src/sentry/static/sentry/scripts/app.js

+54-6
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@
625625
initialize: function(data){
626626
BasePage.prototype.initialize.apply(this, arguments);
627627

628-
_.bindAll(this, 'addAction', 'addCondition');
628+
_.bindAll(this, 'addAction', 'addCondition', 'submitForm');
629629

630630
this.actions_by_id = {};
631631
this.conditions_by_id = {};
@@ -636,13 +636,14 @@
636636
this.condition_sel = this.el.find('select[name="condition"]');
637637
this.condition_table = this.el.find('table.condition-list');
638638
this.condition_table_body = this.condition_table.find('tbody');
639+
this.form = this.el.find('form');
639640

640641
this.action_sel.empty();
641642
this.action_sel.append($('<option></option>'));
642643
$.each(data.actions, _.bind(function(_, action) {
643644
var opt = $('<option></option>');
644645
opt.attr({
645-
value: action.id,
646+
value: action.id
646647
});
647648
opt.text(action.label);
648649
opt.appendTo(this.action_sel);
@@ -655,7 +656,7 @@
655656
$.each(data.conditions, _.bind(function(_, condition) {
656657
var opt = $('<option></option>');
657658
opt.attr({
658-
value: condition.id,
659+
value: condition.id
659660
});
660661
opt.text(condition.label);
661662
opt.appendTo(this.condition_sel);
@@ -665,14 +666,24 @@
665666

666667
this.action_sel.change(this.addAction);
667668
this.condition_sel.change(this.addCondition);
669+
670+
this.form.submit(this.submitForm);
668671
},
669672

670673
addCondition: function() {
671-
var condition = this.conditions_by_id[this.condition_sel.val()];
674+
var node = this.conditions_by_id[this.condition_sel.val()];
672675
var row = $('<tr></tr>');
673676
var remove_btn = $('<button class="btn btn-small">Remove</button>');
677+
var num = this.condition_table_body.find('tr').length;
678+
var html = $('<div>' + node.html + '</div>');
679+
var id_field = $('<input type="hidden" name="id[' + num + ']" value="' + node.id + '">');
674680

675-
row.append($('<td>' + condition.html + '</td>'));
681+
// we need to update the id of all form elements
682+
html.find('input, select, textarea').each(function(_, el){
683+
var $el = $(el);
684+
$el.attr('name', $el.attr('name') + '[' + num + ']');
685+
});
686+
row.append($('<td></td>').append(html).append(id_field));
676687
row.append($('<td></td>').append(remove_btn));
677688
row.appendTo(this.condition_table_body);
678689

@@ -689,8 +700,16 @@
689700
var action = this.actions_by_id[this.action_sel.val()];
690701
var row = $('<tr></tr>');
691702
var remove_btn = $('<button class="btn btn-small">Remove</button>');
703+
var num = this.action_table_body.find('tr').length;
704+
var html = $('<div>' + action.html + '</div>');
705+
var id_field = $('<input type="hidden" name="id[' + num + ']" value="' + action.id + '">');
692706

693-
row.append($('<td>' + action.html + '</td>'));
707+
// we need to update the id of all form elements
708+
html.find('input, select, textarea').each(function(_, el){
709+
var $el = $(el);
710+
$el.attr('name', $el.attr('name') + '[' + num + ']');
711+
});
712+
row.append($('<td></td>').append(html).append(id_field));
694713
row.append($('<td></td>').append(remove_btn));
695714
row.appendTo(this.action_table_body);
696715

@@ -701,6 +720,35 @@
701720

702721
this.action_sel.data("select2").clear();
703722
this.action_table.show();
723+
},
724+
725+
submitForm: function(e) {
726+
e.preventDefault();
727+
728+
var form_data = {
729+
actions: [],
730+
conditions: [],
731+
label: this.form.find('input[name=label]').val()
732+
};
733+
734+
// grab each table row in actions/conditions and create
735+
// a suitable form element out of it
736+
this.action_table_body.find('tr').each(function(_, el){
737+
form_data.actions.push({
738+
id: $(el).data('action-id'),
739+
data: $('input, textarea, select', el).serializeArray() || {}
740+
});
741+
});
742+
743+
this.condition_table_body.find('tr').each(function(_, el){
744+
form_data.conditions.push({
745+
id: $(el).data('condition-id'),
746+
data: $('input, textarea, select', el).serializeArray() || {}
747+
});
748+
});
749+
750+
751+
console.log(JSON.stringify(form_data));
704752
}
705753

706754
});

src/sentry/static/sentry/scripts/global.min.js

+2-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/sentry/static/sentry/scripts/utils.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@
279279
options = {
280280
width: 'element',
281281
allowClear: false,
282-
minimumResultsForSearch: 10,
282+
minimumResultsForSearch: 10
283283
};
284284

285285
if ($this.attr('data-allowClear')) {

src/sentry/templates/sentry/projects/rules/list.html

+14-6
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,18 @@
77
<a href="{% url 'sentry-new-project-rule' project.team.slug project.slug %}" class="btn pull-right btn-primary">{% trans "New Rule" %}</a>
88
<h2>{% trans "Rules" %}</h2>
99
</div>
10-
<p>Below you'll find each available action along with the triggers specified for it. Each action can have any number of triggers.</p>
11-
<h4>Send a notification</h4>
12-
<ul>
13-
<li>When an event is first seen</li>
14-
<li>When an event changes from resolved to unresolved</li>
15-
</ul>
10+
<table class="table table-striped">
11+
<thead>
12+
<tr>
13+
<th>Rule</th>
14+
</tr>
15+
</thead>
16+
<tbody>
17+
{% for rule in rule_list %}
18+
<tr>
19+
<td>{{ rule.label }}</td>
20+
</tr>
21+
{% endfor %}
22+
</tbody>
23+
</table>
1624
{% endblock %}

src/sentry/templates/sentry/projects/rules/new.html

+46-43
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,62 @@
11
{% extends "sentry/projects/manage.html" %}
22

3+
{% load crispy_forms_tags %}
34
{% load i18n %}
45
{% load sentry_helpers %}
56

67
{% block inner %}
78
<div class="page-header">
89
<h2>{% trans "New Rule" %}</h2>
910
</div>
10-
<form method="POST" action="" id="new-rule-form">
11-
{% csrf_token %}
11+
<div id="new-rule-form">
12+
<form method="POST" action="">
13+
{% csrf_token %}
1214

13-
<p>A rule consists of a single action and one or more triggers.</p>
14-
<fieldset>
15-
<div><legend>Details</legend></div>
16-
{% include "sentry/partial/form_base.html" %}
17-
</fieldset>
15+
{{ form|as_crispy_errors }}
1816

19-
<fieldset>
20-
<div><legend>Conditions</legend></div>
21-
<p>When <select name="match" style="width:100px" class="select2-small">
22-
<option value="all">all of</option>
23-
<option value="any">any of</option>
24-
<option value="none">none of</option>
25-
</select> these conditions are met:</p>
26-
<table class="condition-list table table-striped">
27-
<colgroup>
28-
<col>
29-
<col style="width:50px">
30-
</colgroup>
31-
<tbody></tbody>
32-
</table>
33-
<div class="controls">
34-
<select name="condition" class="span6" placeholder="add a condition"></select>
35-
</div>
36-
</fieldset>
17+
<fieldset>
18+
{{ form.label|as_crispy_field }}
19+
</fieldset>
3720

38-
<fieldset>
39-
<div><legend>Actions</legend></div>
40-
<p>Take these actions every time this rules matches:</p>
41-
<table class="action-list table table-striped">
42-
<colgroup>
43-
<col>
44-
<col style="width:50px">
45-
</colgroup>
46-
<tbody></tbody>
47-
</table>
48-
<div class="controls">
49-
<select name="action" class="span6" placeholder="add an action"></select>
50-
</div>
51-
</fieldset>
21+
<fieldset>
22+
<div><legend>Conditions</legend></div>
23+
<p>When <select name="match" style="width:100px" class="select2-small">
24+
<option value="all">all of</option>
25+
<option value="any">any of</option>
26+
<option value="none">none of</option>
27+
</select> these conditions are met:</p>
28+
<table class="condition-list table table-striped">
29+
<colgroup>
30+
<col>
31+
<col style="width:50px">
32+
</colgroup>
33+
<tbody></tbody>
34+
</table>
35+
<div class="controls">
36+
<select name="condition" class="span6" placeholder="add a condition"></select>
37+
</div>
38+
</fieldset>
39+
40+
<fieldset>
41+
<div><legend>Actions</legend></div>
42+
<p>Take these actions every time this rules matches:</p>
43+
<table class="action-list table table-striped">
44+
<colgroup>
45+
<col>
46+
<col style="width:50px">
47+
</colgroup>
48+
<tbody></tbody>
49+
</table>
50+
<div class="controls">
51+
<select name="action" class="span6" placeholder="add an action"></select>
52+
</div>
53+
</fieldset>
5254

53-
<div class="actions">
54-
<button type="submit" class="btn btn-primary">{% trans "Save Rule" %}</button>
55-
</div>
56-
</form>
55+
<div class="actions">
56+
<button type="submit" class="btn btn-primary">{% trans "Save Rule" %}</button>
57+
</div>
58+
</form>
59+
</div>
5760

5861
<script>
5962
new app.NewProjectRulePage({

src/sentry/web/frontend/projects.py

+2-11
Original file line numberDiff line numberDiff line change
@@ -428,17 +428,7 @@ def disable_project_plugin(request, team, project, slug):
428428

429429
@has_access(MEMBER_OWNER)
430430
def list_rules(request, team, project):
431-
from sentry.rules import RULES
432-
433-
rule_instance_list = sorted(
434-
Rule.objects.filter(project=project),
435-
key=lambda x: x.date_added
436-
)
437-
rule_list = []
438-
for rule_inst in rule_instance_list:
439-
rule_cls = RULES[rule_inst.rule_id]
440-
rule = rule_cls(rule_inst)
441-
rule_list.append((rule_inst, rule.render_label()))
431+
rule_list = Rule.objects.filter(project=project)
442432

443433
context = csrf(request)
444434
context.update({
@@ -456,6 +446,7 @@ def new_rule(request, team, project):
456446
from sentry.rules import RULES
457447

458448
form = NewRuleForm(request.POST or None)
449+
print request.POST
459450

460451
if request.POST and form.is_valid():
461452
# rule_cls = RULES[selected_rule]

0 commit comments

Comments
 (0)