From 30484f1a7397a0f7a078aa310d73205054bfa1bb Mon Sep 17 00:00:00 2001 From: ChangHyun Lee Date: Wed, 29 Mar 2017 19:55:42 +0900 Subject: [PATCH] [TIC-Web] add import dialog - add import for recipe and url - add export module Change-Id: I0b47663dcfcd83f0b345d2e2b74aa8e552682588 Signed-off-by: ChangHyun Lee --- config.json | 4 +- controller/router.js | 10 +++ controller/ticcore.js | 41 +++++++++++ public/src/css/style.css | 18 +++-- public/src/index.html | 87 ++++++++++++++++++------ public/src/js/page/export.js | 35 ++++++++++ public/src/js/page/import.js | 148 ++++++++++++++++++++++++++++++++++++++++ public/src/js/page/settings.js | 150 ++++++++++++++++++----------------------- 8 files changed, 385 insertions(+), 108 deletions(-) create mode 100644 public/src/js/page/export.js create mode 100644 public/src/js/page/import.js diff --git a/config.json b/config.json index c507d4f..b3621e3 100644 --- a/config.json +++ b/config.json @@ -47,7 +47,9 @@ "JOB_READ_LOG": "/api/job/log/" }, "PACKAGE": { - "EXPORT": "/api/exports/" + "IMPORT": "/api/imports/", + "EXPORT": "/api/exports/", + "ANALYSIS": "/api/analysis" }, "IMAGE": { "IMAGE_GET_ALL_COUNT": "/api/image/count/", diff --git a/controller/router.js b/controller/router.js index 403cd41..e4670dd 100644 --- a/controller/router.js +++ b/controller/router.js @@ -155,6 +155,16 @@ var init = function (serv) { }); /** + * Get recipe data from tic-core via RESTful API + * @URI /api/imports + * @TYPE POST + */ + router.post('/imports', function (req, res) { + logger.info('an api called that /api/imports'); + core.getImports(req, res); + }); + + /** * Get ks file path from tic-core via RESTful API * @URI /api/exports * @TYPE POST diff --git a/controller/ticcore.js b/controller/ticcore.js index be926cf..1992fa0 100644 --- a/controller/ticcore.js +++ b/controller/ticcore.js @@ -65,6 +65,47 @@ ticcore.getAnalysis = function getAnalysis (req, res) { ticCoreReq.end(); }; +/** + * Get recipe data from tic-core via RESTful API + */ +ticcore.getImports = function getImports (req, res) { + var postData = JSON.stringify(req.body); + var addr = this.server.address(); + + var options = { + host: addr.address, + port: AppConfig.TIC_CORE.PORT || addr.port + 1, + method: 'POST', + path: '/imports', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(postData) + } + }; + + var data = ''; + var ticCoreReq = http.request(options, function (ticCoreRes) { + ticCoreRes.setEncoding('utf8'); + ticCoreRes.on('data', function (chunk) { + data += chunk; + }); + ticCoreRes.on('end', function () { + res.send(data); + }); + }); + + ticCoreReq.write(postData); + + ticCoreReq.on('error', function (err) { + res.send({ + result: 'false', + message: err.message + }) + }); + + ticCoreReq.end(); +}; + ticcore.getExports = function getExports(req, res) { var postData, addr, options, data, ticCoreReq; diff --git a/public/src/css/style.css b/public/src/css/style.css index 4ffea53..1eadbfa 100644 --- a/public/src/css/style.css +++ b/public/src/css/style.css @@ -406,7 +406,7 @@ tr.extended_job_table_row:hover td { background: #e1e1e1; } -#tic-repository-toolbar { +#tic-settings-recipe-toolbar { margin-bottom: 10px; } @@ -416,7 +416,7 @@ tr.extended_job_table_row:hover td { opacity: 0.5; z-index: 2000; } -#tic-repository-list li { +#tic-recipe-list li { cursor: move; display: block; padding: 5px; @@ -425,14 +425,14 @@ tr.extended_job_table_row:hover td { background: #eee; max-width: 100%; } -#tic-repository-list li.placeholder { +#tic-recipe-list li.placeholder { position: relative; margin: 0; padding: 0; border: none; content: ""; } -#tic-repository-list li.placeholder:before { +#tic-recipe-list li.placeholder:before { position: absolute; content: ""; width: 0; @@ -444,7 +444,7 @@ tr.extended_job_table_row:hover td { border-left-color: #f00; border-right: none; } -.tic-repository-url { +.tic-recipe-name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; @@ -499,3 +499,11 @@ a.log-view-content-download { font-size: 11px; font-weight: bold; } + + +/* Import Dialog */ +#tic-import-dialog .form-group { + margin-bottom: 0px; + padding-right: 0px; + padding-left: 0px; +} diff --git a/public/src/index.html b/public/src/index.html index 3f0a32e..e05cbca 100644 --- a/public/src/index.html +++ b/public/src/index.html @@ -275,32 +275,22 @@
Settings
- -
- - -
-
-
Repository
+
Recipe
-
-
- - -
- - - + +
+ +
-
    +
      @@ -375,11 +365,70 @@
    1. --> - + + + + - + \ No newline at end of file diff --git a/public/src/js/page/export.js b/public/src/js/page/export.js new file mode 100644 index 0000000..52e1620 --- /dev/null +++ b/public/src/js/page/export.js @@ -0,0 +1,35 @@ +define([ + 'jquery', + 'lodash', + 'js/util', + 'js/logger', +], function ( + $, + _, + Util, + Logger +) { + 'use strict'; + + var logger = Logger('export.js'); + + function showExportDialog() { + // TODO: show export dialog + Util.showAlertDialog('Not yet implemented'); + } + + function _init() { + logger.info('init'); + } + + _init(); + + return { + /** + * TODO + * @method showExportDialog + */ + showExportDialog: showExportDialog + } + +}); diff --git a/public/src/js/page/import.js b/public/src/js/page/import.js new file mode 100644 index 0000000..e1e68be --- /dev/null +++ b/public/src/js/page/import.js @@ -0,0 +1,148 @@ +define([ + 'jquery', + 'lodash', + 'bootstrap-validator', + 'js/util', + 'js/logger', +], function ( + $, + _, + BootstrapValidator, + Util, + Logger +) { + 'use strict'; + + var logger = Logger('import.js'); + + var CONFIG = null; + var recipeStore = []; + + function _getRecipe() { + var postBody = { + recipes : recipeStore + }; + + return Util.POST(CONFIG.EVENT.PACKAGE.IMPORT, postBody) + .then(function (result) { + if (result.result === 'true') { + return result.data.recipes; + } else { + return Promise.reject(result.message); + } + }); + + } + + function showImportDialog(recipes) { + _clearUI(); + recipeStore = _.map(recipes, function(recipe) { + return _.pick(recipe,['url','type']); + }); + + $('#tic-import-dialog').modal('show'); + + return new Promise(function (resolve, reject) { + // bind event only once + $('#tic-import-recipe-confirm-ok').off('click').on('click', function () { + var radioId = $("input:radio[name='recipe']:checked").attr('id'); + var $inputDom = $('.' + radioId); + var recipeItem = { + url: $inputDom .val(), + type: _.includes($inputDom.attr('id'), 'repo') ? 'repository' : 'recipe' + } + recipeStore.push(recipeItem); + + _getRecipe() + .then(function (recipes) { + resolve(recipes); + $('#tic-import-dialog').modal('hide'); + }) + .catch(function (err) { + _.remove(recipeStore, function (item) { + return item === recipeItem; + }); + $('#tic-import-recipe-confirm-ok').prop('disabled', false); + + $inputDom.parent().removeClass('has-success').addClass('has-error'); + var helpDomContent = ''; + var helpDomId = '#'+ radioId + '-help'; + $(helpDomId).append(helpDomContent); + + resolve(); + }) + }); + }); + } + + function _radioHandler() { + $("input:radio[name='recipe']").each(function (index, value) { + var classDomQuery = '.' + value.id; + $(classDomQuery).each(function (index, dom) { + $(dom).prop('disabled', !value.checked); + if (value.checked === false ) { + if (dom.type === 'url' || dom.type === 'text') { + $(dom).val('').change(); + } + } + }); + }); + } + + function _initUI() { + _clearUI(); + + $("input:radio[name='recipe']").on('change', _radioHandler); + // init for default raido status + _radioHandler(); + + /* Recipe File */ + // TODO: brwser button handler + + $('#tic-import-recipe-container').validator({ + custom: { + unique: function($el) { + var input = $el.val().trim(); + if (_.isEmpty(input)) { + return; + } + var duplicatedUrl = _.filter(recipeStore, ['url', input]); + if (Util.validateURL(input) && !_.isEmpty(duplicatedUrl)) { + $('#tic-import-recipe-confirm-ok').prop('disabled', true); + return 'URL is already in use.'; + } else { + $('#tic-import-recipe-confirm-ok').prop('disabled', false); + } + } + } + }); + } + + function _clearUI() { + $('#tic-import-recipe-confirm-ok').prop('disabled', true); + $("input:radio[id='tic-import-recipe-file-group']").prop('checked', true).change(); + } + + function _init() { + logger.info('init'); + + Util.getAppConfig() + .then(function (conf) { + CONFIG = conf; + }); + + _initUI(); + _clearUI(); + } + + _init(); + + return { + /** + * TODO + * @method showImportDialog + */ + showImportDialog: showImportDialog, + } + +}); diff --git a/public/src/js/page/settings.js b/public/src/js/page/settings.js index ad9e31b..e6f0ce5 100644 --- a/public/src/js/page/settings.js +++ b/public/src/js/page/settings.js @@ -2,12 +2,16 @@ define([ 'jquery', 'jquery-sortable', 'lodash', + 'js/page/import', + 'js/page/export', 'js/util', 'js/logger' ], function ( $, js, _, + Import, + Export, Util, Logger ) { @@ -15,49 +19,54 @@ define([ var logger = Logger('settings.js'); - // FIXME: make RESTful API URL Table - var ANALYSIS_URL = '/api/analysis'; - var ROPO_LI = '
    2. <%= url %>
    3. '; + var CONFIG = null; + var RECIPE_LI = '
    4. <%= name %>
    5. '; - var repoStore = []; // { name, url } - var recipeStore = []; // TODO: define repo spec + var recipeStore = []; // { url, type, name, , } - function getRepoStore() { - return repoStore; + function getRecipeStore() { + return recipeStore; } - function _addRepo(url) { - $('#tic-repository-list').append(_.template(ROPO_LI)({ - url: url - })); + function _addRecipe(recipe) { + var $recipe; + if (recipe.type === 'recipe') { + $recipe = _.template(RECIPE_LI)({ + id: recipe.url, + name: recipe.name + }) + } else if (recipe.type === 'repository') { + $recipe = _.template(RECIPE_LI)({ + id: recipe.url, + name: recipe.url + }) + } - // TODO: define repo spec - repoStore.push({ - url: url - }) + $('#tic-recipe-list').append($recipe); } - // TODO: set/get sortable repo - function _updateRepo() { - var $repo = $('#tic-repository-list'); - $repo.empty(); + // TODO: set/get sortable recipe + function _updateRecipe() { + var $recipe = $('#tic-recipe-list'); + $recipe.empty(); - _.forEach(repoStore, function(repo) { - _addRepo(repo.url); + _.forEach(recipeStore, function(recipe) { + _addRecipe(recipe); }); } function updatePackage() { + // FIXME: var postBody = { - repos : _.map(_.orderBy(repoStore, ['priority']), 'url'), - recipes : ['default'] + //repos : _.map(_.orderBy(recipeStore, ['priority']), 'url'), + recipes : recipeStore }; - return Util.POST(ANALYSIS_URL, postBody) + return Util.POST(CONFIG.EVENT.PACKAGE.ANALYSIS, postBody) .then(function (result) { if (result.result === 'true') { - repoStore = result.data.repos; - _updateRepo(); + recipeStore = result.data.recipes; + _updateRecipe(); return result.data; } else { return Promise.reject(result.message); @@ -68,74 +77,49 @@ define([ function init() { logger.info('init'); - /** - * Recipe Import/Export - */ - function _recipeImportBtnHandler() { - // TODO: - Util.showAlertDialog('Not yet implemented'); - } - $('#tic-repository-recipe-import').on('click', _recipeImportBtnHandler); - function _recipeExportBtnHandler() { - // TODO: - Util.showAlertDialog('Not yet implemented'); - } - $('#tic-repository-recipe-export').on('click', _recipeExportBtnHandler); + Util.getAppConfig() + .then(function (conf) { + CONFIG = conf; + }); /** - * Repository Input Component + * Recipe Import/ Export */ - function _filter() { - var input = $(this).val(); - var duplicatedUrl = _.filter(repoStore, ['url', input]); - - if (Util.validateURL(input) && _.isEmpty(duplicatedUrl)) { - $('#tic-repository-add').prop('disabled', false); - } else { - $('#tic-repository-add').prop('disabled', true); - } - $('#tic-repository-input-clear').toggleClass('hidden', _.isEmpty(input)); + function _importHandler() { + Import.showImportDialog(recipeStore) + .then(function(recipes) { + recipeStore = recipes; + _updateRecipe(); + }); } - $('#tic-repository-input').on('input change', _filter); - function _inputClearBtnHandler() { - $('#tic-repository-input').val('').trigger('change').focus(); - $(this).toggleClass('hidden', true); - } - $('#tic-repository-input-clear').on('click', _inputClearBtnHandler); + $('#tic-settings-recipe-import').on('click', _importHandler); - /** - * Add Repository Button - */ - function _addRepoBtnHandler() { - var $repoInput = $('#tic-repository-input'); - var input = $repoInput.val(); - _addRepo(input); - $repoInput.val(''); - $('#tic-repository-add').prop('disabled', true); - $('#tic-repository-input-clear').addClass('hidden'); + function _exportHandler() { + // TODO: export dialog + Export.showExportDialog(); } - $('#tic-repository-add').prop('disabled', true).on('click', _addRepoBtnHandler); + $('#tic-settings-recipe-export').on('click', _exportHandler); /** - * Remove Repository Button + * Remove Recipe Button */ - function _removeRepoBtnHandler() { + function _removeRecipeBtnHandler() { var $li = $(this).parent(); - var url = $li.text(); - _.remove(repoStore, function (node) { - return _.isEqual(node.url, url); + var id = $li.attr('id'); + _.remove(recipeStore, function (node) { + return _.isEqual(node.url, id); }); $li.remove(); } - $('#tic-repository-list').on('click', 'button', _removeRepoBtnHandler); + $('#tic-recipe-list').on('click', 'button', _removeRecipeBtnHandler); /** - * Repository List + * Recipe List */ var adjustment; - $('#tic-repository-list').sortable({ - group: 'tic-repository-list', + $('#tic-recipe-list').sortable({ + group: 'tic-recipe-list', pullPlaceholder: false, // set $item relative to cursor position @@ -159,7 +143,7 @@ define([ /** * Apply Button */ - function _applyRepoBtnHandler() { + function _applyRecipeBtnHandler() { Util.showLoadingDialog(true); updatePackage() .then(function(rawData) { @@ -174,7 +158,7 @@ define([ Util.showAlertDialog('Failed to load package list.
      Please check the tic-core.
      Error: ' + reason); }); } - $('#tic-repository-apply').on('click', _applyRepoBtnHandler); + $('#tic-recipe-apply').on('click', _applyRecipeBtnHandler); } @@ -189,11 +173,11 @@ define([ updatePackage: updatePackage, /** - * Get repository data - * @method getRepoStore - * @return {array} array of repository object + * Get recipe data + * @method getRecipeStore + * @return {array} array of recipe object */ - getRepoStore: getRepoStore + getRecipeStore: getRecipeStore } -}); +}); \ No newline at end of file -- 2.7.4