Yardstick GUI & GUI deployment 73/37973/5
authorchenjiankun <chenjiankun1@huawei.com>
Mon, 24 Jul 2017 04:13:56 +0000 (04:13 +0000)
committerchenjiankun <chenjiankun1@huawei.com>
Thu, 27 Jul 2017 04:02:50 +0000 (04:02 +0000)
JIRA: YARDSTICK-758

As E release plan, we have the need of yardstick GUI.
This patch is GUI front end code and deployment.
The backend code is yardstick API.

Change-Id: Ib15f78bcc50168c7828beff97256e9939c6da809
Signed-off-by: chenjiankun <chenjiankun1@huawei.com>
79 files changed:
api/database/v2/models.py
api/resources/v2/images.py
api/resources/v2/tasks.py
api/resources/v2/testcases.py
api/urls.py
docker/Dockerfile
docker/nginx.sh [new file with mode: 0755]
docker/supervisor.sh [new file with mode: 0755]
docker/uwsgi.sh [moved from api/api-prepare.sh with 59% similarity]
gui/Gruntfile.js [new file with mode: 0644]
gui/app/404.html [new file with mode: 0644]
gui/app/favicon.ico [new file with mode: 0644]
gui/app/images/back.png [new file with mode: 0644]
gui/app/images/checkno.png [new file with mode: 0644]
gui/app/images/checkyes.png [new file with mode: 0644]
gui/app/images/close.png [new file with mode: 0644]
gui/app/images/loading.gif [new file with mode: 0644]
gui/app/images/loading2.gif [new file with mode: 0644]
gui/app/images/statusno.png [new file with mode: 0644]
gui/app/images/statusyes.png [new file with mode: 0644]
gui/app/images/url.json [new file with mode: 0644]
gui/app/images/yeoman.png [new file with mode: 0644]
gui/app/index.html [new file with mode: 0644]
gui/app/robots.txt [new file with mode: 0644]
gui/app/scripts/app.js [new file with mode: 0644]
gui/app/scripts/controllers/container.controller.js [new file with mode: 0644]
gui/app/scripts/controllers/content.controller.js [new file with mode: 0644]
gui/app/scripts/controllers/detail.controller.js [new file with mode: 0644]
gui/app/scripts/controllers/image.controller.js [new file with mode: 0644]
gui/app/scripts/controllers/main.js [new file with mode: 0644]
gui/app/scripts/controllers/pod.controller.js [new file with mode: 0644]
gui/app/scripts/controllers/project.controller.js [new file with mode: 0644]
gui/app/scripts/controllers/projectDetail.controller.js [new file with mode: 0644]
gui/app/scripts/controllers/report.controller.js [new file with mode: 0644]
gui/app/scripts/controllers/suitecreate.controller.js [new file with mode: 0644]
gui/app/scripts/controllers/suitedetail.controller.js [new file with mode: 0644]
gui/app/scripts/controllers/task.controller.js [new file with mode: 0644]
gui/app/scripts/controllers/taskModify.controller.js [new file with mode: 0644]
gui/app/scripts/controllers/testcase.controller.js [new file with mode: 0644]
gui/app/scripts/controllers/testcasedetail.controller.js [new file with mode: 0644]
gui/app/scripts/controllers/testsuit.controller.js [new file with mode: 0644]
gui/app/scripts/factory/main.factory.js [new file with mode: 0644]
gui/app/scripts/router.config.js [new file with mode: 0644]
gui/app/styles/main.css [new file with mode: 0644]
gui/app/views/container.html [new file with mode: 0644]
gui/app/views/content.html [new file with mode: 0644]
gui/app/views/environmentDetail.html [new file with mode: 0644]
gui/app/views/environmentList.html [new file with mode: 0644]
gui/app/views/layout/footer.html [new file with mode: 0644]
gui/app/views/layout/header.html [new file with mode: 0644]
gui/app/views/layout/sideNav.html [new file with mode: 0644]
gui/app/views/layout/sideNav2.html [new file with mode: 0644]
gui/app/views/main.html [new file with mode: 0644]
gui/app/views/main2.html [new file with mode: 0644]
gui/app/views/modal/chooseContainer.html [new file with mode: 0644]
gui/app/views/modal/deleteConfirm.html [new file with mode: 0644]
gui/app/views/modal/environmentDialog.html [new file with mode: 0644]
gui/app/views/modal/projectCreate.html [new file with mode: 0644]
gui/app/views/modal/suiteName.html [new file with mode: 0644]
gui/app/views/modal/taskCreate.html [new file with mode: 0644]
gui/app/views/podupload.html [new file with mode: 0644]
gui/app/views/projectList.html [new file with mode: 0644]
gui/app/views/projectdetail.html [new file with mode: 0644]
gui/app/views/report.html [new file with mode: 0644]
gui/app/views/suite.html [new file with mode: 0644]
gui/app/views/suitedetail.html [new file with mode: 0644]
gui/app/views/taskList.html [new file with mode: 0644]
gui/app/views/taskmodify.html [new file with mode: 0644]
gui/app/views/testcasechoose.html [new file with mode: 0644]
gui/app/views/testcasedetail.html [new file with mode: 0644]
gui/app/views/testcaselist.html [new file with mode: 0644]
gui/app/views/uploadImage.html [new file with mode: 0644]
gui/bower.json [new file with mode: 0644]
gui/gui.sh [new file with mode: 0755]
gui/package.json [new file with mode: 0644]
gui/test/.jshintrc [new file with mode: 0644]
gui/test/karma.conf.js [new file with mode: 0644]
gui/test/spec/controllers/main.js [new file with mode: 0644]
install.sh

index 64d49cc..1e85559 100644 (file)
@@ -31,7 +31,7 @@ class V2Environment(Base):
 
 
 class V2Openrc(Base):
-    __tablename__ = 'V2_openrc'
+    __tablename__ = 'v2_openrc'
     id = Column(Integer, primary_key=True)
     uuid = Column(String(30))
     name = Column(String(30))
index 7018184..a1577b5 100644 (file)
@@ -29,6 +29,8 @@ class V2Images(ApiResource):
         else:
             images = [self.get_info(change_obj_to_dict(i)) for i in images_list]
             status = 1 if all(i['status'] == 'ACTIVE' for i in images) else 0
+            if not images:
+                status = 0
 
         return result_handler(consts.API_SUCCESS, {'status': status, 'images': images})
 
index 9790d76..e95ae05 100644 (file)
@@ -106,7 +106,8 @@ class V2Task(ApiResource):
 
         if project.tasks:
             LOG.info('update tasks in project')
-            new_task_list = project.tasks.split(',').remove(task_id)
+            new_task_list = project.tasks.split(',')
+            new_task_list.remove(task_id)
             if new_task_list:
                 new_tasks = ','.join(new_task_list)
             else:
index 81b4aa8..8d5b5e3 100644 (file)
@@ -17,7 +17,7 @@ class V2Testcases(ApiResource):
     def get(self):
         param = Param({})
         testcase_list = Testcase().list_all(param)
-        return result_handler(consts.API_SUCCESS, testcase_list)
+        return result_handler(consts.API_SUCCESS, {'testcases': testcase_list})
 
     def post(self):
         return self._dispatch_post()
index 2211348..3fef91a 100644 (file)
@@ -26,15 +26,18 @@ urlpatterns = [
     Url('/api/v2/yardstick/environments/action', 'v2_environments'),
     Url('/api/v2/yardstick/environments/<environment_id>', 'v2_environment'),
 
+    Url('/api/v2/yardstick/openrcs', 'v2_openrcs'),
     Url('/api/v2/yardstick/openrcs/action', 'v2_openrcs'),
     Url('/api/v2/yardstick/openrcs/<openrc_id>', 'v2_openrc'),
 
+    Url('/api/v2/yardstick/pods', 'v2_pods'),
     Url('/api/v2/yardstick/pods/action', 'v2_pods'),
     Url('/api/v2/yardstick/pods/<pod_id>', 'v2_pod'),
 
     Url('/api/v2/yardstick/images', 'v2_images'),
     Url('/api/v2/yardstick/images/action', 'v2_images'),
 
+    Url('/api/v2/yardstick/containers', 'v2_containers'),
     Url('/api/v2/yardstick/containers/action', 'v2_containers'),
     Url('/api/v2/yardstick/containers/<container_id>', 'v2_container'),
 
index 2c4270a..b48a550 100644 (file)
@@ -37,6 +37,7 @@ RUN git clone --depth 1 -b $BRANCH https://gerrit.opnfv.org/gerrit/storperf ${ST
 
 WORKDIR ${YARDSTICK_REPO_DIR}
 RUN ${YARDSTICK_REPO_DIR}/install.sh
+RUN ${YARDSTICK_REPO_DIR}/docker/supervisor.sh
 
 RUN echo "daemon off;" >> /etc/nginx/nginx.conf
 
diff --git a/docker/nginx.sh b/docker/nginx.sh
new file mode 100755 (executable)
index 0000000..26937d1
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/bash
+##############################################################################
+# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+# nginx config
+nginx_config='/etc/nginx/conf.d/yardstick.conf'
+
+if [[ ! -e "${nginx_config}" ]];then
+
+    cat << EOF > "${nginx_config}"
+server {
+    listen 5000;
+    server_name localhost;
+    index  index.htm index.html;
+    location / {
+        include uwsgi_params;
+        uwsgi_pass unix:///var/run/yardstick.sock;
+    }
+
+    location /gui/ {
+        alias /etc/nginx/yardstick/gui/;
+    }
+}
+EOF
+fi
diff --git a/docker/supervisor.sh b/docker/supervisor.sh
new file mode 100755 (executable)
index 0000000..b67de22
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/bash
+##############################################################################
+# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+# nginx service start when boot
+supervisor_config='/etc/supervisor/conf.d/yardstick.conf'
+
+if [[ ! -e "${supervisor_config}" ]];then
+    cat << EOF > "${supervisor_config}"
+[supervisord]
+nodaemon = true
+
+[program:nginx]
+command = service nginx restart
+
+[program:yardstick_uwsgi]
+directory = /etc/yardstick
+command = uwsgi -i yardstick.ini
+EOF
+fi
similarity index 59%
rename from api/api-prepare.sh
rename to docker/uwsgi.sh
index 7632d9d..cf46123 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/bash
 ##############################################################################
-# Copyright (c) 2016 Huawei Technologies Co.,Ltd and others.
+# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others.
 #
 # All rights reserved. This program and the accompanying materials
 # are made available under the terms of the Apache License, Version 2.0
 
 # generate uwsgi config file
 mkdir -p /etc/yardstick
+
+# create api log directory
+mkdir -p /var/log/yardstick
+
+# create yardstick.sock for communicating
+touch /var/run/yardstick.sock
+
 uwsgi_config='/etc/yardstick/yardstick.ini'
 if [[ ! -e "${uwsgi_config}" ]];then
 
@@ -37,48 +44,3 @@ EOF
         echo "virtualenv = ${YARDSTICK_VENV}" >> "${uwsgi_config}"
     fi
 fi
-
-# nginx config
-nginx_config='/etc/nginx/conf.d/yardstick.conf'
-
-if [[ ! -e "${nginx_config}" ]];then
-
-    cat << EOF > "${nginx_config}"
-server {
-    listen 5000;
-    server_name localhost;
-    index  index.htm index.html;
-    location / {
-        include uwsgi_params;
-        uwsgi_pass unix:///var/run/yardstick.sock;
-    }
-}
-EOF
-fi
-
-# nginx service start when boot
-supervisor_config='/etc/supervisor/conf.d/yardstick.conf'
-
-if [[ ! -e "${supervisor_config}" ]];then
-    cat << EOF > "${supervisor_config}"
-[supervisord]
-nodaemon = true
-
-[program:yardstick_nginx]
-user = root
-command = service nginx restart
-autorestart = true
-
-[program:yardstick_uwsgi]
-user = root
-directory = /etc/yardstick
-command = uwsgi -i yardstick.ini
-autorestart = true
-EOF
-fi
-
-# create api log directory
-mkdir -p /var/log/yardstick
-
-# create yardstick.sock for communicating
-touch /var/run/yardstick.sock
diff --git a/gui/Gruntfile.js b/gui/Gruntfile.js
new file mode 100644 (file)
index 0000000..171d65a
--- /dev/null
@@ -0,0 +1,492 @@
+// Generated on 2017-05-31 using generator-angular 0.15.1
+'use strict';
+
+// # Globbing
+// for performance reasons we're only matching one level down:
+// 'test/spec/{,*/}*.js'
+// use this if you want to recursively match all subfolders:
+// 'test/spec/**/*.js'
+
+module.exports = function(grunt) {
+
+    // Time how long tasks take. Can help when optimizing build times
+    require('time-grunt')(grunt);
+
+    // Automatically load required Grunt tasks
+    require('jit-grunt')(grunt, {
+        useminPrepare: 'grunt-usemin',
+        ngtemplates: 'grunt-angular-templates',
+        cdnify: 'grunt-google-cdn'
+    });
+
+    // Configurable paths for the application
+    var appConfig = {
+        app: require('./bower.json').appPath || 'app',
+        dist: 'dist'
+    };
+
+    // Define the configuration for all the tasks
+    grunt.initConfig({
+
+        // Project settings
+        yeoman: appConfig,
+
+        // Watches files for changes and runs tasks based on the changed files
+        watch: {
+            bower: {
+                files: ['bower.json'],
+                tasks: ['wiredep']
+            },
+            js: {
+                files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
+                tasks: ['newer:jshint:all', 'newer:jscs:all'],
+                options: {
+                    livereload: '<%= connect.options.livereload %>'
+                }
+            },
+            jsTest: {
+                files: ['test/spec/{,*/}*.js'],
+                tasks: ['newer:jshint:test', 'newer:jscs:test', 'karma']
+            },
+            styles: {
+                files: ['<%= yeoman.app %>/styles/{,*/}*.css'],
+                tasks: ['newer:copy:styles', 'postcss']
+            },
+            gruntfile: {
+                files: ['Gruntfile.js']
+            },
+            livereload: {
+                options: {
+                    livereload: '<%= connect.options.livereload %>'
+                },
+                files: [
+                    '<%= yeoman.app %>/{,*/}*.html',
+                    '.tmp/styles/{,*/}*.css',
+                    '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
+                ]
+            }
+        },
+
+        // The actual grunt server settings
+        connect: {
+            options: {
+                port: 9099,
+                // Change this to '0.0.0.0' to access the server from outside.
+                hostname: 'localhost',
+                livereload: 35745
+            },
+            livereload: {
+                options: {
+                    open: true,
+                    middleware: function(connect) {
+                        return [
+                            connect.static('.tmp'),
+                            connect().use(
+                                '/bower_components',
+                                connect.static('./bower_components')
+                            ),
+                            connect().use(
+                                '/app/styles',
+                                connect.static('./app/styles')
+                            ),
+                            connect.static(appConfig.app)
+                        ];
+                    }
+                }
+            },
+            test: {
+                options: {
+                    port: 9001,
+                    middleware: function(connect) {
+                        return [
+                            connect.static('.tmp'),
+                            connect.static('test'),
+                            connect().use(
+                                '/bower_components',
+                                connect.static('./bower_components')
+                            ),
+                            connect.static(appConfig.app)
+                        ];
+                    }
+                }
+            },
+            dist: {
+                options: {
+                    open: true,
+                    base: '<%= yeoman.dist %>'
+                }
+            }
+        },
+
+        // Make sure there are no obvious mistakes
+        jshint: {
+            options: {
+                jshintrc: '.jshintrc',
+                reporter: require('jshint-stylish')
+            },
+            all: {
+                src: [
+                    'Gruntfile.js',
+                    '<%= yeoman.app %>/scripts/{,*/}*.js'
+                ]
+            },
+            test: {
+                options: {
+                    jshintrc: 'test/.jshintrc'
+                },
+                src: ['test/spec/{,*/}*.js']
+            }
+        },
+
+        // Make sure code styles are up to par
+        jscs: {
+            options: {
+                config: '.jscsrc',
+                verbose: true
+            },
+            all: {
+                src: [
+                    'Gruntfile.js',
+                    '<%= yeoman.app %>/scripts/{,*/}*.js'
+                ]
+            },
+            test: {
+                src: ['test/spec/{,*/}*.js']
+            }
+        },
+
+        // Empties folders to start fresh
+        clean: {
+            dist: {
+                files: [{
+                    dot: true,
+                    src: [
+                        '.tmp',
+                        '<%= yeoman.dist %>/{,*/}*',
+                        '!<%= yeoman.dist %>/.git{,*/}*'
+                    ]
+                }]
+            },
+            server: '.tmp'
+        },
+
+        // Add vendor prefixed styles
+        postcss: {
+            options: {
+                processors: [
+                    require('autoprefixer-core')({ browsers: ['last 1 version'] })
+                ]
+            },
+            server: {
+                options: {
+                    map: true
+                },
+                files: [{
+                    expand: true,
+                    cwd: '.tmp/styles/',
+                    src: '{,*/}*.css',
+                    dest: '.tmp/styles/'
+                }]
+            },
+            dist: {
+                files: [{
+                    expand: true,
+                    cwd: '.tmp/styles/',
+                    src: '{,*/}*.css',
+                    dest: '.tmp/styles/'
+                }]
+            }
+        },
+
+        // Automatically inject Bower components into the app
+        wiredep: {
+            app: {
+                src: ['<%= yeoman.app %>/index.html'],
+                ignorePath: /\.\.\//
+            },
+            test: {
+                devDependencies: true,
+                src: '<%= karma.unit.configFile %>',
+                ignorePath: /\.\.\//,
+                fileTypes: {
+                    js: {
+                        block: /(([\s\t]*)\/{2}\s*?bower:\s*?(\S*))(\n|\r|.)*?(\/{2}\s*endbower)/gi,
+                        detect: {
+                            js: /'(.*\.js)'/gi
+                        },
+                        replace: {
+                            js: '\'{{filePath}}\','
+                        }
+                    }
+                }
+            }
+        },
+
+        // Renames files for browser caching purposes
+        filerev: {
+            dist: {
+                src: [
+                    '<%= yeoman.dist %>/scripts/{,*/}*.js',
+                    '<%= yeoman.dist %>/styles/{,*/}*.css',
+                    '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
+                    '<%= yeoman.dist %>/styles/fonts/*'
+                ]
+            }
+        },
+
+        // Reads HTML for usemin blocks to enable smart builds that automatically
+        // concat, minify and revision files. Creates configurations in memory so
+        // additional tasks can operate on them
+        useminPrepare: {
+            html: '<%= yeoman.app %>/index.html',
+            options: {
+                dest: '<%= yeoman.dist %>',
+                flow: {
+                    html: {
+                        steps: {
+                            js: ['concat', 'uglifyjs'],
+                            css: ['cssmin']
+                        },
+                        post: {}
+                    }
+                }
+            }
+        },
+
+        // Performs rewrites based on filerev and the useminPrepare configuration
+        usemin: {
+            html: ['<%= yeoman.dist %>/{,*/}*.html'],
+            css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
+            js: ['<%= yeoman.dist %>/scripts/{,*/}*.js'],
+            options: {
+                assetsDirs: [
+                    '<%= yeoman.dist %>',
+                    '<%= yeoman.dist %>/images',
+                    '<%= yeoman.dist %>/styles'
+                ],
+                patterns: {
+                    js: [
+                        [/(images\/[^''""]*\.(png|jpg|jpeg|gif|webp|svg))/g, 'Replacing references to images']
+                    ]
+                }
+            }
+        },
+
+        // The following *-min tasks will produce minified files in the dist folder
+        // By default, your `index.html`'s <!-- Usemin block --> will take care of
+        // minification. These next options are pre-configured if you do not wish
+        // to use the Usemin blocks.
+        // cssmin: {
+        //   dist: {
+        //     files: {
+        //       '<%= yeoman.dist %>/styles/main.css': [
+        //         '.tmp/styles/{,*/}*.css'
+        //       ]
+        //     }
+        //   }
+        // },
+        // uglify: {
+        //   dist: {
+        //     files: {
+        //       '<%= yeoman.dist %>/scripts/scripts.js': [
+        //         '<%= yeoman.dist %>/scripts/scripts.js'
+        //       ]
+        //     }
+        //   }
+        // },
+        // concat: {
+        //   dist: {}
+        // },
+
+        imagemin: {
+            dist: {
+                files: [{
+                    expand: true,
+                    cwd: '<%= yeoman.app %>/images',
+                    src: '{,*/}*.{png,jpg,jpeg,gif}',
+                    dest: '<%= yeoman.dist %>/images'
+                }]
+            }
+        },
+
+        svgmin: {
+            dist: {
+                files: [{
+                    expand: true,
+                    cwd: '<%= yeoman.app %>/images',
+                    src: '{,*/}*.svg',
+                    dest: '<%= yeoman.dist %>/images'
+                }]
+            }
+        },
+
+        htmlmin: {
+            dist: {
+                options: {
+                    collapseWhitespace: true,
+                    conservativeCollapse: true,
+                    collapseBooleanAttributes: true,
+                    removeCommentsFromCDATA: true
+                },
+                files: [{
+                    expand: true,
+                    cwd: '<%= yeoman.dist %>',
+                    src: ['*.html'],
+                    dest: '<%= yeoman.dist %>'
+                }]
+            }
+        },
+
+        ngtemplates: {
+            dist: {
+                options: {
+                    module: 'yardStickGui2App',
+                    htmlmin: '<%= htmlmin.dist.options %>',
+                    usemin: 'scripts/scripts.js'
+                },
+                cwd: '<%= yeoman.app %>',
+                src: 'views/{,*/}*.html',
+                dest: '.tmp/templateCache.js'
+            }
+        },
+
+        // ng-annotate tries to make the code safe for minification automatically
+        // by using the Angular long form for dependency injection.
+        ngAnnotate: {
+            dist: {
+                files: [{
+                    expand: true,
+                    cwd: '.tmp/concat/scripts',
+                    src: '*.js',
+                    dest: '.tmp/concat/scripts'
+                }]
+            }
+        },
+
+        // Replace Google CDN references
+        cdnify: {
+            dist: {
+                html: ['<%= yeoman.dist %>/*.html']
+            }
+        },
+
+        // Copies remaining files to places other tasks can use
+        copy: {
+            dist: {
+                files: [{
+                        expand: true,
+                        dot: true,
+                        cwd: '<%= yeoman.app %>',
+                        dest: '<%= yeoman.dist %>',
+                        src: [
+                            '*.{ico,png,txt}',
+                            '*.html',
+                            'images/{,*/}*.{webp}',
+                            'styles/fonts/{,*/}*.*'
+                        ]
+                    }, {
+                        expand: true,
+                        cwd: '.tmp/images',
+                        dest: '<%= yeoman.dist %>/images',
+                        src: ['generated/*']
+                    }, {
+                        expand: true,
+                        cwd: 'bower_components/bootstrap/dist',
+                        src: 'fonts/*',
+                        dest: '<%= yeoman.dist %>'
+                    },
+                    {
+                        expand: true,
+                        cwd: 'bower_components/components-font-awesome',
+                        src: 'fonts/*',
+                        dest: '<%=yeoman.dist%>'
+                    }
+                ]
+            },
+            styles: {
+                expand: true,
+                cwd: '<%= yeoman.app %>/styles',
+                dest: '.tmp/styles/',
+                src: '{,*/}*.css'
+            }
+        },
+
+        // Run some tasks in parallel to speed up the build process
+        concurrent: {
+            server: [
+                'copy:styles'
+            ],
+            test: [
+                'copy:styles'
+            ],
+            dist: [
+                'copy:styles',
+                'imagemin',
+                'svgmin'
+            ]
+        },
+
+        // Test settings
+        karma: {
+            unit: {
+                configFile: 'test/karma.conf.js',
+                singleRun: true
+            }
+        }
+    });
+
+
+    grunt.registerTask('serve', 'Compile then start a connect web server', function(target) {
+        if (target === 'dist') {
+            return grunt.task.run(['build', 'connect:dist:keepalive']);
+        }
+
+        grunt.task.run([
+            'clean:server',
+            'wiredep',
+            'concurrent:server',
+            'postcss:server',
+            'connect:livereload',
+            'watch'
+        ]);
+    });
+
+    grunt.registerTask('server', 'DEPRECATED TASK. Use the "serve" task instead', function(target) {
+        grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
+        grunt.task.run(['serve:' + target]);
+    });
+
+    grunt.registerTask('test', [
+        'clean:server',
+        'wiredep',
+        'concurrent:test',
+        'postcss',
+        'connect:test',
+        'karma'
+    ]);
+
+    grunt.registerTask('build', [
+        'clean:dist',
+        'wiredep',
+        'useminPrepare',
+        'concurrent:dist',
+        'postcss',
+        'ngtemplates',
+        'concat',
+        'ngAnnotate',
+        'copy:dist',
+        // 'cdnify',
+        'cssmin',
+        'uglify',
+        'filerev',
+        'usemin',
+        'htmlmin'
+    ]);
+
+    grunt.registerTask('default', [
+        'newer:jshint',
+        'newer:jscs',
+        'test',
+        'build'
+    ]);
+};
diff --git a/gui/app/404.html b/gui/app/404.html
new file mode 100644 (file)
index 0000000..899828a
--- /dev/null
@@ -0,0 +1,152 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <title>Page Not Found :(</title>
+    <style>
+      ::-moz-selection {
+        background: #b3d4fc;
+        text-shadow: none;
+      }
+
+      ::selection {
+        background: #b3d4fc;
+        text-shadow: none;
+      }
+
+      html {
+        padding: 30px 10px;
+        font-size: 20px;
+        line-height: 1.4;
+        color: #737373;
+        background: #f0f0f0;
+        -webkit-text-size-adjust: 100%;
+        -ms-text-size-adjust: 100%;
+      }
+
+      html,
+      input {
+        font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+      }
+
+      body {
+        max-width: 500px;
+        padding: 30px 20px 50px;
+        border: 1px solid #b3b3b3;
+        border-radius: 4px;
+        margin: 0 auto;
+        box-shadow: 0 1px 10px #a7a7a7, inset 0 1px 0 #fff;
+        background: #fcfcfc;
+      }
+
+      h1 {
+        margin: 0 10px;
+        font-size: 50px;
+        text-align: center;
+      }
+
+      h1 span {
+        color: #bbb;
+      }
+
+      h3 {
+        margin: 1.5em 0 0.5em;
+      }
+
+      p {
+        margin: 1em 0;
+      }
+
+      ul {
+        padding: 0 0 0 40px;
+        margin: 1em 0;
+      }
+
+      .container {
+        max-width: 380px;
+        margin: 0 auto;
+      }
+
+      /* google search */
+
+      #goog-fixurl ul {
+        list-style: none;
+        padding: 0;
+        margin: 0;
+      }
+
+      #goog-fixurl form {
+        margin: 0;
+      }
+
+      #goog-wm-qt,
+      #goog-wm-sb {
+        border: 1px solid #bbb;
+        font-size: 16px;
+        line-height: normal;
+        vertical-align: top;
+        color: #444;
+        border-radius: 2px;
+      }
+
+      #goog-wm-qt {
+        width: 220px;
+        height: 20px;
+        padding: 5px;
+        margin: 5px 10px 0 0;
+        box-shadow: inset 0 1px 1px #ccc;
+      }
+
+      #goog-wm-sb {
+        display: inline-block;
+        height: 32px;
+        padding: 0 10px;
+        margin: 5px 0 0;
+        white-space: nowrap;
+        cursor: pointer;
+        background-color: #f5f5f5;
+        background-image: -webkit-linear-gradient(rgba(255,255,255,0), #f1f1f1);
+        background-image: -moz-linear-gradient(rgba(255,255,255,0), #f1f1f1);
+        background-image: -ms-linear-gradient(rgba(255,255,255,0), #f1f1f1);
+        background-image: -o-linear-gradient(rgba(255,255,255,0), #f1f1f1);
+        -webkit-appearance: none;
+        -moz-appearance: none;
+        appearance: none;
+      }
+
+      #goog-wm-sb:hover,
+      #goog-wm-sb:focus {
+        border-color: #aaa;
+        box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+        background-color: #f8f8f8;
+      }
+
+      #goog-wm-qt:hover,
+      #goog-wm-qt:focus {
+        border-color: #105cb6;
+        outline: 0;
+        color: #222;
+      }
+
+      input::-moz-focus-inner {
+        padding: 0;
+        border: 0;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="container">
+      <h1>Not found <span>:(</span></h1>
+      <p>Sorry, but the page you were trying to view does not exist.</p>
+      <p>It looks like this was the result of either:</p>
+      <ul>
+        <li>a mistyped address</li>
+        <li>an out-of-date link</li>
+      </ul>
+      <script>
+        var GOOG_FIXURL_LANG = (navigator.language || '').slice(0,2),GOOG_FIXURL_SITE = location.host;
+      </script>
+      <script src="//linkhelp.clients.google.com/tbproxy/lh/wm/fixurl.js"></script>
+    </div>
+  </body>
+</html>
diff --git a/gui/app/favicon.ico b/gui/app/favicon.ico
new file mode 100644 (file)
index 0000000..6527905
Binary files /dev/null and b/gui/app/favicon.ico differ
diff --git a/gui/app/images/back.png b/gui/app/images/back.png
new file mode 100644 (file)
index 0000000..917c86e
Binary files /dev/null and b/gui/app/images/back.png differ
diff --git a/gui/app/images/checkno.png b/gui/app/images/checkno.png
new file mode 100644 (file)
index 0000000..7c68419
Binary files /dev/null and b/gui/app/images/checkno.png differ
diff --git a/gui/app/images/checkyes.png b/gui/app/images/checkyes.png
new file mode 100644 (file)
index 0000000..ef60283
Binary files /dev/null and b/gui/app/images/checkyes.png differ
diff --git a/gui/app/images/close.png b/gui/app/images/close.png
new file mode 100644 (file)
index 0000000..0d2c142
Binary files /dev/null and b/gui/app/images/close.png differ
diff --git a/gui/app/images/loading.gif b/gui/app/images/loading.gif
new file mode 100644 (file)
index 0000000..b04dd11
Binary files /dev/null and b/gui/app/images/loading.gif differ
diff --git a/gui/app/images/loading2.gif b/gui/app/images/loading2.gif
new file mode 100644 (file)
index 0000000..9d15344
Binary files /dev/null and b/gui/app/images/loading2.gif differ
diff --git a/gui/app/images/statusno.png b/gui/app/images/statusno.png
new file mode 100644 (file)
index 0000000..ace4a45
Binary files /dev/null and b/gui/app/images/statusno.png differ
diff --git a/gui/app/images/statusyes.png b/gui/app/images/statusyes.png
new file mode 100644 (file)
index 0000000..d88a99e
Binary files /dev/null and b/gui/app/images/statusyes.png differ
diff --git a/gui/app/images/url.json b/gui/app/images/url.json
new file mode 100644 (file)
index 0000000..f16c4e0
--- /dev/null
@@ -0,0 +1 @@
+{"url": "192.168.23.2:1948"}
\ No newline at end of file
diff --git a/gui/app/images/yeoman.png b/gui/app/images/yeoman.png
new file mode 100644 (file)
index 0000000..92497ad
Binary files /dev/null and b/gui/app/images/yeoman.png differ
diff --git a/gui/app/index.html b/gui/app/index.html
new file mode 100644 (file)
index 0000000..5592656
--- /dev/null
@@ -0,0 +1,111 @@
+<!doctype html>
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <title></title>
+    <meta name="description" content="">
+    <meta name="viewport" content="width=device-width">
+    <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
+    <!-- build:css(.) styles/vendor.css -->
+    <!-- bower:css -->
+    <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" />
+    <link rel="stylesheet" href="bower_components/angular-wizard/dist/angular-wizard.min.css" />
+    <link rel="stylesheet" href="bower_components/AngularJS-Toaster/toaster.css" />
+    <link rel="stylesheet" href="bower_components/ng-dialog/css/ngDialog.css" />
+    <link rel="stylesheet" href="bower_components/ng-dialog/css/ngDialog-theme-default.css" />
+    <link rel="stylesheet" href="bower_components/components-font-awesome/css/font-awesome.css" />
+    <link rel="stylesheet" href="bower_components/v-accordion/dist/v-accordion.css" />
+    <link rel="stylesheet" href="bower_components/angular-loading/angular-loading.css" />
+    <!-- endbower -->
+    <!-- endbuild -->
+    <!-- build:css(.tmp) styles/main.css -->
+    <link rel="stylesheet" href="styles/main.css">
+
+
+    <!-- endbuild -->
+</head>
+
+<script>
+// read file
+
+
+</script>
+
+<body ng-app="yardStickGui2App">
+    <!--[if lte IE 8]>
+      <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
+    <![endif]-->
+
+
+
+
+    <div ui-view></div>
+
+
+
+
+    <!-- Google Analytics: change UA-XXXXX-X to be your site's ID -->
+    <!--<script>
+        ! function(A, n, g, u, l, a, r) {
+            A.GoogleAnalyticsObject = l, A[l] = A[l] || function() {
+                    (A[l].q = A[l].q || []).push(arguments)
+                }, A[l].l = +new Date, a = n.createElement(g),
+                r = n.getElementsByTagName(g)[0], a.src = u, r.parentNode.insertBefore(a, r)
+        }(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');
+
+        ga('create', 'UA-XXXXX-X');
+        ga('send', 'pageview');
+    </script>-->
+
+    <!-- build:js(.) scripts/vendor.js -->
+    <!-- bower:js -->
+    <script src="bower_components/jquery/dist/jquery.js"></script>
+    <script src="bower_components/angular/angular.js"></script>
+    <script src="bower_components/bootstrap/dist/js/bootstrap.js"></script>
+    <script src="bower_components/angular-strap/dist/angular-strap.js"></script>
+    <script src="bower_components/angular-strap/dist/angular-strap.tpl.js"></script>
+    <script src="bower_components/angular-ui-router/release/angular-ui-router.js"></script>
+    <script src="bower_components/angular-animate/angular-animate.js"></script>
+    <script src="bower_components/angular-breadcrumb/release/angular-breadcrumb.js"></script>
+    <script src="bower_components/angular-wizard/dist/angular-wizard.min.js"></script>
+    <script src="bower_components/angular-resource/angular-resource.js"></script>
+    <script src="bower_components/ng-file-upload/ng-file-upload.js"></script>
+    <script src="bower_components/AngularJS-Toaster/toaster.js"></script>
+    <script src="bower_components/ng-dialog/js/ngDialog.js"></script>
+    <script src="bower_components/angularUtils-pagination/dirPagination.js"></script>
+    <script src="bower_components/ngstorage/ngStorage.js"></script>
+    <script src="bower_components/v-accordion/dist/v-accordion.js"></script>
+    <script src="bower_components/spin.js/spin.js"></script>
+    <script src="bower_components/angular-loading/angular-loading.js"></script>
+    <script src="bower_components/spin.js/spin.js"></script>
+    <script src="bower_components/angular-bootstrap/ui-bootstrap-tpls.js"></script>
+    <script src="bower_components/angular-sanitize/angular-sanitize.js"></script>
+    <!-- endbower -->
+    <!-- endbuild -->
+
+    <!-- build:js({.tmp,app}) scripts/scripts.js -->
+    <script src="scripts/app.js"></script>
+    <script src="scripts/router.config.js"></script>
+    <script src="scripts/controllers/main.js"></script>
+    <script src="scripts/factory/main.factory.js"></script>
+    <script src="scripts/controllers/content.controller.js"></script>
+    <script src="scripts/controllers/detail.controller.js"></script>
+    <script src="scripts/controllers/image.controller.js"></script>
+    <script src="scripts/controllers/pod.controller.js"></script>
+    <script src="scripts/controllers/container.controller.js"></script>
+    <script src="scripts/controllers/testcase.controller.js"></script>
+    <script src="scripts/controllers/testcasedetail.controller.js"></script>
+    <script src="scripts/controllers/testsuit.controller.js"></script>
+    <script src="scripts/controllers/suitedetail.controller.js"></script>
+    <script src="scripts/controllers/suitecreate.controller.js"></script>
+    <script src="scripts/controllers/task.controller.js"></script>
+    <script src="scripts/controllers/report.controller.js"></script>
+    <script src="scripts/controllers/project.controller.js"></script>
+    <script src="scripts/controllers/projectDetail.controller.js"></script>
+    <script src="scripts/controllers/taskModify.controller.js"></script>
+
+    <!-- endbuild -->
+</body>
+
+</html>
diff --git a/gui/app/robots.txt b/gui/app/robots.txt
new file mode 100644 (file)
index 0000000..4d521f9
--- /dev/null
@@ -0,0 +1,4 @@
+# robotstxt.org
+
+User-agent: *
+Disallow:
diff --git a/gui/app/scripts/app.js b/gui/app/scripts/app.js
new file mode 100644 (file)
index 0000000..ecb642c
--- /dev/null
@@ -0,0 +1,30 @@
+'use strict';
+
+/**
+ * @ngdoc overview
+ * @name yardStickGui2App
+ * @description
+ * # yardStickGui2App
+ *
+ * Main module of the application.
+ */
+angular
+    .module('yardStickGui2App', [
+        'ui.router',
+        'ngAnimate',
+        'ngSanitize',
+        'mgcrea.ngStrap',
+        'ncy-angular-breadcrumb',
+        'mgo-angular-wizard',
+        'ngResource',
+        'ngFileUpload',
+        'toaster',
+        'ngDialog',
+        'angularUtils.directives.dirPagination',
+        'ngStorage',
+        'vAccordion',
+        'darthwade.dwLoading',
+        'ui.bootstrap'
+
+
+    ]);
diff --git a/gui/app/scripts/controllers/container.controller.js b/gui/app/scripts/controllers/container.controller.js
new file mode 100644 (file)
index 0000000..6c2ccd8
--- /dev/null
@@ -0,0 +1,182 @@
+'use strict';
+
+angular.module('yardStickGui2App')
+    .controller('ContainerController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster', 'ngDialog',
+        function($scope, $state, $stateParams, mainFactory, Upload, toaster, ngDialog) {
+
+
+            init();
+            $scope.showloading = false;
+
+            $scope.displayContainerInfo = [];
+            $scope.containerList = [{ value: 'create_influxdb', name: "InfluxDB" }, { value: 'create_grafana', name: "Grafana" }]
+
+            function init() {
+
+
+                $scope.uuid = $stateParams.uuid;
+                $scope.createContainer = createContainer;
+                $scope.openChooseContainnerDialog = openChooseContainnerDialog;
+
+
+                getItemIdDetail();
+
+            }
+
+            function getItemIdDetail() {
+                $scope.displayContainerInfo = [];
+                mainFactory.ItemDetail().get({
+                    'envId': $scope.uuid
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.envName = response.result.environment.name;
+                        $scope.containerId = response.result.environment.container_id;
+                        if ($scope.containerId != null) {
+
+                            var keysArray = Object.keys($scope.containerId);
+                            for (var k in $scope.containerId) {
+                                getConDetail($scope.containerId[k]);
+                            }
+                        } else {
+                            $scope.podData = null;
+                        }
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function getConDetail(id) {
+                mainFactory.containerDetail().get({
+                    'containerId': id
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        // $scope.podData = response.result;
+                        response.result.container['id'] = id;
+                        $scope.displayContainerInfo.push(response.result.container);
+
+                    }
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+
+            }
+
+            function createContainer() {
+
+                $scope.showloading = true;
+                mainFactory.runAcontainer().post({
+                    'action': $scope.selectContainer.value,
+                    'args': {
+                        'environment_id': $scope.uuid,
+                    }
+                }).$promise.then(function(response) {
+                    $scope.showloading = false;
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'create container success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        setTimeout(function() {
+                            getItemIdDetail();
+                        }, 10000);
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'Wrong',
+                            body: response.error_msg,
+                            timeout: 3000
+                        });
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+
+                })
+            }
+
+            function openChooseContainnerDialog() {
+                ngDialog.open({
+                    template: 'views/modal/chooseContainer.html',
+                    scope: $scope,
+                    className: 'ngdialog-theme-default',
+                    width: 500,
+                    showClose: true,
+                    closeByDocument: false
+                })
+            }
+
+            function chooseResult(name) {
+                $scope.selectContainer = name;
+            }
+            $scope.goBack = function goBack() {
+                $state.go('app2.projectList');
+            }
+
+            $scope.openDeleteEnv = function openDeleteEnv(id, name) {
+                $scope.deleteName = name;
+                $scope.deleteId = id;
+                ngDialog.open({
+                    template: 'views/modal/deleteConfirm.html',
+                    scope: $scope,
+                    className: 'ngdialog-theme-default',
+                    width: 500,
+                    showClose: true,
+                    closeByDocument: false
+                })
+
+            }
+
+            $scope.deleteContainer = function deleteContainer() {
+                mainFactory.deleteContainer().delete({ 'containerId': $scope.deleteId }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'delete container success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        ngDialog.close();
+                        getItemIdDetail();
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'Wrong',
+                            body: response.error_msg,
+                            timeout: 3000
+                        });
+                    }
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+
+
+        }
+    ]);
diff --git a/gui/app/scripts/controllers/content.controller.js b/gui/app/scripts/controllers/content.controller.js
new file mode 100644 (file)
index 0000000..d2bc19e
--- /dev/null
@@ -0,0 +1,136 @@
+'use strict';
+
+angular.module('yardStickGui2App')
+    .controller('ContentController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster', '$location', '$localStorage',
+        function($scope, $state, $stateParams, mainFactory, Upload, toaster, $location, $localStorage) {
+
+
+
+
+            init();
+            $scope.showEnvironment = false;
+            $scope.counldGoDetail = false;
+            $scope.activeStatus = 0;
+
+            $scope.$watch(function() {
+                return location.hash
+            }, function(newvalue, oldvalue) {
+                if (location.hash.indexOf('project') > -1) {
+                    $scope.projectShow = true;
+                    $scope.taskShow = false;
+                    $scope.reportShow = false;
+                } else if (location.hash.indexOf('task') > -1) {
+                    $scope.taskShow = true;
+                    $scope.projectShow = true;
+                } else if (location.hash.indexOf('report') > -1) {
+                    $scope.reportShow = true;
+                    $scope.taskShow = true;
+                    $scope.projectShow = true;
+                }
+
+            })
+
+
+            function init() {
+
+
+                $scope.showEnvironments = showEnvironments;
+                $scope.showSteps = $location.path().indexOf('project');
+                $scope.test = test;
+                $scope.gotoUploadPage = gotoUploadPage;
+                $scope.gotoOpenrcPage = gotoOpenrcPage;
+                $scope.gotoPodPage = gotoPodPage;
+                $scope.gotoContainerPage = gotoContainerPage;
+                $scope.gotoTestcase = gotoTestcase;
+                $scope.gotoEnviron = gotoEnviron;
+                $scope.gotoSuite = gotoSuite;
+                $scope.gotoProject = gotoProject;
+                $scope.gotoTask = gotoTask;
+                $scope.gotoReport = gotoReport;
+                $scope.stepsStatus = $localStorage.stepsStatus;
+                $scope.goBack = goBack;
+
+
+            }
+
+
+
+            function showEnvironments() {
+                $scope.showEnvironment = true;
+            }
+
+            function test() {
+                alert('test');
+            }
+
+            function gotoOpenrcPage() {
+                $scope.path = $location.path();
+                $scope.uuid = $scope.path.split('/').pop();
+                $state.go('app.environmentDetail', { uuid: $scope.uuid })
+            }
+
+            function gotoUploadPage() {
+                $scope.path = $location.path();
+                $scope.uuid = $scope.path.split('/').pop();
+                $state.go('app.uploadImage', { uuid: $scope.uuid });
+            }
+
+            function gotoPodPage() {
+                $scope.path = $location.path();
+                $scope.uuid = $scope.path.split('/').pop();
+                $state.go('app.podUpload', { uuid: $scope.uuid });
+            }
+
+            function gotoContainerPage() {
+                $scope.path = $location.path();
+                $scope.uuid = $scope.path.split('/').pop();
+                $state.go('app.container', { uuid: $scope.uuid });
+            }
+
+            function gotoTestcase() {
+                $state.go('app2.testcase');
+            }
+
+            function gotoEnviron() {
+                if ($location.path().indexOf('env') > -1 || $location.path().indexOf('environment') > -1) {
+                    $scope.counldGoDetail = true;
+                }
+                $state.go('app2.environment');
+            }
+
+            function gotoSuite() {
+                $state.go('app2.testsuite');
+            }
+
+            function gotoProject() {
+                $state.go('app2.projectList');
+            }
+
+            function gotoTask() {
+                $state.go('app2.tasklist');
+            }
+
+            function gotoReport() {
+                $state.go('app2.report');
+            }
+
+            function goBack() {
+                if ($location.path().indexOf('main/environment')) {
+                    return;
+                } else if ($location.path().indexOf('main/envDetail/') || $location.path().indexOf('main/imageDetail/') ||
+                    $location.path().indexOf('main/podupload/') || $location.path().indexOf('main/container/')) {
+                    $state.go('app2.environment');
+                    return;
+                } else {
+                    window.history.back();
+                }
+
+            }
+
+
+
+
+
+
+        }
+    ]);
\ No newline at end of file
diff --git a/gui/app/scripts/controllers/detail.controller.js b/gui/app/scripts/controllers/detail.controller.js
new file mode 100644 (file)
index 0000000..3e2eaa1
--- /dev/null
@@ -0,0 +1,384 @@
+'use strict';
+
+angular.module('yardStickGui2App')
+    .controller('DetailController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster', '$location', 'ngDialog',
+        function($scope, $state, $stateParams, mainFactory, Upload, toaster, $location, ngDialog) {
+
+
+
+
+            init();
+            $scope.showEnvironment = false;
+            $scope.envInfo = [];
+
+            function init() {
+                $scope.showEnvironments = showEnvironments;
+                // $scope.openrcID = $stateParams.uuid;
+                $scope.deleteEnvItem = deleteEnvItem;
+                $scope.addInfo = addInfo;
+                $scope.submitOpenRcFile = submitOpenRcFile;
+                $scope.uploadFiles = uploadFiles;
+                $scope.addEnvironment = addEnvironment;
+
+                $scope.uuid = $stateParams.uuid;
+                $scope.openrcID = $stateParams.opercId;
+                $scope.imageID = $stateParams.imageId;
+                $scope.podID = $stateParams.podId;
+                $scope.containerId = $stateParams.containerId;
+                $scope.ifNew = $stateParams.ifNew;
+
+
+                getItemIdDetail();
+            }
+
+
+
+            function showEnvironments() {
+                $scope.showEnvironment = true;
+            }
+
+
+            function deleteEnvItem(index) {
+                $scope.envInfo.splice(index, 1);
+            }
+
+            function addInfo() {
+                var tempKey = null;
+                var tempValue = null;
+                var temp = {
+                    name: tempKey,
+                    value: tempValue
+                }
+                $scope.envInfo.push(temp);
+
+            }
+
+            function submitOpenRcFile() {
+                $scope.showloading = true;
+
+                var postData = {};
+                postData['action'] = 'update_openrc';
+                rebuildEnvInfo();
+                postData['args'] = {};
+                postData['args']['openrc'] = $scope.postEnvInfo;
+                postData['args']['environment_id'] = $scope.uuid;
+
+
+                mainFactory.postEnvironmentVariable().post(postData).$promise.then(function(response) {
+                    $scope.showloading = false;
+
+                    if (response.status == 1) {
+
+                        $scope.openrcInfo = response.result;
+                        toaster.pop({
+                            type: 'success',
+                            title: 'create success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        $scope.showEnvrionment = true;
+                        getItemIdDetail();
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'faile',
+                            body: response.error_msg,
+                            timeout: 3000
+                        });
+                    }
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            //reconstruc EnvInfo
+            function rebuildEnvInfo() {
+                $scope.postEnvInfo = {};
+                for (var i = 0; i < $scope.envInfo.length; i++) {
+                    $scope.postEnvInfo[$scope.envInfo[i].name] = $scope.envInfo[i].value;
+                }
+
+            }
+
+            //buildtoEnvInfo
+            function buildToEnvInfo(object) {
+                var tempKeyArray = Object.keys(object);
+
+                for (var i = 0; i < tempKeyArray.length; i++) {
+                    var tempkey = tempKeyArray[i];
+                    var tempValue = object[tempKeyArray[i]];
+                    var temp = {
+                        name: tempkey,
+                        value: tempValue
+                    };
+                    $scope.envInfo.push(temp);
+                }
+            }
+
+            function uploadFiles($file, $invalidFiles) {
+                $scope.openrcInfo = {};
+                $scope.loadingOPENrc = true;
+
+                $scope.displayOpenrcFile = $file;
+                timeConstruct($scope.displayOpenrcFile.lastModified);
+                Upload.upload({
+                    url: Base_URL + '/api/v2/yardstick/openrcs',
+                    data: { file: $file, 'environment_id': $scope.uuid, 'action': 'upload_openrc' }
+                }).then(function(response) {
+
+                    $scope.loadingOPENrc = false;
+                    if (response.data.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'upload success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        $scope.openrcInfo = response.data.result;
+                        getItemIdDetail();
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'faile',
+                            body: response.error_msg,
+                            timeout: 3000
+                        });
+                    }
+
+                }, function(error) {
+                    $scope.uploadfile = null;
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function timeConstruct(array) {
+                var date = new Date(1398250549490);
+                var Y = date.getFullYear() + '-';
+                var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
+                var D = date.getDate() + ' ';
+                var h = date.getHours() + ':';
+                var m = date.getMinutes() + ':';
+                var s = date.getSeconds();
+                $scope.filelastModified = Y + M + D + h + m + s;
+
+            }
+
+            function addEnvironment() {
+                mainFactory.addEnvName().post({
+                    'action': 'create_environment',
+                    args: {
+                        'name': $scope.baseElementInfo.name
+                    }
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'create name success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        $scope.uuid = response.result.uuid;
+                        var path = $location.path();
+                        path = path + $scope.uuid;
+                        $location.url(path);
+                        getItemIdDetail();
+                    }
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function getItemIdDetail() {
+
+                mainFactory.ItemDetail().get({
+                    'envId': $scope.uuid
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.baseElementInfo = response.result.environment;
+
+
+                        if ($scope.ifNew != 'true') {
+                            $scope.baseElementInfo = response.result.environment;
+                            if ($scope.baseElementInfo.openrc_id != null) {
+                                getOpenrcDetail($scope.baseElementInfo.openrc_id);
+                            }
+                        }
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'fail',
+                            body: response.error_msg,
+                            timeout: 3000
+                        });
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+
+                })
+            }
+            //getopenRcid
+            function getOpenrcDetail(openrcId) {
+                mainFactory.getEnvironmentDetail().get({
+                    'openrc_id': openrcId
+                }).$promise.then(function(response) {
+                    $scope.openrcInfo = response.result;
+                    buildToEnvInfo($scope.openrcInfo.openrc)
+                }, function(response) {
+
+                })
+            }
+
+
+            //getImgDetail
+            function getImageDetail() {
+                mainFactory.ImageDetail().get({
+                    'image_id': $scope.baseElementInfo.image_id
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.imageDetail = response.result.image;
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            //getPodDetail
+            function getPodDetail() {
+                mainFactory.podDeatil().get({
+                    'podId': $scope.baseElementInfo.pod_id
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.podDetail = response.result.pod;
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+            //getContainerDetail
+            function getPodDetail(containerId) {
+                mainFactory.containerDetail().get({
+                    'containerId': containerId
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.podDetail = response.result.pod;
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'fail',
+                            body: response.error_msg,
+                            timeout: 3000
+                        });
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+            $scope.goBack = function goBack() {
+                window.history.back();
+            }
+
+            $scope.goNext = function goNext() {
+                $scope.path = $location.path();
+                $scope.uuid = $scope.path.split('/').pop();
+                $state.go('app.uploadImage', { uuid: $scope.uuid });
+            }
+
+            $scope.openDeleteEnv = function openDeleteEnv(id, name) {
+                $scope.deleteName = name;
+                $scope.deleteId = id;
+                ngDialog.open({
+                    template: 'views/modal/deleteConfirm.html',
+                    scope: $scope,
+                    className: 'ngdialog-theme-default',
+                    width: 500,
+                    showClose: true,
+                    closeByDocument: false
+                })
+
+            }
+
+            $scope.deleteOpenRc = function deleteOpenRc() {
+                mainFactory.deleteOpenrc().delete({ 'openrc': $scope.baseElementInfo.openrc_id }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'delete openrc success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        ngDialog.close();
+                        getItemIdDetail();
+                        $scope.openrcInfo = null;
+                        $scope.envInfo = [];
+                        $scope.displayOpenrcFile = null;
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'Wrong',
+                            body: response.result,
+                            timeout: 3000
+                        });
+                    }
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+
+
+
+
+
+
+
+
+        }
+
+
+    ]);
diff --git a/gui/app/scripts/controllers/image.controller.js b/gui/app/scripts/controllers/image.controller.js
new file mode 100644 (file)
index 0000000..53acff4
--- /dev/null
@@ -0,0 +1,166 @@
+'use strict';
+
+angular.module('yardStickGui2App')
+    .controller('ImageController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster', '$location', '$interval',
+        function($scope, $state, $stateParams, mainFactory, Upload, toaster, $location, $interval) {
+
+
+            init();
+            $scope.showloading = false;
+            $scope.ifshowStatus = 0;
+
+            function init() {
+
+
+                $scope.uuid = $stateParams.uuid;
+                $scope.uploadImage = uploadImage;
+                getItemIdDetail();
+                getImageListSimple();
+            }
+
+            function getItemIdDetail() {
+                mainFactory.ItemDetail().get({
+                    'envId': $stateParams.uuid
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.baseElementInfo = response.result.environment;
+
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'fail',
+                            body: response.error_msg,
+                            timeout: 3000
+                        });
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function getImageListSimple() {
+
+                mainFactory.ImageList().get({}).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.imageListData = response.result.images;
+                        // $scope.imageStatus = response.result.status;
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'get data failed',
+                            body: 'please retry',
+                            timeout: 3000
+                        });
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'get data failed',
+                        body: 'please retry',
+                        timeout: 3000
+                    });
+                })
+            }
+
+
+            function getImageList() {
+                if ($scope.intervalImgae != undefined) {
+                    $interval.cancel($scope.intervalImgae);
+                }
+                mainFactory.ImageList().get({}).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.imageListData = response.result.images;
+                        $scope.imageStatus = response.result.status;
+
+                        if ($scope.imageStatus == 0) {
+                            $scope.intervalImgae = $interval(function() {
+                                getImageList();
+                            }, 5000);
+                        } else if ($scope.intervalImgae != undefined) {
+                            $interval.cancel($scope.intervalImgae);
+                        }
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'get data failed',
+                            body: 'please retry',
+                            timeout: 3000
+                        });
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'get data failed',
+                        body: 'please retry',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function uploadImage() {
+                $scope.imageStatus = 0;
+                $interval.cancel($scope.intervalImgae);
+                $scope.ifshowStatus = 1;
+                $scope.showloading = true;
+                mainFactory.uploadImage().post({
+                    'action': 'load_image',
+                    'args': {
+                        'environment_id': $scope.uuid
+
+                    }
+                }).$promise.then(function(response) {
+                    $scope.showloading = false;
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'create success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        setTimeout(function() {
+                            getImageList();
+                        }, 10000);
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'failed',
+                            body: 'something wrong',
+                            timeout: 3000
+                        });
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'failed',
+                        body: 'something wrong',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            $scope.goBack = function goBack() {
+                $state.go('app2.projectList');
+            }
+
+            $scope.goNext = function goNext() {
+                $scope.path = $location.path();
+                $scope.uuid = $scope.path.split('/').pop();
+                $state.go('app.podUpload', { uuid: $scope.uuid });
+            }
+
+
+
+
+
+        }
+    ]);
diff --git a/gui/app/scripts/controllers/main.js b/gui/app/scripts/controllers/main.js
new file mode 100644 (file)
index 0000000..e3e880e
--- /dev/null
@@ -0,0 +1,725 @@
+'use strict';
+
+angular.module('yardStickGui2App')
+    .controller('MainCtrl', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster', 'ngDialog', '$localStorage', '$loading', '$interval',
+        function($scope, $state, $stateParams, mainFactory, Upload, toaster, ngDialog, $localStorage, $loading, $interval) {
+
+
+            init();
+            $scope.project = 0;
+            $scope.showloading = false;
+            $scope.showEnvrionment = false;
+            $scope.loadingOPENrc = false;
+            $scope.uuidEnv = null;
+            $scope.showPod = null;
+            $scope.showImage = null;
+            $scope.showContainer = null;
+            $scope.showNextOpenRc = null;
+            $scope.showNextPod = null;
+            $scope.displayContainerInfo = [];
+            $scope.containerList = [{ value: 'create_influxdb', name: "InfluxDB" }, { value: 'create_grafana', name: "Grafana" }]
+            $scope.items = [
+                'The first choice!',
+                'And another choice for you.',
+                'but wait! A third!'
+            ];
+            $scope.$on('$destroy', function() {
+                $interval.cancel($scope.intervalImgae)
+            });
+            $scope.showImageStatus = 0;
+
+
+
+
+
+
+            function init() {
+
+
+                $scope.gotoProject = gotoProject;
+                $scope.gotoEnvironment = gotoEnvironment;
+                $scope.gotoTask = gotoTask;
+                $scope.gotoExcute = gotoExcute;
+                $scope.gotoReport = gotoReport;
+                $scope.deleteEnvItem = deleteEnvItem;
+                $scope.addInfo = addInfo;
+                $scope.submitOpenRcFile = submitOpenRcFile;
+                $scope.uploadFilesPod = uploadFilesPod;
+                $scope.uploadFiles = uploadFiles;
+                $scope.showEnvriomentStatus = showEnvriomentStatus;
+                $scope.openEnvironmentDialog = openEnvironmentDialog;
+                $scope.getEnvironmentList = getEnvironmentList;
+                $scope.gotoDetail = gotoDetail;
+                $scope.addEnvironment = addEnvironment;
+                $scope.createContainer = createContainer;
+                $scope.chooseResult = chooseResult;
+
+                getEnvironmentList();
+                // getImageList();
+
+            }
+
+            function gotoProject() {
+                $scope.project = 1;
+            }
+
+            function gotoEnvironment() {
+                $scope.project = 0;
+            }
+
+            function gotoTask() {
+                $scope.project = 2;
+            }
+
+            function gotoExcute() {
+                $scope.project = 3;
+
+            }
+
+            function gotoReport() {
+                $scope.project = 4;
+            }
+            $scope.skipPod = function skipPod() {
+                $scope.showContainer = 1;
+
+            }
+            $scope.skipContainer = function skipContainer() {
+                getEnvironmentList();
+                ngDialog.close();
+            }
+
+            $scope.goToImage = function goToImage() {
+                getImageListSimple();
+                $scope.showImage = 1;
+            }
+            $scope.goToPod = function goToPod() {
+                $scope.showPod = 1;
+            }
+            $scope.goToPodPrev = function goToPodPrev() {
+                $scope.showImage = null;
+
+            }
+            $scope.skipPodPrev = function skipPodPrev() {
+                $scope.showImage = 1;
+                $scope.showPod = null;
+
+            }
+            $scope.skipContainerPrev = function skipContainerPrev() {
+                $scope.showPod = 1;
+                $scope.showContainer = null;
+            }
+
+            $scope.envInfo = [
+                { name: 'OS_USERNAME', value: '' },
+                { name: 'OS_PASSWORD', value: '' },
+                { name: 'OS_TENANT_NAME', value: '' },
+                { name: 'EXTERNAL_NETWORK', value: '' }
+            ];
+
+
+            function deleteEnvItem(index) {
+                $scope.envInfo.splice(index, 1);
+            }
+
+            function addInfo() {
+                var tempKey = null;
+                var tempValue = null;
+                var temp = {
+                    name: tempKey,
+                    value: tempValue
+                }
+                $scope.envInfo.push(temp);
+
+            }
+
+            function submitOpenRcFile() {
+                $scope.showloading = true;
+
+                var postData = {};
+                postData['action'] = 'update_openrc';
+                rebuildEnvInfo();
+                postData['args'] = {};
+                postData.args["openrc"] = $scope.postEnvInfo;
+                postData.args['environment_id'] = $scope.uuidEnv;
+                mainFactory.postEnvironmentVariable().post(postData).$promise.then(function(response) {
+                    $scope.showloading = false;
+
+                    if (response.status == 1) {
+
+                        $scope.openrcInfo = response.result;
+                        toaster.pop({
+                            type: 'success',
+                            title: 'create success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        $scope.showEnvrionment = true;
+                        // $scope.showImage = response.status;
+                        $scope.showNextOpenRc = 1;
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'fail',
+                            body: response.error_msg,
+                            timeout: 3000
+                        });
+                    }
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+
+                })
+            }
+
+            function uploadFiles($file, $invalidFiles) {
+                $scope.openrcInfo = {};
+                $scope.loadingOPENrc = true;
+                $scope.displayOpenrcFile = $file;
+                timeConstruct($scope.displayOpenrcFile.lastModified);
+                Upload.upload({
+                    url: Base_URL + '/api/v2/yardstick/openrcs',
+                    data: { file: $file, 'environment_id': $scope.uuidEnv, 'action': 'upload_openrc' }
+                }).then(function(response) {
+
+                    $scope.loadingOPENrc = false;
+                    if (response.data.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'upload success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        $scope.openrcInfo = response.data.result;
+
+                        getItemIdDetailforOpenrc();
+                        $scope.showNextOpenRc = 1;
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'fail',
+                            body: response.error_msg,
+                            timeout: 3000
+                        });
+                    }
+
+                }, function(error) {
+                    $scope.uploadfile = null;
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            //reconstruc EnvInfo
+            function rebuildEnvInfo() {
+                $scope.postEnvInfo = {};
+                for (var i = 0; i < $scope.envInfo.length; i++) {
+                    $scope.postEnvInfo[$scope.envInfo[i].name] = $scope.envInfo[i].value;
+                }
+
+            }
+            function uploadFilesPod($file, $invalidFiles) {
+                $scope.loadingOPENrc = true;
+
+                $scope.displayPodFile = $file;
+                timeConstruct($scope.displayPodFile.lastModified);
+                Upload.upload({
+                    url: Base_URL + '/api/v2/yardstick/pods',
+                    data: { file: $file, 'environment_id': $scope.uuidEnv, 'action': 'upload_pod_file' }
+                }).then(function(response) {
+
+                    $scope.loadingOPENrc = false;
+                    if (response.data.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'upload success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+
+                        $scope.podData = response.data.result;
+
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'fail',
+                            body: response.error_msg,
+                            timeout: 3000
+                        });
+                    }
+
+                }, function(error) {
+                    $scope.uploadfile = null;
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function timeConstruct(array) {
+                var date = new Date(1398250549490);
+                var Y = date.getFullYear() + '-';
+                var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
+                var D = date.getDate() + ' ';
+                var h = date.getHours() + ':';
+                var m = date.getMinutes() + ':';
+                var s = date.getSeconds();
+                $scope.filelastModified = Y + M + D + h + m + s;
+
+            }
+
+            //display environment
+            function showEnvriomentStatus() {
+                $scope.showEnvironment = true;
+            }
+
+            //open Environment dialog
+            function openEnvironmentDialog() {
+                $scope.showEnvrionment = false;
+                $scope.loadingOPENrc = false;
+                $scope.uuidEnv = null;
+                $scope.showPod = null;
+                $scope.showImage = null;
+                $scope.showContainer = null;
+                $scope.showNextOpenRc = null;
+                $scope.showNextPod = null;
+                $scope.displayContainerInfo = [];
+
+                $scope.displayPodFile = null;
+                $scope.name = null;
+                $scope.openrcInfo = null;
+                $scope.envInfo = [
+                    { name: 'OS_USERNAME', value: '' },
+                    { name: 'OS_PASSWORD', value: '' },
+                    { name: 'OS_TENANT_NAME', value: '' },
+                    { name: 'EXTERNAL_NETWORK', value: '' }
+                ];
+                $scope.displayOpenrcFile = null;
+                $scope.podData = null;
+                $scope.displayContainerInfo = null;
+                ngDialog.open({
+                    preCloseCallback: function(value) {
+                        getEnvironmentList();
+                        // getImageList();
+                    },
+                    template: 'views/modal/environmentDialog.html',
+                    scope: $scope,
+                    className: 'ngdialog-theme-default',
+                    width: 950,
+                    showClose: true,
+                    closeByDocument: false
+                })
+            }
+
+            function getEnvironmentList() {
+                $loading.start('key');
+
+                mainFactory.getEnvironmentList().get().$promise.then(function(response) {
+                    $scope.environmentList = response.result.environments;
+                    $loading.finish('key');
+
+                }, function(error) {
+                    $loading.finish('key');
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+
+                })
+            }
+
+            //go to detail page
+            function gotoDetail(ifNew, uuid) {
+
+                $state.go('app.environmentDetail', { uuid: uuid, ifNew: ifNew });
+            }
+
+
+            function addEnvironment(name) {
+                mainFactory.addEnvName().post({
+                    'action': 'create_environment',
+                    args: {
+                        'name': name
+                    }
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'create name success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        $scope.uuidEnv = response.result.uuid;
+                        $scope.name = name;
+
+                    }
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+
+
+            $scope.goBack = function goBack() {
+                    $state.go('app2.projectList');
+                }
+            $scope.displayContainerInfo = [];
+
+            function createContainer(selectContainer) {
+
+                $scope.showloading = true;
+                mainFactory.runAcontainer().post({
+                    'action': selectContainer.value,
+                    'args': {
+                        'environment_id': $scope.uuidEnv,
+                    }
+                }).$promise.then(function(response) {
+                    $scope.showloading = false;
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'create container success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+
+                        setTimeout(function() {
+                            getItemIdDetail();
+                        }, 10000);
+                        $scope.ifskipOrClose = 1;
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'Wrong',
+                            body: response.result,
+                            timeout: 3000
+                        });
+                    }
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function getConDetail(id) {
+                mainFactory.containerDetail().get({
+                    'containerId': id
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        // $scope.podData = response.result;
+                        $scope.displayContainerInfo.push(response.result.container);
+
+                    }
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+
+            }
+
+            function chooseResult(name) {
+                $scope.selectContainer = name;
+            }
+
+            function getItemIdDetail() {
+                $scope.displayContainerInfo = [];
+                mainFactory.ItemDetail().get({
+                    'envId': $scope.uuidEnv
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.envName = response.result.environment.name;
+                        $scope.containerId = response.result.environment.container_id;
+                        if ($scope.containerId != null) {
+
+                            var keysArray = Object.keys($scope.containerId);
+                            for (var k in $scope.containerId) {
+                                getConDetail($scope.containerId[k]);
+
+                            }
+
+
+                        } else {
+                            $scope.podData = null;
+                        }
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            $scope.uploadImage = function uploadImage() {
+                $scope.imageStatus = 0;
+                $scope.showImageStatus = 1;
+                $scope.showloading = true;
+                mainFactory.uploadImage().post({
+                    'action': 'load_image',
+                    'args': {
+                        'environment_id': $scope.uuid
+
+                    }
+                }).$promise.then(function(response) {
+                    $scope.showloading = false;
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'create success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        setTimeout(function() {
+                            getImageList();
+                        }, 10000);
+                        $scope.showNextPod = 1;
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'failed',
+                            body: 'something wrong',
+                            timeout: 3000
+                        });
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'failed',
+                        body: 'something wrong',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function getImageList() {
+                if ($scope.intervalImgae != undefined) {
+                    $interval.cancel($scope.intervalImgae);
+                }
+                mainFactory.ImageList().get({}).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.imageListData = response.result.images;
+                        $scope.imageStatus = response.result.status;
+
+                        if ($scope.imageStatus == 0) {
+                            $scope.intervalImgae = $interval(function() {
+                                getImageList();
+                            }, 5000);
+                        } else if ($scope.intervalImgae != undefined) {
+                            $interval.cancel($scope.intervalImgae);
+                        }
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'get data failed',
+                            body: 'please retry',
+                            timeout: 3000
+                        });
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'get data failed',
+                        body: 'please retry',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function getImageListSimple() {
+
+                mainFactory.ImageList().get({}).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.imageListData = response.result.images;
+                        $scope.imageStatus = response.result.status;
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'get data failed',
+                            body: 'please retry',
+                            timeout: 3000
+                        });
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'get data failed',
+                        body: 'please retry',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            $scope.openDeleteEnv = function openDeleteEnv(id, name) {
+                $scope.deleteName = name;
+                $scope.deleteId = id;
+                ngDialog.open({
+                    template: 'views/modal/deleteConfirm.html',
+                    scope: $scope,
+                    className: 'ngdialog-theme-default',
+                    width: 500,
+                    showClose: true,
+                    closeByDocument: false
+                })
+
+            }
+
+            $scope.deleteEnv = function deleteEnv() {
+                mainFactory.deleteEnv().delete({ 'env_id': $scope.deleteId }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'delete environment success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        ngDialog.close();
+                        getEnvironmentList();
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'Wrong',
+                            body: response.result,
+                            timeout: 3000
+                        });
+                    }
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+
+
+
+
+
+            function getItemIdDetailforOpenrc() {
+
+                mainFactory.ItemDetail().get({
+                    'envId': $scope.uuidEnv
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.baseElementInfo = response.result.environment;
+
+
+                        if ($scope.ifNew != 'true') {
+                            $scope.baseElementInfo = response.result.environment;
+                            if ($scope.baseElementInfo.openrc_id != null) {
+                                getOpenrcDetailForOpenrc($scope.baseElementInfo.openrc_id);
+                            }
+                        }
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'fail',
+                            body: response.error_msg,
+                            timeout: 3000
+                        });
+
+                    }
+                }, function(error) {
+
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+
+                })
+            }
+
+
+
+            //getopenRcid
+            function getOpenrcDetailForOpenrc(openrcId) {
+                mainFactory.getEnvironmentDetail().get({
+                    'openrc_id': openrcId
+                }).$promise.then(function(response) {
+                    $scope.openrcInfo = response.result;
+                    buildToEnvInfoOpenrc($scope.openrcInfo.openrc)
+                }, function(response) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'error',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            //buildtoEnvInfo
+            function buildToEnvInfoOpenrc(object) {
+                var tempKeyArray = Object.keys(object);
+                $scope.envInfo = [];
+
+
+                for (var i = 0; i < tempKeyArray.length; i++) {
+                    var tempkey = tempKeyArray[i];
+                    var tempValue = object[tempKeyArray[i]];
+                    var temp = {
+                        name: tempkey,
+                        value: tempValue
+                    };
+                    $scope.envInfo.push(temp);
+                }
+            }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        }
+    ]);
diff --git a/gui/app/scripts/controllers/pod.controller.js b/gui/app/scripts/controllers/pod.controller.js
new file mode 100644 (file)
index 0000000..3ef2368
--- /dev/null
@@ -0,0 +1,179 @@
+'use strict';
+
+angular.module('yardStickGui2App')
+    .controller('PodController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster', '$location', 'ngDialog',
+        function($scope, $state, $stateParams, mainFactory, Upload, toaster, $location, ngDialog) {
+
+
+            init();
+            $scope.showloading = false;
+            $scope.loadingOPENrc = false;
+
+            function init() {
+
+
+                $scope.uuid = $stateParams.uuid;
+                $scope.uploadFiles = uploadFiles;
+                getItemIdDetail();
+
+            }
+
+            function getItemIdDetail() {
+                mainFactory.ItemDetail().get({
+                    'envId': $scope.uuid
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.name = response.result.environment.name;
+                        $scope.podId = response.result.environment.pod_id;
+                        if ($scope.podId != null) {
+                            getPodDetail($scope.podId);
+                        } else {
+                            $scope.podData = null;
+                        }
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function getPodDetail(id) {
+                mainFactory.getPodDetail().get({
+                    'podId': id
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.podData = response.result;
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+
+            }
+
+            //upload pod file
+            function uploadFiles($file, $invalidFiles) {
+                $scope.loadingOPENrc = true;
+
+                $scope.displayOpenrcFile = $file;
+                timeConstruct($scope.displayOpenrcFile.lastModified);
+                Upload.upload({
+                    url: Base_URL + '/api/v2/yardstick/pods',
+                    data: { file: $file, 'environment_id': $scope.uuid, 'action': 'upload_pod_file' }
+                }).then(function(response) {
+
+                    $scope.loadingOPENrc = false;
+                    if (response.data.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'upload success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+
+                        $scope.podData = response.data.result;
+
+                        getItemIdDetail();
+
+
+                    } else {
+
+                    }
+
+                }, function(error) {
+                    $scope.uploadfile = null;
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function timeConstruct(array) {
+                var date = new Date(1398250549490);
+                var Y = date.getFullYear() + '-';
+                var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
+                var D = date.getDate() + ' ';
+                var h = date.getHours() + ':';
+                var m = date.getMinutes() + ':';
+                var s = date.getSeconds();
+                $scope.filelastModified = Y + M + D + h + m + s;
+
+            }
+            $scope.goBack = function goBack() {
+                $state.go('app2.projectList');
+            }
+
+
+            $scope.goNext = function goNext() {
+                $scope.path = $location.path();
+                $scope.uuid = $scope.path.split('/').pop();
+                $state.go('app.container', { uuid: $scope.uuid });
+            }
+
+            $scope.openDeleteEnv = function openDeleteEnv(id, name) {
+                $scope.deleteName = name;
+                $scope.deleteId = id;
+                ngDialog.open({
+                    template: 'views/modal/deleteConfirm.html',
+                    scope: $scope,
+                    className: 'ngdialog-theme-default',
+                    width: 500,
+                    showClose: true,
+                    closeByDocument: false
+                })
+
+            }
+
+            $scope.deletePod = function deletePod() {
+                mainFactory.deletePod().delete({ 'podId': $scope.podId }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'delete pod success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        ngDialog.close();
+                        $scope.uuid = $stateParams.uuid;
+                        $scope.uploadFiles = uploadFiles;
+                        $scope.displayOpenrcFile = null;
+                        getItemIdDetail();
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'Wrong',
+                            body: response.result,
+                            timeout: 3000
+                        });
+                    }
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+
+                })
+            }
+
+
+
+
+
+        }
+    ]);
\ No newline at end of file
diff --git a/gui/app/scripts/controllers/project.controller.js b/gui/app/scripts/controllers/project.controller.js
new file mode 100644 (file)
index 0000000..0a7b8b9
--- /dev/null
@@ -0,0 +1,160 @@
+'use strict';
+
+angular.module('yardStickGui2App')
+    .controller('ProjectController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster', 'ngDialog', '$loading',
+        function($scope, $state, $stateParams, mainFactory, Upload, toaster, ngDialog, $loading) {
+
+
+            init();
+
+
+            function init() {
+
+
+                getProjectList();
+                $scope.openCreateProject = openCreateProject;
+                $scope.createName = createName;
+                $scope.gotoDetail = gotoDetail;
+
+
+            }
+
+            function getProjectList() {
+                $loading.start('key');
+                mainFactory.projectList().get({}).$promise.then(function(response) {
+                    $loading.finish('key');
+                    if (response.status == 1) {
+                        $scope.projectListData = response.result.projects;
+
+
+                    } else {
+
+                    }
+                }, function(error) {
+                    $loading.finish('key');
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+
+                })
+            }
+
+            function openCreateProject() {
+
+                ngDialog.open({
+                    template: 'views/modal/projectCreate.html',
+                    scope: $scope,
+                    className: 'ngdialog-theme-default',
+                    width: 400,
+                    showClose: true,
+                    closeByDocument: false
+                })
+            }
+
+            function createName(name) {
+
+                mainFactory.createProjectName().post({
+                    'action': 'create_project',
+                    'args': {
+                        'name': name,
+                    }
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'create project success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        ngDialog.close();
+                        getProjectList();
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'failed',
+                            body: 'create project failed',
+                            timeout: 3000
+                        });
+                    }
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'failed',
+                        body: 'Something Wrong',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function gotoDetail(id) {
+                $state.go('app2.projectdetail', { projectId: id })
+            }
+
+
+            $scope.openDeleteEnv = function openDeleteEnv(id, name) {
+                $scope.deleteName = name;
+                $scope.deleteId = id;
+                ngDialog.open({
+                    template: 'views/modal/deleteConfirm.html',
+                    scope: $scope,
+                    className: 'ngdialog-theme-default',
+                    width: 500,
+                    showClose: true,
+                    closeByDocument: false
+                })
+
+            }
+
+            $scope.deleteProject = function deleteProject() {
+                mainFactory.deleteProject().delete({ 'project_id': $scope.deleteId }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'delete Project success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        ngDialog.close();
+                        getProjectList();
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'Wrong',
+                            body: response.result,
+                            timeout: 3000
+                        });
+                    }
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+
+                })
+            }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        }
+    ]);
diff --git a/gui/app/scripts/controllers/projectDetail.controller.js b/gui/app/scripts/controllers/projectDetail.controller.js
new file mode 100644 (file)
index 0000000..4ab4a05
--- /dev/null
@@ -0,0 +1,690 @@
+'use strict';
+
+angular.module('yardStickGui2App')
+    .controller('ProjectDetailController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster', 'ngDialog', '$localStorage', '$loading', '$interval',
+        function($scope, $state, $stateParams, mainFactory, Upload, toaster, ngDialog, $localStorage, $loading, $interval) {
+
+
+            init();
+            // $scope.taskListDisplay = [];
+            $scope.blisterPackTemplates = [{ id: 1, name: "Test Case" }, { id: 2, name: "Test Suite" }]
+            $scope.selectType = null;
+            $scope.ifHasEnv = false;
+            $scope.ifHasCase = false;
+            $scope.ifHasSuite = false;
+            $scope.$on('$destroy', function() {
+                $interval.cancel($scope.intervalCount)
+            });
+            $scope.finalTaskListDisplay = [];
+
+
+            function init() {
+
+
+                getProjectDetail();
+
+                $scope.openCreate = openCreate;
+                $scope.createTask = createTask;
+                $scope.constructTestSuit = constructTestSuit;
+                $scope.addEnvToTask = addEnvToTask;
+                $scope.triggerContent = triggerContent;
+                $scope.constructTestCase = constructTestCase;
+                $scope.getTestDeatil = getTestDeatil;
+                $scope.confirmAddCaseOrSuite = confirmAddCaseOrSuite;
+                $scope.runAtask = runAtask;
+                $scope.gotoDetail = gotoDetail;
+                $scope.gotoReport = gotoReport;
+                $scope.gotoModify = gotoModify;
+                $scope.goBack = goBack;
+                $scope.goToExternal = goToExternal;
+
+
+            }
+
+            function getProjectDetail() {
+                if ($scope.intervalCount != undefined) {
+                    $interval.cancel($scope.intervalCount);
+                }
+                $loading.start('key');
+                $scope.taskListDisplay = [];
+                $scope.finalTaskListDisplay = [];
+                mainFactory.getProjectDetail().get({
+                    project_id: $stateParams.projectId
+                }).$promise.then(function(response) {
+                    $loading.finish('key');
+                    if (response.status == 1) {
+
+                        $scope.projectData = response.result.project;
+                        if ($scope.projectData.tasks.length != 0) {
+
+
+                            for (var i = 0; i < $scope.projectData.tasks.length; i++) {
+                                getDetailTaskForList($scope.projectData.tasks[i]);
+                            }
+                            $scope.intervalCount = $interval(function() {
+                                getDetailForEachTask();
+                            }, 10000);
+                        } else {
+
+                            if ($scope.intervalCount != undefined) {
+                                $interval.cancel($scope.intervalCount);
+                            }
+                        }
+                    } else {
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+
+                })
+            }
+
+            // function getProjectDetailSimple() {
+            //     getDetailForEachTask();
+            // }
+
+            function openCreate() {
+                $scope.newUUID = null;
+                $scope.displayEnvName = null;
+                $scope.selectEnv = null;
+                $scope.selectCase = null;
+                $scope.selectType = null;
+                $scope.contentInfo = null;
+                $scope.ifHasEnv = false;
+                $scope.ifHasCase = false;
+                $scope.ifHasSuite = false;
+
+                // getEnvironmentList();
+                $scope.selectEnv = null;
+                ngDialog.open({
+                    template: 'views/modal/taskCreate.html',
+                    scope: $scope,
+                    className: 'ngdialog-theme-default',
+                    width: 800,
+                    showClose: true,
+                    closeByDocument: false,
+                    preCloseCallback: function(value) {
+                        getProjectDetail();
+                    },
+                })
+            }
+
+            function createTask(name) {
+                mainFactory.createTask().post({
+                    'action': 'create_task',
+                    'args': {
+                        'name': name,
+                        'project_id': $stateParams.projectId
+                    }
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'create task success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        $scope.newUUID = response.result.uuid;
+                        getEnvironmentList();
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'create task wrong',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                    }
+
+
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'create task wrong',
+                        body: 'you can go next step',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function getDetailTaskForList(id) {
+
+                mainFactory.getTaskDetail().get({
+                    'taskId': id
+                }).$promise.then(function(response) {
+
+                    if (response.status == 1) {
+                        if (response.result.task.status == -1) {
+                            response.result.task['stausWidth'] = '5%';
+                        } else if (response.result.task.status == 0) {
+                            response.result.task['stausWidth'] = '50%';
+                        } else if (response.result.task.status == 1) {
+                            response.result.task['stausWidth'] = '100%';
+                        } else if (response.result.task.status == 2) {
+                            response.result.task['stausWidth'] = 'red';
+                        }
+                        $scope.taskListDisplay.push(response.result.task);
+                        console.log($scope.taskListDisplay);
+
+                        $scope.finalTaskListDisplay = $scope.taskListDisplay;
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+
+                })
+            }
+
+            function getDetailTaskForListSimple(id, index) {
+
+                mainFactory.getTaskDetail().get({
+                    'taskId': id
+                }).$promise.then(function(response) {
+
+                    if (response.status == 1) {
+                        if (response.result.task.status == -1) {
+
+                            $scope.finalTaskListDisplay[index].stausWidth = '5%';
+                            $scope.finalTaskListDisplay[index].status = response.result.task.status;
+                        } else if (response.result.task.status == 0) {
+
+                            $scope.finalTaskListDisplay[index].stausWidth = '50%';
+                            $scope.finalTaskListDisplay[index].status = response.result.task.status;
+                        } else if (response.result.task.status == 1) {
+
+                            $scope.finalTaskListDisplay[index].stausWidth = '100%';
+                            $scope.finalTaskListDisplay[index].status = response.result.task.status;
+                        } else if (response.result.task.status == 2) {
+
+                            $scope.finalTaskListDisplay[index].stausWidth = 'red';
+                            $scope.finalTaskListDisplay[index].status = response.result.task.status;
+                        }
+
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+
+                })
+            }
+
+            function getDetailForEachTask() {
+                for (var i = 0; i < $scope.finalTaskListDisplay.length; i++) {
+                    if ($scope.finalTaskListDisplay[i].status != 1 && $scope.finalTaskListDisplay[i].status != -1) {
+                        getDetailTaskForListSimple($scope.finalTaskListDisplay[i].uuid, i);
+                    }
+                }
+            }
+
+            function getEnvironmentList() {
+                mainFactory.getEnvironmentList().get().$promise.then(function(response) {
+                    $scope.environmentList = response.result.environments;
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+
+                })
+            }
+
+            function constructTestSuit(id, name) {
+                $scope.displayEnvName = name;
+                $scope.selectEnv = id;
+
+            }
+
+            function constructTestCase(name) {
+
+                $scope.selectCase = name;
+                if ($scope.selectType.name == 'Test Case') {
+                    getCaseInfo();
+                } else {
+                    getSuiteInfo();
+                }
+
+            }
+
+
+
+
+            function addEnvToTask() {
+                mainFactory.taskAddEnv().put({
+                    'taskId': $scope.newUUID,
+                    'action': 'add_environment',
+                    'args': {
+                        'task_id': $scope.newUUID,
+                        'environment_id': $scope.selectEnv
+                    }
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'add environment success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        $scope.ifHasEnv = true;
+
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'create task wrong',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                    }
+
+
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'create task wrong',
+                        body: 'you can go next step',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function triggerContent(name) {
+                $scope.selectCase = null;
+                $scope.displayTable = true;
+
+                $scope.selectType = name;
+                if (name.name == 'Test Case') {
+                    getTestcaseList();
+                } else if (name.name == 'Test Suite') {
+                    getsuiteList();
+                }
+            }
+
+            function getTestcaseList() {
+                mainFactory.getTestcaselist().get({
+
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.testcaselist = response.result;
+
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function getsuiteList() {
+                mainFactory.suiteList().get({
+
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.testsuitlist = response.result.testsuites;
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function getTestDeatil() {
+
+
+                if ($scope.selectType.name == 'Test Case') {
+                    getTestcaseDetail();
+                } else {
+                    getSuiteDetail();
+                }
+
+            }
+
+            function getCaseInfo() {
+
+
+
+                mainFactory.getTestcaseDetail().get({
+                    'testcasename': $scope.selectCase
+
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+
+                        $scope.contentInfo = response.result.testcase;
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function getSuiteInfo() {
+                mainFactory.suiteDetail().get({
+                    'suiteName': $scope.selectCase.split('.')[0]
+
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.contentInfo = response.result.testsuite;
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+
+            function getSuiteDetail() {
+                mainFactory.suiteDetail().get({
+                    'suiteName': $scope.selectCase.split('.')[0]
+
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.displayTable = false;
+                        $scope.contentInfo = response.result.testsuite;
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+
+            function getTestcaseDetail() {
+                mainFactory.getTestcaseDetail().get({
+                    'testcasename': $scope.selectCase
+
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+
+                        $scope.displayTable = false;
+                        $scope.contentInfo = response.result.testcase;
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function addCasetoTask(content) {
+                mainFactory.taskAddEnv().put({
+                    'taskId': $scope.newUUID,
+                    'action': 'add_case',
+                    'args': {
+                        'task_id': $scope.newUUID,
+                        'case_name': $scope.selectCase,
+                        'case_content': content
+                    }
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'add test case success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        $scope.ifHasCase = true;
+
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'create task wrong',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'create task wrong',
+                        body: 'you can go next step',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function addSuitetoTask(content) {
+                mainFactory.taskAddEnv().put({
+                    'taskId': $scope.newUUID,
+                    'action': 'add_suite',
+                    'args': {
+                        'task_id': $scope.newUUID,
+                        'suite_name': $scope.selectCase.split('.')[0],
+                        'suite_content': content
+                    }
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'add test suite success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        $scope.ifHasSuite = true;
+
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'create task wrong',
+                            body: 'wrong',
+                            timeout: 3000
+                        });
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'create task wrong',
+                        body: 'something wrong',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function confirmAddCaseOrSuite(content) {
+                if ($scope.selectType.name == "Test Case") {
+                    addCasetoTask(content);
+                } else {
+                    addSuitetoTask(content);
+                }
+            }
+
+            function runAtask(id) {
+                mainFactory.taskAddEnv().put({
+                    'taskId': id,
+                    'action': 'run',
+                    'args': {
+                        'task_id': id
+                    }
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'run a task success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        ngDialog.close();
+                        // getProjectDetail();
+                    } else {
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+
+                })
+            }
+
+            $scope.runAtaskForTable = function runAtaskForTable(id) {
+                mainFactory.taskAddEnv().put({
+                    'taskId': id,
+                    'action': 'run',
+                    'args': {
+                        'task_id': id
+                    }
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        // toaster.pop({
+                        //     type: 'success',
+                        //     title: 'run a task success',
+                        //     body: 'you can go next step',
+                        //     timeout: 3000
+                        // });
+                        // ngDialog.close();
+                        getProjectDetail();
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'fail',
+                            body: response.result,
+                            timeout: 3000
+                        });
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+
+                })
+            }
+
+            function gotoDetail(id) {
+
+
+                $state.go('app2.tasklist', { taskId: id });
+
+            }
+
+            function gotoReport(id) {
+                $state.go('app2.report', { taskId: id });
+            }
+
+            function gotoModify(id) {
+                $state.go('app2.taskModify', { taskId: id });
+            }
+
+            function goBack() {
+                window.history.back();
+            }
+
+            function goToExternal() {
+                window.open(External_URL, '_blank');
+            }
+
+            $scope.openDeleteEnv = function openDeleteEnv(id, name) {
+                $scope.deleteName = name;
+                $scope.deleteId = id;
+                ngDialog.open({
+                    template: 'views/modal/deleteConfirm.html',
+                    scope: $scope,
+                    className: 'ngdialog-theme-default',
+                    width: 500,
+                    showClose: true,
+                    closeByDocument: false
+                })
+
+            }
+
+            $scope.deleteTask = function deleteTask() {
+                mainFactory.deleteTask().delete({ 'task_id': $scope.deleteId }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'delete Task success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        ngDialog.close();
+                        getProjectDetail();
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'Wrong',
+                            body: response.result,
+                            timeout: 3000
+                        });
+                    }
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+
+                })
+            }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        }
+    ]);
\ No newline at end of file
diff --git a/gui/app/scripts/controllers/report.controller.js b/gui/app/scripts/controllers/report.controller.js
new file mode 100644 (file)
index 0000000..9b6b595
--- /dev/null
@@ -0,0 +1,115 @@
+'use strict';
+
+angular.module('yardStickGui2App')
+    .controller('ReportController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster', 'ngDialog',
+        function($scope, $state, $stateParams, mainFactory, Upload, toaster, ngDialog) {
+
+
+            init();
+
+
+            function init() {
+                getDetailTaskForList();
+
+
+
+            }
+            $scope.goBack = function goBack() {
+                window.history.back();
+            }
+
+            function getDetailTaskForList(id) {
+                mainFactory.getTaskDetail().get({
+                    'taskId': $stateParams.taskId
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        if (response.result.task.status == -1) {
+                            response.result.task['stausWidth'] = '5%';
+                        } else if (response.result.task.status == 0) {
+                            response.result.task['stausWidth'] = '50%';
+                        } else if (response.result.task.status == 1) {
+                            response.result.task['stausWidth'] = '100%';
+                        } else if (response.result.task.status == 2) {
+                            response.result.task['stausWidth'] = 'red';
+                        }
+                        $scope.result = response.result.task;
+                        $scope.testcaseinfo = response.result.task.result.testcases;
+                        var key = Object.keys($scope.testcaseinfo);
+                        $scope.testcaseResult = $scope.testcaseinfo[key];
+
+                        $scope.envIdForTask = response.result.task.environment_id;
+                        getItemIdDetail();
+
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+
+                })
+            }
+
+            $scope.goToExternal = function goToExternal(id) {
+                var url = External_URL + ':' + $scope.jumpPort + '/dashboard/db' + '/' + id;
+
+                window.open(url, '_blank');
+            }
+
+            function getItemIdDetail() {
+                $scope.displayContainerInfo = [];
+                mainFactory.ItemDetail().get({
+                    'envId': $scope.envIdForTask
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        if (response.result.environment.container_id.grafana != null) {
+                            getConDetail(response.result.environment.container_id.grafana);
+
+                        } else {
+                            $scope.jumpPort = 3000;
+                        }
+
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function getConDetail(id) {
+                mainFactory.containerDetail().get({
+                    'containerId': id
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        // $scope.podData = response.result;
+                        $scope.jumpPort = response.result.container.port;
+
+                    }
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+
+            }
+
+
+
+
+
+
+
+        }
+    ]);
diff --git a/gui/app/scripts/controllers/suitecreate.controller.js b/gui/app/scripts/controllers/suitecreate.controller.js
new file mode 100644 (file)
index 0000000..4a7b6fe
--- /dev/null
@@ -0,0 +1,104 @@
+'use strict';
+
+angular.module('yardStickGui2App')
+    .controller('suitcreateController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster', 'ngDialog',
+        function($scope, $state, $stateParams, mainFactory, Upload, toaster, ngDialog) {
+
+
+            init();
+
+
+            function init() {
+
+                getTestcaseList();
+                $scope.constructTestSuit = constructTestSuit;
+                $scope.openDialog = openDialog;
+                $scope.createSuite = createSuite;
+
+            }
+
+            function getTestcaseList() {
+                mainFactory.getTestcaselist().get({
+
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.testcaselist = response.result;
+
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            $scope.testsuiteList = [];
+            $scope.suitReconstructList = [];
+
+            function constructTestSuit(name) {
+
+                var index = $scope.testsuiteList.indexOf(name);
+                if (index > -1) {
+                    $scope.testsuiteList.splice(index, 1);
+                } else {
+                    $scope.testsuiteList.push(name);
+                }
+
+
+                $scope.suitReconstructList = $scope.testsuiteList;
+
+            }
+
+            function createSuite(name) {
+                mainFactory.suiteCreate().post({
+                    'action': 'create_suite',
+                    'args': {
+                        'name': name,
+                        'testcases': $scope.testsuiteList
+                    }
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'create suite success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        ngDialog.close();
+                    } else {
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function openDialog() {
+                ngDialog.open({
+                    template: 'views/modal/suiteName.html',
+                    className: 'ngdialog-theme-default',
+                    scope: $scope,
+                    width: 314,
+                    showClose: true,
+                    closeByDocument: false
+                })
+            }
+
+
+
+
+
+
+
+
+        }
+    ]);
\ No newline at end of file
diff --git a/gui/app/scripts/controllers/suitedetail.controller.js b/gui/app/scripts/controllers/suitedetail.controller.js
new file mode 100644 (file)
index 0000000..0dd39c3
--- /dev/null
@@ -0,0 +1,48 @@
+'use strict';
+
+angular.module('yardStickGui2App')
+    .controller('suiteDetailController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster',
+        function($scope, $state, $stateParams, mainFactory, Upload, toaster) {
+
+
+            init();
+
+
+            function init() {
+
+                getSuiteDetail();
+
+            }
+
+            function getSuiteDetail() {
+                mainFactory.suiteDetail().get({
+                    'suiteName': $stateParams.name
+
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.suiteinfo = response.result.testsuite;
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+            $scope.goBack = function goBack() {
+                window.history.back();
+            }
+
+
+
+
+
+
+
+
+
+        }
+    ]);
diff --git a/gui/app/scripts/controllers/task.controller.js b/gui/app/scripts/controllers/task.controller.js
new file mode 100644 (file)
index 0000000..05546f9
--- /dev/null
@@ -0,0 +1,175 @@
+'use strict';
+
+angular.module('yardStickGui2App')
+    .controller('TaskController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster', 'ngDialog',
+        function($scope, $state, $stateParams, mainFactory, Upload, toaster, ngDialog) {
+
+
+            init();
+
+
+            function init() {
+                getDetailTaskForList();
+
+            }
+
+            function getDetailTaskForList() {
+                mainFactory.getTaskDetail().get({
+                    'taskId': $stateParams.taskId
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        if (response.result.task.status == -1) {
+                            response.result.task['stausWidth'] = '5%';
+                        } else if (response.result.task.status == 0) {
+                            response.result.task['stausWidth'] = '50%';
+                        } else if (response.result.task.status == 1) {
+                            response.result.task['stausWidth'] = '100%';
+                        } else if (response.result.task.status == 2) {
+                            response.result.task['stausWidth'] = 'red';
+                        }
+
+                        $scope.taskDetailData = response.result.task;
+                        if ($scope.taskDetailData.environment_id != null) {
+                            getItemIdDetail($scope.taskDetailData.environment_id);
+                        }
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+
+            function getItemIdDetail(id) {
+                mainFactory.ItemDetail().get({
+                    'envId': id
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.displayEnv = response.result.environment;
+
+                        if (response.result.environment.pod_id != null) {
+                            getPodDetail(response.result.environment.pod_id);
+                        } else if (response.result.environment.image_id != null) {
+                            getImageDetail(response.result.environment.image_id);
+                        } else if (response.result.environment.openrc_id != null) {
+                            getOpenrcDetail(response.result.environment.openrc_id != null);
+                        } else if (response.result.environment.container_id.length != 0) {
+                            $scope.displayContainerDetail = [];
+                            var containerArray = response.result.environment.container_id;
+                            for (var i = 0; i < containerArray.length; i++) {
+                                getContainerId(containerArray[i]);
+                            }
+
+                        }
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'fail',
+                            body: response.error_msg,
+                            timeout: 3000
+                        });
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            //getopenRcid
+            function getOpenrcDetail(openrcId) {
+                mainFactory.getEnvironmentDetail().get({
+                    'openrc_id': openrcId
+                }).$promise.then(function(response) {
+                    //openrc数据
+                    $scope.openrcInfo = response.result;
+                    // buildToEnvInfo($scope.openrcInfo.openrc)
+                }, function(response) {
+
+                })
+            }
+
+
+            //getImgDetail
+            function getImageDetail(id) {
+                mainFactory.ImageDetail().get({
+                    'image_id': id
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.imageDetail = response.result.image;
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            //getPodDetail
+            function getPodDetail(id) {
+                mainFactory.podDeatil().get({
+                    'podId': id
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.podDetail = response.result.pod;
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+            //getContainerDetail
+            function getContainerId(containerId) {
+                mainFactory.containerDetail().get({
+                    'containerId': containerId
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.container = response.result.container;
+                        $scope.displayContainerDetail.push($scope.container);
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'fail',
+                            body: response.error_msg,
+                            timeout: 3000
+                        });
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+            $scope.goBack = function goBack() {
+                window.history.back();
+            }
+
+
+
+
+
+
+
+
+        }
+    ]);
\ No newline at end of file
diff --git a/gui/app/scripts/controllers/taskModify.controller.js b/gui/app/scripts/controllers/taskModify.controller.js
new file mode 100644 (file)
index 0000000..757d658
--- /dev/null
@@ -0,0 +1,533 @@
+'use strict';
+
+angular.module('yardStickGui2App')
+    .controller('TaskModifyController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster',
+        function($scope, $state, $stateParams, mainFactory, Upload, toaster) {
+
+
+            init();
+            $scope.blisterPackTemplates = [{ id: 1, name: "Test Case" }, { id: 2, name: "Test Suite" }]
+            $scope.selectType = null;
+
+            $scope.sourceShow = null;
+
+
+
+            function init() {
+                getDetailTaskForList();
+                getEnvironmentList();
+                $scope.triggerContent = triggerContent;
+                $scope.constructTestSuit = constructTestSuit;
+                $scope.constructTestCase = constructTestCase;
+                $scope.getTestDeatil = getTestDeatil;
+                $scope.confirmToServer = confirmToServer;
+                $scope.addEnvToTask = addEnvToTask;
+            }
+
+            function getDetailTaskForList() {
+                mainFactory.getTaskDetail().get({
+                    'taskId': $stateParams.taskId
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        if (response.result.task.status == -1) {
+                            response.result.task['stausWidth'] = '5%';
+                        } else if (response.result.task.status == 0) {
+                            response.result.task['stausWidth'] = '50%';
+                        } else if (response.result.task.status == 1) {
+                            response.result.task['stausWidth'] = '100%';
+                        } else if (response.result.task.status == 2) {
+                            response.result.task['stausWidth'] = 'red';
+                        }
+
+                        $scope.taskDetailData = response.result.task;
+                        $scope.selectEnv = $scope.taskDetailData.environment_id;
+
+                        if ($scope.taskDetailData.environment_id != null) {
+                            getItemIdDetail($scope.taskDetailData.environment_id);
+                        }
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function getItemIdDetail(id) {
+                mainFactory.ItemDetail().get({
+                    'envId': id
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.envName = response.result.environment.name;
+                        // $scope.selectEnv = $scope.envName;
+                    } else {
+                        alert('Something Wrong!');
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            //getopenRcid
+            function getOpenrcDetail(openrcId) {
+                mainFactory.getEnvironmentDetail().get({
+                    'openrc_id': openrcId
+                }).$promise.then(function(response) {
+                    $scope.openrcInfo = response.result;
+                    // buildToEnvInfo($scope.openrcInfo.openrc)
+                }, function(response) {
+
+                })
+            }
+
+
+            //getImgDetail
+            function getImageDetail(id) {
+                mainFactory.ImageDetail().get({
+                    'image_id': id
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.imageDetail = response.result.image;
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            //getPodDetail
+            function getPodDetail(id) {
+                mainFactory.podDeatil().get({
+                    'podId': id
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.podDetail = response.result.pod;
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+            //getContainerDetail
+            function getContainerId(containerId) {
+                mainFactory.containerDetail().get({
+                    'containerId': containerId
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.container = response.result.container;
+                        $scope.displayContainerDetail.push($scope.container);
+
+                    } else {
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function getEnvironmentList() {
+                mainFactory.getEnvironmentList().get().$promise.then(function(response) {
+                    $scope.environmentList = response.result.environments;
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+
+            function triggerContent(name) {
+                $scope.selectCase = null;
+                $scope.displayTable = true;
+
+                $scope.selectType = name;
+                if (name.name == 'Test Case') {
+                    $scope.taskDetailData.suite = false;
+                    getTestcaseList();
+                } else if (name.name == 'Test Suite') {
+                    $scope.taskDetailData.suite = true;
+                    getsuiteList();
+                }
+            }
+
+            function getTestcaseList() {
+                mainFactory.getTestcaselist().get({
+
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.testcaselist = response.result;
+
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function getsuiteList() {
+                mainFactory.suiteList().get({
+
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.testsuitlist = response.result.testsuites;
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+
+            function constructTestSuit(id, name) {
+
+                $scope.envName = name;
+                $scope.selectEnv = id;
+
+            }
+
+            function constructTestCase(name) {
+
+                $scope.selectCase = name;
+                if ($scope.selectType.name == 'Test Case') {
+                    getCaseInfo();
+                } else {
+                    getSuiteInfo();
+                }
+
+            }
+
+            function getCaseInfo() {
+
+
+
+                mainFactory.getTestcaseDetail().get({
+                    'testcasename': $scope.selectCase
+
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+
+                        $scope.contentInfo = response.result.testcase;
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function getSuiteInfo() {
+                mainFactory.suiteDetail().get({
+                    'suiteName': $scope.selectCase.split('.')[0]
+
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.contentInfo = response.result.testsuite;
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+
+            function getTestDeatil() {
+
+
+                if ($scope.selectType.name == 'Test Case') {
+                    getTestcaseDetail();
+                } else {
+                    getSuiteDetail();
+                }
+
+            }
+
+            function getSuiteDetail() {
+                mainFactory.suiteDetail().get({
+                    'suiteName': $scope.selectCase.split('.')[0]
+
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.displayTable = false;
+                        $scope.contentInfo = response.result.testsuite;
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+
+            function getTestcaseDetail() {
+                mainFactory.getTestcaseDetail().get({
+                    'testcasename': $scope.selectCase
+
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+
+                        $scope.displayTable = false;
+                        $scope.contentInfo = response.result.testcase;
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+
+
+            function addCasetoTask(content) {
+                mainFactory.taskAddEnv().put({
+                    'taskId': $stateParams.taskId,
+                    'action': 'add_case',
+                    'args': {
+                        'task_id': $stateParams.taskId,
+                        'case_name': $scope.selectCase,
+                        'case_content': content
+                    }
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'add test case success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        $scope.ifHasCase = true;
+
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'create task wrong',
+                            body: '',
+                            timeout: 3000
+                        });
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'create task wrong',
+                        body: '',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function addSuitetoTask(content) {
+                mainFactory.taskAddEnv().put({
+                    'taskId': $stateParams.taskId,
+                    'action': 'add_suite',
+                    'args': {
+                        'task_id': $stateParams.taskId,
+                        'suite_name': $scope.selectCase.split('.')[0],
+                        'suite_content': content
+                    }
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'add test suite success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        $scope.ifHasSuite = true;
+
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'create task wrong',
+                            body: 'wrong',
+                            timeout: 3000
+                        });
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'create task wrong',
+                        body: 'something wrong',
+                        timeout: 3000
+                    });
+                })
+            }
+            $scope.changeStatussourceTrue = function changeStatussourceTrue() {
+                $scope.selectCase = null;
+                $scope.sourceShow = true;
+            }
+
+            $scope.changeStatussourceFalse = function changeStatussourceFalse() {
+                $scope.sourceShow = false;
+            }
+
+            function confirmToServer(content1, content2) {
+
+                var content;
+                if ($scope.sourceShow == false) {
+                    content = content2;
+                    $scope.selectCase = $scope.taskDetailData.case_name;
+                } else if ($scope.sourceShow == true) {
+                    content = content1;
+                }
+                if ($scope.selectCase == 'Test Case' || $scope.taskDetailData.suite == false) {
+
+                    addCasetoTask(content);
+                } else {
+                    addSuitetoTask(content);
+                }
+            }
+
+
+            function addEnvToTask() {
+
+                mainFactory.taskAddEnv().put({
+                    'taskId': $stateParams.taskId,
+                    'action': 'add_environment',
+                    'args': {
+                        'task_id': $stateParams.taskId,
+                        'environment_id': $scope.selectEnv
+                    }
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'add environment success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        $scope.ifHasEnv = true;
+
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'create task wrong',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                    }
+
+
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'create task wrong',
+                        body: 'you can go next step',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            $scope.goBack = function goBack() {
+                window.history.back();
+            }
+
+            $scope.runAtask = function runAtask() {
+                mainFactory.taskAddEnv().put({
+                    'taskId': $stateParams.taskId,
+                    'action': 'run',
+                    'args': {
+                        'task_id': $stateParams.taskId
+                    }
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'run a task success',
+                            body: 'go to task list page...',
+                            timeout: 3000
+                        });
+                        setTimeout(function() {
+                            window.history.back();
+                        }, 2000);
+
+
+
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'fail',
+                            body: response.error_msg,
+                            timeout: 3000
+                        });
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        }
+    ]);
diff --git a/gui/app/scripts/controllers/testcase.controller.js b/gui/app/scripts/controllers/testcase.controller.js
new file mode 100644 (file)
index 0000000..616ceb4
--- /dev/null
@@ -0,0 +1,154 @@
+'use strict';
+
+angular.module('yardStickGui2App')
+    .controller('TestcaseController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster', 'ngDialog', '$loading',
+        function($scope, $state, $stateParams, mainFactory, Upload, toaster, ngDialog, $loading) {
+
+
+            init();
+            $scope.loadingOPENrc = false;
+
+
+            function init() {
+                $scope.testcaselist = [];
+                getTestcaseList();
+                $scope.gotoDetail = gotoDetail;
+                $scope.uploadFiles = uploadFiles;
+
+
+            }
+
+            function getTestcaseList() {
+                $loading.start('key');
+                mainFactory.getTestcaselist().get({
+
+                }).$promise.then(function(response) {
+                    $loading.finish('key');
+                    if (response.status == 1) {
+                        $scope.testcaselist = response.result;
+
+
+                    }
+                }, function(error) {
+                    $loading.finish('key');
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function gotoDetail(name) {
+                $state.go('app2.testcasedetail', { name: name });
+            }
+
+
+            function uploadFiles($file, $invalidFiles) {
+                $scope.loadingOPENrc = true;
+
+                $scope.displayOpenrcFile = $file;
+                timeConstruct($scope.displayOpenrcFile.lastModified);
+                Upload.upload({
+                    url: Base_URL + '/api/v2/yardstick/testcases',
+                    data: { file: $file, 'action': 'upload_case' }
+                }).then(function(response) {
+
+                    $scope.loadingOPENrc = false;
+                    if (response.data.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'upload success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+
+
+
+                    } else {
+
+                    }
+
+                }, function(error) {
+                    $scope.uploadfile = null;
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function timeConstruct(array) {
+                var date = new Date(1398250549490);
+                var Y = date.getFullYear() + '-';
+                var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
+                var D = date.getDate() + ' ';
+                var h = date.getHours() + ':';
+                var m = date.getMinutes() + ':';
+                var s = date.getSeconds();
+                $scope.filelastModified = Y + M + D + h + m + s;
+
+            }
+            $scope.goBack = function goBack() {
+                $state.go('app2.projectList');
+            }
+
+            $scope.openDeleteEnv = function openDeleteEnv(id, name) {
+                $scope.deleteName = name;
+                $scope.deleteId = id;
+                ngDialog.open({
+                    template: 'views/modal/deleteConfirm.html',
+                    scope: $scope,
+                    className: 'ngdialog-theme-default',
+                    width: 500,
+                    showClose: true,
+                    closeByDocument: false
+                })
+
+            }
+
+            $scope.deleteTestCase = function deleteTestCase() {
+                mainFactory.deleteTestCase().delete({ 'caseName': $scope.deleteId }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'delete Test Case success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        ngDialog.close();
+                        getTestcaseList();
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'Wrong',
+                            body: response.result,
+                            timeout: 3000
+                        });
+                    }
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+
+                })
+            }
+
+
+
+
+
+
+
+
+
+
+        }
+    ]);
\ No newline at end of file
diff --git a/gui/app/scripts/controllers/testcasedetail.controller.js b/gui/app/scripts/controllers/testcasedetail.controller.js
new file mode 100644 (file)
index 0000000..4e824ca
--- /dev/null
@@ -0,0 +1,50 @@
+'use strict';
+
+angular.module('yardStickGui2App')
+    .controller('testcaseDetailController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster',
+        function($scope, $state, $stateParams, mainFactory, Upload, toaster) {
+
+
+            init();
+
+
+            function init() {
+
+                getTestcaseDetail();
+
+
+            }
+
+            function getTestcaseDetail() {
+                mainFactory.getTestcaseDetail().get({
+                    'testcasename': $stateParams.name
+
+                }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        $scope.testcaseInfo = response.result.testcase;
+
+                    }
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            $scope.goBack = function goBack() {
+                window.history.back();
+            }
+
+
+
+
+
+
+
+
+
+        }
+    ]);
\ No newline at end of file
diff --git a/gui/app/scripts/controllers/testsuit.controller.js b/gui/app/scripts/controllers/testsuit.controller.js
new file mode 100644 (file)
index 0000000..abc9095
--- /dev/null
@@ -0,0 +1,119 @@
+'use strict';
+
+angular.module('yardStickGui2App')
+    .controller('SuiteListController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster', 'ngDialog', '$loading',
+        function($scope, $state, $stateParams, mainFactory, Upload, toaster, ngDialog, $loading) {
+
+
+            init();
+
+
+            function init() {
+                $scope.testsuitlist = [];
+                getsuiteList();
+                $scope.gotoDetail = gotoDetail;
+                $scope.gotoCreateSuite = gotoCreateSuite;
+
+
+            }
+
+            function getsuiteList() {
+                $loading.start('key');
+                mainFactory.suiteList().get({
+
+                }).$promise.then(function(response) {
+                    $loading.finish('key');
+                    if (response.status == 1) {
+                        $scope.testsuitlist = response.result.testsuites;
+
+                    }
+                }, function(error) {
+                    $loading.finish('key');
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+            function gotoDetail(name) {
+                var temp = name.split('.')[0];
+
+                $state.go('app2.suitedetail', { name: temp })
+
+            }
+
+            function gotoCreateSuite() {
+                $state.go('app2.suitcreate');
+            }
+
+            $scope.goBack = function goBack() {
+                $state.go('app2.projectList');
+            }
+
+
+            $scope.openDeleteEnv = function openDeleteEnv(id, name) {
+                $scope.deleteName = name;
+                $scope.deleteId = id.split('.')[0];
+                ngDialog.open({
+                    template: 'views/modal/deleteConfirm.html',
+                    scope: $scope,
+                    className: 'ngdialog-theme-default',
+                    width: 500,
+                    showClose: true,
+                    closeByDocument: false
+                })
+
+            }
+
+            $scope.deleteSuite = function deleteSuite() {
+                mainFactory.deleteTestSuite().delete({ 'suite_name': $scope.deleteId }).$promise.then(function(response) {
+                    if (response.status == 1) {
+                        toaster.pop({
+                            type: 'success',
+                            title: 'delete Test Suite success',
+                            body: 'you can go next step',
+                            timeout: 3000
+                        });
+                        ngDialog.close();
+                        getTestcaseList();
+                    } else {
+                        toaster.pop({
+                            type: 'error',
+                            title: 'Wrong',
+                            body: response.result,
+                            timeout: 3000
+                        });
+                    }
+
+                }, function(error) {
+                    toaster.pop({
+                        type: 'error',
+                        title: 'fail',
+                        body: 'unknow error',
+                        timeout: 3000
+                    });
+                })
+            }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        }
+    ]);
\ No newline at end of file
diff --git a/gui/app/scripts/factory/main.factory.js b/gui/app/scripts/factory/main.factory.js
new file mode 100644 (file)
index 0000000..f8e9df9
--- /dev/null
@@ -0,0 +1,247 @@
+'use strict';
+
+/**
+ * get data factory
+ */
+
+
+var Base_URL;
+var Grafana_URL;
+
+angular.module('yardStickGui2App')
+    .factory('mainFactory', ['$resource','$rootScope','$http', '$location',function($resource, $rootScope,$http,$location) {
+
+        Base_URL = 'http://' + $location.host() + ':' + $location.port();
+        Grafana_URL = 'http://' + $location.host();
+
+        return {
+
+            postEnvironmentVariable: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/openrcs', {}, {
+                    'post': {
+                        method: 'POST'
+                    }
+                })
+            },
+            uploadOpenrc: function() {
+                return $resource(Base_URL + '/ap/v2/yardstick/openrcs', {}, {
+                    'post': {
+                        method: 'POST'
+                    }
+                })
+            },
+            getEnvironmentList: function() {
+                return $resource(Base_URL+ '/api/v2/yardstick/environments', {}, {
+                    'get': {
+                        method: 'GET'
+                    }
+                })
+            },
+            getEnvironmentDetail: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/openrcs/:openrc_id', { openrc_id: "@openrc_id" }, {
+                    'get': {
+                        method: 'GET'
+                    }
+                })
+            },
+            addEnvName: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/environments', {}, {
+                    'post': {
+                        method: 'POST'
+                    }
+                })
+            },
+            ItemDetail: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/environments/:envId', { envId: "@envId" }, {
+                    'get': {
+                        method: 'GET'
+                    }
+                })
+            },
+            ImageDetail: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/images/:image_id', { image_id: "@image_id" }, {
+                    'get': {
+                        method: 'GET'
+                    }
+                })
+            },
+            podDeatil: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/pods/:podId', { podId: "@podId" }, {
+                    'get': {
+                        method: 'GET'
+                    }
+                })
+            },
+            containerDetail: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/containers/:containerId', { containerId: "@containerId" }, {
+                    'get': {
+                        method: 'GET'
+                    }
+                })
+            },
+            ImageList: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/images', {}, {
+                    'get': {
+                        method: 'GET'
+                    }
+                })
+            },
+            uploadImage: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/images', {}, {
+                    'post': {
+                        method: 'POST'
+                    }
+                })
+            },
+            getPodDetail: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/pods/:podId', { podId: "@podId" }, {
+                    'get': {
+                        method: 'GET'
+                    }
+                })
+            },
+            runAcontainer: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/containers', { podId: "@podId" }, {
+                    'post': {
+                        method: 'POST'
+                    }
+                })
+            },
+            getTestcaselist: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/testcases', {}, {
+                    'get': {
+                        method: 'GET'
+                    }
+                })
+            },
+            getTestcaseDetail: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/testcases/:testcasename', { testcasename: "@testcasename" }, {
+                    'get': {
+                        method: 'GET'
+                    }
+                })
+            },
+            suiteList: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/testsuites', {}, {
+                    'get': {
+                        method: 'GET'
+                    }
+                })
+            },
+            suiteDetail: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/testsuites/:suiteName', { suiteName: "@suiteName" }, {
+                    'get': {
+                        method: 'GET'
+                    }
+                })
+            },
+            suiteCreate: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/testsuites', {}, {
+                    'post': {
+                        method: 'POST'
+                    }
+                })
+            },
+            projectList: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/projects', {}, {
+                    'get': {
+                        method: 'GET'
+                    }
+                })
+            },
+            createProjectName: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/projects', {}, {
+                    'post': {
+                        method: 'POST'
+                    }
+                })
+            },
+            getProjectDetail: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/projects/:project_id', { project_id: "@project_id" }, {
+                    'post': {
+                        method: 'POST'
+                    }
+                })
+            },
+            createTask: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/tasks', {}, {
+                    'post': {
+                        method: 'POST'
+                    }
+                })
+            },
+            getTaskDetail: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/tasks/:taskId', { taskId: "@taskId" }, {
+                    'get': {
+                        method: 'GET'
+                    }
+                })
+            },
+
+            taskAddEnv: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/tasks/:taskId', { taskId: "@taskId" }, {
+                    'put': {
+                        method: 'PUT'
+                    }
+                })
+            },
+            //delete operate
+            deleteEnv: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/environments/:env_id', { env_id: '@env_id' }, {
+                    'delete': {
+                        method: 'DELETE'
+                    }
+                })
+            },
+            deleteOpenrc: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/openrcs/:openrc', { openrc: '@openrc' }, {
+                    'delete': {
+                        method: 'DELETE'
+                    }
+                })
+            },
+            deletePod: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/pods/:podId', { podId: '@podId' }, {
+                    'delete': {
+                        method: 'DELETE'
+                    }
+                })
+            },
+            deleteContainer: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/containers/:containerId', { containerId: '@containerId' }, {
+                    'delete': {
+                        method: 'DELETE'
+                    }
+                })
+            },
+            deleteTestCase: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/testcases/:caseName', { caseName: '@caseName' }, {
+                    'delete': {
+                        method: 'DELETE'
+                    }
+                })
+            },
+            deleteTestSuite: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/testsuites/:suite_name', { suite_name: '@suite_name' }, {
+                    'delete': {
+                        method: 'DELETE'
+                    }
+                })
+            },
+            deleteProject: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/projects/:project_id', { project_id: '@project_id' }, {
+                    'delete': {
+                        method: 'DELETE'
+                    }
+                })
+            },
+            deleteTask: function() {
+                return $resource(Base_URL + '/api/v2/yardstick/tasks/:task_id', { task_id: '@task_id' }, {
+                    'delete': {
+                        method: 'DELETE'
+                    }
+                })
+            }
+
+        };
+    }]);
diff --git a/gui/app/scripts/router.config.js b/gui/app/scripts/router.config.js
new file mode 100644 (file)
index 0000000..b429542
--- /dev/null
@@ -0,0 +1,184 @@
+'use strict';
+
+angular.module('yardStickGui2App')
+    .run(
+        ['$rootScope', '$state', '$stateParams',
+            function($rootScope, $state, $stateParams) {
+                $rootScope.$state = $state;
+                $rootScope.$stateParams = $stateParams;
+
+            }
+        ]
+    )
+    .config(['$stateProvider', '$urlRouterProvider', '$locationProvider',
+        function($stateProvider, $urlRouterProvider, $locationProvider) {
+            $urlRouterProvider
+                .otherwise('main/environment');
+
+
+
+
+            $stateProvider
+
+                .state('app2', {
+                    url: "/main",
+                    controller: 'ContentController',
+                    templateUrl: "views/main2.html",
+                    ncyBreadcrumb: {
+                        label: 'Main'
+                    }
+                })
+                .state('app', {
+                    url: "/main",
+                    controller: 'ContentController',
+                    templateUrl: "views/main.html",
+                    ncyBreadcrumb: {
+                        label: 'Main'
+                    }
+                })
+
+            .state('app2.environment', {
+                    url: '/environment',
+                    templateUrl: 'views/environmentList.html',
+                    controller: 'MainCtrl',
+                    ncyBreadcrumb: {
+                        label: 'Environment'
+                    }
+                })
+                .state('app2.testcase', {
+                    url: '/testcase',
+                    templateUrl: 'views/testcaselist.html',
+                    controller: 'TestcaseController',
+                    ncyBreadcrumb: {
+                        label: 'Test Case'
+                    }
+                })
+                .state('app2.testsuite', {
+                    url: '/suite',
+                    templateUrl: 'views/suite.html',
+                    controller: 'SuiteListController',
+                    ncyBreadcrumb: {
+                        label: 'Test Suite'
+                    }
+                })
+                .state('app2.suitcreate', {
+                    url: '/suitcreate',
+                    templateUrl: 'views/testcasechoose.html',
+                    controller: 'suitcreateController',
+                    ncyBreadcrumb: {
+                        label: 'Suite Create'
+                    }
+                })
+                .state('app2.testcasedetail', {
+                    url: '/testdetail/:name',
+                    templateUrl: 'views/testcasedetail.html',
+                    controller: 'testcaseDetailController',
+                    ncyBreadcrumb: {
+                        label: 'Test Case Detail'
+                    },
+                    params: { name: null }
+                })
+                .state('app2.suitedetail', {
+                    url: '/suitedetail/:name',
+                    templateUrl: 'views/suitedetail.html',
+                    controller: 'suiteDetailController',
+                    ncyBreadcrumb: {
+                        label: 'Suite Detail'
+                    },
+                    params: { name: null }
+                })
+                .state('app.environmentDetail', {
+                    url: '/envDetail/:uuid',
+                    templateUrl: 'views/environmentDetail.html',
+                    controller: 'DetailController',
+                    params: { uuid: null, ifNew: null },
+                    ncyBreadcrumb: {
+                        label: 'Environment Detail'
+                    }
+                })
+                .state('app.uploadImage', {
+                    url: '/envimageDetail/:uuid',
+                    templateUrl: 'views/uploadImage.html',
+                    controller: 'ImageController',
+                    params: { uuid: null },
+                    ncyBreadcrumb: {
+                        label: 'Upload Image'
+                    }
+
+                })
+                .state('app.podUpload', {
+                    url: '/envpodupload/:uuid',
+                    templateUrl: 'views/podupload.html',
+                    controller: 'PodController',
+                    params: { uuid: null },
+                    ncyBreadcrumb: {
+                        label: 'Pod Upload'
+                    }
+                })
+                .state('app.container', {
+                    url: '/envcontainer/:uuid',
+                    templateUrl: 'views/container.html',
+                    controller: 'ContainerController',
+                    params: { uuid: null },
+                    ncyBreadcrumb: {
+                        label: 'Container Manage'
+                    }
+                })
+                .state('app2.projectList', {
+                    url: '/project',
+                    templateUrl: 'views/projectList.html',
+                    controller: 'ProjectController',
+                    ncyBreadcrumb: {
+                        label: 'Project'
+                    }
+
+                })
+                .state('app2.tasklist', {
+                    url: '/task/:taskId',
+                    templateUrl: 'views/taskList.html',
+                    controller: 'TaskController',
+                    params: { taskId: null },
+                    ncyBreadcrumb: {
+                        label: 'Task'
+                    }
+
+                })
+                .state('app2.report', {
+                    url: '/report/:taskId',
+                    templateUrl: 'views/report.html',
+                    controller: 'ReportController',
+                    params: { taskId: null },
+                    ncyBreadcrumb: {
+                        label: 'Report'
+                    }
+
+                })
+                .state('app2.projectdetail', {
+                    url: '/projectdetail/:projectId',
+                    templateUrl: 'views/projectdetail.html',
+                    controller: 'ProjectDetailController',
+                    params: { projectId: null },
+                    ncyBreadcrumb: {
+                        label: 'Project Detail'
+                    }
+
+                })
+                .state('app2.taskModify', {
+                    url: '/taskModify/:taskId',
+                    templateUrl: 'views/taskmodify.html',
+                    controller: 'TaskModifyController',
+                    params: { taskId: null },
+                    ncyBreadcrumb: {
+                        label: 'Modify Task'
+                    }
+
+
+                })
+
+
+
+
+
+        }
+    ])
+    .run();
diff --git a/gui/app/styles/main.css b/gui/app/styles/main.css
new file mode 100644 (file)
index 0000000..e13a66b
--- /dev/null
@@ -0,0 +1,208 @@
+.browsehappy {
+    margin: 0.2em 0;
+    background: #ccc;
+    color: #000;
+    padding: 0.2em 0;
+}
+
+body {
+    padding: 0;
+}
+
+
+/* Everything but the jumbotron gets side spacing for mobile first views */
+
+.header,
+.marketing,
+.footer {
+    /*padding-left: 15px;
+    padding-right: 15px;*/
+}
+
+
+/* Custom page header */
+
+.header {
+    border-bottom: 1px solid #e5e5e5;
+    margin-bottom: 10px;
+}
+
+
+/* Make the masthead heading the same height as the navigation */
+
+.header h3 {
+    margin-top: 0;
+    margin-bottom: 0;
+    line-height: 40px;
+    padding-bottom: 19px;
+}
+
+
+/* Custom page footer */
+
+.footer {
+    padding-top: 19px;
+    color: #777;
+    border-top: 1px solid #e5e5e5;
+}
+
+.container-narrow>hr {
+    margin: 30px 0;
+}
+
+
+/* Main marketing message and sign up button */
+
+.jumbotron {
+    text-align: center;
+    border-bottom: 1px solid #e5e5e5;
+}
+
+.jumbotron .btn {
+    font-size: 21px;
+    padding: 14px 24px;
+}
+
+
+/* Supporting marketing content */
+
+.marketing {
+    margin: 40px 0;
+}
+
+.marketing p+h4 {
+    margin-top: 28px;
+}
+
+
+/* Responsive: Portrait tablets and up */
+
+@media screen and (min-width: 768px) {
+    .container {
+        max-width: 730px;
+    }
+    /* Remove the padding we set earlier */
+    .header,
+    .marketing,
+    .footer {
+        padding-left: 0;
+        padding-right: 0;
+    }
+    /* Space out the masthead */
+    .header {
+        margin-bottom: 30px;
+    }
+    /* Remove the bottom border on the jumbotron for visual effect */
+    .jumbotron {
+        border-bottom: 0;
+    }
+}
+
+.jumbotron.ng-scope {
+    margin-top: 100px;
+}
+
+.content {
+    /*margin-left: 300px;*/
+    /*margin-left: 100px;*/
+    position: relative;
+    margin-left: 25%;
+    width: 70%;
+    border: 1px solid #dfe3e4;
+    border-radius: 5px;
+    padding: 20px 20px 5px 20px;
+    height: 100%;
+    margin-right: 10px;
+    /*border-bottom: none;*/
+    margin-bottom: 10px;
+    padding-bottom: 20px;
+    /* overflow: hidden; */
+}
+
+.ngdialog.ngdialog-theme-default .ngdialog-content {
+    background-color: #fff;
+}
+
+.progree-parent {
+    width: 50%;
+    background-color: #dfe3e4;
+    height: 10px;
+    border-radius: 10px;
+}
+
+.progree-child {
+    width: 50%;
+    background-color: #2ecc71;
+    /* background-color: white; */
+    height: 10px;
+    border-radius: 5px;
+}
+
+textarea {
+    width: 100%;
+    height: 400px;
+    border-radius: 5px;
+    border: 1px solid #e8e8e8;
+}
+
+.naviSide {
+    position: fixed;
+    left: 0px;
+    top: 0px;
+    height: 150%;
+    background-color: #f8f8f8;
+    width: 210px;
+    padding: 30px 0 0 0;
+    border-radius: 10px;
+    border-right: 1px solid #e7e7e7;
+    z-index: 2;
+}
+
+.panel-body {
+    border: none;
+}
+
+.panel-group {
+    width: 210px;
+}
+
+.panel-group {
+    margin-bottom: 0px;
+}
+
+* {
+    border-radius: 0px ! important;
+}
+
+.naviSide.ng-scope {
+    box-shadow: 1px 1px 2px #888888;
+}
+
+.pagination>li>a,
+.pagination>li>span {
+    color: #333;
+}
+
+.pagination>.active>a,
+.pagination>.active>span,
+.pagination>.active>a:hover,
+.pagination>.active>span:hover,
+.pagination>.active>a:focus,
+.pagination>.active>span:focus {
+    background-color: #f9f9f9;
+    color: #333;
+    border-color: #ddd;
+}
+
+.ngdialog.ngdialog-theme-default .ngdialog-close{
+    border: none;
+    background-color: #fff;
+}
+
+button:focus {outline:0;}
+input:focus{outline: 0}
+
+.ngdialog-content {
+    overflow: hidden;
+}
+
diff --git a/gui/app/views/container.html b/gui/app/views/container.html
new file mode 100644 (file)
index 0000000..b3d78bf
--- /dev/null
@@ -0,0 +1,134 @@
+<!--container management-->
+
+<div class="content">
+    <div style="display:flex;flex-direction:row;">
+        <div style="width:750px;">
+
+            <h3>{{envName}} -- Container
+                <!--<button class="btn btn-default" style="float:right">Go Next</button>-->
+
+            </h3>
+            <!--<p>In this process, you can input your define openrc config or upload a openrc file</p>-->
+
+            <hr/>
+
+            <select ng-model="selectContainer" data-ng-options="container as container.name for container in containerList">
+                <option value="">Choose...</option>
+            </select>
+
+            <button class="btn btn-default" ng-click="createContainer()" ng-disabled="selectContainer==null">
+                                    <div ng-show="!showloading">Create</div>
+                                    <img src="images/loading2.gif" width="25" height="25" ng-if="showloading" />
+            </button>
+
+            <hr/>
+
+            <div>
+                <h4 ng-show="displayContainerInfo.length==0">No Container Data</h4>
+                <div ng-show="displayContainerInfo.length!=0">
+                    <h4>Current Container</h4>
+                    <table class="table table-striped">
+
+                        <tr>
+                            <th>name</th>
+                            <th>status</th>
+                            <th>time</th>
+                            <th>delete</th>
+
+                        </tr>
+                        <tr ng-repeat="con in displayContainerInfo">
+                            <td>{{con.name}}</td>
+                            <td>{{con.status}}</td>
+                            <td>{{con.time}}</td>
+                            <td>
+                                <button class="btn btn-default btn-sm" ng-click="openDeleteEnv(con.id,'container')">Delete</button>
+                            </td>
+
+
+                        </tr>
+
+
+
+                    </table>
+                </div>
+            </div>
+
+
+
+
+
+
+
+
+
+
+        </div>
+
+
+    </div>
+
+</div>
+<toaster-container></toaster-container>
+
+<style>
+    .form-control {
+        border-radius: 5px;
+        width: 200px;
+        margin-bottom: 10px;
+    }
+
+    .uploadbutton {
+        background-color: #007ACC;
+        color: #fff;
+        border: 0px;
+        border-radius: 5px;
+        height: 27px;
+    }
+
+    .edit-title {
+        border: 0px;
+        background-color: #ffffff;
+        margin-bottom: 5px;
+        font-size: 12px;
+    }
+
+    .null-edit-title {
+        border: 1px solid #e5e6e7;
+        border-radius: 5px;
+        margin-bottom: 3px;
+    }
+
+    .item-info {
+        display: flex;
+        flex-direction: row;
+    }
+
+    .delete-img {
+        width: 15px;
+        height: 15px;
+        opacity: 0.8;
+        margin-left: -10px;
+        margin-top: -3px;
+        cursor: pointer;
+    }
+
+    .nextButton {
+        margin-top: 30px;
+        border: none;
+        border-radius: 5px;
+        padding: 6px;
+        background-color: #339933;
+        color: #ffffff;
+        text-align: center;
+        /* margin-left: 300px; */
+    }
+
+    select {
+        height: 30px;
+        border-radius: 5px;
+        border: 1px solid #e8e8e8;
+        width: 135px;
+        margin-top: 20px;
+        margin-left: 20px;
+    }
+</style>
diff --git a/gui/app/views/content.html b/gui/app/views/content.html
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gui/app/views/environmentDetail.html b/gui/app/views/environmentDetail.html
new file mode 100644 (file)
index 0000000..4d5f21c
--- /dev/null
@@ -0,0 +1,143 @@
+<!--environment detail page-->
+
+<div class="content" style="overflow-x: scroll;">
+    <div style="display:flex;flex-direction:row;">
+        <div>
+
+
+            <h3> {{baseElementInfo.name}} -- Openrc
+                <button class="btn btn-default" style="float:right" ng-click="goNext()">Next</button>
+                <button class="btn btn-default" style="float:right;margin-right:10px;" ng-click="openDeleteEnv(1,'openrc')">Delete</button>
+            </h3>
+            <!--<p>In this process, you can input your define openrc config or upload a openrc file</p>-->
+
+
+
+            <div>
+
+                <button style="display:inline;" class="btn btn-default" ng-click="addEnvironment()" ng-show="uuid==null">Add Name</button>
+            </div>
+
+
+
+            <hr/>
+            <div bs-tabs style="width:600px;">
+                <div data-title="Detail" bs-pane ng-if="openrcInfo.openrc!=null">
+
+                    <h4>
+                        You have already set up the openrc parameters
+                    </h4>
+                    <hr />
+                    <div ng-repeat="(key,value) in openrcInfo.openrc">
+                        <nobr>
+                            <font style="font-weight:600;font-size:14px;">{{key}} : </font>
+                            <font style="font-size:14px;">{{value}}</font>
+                        </nobr>
+                    </div>
+
+                </div>
+                <div data-title="Update" bs-pane>
+
+                    <div style="margin-top:20px;">
+                        <button class="btn btn-default" ng-click="addInfo()" style="margin-bottom:20px;">Add</button>
+                        <div style="height:300px;width:800px;display:flex;flex-direction:column;flex-wrap:wrap;margin-left:5px;">
+                            <div ng-repeat="info in envInfo">
+                                <!--<div> {{info.name}}</div>-->
+
+                                <input class="edit-title" ng-model="info.name" ng-class="{'null-edit-title':info.name==null}" ng-attr-type="{{info.name.indexOf('PASSWORD')>-1 ? password : text}}" />
+
+                                <div class="item-info">
+                                    <input class="form-control" type="text" ng-model="info.value" />
+                                    <!--<button class="delete-button" ng-click="deleteEnvItem($index)">delete</button>-->
+                                    <img src="images/close.png" ng-click="deleteEnvItem($index)" class="delete-img" />
+                                </div>
+
+
+
+                            </div>
+                        </div>
+                        <button class="btn btn-default" ng-click="submitOpenRcFile()" style="margin-bottom:20px;">
+                                     <div ng-if="!showloading">submit</div>
+                                     <img src="images/loading2.gif" width="25" height="25" ng-if="showloading" />
+                                </button>
+
+                    </div>
+
+                </div>
+                <div data-title="Upload File" bs-pane>
+                    <div style="margin-top:20px;height:405px;">
+                        <button class="btn btn-default" style="margin-bottom:20px;" ngf-select="uploadFiles($file, $invalidFiles)" ngf-max-size="5MB">
+                                    <div ng-show="!loadingOPENrc">Upload</div>
+                                     <img src="images/loading2.gif" width="25" height="25" ng-if="loadingOPENrc" />
+                                    </button>
+
+                        <!--<div ng-show="displayOpenrcFile!=null || displayOpenrcFile!=undefined">
+                            {{displayOpenrcFile.name}} last modified: {{filelastModified}}
+                        </div>-->
+                    </div>
+                </div>
+            </div>
+
+
+
+        </div>
+
+
+    </div>
+
+</div>
+<toaster-container></toaster-container>
+
+<style>
+    .form-control {
+        border-radius: 5px;
+        width: 200px;
+        margin-bottom: 10px;
+    }
+
+    .uploadbutton {
+        background-color: #007ACC;
+        color: #fff;
+        border: 0px;
+        border-radius: 5px;
+        height: 27px;
+    }
+
+    .edit-title {
+        border: 0px;
+        background-color: #ffffff;
+        margin-bottom: 5px;
+        font-size: 12px;
+    }
+
+    .null-edit-title {
+        border: 1px solid #e5e6e7;
+        border-radius: 5px;
+        margin-bottom: 3px;
+    }
+
+    .item-info {
+        display: flex;
+        flex-direction: row;
+    }
+
+    .delete-img {
+        width: 15px;
+        height: 15px;
+        opacity: 0.8;
+        margin-left: -10px;
+        margin-top: -3px;
+        cursor: pointer;
+    }
+
+    .nextButton {
+        margin-top: 30px;
+        border: none;
+        border-radius: 5px;
+        padding: 6px;
+        background-color: #339933;
+        color: #ffffff;
+        text-align: center;
+        /* margin-left: 300px; */
+    }
+</style>
diff --git a/gui/app/views/environmentList.html b/gui/app/views/environmentList.html
new file mode 100644 (file)
index 0000000..29273a7
--- /dev/null
@@ -0,0 +1,155 @@
+<div class="content">
+
+    <!--environmentList-->
+    <i class="fa fa-arrow-left fa-1x" aria-hidden="true" style="color: #999;cursor:pointer" ng-click="goBack()">Back</i>
+
+    <div>
+
+        <h3>Environments
+            <button class="btn btn-default btn-sm" style="margin-left:30px;display:inline" ng-click="openEnvironmentDialog()">Add</button>
+        </h3>
+        <hr/>
+
+        <!--<div ng-repeat="env in environmentList">
+            {{env.name}}
+        </div>-->
+        <div dw-loading="key" dw-loading-options="{text:'loading'}">
+            <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;background-color: #f9f9f9;">
+                <div style="font-weight:600">Name</div>
+                <div style="font-weight:600;margin-right:80px;">Action</div>
+
+            </div>
+
+            <div dir-paginate="env in environmentList | orderBy:'-id' | itemsPerPage: 10 ">
+                <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;">
+                    <div> <a style="color:#e95420" ng-click="gotoDetail('false',env.uuid)">{{env.name}}</a></div>
+                    <div>
+
+                        <!-- <button class="btn btn-default btn-sm" ng-click="openDeleteEnv(env.uuid,'environment')">Delete</button> -->
+
+                        <div class="btn-group" uib-dropdown is-open="status.isopen" style="margin-right:60px;">
+                            <button id="single-button" type="button" class="btn btn-default btn-sm" uib-dropdown-toggle>
+                            Modify <span class="caret"></span>
+                        </button>
+                            <ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="single-button">
+                                <li role="menuitem"><a ng-click="openDeleteEnv(env.uuid,'environment')">Delete</a></li>
+                                <!-- <li role="menuitem"><a href="#">Another action</a></li>
+        <li role="menuitem"><a href="#">Something else here</a></li>
+        <li class="divider"></li>
+        <li role="menuitem"><a href="#">Separated link</a></li> -->
+                            </ul>
+                        </div>
+                    </div>
+
+
+
+                </div>
+
+            </div>
+            <center>
+                <dir-pagination-controls></dir-pagination-controls>
+            </center>
+        </div>
+
+
+
+
+
+
+
+    </div>
+
+
+
+
+</div>
+
+<toaster-container></toaster-container>
+
+<style>
+    .form-control {
+        border-radius: 5px;
+        width: 300px;
+        margin-bottom: 10px;
+    }
+
+    .uploadbutton {
+        background-color: #007ACC;
+        color: #fff;
+        border: 0px;
+        border-radius: 5px;
+        height: 27px;
+    }
+
+    .edit-title {
+        border: 0px;
+        background-color: #ffffff;
+        margin-bottom: 5px;
+    }
+
+    .null-edit-title {
+        border: 1px solid #e5e6e7;
+        border-radius: 5px;
+        margin-bottom: 3px;
+    }
+
+    .item-info {
+        display: flex;
+        flex-direction: row;
+    }
+
+    .delete-img {
+        width: 19px;
+        height: 19px;
+        opacity: 0.8;
+        margin-left: 5px;
+        margin-top: 4px;
+        cursor: pointer;
+    }
+
+    .deepColor {
+        background-color: #f9f9f9;
+    }
+
+    .nextButton {
+        margin-top: 30px;
+        border: none;
+        border-radius: 5px;
+        padding: 6px;
+        background-color: #339933;
+        color: #ffffff;
+        text-align: center;
+        /* margin-left: 300px; */
+    }
+
+    .bs-sidenav {
+        margin-top: 40px;
+        margin-bottom: 20px;
+        width: 124px;
+    }
+
+    .nav {
+        margin-bottom: 0;
+        padding-left: 0;
+        list-style: none;
+    }
+
+    .nav>li {
+        position: relative;
+        display: block;
+    }
+
+    li {
+        display: list-item;
+        text-align: -webkit-match-parent;
+    }
+
+    a {
+        cursor: pointer;
+    }
+
+    a.active {
+        background-color: #EEEEEE;
+        border-radius: 5px;
+    }
+</style>
diff --git a/gui/app/views/layout/footer.html b/gui/app/views/layout/footer.html
new file mode 100644 (file)
index 0000000..cfdf74a
--- /dev/null
@@ -0,0 +1,5 @@
+<div class="footer">
+    <div class="container">
+        <p></p>
+    </div>
+</div>
\ No newline at end of file
diff --git a/gui/app/views/layout/header.html b/gui/app/views/layout/header.html
new file mode 100644 (file)
index 0000000..033322a
--- /dev/null
@@ -0,0 +1,43 @@
+<div class="header">
+    <div class="navbar navbar-default" role="navigation">
+        <div>
+            <div class="navbar-header">
+
+
+
+                <a class="navbar-brand" href="#/">Yardstick</a>
+            </div>
+
+
+        </div>
+    </div>
+</div>
+</div>
+
+<style>
+    .header {
+        position: fixed;
+        top: 0px;
+        width: 100%;
+        /*box-shadow: 3px 2px 5px #888888;*/
+        z-index: 9;
+    }
+
+    .navbar {
+        position: relative;
+        min-height: 50px;
+        margin-bottom: 0px;
+        border: none;
+        /* border: 1px solid transparent; */
+    }
+
+    .navbar {
+        border-radius: 0px;
+        background-color: #e95420;
+        color: #fff;
+    }
+
+    .navbar-default .navbar-brand {
+        color: #fff;
+    }
+</style>
diff --git a/gui/app/views/layout/sideNav.html b/gui/app/views/layout/sideNav.html
new file mode 100644 (file)
index 0000000..42dcbbc
--- /dev/null
@@ -0,0 +1,141 @@
+<div class="naviSide">
+
+
+
+
+    <ul class="nav bs-sidenav">
+
+        <div class="panel-group " role="tablist " aria-multiselectable="true " bs-collapse style="margin-bottom:0px; ">
+            <div class="panel panel-default ">
+                <div class="panel-heading " role="tab ">
+                    <h4 class="panel-title ">
+                        <a bs-collapse-toggle style=" text-decoration: none;" ng-click="gotoProject();">
+        Project
+        </a>
+                    </h4>
+
+                </div>
+
+            </div>
+        </div>
+        <div class="panel-group" role="tablist" aria-multiselectable="true" bs-collapse style="margin-bottom:0px;" ng-model="activeStatus">
+            <div class="panel panel-default">
+                <div class="panel-heading" role="tab">
+                    <h4 class="panel-title">
+                        <a bs-collapse-toggle style=" text-decoration: none;">
+                            <div style="display:inline;" ng-click="gotoEnviron()">Environment </div>
+                            <i class="fa fa-sort-asc" aria-hidden="true" style="margin-left: 71px;display:inline" ng-show="activeStatus==0"></i>
+                            <i class="fa fa-sort-desc" aria-hidden="true" style="margin-left: 71px;display:inline" ng-show="activeStatus==-1"></i>
+                        </a>
+                    </h4>
+                </div>
+                <div class="panel-collapse" role="tabpanel" bs-collapse-target>
+                    <div class="panel-body" style="border-top: 2px solid grey;text-align: right;cursor:pointer" ng-click="gotoOpenrcPage()" ng-class="{active:$state.includes('app.environmentDetail')}">
+                        Openrc
+                    </div>
+                    <div class="panel-body " style="border:none;text-align: right;cursor:pointer" ng-click="gotoUploadPage()" ng-class="{active:$state.includes('app.uploadImage')}">
+                        Image
+                    </div>
+                    <div class="panel-body " style="border:none;text-align: right;cursor:pointer" ng-click="gotoPodPage()" ng-class="{active:$state.includes('app.podUpload')}">
+                        Pod File
+                    </div>
+                    <div class="panel-body " style="border:none;text-align: right;cursor:pointer" ng-click="gotoContainerPage()" ng-class="{active:$state.includes('app.container')}">
+                        Container
+                    </div>
+                    <div class="panel-body " style="border:none;text-align: right;">
+                        Others
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <div class="panel-group " role="tablist " aria-multiselectable="true " bs-collapse style="margin-bottom:0px; ">
+            <div class="panel panel-default ">
+                <div class="panel-heading " role="tab ">
+                    <h4 class="panel-title ">
+                        <a bs-collapse-toggle style=" text-decoration: none;" ng-click="gotoTestcase()">
+         Test Case
+        </a>
+                    </h4>
+
+                </div>
+
+            </div>
+        </div>
+
+        <div class="panel-group " role="tablist " aria-multiselectable="true " bs-collapse style="margin-bottom:0px; ">
+            <div class="panel panel-default ">
+                <div class="panel-heading " role="tab ">
+                    <h4 class="panel-title ">
+                        <a bs-collapse-toggle style=" text-decoration: none;" ng-click="gotoSuite()">
+        Test Suite
+        </a>
+                    </h4>
+
+                </div>
+
+            </div>
+        </div>
+
+
+
+    </ul>
+
+
+
+
+
+</div>
+
+
+<style>
+    .bs-sidenav {
+        margin-top: 40px;
+        margin-bottom: 20px;
+        width: 124px;
+    }
+
+    .naviSide {
+        height: 150%;
+    }
+
+    .nav {
+        margin-bottom: 0;
+        padding-left: 0;
+        list-style: none;
+    }
+
+    .nav>li {
+        position: relative;
+        display: block;
+    }
+
+    li {
+        display: list-item;
+        text-align: -webkit-match-parent;
+    }
+
+    a {
+        cursor: pointer;
+    }
+
+    a.active {
+        background-color: #EEEEEE;
+        border-radius: 5px;
+        width: 165px;
+    }
+    /*
+    a:hover {
+        width: 165px;
+    }*/
+
+    .nav>li>a:hover,
+    .nav>li>a:focus {
+        text-decoration: underline;
+        background-color: transparent;
+    }
+
+    .active.panel-body {
+        background-color: #dfe3e4;
+    }
+</style>
diff --git a/gui/app/views/layout/sideNav2.html b/gui/app/views/layout/sideNav2.html
new file mode 100644 (file)
index 0000000..104a9c6
--- /dev/null
@@ -0,0 +1,108 @@
+<div class="naviSide">
+
+
+    <ul class="nav bs-sidenav">
+
+        <div class="panel-group " role="tablist " aria-multiselectable="true " bs-collapse style="margin-bottom:0px; ">
+            <div class="panel panel-default ">
+                <div class="panel-heading " role="tab ">
+                    <h4 class="panel-title ">
+                        <a bs-collapse-toggle style=" text-decoration: none;" ng-click="gotoProject();">
+        Project
+        </a>
+                    </h4>
+
+                </div>
+
+            </div>
+        </div>
+        <div class="panel-group" role="tablist" aria-multiselectable="false" bs-collapse style="margin-bottom:0px;">
+            <div class="panel panel-default">
+                <div class="panel-heading" role="tab">
+                    <h4 class="panel-title">
+                        <a bs-collapse-toggle style=" text-decoration: none;">
+                            <div style="display:inline;" ng-click="gotoEnviron()">Environment </div>
+                            <!--<i class="fa fa-sort-asc" aria-hidden="true" style="margin-left: 71px;display:inline"></i>-->
+                        </a>
+                    </h4>
+                </div>
+
+            </div>
+        </div>
+
+        <div class="panel-group " role="tablist " aria-multiselectable="true " bs-collapse style="margin-bottom:0px; ">
+            <div class="panel panel-default ">
+                <div class="panel-heading " role="tab ">
+                    <h4 class="panel-title ">
+                        <a bs-collapse-toggle style=" text-decoration: none;" ng-click="gotoTestcase()">
+         Test Case
+        </a>
+                    </h4>
+
+                </div>
+
+            </div>
+        </div>
+
+        <div class="panel-group " role="tablist " aria-multiselectable="true " bs-collapse style="margin-bottom:0px; ">
+            <div class="panel panel-default ">
+                <div class="panel-heading " role="tab ">
+                    <h4 class="panel-title ">
+                        <a bs-collapse-toggle style=" text-decoration: none;" ng-click="gotoSuite()">
+        Test Suite
+        </a>
+                    </h4>
+
+                </div>
+
+            </div>
+        </div>
+
+
+
+    </ul>
+
+</div>
+
+<style>
+    .bs-sidenav {
+        margin-top: 40px;
+        margin-bottom: 20px;
+        width: 124px;
+    }
+
+    .nav {
+        margin-bottom: 0;
+        padding-left: 0;
+        list-style: none;
+    }
+
+    .nav>li {
+        position: relative;
+        display: block;
+    }
+
+    li {
+        display: list-item;
+        text-align: -webkit-match-parent;
+    }
+
+    a {
+        cursor: pointer;
+    }
+
+    a.active {
+        background-color: #EEEEEE;
+        border-radius: 5px;
+        width: 165px;
+    }
+    /*a:hover {
+        width: 165px;
+    }*/
+
+    .nav>li>a:hover,
+    .nav>li>a:focus {
+        text-decoration: underline;
+        background-color: transparent;
+    }
+</style>
diff --git a/gui/app/views/main.html b/gui/app/views/main.html
new file mode 100644 (file)
index 0000000..d5f7a3a
--- /dev/null
@@ -0,0 +1,174 @@
+<div>
+    <div ng-include="'views/layout/header.html'"></div>
+</div>
+<div ng-include="'views/layout/sideNav.html'"></div>
+
+
+<div style="margin-top:80px;margin-left:100px;display:flex;flex-direction:row">
+    <!--<div ncy-breadcrumb></div>-->
+    <div>
+        <ol class="progressDefine">
+            <li data-step="1" ng-click="gotoProject();" style="cursor:pointer" ng-class="{'is-complete':projectShow}">
+                Project
+            </li>
+            <li data-step="2" ng-class="{'is-complete':taskShow}">
+                Task
+            </li>
+
+            <li data-step="3" ng-class="{'progressDefine__last':reportShow}">
+                Reporting
+            </li>
+
+        </ol>
+    </div>
+
+
+</div>
+
+
+
+
+
+
+
+
+
+<div ui-view></div>
+
+
+
+<style>
+    .stepsContent {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-around;
+        margin-left: 120px;
+        margin-top: 100px;
+    }
+
+    .stepItem {
+        display: flex;
+        flex-direction: column;
+    }
+
+    .nextButton {
+        margin-left: 500px;
+    }
+
+    .progressDefine {
+        list-style: none;
+        margin: 0;
+        padding: 0;
+        display: table;
+        table-layout: fixed;
+        width: 100%;
+        color: #849397;
+    }
+
+    .progressDefine>li {
+        position: relative;
+        display: table-cell;
+        text-align: center;
+        font-size: 0.8em;
+    }
+
+    .progressDefine>li:before {
+        content: attr(data-step);
+        display: block;
+        margin: 0 auto;
+        background: #DFE3E4;
+        width: 3em;
+        height: 3em;
+        text-align: center;
+        margin-bottom: 0.25em;
+        line-height: 3em;
+        border-radius: 100%;
+        position: relative;
+        z-index: 5;
+    }
+
+    .progressDefine>li:after {
+        content: '';
+        position: absolute;
+        display: block;
+        background: #DFE3E4;
+        width: 100%;
+        height: 0.5em;
+        top: 1.25em;
+        left: 50%;
+        margin-left: 1.5em\9;
+        z-index: -1;
+    }
+
+    .progressDefine>li:last-child:after {
+        display: none;
+    }
+
+    .progressDefine>li.is-complete {
+        color: #e95420;
+    }
+
+    .progressDefine>li.is-complete:before,
+    .progressDefine>li.is-complete:after {
+        color: #FFF;
+        background: #e95420;
+    }
+
+    .progressDefine>li.is-active {
+        color: #3498DB;
+    }
+
+    .progressDefine>li.is-active:before {
+        color: #FFF;
+        background: #3498DB;
+    }
+    /**
+ * Needed for IE8
+ */
+
+    .progressDefine__last:after {
+        display: none !important;
+    }
+    /**
+ * Size Extensions
+ */
+
+    .progressDefine--medium {
+        font-size: 1.5em;
+    }
+
+    .progressDefine--large {
+        font-size: 2em;
+    }
+    /**
+ * Some Generic Stylings
+ */
+
+    *,
+    *:after,
+    *:before {
+        box-sizing: border-box;
+    }
+
+    h1 {
+        margin-bottom: 1.5em;
+    }
+
+    .progressDefine {
+        margin-bottom: 3em;
+    }
+
+    a {
+        color: #3498DB;
+        text-decoration: none;
+    }
+
+    a:hover {
+        text-decoration: underline;
+    }
+    /*
+    body {
+        text-align: center;
+        color: #444;
+    }*/
+</style>
diff --git a/gui/app/views/main2.html b/gui/app/views/main2.html
new file mode 100644 (file)
index 0000000..661d604
--- /dev/null
@@ -0,0 +1,174 @@
+<div>
+    <div ng-include="'views/layout/header.html'"></div>
+</div>
+<div ng-include="'views/layout/sideNav2.html'"></div>
+
+
+<div style="margin-top:80px;margin-left:220px;">
+    <!--<div ncy-breadcrumb></div>-->
+    <div>
+        <ol class="progressDefine">
+            <li data-step="1" ng-click="gotoProject();" style="cursor:pointer" ng-class="{'is-complete':projectShow}">
+                Project
+            </li>
+            <li data-step="2" ng-class="{'is-complete':taskShow}">
+                Task
+            </li>
+
+            <li data-step="3" ng-class="{'is-complete':reportShow}">
+                Reporting
+            </li>
+
+        </ol>
+    </div>
+
+
+</div>
+
+
+
+
+
+
+
+
+
+<div ui-view></div>
+
+
+
+<style>
+    .stepsContent {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-around;
+        margin-left: 120px;
+        margin-top: 100px;
+    }
+
+    .stepItem {
+        display: flex;
+        flex-direction: column;
+    }
+
+    .nextButton {
+        margin-left: 500px;
+    }
+
+    .progressDefine {
+        list-style: none;
+        margin: 0;
+        padding: 0;
+        display: table;
+        table-layout: fixed;
+        width: 100%;
+        color: #849397;
+    }
+
+    .progressDefine>li {
+        position: relative;
+        display: table-cell;
+        text-align: center;
+        font-size: 0.8em;
+    }
+
+    .progressDefine>li:before {
+        content: attr(data-step);
+        display: block;
+        margin: 0 auto;
+        background: #DFE3E4;
+        width: 3em;
+        height: 3em;
+        text-align: center;
+        margin-bottom: 0.25em;
+        line-height: 3em;
+        border-radius: 100%;
+        position: relative;
+        z-index: 5;
+    }
+
+    .progressDefine>li:after {
+        content: '';
+        position: absolute;
+        display: block;
+        background: #DFE3E4;
+        width: 100%;
+        height: 0.5em;
+        top: 1.25em;
+        left: 50%;
+        margin-left: 1.5em\9;
+        z-index: -1;
+    }
+
+    .progressDefine>li:last-child:after {
+        display: none;
+    }
+
+    .progressDefine>li.is-complete {
+        color: #e95420;
+    }
+
+    .progressDefine>li.is-complete:before,
+    .progressDefine>li.is-complete:after {
+        color: #FFF;
+        background: #e95420;
+    }
+
+    .progressDefine>li.is-active {
+        color: #3498DB;
+    }
+
+    .progressDefine>li.is-active:before {
+        color: #FFF;
+        background: #3498DB;
+    }
+    /**
+ * Needed for IE8
+ */
+
+    .progressDefine__last:after {
+        display: none !important;
+    }
+    /**
+ * Size Extensions
+ */
+
+    .progressDefine--medium {
+        font-size: 1.5em;
+    }
+
+    .progressDefine--large {
+        font-size: 2em;
+    }
+    /**
+ * Some Generic Stylings
+ */
+
+    *,
+    *:after,
+    *:before {
+        box-sizing: border-box;
+    }
+
+    h1 {
+        margin-bottom: 1.5em;
+    }
+
+    .progressDefine {
+        margin-bottom: 3em;
+    }
+
+    a {
+        color: #3498DB;
+        text-decoration: none;
+    }
+
+    a:hover {
+        text-decoration: underline;
+    }
+    /*
+    body {
+        text-align: center;
+        color: #444;
+    }*/
+</style>
diff --git a/gui/app/views/modal/chooseContainer.html b/gui/app/views/modal/chooseContainer.html
new file mode 100644 (file)
index 0000000..4b857b2
--- /dev/null
@@ -0,0 +1,15 @@
+<h3>Choose Containers</h3>
+<hr/>
+
+
+
+<style>
+    select {
+        height: 30px;
+        border-radius: 5px;
+        border: 1px solid #e8e8e8;
+        width: 135px;
+        margin-top: 20px;
+        margin-left: 20px;
+    }
+</style>
\ No newline at end of file
diff --git a/gui/app/views/modal/deleteConfirm.html b/gui/app/views/modal/deleteConfirm.html
new file mode 100644 (file)
index 0000000..1659b88
--- /dev/null
@@ -0,0 +1,19 @@
+<div>Confirm delete {{deleteName}} ?</div>
+
+<div style="display:flex;flex-direction:row; margin-left: 150px;margin-top: 30px;">
+    <button class="btn btn-default" ng-click="deleteEnv()" ng-show="deleteName=='environment'">Confirm</button>
+    <button class="btn btn-default" ng-click="deleteProject()" ng-show="deleteName=='project'">Confirm</button>
+    <button class="btn btn-default" ng-click="deleteTask()" ng-show="deleteName=='task'">Confirm</button>
+    <button class="btn btn-default" ng-click="deleteTestCase()" ng-show="deleteName=='test case'">Confirm</button>
+    <button class="btn btn-default" ng-click="deleteSuite()" ng-show="deleteName=='test suite'">Confirm</button>
+    <button class="btn btn-default" ng-click="deleteContainer()" ng-show="deleteName=='container'">Confirm</button>
+    <button class="btn btn-default" ng-click="deletePod()" ng-show="deleteName=='pod'">Confirm</button>
+    <button class="btn btn-default" ng-click="deleteOpenRc()" ng-show="deleteName=='openrc'">Confirm</button>
+
+
+
+
+
+    <button class="btn btn-default" style="margin-left:10px;" ng-click="closeThisDialog()">Cancel</button>
+
+</div>
\ No newline at end of file
diff --git a/gui/app/views/modal/environmentDialog.html b/gui/app/views/modal/environmentDialog.html
new file mode 100644 (file)
index 0000000..a5b88d2
--- /dev/null
@@ -0,0 +1,330 @@
+<!--environment input dialog-->
+
+<div>
+    <div ng-if="uuidEnv==null">
+        <h4>Environment Name</h4>
+        <input type="text" ng-model="name" style="width:300px;" />
+
+        <div style="text-align:center;margin-top:20px;">
+            <button class="btn btn-default" ng-disabled=" name==null || name==''" ng-click="addEnvironment(name)">Create</button>
+        </div>
+    </div>
+
+
+    <div style="display:flex;flex-direction:row;" ng-if="uuidEnv!=null&&showImage==null">
+        <div>
+            <h3> {{name}} -- Openrc
+                <!--<button class="btn btn-default" style="float:right" ng-click="goNext()">Next</button>-->
+                <button class="btn btn-default" ng-click="goToImage()" style="margin-bottom:20px;float:right" ng-disabled="showNextOpenRc==null && showNextOpenRc==null ">
+                                        Next
+                                </button>
+            </h3>
+            <!--<p>In this process, you can input your define openrc config or upload a openrc file</p>-->
+            <div>
+
+                <!--<button style="display:inline;" class="btn btn-default" ng-click="addEnvironment()" ng-show="uuid==null">Add Name</button>-->
+            </div>
+
+            <hr/>
+            <div bs-tabs style="width:750px;">
+                <div data-title="Detail" bs-pane ng-if="openrcInfo.openrc!=null">
+
+                    <h4>
+                        You have already set up the openrc parameters
+                    </h4>
+                    <hr />
+                    <div ng-repeat="(key,value) in openrcInfo.openrc">
+                        <nobr>
+                            <font style="font-weight:600;font-size:14px;">{{key}} : </font>
+                            <font style="font-size:14px;">{{value}}</font>
+                        </nobr>
+                    </div>
+
+                </div>
+                <div data-title="Update" bs-pane>
+
+                    <div style="margin-top:20px;">
+                        <button class="btn btn-default" ng-click="addInfo()" style="margin-bottom:20px;">Add</button>
+                        <div style="height:300px;width:800px;display:flex;flex-direction:column;flex-wrap:wrap;margin-left:5px;overflow-x:scroll">
+                            <div ng-repeat="info in envInfo">
+                                <!--<div> {{info.name}}</div>-->
+
+                                <input class="edit-title" ng-model="info.name" ng-class="{'null-edit-title':info.name==null}" ng-attr-type="{{info.name.indexOf('PASSWORD')>-1 ? password : text}}" />
+
+                                <div class="item-info">
+                                    <input class="form-control" type="text" ng-model="info.value" />
+                                    <!--<button class="delete-button" ng-click="deleteEnvItem($index)">delete</button>-->
+                                    <img src="images/close.png" ng-click="deleteEnvItem($index)" class="delete-img" />
+                                </div>
+
+
+
+                            </div>
+                        </div>
+                        <button class="btn btn-default" ng-click="submitOpenRcFile();" style="margin-bottom:20px;">
+                                     <div ng-if="!showloading">Submit</div>
+                                     <img src="images/loading2.gif" width="25" height="25" ng-if="showloading" />
+                                </button>
+
+
+                    </div>
+
+                </div>
+                <div data-title="Upload File" bs-pane>
+                    <div style="margin-top:20px;height:405px;">
+                        <button class="btn btn-default" style="margin-bottom:20px;" ngf-select="uploadFiles($file, $invalidFiles);" ngf-max-size="5MB">
+                                    <div ng-show="!loadingOPENrc">Upload</div>
+                                     <img src="images/loading2.gif" width="25" height="25" ng-if="loadingOPENrc" />
+                                    </button>
+                        <!--<button class="btn btn-default" style="margin-bottom:20px;" ng-disabled="showNextOpenRc==null" ng-click="goToImage()">
+                                       Next
+                        </button>-->
+
+                        <!--<div ng-if="displayOpenrcFile!=null || displayOpenrcFile!=undefined">
+                            {{displayOpenrcFile.name}} last modified: {{filelastModified}}
+                        </div>-->
+                    </div>
+                </div>
+            </div>
+
+
+
+        </div>
+
+
+    </div>
+
+    <div ng-if="showImage==1&&showPod==null">
+        <div style="display:flex;flex-direction:row;">
+            <div style="width:750px;">
+
+                <h3>{{name}} -- Image
+
+                    <button class="btn btn-default" ng-click="goToPod()" ng-disabled="showNextPod==null" style="float:right">
+                 Next
+            </button>
+                    <button class="btn btn-default" ng-click="goToPodPrev()" style="margin-right:5px;float:right">
+                 Previous
+            </button>
+
+                </h3>
+                <!--<p>In this process, you can input your define openrc config or upload a openrc file</p>-->
+
+                <hr/>
+
+                <button class="btn btn-default" ng-click="uploadImage()">
+                 <div ng-if="!showloading">Load Image</div>
+                 <img src="images/loading2.gif" width="25" height="25" ng-if="showloading" />
+
+                 </button>
+
+                <i class="fa fa-check" aria-hidden="true" style="margin-top:34px;margin-left:5px;color: #2ecc71;" ng-show="imageStatus==1&&showImageStatus==1">done</i>
+                <i class="fa fa-spinner" aria-hidden="true" style="margin-top:34px;margin-left:5px;color: #2ecc71;" ng-show="imageStatus==0&&showImageStatus==1">loading</i>
+                <i class="fa fa-exclamation-triangle" aria-hidden="true" style="margin-top:34px;margin-left:5px;color: red;" ng-show="imageStatus==2&&showImageStatus==1">error</i>
+
+
+                <!--<button class="btn btn-default" ng-click="goToPod()" ng-disabled="showNextPod==null">
+                 Next
+            </button>-->
+                <hr>
+                <h4>Current Images</h4>
+
+                <div>
+                    <table class="table table-striped">
+
+                        <tr>
+                            <th>name</th>
+                            <th>size</th>
+                            <th>status</th>
+                            <th>time</th>
+                        </tr>
+                        <tr ng-repeat="image in imageListData">
+                            <td>{{image.name}}</td>
+                            <td>{{image.size/1024}} mb</td>
+                            <td>{{image.status}}</td>
+                            <td>{{image.time}}</td>
+
+                        </tr>
+
+
+
+                    </table>
+                </div>
+
+
+            </div>
+
+
+        </div>
+    </div>
+
+    <div ng-if="showPod==1&&showContainer==null">
+        <div style="display:flex;flex-direction:row;">
+            <div style="width:750px;">
+
+
+                <h3>{{name}} -- Pod File
+                    <div style="float:right">
+                        <button class="btn btn-default" ng-click="skipPodPrev()">Previous</button>
+                        <button class="btn btn-default" ng-click="skipPod()" ng-show="podData==null">Skip</button>
+                        <button class="btn btn-default" ng-click="skipPod()" ng-show="podData!=null">Next</button>
+
+                    </div>
+
+                </h3>
+
+                <hr/>
+
+                <button class="btn btn-default" ngf-select="uploadFilesPod($file, $invalidFiles)" ngf-max-size="5MB">
+                                    <div ng-show="!loadingOPENrc">Upload</div>
+                                     <img src="images/loading2.gif" width="25" height="25" ng-if="loadingOPENrc" />
+            </button>
+
+
+                <hr/>
+
+                <div>
+                    <h4>Current Pod Configuration</h4>
+                    <table class="table table-striped">
+
+                        <tr>
+                            <th>ip</th>
+                            <th>name</th>
+                            <th>password</th>
+                            <th>role</th>
+                            <th>user</th>
+                        </tr>
+                        <tr ng-repeat="pod in podData.pod.nodes">
+                            <td>{{pod.ip}}</td>
+                            <td>{{pod.name}}</td>
+                            <td>{{pod.password}}</td>
+                            <td>{{pod.role}}</td>
+                            <td>{{pod.user}}</td>
+
+                        </tr>
+                        <tr ng-show="podData.length==0">
+                            <td>no data</td>
+
+                        </tr>
+
+
+
+                    </table>
+                </div>
+
+
+
+
+
+
+
+
+
+
+            </div>
+
+
+        </div>
+
+    </div>
+
+    <div ng-if="showContainer!=null">
+        <div style="display:flex;flex-direction:row;">
+            <div style="width:750px;">
+
+                <h3>{{name}} -- Container
+                    <div style="float:right">
+                        <button class="btn btn-default" ng-click="skipContainerPrev()">Previous</button>
+                        <button class="btn btn-default" ng-click="skipContainer()" ng-show="ifskipOrClose!=1">
+                            Skip
+            </button>
+                        <button class="btn btn-default" ng-click="closeThisDialog(); getEnvironmentList();" ng-show="ifskipOrClose==1">
+                           Close
+            </button>
+                    </div>
+                    <!--<button class="btn btn-default" style="float:right">Go Next</button>-->
+                </h3>
+                <!--<p>In this process, you can input your define openrc config or upload a openrc file</p>-->
+
+                <hr/>
+
+                <select ng-model="selectContainer" data-ng-options="container as container.name for container in containerList">
+                <option value="">Choose...</option>
+            </select>
+
+                <button class="btn btn-default" ng-click="createContainer(selectContainer)" ng-disabled="selectContainer==null">
+                                    <div ng-show="!showloading">Create</div>
+                                    <img src="images/loading2.gif" width="25" height="25" ng-if="showloading" />
+            </button>
+                <!--<button class="btn btn-default" ng-click="skipContainer()" ng-show="ifskipOrClose!=1">
+                            Skip
+            </button>
+                <button class="btn btn-default" ng-click="closeThisDialog(); getEnvironmentList();" ng-show="ifskipOrClose==1">
+                           Close
+            </button>-->
+
+                <hr/>
+
+                <div>
+                    <h4>Current Contain</h4>
+                    <table class="table table-striped">
+
+                        <tr>
+                            <th>name</th>
+                            <th>status</th>
+                            <th>time</th>
+
+                        </tr>
+                        <tr ng-repeat="con in displayContainerInfo">
+                            <td>{{con.name}}</td>
+                            <td>{{con.status}}</td>
+                            <td>{{con.time}}</td>
+
+
+                        </tr>
+
+
+
+                    </table>
+                </div>
+
+
+
+
+
+
+
+
+
+
+            </div>
+
+
+        </div>
+
+    </div>
+
+
+
+
+
+
+</div>
+
+
+<style>
+    input {
+        border-radius: 10px;
+        border: 1px solid #eeeeee;
+        width: 100%;
+    }
+
+    select {
+        height: 30px;
+        border-radius: 5px;
+        border: 1px solid #e8e8e8;
+        width: 135px;
+        margin-top: 20px;
+        margin-left: 20px;
+    }
+</style>
diff --git a/gui/app/views/modal/projectCreate.html b/gui/app/views/modal/projectCreate.html
new file mode 100644 (file)
index 0000000..74839e7
--- /dev/null
@@ -0,0 +1,21 @@
+<div>
+
+    <h4>Enter Project Name</h4>
+    <input type="text" ng-model="name" />
+
+    <div style="text-align:center;margin-top:20px;">
+        <button class="btn btn-default" ng-disabled=" name==null || name==''" ng-click="createName(name)">Create</button>
+    </div>
+
+
+
+</div>
+
+
+<style>
+    input {
+        border-radius: 10px;
+        border: 1px solid #eeeeee;
+        width: 100%;
+    }
+</style>
diff --git a/gui/app/views/modal/suiteName.html b/gui/app/views/modal/suiteName.html
new file mode 100644 (file)
index 0000000..981d242
--- /dev/null
@@ -0,0 +1,18 @@
+<h4>Enter Suite Name</h4>
+<hr/> You have choose:
+<div ng-repeat="selected in suitReconstructList">{{selected}}</div>
+<hr/>
+<input type="text" ng-model="name" />
+
+<div style="text-align:center;margin-top:20px;">
+    <button class="btn btn-default" ng-disabled="testsuiteList.length==0 || name==null || name==''" ng-click="createSuite(name)">Create</button>
+</div>
+
+
+<style>
+    input {
+        border-radius: 10px;
+        border: 1px solid #eeeeee;
+        width: 100%;
+    }
+</style>
diff --git a/gui/app/views/modal/taskCreate.html b/gui/app/views/modal/taskCreate.html
new file mode 100644 (file)
index 0000000..e7812cf
--- /dev/null
@@ -0,0 +1,134 @@
+
+<h4>Create Task</h4>
+<hr/>
+<div>
+    <div style="display:inline">Name <input type="text" ng-model="name" style="width:200px" /></div>
+    <button style="display:inline" class="btn btn-default" ng-disabled="name==null || name==''" ng-click="createTask(name)" ng-show="newUUID==null">Create</button>
+</div>
+<hr/>
+
+<div bs-tabs ng-show="newUUID!=null">
+    <div data-title="Environment" bs-pane>
+        <div style="margin-top:10px" ng-show="displayEnvName!=null">
+            <div style="display:inline">Choose Environment : {{displayEnvName}}</div>
+            <button class="btn btn-default" style="display:inline;float:right;margin-right:10px;margin-top: -4px;" ng-click="addEnvToTask()">confirm</button>
+        </div>
+        <hr />
+        <div dir-paginate="env in environmentList | orderBy:'-id' | itemsPerPage: 10 ">
+            <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;" ng-class="{deepColor: $index%2==0}">
+                <div> {{env.name}}</div>
+                <!--<button class="btn btn-default btn-sm" ng-click="gotoDetail('false',env.uuid)">detail</button>-->
+                <img src="images/checkyes.png" style="height:18px;cursor:pointer" ng-click="constructTestSuit(env.uuid,env.name)" ng-show="selectEnv==env.uuid" />
+                <img src="images/checkno.png" style="height:18px;cursor:pointer" ng-click="constructTestSuit(env.uuid,env.name)" ng-show="selectEnv!=env.uuid" />
+
+            </div>
+            <!--<hr style="margin-top:5px;margin-bottom:5px;" />-->
+        </div>
+        <center>
+            <dir-pagination-controls></dir-pagination-controls>
+        </center>
+
+    </div>
+    <div data-title="Content" bs-pane>
+        <div style="display:flex;flex-direction:row">
+            <div style="margin-top:20px;">Source of Content</div>
+
+
+            <select ng-model="selectType" ng-change="triggerContent(selectType)" data-ng-options="blisterPackTemplate as blisterPackTemplate.name for blisterPackTemplate in blisterPackTemplates">
+    <option value="">Choose...</option>
+            </select>
+
+        </div>
+        <div style="margin-top:10px" ng-show="selectCase!=null">
+            <div style="display:inline">Choose Source: {{selectCase}}</div>
+            <button class="btn btn-default" style="display:inline;float:right;margin-right:10px;margin-top: -4px;" ng-click="confirmAddCaseOrSuite(contentInfo)">Confirm</button>
+            <button class="btn btn-default" style="display:inline;float:right;margin-right:10px;margin-top: -4px;" ng-click="getTestDeatil()">Edit</button>
+        </div>
+        <hr/>
+
+        <div ng-show="displayTable==true">
+            <div ng-show="testcaselist.testcases.length!=0 && selectType.name=='Test Case'">
+                <div dir-paginate="test in testcaselist.testcases | itemsPerPage: 10" pagination-id="testcase">
+                    <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;" ng-class="{deepColor: $index%2==0}">
+                        <div> {{test.Name}}</div>
+                        <div style="font-size:10px;">{{test.Description}}</div>
+                        <img src="images/checkyes.png" style="height:18px;cursor:pointer" ng-click="constructTestCase(test.Name)" ng-show="selectCase==test.Name" />
+                        <img src="images/checkno.png" style="height:18px;cursor:pointer" ng-click="constructTestCase(test.Name)" ng-show="selectCase!=test.Name" />
+
+                    </div>
+                    <!--<hr style="margin-top:5px;margin-bottom:5px;" />-->
+                </div>
+                <center>
+                    <dir-pagination-controls pagination-id="testcase"></dir-pagination-controls>
+                </center>
+            </div>
+
+            <div ng-show="testsuitlist.length!=0 && selectType.name=='Test Suite'">
+                <div dir-paginate="suite in testsuitlist | itemsPerPage: 10" pagination-id="testsuite">
+                    <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;" ng-class="{deepColor: $index%2==0}">
+                        <div> {{suite}}</div>
+
+                        <img src="images/checkyes.png" style="height:18px;cursor:pointer" ng-click="constructTestCase(suite)" ng-show="selectCase==suite" />
+                        <img src="images/checkno.png" style="height:18px;cursor:pointer" ng-click="constructTestCase(suite)" ng-show="selectCase!=suite" />
+
+                    </div>
+                    <!--<hr style="margin-top:5px;margin-bottom:5px;" />-->
+                </div>
+                <center>
+                    <dir-pagination-controls pagination-id="testsuite"></dir-pagination-controls>
+                </center>
+            </div>
+        </div>
+
+        <div ng-show="displayTable==false">
+            <textarea ng-model="contentInfo" spellcheck="false">
+
+
+            </textarea>
+
+
+        </div>
+
+
+
+
+    </div>
+</div>
+
+<div style="text-align:center;margin-top:20px;">
+    <button class="btn btn-default" ng-click="closeThisDialog()" ng-disabled="newUUID===null || ifHasEnv!=true || (ifHasCase!=true && ifHasSuite!=true)">Close</button>
+    <button class="btn btn-default" ng-disabled="newUUID===null || ifHasEnv!=true || (ifHasCase!=true && ifHasSuite!=true)" ng-click="runAtask(newUUID)">Run</button>
+</div>
+
+
+<style>
+    input {
+        border-radius: 10px;
+        border: 1px solid #eeeeee;
+        width: 100%;
+    }
+
+    .deepColor {
+        background-color: #f9f9f9;
+    }
+
+    select {
+        height: 30px;
+        border-radius: 5px;
+        border: 1px solid #e8e8e8;
+        width: 135px;
+        margin-top: 20px;
+        margin-left: 20px;
+    }
+
+    textarea {
+        width: 100%;
+        height: 400px;
+        border-radius: 5px;
+        border: 1px solid #e8e8e8;
+    }
+
+    .deepColor {
+        background-color: #f9f9f9;
+    }
+</style>
diff --git a/gui/app/views/podupload.html b/gui/app/views/podupload.html
new file mode 100644 (file)
index 0000000..99e83ac
--- /dev/null
@@ -0,0 +1,136 @@
+<!--pod file upload-->
+
+<div class="content">
+    <div style="display:flex;flex-direction:row;">
+        <div style="width:750px;">
+            <!--<i class="fa fa-arrow-left fa-1x" aria-hidden="true" style="color: #999;cursor:pointer" ng-click="goBack()">Back</i>-->
+
+
+            <h3>{{name}} -- Pod File
+                <button class="btn btn-default" style="float:right" ng-click="goNext()">Next</button>
+            </h3>
+            <!--<p>In this process, you can input your define openrc config or upload a openrc file</p>-->
+
+            <hr/>
+
+            <button class="btn btn-default" ngf-select="uploadFiles($file, $invalidFiles)" ngf-max-size="5MB">
+                                    <div ng-show="!loadingOPENrc">Upload</div>
+                                     <img src="images/loading2.gif" width="25" height="25" ng-if="loadingOPENrc" />
+            </button>
+            <button class="btn btn-default" ng-click="openDeleteEnv(1,'pod')">Delete</button>
+
+            <!--<div ng-show="displayOpenrcFile!=null || displayOpenrcFile!=undefined ||podData.pod.nodes!=null ">
+                {{displayOpenrcFile.name}} last modified: {{filelastModified}}
+            </div>-->
+
+            <hr/>
+
+            <div>
+                <h4 ng-show="podData.pod.nodes==null">No Pod Configuration</h4>
+                <div ng-show="podData.pod.nodes!=null">
+                    <h4>Current Pod Configuration</h4>
+                    <table class="table table-striped">
+
+                        <tr>
+                            <th>ip</th>
+                            <th>name</th>
+                            <th>password</th>
+                            <th>role</th>
+                            <th>user</th>
+                        </tr>
+                        <tr ng-repeat="pod in podData.pod.nodes">
+                            <td>{{pod.ip}}</td>
+                            <td>{{pod.name}}</td>
+                            <td>{{pod.password}}</td>
+                            <td>{{pod.role}}</td>
+                            <td>{{pod.user}}</td>
+
+                        </tr>
+
+
+
+                    </table>
+                </div>
+            </div>
+
+
+
+
+
+
+
+
+
+
+        </div>
+        <!--<div style="margin-top:60px;margin-left:67px;">
+            <h3>Openrc parameters</h3>
+            <div>
+                You have already set up the openrc parameters
+            </div>
+            <div ng-repeat="(key,value) in openrcInfo.openrc">
+                <nobr>
+                    <font style="font-weight:600;font-size:15px;">{{key}} : </font>
+                    <font style="font-size:15px;">{{value}}</font>
+                </nobr>
+            </div>
+        </div>-->
+
+    </div>
+
+</div>
+<toaster-container></toaster-container>
+
+<style>
+    .form-control {
+        border-radius: 5px;
+        width: 200px;
+        margin-bottom: 10px;
+    }
+
+    .uploadbutton {
+        background-color: #007ACC;
+        color: #fff;
+        border: 0px;
+        border-radius: 5px;
+        height: 27px;
+    }
+
+    .edit-title {
+        border: 0px;
+        background-color: #ffffff;
+        margin-bottom: 5px;
+        font-size: 12px;
+    }
+
+    .null-edit-title {
+        border: 1px solid #e5e6e7;
+        border-radius: 5px;
+        margin-bottom: 3px;
+    }
+
+    .item-info {
+        display: flex;
+        flex-direction: row;
+    }
+
+    .delete-img {
+        width: 15px;
+        height: 15px;
+        opacity: 0.8;
+        margin-left: -10px;
+        margin-top: -3px;
+        cursor: pointer;
+    }
+
+    .nextButton {
+        margin-top: 30px;
+        border: none;
+        border-radius: 5px;
+        padding: 6px;
+        background-color: #339933;
+        color: #ffffff;
+        text-align: center;
+        /* margin-left: 300px; */
+    }
+</style>
diff --git a/gui/app/views/projectList.html b/gui/app/views/projectList.html
new file mode 100644 (file)
index 0000000..ea6e63d
--- /dev/null
@@ -0,0 +1,57 @@
+<div class="content">
+
+    <h3>Projects
+        <button class="btn btn-default btn-sm" style="margin-left:30px;" ng-click="openCreateProject()">Create</button>
+    </h3>
+
+    <hr/>
+
+
+
+    <div dw-loading="key" dw-loading-options="{text:'loading'}">
+        <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;background-color:#f9f9f9;">
+            <div style="font-weight:600">Name</div>
+            <div style="font-weight:600;margin-right:4px;">Action</div>
+
+        </div>
+
+        <div dir-paginate="project in projectListData | orderBy:'-id' | itemsPerPage: 10 ">
+            <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;">
+                <div>
+                    <a ng-click="gotoDetail(project.uuid)" style="color:#e95420"> {{project.name}}</a>
+                </div>
+                <div>
+                    <!-- <button class="btn btn-default btn-sm" ng-click="gotoDetail(project.uuid)">Detail</button> -->
+                    <!--<button class="btn btn-default btn-sm" ng-click="openDeleteEnv(project.uuid,'project')">Delete</button>-->
+                    <div class="btn-group" uib-dropdown is-open="status.isopen" style="margin-right:20px;">
+                        <button id="single-button" type="button" class="btn btn-default btn-sm" uib-dropdown-toggle>
+                            Modify <span class="caret"></span>
+                        </button>
+                        <ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="single-button">
+                            <li role="menuitem" ng-show="task.status!=0"><a ng-click="openDeleteEnv(project.uuid,'project')">delete</a></li>
+
+
+                        </ul>
+                    </div>
+                </div>
+
+            </div>
+            <!--<hr style="margin-top:5px;margin-bottom:5px;" />-->
+        </div>
+        <center>
+            <dir-pagination-controls></dir-pagination-controls>
+        </center>
+
+    </div>
+
+
+</div>
+
+<toaster-container></toaster-container>
+
+
+<style>
+    .deepColor {
+        background-color: #f9f9f9;
+    }
+</style>
diff --git a/gui/app/views/projectdetail.html b/gui/app/views/projectdetail.html
new file mode 100644 (file)
index 0000000..ff61c5f
--- /dev/null
@@ -0,0 +1,97 @@
+<div class="content">
+    <i class="fa fa-arrow-left fa-1x" aria-hidden="true" style="color: #999;cursor:pointer" ng-click="goBack()">Back</i>
+
+    <h3>Project -- Task
+
+    </h3>
+
+    <hr/>
+
+    <div>
+
+        <h4>{{projectData.name}}</h4>
+        <h5>{{projectData.time}}</h5>
+        <hr/>
+        <h4>Tasks
+            <button class="btn btn-default btn-sm" style="margin-left:30px;" ng-click="openCreate()">Create</button>
+        </h4>
+        <div ng-show="projectData.tasks.length==0">No task in this project</div>
+        <table class="table " width="100%" dw-loading="key" dw-loading-options="{text:'loading'}">
+            <tr style="background-color:#f9f9f9">
+                <td style="font-weight:700">Name</td>
+                <td style="font-weight:700"> Status</td>
+                <td style="font-weight:700">Action</td>
+            </tr>
+            <tr dir-paginate="task in finalTaskListDisplay | orderBy:'-id' | itemsPerPage: 6 " pagination-id="table">
+
+                <td width="10%"> <a ng-click="gotoDetail(task.uuid)" style="color:#e95420"> {{task.name}} </a></td>
+                <td width="40%">
+                    <div class="progree-parent" ng-show="task.status!=2">
+                        <div class="progree-child" ng-style="{'width':task.stausWidth}">
+                        </div>
+                    </div>
+                    <div class="progree-parent" ng-show="task.status==2" style="background-color:red">
+                        <div class="progree-child" style="width:0">
+                        </div>
+                    </div>
+                </td>
+
+
+                <td width="50%">
+
+                    <div class="btn-group" uib-dropdown is-open="status.isopen" style="margin-right:20px;">
+                        <button id="single-button" type="button" class="btn btn-default btn-sm" uib-dropdown-toggle>
+                            Modify <span class="caret"></span>
+                        </button>
+                        <ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="single-button">
+                            <li role="menuitem" ng-show="task.status!=0"><a ng-click="runAtaskForTable(task.uuid)">run</a></li>
+
+                            <li role="menuitem" ng-show="task.status!=0"><a ng-click="gotoModify(task.uuid)">modify</a></li>
+                            <li role="menuitem" ng-show="task.status!=-1 && task.status!=0"><a ng-click="gotoReport(task.uuid)" style="color:#2ecc71">reporting</a></li>
+                            <li role="menuitem"><a ng-click="openDeleteEnv(task.uuid,'task')">delete</a></li>
+
+
+                        </ul>
+                    </div>
+                    <!-- <button class="btn btn-default btn-sm" ng-click="runAtask(task.uuid)" ng-disabled="task.status!=-1">run</button>
+                    <button class="btn btn-default btn-sm" ng-click="gotoDetail(task.uuid)">detail</button>
+                    <button class="btn btn-default btn-sm" ng-click="gotoModify(task.uuid)" ng-disabled="task.status==0">modify</button>
+                    <button class="btn btn-default btn-sm" ng-click="gotoReport(task.uuid)" style="color:#2ecc71" ng-disabled="task.status==-1 || task.status==0">reporting</button>
+                    <button class="btn btn-default btn-sm" ng-click="openDeleteEnv(task.uuid,'task')">delete</button>   -->
+
+                </td>
+
+            </tr>
+        </table>
+
+
+
+    </div>
+    <center>
+        <dir-pagination-controls pagination-id="table"></dir-pagination-controls>
+    </center>
+
+</div>
+
+
+
+</div>
+
+<toaster-container></toaster-container>
+
+<style>
+    .progree-parent {
+        width: 50%;
+        background-color: #dfe3e4;
+        height: 10px;
+        border-radius: 10px;
+    }
+
+    .progree-child {
+        width: 50%;
+        background-color: #2ecc71;
+        /* background-color: white; */
+        height: 10px;
+        border-radius: 5px;
+    }
+</style>
diff --git a/gui/app/views/report.html b/gui/app/views/report.html
new file mode 100644 (file)
index 0000000..78ac6a0
--- /dev/null
@@ -0,0 +1,56 @@
+<div class="content">
+    <i class="fa fa-arrow-left fa-1x" aria-hidden="true" style="color: #999;cursor:pointer" ng-click="goBack()">Back</i>
+    <h3>Yardstick Report </h3>
+    <hr/>
+    <div>
+
+        <div>Task ID : {{result.result.task_id}} </div>
+        <div style="margin-top:5px;">Criteria :
+            <font style="color:#2ECC71" ng-show="result.result.criteria=='PASS'"> {{result.result.criteria}}</font>
+            <font style="color:red" ng-show="result.result.criteria=='FAIL'"> {{result.result.criteria}}</font>
+        </div>
+        <hr/>
+        <caption>Information</caption>
+        <table class="table table-striped">
+            <tr>
+                <th>#</th>
+                <th>key</th>
+                <th>value</th>
+            </tr>
+            <tbody>
+                <tr ng-repeat="(key,value) in  result.result.info">
+                    <td>{{$index}}</td>
+                    <td>{{key}}</td>
+                    <td>{{value}}</td>
+                </tr>
+
+            </tbody>
+        </table>
+        <hr/>
+
+        <caption>Test Cases</caption>
+        <table class="table table-striped">
+            <tr>
+                <th>#</th>
+                <th>key</th>
+
+                <th>value</th>
+                <th>grafana</th>
+            </tr>
+            <tbody>
+                <tr ng-repeat="(key,value) in result.result.testcases">
+                    <td>{{$index}}</td>
+                    <td>{{key}}</td>
+
+                    <td>{{value.criteria}}</td>
+                    <td> <button class="btn btn-default btn-sm" ng-click="goToExternal(key)"> grafana</button></td>
+                </tr>
+            </tbody>
+        </table>
+
+    </div>
+</div>
+
+
+
+</div>
diff --git a/gui/app/views/suite.html b/gui/app/views/suite.html
new file mode 100644 (file)
index 0000000..8e13483
--- /dev/null
@@ -0,0 +1,149 @@
+<div class="content">
+    <!--suitelist-->
+    <i class="fa fa-arrow-left fa-1x" aria-hidden="true" style="color: #999;cursor:pointer" ng-click="goBack()">Back</i>
+
+    <div>
+        Test Suites
+        <button class="btn btn-default" style="margin-left:20px;" ng-click="gotoCreateSuite()">
+                                   Create
+
+                                    </button>
+
+        <!--<div ng-show="displayOpenrcFile!=null || displayOpenrcFile!=undefined">
+            {{displayOpenrcFile.name}} last modified: {{filelastModified}}
+        </div>-->
+        <hr/>
+
+        <!--<div ng-repeat="env in environmentList">
+            {{env.name}}
+        </div>-->
+        <div dw-loading="key" dw-loading-options="{text:'loading'}">
+        <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;background-color: #f9f9f9;" >
+            <div style="font-weight:600">Name</div>
+            <div style="font-weight:600;margin-right:4px;">Operate</div>
+
+        </div>
+
+
+        <div dir-paginate="suite in testsuitlist | itemsPerPage: 10">
+            <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;">
+                <div>
+                    <a style="color:#e95420"  ng-click="gotoDetail(suite)"> {{suite}}
+                    </a>
+                    </div>
+                <div>
+                    <!-- <button class="btn btn-default btn-sm" ng-click="gotoDetail(suite)">Detail</button> -->
+                    <button class="btn btn-default btn-sm" ng-click="openDeleteEnv(suite,'test suite')">Delete</button>
+                </div>
+
+            </div>
+
+        </div>
+        <center>
+            <dir-pagination-controls></dir-pagination-controls>
+        </center>
+        </div>
+
+
+
+
+
+
+
+
+    </div>
+
+
+
+
+</div>
+
+<toaster-container></toaster-container>
+
+<style>
+    .deepColor {
+        background-color: #f9f9f9;
+    }
+
+    .form-control {
+        border-radius: 5px;
+        width: 300px;
+        margin-bottom: 10px;
+    }
+
+    .uploadbutton {
+        background-color: #007ACC;
+        color: #fff;
+        border: 0px;
+        border-radius: 5px;
+        height: 27px;
+    }
+
+    .edit-title {
+        border: 0px;
+        background-color: #ffffff;
+        margin-bottom: 5px;
+    }
+
+    .null-edit-title {
+        border: 1px solid #e5e6e7;
+        border-radius: 5px;
+        margin-bottom: 3px;
+    }
+
+    .item-info {
+        display: flex;
+        flex-direction: row;
+    }
+
+    .delete-img {
+        width: 19px;
+        height: 19px;
+        opacity: 0.8;
+        margin-left: 5px;
+        margin-top: 4px;
+        cursor: pointer;
+    }
+
+    .nextButton {
+        margin-top: 30px;
+        border: none;
+        border-radius: 5px;
+        padding: 6px;
+        background-color: #339933;
+        color: #ffffff;
+        text-align: center;
+        /* margin-left: 300px; */
+    }
+
+    .bs-sidenav {
+        margin-top: 40px;
+        margin-bottom: 20px;
+        width: 124px;
+    }
+
+    .nav {
+        margin-bottom: 0;
+        padding-left: 0;
+        list-style: none;
+    }
+
+    .nav>li {
+        position: relative;
+        display: block;
+    }
+
+    li {
+        display: list-item;
+        text-align: -webkit-match-parent;
+    }
+
+    a {
+        cursor: pointer;
+    }
+
+    a.active {
+        background-color: #EEEEEE;
+        border-radius: 5px;
+    }
+</style>
diff --git a/gui/app/views/suitedetail.html b/gui/app/views/suitedetail.html
new file mode 100644 (file)
index 0000000..6122f65
--- /dev/null
@@ -0,0 +1,110 @@
+<div class="content">
+    <!--testcaselist-->
+    <div>
+        <i class="fa fa-arrow-left fa-1x" aria-hidden="true" style="color: #999;cursor:pointer" ng-click="goBack()">Back</i>
+
+        <h3>Detail</h3>
+        <hr/>
+
+        <textarea ng-model="suiteinfo" spellcheck="false">
+
+        </textarea>
+
+
+
+
+
+
+
+    </div>
+
+
+
+
+</div>
+
+<toaster-container></toaster-container>
+
+<style>
+    .form-control {
+        border-radius: 5px;
+        width: 300px;
+        margin-bottom: 10px;
+    }
+
+    .uploadbutton {
+        background-color: #007ACC;
+        color: #fff;
+        border: 0px;
+        border-radius: 5px;
+        height: 27px;
+    }
+
+    .edit-title {
+        border: 0px;
+        background-color: #ffffff;
+        margin-bottom: 5px;
+    }
+
+    .null-edit-title {
+        border: 1px solid #e5e6e7;
+        border-radius: 5px;
+        margin-bottom: 3px;
+    }
+
+    .item-info {
+        display: flex;
+        flex-direction: row;
+    }
+
+    .delete-img {
+        width: 19px;
+        height: 19px;
+        opacity: 0.8;
+        margin-left: 5px;
+        margin-top: 4px;
+        cursor: pointer;
+    }
+
+    .nextButton {
+        margin-top: 30px;
+        border: none;
+        border-radius: 5px;
+        padding: 6px;
+        background-color: #339933;
+        color: #ffffff;
+        text-align: center;
+        /* margin-left: 300px; */
+    }
+
+    .bs-sidenav {
+        margin-top: 40px;
+        margin-bottom: 20px;
+        width: 124px;
+    }
+
+    .nav {
+        margin-bottom: 0;
+        padding-left: 0;
+        list-style: none;
+    }
+
+    .nav>li {
+        position: relative;
+        display: block;
+    }
+
+    li {
+        display: list-item;
+        text-align: -webkit-match-parent;
+    }
+
+    a {
+        cursor: pointer;
+    }
+
+    a.active {
+        background-color: #EEEEEE;
+        border-radius: 5px;
+    }
+</style>
diff --git a/gui/app/views/taskList.html b/gui/app/views/taskList.html
new file mode 100644 (file)
index 0000000..159fed5
--- /dev/null
@@ -0,0 +1,62 @@
+<div class="content">
+    <i class="fa fa-arrow-left fa-1x" aria-hidden="true" style="color: #999;cursor:pointer" ng-click="goBack()">Back</i>
+    <h3>Detail</h3>
+    <hr/>
+    <div style="display:flex;flex-direction:row">
+        <div>
+            <h4>{{taskDetailData.name}}</h4>
+            <div style="margin-top:5px;">{{taskDetailData.time}}</div>
+        </div>
+        <div class="progree-parent" ng-show="taskDetailData.status!=2" style="margin-top:34px;margin-left:30px;">
+            <div class="progree-child" ng-style="{'width':taskDetailData.stausWidth}">
+            </div>
+
+        </div>
+        <div class="progree-parent" ng-show="taskDetailData.status==2" style="background-color:red;margin-top:34px;margin-left:30px;">
+            <div class="progree-child" style="width:0">
+            </div>
+        </div>
+        <i class="fa fa-check" aria-hidden="true" style="margin-top:34px;margin-left:5px;color: #2ecc71;" ng-show="taskDetailData.status==1">finish</i>
+        <i class="fa fa-spinner" aria-hidden="true" style="margin-top:34px;margin-left:5px;color: #2ecc71;" ng-show="taskDetailData.status==0">runing</i>
+        <i class="fa fa-exclamation-triangle" aria-hidden="true" style="margin-top:34px;margin-left:5px;color: red;" ng-show="taskDetailData.status==2">failed</i>
+    </div>
+
+    <div style="margin-top:5px;">Environment : {{displayEnv.name}} </div>
+    <div ng-show="taskDetailData.case_name!=false" style="margin-top:5px;margin-bottom:5px;"> Name : {{taskDetailData.case_name}}</div>
+    <textarea ng-model="taskDetailData.content" spellcheck="false">
+
+    </textarea>
+
+    <div style="text-align:center;margin-top:20px;">
+        <button class="btn btn-default" ng-click="createTask(name)" ng-show="">Run</button>
+    </div>
+</div>
+
+
+<style>
+    input {
+        border-radius: 10px;
+        border: 1px solid #eeeeee;
+        width: 100%;
+    }
+
+    select {
+        height: 30px;
+        border-radius: 5px;
+        border: 1px solid #e8e8e8;
+        width: 135px;
+        margin-top: 20px;
+        margin-left: 20px;
+    }
+
+    textarea {
+        width: 100%;
+        height: 350px;
+        border-radius: 5px;
+        border: 1px solid #e8e8e8;
+    }
+
+    .content {
+        height: 90%;
+    }
+</style>
diff --git a/gui/app/views/taskmodify.html b/gui/app/views/taskmodify.html
new file mode 100644 (file)
index 0000000..a4593f7
--- /dev/null
@@ -0,0 +1,162 @@
+<div class="content">
+    <i class="fa fa-arrow-left fa-1x" aria-hidden="true" style="color: #999;cursor:pointer" ng-click="goBack()">Back</i>
+    <h4>Modify </h4>
+
+    <hr/>
+
+    <div>
+        <div style="display:inline">Name <input type="text" ng-model="taskDetailData.name" style="width:200px" /></div>
+
+        <button class="btn btn-default" ng-click="runAtask()" style="float:right;margin-right:10px;">Run</button>
+    </div>
+    <hr/>
+
+    <div bs-tabs>
+        <div data-title="Environment" bs-pane>
+            <div style="margin-top:10px">
+                <div style="display:inline">Choose Environment : {{envName}}</div>
+                <button class="btn btn-default" style="display:inline;float:right;margin-right:10px;margin-top: -4px;" ng-click="addEnvToTask()">Confirm</button>
+            </div>
+            <hr />
+            <div dir-paginate="env in environmentList | orderBy:'-id' | itemsPerPage: 10 ">
+                <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;" ng-class="{deepColor: $index%2==0}">
+                    <div> {{env.name}}</div>
+                    <!--<button class="btn btn-default btn-sm" ng-click="gotoDetail('false',env.uuid)">detail</button>-->
+                    <img src="images/checkyes.png" style="height:18px;cursor:pointer" ng-click="constructTestSuit(env.uuid,env.name)" ng-show="selectEnv==env.uuid" />
+                    <img src="images/checkno.png" style="height:18px;cursor:pointer" ng-click="constructTestSuit(env.uuid,env.name)" ng-show="selectEnv!=env.uuid" />
+
+                </div>
+                <!--<hr style="margin-top:5px;margin-bottom:5px;" />-->
+            </div>
+            <center>
+                <dir-pagination-controls></dir-pagination-controls>
+            </center>
+
+        </div>
+        <div data-title="Content" bs-pane>
+            <div style="margin-top:10px;">
+                <button class="btn btn-default" ng-click="changeStatussourceFalse()">Modify Content</button>
+                <button class="btn btn-default" ng-click="changeStatussourceTrue()">Modify Source</button>
+                <div class="label-type" ng-show="taskDetailData.suite==false"> Test Case</div>
+                <div class="label-type" ng-show="taskDetailData.suite==true"> Test Suite</div>
+                <button class="btn btn-default" style="float:right" ng-disabled="sourceShow==null" ng-click="confirmToServer(contentInfo,taskDetailData.content)">Confirm</button>
+            </div>
+
+
+            <textarea ng-model="taskDetailData.content" ng-show="sourceShow==false" style="margin-top:5px;" spellcheck="false">
+
+
+            </textarea>
+
+            <div ng-show="sourceShow==true">
+                <div style="display:flex;flex-direction:row">
+                    <div style="margin-top:20px;">Source of Content</div>
+
+
+                    <select ng-model="selectType" ng-change="triggerContent(selectType)" data-ng-options="blisterPackTemplate as blisterPackTemplate.name for blisterPackTemplate in blisterPackTemplates">
+                  <option value="">Choose...</option>
+            </select>
+
+                </div>
+
+                <div style="margin-top:10px" ng-show="selectCase!=null ">
+                    <div style="display:inline">Choose Source : {{selectCase}}</div>
+                    <!--<button class="btn btn-default" style="display:inline;float:right;margin-right:10px;margin-top: -4px;" ng-click="confirmAddCaseOrSuite(contentInfo)">Confirm</button>-->
+                    <button class="btn btn-default" style="display:inline;float:right;margin-right:10px;margin-top: -4px;" ng-click="getTestDeatil()">Edit</button>
+                </div>
+                <hr/>
+
+                <div ng-show="displayTable==true">
+                    <div ng-show="testcaselist.testcases.length!=0 && selectType.name=='Test Case'">
+                        <div dir-paginate="test in testcaselist.testcases | itemsPerPage: 10" pagination-id="testcase">
+                            <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;" ng-class="{deepColor: $index%2==0}">
+                                <div> {{test.Name}}</div>
+                                <div style="font-size:10px;">{{test.Description}}</div>
+                                <img src="images/checkyes.png" style="height:18px;cursor:pointer" ng-click="constructTestCase(test.Name)" ng-show="selectCase==test.Name" />
+                                <img src="images/checkno.png" style="height:18px;cursor:pointer" ng-click="constructTestCase(test.Name)" ng-show="selectCase!=test.Name" />
+
+                            </div>
+                            <!--<hr style="margin-top:5px;margin-bottom:5px;" />-->
+                        </div>
+                        <center>
+                            <dir-pagination-controls pagination-id="testcase"></dir-pagination-controls>
+                        </center>
+                    </div>
+
+                    <div ng-show="testsuitlist.length!=0 && selectType.name=='Test Suite'">
+                        <div dir-paginate="suite in testsuitlist | itemsPerPage: 10" pagination-id="testsuite">
+                            <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;" ng-class="{deepColor: $index%2==0}">
+                                <div> {{suite}}</div>
+
+                                <img src="images/checkyes.png" style="height:18px;cursor:pointer" ng-click="constructTestCase(suite)" ng-show="selectCase==suite" />
+                                <img src="images/checkno.png" style="height:18px;cursor:pointer" ng-click="constructTestCase(suite)" ng-show="selectCase!=suite" />
+
+                            </div>
+                            <!--<hr style="margin-top:5px;margin-bottom:5px;" />-->
+                        </div>
+                        <center>
+                            <dir-pagination-controls pagination-id="testsuite"></dir-pagination-controls>
+                        </center>
+                    </div>
+                </div>
+
+                <div ng-show="displayTable==false">
+                    <textarea ng-model="contentInfo" spellcheck="false">
+            </textarea>
+
+
+                </div>
+            </div>
+
+
+
+
+        </div>
+    </div>
+
+
+</div>
+<toaster-container></toaster-container>
+
+
+<style>
+    input {
+        border-radius: 10px;
+        border: 1px solid #eeeeee;
+        width: 100%;
+        padding: 5px;
+    }
+
+    .deepColor {
+        background-color: #f9f9f9;
+    }
+
+    select {
+        height: 30px;
+        border-radius: 5px;
+        border: 1px solid #e8e8e8;
+        width: 135px;
+        margin-top: 20px;
+        margin-left: 20px;
+    }
+
+    textarea {
+        width: 100%;
+        height: 350px;
+        border-radius: 5px;
+        border: 1px solid #e8e8e8;
+    }
+
+    .label-type {
+        display: inline;
+        background-color: #2ecc71;
+        color: #fff;
+        border-radius: 5px;
+        padding: 3px;
+        font-size: 10px;
+    }
+
+    .content {
+        height: auto;
+    }
+</style>
diff --git a/gui/app/views/testcasechoose.html b/gui/app/views/testcasechoose.html
new file mode 100644 (file)
index 0000000..12bdb83
--- /dev/null
@@ -0,0 +1,48 @@
+<div class="content">
+
+    <div>
+        Test case list
+        <button class="btn btn-default" style="margin-left:20px;" ng-click="openDialog()">
+                                    <div ng-show="!loadingOPENrc">Create </div>
+                                     <img src="images/loading2.gif" width="25" height="25" ng-if="loadingOPENrc" />
+                                    </button>
+
+
+        <hr/> You have choose :
+        <div ng-repeat="selected in suitReconstructList" style="display:inline;" class="item">{{selected}}</div>
+        <hr/>
+
+        <!--<div ng-repeat="env in environmentList">
+            {{env.name}}
+        </div>-->
+        <div dir-paginate="test in testcaselist.testcases | itemsPerPage: 10">
+            <div style="display:flex;flex-direction:row;">
+                <img src="images/checkyes.png" style="height:12px;cursor:pointer" ng-click="constructTestSuit(test.Name)" ng-show="testsuiteList.indexOf(test.Name)>-1" />
+                <img src="images/checkno.png" style="height:12px;cursor:pointer" ng-click="constructTestSuit(test.Name)" ng-show="testsuiteList.indexOf(test.Name)==-1" />
+                <div style="margin-left:50px;"> {{test.Name}}</div>
+                <div style="font-size:10px;margin-left:100px">{{test.Description}}</div>
+
+            </div>
+            <hr style="margin-top:5px;margin-bottom:5px;" />
+        </div>
+        <center>
+            <dir-pagination-controls></dir-pagination-controls>
+        </center>
+
+
+
+    </div>
+    <toaster-container></toaster-container>
+
+    <style>
+        .item {
+            background-color: #3498db;
+            color: #fff;
+            width: 150px;
+            border-radius: 5px;
+            padding-left: 10px;
+            margin-left: 2px;
+            margin-top: 3px;
+            padding: 4px;
+        }
+    </style>
diff --git a/gui/app/views/testcasedetail.html b/gui/app/views/testcasedetail.html
new file mode 100644 (file)
index 0000000..43a5153
--- /dev/null
@@ -0,0 +1,110 @@
+<div class="content">
+    <!--testcaselist-->
+    <div>
+        <i class="fa fa-arrow-left fa-1x" aria-hidden="true" style="color: #999;cursor:pointer" ng-click="goBack()">Back</i>
+
+        <h4>Detail</h4>
+        <hr/>
+
+        <textarea ng-model="testcaseInfo" spellcheck="false">
+
+        </textarea>
+
+
+
+
+
+
+
+    </div>
+
+
+
+
+</div>
+
+<toaster-container></toaster-container>
+
+<style>
+    .form-control {
+        border-radius: 5px;
+        width: 300px;
+        margin-bottom: 10px;
+    }
+
+    .uploadbutton {
+        background-color: #007ACC;
+        color: #fff;
+        border: 0px;
+        border-radius: 5px;
+        height: 27px;
+    }
+
+    .edit-title {
+        border: 0px;
+        background-color: #ffffff;
+        margin-bottom: 5px;
+    }
+
+    .null-edit-title {
+        border: 1px solid #e5e6e7;
+        border-radius: 5px;
+        margin-bottom: 3px;
+    }
+
+    .item-info {
+        display: flex;
+        flex-direction: row;
+    }
+
+    .delete-img {
+        width: 19px;
+        height: 19px;
+        opacity: 0.8;
+        margin-left: 5px;
+        margin-top: 4px;
+        cursor: pointer;
+    }
+
+    .nextButton {
+        margin-top: 30px;
+        border: none;
+        border-radius: 5px;
+        padding: 6px;
+        background-color: #339933;
+        color: #ffffff;
+        text-align: center;
+        /* margin-left: 300px; */
+    }
+
+    .bs-sidenav {
+        margin-top: 40px;
+        margin-bottom: 20px;
+        width: 124px;
+    }
+
+    .nav {
+        margin-bottom: 0;
+        padding-left: 0;
+        list-style: none;
+    }
+
+    .nav>li {
+        position: relative;
+        display: block;
+    }
+
+    li {
+        display: list-item;
+        text-align: -webkit-match-parent;
+    }
+
+    a {
+        cursor: pointer;
+    }
+
+    a.active {
+        background-color: #EEEEEE;
+        border-radius: 5px;
+    }
+</style>
diff --git a/gui/app/views/testcaselist.html b/gui/app/views/testcaselist.html
new file mode 100644 (file)
index 0000000..3e8cfcc
--- /dev/null
@@ -0,0 +1,150 @@
+<div class="content">
+    <!--testcaselist-->
+    <i class="fa fa-arrow-left fa-1x" aria-hidden="true" style="color: #999;cursor:pointer" ng-click="goBack()">Back</i>
+
+    <div>
+        Test Cases
+        <button class="btn btn-default" style="margin-left:20px;" ngf-select="uploadFiles($file, $invalidFiles)" ngf-max-size="5MB">
+                                    <div ng-show="!loadingOPENrc">Upload</div>
+                                     <img src="images/loading2.gif" width="25" height="25" ng-if="loadingOPENrc" />
+                                    </button>
+
+        <!--<div ng-show="displayOpenrcFile!=null || displayOpenrcFile!=undefined">
+            {{displayOpenrcFile.name}} last modified: {{filelastModified}}
+        </div>-->
+        <hr/>
+
+        <!--<div ng-repeat="env in environmentList">
+            {{env.name}}
+        </div>-->
+        <div dw-loading="key" dw-loading-options="{text:'loading'}">
+        <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;background-color: #f9f9f9">
+            <div style="font-weight:600">Name</div>
+            <div style="font-weight:600;margin-right:4px;">Operate</div>
+
+        </div>
+
+        <div dir-paginate="test in testcaselist.testcases | itemsPerPage: 10">
+            <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;">
+                <div>
+
+                   <a style="color:#e95420" ng-click="gotoDetail(test.Name)">
+                       {{test.Name}}
+                   </a>
+                    </div>
+                <div style="font-size:10px;">{{test.Description}}</div>
+                <div>
+                    <!-- <button class="btn btn-default btn-sm" ng-click="gotoDetail(test.Name)">Detail</button> -->
+                    <button class="btn btn-default btn-sm" ng-click="openDeleteEnv(test.Name,'test case')">Delete</button>
+                </div>
+
+            </div>
+
+        </div>
+        <center>
+            <dir-pagination-controls></dir-pagination-controls>
+        </center>
+        </div>
+
+
+
+
+
+
+
+    </div>
+
+
+
+
+</div>
+
+<toaster-container></toaster-container>
+
+<style>
+    .deepColor {
+        background-color: #f9f9f9;
+    }
+
+    .form-control {
+        border-radius: 5px;
+        width: 300px;
+        margin-bottom: 10px;
+    }
+
+    .uploadbutton {
+        background-color: #007ACC;
+        color: #fff;
+        border: 0px;
+        border-radius: 5px;
+        height: 27px;
+    }
+
+    .edit-title {
+        border: 0px;
+        background-color: #ffffff;
+        margin-bottom: 5px;
+    }
+
+    .null-edit-title {
+        border: 1px solid #e5e6e7;
+        border-radius: 5px;
+        margin-bottom: 3px;
+    }
+
+    .item-info {
+        display: flex;
+        flex-direction: row;
+    }
+
+    .delete-img {
+        width: 19px;
+        height: 19px;
+        opacity: 0.8;
+        margin-left: 5px;
+        margin-top: 4px;
+        cursor: pointer;
+    }
+
+    .nextButton {
+        margin-top: 30px;
+        border: none;
+        border-radius: 5px;
+        padding: 6px;
+        background-color: #339933;
+        color: #ffffff;
+        text-align: center;
+        /* margin-left: 300px; */
+    }
+
+    .bs-sidenav {
+        margin-top: 40px;
+        margin-bottom: 20px;
+        width: 124px;
+    }
+
+    .nav {
+        margin-bottom: 0;
+        padding-left: 0;
+        list-style: none;
+    }
+
+    .nav>li {
+        position: relative;
+        display: block;
+    }
+
+    li {
+        display: list-item;
+        text-align: -webkit-match-parent;
+    }
+
+    a {
+        cursor: pointer;
+    }
+
+    a.active {
+        background-color: #EEEEEE;
+        border-radius: 5px;
+    }
+</style>
diff --git a/gui/app/views/uploadImage.html b/gui/app/views/uploadImage.html
new file mode 100644 (file)
index 0000000..17ccfdb
--- /dev/null
@@ -0,0 +1,145 @@
+<!--upload image  page-->
+
+<div class="content">
+    <div style="display:flex;flex-direction:row;">
+        <div style="width:750px;">
+
+            <h3>{{baseElementInfo.name}} -- Image
+                <button class="btn btn-default" style="float:right" ng-click="goNext()">Next</button>
+            </h3>
+            <!--<p>In this process, you can input your define openrc config or upload a openrc file</p>-->
+
+            <hr/>
+            <button class="btn btn-default" ng-click="uploadImage()">
+                 <div ng-if="!showloading">Load Image</div>
+                 <img src="images/loading2.gif" width="25" height="25" ng-if="showloading" />
+            </button>
+            <i class="fa fa-check" aria-hidden="true" style="margin-top:34px;margin-left:5px;color: #2ecc71;" ng-show="imageStatus==1&&ifshowStatus==1">done</i>
+            <i class="fa fa-spinner" aria-hidden="true" style="margin-top:34px;margin-left:5px;color: #2ecc71;" ng-show="imageStatus==0&&ifshowStatus==1">loading</i>
+            <i class="fa fa-exclamation-triangle" aria-hidden="true" style="margin-top:34px;margin-left:5px;color: red;" ng-show="imageStatus==2&&ifshowStatus==1">error</i>
+
+            <hr>
+            <h4>Current Images</h4>
+
+            <div>
+                <table class="table table-striped">
+
+                    <tr>
+                        <th>name</th>
+                        <th>size</th>
+                        <th>status</th>
+                        <th>time</th>
+                    </tr>
+                    <tr ng-repeat="image in imageListData">
+                        <td>{{image.name}}</td>
+                        <td>{{image.size/1024}} MB</td>
+                        <td>{{image.status}}</td>
+                        <td>{{image.time}}</td>
+
+                    </tr>
+
+
+
+                </table>
+            </div>
+
+
+
+
+
+
+
+
+
+        </div>
+
+
+    </div>
+
+</div>
+<toaster-container></toaster-container>
+
+<style>
+    .form-control {
+        border-radius: 5px;
+        width: 200px;
+        margin-bottom: 10px;
+    }
+
+    .uploadbutton {
+        background-color: #007ACC;
+        color: #fff;
+        border: 0px;
+        border-radius: 5px;
+        height: 27px;
+    }
+
+    .edit-title {
+        border: 0px;
+        background-color: #ffffff;
+        margin-bottom: 5px;
+        font-size: 12px;
+    }
+
+    .null-edit-title {
+        border: 1px solid #e5e6e7;
+        border-radius: 5px;
+        margin-bottom: 3px;
+    }
+
+    .item-info {
+        display: flex;
+        flex-direction: row;
+    }
+
+    .delete-img {
+        width: 15px;
+        height: 15px;
+        opacity: 0.8;
+        margin-left: -10px;
+        margin-top: -3px;
+        cursor: pointer;
+    }
+
+    .nextButton {
+        margin-top: 30px;
+        border: none;
+        border-radius: 5px;
+        padding: 6px;
+        background-color: #339933;
+        color: #ffffff;
+        text-align: center;
+        /* margin-left: 300px; */
+    }
+
+    .bs-sidenav {
+        margin-top: 40px;
+        margin-bottom: 20px;
+        width: 124px;
+    }
+
+    .nav {
+        margin-bottom: 0;
+        padding-left: 0;
+        list-style: none;
+    }
+
+    .nav>li {
+        position: relative;
+        display: block;
+    }
+
+    li {
+        display: list-item;
+        text-align: -webkit-match-parent;
+    }
+
+    a {
+        cursor: pointer;
+    }
+
+    a.active {
+        background-color: #EEEEEE;
+        border-radius: 5px;
+    }
+</style>
diff --git a/gui/bower.json b/gui/bower.json
new file mode 100644 (file)
index 0000000..6da3bee
--- /dev/null
@@ -0,0 +1,45 @@
+{
+  "name": "yard-stick-gui2",
+  "version": "0.0.0",
+  "dependencies": {
+    "angular": "^1.4.0",
+    "bootstrap": "^3.2.0",
+    "angular-strap": "^2.3.12",
+    "angular-ui-router": "^1.0.3",
+    "angular-animate": "^1.6.4",
+    "angular-breadcrumb": "^0.5.0",
+    "angular-wizard": "^0.10.0",
+    "angular-resource": "^1.6.4",
+    "ng-file-upload": "^12.2.13",
+    "AngularJS-Toaster": "angularjs-toaster#^2.1.0",
+    "ng-dialog": "^1.3.0",
+    "angularUtils-pagination": "angular-utils-pagination#^0.11.1",
+    "components-font-awesome": "^4.7.0",
+    "ngstorage": "^0.3.11",
+    "v-accordion": "^1.6.0",
+    "angular-loading": "^0.1.4",
+    "angular-bootstrap": "^2.5.0",
+    "angular-sanitize": "^1.6.5"
+  },
+  "devDependencies": {
+    "angular-mocks": "^1.4.0"
+  },
+  "appPath": "app",
+  "moduleName": "yardStickGui2App",
+  "overrides": {
+    "bootstrap": {
+      "main": [
+        "less/bootstrap.less",
+        "dist/css/bootstrap.css",
+        "dist/js/bootstrap.js"
+      ]
+    },
+    "angular-loading": {
+      "main": [
+        "angular-loading.css",
+        "angular-loading.js",
+        "../spin.js/spin.js"
+      ]
+    }
+  }
+}
diff --git a/gui/gui.sh b/gui/gui.sh
new file mode 100755 (executable)
index 0000000..12a1492
--- /dev/null
@@ -0,0 +1,8 @@
+apt-get install -y nodejs
+apt-get install -y npm
+ln -s /usr/bin/nodejs /usr/bin/node
+npm install
+npm install -g grunt
+npm install -g bower
+bower install --force --allow-root
+grunt build
diff --git a/gui/package.json b/gui/package.json
new file mode 100644 (file)
index 0000000..b85c754
--- /dev/null
@@ -0,0 +1,43 @@
+{
+  "name": "yardstickgui2",
+  "private": true,
+  "devDependencies": {
+    "autoprefixer-core": "^5.2.1",
+    "grunt": "^0.4.5",
+    "grunt-angular-templates": "^0.5.7",
+    "grunt-concurrent": "^1.0.0",
+    "grunt-contrib-clean": "^0.6.0",
+    "grunt-contrib-concat": "^0.5.0",
+    "grunt-contrib-connect": "^0.9.0",
+    "grunt-contrib-copy": "^0.7.0",
+    "grunt-contrib-cssmin": "^0.12.0",
+    "grunt-contrib-htmlmin": "^0.4.0",
+    "grunt-contrib-imagemin": "^1.0.0",
+    "grunt-contrib-jshint": "^0.11.0",
+    "grunt-contrib-uglify": "^0.7.0",
+    "grunt-contrib-watch": "^0.6.1",
+    "grunt-filerev": "^2.1.2",
+    "grunt-google-cdn": "^0.4.3",
+    "grunt-jscs": "^1.8.0",
+    "grunt-newer": "^1.1.0",
+    "grunt-ng-annotate": "^0.9.2",
+    "grunt-postcss": "^0.5.5",
+    "grunt-svgmin": "^2.0.0",
+    "grunt-usemin": "^3.0.0",
+    "grunt-wiredep": "^2.0.0",
+    "jasmine-core": "^2.6.2",
+    "jit-grunt": "^0.9.1",
+    "jshint-stylish": "^1.0.0",
+    "karma": "^1.7.0",
+    "karma-jasmine": "^1.1.0",
+    "karma-phantomjs-launcher": "^1.0.4",
+    "phantomjs-prebuilt": "^2.1.14",
+    "time-grunt": "^1.0.0"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "scripts": {
+    "test": "karma start test\\karma.conf.js"
+  }
+}
diff --git a/gui/test/.jshintrc b/gui/test/.jshintrc
new file mode 100644 (file)
index 0000000..b2ce4ef
--- /dev/null
@@ -0,0 +1,18 @@
+{
+  "bitwise": true,
+  "browser": true,
+  "curly": true,
+  "eqeqeq": true,
+  "esnext": true,
+  "jasmine": true,
+  "latedef": true,
+  "noarg": true,
+  "node": true,
+  "strict": true,
+  "undef": true,
+  "unused": true,
+  "globals": {
+    "angular": false,
+    "inject": false
+  }
+}
diff --git a/gui/test/karma.conf.js b/gui/test/karma.conf.js
new file mode 100644 (file)
index 0000000..a9ab3a8
--- /dev/null
@@ -0,0 +1,93 @@
+// Karma configuration
+// Generated on 2017-05-31
+
+module.exports = function(config) {
+  'use strict';
+
+  config.set({
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+    // base path, that will be used to resolve files and exclude
+    basePath: '../',
+
+    // testing framework to use (jasmine/mocha/qunit/...)
+    // as well as any additional frameworks (requirejs/chai/sinon/...)
+    frameworks: [
+      'jasmine'
+    ],
+
+    // list of files / patterns to load in the browser
+    files: [
+      // bower:js
+      'bower_components/jquery/dist/jquery.js',
+      'bower_components/angular/angular.js',
+      'bower_components/bootstrap/dist/js/bootstrap.js',
+      'bower_components/angular-strap/dist/angular-strap.js',
+      'bower_components/angular-strap/dist/angular-strap.tpl.js',
+      'bower_components/angular-ui-router/release/angular-ui-router.js',
+      'bower_components/angular-animate/angular-animate.js',
+      'bower_components/angular-breadcrumb/release/angular-breadcrumb.js',
+      'bower_components/angular-wizard/dist/angular-wizard.min.js',
+      'bower_components/angular-resource/angular-resource.js',
+      'bower_components/ng-file-upload/ng-file-upload.js',
+      'bower_components/AngularJS-Toaster/toaster.js',
+      'bower_components/ng-dialog/js/ngDialog.js',
+      'bower_components/angularUtils-pagination/dirPagination.js',
+      'bower_components/ngstorage/ngStorage.js',
+      'bower_components/v-accordion/dist/v-accordion.js',
+      'bower_components/spin.js/spin.js',
+      'bower_components/angular-loading/angular-loading.js',
+      'bower_components/spin.js/spin.js',
+      'bower_components/angular-bootstrap/ui-bootstrap-tpls.js',
+      'bower_components/angular-sanitize/angular-sanitize.js',
+      'bower_components/angular-mocks/angular-mocks.js',
+      // endbower
+      'app/scripts/**/*.js',
+      'test/mock/**/*.js',
+      'test/spec/**/*.js'
+    ],
+
+    // list of files / patterns to exclude
+    exclude: [
+    ],
+
+    // web server port
+    port: 8080,
+
+    // Start these browsers, currently available:
+    // - Chrome
+    // - ChromeCanary
+    // - Firefox
+    // - Opera
+    // - Safari (only Mac)
+    // - PhantomJS
+    // - IE (only Windows)
+    browsers: [
+      'PhantomJS'
+    ],
+
+    // Which plugins to enable
+    plugins: [
+      'karma-phantomjs-launcher',
+      'karma-jasmine'
+    ],
+
+    // Continuous Integration mode
+    // if true, it capture browsers, run tests and exit
+    singleRun: false,
+
+    colors: true,
+
+    // level of logging
+    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+    // Uncomment the following lines if you are using grunt's server to run the tests
+    // proxies: {
+    //   '/': 'http://localhost:9000/'
+    // },
+    // URL root prevent conflicts with the site root
+    // urlRoot: '_karma_'
+  });
+};
diff --git a/gui/test/spec/controllers/main.js b/gui/test/spec/controllers/main.js
new file mode 100644 (file)
index 0000000..27e0a5a
--- /dev/null
@@ -0,0 +1,23 @@
+'use strict';
+
+describe('Controller: MainCtrl', function () {
+
+  // load the controller's module
+  beforeEach(module('yardStickGui2App'));
+
+  var MainCtrl,
+    scope;
+
+  // Initialize the controller and a mock scope
+  beforeEach(inject(function ($controller, $rootScope) {
+    scope = $rootScope.$new();
+    MainCtrl = $controller('MainCtrl', {
+      $scope: scope
+      // place here mocked dependencies
+    });
+  }));
+
+  it('should attach a list of awesomeThings to the scope', function () {
+    expect(MainCtrl.awesomeThings.length).toBe(3);
+  });
+});
index ad14b8e..e82ae02 100755 (executable)
@@ -86,7 +86,10 @@ easy_install -U pip
 pip install -r requirements.txt
 pip install -e .
 
-/bin/bash "$(pwd)/api/api-prepare.sh"
+/bin/bash "${PWD}/docker/uwsgi.sh"
+/bin/bash "${PWD}/docker/nginx.sh"
+cd "${PWD}/gui" && /bin/bash gui.sh
+mv dist /etc/nginx/yardstick/gui
 
 service nginx restart
 uwsgi -i /etc/yardstick/yardstick.ini