blob: 296483985a2387160d32b6396ce070487b60e324 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001"use strict"
2
3function importLayerPageInit (ctx) {
4
5 var layerDepBtn = $("#add-layer-dependency-btn");
6 var importAndAddBtn = $("#import-and-add-btn");
7 var layerNameInput = $("#import-layer-name");
8 var vcsURLInput = $("#layer-git-repo-url");
9 var gitRefInput = $("#layer-git-ref");
10 var layerDepInput = $("#layer-dependency");
11 var layerNameCtrl = $("#layer-name-ctrl");
12 var duplicatedLayerName = $("#duplicated-layer-name-hint");
Patrick Williamsc0f7c042017-02-23 20:41:17 -060013 var localDirPath = $("#local-dir-path");
Patrick Williamsc124f4f2015-09-15 14:41:29 -050014
15 var layerDeps = {};
16 var layerDepsDeps = {};
17 var currentLayerDepSelection;
18 var validLayerName = /^(\w|-)+$/;
19
Patrick Williamsc0f7c042017-02-23 20:41:17 -060020 libtoaster.makeTypeahead(layerDepInput,
21 libtoaster.ctx.layersTypeAheadUrl,
22 { include_added: "true" }, function(item){
Patrick Williamsc124f4f2015-09-15 14:41:29 -050023 currentLayerDepSelection = item;
Patrick Williamsc0f7c042017-02-23 20:41:17 -060024 layerDepBtn.removeAttr("disabled");
Patrick Williamsc124f4f2015-09-15 14:41:29 -050025 });
26
Patrick Williamsc0f7c042017-02-23 20:41:17 -060027 layerDepInput.on("typeahead:select", function(event, data){
28 currentLayerDepSelection = data;
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050029 });
30
Patrick Williamsc0f7c042017-02-23 20:41:17 -060031 // Disable local dir repo when page is loaded.
32 $('#local-dir').hide();
33
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050034 // disable the "Add layer" button when the layer input typeahead is empty
35 // or not in the typeahead choices
Patrick Williamsc0f7c042017-02-23 20:41:17 -060036 layerDepInput.on("input change", function(){
37 layerDepBtn.attr("disabled","disabled");
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050038 });
Patrick Williamsc124f4f2015-09-15 14:41:29 -050039
40 /* We automatically add "openembedded-core" layer for convenience as a
41 * dependency as pretty much all layers depend on this one
42 */
43 $.getJSON(libtoaster.ctx.layersTypeAheadUrl,
44 { include_added: "true" , search: "openembedded-core" },
45 function(layer) {
46 if (layer.results.length > 0) {
47 currentLayerDepSelection = layer.results[0];
Brad Bishop6e60e8b2018-02-01 10:27:11 -050048 layerDepBtn.click();
Patrick Williamsc124f4f2015-09-15 14:41:29 -050049 }
50 });
51
52 layerDepBtn.click(function(){
53 if (currentLayerDepSelection == undefined)
54 return;
55
56 layerDeps[currentLayerDepSelection.id] = currentLayerDepSelection;
57
58 /* Make a list item for the new layer dependency */
Patrick Williamsc0f7c042017-02-23 20:41:17 -060059 var newLayerDep = $("<li><a></a><span class=\"glyphicon glyphicon-trash\" data-toggle=\"tooltip\" title=\"Remove\"></span></li>");
Patrick Williamsc124f4f2015-09-15 14:41:29 -050060
61 newLayerDep.data('layer-id', currentLayerDepSelection.id);
62 newLayerDep.children("span").tooltip();
63
64 var link = newLayerDep.children("a");
65 link.attr("href", currentLayerDepSelection.layerdetailurl);
66 link.text(currentLayerDepSelection.name);
67 link.tooltip({title: currentLayerDepSelection.tooltip, placement: "right"});
68
69 var trashItem = newLayerDep.children("span");
70 trashItem.click(function () {
71 var toRemove = $(this).parent().data('layer-id');
72 delete layerDeps[toRemove];
73 $(this).parent().fadeOut(function (){
74 $(this).remove();
75 });
76 });
77
78 $("#layer-deps-list").append(newLayerDep);
79
Patrick Williamsc0f7c042017-02-23 20:41:17 -060080 libtoaster.getLayerDepsForProject(currentLayerDepSelection.layerdetailurl,
81 function (data){
Patrick Williamsc124f4f2015-09-15 14:41:29 -050082 /* These are the dependencies of the layer added as a dependency */
83 if (data.list.length > 0) {
84 currentLayerDepSelection.url = currentLayerDepSelection.layerdetailurl;
85 layerDeps[currentLayerDepSelection.id].deps = data.list;
86 }
87
88 /* Clear the current selection */
89 layerDepInput.val("");
90 currentLayerDepSelection = undefined;
91 layerDepBtn.attr("disabled","disabled");
92 }, null);
93 });
94
Patrick Williamsc0f7c042017-02-23 20:41:17 -060095 importAndAddBtn.click(function(e){
96 e.preventDefault();
Patrick Williamsc124f4f2015-09-15 14:41:29 -050097 /* This is a list of the names from layerDeps for the layer deps
98 * modal dialog body
99 */
100 var depNames = [];
101
102 /* arrray of all layer dep ids includes parent and child deps */
103 var allDeps = [];
104
105 /* temporary object to use to do a reduce on the dependencies for each
106 * layer dependency added
107 */
108 var depDeps = {};
109
110 /* the layers that have dependencies have an extra property "deps"
111 * look in this for each layer and reduce this to a unquie object
112 * of deps.
113 */
114 for (var key in layerDeps){
115 if (layerDeps[key].hasOwnProperty('deps')){
116 for (var dep in layerDeps[key].deps){
117 var layer = layerDeps[key].deps[dep];
118 depDeps[layer.id] = layer;
119 }
120 }
121 depNames.push(layerDeps[key].name);
122 allDeps.push(layerDeps[key].id);
123 }
124
125 /* we actually want it as an array so convert it now */
126 var depDepsArray = [];
127 for (var key in depDeps)
128 depDepsArray.push (depDeps[key]);
129
130 if (depDepsArray.length > 0) {
131 var layer = { name: layerNameInput.val(), url: "#", id: -1 };
132 var title = "Layer";
133 var body = "<strong>"+layer.name+"</strong>'s dependencies ("+
134 depNames.join(", ")+"</span>) require some layers that are not added to your project. Select the ones you want to add:</p>";
135
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600136 showLayerDepsModal(layer,
137 depDepsArray,
138 title, body, false, function(layerObsList){
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500139 /* Add the accepted layer dependencies' ids to the allDeps array */
140 for (var key in layerObsList){
141 allDeps.push(layerObsList[key].id);
142 }
143 import_and_add ();
144 });
145 } else {
146 import_and_add ();
147 }
148
149 function import_and_add () {
150 /* convert to a csv of all the deps to be added */
151 var layerDepsCsv = allDeps.join(",");
152
153 var layerData = {
154 name: layerNameInput.val(),
155 vcs_url: vcsURLInput.val(),
156 git_ref: gitRefInput.val(),
157 dir_path: $("#layer-subdir").val(),
158 project_id: libtoaster.ctx.projectId,
159 layer_deps: layerDepsCsv,
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600160 local_source_dir: $('#local-dir-path').val(),
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500161 add_to_project: true,
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500162 };
163
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600164 if ($('input[name=repo]:checked').val() == "git") {
165 layerData.local_source_dir = "";
166 } else {
167 layerData.vcs_url = "";
168 layerData.git_ref = "";
169 }
170
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500171 $.ajax({
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500172 type: "PUT",
173 url: ctx.xhrLayerUrl,
174 data: JSON.stringify(layerData),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500175 headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
176 success: function (data) {
177 if (data.error != "ok") {
178 console.log(data.error);
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500179 /* let the user know why nothing happened */
180 alert(data.error)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500181 } else {
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600182 createImportedNotification(data);
183 window.location.replace(libtoaster.ctx.projectPageUrl);
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500184 }
185 },
186 error: function (data) {
187 console.log("Call failed");
188 console.log(data);
189 }
190 });
191 }
192 });
193
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600194 /* Layer imported notification */
195 function createImportedNotification(imported){
196 var message = "Layer imported";
197
198 if (imported.deps_added.length === 0) {
199 message = "You have imported <strong><a class=\"alert-link\" href=\""+imported.imported_layer.layerdetailurl+"\">"+imported.imported_layer.name+"</a></strong> and added it to your project.";
200 } else {
201
202 var links = "<a href=\""+imported.imported_layer.layerdetailurl+"\">"+imported.imported_layer.name+"</a>, ";
203
204 imported.deps_added.map (function(item, index){
205 links +='<a href="'+item.layerdetailurl+'">'+item.name+'</a>';
206 /*If we're at the last element we don't want the trailing comma */
207 if (imported.deps_added[index+1] !== undefined)
208 links += ', ';
209 });
210
211 /* Length + 1 here to do deps + the imported layer */
212 message = 'You have imported <strong><a href="'+imported.imported_layer.layerdetailurl+'">'+imported.imported_layer.name+'</a></strong> and added <strong>'+(imported.deps_added.length+1)+'</strong> layers to your project: <strong>'+links+'</strong>';
213 }
214
215 libtoaster.setNotification("layer-imported", message);
216 }
217
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500218 function enable_import_btn(enabled) {
219 var importAndAddHint = $("#import-and-add-hint");
220
221 if (enabled) {
222 importAndAddBtn.removeAttr("disabled");
223 importAndAddHint.hide();
224 return;
225 }
226
227 importAndAddBtn.attr("disabled", "disabled");
228 importAndAddHint.show();
229 }
230
231 function check_form() {
232 var valid = false;
233 var inputs = $("input:required");
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600234 var inputStr = inputs.val().split("");
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500235
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600236 for (var i=0; i<inputs.val().length; i++){
237 if (!(valid = inputStr[i])){
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500238 enable_import_btn(false);
239 break;
240 }
241 }
242
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600243 if (valid) {
244 if ($("#local-dir-radio").prop("checked") &&
245 localDirPath.val().length > 0) {
246 enable_import_btn(true);
247 }
248
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500249 if ($("#git-repo-radio").prop("checked")) {
250 if (gitRefInput.val().length > 0 &&
251 gitRefInput.val() == 'HEAD') {
252 $('#invalid-layer-revision-hint').show();
253 $('#layer-revision-ctrl').addClass('has-error');
254 enable_import_btn(false);
255 } else if (vcsURLInput.val().length > 0 &&
256 gitRefInput.val().length > 0) {
257 $('#invalid-layer-revision-hint').hide();
258 $('#layer-revision-ctrl').removeClass('has-error');
259 enable_import_btn(true);
260 }
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600261 }
262 }
263
264 if (inputs.val().length == 0)
265 enable_import_btn(false);
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500266 }
267
268 function layerExistsError(layer){
269 var dupLayerInfo = $("#duplicate-layer-info");
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500270
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600271 if (layer.local_source_dir) {
272 $("#git-layer-dup").hide();
273 $("#local-layer-dup").fadeIn();
274 dupLayerInfo.find(".dup-layer-name").text(layer.name);
275 dupLayerInfo.find(".dup-layer-link").attr("href", layer.layerdetailurl);
276 dupLayerInfo.find("#dup-local-source-dir-name").text(layer.local_source_dir);
277 } else {
278 $("#git-layer-dup").fadeIn();
279 $("#local-layer-dup").hide();
280 dupLayerInfo.find(".dup-layer-name").text(layer.name);
281 dupLayerInfo.find(".dup-layer-link").attr("href", layer.layerdetailurl);
282 dupLayerInfo.find("#dup-layer-vcs-url").text(layer.vcs_url);
283 dupLayerInfo.find("#dup-layer-revision").text(layer.vcs_reference);
284 }
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500285 $(".fields-apart-from-layer-name").fadeOut(function(){
286
287 dupLayerInfo.fadeIn();
288 });
289 }
290
291 layerNameInput.on('blur', function() {
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600292 if (!$(this).val()){
293 return;
294 }
295 var name = $(this).val();
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500296
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600297 /* Check if the layer name exists */
298 $.getJSON(libtoaster.ctx.layersTypeAheadUrl,
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500299 { include_added: "true" , search: name, format: "json" },
300 function(layer) {
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500301 if (layer.results.length > 0) {
302 for (var i in layer.results){
303 if (layer.results[i].name == name) {
304 layerExistsError(layer.results[i]);
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500305 }
306 }
307 }
308 });
309 });
310
311 vcsURLInput.on('input', function() {
312 check_form();
313 });
314
315 gitRefInput.on('input', function() {
316 check_form();
317 });
318
319 layerNameInput.on('input', function() {
320 if ($(this).val() && !validLayerName.test($(this).val())){
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600321 layerNameCtrl.addClass("has-error")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500322 $("#invalid-layer-name-hint").show();
323 enable_import_btn(false);
324 return;
325 }
326
327 if ($("#duplicate-layer-info").css("display") != "None"){
328 $("#duplicate-layer-info").fadeOut(function(){
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600329 $(".fields-apart-from-layer-name").show();
330 radioDisplay();
331 });
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500332
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600333 }
334
335 radioDisplay();
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500336
337 /* Don't remove the error class if we're displaying the error for another
338 * reason.
339 */
340 if (!duplicatedLayerName.is(":visible"))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600341 layerNameCtrl.removeClass("has-error")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500342
343 $("#invalid-layer-name-hint").hide();
344 check_form();
345 });
346
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500347 /* Setup 'blank' typeahead */
348 libtoaster.makeTypeahead(gitRefInput,
349 ctx.xhrGitRevTypeAheadUrl,
350 { git_url: null }, function(){});
351
352
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500353 vcsURLInput.focusout(function (){
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500354 if (!$(this).val())
355 return;
356
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500357 /* If we a layer name specified don't overwrite it or if there isn't a
358 * url typed in yet return
359 */
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500360 if (!layerNameInput.val() && $(this).val().search("/")){
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500361 var urlPts = $(this).val().split("/");
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500362 /* Add a suggestion of the layer name */
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500363 var suggestion = urlPts[urlPts.length-1].replace(".git","");
364 layerNameInput.val(suggestion);
365 }
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500366
367 /* Now actually setup the typeahead properly with the git url entered */
368 gitRefInput._typeahead('destroy');
369
370 libtoaster.makeTypeahead(gitRefInput,
371 ctx.xhrGitRevTypeAheadUrl,
372 { git_url: $(this).val() },
373 function(selected){
374 gitRefInput._typeahead("close");
375 });
376
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500377 });
378
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600379 function radioDisplay() {
380 if ($('input[name=repo]:checked').val() == "local") {
381 $('#git-repo').hide();
382 $('#import-git-layer-and-add-hint').hide();
383 $('#local-dir').fadeIn();
384 $('#import-local-dir-and-add-hint').fadeIn();
385 } else {
386 $('#local-dir').hide();
387 $('#import-local-dir-and-add-hint').hide();
388 $('#git-repo').fadeIn();
389 $('#import-git-layer-and-add-hint').fadeIn();
390 }
391 }
392
393 $('input:radio[name="repo"]').change(function() {
394 radioDisplay();
395 if ($("#local-dir-radio").prop("checked")) {
396 if (localDirPath.val().length > 0) {
397 enable_import_btn(true);
398 } else {
399 enable_import_btn(false);
400 }
401 }
402 if ($("#git-repo-radio").prop("checked")) {
403 if (vcsURLInput.val().length > 0 && gitRefInput.val().length > 0) {
404 enable_import_btn(true);
405 } else {
406 enable_import_btn(false);
407 }
408 }
409 });
410
411 localDirPath.on('input', function(){
412 if ($(this).val().trim().length == 0) {
413 $('#import-and-add-btn').attr("disabled","disabled");
414 $('#local-dir').addClass('has-error');
415 $('#hintError-dir-abs-path').show();
416 $('#hintError-dir-path-starts-with-slash').show();
417 } else {
418 var input = $(this);
419 var reBeginWithSlash = /^\//;
420 var reCheckVariable = /^\$/;
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500421 var re = /([ <>\\|":%\?\*]+)/;
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600422
423 var invalidDir = re.test(input.val());
424 var invalidSlash = reBeginWithSlash.test(input.val());
425 var invalidVar = reCheckVariable.test(input.val());
426
427 if (!invalidSlash && !invalidVar) {
428 $('#local-dir').addClass('has-error');
429 $('#import-and-add-btn').attr("disabled","disabled");
430 $('#hintError-dir-abs-path').show();
431 $('#hintError-dir-path-starts-with-slash').show();
432 } else if (invalidDir) {
433 $('#local-dir').addClass('has-error');
434 $('#import-and-add-btn').attr("disabled","disabled");
435 $('#hintError-dir-path').show();
436 } else {
437 $('#local-dir').removeClass('has-error');
438 if (layerNameInput.val().length > 0) {
439 $('#import-and-add-btn').removeAttr("disabled");
440 }
441 $('#hintError-dir-abs-path').hide();
442 $('#hintError-dir-path-starts-with-slash').hide();
443 $('#hintError-dir-path').hide();
444 }
445 }
446 });
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500447}