task-manager 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +4 -0
  3. data/Rakefile +27 -0
  4. data/app/assets/images/task-manager/icons/add.png +0 -0
  5. data/app/assets/images/task-manager/icons/delete.png +0 -0
  6. data/app/assets/images/task-manager/icons/edit.png +0 -0
  7. data/app/assets/javascripts/task-manager/application.js +43 -0
  8. data/app/assets/javascripts/task-manager/extjs/app/controller/Plans.js +359 -0
  9. data/app/assets/javascripts/task-manager/extjs/app/controller/Tasks.js +56 -0
  10. data/app/assets/javascripts/task-manager/extjs/app/helper/application_helper.js +24 -0
  11. data/app/assets/javascripts/task-manager/extjs/app/model/Assignee.js +19 -0
  12. data/app/assets/javascripts/task-manager/extjs/app/model/Plan.js +195 -0
  13. data/app/assets/javascripts/task-manager/extjs/app/model/Task.js +23 -0
  14. data/app/assets/javascripts/task-manager/extjs/app/store/Assignees.js +53 -0
  15. data/app/assets/javascripts/task-manager/extjs/app/store/AssigneesTree.js +3 -0
  16. data/app/assets/javascripts/task-manager/extjs/app/store/Booleans.js +9 -0
  17. data/app/assets/javascripts/task-manager/extjs/app/store/Days.js +38 -0
  18. data/app/assets/javascripts/task-manager/extjs/app/store/Hours.js +31 -0
  19. data/app/assets/javascripts/task-manager/extjs/app/store/Minutes.js +67 -0
  20. data/app/assets/javascripts/task-manager/extjs/app/store/Months.js +19 -0
  21. data/app/assets/javascripts/task-manager/extjs/app/store/Plans.js +6 -0
  22. data/app/assets/javascripts/task-manager/extjs/app/store/QuarterlyMonths.js +10 -0
  23. data/app/assets/javascripts/task-manager/extjs/app/store/Statuses.js +11 -0
  24. data/app/assets/javascripts/task-manager/extjs/app/store/Tasks.js +6 -0
  25. data/app/assets/javascripts/task-manager/extjs/app/store/Types.js +12 -0
  26. data/app/assets/javascripts/task-manager/extjs/app/store/WeekDays.js +14 -0
  27. data/app/assets/javascripts/task-manager/extjs/app/view/plan/AssignablesWindow.js +23 -0
  28. data/app/assets/javascripts/task-manager/extjs/app/view/plan/Edit.js +189 -0
  29. data/app/assets/javascripts/task-manager/extjs/app/view/plan/EditWindow.js +21 -0
  30. data/app/assets/javascripts/task-manager/extjs/app/view/plan/Grid.js +92 -0
  31. data/app/assets/javascripts/task-manager/extjs/app/view/plan/Index.js +24 -0
  32. data/app/assets/javascripts/task-manager/extjs/app/view/plan/New.js +190 -0
  33. data/app/assets/javascripts/task-manager/extjs/app/view/plan/Search.js +132 -0
  34. data/app/assets/javascripts/task-manager/extjs/app/view/plan/SelectAssignables.js +22 -0
  35. data/app/assets/javascripts/task-manager/extjs/app/view/plan/SelectAssignablesGrid.js +22 -0
  36. data/app/assets/javascripts/task-manager/extjs/app/view/plan/SelectAssignablesTree.js +9 -0
  37. data/app/assets/javascripts/task-manager/extjs/app/view/plan/Window.js +21 -0
  38. data/app/assets/javascripts/task-manager/extjs/app/view/task/Grid.js +62 -0
  39. data/app/assets/javascripts/task-manager/extjs/app/view/task/Index.js +21 -0
  40. data/app/assets/javascripts/task-manager/extjs/app/view/task/Search.js +148 -0
  41. data/app/assets/javascripts/task-manager/extjs/lib/ux/MultiSelectablePagingGrid.js +20 -0
  42. data/app/assets/javascripts/task-manager/extjs/lib/ux/RowExpander.js +230 -0
  43. data/app/assets/stylesheets/task-manager/application.css.scss +13 -0
  44. data/app/assets/stylesheets/task-manager/extjs.css.scss +43 -0
  45. data/app/controllers/task_manager/api/v1/plans_controller.rb +251 -0
  46. data/app/controllers/task_manager/api/v1/tasks_controller.rb +82 -0
  47. data/app/controllers/task_manager/application_controller.rb +4 -0
  48. data/app/helpers/task_manager/application_helper.rb +4 -0
  49. data/app/models/task_manager/assignable.rb +10 -0
  50. data/app/models/task_manager/callable.rb +10 -0
  51. data/app/models/task_manager/plan.rb +114 -0
  52. data/app/models/task_manager/task.rb +81 -0
  53. data/app/serializers/task_manager/plan_serializer.rb +8 -0
  54. data/app/serializers/task_manager/task_serializer.rb +8 -0
  55. data/app/views/layouts/task-manager/application.html.erb +14 -0
  56. data/config/routes.rb +8 -0
  57. data/db/migrate/20121102054723_setup_hstore.rb +9 -0
  58. data/db/migrate/20121102055137_create_task_manager_plans.rb +16 -0
  59. data/db/migrate/20121102142657_create_task_manager_assignables.rb +13 -0
  60. data/db/migrate/20121102150720_create_task_manager_callables.rb +13 -0
  61. data/db/migrate/20121105170602_create_task_manager_tasks.rb +18 -0
  62. data/lib/task-manager.rb +37 -0
  63. data/lib/task-manager/api_constraints.rb +12 -0
  64. data/lib/task-manager/deadline_calculator.rb +22 -0
  65. data/lib/task-manager/deadline_validator.rb +27 -0
  66. data/lib/task-manager/engine.rb +5 -0
  67. data/lib/task-manager/version.rb +3 -0
  68. data/lib/tasks/task-manager_tasks.rake +4 -0
  69. metadata +327 -0
@@ -0,0 +1,56 @@
1
+ Ext.define('TM.controller.Tasks', {
2
+ extend: 'Ext.app.Controller',
3
+
4
+ views: ['task.Index'],
5
+
6
+ refs: [{
7
+ ref: 'searchForm',
8
+ selector: 'task_search'
9
+ }],
10
+
11
+ init: function() {
12
+ this.control({
13
+ 'task_search button[action="query"]': {
14
+ click: this.onQueryClick
15
+ },
16
+ 'task_search button[action="reset"]': {
17
+ click: this.onSearchResetClick
18
+ },
19
+ 'task_grid button[action="delete"]': {
20
+ click: this.onDeleteClick
21
+ }
22
+ });
23
+ },
24
+
25
+ onQueryClick: function(btn) {
26
+ var params = this.getSearchForm().getValues();
27
+ Ext.getStore('TM.store.Tasks').load({ params: params });
28
+ },
29
+
30
+ onSearchResetClick: function(btn) {
31
+ this.getSearchForm().getForm().reset();
32
+ },
33
+
34
+ onDeleteClick: function(btn) {
35
+ var select = btn.up('task_grid').getSelectionModel().getSelection()[0];
36
+ if(select == null) {
37
+ Ext.Msg.alert('提示','请选择要删除的计划任务');
38
+ return;
39
+ }
40
+
41
+ Ext.Msg.confirm('提示','您确认要删除选中的计划任务吗?', function(b){
42
+ if(b != 'yes') return;
43
+
44
+ var selected = btn.up('task_grid').getSelectionModel().getSelection();
45
+ Ext.each(selected, function(s){
46
+ this.callParent(arguments);
47
+
48
+ if(this.store) this.store.remove(this);
49
+ });
50
+ });
51
+ },
52
+
53
+ index: function() {
54
+ this.render('TM.view.task.Index');
55
+ }
56
+ });
@@ -0,0 +1,24 @@
1
+ Ext.define('TM.helper.ApplicationHelper', {
2
+ translateType: function(t) {
3
+ var translations = {
4
+ yearly: '年计划',
5
+ quarterly: '季计划',
6
+ monthly: '月计划',
7
+ weekly: '周计划',
8
+ daily: '日计划'
9
+ };
10
+
11
+ return translations[t];
12
+ },
13
+
14
+ translateStatus: function(s) {
15
+ var translations = {
16
+ new: '新建',
17
+ in_process: '进行中',
18
+ expired: '已过期',
19
+ finished: '已完成'
20
+ };
21
+
22
+ return translations[s];
23
+ }
24
+ });
@@ -0,0 +1,19 @@
1
+ Ext.define('TM.model.Assignee', {
2
+ extend: 'Ext.data.Model',
3
+
4
+ fields: [
5
+ { name: 'id', type: 'int' },
6
+ { name: 'name' },
7
+ { name: 'class_name' },
8
+ { name: 'parent_id', type: 'int' }
9
+ ],
10
+
11
+ proxy: {
12
+ type: 'rest',
13
+ url: '/assignees.json',
14
+ reader: {
15
+ root: 'assignees',
16
+ totalProperty: 'total'
17
+ }
18
+ }
19
+ });
@@ -0,0 +1,195 @@
1
+ Ext.define('TM.model.Plan', {
2
+ extend: 'Ext.data.Model',
3
+
4
+ fields: [
5
+ { name: 'id', type: 'int' },
6
+
7
+ { name: 'name' },
8
+ { name: 'plan_type' },
9
+ { name: 'data', type: 'auto' },
10
+ { name: 'dataX', convert: function(v, record) {
11
+ return record.get('data').x;
12
+ }},
13
+ { name: 'dataY', convert: function(v, record) {
14
+ return record.get('data').y;
15
+ }},
16
+ { name: 'quarterly_month', convert: function(v, record) {
17
+ if (record.get('plan_type') == 'quarterly') return record.get('data').deadline_month;
18
+ return null;
19
+ }},
20
+ { name: 'month', convert: function(v, record) {
21
+ if (record.get('plan_type') == 'yearly') return record.get('data').deadline_month;
22
+ return null;
23
+ }},
24
+ { name: 'weekly_day', convert: function(v, record) {
25
+ if (record.get('plan_type') == 'weekly') return record.get('data').deadline_day;
26
+ return null;
27
+ }},
28
+ { name: 'day', convert: function(v, record) {
29
+ if (record.get('plan_type') != 'weekly') return record.get('data').deadline_day;
30
+ return null;
31
+ }},
32
+ { name: 'hour', convert: function(v, record) {
33
+ return record.get('data').deadline_hour;
34
+ }},
35
+ { name: 'minute', convert: function(v, record) {
36
+ return record.get('data').deadline_minute;
37
+ }},
38
+ { name: 'autocompletable', type: 'boolean' },
39
+
40
+ { name: 'begin_to_remind', type: 'int' },
41
+
42
+ { name: 'enabled_at', type: 'date' },
43
+ { name: 'last_task_created_at', type: 'date' },
44
+
45
+
46
+ { name: 'created_at', type: 'date' },
47
+ { name: 'updated_at', type: 'date' },
48
+
49
+ { name: 'assignees', type: 'auto' }
50
+ ],
51
+
52
+ proxy: {
53
+ type: 'rest',
54
+ url: '/task-manager/api/plans',
55
+ reader: {
56
+ root: 'plans',
57
+ totalProperty: 'total'
58
+ }
59
+ },
60
+
61
+ set: function() {
62
+ if (typeof arguments[0] === 'object') {
63
+ this.callParent(arguments);
64
+
65
+ obj = arguments[0];
66
+ if (obj.data) {
67
+ this.set('dataX', obj.data.x);
68
+ this.set('dataY', obj.data.y);
69
+ this.set('quarterly_month', obj.data.deadline_month);
70
+ this.set('month', obj.data.deadline_month);
71
+ this.set('weekly_day', obj.data.deadline_day);
72
+ this.set('day', obj.data.deadline_day);
73
+ this.set('hour', obj.data.deadline_hour);
74
+ this.set('minute', obj.data.deadline_minute);
75
+ }
76
+ } else {
77
+ this.callParent(arguments);
78
+ }
79
+ },
80
+
81
+ update: function(attrs, opts) {
82
+ var self = this;
83
+ var plan = Ext.create('TM.model.Plan', attrs);
84
+
85
+ opts = opts || {};
86
+ var success = opts.success;
87
+
88
+ var assignables_attributes = new Array();
89
+ Ext.Array.forEach(attrs.assignees, function(node, index, assignees) {
90
+ var record = Ext.getStore('TM.store.Assignees').getById(node.get('id'));
91
+ assignables_attributes.push({
92
+ assignee_id: record.get('id'),
93
+ assignee_type: record.get('class_name')
94
+ });
95
+ });
96
+
97
+ var callables_attributes = new Array();
98
+
99
+ Ext.apply(opts, {
100
+ url: '/task-manager/api/plans/'+this.get('id'),
101
+ method: 'PUT',
102
+ jsonData: {
103
+ plan: {
104
+ data: {
105
+ x: attrs.dataX,
106
+ y: attrs.dataY,
107
+ deadline_month: attrs.plan_type == 'quarterly' ? attrs.quarterly_month : (attrs.plan_type == 'yearly' ? attrs.month : null),
108
+ deadline_day: attrs.plan_type == 'weekly' ? attrs.weekly_day : (attrs.plan_type == 'daily' ? null : attrs.day),
109
+ deadline_hour: attrs.hour,
110
+ deadline_minute: attrs.minute
111
+ },
112
+ name: attrs.name,
113
+ plan_type: attrs.plan_type,
114
+ enabled_at: attrs.enabled_at,
115
+ begin_to_remind: attrs.begin_to_remind,
116
+ autocompletable: attrs.autocompletable,
117
+ assignables_attributes: assignables_attributes,
118
+ callables_attributes: callables_attributes
119
+ }
120
+ },
121
+ success: function(response) {
122
+ var obj = Ext.JSON.decode(response.responseText);
123
+ self.set(obj.plan);
124
+ self.commit();
125
+
126
+ if(success) success.call(opts.scope || this);
127
+ }
128
+ });
129
+ Ext.Ajax.request(opts);
130
+
131
+ return plan;
132
+ },
133
+
134
+ statics: {
135
+ create: function(attrs, opts) {
136
+ var plan = Ext.create('TM.model.Plan', attrs);
137
+
138
+ opts = opts || {};
139
+ var success = opts.success;
140
+
141
+ var assignables_attributes = new Array();
142
+ Ext.Array.forEach(attrs.assignees, function(node, index, assignees) {
143
+ var record = Ext.getStore('TM.store.Assignees').getById(node.get('id'));
144
+ assignables_attributes.push({
145
+ assignee_id: record.get('id'),
146
+ assignee_type: record.get('class_name')
147
+ })
148
+ });
149
+
150
+ var callables_attributes = new Array();
151
+
152
+ Ext.apply(opts, {
153
+ url: '/task-manager/api/plans',
154
+ method: 'POST',
155
+ jsonData: {
156
+ plan: {
157
+ data: {
158
+ x: attrs.dataX,
159
+ y: attrs.dataY,
160
+ deadline_month: attrs.plan_type == 'quarterly' ? attrs.quarterly_month : (attrs.plan_type == 'yearly' ? attrs.month : null),
161
+ deadline_day: attrs.plan_type == 'weekly' ? attrs.weekly_day : (attrs.plan_type == 'daily' ? null : attrs.day),
162
+ deadline_hour: attrs.hour,
163
+ deadline_minute: attrs.minute
164
+ },
165
+ name: attrs.name,
166
+ plan_type: attrs.plan_type,
167
+ enabled_at: attrs.enabled_at,
168
+ begin_to_remind: attrs.begin_to_remind,
169
+ autocompletable: attrs.autocompletable,
170
+ assignables_attributes: assignables_attributes,
171
+ callables_attributes: callables_attributes
172
+ }
173
+ },
174
+ success: function(response) {
175
+ var obj = Ext.JSON.decode(response.responseText);
176
+ plan.set(obj.plan);
177
+ //plan.set('dataX', obj.plan.data.x);
178
+ plan.commit();
179
+
180
+ if(success) success.call(opts.scope || this);
181
+ }
182
+ });
183
+ Ext.Ajax.request(opts);
184
+
185
+ return plan;
186
+ }
187
+ },
188
+
189
+ destroy: function() {
190
+ this.callParent(arguments);
191
+
192
+ if(this.store) this.store.remove(this);
193
+ }
194
+ });
195
+
@@ -0,0 +1,23 @@
1
+ Ext.define('TM.model.Task', {
2
+ extend: 'Ext.data.Model',
3
+
4
+ fields: [
5
+ { name: 'id', type: 'int' },
6
+ { name: 'name'},
7
+ { name: 'task_type'},
8
+ { name: 'data', type: 'auto' },
9
+ { name: 'status' },
10
+ { name: 'deadline', type: 'date'},
11
+ { name: 'created_at', type: 'date' },
12
+ { name: 'updated_at', type: 'date' }
13
+ ],
14
+
15
+ proxy: {
16
+ type: 'rest',
17
+ url: '/task-manager/api/tasks',
18
+ reader: {
19
+ root: 'tasks',
20
+ totalProperty: 'total'
21
+ }
22
+ },
23
+ });
@@ -0,0 +1,53 @@
1
+ Ext.define('TM.store.Assignees', {
2
+ extend: 'Ext.data.Store',
3
+
4
+ autoLoad: true,
5
+ model: 'TM.model.Assignee',
6
+
7
+ toTreeStore: function() {
8
+
9
+ var self = this;
10
+ var store = {
11
+ root: {
12
+ expanded: true,
13
+ children: []
14
+ }
15
+ };
16
+
17
+ self.each(function(assignee) {
18
+ self.addChild(self.getPositionById(store.root,
19
+ assignee.get('parent_id')), assignee);
20
+ });
21
+
22
+ return store;
23
+ },
24
+
25
+ // @private
26
+ getPositionById: function(root, id) {
27
+ if (id == null || id == 0) return root;
28
+ if (root.id == id) return root;
29
+
30
+ var childrenLength = root.children ? root.children.length : 0;
31
+ for (var i = 0; i < childrenLength; i++) {
32
+ var result = this.getPositionById(root.children[i], id);
33
+ if (result != null) return result;
34
+ }
35
+
36
+ return null;
37
+ },
38
+
39
+ addChild: function(root, record) {
40
+ if (root.children == null) root.children = [];
41
+
42
+ root.children.push({
43
+ id: record.get('id'),
44
+ text: record.get('name'),
45
+ checked: false,
46
+ leaf: true
47
+ });
48
+
49
+ if (root.leaf != null) {
50
+ root.leaf == true ? root.leaf = false : null;
51
+ }
52
+ }
53
+ });
@@ -0,0 +1,3 @@
1
+ Ext.define('TM.store.AssigneesTree', {
2
+ extend: 'Ext.data.TreeStore'
3
+ });
@@ -0,0 +1,9 @@
1
+ Ext.define('TM.store.Booleans',{
2
+ extend: 'Ext.data.Store',
3
+
4
+ fields: ['text', 'value'],
5
+ data : [
6
+ { "text": "否", 'value': 'false' },
7
+ { "text": "是", 'value': 'true' }
8
+ ]
9
+ });
@@ -0,0 +1,38 @@
1
+ Ext.define('TM.store.Days', {
2
+ extend: 'Ext.data.Store',
3
+
4
+ fields: ['text', 'value'],
5
+ data : [
6
+ { "text": "1", 'value': '1' },
7
+ { "text": "2", 'value': '2' },
8
+ { "text": "3", 'value': '3' },
9
+ { "text": "4", 'value': '4' },
10
+ { "text": "5", 'value': '5' },
11
+ { "text": "6", 'value': '6' },
12
+ { "text": "7", 'value': '7' },
13
+ { "text": "8", 'value': '8' },
14
+ { "text": "9", 'value': '9' },
15
+ { "text": "10", 'value': '10' },
16
+ { "text": "11", 'value': '11' },
17
+ { "text": "12", 'value': '12' },
18
+ { "text": "13", 'value': '13' },
19
+ { "text": "14", 'value': '14' },
20
+ { "text": "15", 'value': '15' },
21
+ { "text": "16", 'value': '16' },
22
+ { "text": "17", 'value': '17' },
23
+ { "text": "18", 'value': '18' },
24
+ { "text": "19", 'value': '19' },
25
+ { "text": "20", 'value': '20' },
26
+ { "text": "21", 'value': '21' },
27
+ { "text": "22", 'value': '22' },
28
+ { "text": "23", 'value': '23' },
29
+ { "text": "24", 'value': '24' },
30
+ { "text": "25", 'value': '25' },
31
+ { "text": "26", 'value': '26' },
32
+ { "text": "27", 'value': '27' },
33
+ { "text": "28", 'value': '28' },
34
+ { "text": "29", 'value': '29' },
35
+ { "text": "30", 'value': '30' },
36
+ { "text": "31", 'value': '31' }
37
+ ]
38
+ });
@@ -0,0 +1,31 @@
1
+ Ext.define('TM.store.Hours',{
2
+ extend: 'Ext.data.Store',
3
+
4
+ fields: ['text', 'value'],
5
+ data : [
6
+ { "text": "0时", 'value': '0' },
7
+ { "text": "1时", 'value': '1' },
8
+ { "text": "2时", 'value': '2' },
9
+ { "text": "3时", 'value': '3' },
10
+ { "text": "4时", 'value': '4' },
11
+ { "text": "5时", 'value': '5' },
12
+ { "text": "6时", 'value': '6' },
13
+ { "text": "7时", 'value': '7' },
14
+ { "text": "8时", 'value': '8' },
15
+ { "text": "9时", 'value': '9' },
16
+ { "text": "10时", 'value': '10' },
17
+ { "text": "11时", 'value': '11' },
18
+ { "text": "12时", 'value': '12' },
19
+ { "text": "13时", 'value': '13' },
20
+ { "text": "14时", 'value': '14' },
21
+ { "text": "15时", 'value': '15' },
22
+ { "text": "16时", 'value': '16' },
23
+ { "text": "17时", 'value': '17' },
24
+ { "text": "18时", 'value': '18' },
25
+ { "text": "19时", 'value': '19' },
26
+ { "text": "20时", 'value': '20' },
27
+ { "text": "21时", 'value': '21' },
28
+ { "text": "22时", 'value': '22' },
29
+ { "text": "23时", 'value': '23' }
30
+ ]
31
+ });