frontline 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/CHANGELOG.md +0 -0
  2. data/LICENSE +19 -0
  3. data/README.md +92 -0
  4. data/Rakefile +21 -0
  5. data/assets/ansi_up.js +143 -0
  6. data/assets/api.js +533 -0
  7. data/assets/bootstrap/css/bootstrap-responsive.min.css +9 -0
  8. data/assets/bootstrap/css/bootstrap.min.css +9 -0
  9. data/assets/bootstrap/img/glyphicons-halflings-white.png +0 -0
  10. data/assets/bootstrap/img/glyphicons-halflings.png +0 -0
  11. data/assets/bootstrap/js/bootstrap.min.js +6 -0
  12. data/assets/jquery.cookie.js +95 -0
  13. data/assets/jquery.js +6 -0
  14. data/assets/noty/jquery.noty.js +520 -0
  15. data/assets/noty/layouts/top.js +34 -0
  16. data/assets/noty/layouts/topRight.js +43 -0
  17. data/assets/noty/promise.js +432 -0
  18. data/assets/noty/themes/default.js +156 -0
  19. data/assets/select2-bootstrap.css +86 -0
  20. data/assets/select2/select2-spinner.gif +0 -0
  21. data/assets/select2/select2.css +615 -0
  22. data/assets/select2/select2.min.js +22 -0
  23. data/assets/select2/select2.png +0 -0
  24. data/assets/select2/select2x2.png +0 -0
  25. data/assets/typeahead.js-bootstrap.css +49 -0
  26. data/assets/typeahead.min.js +7 -0
  27. data/assets/ui.css +28 -0
  28. data/assets/xhr.js +19 -0
  29. data/bin/frontline +19 -0
  30. data/frontline.gemspec +31 -0
  31. data/images/0.png +0 -0
  32. data/lib/frontline.rb +23 -0
  33. data/lib/frontline/actions.rb +15 -0
  34. data/lib/frontline/app.rb +86 -0
  35. data/lib/frontline/controllers/controllers.rb +71 -0
  36. data/lib/frontline/controllers/index.rb +167 -0
  37. data/lib/frontline/controllers/models.rb +104 -0
  38. data/lib/frontline/controllers/sources.rb +11 -0
  39. data/lib/frontline/frontline.rb +11 -0
  40. data/lib/frontline/helpers.rb +179 -0
  41. data/lib/frontline/inflect.rb +183 -0
  42. data/lib/frontline/templates/controllers/controller.slim +27 -0
  43. data/lib/frontline/templates/controllers/index.slim +56 -0
  44. data/lib/frontline/templates/controllers/route.slim +17 -0
  45. data/lib/frontline/templates/controllers/route_editor.slim +45 -0
  46. data/lib/frontline/templates/controllers/route_layout.slim +88 -0
  47. data/lib/frontline/templates/editor.slim +17 -0
  48. data/lib/frontline/templates/error.slim +36 -0
  49. data/lib/frontline/templates/index/applications.slim +123 -0
  50. data/lib/frontline/templates/layout.slim +182 -0
  51. data/lib/frontline/templates/models/index.slim +31 -0
  52. data/lib/frontline/templates/models/migration.slim +46 -0
  53. data/lib/frontline/templates/models/migration_layout.slim +159 -0
  54. data/lib/frontline/templates/models/model.slim +34 -0
  55. metadata +245 -0
File without changes
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+
2
+ Copyright (c) 2013 Silviu Rusu <slivuz@gmail.com>
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"),
6
+ to deal in the Software without restriction, including without limitation
7
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
+ and/or sell copies of the Software, and to permit persons to whom the Software
9
+ is furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,92 @@
1
+ ## Frontline
2
+
3
+ ### A Web Application for building Web Applications ([DEMO](http://frontline.rbho.me/applications))
4
+
5
+ **Using Demo:**
6
+
7
+ To load demo application insert "/home/vagrant/projects/CMS" into path field and something into name field.
8
+ <br>
9
+ Click "Load Application".
10
+
11
+ To generate a new application insert "/home/vagrant/projects/APP_NAME_HERE" into path field and something into name field.
12
+ <br>
13
+ Click "Generate Application".
14
+
15
+ Database credentials:
16
+
17
+ - type: mysql
18
+ - name: frontline
19
+ - user: root
20
+ - pass: mrp
21
+
22
+ ### Wait, what is this all about?
23
+
24
+ Basically it is a web interface for [Enginery Builder](https://github.com/espresso/enginery).
25
+
26
+ It allow to "visually" build applications, CRUDify controllers, routes, models etc. as well as run migrations, specs, execute bundler and git commands, manage assets etc.
27
+
28
+
29
+ ## Install
30
+
31
+ ```bash
32
+ $ gem install frontline
33
+ ```
34
+
35
+ \+ `$ rbenv rehash` if you are using `rbenv`.
36
+
37
+ ## Use
38
+
39
+ Simply run `frontline` from terminal:
40
+
41
+ ```bash
42
+ $ frontline
43
+ ```
44
+
45
+ This will start `Frontline` application on port `5000`.
46
+
47
+ Now open your browser at [localhost:5000](http://localhost:5000) and start manage your applications.
48
+
49
+ To start `Frontline` on another port use `-p` option:
50
+
51
+ ```bash
52
+ $ frontline -p PortNumber
53
+ ```
54
+
55
+ To generate a new application set application name and full path to the folder that will hold application sources.
56
+
57
+ If folder at given path exists it should be empty.
58
+
59
+ If it does not it will be created.
60
+
61
+ <img src="https://raw.github.com/espresso/frontline/master/images/0.png">
62
+
63
+ If you already have some application it can be loaded into `Frontline` same way - provide application name, full path to application root and click "Load" button.
64
+
65
+ To start manage some application simply click on its name.
66
+
67
+ To remove some application from list click the icon beside application name.
68
+
69
+ After you entered some application, the top menu will contain a dropdown with application names from where you can easily switch managed application.
70
+
71
+
72
+ ## Contributing
73
+
74
+ - Fork Frontline repository
75
+ - Make your changes
76
+ - Submit a pull request
77
+
78
+ <hr>
79
+ <p>
80
+ Issues/Bugs:
81
+ <a href="https://github.com/espresso/frontline/issues">
82
+ github.com/espresso/frontline/issues</a>
83
+ </p>
84
+ <p>
85
+ Mailing List: <a href="https://groups.google.com/forum/?fromgroups#!forum/espresso-framework">
86
+ groups.google.com/.../espresso-framework</a>
87
+ </p>
88
+ <p>
89
+ IRC channel: #espressorb on irc.freenode.net
90
+ </p>
91
+
92
+ ### Author - [Silviu Rusu](https://github.com/slivu). License - [MIT](https://github.com/espresso/frontline/blob/master/LICENSE).
@@ -0,0 +1,21 @@
1
+ require 'rake'
2
+ require 'bundler/gem_helper'
3
+ require './lib/frontline/frontline'
4
+
5
+ namespace :assets do
6
+ desc 'Update css files to correctly load background images'
7
+ task :css do
8
+ puts "Looking for css files containing background(-image)?:url ..."
9
+ src = /background(\-image)?[\s+]?\:(.*?)url\((\W+)?([^\.]*)\.(\w+)(\W+)?\)/
10
+ dst = 'background\1:\2url(\3\4.\5%s\6)' % Frontline::ASSETS_SUFFIX
11
+ Dir['./assets/**/*.css'].each do |file|
12
+ css = File.read(file)
13
+ if css =~ src
14
+ puts "Updating #{file}"
15
+ File.open(file, 'w') {|f| f << css.gsub(src, dst)}
16
+ end
17
+ end
18
+ puts "Done"
19
+ end
20
+ end
21
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,143 @@
1
+ // ansi_up.js
2
+ // version : 1.0.0
3
+ // author : Dru Nelson
4
+ // license : MIT
5
+ // http://github.com/drudru/ansi_up
6
+
7
+ (function (Date, undefined) {
8
+
9
+ var ansi_up,
10
+ VERSION = "1.0.0",
11
+
12
+ // check for nodeJS
13
+ hasModule = (typeof module !== 'undefined'),
14
+
15
+ // Normal and then Bright
16
+ ANSI_COLORS = [
17
+ ["0,0,0", "187, 0, 0", "0, 187, 0", "187, 187, 0", "0, 0, 187", "187, 0, 187", "0, 187, 187", "255,255,255" ],
18
+ ["85,85,85", "255, 85, 85", "0, 255, 0", "255, 255, 85", "85, 85, 255", "255, 85, 255", "85, 255, 255", "255,255,255" ]
19
+ ];
20
+
21
+ function Ansi_Up() {
22
+ this.fg = this.bg = null;
23
+ this.bright = 0;
24
+ }
25
+
26
+ Ansi_Up.prototype.escape_for_html = function (txt) {
27
+ return txt.replace(/[&<>]/gm, function(str) {
28
+ if (str == "&") return "&amp;";
29
+ if (str == "<") return "&lt;";
30
+ if (str == ">") return "&gt;";
31
+ });
32
+ };
33
+
34
+ Ansi_Up.prototype.linkify = function (txt) {
35
+ return txt.replace(/(https?:\/\/[^\s]+)/gm, function(str) {
36
+ return "<a href=\"" + str + "\">" + str + "</a>";
37
+ });
38
+ };
39
+
40
+ Ansi_Up.prototype.ansi_to_html = function (txt) {
41
+
42
+ var data4 = txt.split(/\033\[/);
43
+
44
+ var first = data4.shift(); // the first chunk is not the result of the split
45
+
46
+ var self = this;
47
+ var data5 = data4.map(function (chunk) {
48
+ return self.process_chunk(chunk);
49
+ });
50
+
51
+ data5.unshift(first);
52
+
53
+ var flattened_data = data5.reduce( function (a, b) {
54
+ if (Array.isArray(b))
55
+ return a.concat(b);
56
+
57
+ a.push(b);
58
+ return a;
59
+ }, []);
60
+
61
+ var escaped_data = flattened_data.join('');
62
+
63
+ return escaped_data;
64
+ };
65
+
66
+ Ansi_Up.prototype.process_chunk = function (text) {
67
+
68
+ // Do proper handling of sequences (aka - injest vi split(';') into state machine
69
+ //match,codes,txt = text.match(/([\d;]+)m(.*)/m);
70
+ var matches = text.match(/([\d;]+?)m([^]*)/m);
71
+
72
+ if (!matches) return text;
73
+
74
+ var orig_txt = matches[2];
75
+ var nums = matches[1].split(';');
76
+
77
+ var self = this;
78
+ nums.map(function (num_str) {
79
+
80
+ var num = parseInt(num_str);
81
+
82
+ if (num === 0) {
83
+ self.fg = self.bg = null;
84
+ self.bright = 0;
85
+ } else if (num === 1) {
86
+ self.bright = 1;
87
+ } else if ((num >= 30) && (num < 38)) {
88
+ self.fg = "rgb(" + ANSI_COLORS[self.bright][(num % 10)] + ")";
89
+ } else if ((num >= 40) && (num < 48)) {
90
+ self.bg = "rgb(" + ANSI_COLORS[0][(num % 10)] + ")";
91
+ }
92
+ });
93
+
94
+ if ((self.fg === null) && (self.bg === null)) {
95
+ return orig_txt;
96
+ } else {
97
+ var style = [];
98
+ if (self.fg)
99
+ style.push("color:" + self.fg);
100
+ if (self.bg)
101
+ style.push("background-color:" + self.bg);
102
+ return ["<span style=\"" + style.join(';') + "\">", orig_txt, "</span>"];
103
+ }
104
+ };
105
+
106
+ // Module exports
107
+ ansi_up = {
108
+
109
+ escape_for_html: function (txt) {
110
+ var a2h = new Ansi_Up();
111
+ return a2h.escape_for_html(txt);
112
+ },
113
+
114
+ linkify: function (txt) {
115
+ var a2h = new Ansi_Up();
116
+ return a2h.linkify(txt);
117
+ },
118
+
119
+ ansi_to_html: function (txt) {
120
+ var a2h = new Ansi_Up();
121
+ return a2h.ansi_to_html(txt);
122
+ },
123
+
124
+ ansi_to_html_obj: function () {
125
+ return new Ansi_Up();
126
+ }
127
+ };
128
+
129
+ // CommonJS module is defined
130
+ if (hasModule) {
131
+ module.exports = ansi_up;
132
+ }
133
+ /*global ender:false */
134
+ if (typeof window !== 'undefined' && typeof ender === 'undefined') {
135
+ window.ansi_up = ansi_up;
136
+ }
137
+ /*global define:false */
138
+ if (typeof define === "function" && define.amd) {
139
+ define("ansi_up", [], function () {
140
+ return ansi_up;
141
+ });
142
+ }
143
+ })(Date);
@@ -0,0 +1,533 @@
1
+ FrontlineAPI = function() {
2
+ var errorInstance;
3
+ this.activeContainer;
4
+ this.wins = {};
5
+
6
+ this.ApplicationCRUD = function(baseURL) {
7
+
8
+ var cookieOptions = {path: '/', expires: 3650};
9
+
10
+ this.generate = function() {
11
+ var name = validateName();
12
+ if(!name) return;
13
+
14
+ if(applicationExists(name))
15
+ return Frontline.alert('A application with same name already exists');
16
+
17
+ var path = validatePath();
18
+ if (!path) return;
19
+
20
+ var url = baseURL + '/generate';
21
+ var data = {
22
+ settings: $('#applicationSettingsForm').serialize(),
23
+ uuid: Frontline.UUID(),
24
+ name: name,
25
+ path: path,
26
+ preview_url: $('#previewURL').val()
27
+ }
28
+ $.ajax({
29
+ type: 'POST', url: url, data: data, complete: function(xhr, txtResponse) {
30
+ txtResponse == 'success' || Frontline.error(xhr.responseText);
31
+ }
32
+ });
33
+ }
34
+
35
+ this.load = function() {
36
+ var name = validateName();
37
+ if(!name) return;
38
+
39
+ var path = validatePath();
40
+ if (!path) return;
41
+
42
+ var previewURL = $('#previewURL').val();
43
+
44
+ var api = this;
45
+ $.ajax({
46
+ type: 'POST',
47
+ url: baseURL + '/load',
48
+ data: {path: path},
49
+ complete: function(xhr, txtResponse) {
50
+ if(txtResponse == 'success') {
51
+ if (api.addToList(JSON.stringify([name, path, previewURL])))
52
+ location.reload();
53
+ } else Frontline.error(xhr.responseText);
54
+ }
55
+ });
56
+ }
57
+
58
+ this.addToList = function(string) {
59
+ var application = JSON.parse(string);
60
+ if(applicationExists(application[0])) {
61
+ Frontline.alert('A application with same name already exists');
62
+ return false;
63
+ }
64
+ var applications = getApplications();
65
+ if(applications && applications.push(application))
66
+ setApplications(applications);
67
+ return true;
68
+ }
69
+
70
+ this.removeFromList = function(name) {
71
+ if(!confirm("This will remove the application from list. Continue?"))
72
+ return false;
73
+
74
+ var applications = getApplications();
75
+ for (var i = 0; i < applications.length; i++) {
76
+ var application = applications[i];
77
+ if(application && application[0] == name) applications.splice(i, 1);
78
+ }
79
+ setApplications(applications);
80
+ location.reload();
81
+ }
82
+
83
+ var applicationExists = function(name) {
84
+ var applications = getApplications();
85
+ for (var i = 0; i < applications.length; i++) {
86
+ var p = applications[i];
87
+ if(p && p[0] == name) return p;
88
+ }
89
+ return false;
90
+ }
91
+
92
+ var getApplications = function(){
93
+ return JSON.parse($.cookie('Applications') || '[]');
94
+ }
95
+
96
+ var setApplications = function(applications){
97
+ $.cookie('Applications', JSON.stringify(applications), cookieOptions);
98
+ }
99
+
100
+ var validateName = function() {
101
+ var name;
102
+ var smth = ($('#applicationName').val() || '').replace(/^\s+|\s+$/g, '');
103
+ if(smth.length > 0)
104
+ name = smth;
105
+ else
106
+ Frontline.alert('Please provide application name');
107
+ return name;
108
+ }
109
+
110
+ var validatePath = function() {
111
+ var path;
112
+ var smth = ($('#applicationPath').val() || '').replace(/^\s+|\s+$/g, '');
113
+ if(smth.length > 0){
114
+ if(smth[0] == '/')
115
+ path = smth;
116
+ else
117
+ Frontline.alert('Only Absolute paths accepted');
118
+ } else
119
+ Frontline.alert('Please provide full path to application');
120
+ return path;
121
+ }
122
+
123
+ }
124
+
125
+ this.FileCRUD = function(baseURL) {
126
+
127
+ this.toggleEditor = function(path) {
128
+ $.ajax({
129
+ type: 'GET',
130
+ url: baseURL,
131
+ data: {path: path},
132
+ complete: function(xhr, txtResponse) {
133
+ if(txtResponse == 'success') {
134
+ $('#editorContainer').html(xhr.responseText);
135
+ } else {
136
+ Frontline.error(xhr.responseText);
137
+ }
138
+ }
139
+ });
140
+ }
141
+
142
+ this.saveFile = function(path, domID) {
143
+ $.ajax({
144
+ type: 'PUT',
145
+ url: baseURL,
146
+ data: {path: path, content: $(domID || '#editor').val()},
147
+ complete: function(xhr, txtResponse) {
148
+ if(txtResponse == 'success') {
149
+ Frontline.alert('File Successfully Saved');
150
+ } else {
151
+ Frontline.error(xhr.responseText);
152
+ }
153
+ }
154
+ });
155
+ }
156
+ }
157
+
158
+ this.CRUD = function(baseURL, activeContainer) {
159
+
160
+ this.create = function(formSelector) {
161
+ if (isEmpty('name', $(formSelector + ' :input[name=name]').val())) return false;
162
+ invoke('POST', $(formSelector).serialize());
163
+ }
164
+
165
+ this.delete = function(name, confirmation) {
166
+ if (isEmpty('name', name)) return false;
167
+
168
+ confirmation = confirmation || 'This action can not be undone! Continue?';
169
+ if (confirm(confirmation))
170
+ invoke('DELETE', {name: name});
171
+ }
172
+
173
+ var invoke = function(requestMethod, data) {
174
+ Frontline.activeContainer = activeContainer;
175
+ $.ajax({
176
+ type: requestMethod,
177
+ url: baseURL + '?uuid=' + Frontline.UUID(),
178
+ data: data,
179
+ complete: function(xhr, txtResponse) {
180
+ txtResponse == 'success' || Frontline.error(xhr.responseText);
181
+ }
182
+ });
183
+ }
184
+ }
185
+
186
+ this.Migrations = function(baseURL, activeContainer) {
187
+
188
+ this.newColumn = function(formSelector) {
189
+ var model = $(formSelector + ' :input[name=model]').val();
190
+ if (isEmpty('Model Name', model)) return false;
191
+
192
+ var name = $(formSelector + ' :input[name=name]').val();
193
+ if (isEmpty('Column Name', name)) return false;
194
+
195
+ var type = $(formSelector + ' :input[name=type]').val();
196
+
197
+ var label = $(formSelector + ' :input[name=label]').val();
198
+
199
+ var data = {
200
+ name: label || ['adding', model, name, 'column'].join('-'),
201
+ column: (type ? name + ':' + type : name)
202
+ }
203
+ invoke('POST', data);
204
+ }
205
+
206
+ this.updateColumn = function(formSelector) {
207
+ var model = $(formSelector + ' :input[name=model]').val();
208
+ if (isEmpty('Model Name', model)) return false;
209
+
210
+ var name = $(formSelector + ' :input[name=name]').val();
211
+ if (isEmpty('Column Name', name)) return false;
212
+
213
+ var type = $(formSelector + ' :input[name=type]').val();
214
+ if (isEmpty('New Column Type', type)) return false;
215
+
216
+ var label = $(formSelector + ' :input[name=label]').val();
217
+
218
+ var data = {
219
+ name: label || ['updating', model, name, 'to', type].join('-'),
220
+ update_column: [name, type].join(':')
221
+ }
222
+ invoke('POST', data);
223
+ }
224
+
225
+ this.renameColumn = function(formSelector) {
226
+ var model = $(formSelector + ' :input[name=model]').val();
227
+ if (isEmpty('Model Name', model)) return false;
228
+
229
+ var name = $(formSelector + ' :input[name=name]').val();
230
+ if (isEmpty('Column Name', name)) return false;
231
+
232
+ var new_name = $(formSelector + ' :input[name=new_name]').val();
233
+ if (isEmpty('New Name', new_name)) return false;
234
+
235
+ var label = $(formSelector + ' :input[name=label]').val();
236
+
237
+ var data = {
238
+ name: label || ['renaming', model, name, 'to', new_name].join('-'),
239
+ rename_column: name + ':' + new_name
240
+ }
241
+ invoke('POST', data);
242
+ }
243
+
244
+ this.run = function(vector, formSelector) {
245
+
246
+ var data = {migrations: [], vector: vector};
247
+
248
+ if (formSelector) {
249
+ $(formSelector + ' :input[name=migrations]:checked').map(function() {
250
+ data.migrations.push($(this).val());
251
+ });
252
+ if(data.migrations.length == 0) {
253
+ Frontline.alert('No migrations selected');
254
+ return false;
255
+ }
256
+ if($(formSelector + ' :input[name=forceRun]').prop('checked'))
257
+ data['force_run'] = true;
258
+ } else {
259
+ if(!confirm('This will run ' + vector.toUpperCase() + ' all outstanding migrations! Continue?'))
260
+ return false;
261
+
262
+ data['force_yes'] = true;
263
+ }
264
+
265
+ invoke('POST', data);
266
+ }
267
+
268
+ this.delete = function(name, confirmation) {
269
+ if (isEmpty('name', name)) return false;
270
+
271
+ confirmation = confirmation || 'This action can not be undone! Continue?';
272
+ if (confirm(confirmation))
273
+ invoke('DELETE', {name: name});
274
+ }
275
+
276
+ var invoke = function(requestMethod, data) {
277
+ if(activeContainer)
278
+ Frontline.activeContainer = activeContainer;
279
+ $.ajax({
280
+ type: requestMethod,
281
+ url: baseURL + '?uuid=' + Frontline.UUID(),
282
+ data: data,
283
+ complete: function(xhr, txtResponse) {
284
+ txtResponse == 'success' || Frontline.error(xhr.responseText);
285
+ }
286
+ });
287
+ }
288
+ }
289
+
290
+ this.runSpecs = function(baseURL, controller) {
291
+ var data = {uuid: Frontline.UUID()};
292
+ controller && (data['controller'] = controller);
293
+ $.ajax({
294
+ type: 'POST',
295
+ url: baseURL,
296
+ data: data,
297
+ complete: function(xhr, txtResponse) {
298
+ txtResponse == 'success' || Frontline.error(xhr.responseText);
299
+ }
300
+ });
301
+ }
302
+
303
+ this.runCmd = function(url, confirmation) {
304
+ if (confirmation && !confirm(confirmation)) return false;
305
+
306
+ $.ajax({
307
+ type: 'POST',
308
+ url: url + '?uuid=' + Frontline.UUID(),
309
+ complete: function(xhr, txtResponse) {
310
+ txtResponse == 'success' || Frontline.error(xhr.responseText);
311
+ }
312
+ });
313
+ }
314
+
315
+ this.Git = function(baseURL) {
316
+
317
+ this.init = function() {
318
+ if(!confirm("This will initialize or reinitialize the Git repository. Continue?")) return;
319
+ invoke(baseURL + '/init');
320
+ }
321
+
322
+ this.origin = function(url) {
323
+ var url = (url || '').replace(/^\s+|\s+$/g, '');
324
+ if(url.length == 0) return Frontline.alert('Please provide remote URL');
325
+ invoke(baseURL + '/origin', {url: url});
326
+ }
327
+
328
+ this.commit = function(message) {
329
+ message = (message || '').replace(/^\s+|\s+$/g, '');
330
+ if(message.length == 0) return Frontline.alert('Can not deploy without a deploy message');
331
+ invoke(baseURL + '/commit', {message: message});
332
+ }
333
+
334
+ this.push = function() {
335
+ if(!confirm("This will push last commits to remote server. Continue?")) return;
336
+ invoke(baseURL + '/push');
337
+ }
338
+
339
+ var invoke = function(url, data) {
340
+ $.ajax({
341
+ type: 'POST',
342
+ url: url + '?uuid=' + Frontline.UUID(),
343
+ data: data,
344
+ complete: function(xhr, txtResponse) {
345
+ txtResponse == 'success' || Frontline.error(xhr.responseText);
346
+ }
347
+ });
348
+ }
349
+ }
350
+
351
+ this.PTYEventListener = function(streamURL) {
352
+ var evs = new EventSource([streamURL, Frontline.UUID()].join('/'));
353
+ evs.addEventListener('modal', function(e) {
354
+ if (e.data == 'show') {
355
+ $('#PTYModalHeader').html('Please wait...');
356
+ $('#PTYModalBody').html(null);
357
+ $('#PTYModal').modal();
358
+ } else if (e.data == 'hide') {
359
+ $('#PTYModalHeader').html('Completed');
360
+ $('#PTYModal').modal('hide');
361
+ }
362
+ $('#lastOperationToggler').show();
363
+ }, false);
364
+
365
+ evs.addEventListener('content', function(e) {
366
+ $('#PTYModalBody').append(ansi_up.ansi_to_html(e.data)).animate({
367
+ scrollTop: $('#PTYModalBody').prop('scrollHeight')
368
+ }, 0);
369
+ }, false);
370
+
371
+ evs.addEventListener('persist_application', function(e) {
372
+ new Frontline.ApplicationCRUD().addToList(e.data);
373
+ }, false);
374
+
375
+ evs.addEventListener('render', function(e) {
376
+ $(Frontline.activeContainer).html(e.data);
377
+ $('input[name=name]').val(null);
378
+ }, false);
379
+
380
+ evs.addEventListener('failures', function(e) {
381
+ $('#PTYModalHeader').html('Errored');
382
+ $('.' + e.data).addClass('text-error');
383
+ }, false);
384
+
385
+ evs.addEventListener('reload', function() {
386
+ location.reload();
387
+ }, false);
388
+ }
389
+
390
+ this.UUID = function() {
391
+ if (typeof window.eventSourceUUID == 'undefined')
392
+ eventSourceUUID = generateUUID();
393
+ return eventSourceUUID;
394
+ }
395
+
396
+ this.alert = function(msg, timeout) {
397
+ noty({
398
+ text: msg,
399
+ type: 'information',
400
+ layout: 'topRight',
401
+ timeout: timeout || 2000
402
+ });
403
+ }
404
+
405
+ this.sticky_alert = function(msg) {
406
+ noty({
407
+ text: msg,
408
+ type: 'information',
409
+ layout: 'topRight'
410
+ });
411
+ }
412
+
413
+ this.warn = function(msg, timeout) {
414
+ noty({
415
+ text: msg,
416
+ type: 'warning',
417
+ layout: 'topRight',
418
+ timeout: timeout || 3000
419
+ });
420
+ }
421
+
422
+ this.sticky_warn = function(msg) {
423
+ noty({
424
+ text: msg,
425
+ type: 'warning',
426
+ layout: 'topRight'
427
+ });
428
+ }
429
+
430
+ this.error = function(msg) {
431
+ msg = msg.replace(/</gm, '&lt;').replace(/>/gm, '&gt;').
432
+ replace(/\n|\r/gm, '<br>').replace(/\t/gm, '&nbsp;&nbsp;');
433
+ errorInstance = noty({
434
+ text: '<div style="text-align: left; max-height: 280px; overflow: auto;">' + msg + '</div>',
435
+ type: 'warning',
436
+ layout: 'top',
437
+ modal: true,
438
+ closeWith: ['button'],
439
+ buttons: [
440
+ {addClass: 'btn btn-primary', text: 'Close', onClick: function($noty) {
441
+ $noty.close();
442
+ }
443
+ }
444
+ ]
445
+ });
446
+ }
447
+
448
+ this.dismissLastError = function() {
449
+ errorInstance && errorInstance.close();
450
+ }
451
+
452
+ this.triggerSelectable = function(domSelector) {
453
+ $(domSelector || 'select.frontline-selectable').each(function(i,e) {
454
+ e = $(e);
455
+ (e.attr('style') || '').match(/width/ig) || e.css('width', '10em');
456
+ if(e.select2 == 'undefined') return false;
457
+ e.select2({width: 'copy'});
458
+ });
459
+ }
460
+
461
+ var generateUUID = function(){
462
+ var d = new Date().getTime();
463
+ var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
464
+ var r = (d + Math.random()*16)%16 | 0;
465
+ d = Math.floor(d/16);
466
+ return (c=='x' ? r : (r&0x7|0x8)).toString(16);
467
+ });
468
+ return uuid;
469
+ }
470
+
471
+ this.openWindow = function(domID_or_opts) {
472
+ if (typeof domID_or_opts == "object")
473
+ var url = domID_or_opts.url;
474
+ else {
475
+ var elm = $('#' + domID_or_opts);
476
+ var url = [elm.attr('data-url'), elm.val()||''].join('/');
477
+ }
478
+ var win = Frontline.wins[url];
479
+ if (!win || win.closed) {
480
+ win = window.open(url, '_blank');
481
+ Frontline.wins[url] = win;
482
+ }
483
+ win.location = url;
484
+ win.focus();
485
+ }
486
+
487
+ this.routeEditor = function(url, domID) {
488
+ $.ajax({
489
+ type: 'GET',
490
+ url: url,
491
+ complete: function(xhr, txtResponse) {
492
+ if (txtResponse == 'success') {
493
+ $(domID).html(xhr.responseText);
494
+ }
495
+ else Frontline.error(xhr.responseText);
496
+ }
497
+ });
498
+ }
499
+
500
+ this.ajaxifyTabs = function(selector) {
501
+ $(selector).bind('show', function(e) {
502
+ var a = $(e.target);
503
+ $.get(a.attr('data-url'), function(r) {
504
+ $('#' + a.attr('href').substr(1)).html(r);
505
+ });
506
+ });
507
+ }
508
+
509
+ var isEmpty = function(variable, val) {
510
+ if (val && jQuery.trim(val).length > 0) return false;
511
+ Frontline.warn('Wrong ' + variable + ' provided');
512
+ return true;
513
+ }
514
+ }
515
+
516
+ $(function(){
517
+ $('.sticky-dropdown').click(function (e) { e.stopPropagation() });
518
+
519
+ $('#GitCommit').keypress(function (e) {
520
+ if (e.which == 13) {
521
+ gitDeployer.commit($(this).val());
522
+ e.preventDefault();
523
+ }
524
+ });
525
+
526
+ $('#GitOrigin').keypress(function (e) {
527
+ if (e.which == 13) {
528
+ gitDeployer.origin($(this).val());
529
+ e.preventDefault();
530
+ }
531
+ });
532
+
533
+ });