Migrates all JS code to webpack

- moves the fonts back to the war/src/main/webapp/css folder
This commit is contained in:
Félix Queiruga 2019-12-05 10:34:13 +01:00
parent 7f6bd4dde1
commit f88d1f8771
69 changed files with 1346 additions and 291 deletions

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"editor.formatOnSave": false
}

View File

@ -271,6 +271,8 @@ THE SOFTWARE.
</div>
<j:if test="${layoutType!='full-screen'}">
<link rel="stylesheet" href="${resURL}/jsbundles/pluginSetupWizard.css" type="text/css" />
<footer>
<div class="container-fluid">
<div class="row">

3
war/.babelrc Normal file
View File

@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env"],
}

11
war/.jshintrc.json Normal file
View File

@ -0,0 +1,11 @@
{
"curly": true,
"eqeqeq": true,
"unused": true,
"undef": true,
"browser": true,
"browserify": true,
"jasmine": true,
"esversion": 6,
"predef": ["console", "Hash"]
}

View File

@ -7,29 +7,29 @@ var builder = require('jenkins-js-builder');
// Bundle the page init script.
// See https://github.com/jenkinsci/js-builder#bundling
//
builder.bundle('src/main/js/page-init.js')
.withExternalModuleMapping('jquery-detached', 'core-assets/jquery-detached:jquery2')
.inDir('src/main/webapp/jsbundles');
// builder.bundle('src/main/js/page-init.js')
// .withExternalModuleMapping('jquery-detached', 'core-assets/jquery-detached:jquery2')
// .inDir('src/main/webapp/jsbundles');
//
// Bundle the Install Wizard.
// See https://github.com/jenkinsci/js-builder#bundling
//
builder.bundle('src/main/js/pluginSetupWizard.js')
.withExternalModuleMapping('jquery-detached', 'core-assets/jquery-detached:jquery2')
.withExternalModuleMapping('bootstrap', 'core-assets/bootstrap:bootstrap3', {addDefaultCSS: true})
.withExternalModuleMapping('handlebars', 'core-assets/handlebars:handlebars3')
.less('src/main/less/pluginSetupWizard.less')
.inDir('src/main/webapp/jsbundles');
// builder.bundle('src/main/js/pluginSetupWizard.js')
// .withExternalModuleMapping('jquery-detached', 'core-assets/jquery-detached:jquery2')
// .withExternalModuleMapping('bootstrap', 'core-assets/bootstrap:bootstrap3', {addDefaultCSS: true})
// .withExternalModuleMapping('handlebars', 'core-assets/handlebars:handlebars3')
// // .less('src/main/less/pluginSetupWizard.less')
// .inDir('src/main/webapp/jsbundles');
//
// //
// Bundle the Upgrade Wizard.
//
builder.bundle('src/main/js/upgradeWizard.js')
.withExternalModuleMapping('jquery-detached', 'core-assets/jquery-detached:jquery2')
.withExternalModuleMapping('bootstrap', 'core-assets/bootstrap:bootstrap3')
.withExternalModuleMapping('handlebars', 'core-assets/handlebars:handlebars3')
.inDir('src/main/webapp/jsbundles');
// builder.bundle('src/main/js/upgradeWizard.js')
// .withExternalModuleMapping('jquery-detached', 'core-assets/jquery-detached:jquery2')
// .withExternalModuleMapping('bootstrap', 'core-assets/bootstrap:bootstrap3')
// .withExternalModuleMapping('handlebars', 'core-assets/handlebars:handlebars3')
// .inDir('src/main/webapp/jsbundles');
//
// Bundle the Config Tab Bar.

View File

@ -10,18 +10,25 @@
},
"private": true,
"scripts": {
"dev": "webpack --config webpack.config.js"
"dev": "webpack --config webpack.config.js",
"test": "babel ./node_modules/jasmine/bin/jasmine.js src/test/js/widgets/config/tabbar-spec.js"
},
"devDependencies": {
"@babel/cli": "^7.7.4",
"@babel/core": "^7.7.4",
"css-loader": "^3.2.0",
"file-loader": "^5.0.2",
"gulp": "^3.9.0",
"gulp-less": "^3.1.0",
"handlebars": "^3.0.3",
"handlebars-loader": "^1.7.1",
"hbsfy": "^2.4.1",
"jasmine": "^3.5.0",
"jenkins-handlebars-rt": "^1.0.1",
"jenkins-js-builder": "0.0.40",
"jenkins-js-test": "^1.0.0",
"jshint": "^2.10.3",
"less": "^3.10.3",
"less-loader": "^5.0.0",
"mini-css-extract-plugin": "^0.8.0",
"webpack": "^4.41.2",
@ -29,12 +36,12 @@
"webpack-fix-style-only-entries": "^0.4.0"
},
"dependencies": {
"bootstrap-detached": "^3.3.5-v1",
"file-loader": "^5.0.2",
"@babel/preset-env": "^7.7.4",
"babel-loader": "^8.0.6",
"bootstrap": "3.3.5",
"jenkins-js-modules": "^1.5.0",
"jquery": "2.1.4",
"jquery-detached": "^2.1.4-v2",
"less": "^3.10.3",
"window-handle": "^1.0.0"
}
}

View File

@ -1,5 +1,5 @@
// Initialize all modules by requiring them. Also makes sure they get bundled (see gulpfile.js).
var $ = require('jquery-detached').getJQuery();
import $ from 'jquery';
var getItems = function() {
var d = $.Deferred();
@ -9,7 +9,7 @@ var getItems = function() {
}
);
return d.promise();
};
};
var jRoot = $('head').attr('data-rooturl');

View File

@ -1,13 +1,14 @@
/**
* Provides a wrapper to interact with the plugin manager & update center
*/
var jenkins = require('../util/jenkins');
import jenkins from '../util/jenkins';
//Get plugin info (plugins + recommended plugin list) from update centers.
var plugins;
exports.initialPluginList = function(handler) {
var pluginManager = {};
pluginManager.initialPluginList = function(handler) {
jenkins.get('/setupWizard/platformPluginList', function(response) {
if(response.status !== 'ok') {
handler.call({ isError: true, data: response.data });
@ -22,10 +23,10 @@ exports.initialPluginList = function(handler) {
}
});
};
// Call this to initialize the plugin list
exports.init = function(handler) {
exports.initialPluginList(function(initialPluginCategories) {
pluginManager.init = function(handler) {
pluginManager.initialPluginList(function(initialPluginCategories) {
plugins = {};
plugins.names = [];
plugins.recommendedPlugins = [];
@ -52,7 +53,7 @@ exports.init = function(handler) {
}
handler();
});
};
};
// default 10 seconds for AJAX responses to return before triggering an error condition
var pluginManagerErrorTimeoutMillis = 10 * 1000;
@ -61,7 +62,7 @@ var pluginManagerErrorTimeoutMillis = 10 * 1000;
* Get the curated list of plugins to be offered in the wizard.
* @returns The curated list of plugins to be offered in the wizard.
*/
exports.plugins = function() {
pluginManager.plugins = function() {
return plugins.availablePlugins;
};
@ -69,7 +70,7 @@ exports.plugins = function() {
* Get the curated list of plugins to be offered in the wizard by name only.
* @returns The curated list of plugins to be offered in the wizard by name only.
*/
exports.pluginNames = function() {
pluginManager.pluginNames = function() {
return plugins.names;
};
@ -79,7 +80,7 @@ exports.pluginNames = function() {
* The user can easily change this selection.
* @returns The subset of plugins (subset of the plugin list) that are recommended by default.
*/
exports.recommendedPluginNames = function() {
pluginManager.recommendedPluginNames = function() {
return plugins.recommendedPlugins.slice(); // copy this
};
@ -89,7 +90,7 @@ exports.recommendedPluginNames = function() {
* If handler is called with this.isError, there will be a corresponding this.errorMessage indicating
* the failure reason
*/
exports.installPlugins = function(plugins, handler) {
pluginManager.installPlugins = function(plugins, handler) {
jenkins.post('/pluginManager/installPlugins', { dynamicLoad: true, plugins: plugins }, function(response) {
if(response.status !== 'ok') {
handler.call({ isError: true, errorMessage: response.message });
@ -110,7 +111,7 @@ exports.installPlugins = function(plugins, handler) {
* to the handler function. If argument 2 is non-null, it will be treated as a correlationId, which
* must be retrieved from a prior installPlugins call.
*/
exports.installStatus = function(handler, correlationId) {
pluginManager.installStatus = function(handler, correlationId) {
var url = '/updateCenter/installStatus';
if(correlationId !== undefined) {
url += '?correlationId=' + correlationId;
@ -137,7 +138,7 @@ exports.installStatus = function(handler, correlationId) {
* ...
* ]
*/
exports.availablePlugins = function(handler) {
pluginManager.availablePlugins = function(handler) {
jenkins.get('/pluginManager/plugins', function(response) {
if(response.status !== 'ok') {
handler.call({ isError: true, errorMessage: response.message });
@ -159,7 +160,7 @@ exports.availablePlugins = function(handler) {
* to the handler function. If argument 2 is non-null, it will be treated as a correlationId, which
* must be retrieved from a prior installPlugins call.
*/
exports.incompleteInstallStatus = function(handler, correlationId) {
pluginManager.incompleteInstallStatus = function(handler, correlationId) {
var url = '/updateCenter/incompleteInstallStatus';
if(correlationId !== undefined) {
url += '?correlationId=' + correlationId;
@ -182,7 +183,7 @@ exports.incompleteInstallStatus = function(handler, correlationId) {
/**
* Call this to complete the installation without installing anything
*/
exports.completeInstall = function(handler) {
pluginManager.completeInstall = function(handler) {
jenkins.post('/setupWizard/completeInstall', {}, function() {
handler.call({ isError: false });
}, {
@ -196,7 +197,7 @@ exports.completeInstall = function(handler) {
/**
* Indicates there is a restart required to complete plugin installations
*/
exports.getRestartStatus = function(handler) {
pluginManager.getRestartStatus = function(handler) {
jenkins.get('/setupWizard/restartStatus', function(response) {
handler.call({ isError: false }, response.data);
}, {
@ -210,7 +211,7 @@ exports.getRestartStatus = function(handler) {
/**
* Skip failed plugins, continue
*/
exports.installPluginsDone = function(handler) {
pluginManager.installPluginsDone = function(handler) {
jenkins.post('/pluginManager/installPluginsDone', {}, function() {
handler();
}, {
@ -224,7 +225,7 @@ exports.installPluginsDone = function(handler) {
/**
* Restart Jenkins
*/
exports.restartJenkins = function(handler) {
pluginManager.restartJenkins = function(handler) {
jenkins.post('/updateCenter/safeRestart', {}, function() {
handler.call({ isError: false });
}, {
@ -234,3 +235,5 @@ exports.restartJenkins = function(handler) {
}
});
};
export default pluginManager;

View File

@ -1,13 +1,12 @@
/**
* Provides a wrapper to interact with the security configuration
*/
var jenkins = require('../util/jenkins');
import jenkins from '../util/jenkins';
/**
* Calls a stapler post method to save the first user settings
*/
exports.saveFirstUser = function($form, success, error) {
function saveFirstUser($form, success, error) {
jenkins.staplerPost(
'/setupWizard/createAdminUser',
$form,
@ -22,7 +21,7 @@ exports.saveFirstUser = function($form, success, error) {
});
};
exports.saveConfigureInstance = function($form, success, error){
function saveConfigureInstance($form, success, error){
jenkins.staplerPost(
'/setupWizard/configureInstance',
$form,
@ -40,7 +39,7 @@ exports.saveConfigureInstance = function($form, success, error){
/**
* Calls a stapler post method to save the first user settings
*/
exports.saveProxy = function($form, success, error) {
function saveProxy($form, success, error) {
jenkins.staplerPost(
'/pluginManager/proxyConfigure',
$form,
@ -49,3 +48,9 @@ exports.saveProxy = function($form, success, error) {
error: error
});
};
export default {
saveFirstUser: saveFirstUser,
saveConfigureInstance: saveConfigureInstance,
saveProxy: saveProxy
}

View File

@ -1,16 +1,17 @@
var $ = require('jquery-detached').getJQuery();
import $ from 'jquery';
import windowHandle from 'window-handle';
var page = require('./util/page.js');
var windowHandle = require('window-handle');
var isScrolling = false;
var ignoreNextScrollEvent = false;
var pageHeaderHeight = page.pageHeaderHeight();
var breadcrumbBarHeight = page.breadcrumbBarHeight();
// Some stuff useful for testing.
exports.tabbars = [];
exports.scrollspeed = 500;
export var tabbars = [];
export var scrollspeed = 500;
var eventListeners = [];
exports.on = function(listener) {
export var on = function(listener) {
eventListeners.push(listener);
};
function notify(event) {
@ -23,7 +24,7 @@ $(function() {
var tabBarWidget = require('./widgets/config/tabbar.js');
tabBarWidget.addPageTabs('.config-table.scrollspy', function(tabBar) {
exports.tabbars.push(tabBar);
tabbars.push(tabBar);
tabBarWidget.addFinderToggle(tabBar);
tabBar.onShowSection(function() {
@ -50,7 +51,7 @@ function scrollTo(section, tabBar) {
isScrolling = true;
$('html,body').animate({
scrollTop: scrollTop
}, exports.scrollspeed, function() {
}, scrollspeed, function() {
if (isScrolling) {
notify({
type: 'click_scrollto',
@ -87,7 +88,7 @@ function autoActivateTabs(tabBar) {
if (!section.isVisible()) {
return;
}
// each section enters the viewport at its distance down the page, less the height of
// the toolbar, which hangs down the page. Or it is zero if the section doesn't
// match or was removed...

View File

@ -1,4 +1,5 @@
var $ = require('jquery-detached').getJQuery();
import $ from 'jquery';
var page = require('./util/page.js');
var jenkinsLocalStorage = require('./util/jenkinsLocalStorage.js');
@ -27,6 +28,9 @@ $(function() {
var tabBarLastSectionKey = 'config:' + tabBar.configForm.attr('name') + ':last-tab';
var tabBarLastSection = jenkinsLocalStorage.getPageItem(tabBarLastSectionKey, tabBar.sections[0].id);
tabBar.onShowSection(function() {
console.log('tabbar this!', this, this.id)
jenkinsLocalStorage.setPageItem(tabBarLastSectionKey, this.id);
});
tabBar.showSection(tabBarLastSection);

View File

@ -0,0 +1,3 @@
export default function id(str) {
return (''+str).replace(/\W+/g, '_');
}

View File

@ -0,0 +1,5 @@
export default function ifeq(o1, o2, options) {
if(o1 === o2) {
return options.fn();
}
}

View File

@ -0,0 +1,5 @@
export default function ifneq(o1, o2, options) {
if(o1 !== o2) {
return options.fn();
}
}

View File

@ -0,0 +1,5 @@
export default function inArray(arr, val, options) {
if(arr.indexOf(val) >= 0) {
return options.fn();
}
}

View File

@ -0,0 +1,8 @@
export default function replace() {
var val = arguments[0];
// second, through second to last - options is last
for (var i = 1; i < arguments.length - 1; i++) {
val = val.replace('{' + (i-1) + '}', arguments[i]);
}
return val;
}

View File

@ -2,7 +2,7 @@
* Page initialisation tasks.
*/
var $ = require('jquery-detached').getJQuery();
var $ = require('jquery')
var jsModules = require('jenkins-js-modules');
$(function() {

File diff suppressed because one or more lines are too long

View File

@ -1,8 +1,10 @@
// Initialize all modules by requiring them. Also makes sure they get bundled (see gulpfile.js).
var $ = require('jquery-detached').getJQuery();
// var $ = require('jquery-detached').getJQuery();
import $ from 'jquery'
import pluginSetupWizard from './pluginSetupWizardGui'
// This is the main module
var pluginSetupWizard = require('./pluginSetupWizardGui');
// var pluginSetupWizard = require('./pluginSetupWizardGui');
// This entry point for the bundle only bootstraps the main module in a browser
$(function() {

View File

@ -2,21 +2,35 @@
* Jenkins first-run install wizard
*/
// Require modules here, make sure they get browserify'd/bundled
var jquery = require('jquery-detached');
var bootstrap = require('bootstrap-detached');
var jenkins = require('./util/jenkins');
var pluginManager = require('./api/pluginManager');
var securityConfig = require('./api/securityConfig');
import $ from 'jquery';
import Handlebars from 'handlebars';
import jenkins from './util/jenkins';
import pluginManager from './api/pluginManager';
import securityConfig from './api/securityConfig';
import idIfy from './handlebars-helpers/id';
import { enhanceJQueryWithBootstrap } from './plugin-setup-wizard/bootstrap-detached';
import errorPanel from './templates/errorPanel.hbs';
import loadingPanel from './templates/loadingPanel.hbs';
import welcomePanel from './templates/welcomePanel.hbs';
import progressPanel from './templates/progressPanel.hbs';
import pluginSuccessPanel from './templates/successPanel.hbs';
import pluginSelectionPanel from './templates/pluginSelectionPanel.hbs';
import setupCompletePanel from './templates/setupCompletePanel.hbs';
import proxyConfigPanel from './templates/proxyConfigPanel.hbs';
import firstUserPanel from './templates/firstUserPanel.hbs';
import configureInstancePanel from './templates/configureInstance.hbs';
import offlinePanel from './templates/offlinePanel.hbs';
import pluginSetupWizard from './templates/pluginSetupWizard.hbs';
import incompleteInstallationPanel from './templates/incompleteInstallationPanel.hbs';
import pluginSelectList from './templates/pluginSelectList.hbs';
window.zq = jquery.getJQuery();
Handlebars.registerPartial('pluginSelectList', pluginSelectList);
window.zq = $
// Setup the dialog, exported
var createPluginSetupWizard = function(appendTarget) {
// call getJQuery / getBootstrap within the main function so it will work with tests -- if getJQuery etc is called in the main
var $ = jquery.getJQuery();
var $bs = bootstrap.getBootstrap();
var Handlebars = jenkins.initHandlebars();
var $bs = enhanceJQueryWithBootstrap($);
// Necessary handlebars helpers:
// returns the plugin count string per category selected vs. available e.g. (5/44)
@ -85,7 +99,7 @@ var createPluginSetupWizard = function(appendTarget) {
var deps = $.grep(plug.allDependencies, function(value) { // remove self
return value !== plugName;
});
var out = '';
for(var i = 0; i < deps.length; i++) {
var depName = deps[i];
@ -103,31 +117,18 @@ var createPluginSetupWizard = function(appendTarget) {
return options.fn();
}
});
// Include handlebars templates here - explicitly require them and they'll be available by hbsfy as part of the bundle process
var errorPanel = require('./templates/errorPanel.hbs');
var loadingPanel = require('./templates/loadingPanel.hbs');
var welcomePanel = require('./templates/welcomePanel.hbs');
var progressPanel = require('./templates/progressPanel.hbs');
var pluginSuccessPanel = require('./templates/successPanel.hbs');
var pluginSelectionPanel = require('./templates/pluginSelectionPanel.hbs');
var setupCompletePanel = require('./templates/setupCompletePanel.hbs');
var proxyConfigPanel = require('./templates/proxyConfigPanel.hbs');
var firstUserPanel = require('./templates/firstUserPanel.hbs');
var configureInstancePanel = require('./templates/configureInstance.hbs');
var offlinePanel = require('./templates/offlinePanel.hbs');
var pluginSetupWizard = require('./templates/pluginSetupWizard.hbs');
var incompleteInstallationPanel = require('./templates/incompleteInstallationPanel.hbs');
var pluginSelectList = require('./templates/pluginSelectList.hbs');
Handlebars.registerPartial('pluginSelectList', pluginSelectList);
// wrap calls with this method to handle generic errors returned by the plugin manager
var handleGenericError = function(success) {
return function() {
if(this.isError) {
var errorMessage = this.errorMessage;
if(!errorMessage || this.errorMessage === 'timeout') {
// Workaround for webpack not passing context to anonymous functions
var self = this || window;
if(self.isError) {
var errorMessage = self.errorMessage;
if(!errorMessage || self.errorMessage === 'timeout') {
errorMessage = translations.installWizard_error_connection;
}
else {
@ -136,14 +137,14 @@ var createPluginSetupWizard = function(appendTarget) {
setPanel(errorPanel, { errorMessage: errorMessage });
return;
}
success.apply(this, arguments);
success.apply(self, arguments);
};
};
var pluginList;
var allPluginNames;
var selectedPluginNames;
// state variables for plugin data, selected plugins, etc.:
var visibleDependencies = {};
var categories = [];
@ -155,9 +156,9 @@ var createPluginSetupWizard = function(appendTarget) {
$wizard.appendTo(appendTarget);
var $container = $wizard.find('.modal-content');
var currentPanel;
var self = this;
// show tooltips; this is done here to work around a bootstrap/prototype incompatibility
$(document).on('mouseenter', '*[data-tooltip]', function() {
var $tip = $bs(this);
@ -172,7 +173,7 @@ var createPluginSetupWizard = function(appendTarget) {
title: text
}).tooltip('show');
});
// handle clicking links that might not get highlighted due to position on the page
$wizard.on('click', '.nav>li>a', function(){
var $li = $(this).parent();
@ -194,7 +195,7 @@ var createPluginSetupWizard = function(appendTarget) {
// any decorations after DOM replacement go here
}
];
var getJenkinsVersionFull = function() {
var version = $('body').attr('data-version');
if(!version) {
@ -256,7 +257,7 @@ var createPluginSetupWizard = function(appendTarget) {
});
oncomplete();
// try to refocus on the element that had focus
try {
var e = $('body')[0];
@ -275,7 +276,7 @@ var createPluginSetupWizard = function(appendTarget) {
currentPanel = panel;
$container.append(html);
decorate($container);
var $modalHeader = $container.find('.modal-header');
if($modalHeader.length > 0 && $modalHeader.is('.closeable')) {
$modalHeader.prepend(
@ -290,7 +291,7 @@ var createPluginSetupWizard = function(appendTarget) {
}
$modalFooter.prepend('<div class="jenkins-version">'+translations.installWizard_jenkinsVersionTitle+' '+getJenkinsVersionFull()+'</div>');
}
oncomplete();
};
var $modalBody = $container.find('.modal-body');
@ -386,7 +387,7 @@ var createPluginSetupWizard = function(appendTarget) {
showStatePanel();
}));
};
// toggles visibility of dependency listing for a plugin
var toggleDependencyList = function() {
var $btn = $(this);
@ -412,17 +413,17 @@ var createPluginSetupWizard = function(appendTarget) {
installPlugins(pluginManager.recommendedPluginNames());
});
};
var enableButtonsAfterFrameLoad = function() {
$('iframe[src]').load(function() {
$('button').prop({disabled:false});
});
};
var enableButtonsImmediately = function() {
$('button').prop({disabled:false});
};
// errors: Map of nameOfField to errorMessage
var displayErrors = function(iframe, errors) {
if(!errors){
@ -443,11 +444,11 @@ var createPluginSetupWizard = function(appendTarget) {
$errorPanel.text(message);
}
};
var setupFirstUser = function() {
setPanel(firstUserPanel, {}, enableButtonsAfterFrameLoad);
};
var showConfigureInstance = function(messages) {
setPanel(configureInstancePanel, messages, enableButtonsAfterFrameLoad);
};
@ -484,7 +485,7 @@ var createPluginSetupWizard = function(appendTarget) {
stateHandlers.DEFAULT();
}
};
// Define actions
var showInstallProgress = function() {
// check for installing plugins that failed
@ -492,7 +493,7 @@ var createPluginSetupWizard = function(appendTarget) {
setPanel(pluginSuccessPanel, { installingPlugins : installingPlugins, failedPlugins: true });
return;
}
var attachScrollEvent = function() {
var $c = $('.install-console-scroll');
if (!$c.length) {
@ -517,7 +518,7 @@ var createPluginSetupWizard = function(appendTarget) {
});
}
};
initInstallingPluginList();
setPanel(progressPanel, { installingPlugins : installingPlugins }, attachScrollEvent);
@ -525,7 +526,7 @@ var createPluginSetupWizard = function(appendTarget) {
var updateStatus = function() {
pluginManager.installStatus(handleGenericError(function(data) {
var jobs = data.jobs;
var i, j;
var complete = 0;
var total = 0;
@ -596,7 +597,7 @@ var createPluginSetupWizard = function(appendTarget) {
}
$txt.append($div);
var $itemProgress = $('.selected-plugin[id="installing-' + jenkins.idIfy(j.name) + '"]');
var $itemProgress = $('.selected-plugin[id="installing-' + idIfy(j.name) + '"]');
if($itemProgress.length > 0 && !$itemProgress.is('.'+state)) {
$itemProgress.addClass(state);
}
@ -647,7 +648,7 @@ var createPluginSetupWizard = function(appendTarget) {
oncomplete();
}));
};
var loadPluginCategories = function(oncomplete) {
loadPluginData(function() {
categories = [];
@ -828,7 +829,7 @@ var createPluginSetupWizard = function(appendTarget) {
var val = $(this).val();
searchForPlugins(val, true);
});
// handle keyboard up/down navigation between items in
// in the list, if we're focused somewhere inside
$wizard.on('keydown', '.plugin-list', function(e) {
@ -942,7 +943,7 @@ var createPluginSetupWizard = function(appendTarget) {
firstUserSkipped = true;
showConfigureInstance();
};
var handleConfigureInstanceResponseSuccess = function (data) {
if (data.status === 'ok') {
if(firstUserSkipped){
@ -976,13 +977,13 @@ var createPluginSetupWizard = function(appendTarget) {
doc.close();
$('button').prop({disabled:false});
};
var saveConfigureInstance = function() {
$('button').prop({disabled:true});
var $form = $('iframe#setup-configure-instance').contents().find('form:not(.no-json)');
securityConfig.saveConfigureInstance($form, handleConfigureInstanceResponseSuccess, handleConfigureInstanceResponseError);
};
var skipFirstUserAndConfigureInstance = function(){
firstUserSkipped = true;
skipConfigureInstance();
@ -990,36 +991,36 @@ var createPluginSetupWizard = function(appendTarget) {
var skipConfigureInstance = function() {
$('button').prop({disabled:true});
var message = '';
if(firstUserSkipped){
message += translations.installWizard_firstUserSkippedMessage;
}
message += translations.installWizard_configureInstanceSkippedMessage;
showSetupCompletePanel({message: message});
};
// call to setup the proxy
var setupProxy = function() {
setPanel(proxyConfigPanel, {}, enableButtonsAfterFrameLoad);
};
// Save the proxy config
var saveProxyConfig = function() {
securityConfig.saveProxy($('iframe[src]').contents().find('form:not(.no-json)'), function() {
jenkins.goTo('/'); // this will re-run connectivity test
});
};
// push failed plugins to retry
var retryFailedPlugins = function() {
var failedPlugins = failedPluginNames;
failedPluginNames = [];
installPlugins(failedPlugins);
};
// continue with failed plugins
var continueWithFailedPlugins = function() {
pluginManager.installPluginsDone(function(){
@ -1029,7 +1030,7 @@ var createPluginSetupWizard = function(appendTarget) {
}));
});
};
// Call this to resume an installation after restart
var resumeInstallation = function() {
// don't re-initialize installing plugins
@ -1078,7 +1079,7 @@ var createPluginSetupWizard = function(appendTarget) {
jenkins.goTo('/');
}));
};
var startOver = function() {
jenkins.goTo('/');
};
@ -1122,7 +1123,7 @@ var createPluginSetupWizard = function(appendTarget) {
// do this so the page isn't blank while doing connectivity checks and other downloads
setPanel(loadingPanel);
// Process extensions
var extensionTranslationOverrides = [];
/* globals setupWizardExtensions: true */
@ -1145,11 +1146,11 @@ var createPluginSetupWizard = function(appendTarget) {
});
});
}
for(var cls in actions) {
bindClickHandler(cls, actions[cls]);
}
var showInitialSetupWizard = function() {
// check for connectivity to the configured default update site
/* globals defaultUpdateSiteId: true */
@ -1162,7 +1163,7 @@ var createPluginSetupWizard = function(appendTarget) {
}
return;
}
// Initialize the plugin manager after connectivity checks
pluginManager.init(handleGenericError(function() {
pluginList = pluginManager.plugins();
@ -1172,7 +1173,7 @@ var createPluginSetupWizard = function(appendTarget) {
// check for updates when first loaded...
pluginManager.installStatus(handleGenericError(function(data) {
var jobs = data.jobs;
if(jobs.length > 0) {
if (installingPlugins.length === 0) {
// This can happen on a page reload if we are in the middle of
@ -1211,7 +1212,7 @@ var createPluginSetupWizard = function(appendTarget) {
for(var plugName in incompleteStatus) {
var j = getInstallingPlugin(plugName);
if (!j) {
console.warn('Plugin "' + plugName + '" not found in the list of installing plugins.');
continue;
@ -1252,19 +1253,21 @@ var createPluginSetupWizard = function(appendTarget) {
}));
}));
};
// kick off to get resource bundle
jenkins.loadTranslations('jenkins.install.pluginSetupWizard', handleGenericError(function(localizations) {
translations = localizations;
// process any translation overrides
$.each(extensionTranslationOverrides, function() {
this(translations);
});
showInitialSetupWizard();
}));
};
var exports = {}
// export wizard creation method
exports.init = createPluginSetupWizard;
export default exports

View File

@ -1,17 +1,16 @@
/**
* Jenkins JS Modules common utility functions
*/
// Get the modules
var jquery = require('jquery-detached');
var wh = require('window-handle');
import $ from 'jquery'
import wh from 'window-handle'
var debug = false;
var jenkins = {}
// gets the base Jenkins URL including context path
exports.baseUrl = function() {
var $ = jquery.getJQuery();
jenkins.baseUrl = function() {
var u = $('head').attr('data-rooturl');
if(!u) {
u = '';
@ -20,7 +19,7 @@ exports.baseUrl = function() {
};
// awful hack to get around JSONifying things with Prototype taking over wrong. ugh. Prototype is the worst.
exports.stringify = function(o) {
jenkins.stringify = function(o) {
if(Array.prototype.toJSON) { // Prototype f's this up something bad
var protoJSON = {
a: Array.prototype.toJSON,
@ -56,31 +55,23 @@ exports.stringify = function(o) {
}
};
/**
* Take a string and replace non-id characters to make it a friendly-ish XML id
*/
exports.idIfy = function(str) {
return (''+str).replace(/\W+/g, '_');
};
/**
* redirect
*/
exports.goTo = function(url) {
wh.getWindow().location.replace(exports.baseUrl() + url);
jenkins.goTo = function(url) {
wh.getWindow().location.replace(jenkins.baseUrl() + url);
};
/**
* Jenkins AJAX GET callback.
* If last parameter is an object, will be extended to jQuery options (e.g. pass { error: function() ... } to handle errors)
*/
exports.get = function(url, success, options) {
jenkins.get = function(url, success, options) {
if(debug) {
console.log('get: ' + url);
}
var $ = jquery.getJQuery();
var args = {
url: exports.baseUrl() + url,
url: jenkins.baseUrl() + url,
type: 'GET',
cache: false,
dataType: 'json',
@ -96,13 +87,11 @@ exports.get = function(url, success, options) {
* Jenkins AJAX POST callback, formats data as a JSON object post (note: works around prototype.js ugliness using stringify() above)
* If last parameter is an object, will be extended to jQuery options (e.g. pass { error: function() ... } to handle errors)
*/
exports.post = function(url, data, success, options) {
jenkins.post = function(url, data, success, options) {
if(debug) {
console.log('post: ' + url);
}
var $ = jquery.getJQuery();
// handle crumbs
var headers = {};
var wnd = wh.getWindow();
@ -113,22 +102,22 @@ exports.post = function(url, data, success, options) {
else if('crumb' in wnd) {
crumb = wnd.crumb;
}
if(crumb) {
headers[crumb.fieldName] = crumb.value;
}
var formBody = data;
if(formBody instanceof Object) {
if(crumb) {
formBody = $.extend({}, formBody);
formBody[crumb.fieldName] = crumb.value;
}
formBody = exports.stringify(formBody);
formBody = jenkins.stringify(formBody);
}
var args = {
url: exports.baseUrl() + url,
url: jenkins.baseUrl() + url,
type: 'POST',
cache: false,
dataType: 'json',
@ -143,50 +132,12 @@ exports.post = function(url, data, success, options) {
$.ajax(args);
};
/**
* handlebars setup, this does not seem to actually work or get called by the require() of this file, so have to explicitly call it
*/
exports.initHandlebars = function() {
var Handlebars = require('handlebars');
Handlebars.registerHelper('ifeq', function(o1, o2, options) {
if(o1 === o2) {
return options.fn();
}
});
Handlebars.registerHelper('ifneq', function(o1, o2, options) {
if(o1 !== o2) {
return options.fn();
}
});
Handlebars.registerHelper('in-array', function(arr, val, options) {
if(arr.indexOf(val) >= 0) {
return options.fn();
}
});
Handlebars.registerHelper('id', exports.idIfy);
Handlebars.registerHelper('replace', function() {
var val = arguments[0];
// second, through second to last - options is last
for (var i = 1; i < arguments.length - 1; i++) {
val = val.replace('{' + (i-1) + '}', arguments[i]);
}
return val;
});
return Handlebars;
};
/**
* Load translations for the given bundle ID, provide the message object to the handler.
* Optional error handler as the last argument.
*/
exports.loadTranslations = function(bundleName, handler, onError) {
exports.get('/i18n/resourceBundle?baseName=' +bundleName, function(res) {
jenkins.loadTranslations = function(bundleName, handler, onError) {
jenkins.get('/i18n/resourceBundle?baseName=' +bundleName, function(res) {
if(res.status !== 'ok') {
if(onError) {
onError(res.message);
@ -218,14 +169,14 @@ exports.loadTranslations = function(bundleName, handler, onError) {
/**
* Runs a connectivity test, calls handler with a boolean whether there is sufficient connectivity to the internet
*/
exports.testConnectivity = function(siteId, handler) {
jenkins.testConnectivity = function(siteId, handler) {
// check the connectivity api
var testConnectivity = function() {
exports.get('/updateCenter/connectionStatus?siteId=' + siteId, function(response) {
jenkins.get('/updateCenter/connectionStatus?siteId=' + siteId, function(response) {
if(response.status !== 'ok') {
handler(false, true, response.message);
}
// Define statuses, which need additional check iteration via async job on the Jenkins master
// Statuses like "OK" or "SKIPPED" are considered as fine.
var uncheckedStatuses = ['PRECHECK', 'CHECKING', 'UNCHECKED'];
@ -235,7 +186,7 @@ exports.testConnectivity = function(siteId, handler) {
else {
// Update site should be always reachable, but we do not require the internet connection
// if it's explicitly skipped by the update center
if(response.status !== 'ok' || response.data.updatesite !== 'OK' ||
if(response.status !== 'ok' || response.data.updatesite !== 'OK' ||
(response.data.internet !== 'OK' && response.data.internet !== 'SKIPPED')) {
// no connectivity, but not fatal
handler(false, false);
@ -246,7 +197,7 @@ exports.testConnectivity = function(siteId, handler) {
}
}, { error: function(xhr, textStatus, errorThrown) {
if (xhr.status === 403) {
exports.goTo('/login');
jenkins.goTo('/login');
} else {
handler.call({ isError: true, errorMessage: errorThrown });
}
@ -259,8 +210,7 @@ exports.testConnectivity = function(siteId, handler) {
/**
* gets the window containing a form, taking in to account top-level iframes
*/
exports.getWindow = function($form) {
var $ = jquery.getJQuery();
jenkins.getWindow = function($form) {
$form = $($form);
var wnd = wh.getWindow();
$(top.document).find('iframe').each(function() {
@ -278,13 +228,12 @@ exports.getWindow = function($form) {
/**
* Builds a stapler form post
*/
exports.buildFormPost = function($form) {
var $ = jquery.getJQuery();
jenkins.buildFormPost = function($form) {
$form = $($form);
var wnd = exports.getWindow($form);
var wnd = jenkins.getWindow($form);
var form = $form[0];
if(wnd.buildFormTree(form)) {
return $form.serialize() + "&" + jquery.param({
return $form.serialize() + "&" + $.param({
'core:apply': '',
'Submit': 'Save',
'json': $form.find('input[name=json]').val()
@ -296,10 +245,9 @@ exports.buildFormPost = function($form) {
/**
* Gets the crumb, if crumbs are enabled
*/
exports.getFormCrumb = function($form) {
var $ = jquery.getJQuery();
jenkins.getFormCrumb = function($form) {
$form = $($form);
var wnd = exports.getWindow($form);
var wnd = jenkins.getWindow($form);
return wnd.crumb;
};
@ -307,12 +255,11 @@ exports.getFormCrumb = function($form) {
* Jenkins Stapler JSON POST callback
* If last parameter is an object, will be extended to jQuery options (e.g. pass { error: function() ... } to handle errors)
*/
exports.staplerPost = function(url, $form, success, options) {
var $ = jquery.getJQuery();
jenkins.staplerPost = function(url, $form, success, options) {
$form = $($form);
var postBody = exports.buildFormPost($form);
var crumb = exports.getFormCrumb($form);
exports.post(
var postBody = jenkins.buildFormPost($form);
var crumb = jenkins.getFormCrumb($form);
jenkins.post(
url,
postBody,
success, $.extend({
@ -321,3 +268,5 @@ exports.staplerPost = function(url, $form, success, options) {
crumb: crumb
}, options));
};
export default jenkins;

View File

@ -1,11 +1,17 @@
/*
* Some internal jQuery extensions.
*
* After migrating to webpack it modifies the provided version of jquery
*/
import $ from 'jquery';
import windowHandle from 'window-handle';
var jQD = require('jquery-detached');
/**
* TODO: look into other way of doing this
*/
var $ext;
exports.getJQuery = function() {
export var getJQuery = function() {
if (!$ext) {
initJQueryExt();
}
@ -15,15 +21,15 @@ exports.getJQuery = function() {
/*
* Clear the $ext instance if the window changes. Primarily for unit testing.
*/
var windowHandle = require('window-handle');
windowHandle.getWindow(function() {
$ext = undefined;
});
/**
* Adds the :containsci selector to jQuery
*/
function initJQueryExt() {
// We are going to be adding "stuff" to jQuery. We create a totally new jQuery instance
// because we do NOT want to run the risk of polluting the shared instance.
$ext = jQD.newJQuery();
$ext = $;
/**
* A pseudo selector that performs a case insensitive text contains search i.e. the same
@ -38,3 +44,4 @@ function initJQueryExt() {
});
}
initJQueryExt();

View File

@ -5,11 +5,9 @@ var jenkinsLocalStorage = require('../../util/jenkinsLocalStorage.js');
var tableMetadata = require('./model/ConfigTableMetaData.js');
var behaviorShim = require('../../util/behavior-shim');
exports.tabBarShowPreferenceKey = 'config:usetabs';
exports.addPageTabs = function(configSelector, onEachConfigTable, options) {
var $ = jQD.getJQuery();
export var tabBarShowPreferenceKey = 'config:usetabs';
export var addPageTabs = function(configSelector, onEachConfigTable, options) {
$(function() {
behaviorShim.specify(".dd-handle", 'config-drag-start', 1000, function(el) {
page.fixDragEvent(el);
@ -21,29 +19,29 @@ exports.addPageTabs = function(configSelector, onEachConfigTable, options) {
// Only do job configs for now.
var configTables = $(configSelector);
if (configTables.size() > 0) {
var tabBarShowPreference = jenkinsLocalStorage.getGlobalItem(exports.tabBarShowPreferenceKey, "yes");
var tabBarShowPreference = jenkinsLocalStorage.getGlobalItem(tabBarShowPreferenceKey, "yes");
page.fixDragEvent(configTables);
if (tabBarShowPreference === "yes") {
configTables.each(function() {
var configTable = $(this);
var tabBar = exports.addTabs(configTable, options);
var tabBar = addTabs(configTable, options);
onEachConfigTable.call(configTable, tabBar);
tabBar.deactivator.click(function() {
jenkinsLocalStorage.setGlobalItem(exports.tabBarShowPreferenceKey, "no");
jenkinsLocalStorage.setGlobalItem(tabBarShowPreferenceKey, "no");
require('window-handle').getWindow().location.reload();
});
});
} else {
configTables.each(function() {
var configTable = $(this);
var activator = exports.addTabsActivator(configTable);
var activator = addTabsActivator(configTable);
tableMetadata.markConfigTableParentForm(configTable);
activator.click(function() {
jenkinsLocalStorage.setGlobalItem(exports.tabBarShowPreferenceKey, "yes");
jenkinsLocalStorage.setGlobalItem(tabBarShowPreferenceKey, "yes");
require('window-handle').getWindow().location.reload();
});
});
@ -53,12 +51,11 @@ exports.addPageTabs = function(configSelector, onEachConfigTable, options) {
});
};
exports.addTabsOnFirst = function() {
return exports.addTabs(tableMetadata.findConfigTables().first());
export var addTabsOnFirst = function() {
return addTabs(tableMetadata.findConfigTables().first());
};
exports.addTabs = function(configTable, options) {
var $ = jQD.getJQuery();
export var addTabs = function(configTable, options) {
var configTableMetadata;
var tabOptions = (options || {});
var trackSectionVisibility = (tabOptions.trackSectionVisibility || false);
@ -124,16 +121,14 @@ exports.addTabs = function(configTable, options) {
return configTableMetadata;
};
exports.addTabsActivator = function(configTable) {
var $ = jQD.getJQuery();
export var addTabsActivator = function(configTable) {
var configWidgets = $('<div class="jenkins-config-widgets"><div class="showTabs" title="Add configuration section tabs">Add tabs</div></div>');
configWidgets.insertBefore(configTable.parent());
return configWidgets;
};
exports.addFinderToggle = function(configTableMetadata) {
var $ = jQD.getJQuery();
export var addFinderToggle = function(configTableMetadata) {
var findToggle = $('<div class="find-toggle" title="Find"></div>');
var finderShowPreferenceKey = 'config:showfinder';

View File

@ -1,6 +1,6 @@
@import (css) './font-awesome/css/font-awesome.css';
@import (css) './icomoon/css/icomoon.css';
@import (css) './google-fonts/roboto/css/roboto.css';
@import (css) '../webapp/css/font-awesome/css/font-awesome.min.css';
@import (css) '../webapp/css/icomoon/css/icomoon.css';
@import (css) '../webapp/css/google-fonts/roboto/css/roboto.css';
.bootstrap-3 * {
// simple reset
@ -943,3 +943,7 @@ body .plugin-setup-wizard { // need specificity, revisit the CSS inclusion order
height: 5em;
}
}
.bootstrap-3 {
@import (less) '../../../node_modules/bootstrap/less/bootstrap.less';
}

View File

Before

Width:  |  Height:  |  Size: 381 KiB

After

Width:  |  Height:  |  Size: 381 KiB

View File

Before

Width:  |  Height:  |  Size: 198 KiB

After

Width:  |  Height:  |  Size: 198 KiB

View File

@ -1,17 +1,20 @@
var jsTest = require("jenkins-js-test");
// mock the behaviors stuff.
var behaviorShim = jsTest.requireSrcModule('util/behavior-shim');
// var behaviorShim = jsTest.requireSrcModule('util/behavior-shim');
var behaviorShim = require('../../../../main/js/util/behavior-shim');
behaviorShim.specify = function(selector, id, priority, behavior) {
behavior();
};
// Mock out the fireBottomStickerAdjustEvent function ... it accesses Event.
var page = jsTest.requireSrcModule('util/page');
// var page = jsTest.requireSrcModule('../../../../main/js/util/page');
var page = require('../../../../main/js/util/page');
page.fireBottomStickerAdjustEvent = function() {};
var windowHandle = require('window-handle');
windowHandle.getWindow(function() {
var localStorage = jsTest.requireSrcModule('util/localStorage');
// var localStorage = jsTest.requireSrcModule('../../../../main/js/util/localStorage');
var localStorage = require('../../../../main/js/util/localStorage');
localStorage.setMock();
});

View File

@ -3,14 +3,14 @@ const MiniCSSExtractPlugin = require('mini-css-extract-plugin');
const FixStyleOnlyEntriesPlugin = require("webpack-fix-style-only-entries");
module.exports = {
// mode: 'development',
mode: 'development',
entry: {
// "page-init": [path.join(__dirname, "src/main/js/page-init.js")],
"page-init": [path.join(__dirname, "src/main/js/page-init.js")],
"pluginSetupWizard": [
// path.join(__dirname, "src/main/js/pluginSetupWizard.js"),
path.join(__dirname, "src/main/js/pluginSetupWizard.js"),
path.join(__dirname, "src/main/less/pluginSetupWizard.less"),
],
// "upgradeWizard": [path.join(__dirname, "src/main/js/upgradeWizard.js")],
"upgradeWizard": [path.join(__dirname, "src/main/js/upgradeWizard.js")],
"add-item": [
path.join(__dirname, "src/main/js/add-item.js"),
path.join(__dirname, "src/main/js/add-item.less"),
@ -51,6 +51,31 @@ module.exports = {
}
]
},
{
test: /\.hbs$/,
loader: "handlebars-loader",
options: {
helperDirs: path.join(__dirname, 'src/main/js/handlebars-helpers'),
precompileOptions: {
knownHelpersOnly: false,
// Helpers registered with Handlebars.registerHelper must be listed so that
// handlebars-loader will expect them when compiling the templates
knownHelpers: [
'pluginCountForCategory',
'totalPluginCount',
'inSelectedPlugins',
'dependencyCount',
'eachDependency',
'ifVisibleDependency'
]
},
},
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
},
]
},
optimization: {
@ -64,5 +89,11 @@ module.exports = {
// }
// }
}
}
},
resolve: {
alias:{
// Needed to be able to register helpers at runtime
handlebars: 'handlebars/runtime',
},
},
}

File diff suppressed because it is too large Load Diff