[TIC-Web] add import dialog 39/121939/12
authorChangHyun Lee <leechwin.lee@samsung.com>
Wed, 29 Mar 2017 10:55:42 +0000 (19:55 +0900)
committerChangHyun Lee <leechwin.lee@samsung.com>
Wed, 5 Apr 2017 05:22:31 +0000 (14:22 +0900)
- add import for recipe and url
- add export module

Change-Id: I0b47663dcfcd83f0b345d2e2b74aa8e552682588
Signed-off-by: ChangHyun Lee <leechwin.lee@samsung.com>
config.json
controller/router.js
controller/ticcore.js
public/src/css/style.css
public/src/index.html
public/src/js/page/export.js [new file with mode: 0644]
public/src/js/page/import.js [new file with mode: 0644]
public/src/js/page/settings.js

index c507d4f..b3621e3 100644 (file)
@@ -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/",
index 403cd41..e4670dd 100644 (file)
@@ -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
index be926cf..1992fa0 100644 (file)
@@ -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;
 
index 4ffea53..1eadbfa 100644 (file)
@@ -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;
+}
index 3f0a32e..e05cbca 100644 (file)
                         <div class="panel panel-primary">
                             <div class="panel-heading">Settings</div>
                             <div class="panel-body">
-                                <!-- Settings Toolbar -->
-                                <div id="tic-repository-toolbar">
-                                    <button type="button" id="tic-repository-recipe-import" class="btn btn-default"><i class="fa fa-download"></i> Recipe Import</button>
-                                    <button type="button" id="tic-repository-recipe-export" class="btn btn-default"><i class="fa fa-upload"></i> Recipe Export</button>
-                                </div>
-
                                 <!-- Repository Column -->
                                 <div class="panel panel-primary">
-                                    <div class="panel-heading">Repository</div>
+                                    <div class="panel-heading">Recipe</div>
                                     <div class="panel-body">
-                                        <div class="input-group">
-                                            <div class="form-group has-feedback has-clear">
-                                                <input id="tic-repository-input" type="text" class="form-control" placeholder="Enter repository URL">
-                                                <span id="tic-repository-input-clear" class="form-control-clear glyphicon glyphicon-remove form-control-feedback hidden"></span>
-                                            </div>
-                                            <span class="input-group-btn">
-                                                <button type="button" id="tic-repository-add"class="btn btn-default">Add Repository</button>
-                                            </span>
+                                        <!-- Settings Toolbar -->
+                                        <div id="tic-settings-recipe-toolbar">
+                                            <button type="button" id="tic-settings-recipe-import" class="btn btn-default"><i class="fa fa-download"></i> Import</button>
+                                            <button type="button" id="tic-settings-recipe-export" class="btn btn-default"><i class="fa fa-upload"></i> Export</button>
                                         </div>
-                                        <ol id="tic-repository-list" class="list-group"></ol>
+                                        <ol id="tic-recipe-list" class="list-group"></ol>
                                     </div>
                                 </div>
                             </div>
 
                             <div class="panel-footer">
-                                <a id="tic-repository-apply" type="button" class="btn btn-primary" href="#tic-package-section">Apply</a>
+                                <a id="tic-recipe-apply" type="button" class="btn btn-primary" href="#tic-package-section">Apply</a>
                             </div>
                         </div>
                     </div><!-- /End Settings Column -->
                 <li class="divider"></li>
                 -->
             </ul>
-        </div><!-- /Context menu in package tree -->
+        </div><!-- /End Context menu in package tree -->
+
+        <!-- Import Dialog -->
+        <div class="modal fade" id="tic-import-dialog" tabindex="-1" role="dialog" aria-hidden="true" data-backdrop="static">
+            <div class="modal-dialog">
+                <div class="modal-content">
+                    <div class="modal-header">
+                        <h4 class="modal-title">Add Recipe or Repository</h4>
+                    </div>
+                    <div class="modal-body">
+                        <div id="tic-import-recipe-container" data-toggle="validator" data-validate="true">
+                            <!-- Recipe File -->
+                            <div class="row">
+                                <div class="form-group col-md-3">
+                                    <div class="radio">
+                                        <label class="radio-inline control-label"><input id="tic-import-recipe-file-group" type="radio" name="recipe" checked="checked"> Recipe File</label>
+                                    </div>
+                                </div>
+                                <div class="form-group has-feedback has-clear col-md-5">
+                                    <input class="form-control tic-import-recipe-file-group" id="tic-import-recipe-file-input" type="text" readonly>
+                                </div>
+                                <div class="form-group col-md-2">
+                                    <button id="tic-import-recipe-file-browser" class="tic-import-recipe-file-group btn btn-primary" type="button">Browser..</button>
+                                </div>
+                            </div>
+
+                            <!-- Recipe URL -->
+                            <div class="row">
+                                <div class="form-group col-md-3">
+                                    <div class="radio">
+                                        <label class="radio-inline control-label"><input id="tic-import-recipe-url-group" type="radio" name="recipe"> Recipe URL</label>
+                                    </div>
+                                </div>
+                                <div id="tic-import-recipe-url-group" class="form-group has-feedback has-clear col-md-7">
+                                    <input class="form-control tic-import-recipe-url-group" id="tic-import-recipe-url-input" type="url" placeholder="Enter recipe URL" data-unique="unique">
+                                    <div id="tic-import-recipe-url-group-help" class="help-block with-errors"></div>
+                                </div>
+                            </div>
+
+                            <!-- Repository URL -->
+                            <div class="row">
+                                <div class="form-group col-md-3">
+                                    <div class="radio">
+                                        <label class="radio-inline control-label"><input id="tic-import-recipe-repo-url-group" type="radio" name="recipe" > Repository URL</label>
+                                    </div>
+                                </div>
+                                <div class="form-group has-feedback has-clear col-md-7">
+                                    <input class="form-control tic-import-recipe-repo-url-group" id="tic-import-recipe-repo-url-input" type="url" placeholder="Enter repository URL" data-unique="unique">
+                                    <div class="help-block with-errors"></div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="modal-footer">
+                        <button id="tic-import-recipe-confirm-ok" type="button" class="btn btn-primary">OK</button>
+                        <button id="tic-import-recipe-confirm-cancel" type="button" class="btn btn-danger" data-dismiss="modal">Cancel</button>
+                    </div>
+                </div>
+            </div>
+        </div><!-- /End Import Dialog -->
 
         <!-- library loading -->
         <script src="/socket.io/socket.io.js"></script>
         <script src="/js/config.js"></script>
         <script src="/lib/requirejs/require.js" data-main="js/main"></script>
     </body>
-</html>
+</html>
\ 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 (file)
index 0000000..52e1620
--- /dev/null
@@ -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 (file)
index 0000000..e1e68be
--- /dev/null
@@ -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 = '<ul class="list-unstyled"><li>' + err + '</li></ul>';
+                    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,
+    }
+
+});
index ad9e31b..e6f0ce5 100644 (file)
@@ -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 = '<li class="list-group-item clearfix"><span class="tic-repository-url"><%= url %></span><button type="button" class="btn pull-right btn-default"><i class="fa fa-trash-o"></i></button></li>';
+    var CONFIG = null;
+    var RECIPE_LI = '<li class="list-group-item clearfix" id="<%= id %>"><span class="tic-recipe-name"><%= name %></span><button type="button" class="btn pull-right btn-default"><i class="fa fa-trash-o"></i></button></li>';
 
-    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.<br>Please check the tic-core.<br>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