frontline 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ });