Design the scenario create method 39/50039/7
authorSerenaFeng <feng.xiaowei@zte.com.cn>
Fri, 5 Jan 2018 06:39:12 +0000 (14:39 +0800)
committerthuva4 <tharma.thuva@gmail.com>
Tue, 9 Jan 2018 14:26:56 +0000 (19:56 +0530)
design scenario create method in modal way.
design scenario page.
Add,delete for installers,versions, projects, customs, trust
indicators and scores are implemented.
tests are not included. validations are not added.

Change-Id: I999229c00869fcd5a4efa97cb2679a08fc24b271
Signed-off-by: thuva4 <tharma.thuva@gmail.com>
21 files changed:
testapi/docker/Dockerfile
testapi/opnfv_testapi/common/check.py
testapi/opnfv_testapi/handlers/base_handlers.py
testapi/opnfv_testapi/models/testcase_models.py
testapi/opnfv_testapi/tests/unit/handlers/test_scenario.py
testapi/opnfv_testapi/ui/app.js
testapi/opnfv_testapi/ui/components/scenarios/modals/customModal.html [new file with mode: 0644]
testapi/opnfv_testapi/ui/components/scenarios/modals/installerModal.html [new file with mode: 0644]
testapi/opnfv_testapi/ui/components/scenarios/modals/projectModal.html [new file with mode: 0644]
testapi/opnfv_testapi/ui/components/scenarios/modals/scenarioModal.html [new file with mode: 0644]
testapi/opnfv_testapi/ui/components/scenarios/modals/scenarioNameUpdate.html [new file with mode: 0644]
testapi/opnfv_testapi/ui/components/scenarios/modals/scoreModal.html [new file with mode: 0644]
testapi/opnfv_testapi/ui/components/scenarios/modals/trustIndicatorModal.html [new file with mode: 0644]
testapi/opnfv_testapi/ui/components/scenarios/modals/versionModal.html [new file with mode: 0644]
testapi/opnfv_testapi/ui/components/scenarios/scenario/scenario.html [new file with mode: 0644]
testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js [new file with mode: 0644]
testapi/opnfv_testapi/ui/components/scenarios/scenarios.html [new file with mode: 0644]
testapi/opnfv_testapi/ui/components/scenarios/scenariosController.js [new file with mode: 0644]
testapi/opnfv_testapi/ui/index.html
testapi/opnfv_testapi/ui/shared/header/header.html
testapi/requirements.txt

index 33088c7..bbf12fc 100644 (file)
@@ -40,7 +40,7 @@ python-pip \
 crudini \
 --no-install-recommends
 
-RUN pip install --upgrade pip
+RUN pip install --upgrade pip requests
 
 RUN git config --global http.sslVerify false
 RUN git clone https://gerrit.opnfv.org/gerrit/releng-testresults /home/releng-testresults
@@ -48,10 +48,5 @@ RUN git clone https://gerrit.opnfv.org/gerrit/releng-testresults /home/releng-te
 WORKDIR /home/releng-testresults/testapi
 RUN pip install -r requirements.txt
 
-# bugfix
-# SSLError: hostname 'identity.linuxfoundation.org' doesn't match 'c.sni.fastly.net'
-# hope it is a temprary, try to fix it in upstream python-cas lib
-RUN sed -i '152,152s/)/,\ verify=False)/g' /usr/local/lib/python2.7/dist-packages/cas.py
-
 RUN python setup.py install
 CMD ["bash", "docker/start-server.sh"]
index 333871d..9b3ab01 100644 (file)
@@ -21,7 +21,7 @@ from opnfv_testapi.db import api as dbapi
 def is_authorized(method):
     @functools.wraps(method)
     def wrapper(self, *args, **kwargs):
-        if CONF.api_authenticate and self.table in ['pods', 'projects', 'testcases']:
+        if CONF.api_authenticate and self.table in ['pods', 'projects', 'testcases', 'scenarios']:
             testapi_id = self.get_secure_cookie(constants.TESTAPI_ID)
             if not testapi_id:
                 raises.Unauthorized(message.not_login())
index 9eac737..537077d 100644 (file)
@@ -200,6 +200,7 @@ class GenericApiHandler(web.RequestHandler):
     @gen.coroutine
     @check.no_body
     @check.not_exist
+    @check.is_authorized
     @check.updated_one_not_exist
     def pure_update(self, data, query=None, **kwargs):
         data = self.table_cls.from_dict(data)
index 1a55cf7..96195b2 100644 (file)
@@ -51,8 +51,10 @@ class TestcaseUpdateRequest(TestcaseCreateRequest):
 
 @swagger.model()
 class Testcase(TestcaseCreateRequest):
-    def __init__(self, _id=None, **kwargs):
-        self._id = None
+    def __init__(self, **kwargs):
+        self._id = kwargs.pop('_id', '')
+        self.project_name = kwargs.pop('project_name', '')
+        self.creation_date = kwargs.pop('creation_date', '')
         super(Testcase, self).__init__(**kwargs)
 
 
index 5d1b738..481078d 100644 (file)
@@ -4,6 +4,7 @@ import httplib
 
 from opnfv_testapi.common import message
 import opnfv_testapi.models.scenario_models as sm
+from opnfv_testapi.tests.unit import executor
 from opnfv_testapi.tests.unit.handlers import test_base as base
 
 
@@ -20,6 +21,7 @@ class TestScenarioBase(base.TestBase):
         self.req_d = self.load_json('scenario-c1')
         self.req_2 = self.load_json('scenario-c2')
 
+    @executor.mock_valid_lfid()
     def create_return_name(self, req):
         _, res = self.create(req)
         return res.href.split('/')[-1]
@@ -45,27 +47,32 @@ class TestScenarioBase(base.TestBase):
 
 
 class TestScenarioCreate(TestScenarioBase):
+    @executor.mock_valid_lfid()
     def test_withoutBody(self):
         (code, body) = self.create()
         self.assertEqual(code, httplib.BAD_REQUEST)
 
+    @executor.mock_valid_lfid()
     def test_emptyName(self):
         req_empty = sm.ScenarioCreateRequest('')
         (code, body) = self.create(req_empty)
         self.assertEqual(code, httplib.BAD_REQUEST)
         self.assertIn(message.missing('name'), body)
 
+    @executor.mock_valid_lfid()
     def test_noneName(self):
         req_none = sm.ScenarioCreateRequest(None)
         (code, body) = self.create(req_none)
         self.assertEqual(code, httplib.BAD_REQUEST)
         self.assertIn(message.missing('name'), body)
 
+    @executor.mock_valid_lfid()
     def test_success(self):
         (code, body) = self.create_d()
         self.assertEqual(code, httplib.OK)
         self.assert_create_body(body)
 
+    @executor.mock_valid_lfid()
     def test_alreadyExist(self):
         self.create_d()
         (code, body) = self.create_d()
@@ -128,6 +135,7 @@ class TestScenarioDelete(TestScenarioBase):
         code, body = self.delete('notFound')
         self.assertEqual(code, httplib.NOT_FOUND)
 
+    @executor.mock_valid_lfid()
     def test_success(self):
         scenario = self.create_return_name(self.req_d)
         code, _ = self.delete(scenario)
@@ -182,6 +190,7 @@ class TestScenarioUpdate(TestScenarioBase):
             return wrapper
         return _update_partial
 
+    @executor.mock_valid_lfid()
     @update_partial('_add', '_success')
     def test_addScore(self):
         add = sm.ScenarioScore(date=str(datetime.now()), score='11/12')
@@ -193,6 +202,7 @@ class TestScenarioUpdate(TestScenarioBase):
 
         return add
 
+    @executor.mock_valid_lfid()
     @update_partial('_add', '_success')
     def test_addTrustIndicator(self):
         add = sm.ScenarioTI(date=str(datetime.now()), status='gold')
@@ -204,6 +214,7 @@ class TestScenarioUpdate(TestScenarioBase):
 
         return add
 
+    @executor.mock_valid_lfid()
     @update_partial('_add', '_success')
     def test_addCustoms(self):
         adds = ['odl', 'parser', 'vping_ssh']
@@ -214,6 +225,7 @@ class TestScenarioUpdate(TestScenarioBase):
                                                  self.locate_project)
         return adds
 
+    @executor.mock_valid_lfid()
     @update_partial('_update', '_success')
     def test_updateCustoms(self):
         updates = ['odl', 'parser', 'vping_ssh']
@@ -225,6 +237,7 @@ class TestScenarioUpdate(TestScenarioBase):
 
         return updates
 
+    @executor.mock_valid_lfid()
     @update_partial('_delete', '_success')
     def test_deleteCustoms(self):
         deletes = ['vping_ssh']
@@ -236,6 +249,7 @@ class TestScenarioUpdate(TestScenarioBase):
 
         return deletes
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('projects')
     @update_partial('_add', '_success')
     def test_addProjects_succ(self):
@@ -243,12 +257,14 @@ class TestScenarioUpdate(TestScenarioBase):
         self.req_d['installers'][0]['versions'][0]['projects'].append(add)
         return [add]
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('projects')
     @update_partial('_add', '_conflict')
     def test_addProjects_already_exist(self):
         add = sm.ScenarioProject(project='functest').format()
         return [add]
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('projects')
     @update_partial('_add', '_bad_request')
     def test_addProjects_bad_schema(self):
@@ -256,6 +272,7 @@ class TestScenarioUpdate(TestScenarioBase):
         add['score'] = None
         return [add]
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('projects')
     @update_partial('_update', '_success')
     def test_updateProjects_succ(self):
@@ -263,12 +280,14 @@ class TestScenarioUpdate(TestScenarioBase):
         self.req_d['installers'][0]['versions'][0]['projects'] = [update]
         return [update]
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('projects')
     @update_partial('_update', '_conflict')
     def test_updateProjects_duplicated(self):
         update = sm.ScenarioProject(project='qtip').format()
         return [update, update]
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('projects')
     @update_partial('_update', '_bad_request')
     def test_updateProjects_bad_schema(self):
@@ -276,6 +295,7 @@ class TestScenarioUpdate(TestScenarioBase):
         update['score'] = None
         return [update]
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('projects')
     @update_partial('_delete', '_success')
     def test_deleteProjects(self):
@@ -286,6 +306,7 @@ class TestScenarioUpdate(TestScenarioBase):
             projects)
         return deletes
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('owner')
     @update_partial('_update', '_success')
     def test_changeOwner(self):
@@ -294,6 +315,7 @@ class TestScenarioUpdate(TestScenarioBase):
         self.req_d['installers'][0]['versions'][0]['owner'] = new_owner
         return update
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('versions')
     @update_partial('_add', '_success')
     def test_addVersions_succ(self):
@@ -301,12 +323,14 @@ class TestScenarioUpdate(TestScenarioBase):
         self.req_d['installers'][0]['versions'].append(add)
         return [add]
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('versions')
     @update_partial('_add', '_conflict')
     def test_addVersions_already_exist(self):
         add = sm.ScenarioVersion(version='master').format()
         return [add]
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('versions')
     @update_partial('_add', '_bad_request')
     def test_addVersions_bad_schema(self):
@@ -314,6 +338,7 @@ class TestScenarioUpdate(TestScenarioBase):
         add['notexist'] = None
         return [add]
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('versions')
     @update_partial('_update', '_success')
     def test_updateVersions_succ(self):
@@ -321,12 +346,14 @@ class TestScenarioUpdate(TestScenarioBase):
         self.req_d['installers'][0]['versions'] = [update]
         return [update]
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('versions')
     @update_partial('_update', '_conflict')
     def test_updateVersions_duplicated(self):
         update = sm.ScenarioVersion(version='euphrates').format()
         return [update, update]
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('versions')
     @update_partial('_update', '_bad_request')
     def test_updateVersions_bad_schema(self):
@@ -334,6 +361,7 @@ class TestScenarioUpdate(TestScenarioBase):
         update['not_owner'] = 'Iam'
         return [update]
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('versions')
     @update_partial('_delete', '_success')
     def test_deleteVersions(self):
@@ -344,6 +372,7 @@ class TestScenarioUpdate(TestScenarioBase):
             versions)
         return deletes
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('installers')
     @update_partial('_add', '_success')
     def test_addInstallers_succ(self):
@@ -351,12 +380,14 @@ class TestScenarioUpdate(TestScenarioBase):
         self.req_d['installers'].append(add)
         return [add]
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('installers')
     @update_partial('_add', '_conflict')
     def test_addInstallers_already_exist(self):
         add = sm.ScenarioInstaller(installer='apex').format()
         return [add]
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('installers')
     @update_partial('_add', '_bad_request')
     def test_addInstallers_bad_schema(self):
@@ -364,6 +395,7 @@ class TestScenarioUpdate(TestScenarioBase):
         add['not_exist'] = 'not_exist'
         return [add]
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('installers')
     @update_partial('_update', '_success')
     def test_updateInstallers_succ(self):
@@ -371,12 +403,14 @@ class TestScenarioUpdate(TestScenarioBase):
         self.req_d['installers'] = [update]
         return [update]
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('installers')
     @update_partial('_update', '_conflict')
     def test_updateInstallers_duplicated(self):
         update = sm.ScenarioInstaller(installer='daisy').format()
         return [update, update]
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('installers')
     @update_partial('_update', '_bad_request')
     def test_updateInstallers_bad_schema(self):
@@ -384,6 +418,7 @@ class TestScenarioUpdate(TestScenarioBase):
         update['not_exist'] = 'not_exist'
         return [update]
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('installers')
     @update_partial('_delete', '_success')
     def test_deleteInstallers(self):
@@ -394,6 +429,7 @@ class TestScenarioUpdate(TestScenarioBase):
             installers)
         return deletes
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('rename')
     @update_partial('_update', '_success')
     def test_renameScenario(self):
@@ -402,6 +438,7 @@ class TestScenarioUpdate(TestScenarioBase):
         self.req_d['name'] = new_name
         return update
 
+    @executor.mock_valid_lfid()
     @update_url_fixture('rename')
     @update_partial('_update', '_forbidden')
     def test_renameScenario_exist(self):
index 2a34838..590b48e 100644 (file)
                 templateUrl: 'testapi-ui/components/projects/project/project.html',
                 controller: 'ProjectController as ctrl'
             }).
+            state('scenarios', {
+                url: '/scenarios',
+                templateUrl: 'testapi-ui/components/scenarios/scenarios.html',
+                controller: 'ScenariosController as ctrl'
+            }).
+            state('scenario', {
+                url: '/scenarios/:name',
+                templateUrl: 'testapi-ui/components/scenarios/scenario/scenario.html',
+                controller: 'ScenarioController as ctrl'
+            }).
             state('testCase', {
                 url: '/projects/:project_name/:name',
                 templateUrl: 'testapi-ui/components/projects/project/testCases/testCase/testCase.html',
diff --git a/testapi/opnfv_testapi/ui/components/scenarios/modals/customModal.html b/testapi/opnfv_testapi/ui/components/scenarios/modals/customModal.html
new file mode 100644 (file)
index 0000000..987cb1e
--- /dev/null
@@ -0,0 +1,28 @@
+<div class="ball" style="padding:5px;">
+        <div class="modal-body">
+            <div class="form-horizontal">
+                <fieldset>
+                    <div class="form-group">
+                        <legend>{{customModalCtrl.data.text}}</legend>
+                        <div class="row">
+                                <div class="update-project">
+                                    <label for="cpid" class="control-label col-sm-4">Custom: </label>
+                                    <div class="col-sm-6">
+                                        <input type="text" class="form-control" ng-model="customModalCtrl.custom"/>
+                                        <p class="help-block"></p>
+                                    </div>
+                                </div>
+                        </div>
+                    </div>
+                </fieldset>
+            </div>
+        </div>
+        <div class="modal-footer">
+            <div ng-show="customModalCtrl.showCreateError" style="padding:0px;" class="col-md-6 alert alert-danger" role="alert">
+                    <span class="pull-right">&nbsp;{{customModalCtrl.error}}</span>
+                    <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span>
+            </div>
+            <button class="btn btn-primary" ng-click="customModalCtrl.confirm()">Ok</button>
+            <button class="btn btn-default" ng-click="customModalCtrl.cancel()">Cancel</button>
+        </div>
+    </div>
\ No newline at end of file
diff --git a/testapi/opnfv_testapi/ui/components/scenarios/modals/installerModal.html b/testapi/opnfv_testapi/ui/components/scenarios/modals/installerModal.html
new file mode 100644 (file)
index 0000000..4be1375
--- /dev/null
@@ -0,0 +1,59 @@
+<div class="ball" style="padding:5px;">
+        <div class="modal-body">
+            <div class="form-horizontal">
+                <fieldset>
+                    <div class="form-group">
+                        <legend>{{installerModalCtrl.data.text}}</legend>
+                        <div class="row">
+                                <div class="update-project">
+                                    <div class="col-sm-4">
+                                    <label for="cpid" class="control-label col-sm-2"> Name: </label>
+                                    </div>
+                                    <div class="col-sm-6">
+                                        <input type="text" class="form-control" ng-model="installerModalCtrl.installer.installer"/>
+                                        <p class="help-block"></p>
+                                        </div>
+                                </div>
+                                <div class="update-project">
+                                    <div class="col-sm-4">
+                                        <label for="cpid" class="control-label col-sm-2"> Version: </label>
+                                    </div>
+                                    <div class="col-sm-6">
+                                        <button class="btn btn-primary" ng-click="installerModalCtrl.openVersionModal()">Add&nbsp;Version</button>
+                                        <p class="help-block"></p>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                </fieldset>
+            </div>
+            <div class='clo-md-12' style="padding-right:0px">
+                    <h3>Version</h3>
+                    <div class="table-responsive">
+                        <table class="table table-bordered table-hover"  ng-data="installerModalCtrl.installer.versions">
+                        <thead>
+                        <tr style="
+                        text-align: center;">
+                            <th style="width: 19%;">Version</th>
+                        </tr>
+                        </thead>
+                        <tbody>
+                        <tr ng-repeat-start="(index, version) in installerModalCtrl.installer.versions" style="padding:9px">
+                            <td>{{version.version}}</td>
+                        </tr>
+                        <tr ng-repeat-end=>
+                        </tr>
+                        </tbody>
+                        </table>
+                    </div>
+                </div>
+        </div>
+        <div class="modal-footer">
+            <div ng-show="installerModalCtrl.showCreateError" style="padding:0px;" class="col-md-6 alert alert-danger" role="alert">
+                    <span class="pull-right">&nbsp;{{installerModalCtrl.error}}</span>
+                    <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span>
+            </div>
+            <button class="btn btn-primary" ng-click="installerModalCtrl.confirm()">Ok</button>
+            <button class="btn btn-default" ng-click="installerModalCtrl.cancel()">Cancel</button>
+        </div>
+    </div>
\ No newline at end of file
diff --git a/testapi/opnfv_testapi/ui/components/scenarios/modals/projectModal.html b/testapi/opnfv_testapi/ui/components/scenarios/modals/projectModal.html
new file mode 100644 (file)
index 0000000..5885a61
--- /dev/null
@@ -0,0 +1,121 @@
+<div class="ball" style="padding:5px;">
+        <div class="modal-body">
+            <div class="form-horizontal">
+                <fieldset>
+                    <div class="form-group">
+                        <legend>{{projectModalCtrl.data.text}}</legend>
+                        <div class="row">
+                                <div class="update-project">
+                                    <div class="col-sm-4">
+                                        <label for="cpid" class="control-label"> Project&nbsp;Name: </label>
+                                    </div>
+                                    <div class="col-sm-6">
+                                        <input type="text" class="form-control" ng-model="projectModalCtrl.project.project"/>
+                                        <p class="help-block"></p>
+                                    </div>
+                                </div>
+                                <div class="update-project">
+                                    <div class="col-sm-4">
+                                        <label for="cpid" class="control-label"> Trust&nbsp;Indicator: </label>
+                                    </div>
+                                    <div class="col-sm-6">
+                                        <button class="btn btn-primary" ng-click="projectModalCtrl.openTrustIndicatorModal()">Add&nbsp;Trust&nbsp;Indicator</button>
+                                            <p class="help-block"></p>
+                                    </div>
+                                </div>
+                                <div class="update-project">
+                                    <div class="col-sm-4">
+                                        <label for="cpid" class="control-label"> Score: </label>
+                                    </div>
+                                    <div class="col-sm-6">
+                                        <button class="btn btn-primary" ng-click="projectModalCtrl.openScoreModal()">Add&nbsp;Score</button>
+                                            <p class="help-block"></p>
+                                    </div>
+                                </div>
+                                <div class="update-project">
+                                    <div class="col-sm-4">
+                                        <label for="cpid" class="control-label"> Custom: </label>
+                                    </div>
+                                    <div class="col-sm-6">
+                                        <button class="btn btn-primary" ng-click="projectModalCtrl.openCustomModal()">Add&nbsp;Custom</button>
+                                            <p class="help-block"></p>
+                                    </div>
+                                </div>
+                            </div>
+                    </div>
+                </fieldset>
+            </div>
+            <div class='clo-md-12' style="padding-right:0px">
+                <h3>Scores</h3>
+                <div class="table-responsive">
+                    <table class="table table-bordered table-hover"  ng-data="projectModalCtrl.project.scores">
+                    <thead>
+                    <tr style="
+                    text-align: center;">
+                        <th style="width: 1%;">Score</th>
+                        <th style="width: 19%;">Date</th>
+                    </tr>
+                    </thead>
+                    <tbody>
+                    <tr ng-repeat-start="(index, score) in projectModalCtrl.project.scores" style="padding:9px">
+                        <td>{{score.score}}</td>
+                        <td>{{score.date}}</td>
+                    </tr>
+                    <tr ng-repeat-end=>
+                    </tr>
+                    </tbody>
+                    </table>
+                </div>
+            </div>
+            <div class='clo-md-12' style="padding-right:0px">
+                <h3>Trust&nbsp;Indicator</h3>
+                <div class="table-responsive">
+                    <table class="table table-bordered table-hover"  ng-data="projectModalCtrl.project.trust_indicators">
+                    <thead>
+                    <tr style="
+                    text-align: center;">
+                        <th style="width: 1%;">Status</th>
+                        <th style="width: 19%;">Date</th>
+                    </tr>
+                    </thead>
+                    <tbody>
+                    <tr ng-repeat-start="(index, trustIndicator) in projectModalCtrl.project.trust_indicators" style="padding:9px">
+                        <td>{{trustIndicator.status}}</td>
+                        <td>{{trustIndicator.date}}</td>
+                    </tr>
+                    <tr ng-repeat-end=>
+                    </tr>
+                    </tbody>
+                    </table>
+                </div>
+            </div>
+            <div class='clo-md-12' style="padding-right:0px">
+                <h3>Customs</h3>
+                <div class="table-responsive">
+                    <table class="table table-bordered table-hover"  ng-data="projectModalCtrl.project.customs">
+                    <thead>
+                    <tr style="
+                    text-align: center;">
+                        <th style="width: 1%;">Custom</th>
+                    </tr>
+                    </thead>
+                    <tbody>
+                    <tr ng-repeat-start="(index, custom) in projectModalCtrl.project.customs" style="padding:9px">
+                        <td>{{custom}}</td>
+                    </tr>
+                    <tr ng-repeat-end=>
+                    </tr>
+                    </tbody>
+                    </table>
+                </div>
+            </div>
+        </div>
+        <div class="modal-footer">
+            <div ng-show="projectModalCtrl.showCreateError" style="padding:0px;" class="col-md-6 alert alert-danger" role="alert">
+                    <span class="pull-right">&nbsp;{{projectModalCtrl.error}}</span>
+                    <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span>
+            </div>
+            <button class="btn btn-primary" ng-click="projectModalCtrl.confirm()">Ok</button>
+            <button class="btn btn-default" ng-click="projectModalCtrl.cancel()">Cancel</button>
+        </div>
+    </div>
\ No newline at end of file
diff --git a/testapi/opnfv_testapi/ui/components/scenarios/modals/scenarioModal.html b/testapi/opnfv_testapi/ui/components/scenarios/modals/scenarioModal.html
new file mode 100644 (file)
index 0000000..2b5ba9e
--- /dev/null
@@ -0,0 +1,59 @@
+<div class="ball" style="padding:5px;">
+    <div class="modal-body">
+        <div class="form-horizontal">
+            <fieldset>
+                <div class="form-group">
+                    <legend>{{scenarioModalController.data.text}}</legend>
+                    <div class="row">
+                            <div class="update-project">
+                                <div class="col-sm-4">
+                                <label for="cpid" class="control-label col-sm-2"> Name: </label>
+                                </div>
+                                <div class="col-sm-6">
+                                    <input type="text" class="form-control" ng-model="scenarioModalController.scenario.name"/>
+                                    <p class="help-block"></p>
+                                    </div>
+                            </div>
+                            <div class="update-project">
+                                <div class="col-sm-4">
+                                    <label for="cpid" class="control-label col-sm-2"> Installer: </label>
+                                </div>
+                                <div class="col-sm-6">
+                                    <button class="btn btn-primary" ng-click="scenarioModalController.openInstallerModal()">Add&nbsp;Installer</button>
+                                    <p class="help-block"></p>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+            </fieldset>
+        </div>
+        <div class='clo-md-12' style="padding-right:0px">
+                <h3>Installers</h3>
+                <div class="table-responsive">
+                    <table class="table table-bordered table-hover"  ng-data="scenarioModalController.scenario">
+                    <thead>
+                    <tr style="
+                    text-align: center;">
+                        <th style="width: 19%;">Installers</th>
+                    </tr>
+                    </thead>
+                    <tbody>
+                    <tr ng-repeat-start="(index, installer) in scenarioModalController.scenario.installers" style="padding:9px">
+                        <td>{{installer.installer}}</td>
+                    </tr>
+                    <tr ng-repeat-end=>
+                    </tr>
+                    </tbody>
+                    </table>
+                </div>
+            </div>
+    </div>
+    <div class="modal-footer">
+        <div ng-show="scenarioModalController.showCreateError" style="padding:0px;" class="col-md-6 alert alert-danger" role="alert">
+                <span class="pull-right">&nbsp;{{scenarioModalController.error}}</span>
+                <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span>
+        </div>
+        <button class="btn btn-primary" ng-click="scenarioModalController.confirm()">Ok</button>
+        <button class="btn btn-default" ng-click="scenarioModalController.cancel()">Cancel</button>
+    </div>
+</div>
\ No newline at end of file
diff --git a/testapi/opnfv_testapi/ui/components/scenarios/modals/scenarioNameUpdate.html b/testapi/opnfv_testapi/ui/components/scenarios/modals/scenarioNameUpdate.html
new file mode 100644 (file)
index 0000000..e793c05
--- /dev/null
@@ -0,0 +1,28 @@
+<div class="ball" style="padding:5px;">
+        <div class="modal-body">
+            <div class="form-horizontal">
+                <fieldset>
+                    <div class="form-group">
+                        <legend>{{ScenarioNameUpdateCtrl.data.text}}</legend>
+                        <div class="row">
+                                <div class="update-project">
+                                    <label for="cpid" class="control-label col-sm-4">Name: </label>
+                                    <div class="col-sm-6">
+                                        <input type="text" class="form-control" ng-model="ScenarioNameUpdateCtrl.name"/>
+                                        <p class="help-block"></p>
+                                    </div>
+                                </div>
+                        </div>
+                    </div>
+                </fieldset>
+            </div>
+        </div>
+        <div class="modal-footer">
+            <div ng-show="ScenarioNameUpdateCtrl.showCreateError" style="padding:0px;" class="col-md-6 alert alert-danger" role="alert">
+                    <span class="pull-right">&nbsp;{{ScenarioNameUpdateCtrl.error}}</span>
+                    <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span>
+            </div>
+            <button class="btn btn-primary" ng-click="ScenarioNameUpdateCtrl.confirm()">Ok</button>
+            <button class="btn btn-default" ng-click="ScenarioNameUpdateCtrl.cancel()">Cancel</button>
+        </div>
+    </div>
\ No newline at end of file
diff --git a/testapi/opnfv_testapi/ui/components/scenarios/modals/scoreModal.html b/testapi/opnfv_testapi/ui/components/scenarios/modals/scoreModal.html
new file mode 100644 (file)
index 0000000..55b5cfd
--- /dev/null
@@ -0,0 +1,51 @@
+
+
+    <div class="ball" style="padding:5px;">
+            <div class="modal-body">
+                <div class="form-horizontal">
+                    <fieldset>
+                        <div class="form-group">
+                            <legend>{{scoreModalCtrl.data.text}}</legend>
+                            <div class="row">
+                                    <div class="update-project">
+                                        <label for="cpid" class="control-label col-sm-4">Score: </label>
+                                        <div class="col-sm-6">
+                                            <input type="text" class="form-control" ng-model="scoreModalCtrl.score.score"/>
+                                            <p class="help-block"></p>
+                                        </div>
+                                    </div>
+                                    <div class="update-project">
+                                        <div>
+                                            <div class="col-md-4" style="text-align:right;">
+                                                <span style="margin-top:6px;">Date:&nbsp;&nbsp;</span>
+                                            </div>
+                                            <div class="col-md-6">
+                                                <p class="input-group" style="display:inline-flex;">
+                                                    <input type="text" class="form-control"
+                                                        uib-datepicker-popup="{{scoreModalCtrl.format}}"
+                                                        ng-model="scoreModalCtrl.score.date" is-open="scoreModalCtrl.endOpen"
+                                                        close-text="Close" />
+                                                    <span class="input-group-btn">
+                                                        <button type="button" class="btn btn-default" ng-click="scoreModalCtrl.open($event, 'endOpen')">
+                                                            <i class="glyphicon glyphicon-calendar"></i>
+                                                        </button>
+                                                    </span>
+                                                </p>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                    </fieldset>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <div ng-show="scoreModalCtrl.showCreateError" style="padding:0px;" class="col-md-6 alert alert-danger" role="alert">
+                        <span class="pull-right">&nbsp;{{scoreModalCtrl.error}}</span>
+                        <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span>
+                </div>
+                <button class="btn btn-primary" ng-click="scoreModalCtrl.confirm()">Ok</button>
+                <button class="btn btn-default" ng-click="scoreModalCtrl.cancel()">Cancel</button>
+            </div>
+        </div>
\ No newline at end of file
diff --git a/testapi/opnfv_testapi/ui/components/scenarios/modals/trustIndicatorModal.html b/testapi/opnfv_testapi/ui/components/scenarios/modals/trustIndicatorModal.html
new file mode 100644 (file)
index 0000000..b84bd5d
--- /dev/null
@@ -0,0 +1,49 @@
+<div class="ball" style="padding:5px;">
+        <div class="modal-body">
+            <div class="form-horizontal">
+                <fieldset>
+                    <div class="form-group">
+                        <legend>{{trustIndicatorModalCtrl.data.text}}</legend>
+                        <div class="row">
+                                <div class="update-project">
+                                    <label for="cpid" class="control-label col-sm-4">Status: </label>
+                                    <div class="col-sm-6">
+                                        <input type="text" class="form-control" ng-model="trustIndicatorModalCtrl.ti.status"/>
+                                        <p class="help-block"></p>
+                                    </div>
+                                </div>
+                                <div class="update-project">
+                                    <div>
+                                        <div class="col-md-4" style="text-align:right;">
+                                            <span style="margin-top:6px;">Date:&nbsp;&nbsp;</span>
+                                        </div>
+                                        <div class="col-md-6">
+                                            <p class="input-group" style="display:inline-flex;">
+                                                <input type="text" class="form-control"
+                                                    uib-datepicker-popup="{{trustIndicatorModalCtrl.format}}"
+                                                    ng-model="trustIndicatorModalCtrl.ti.date" is-open="trustIndicatorModalCtrl.endOpen"
+                                                    close-text="Close" />
+                                                <span class="input-group-btn">
+                                                    <button type="button" class="btn btn-default" ng-click="trustIndicatorModalCtrl.open($event, 'endOpen')">
+                                                        <i class="glyphicon glyphicon-calendar"></i>
+                                                    </button>
+                                                </span>
+                                            </p>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </fieldset>
+            </div>
+        </div>
+        <div class="modal-footer">
+            <div ng-show="trustIndicatorModalCtrl.showCreateError" style="padding:0px;" class="col-md-6 alert alert-danger" role="alert">
+                    <span class="pull-right">&nbsp;{{trustIndicatorModalCtrl.error}}</span>
+                    <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span>
+            </div>
+            <button class="btn btn-primary" ng-click="trustIndicatorModalCtrl.confirm()">Ok</button>
+            <button class="btn btn-default" ng-click="trustIndicatorModalCtrl.cancel()">Cancel</button>
+        </div>
+    </div>
\ No newline at end of file
diff --git a/testapi/opnfv_testapi/ui/components/scenarios/modals/versionModal.html b/testapi/opnfv_testapi/ui/components/scenarios/modals/versionModal.html
new file mode 100644 (file)
index 0000000..f679f0b
--- /dev/null
@@ -0,0 +1,68 @@
+<div class="ball" style="padding:5px;">
+        <div class="modal-body">
+            <div class="form-horizontal">
+                <fieldset>
+                    <div class="form-group">
+                        <legend>{{versionModalCtrl.data.text}}</legend>
+                        <div class="row">
+                                <div class="update-project">
+                                    <div class="col-sm-4">
+                                        <label for="cpid" class="control-label col-sm-2"> Version: </label>
+                                    </div>
+                                    <div class="col-sm-6">
+                                        <input type="text" class="form-control" ng-model="versionModalCtrl.version.version"/>
+                                            <p class="help-block"></p>
+                                    </div>
+                                </div>
+                                <div class="update-project">
+                                    <div class="col-sm-4">
+                                        <label for="cpid" class="control-label col-sm-2"> Owner: </label>
+                                    </div>
+                                    <div class="col-sm-6">
+                                        <input type="text" class="form-control" ng-model="versionModalCtrl.version.owner"/>
+                                            <p class="help-block"></p>
+                                    </div>
+                                </div>
+                                <div class="update-project">
+                                    <div class="col-sm-4">
+                                    <label for="cpid" class="control-label col-sm-2"> Project: </label>
+                                    </div>
+                                    <div class="col-sm-4">
+                                    <button class="btn btn-primary" ng-click="versionModalCtrl.openProjectModal()">Add&nbsp;Project:</button>
+                                        <p class="help-block"></p>
+                                        </div>
+                                </div>
+                            </div>
+                        </div>
+                </fieldset>
+            </div>
+            <div class='clo-md-12' style="padding-right:0px">
+                    <h3>Projects</h3>
+                    <div class="table-responsive">
+                        <table class="table table-bordered table-hover"  ng-data="versionModalCtrl.version.projects">
+                        <thead>
+                        <tr style="
+                        text-align: center;">
+                            <th style="width: 19%;">Project</th>
+                        </tr>
+                        </thead>
+                        <tbody>
+                        <tr ng-repeat-start="(index, project) in versionModalCtrl.version.projects" style="padding:9px">
+                            <td>{{project.project}}</td>
+                        </tr>
+                        <tr ng-repeat-end=>
+                        </tr>
+                        </tbody>
+                        </table>
+                    </div>
+                </div>
+        </div>
+        <div class="modal-footer">
+            <div ng-show="versionModalCtrl.showCreateError" style="padding:0px;" class="col-md-6 alert alert-danger" role="alert">
+                    <span class="pull-right">&nbsp;{{versionModalCtrl.error}}</span>
+                    <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span>
+            </div>
+            <button class="btn btn-primary" ng-click="versionModalCtrl.confirm()">Ok</button>
+            <button class="btn btn-default" ng-click="versionModalCtrl.cancel()">Cancel</button>
+        </div>
+    </div>
\ No newline at end of file
diff --git a/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenario.html b/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenario.html
new file mode 100644 (file)
index 0000000..d96986e
--- /dev/null
@@ -0,0 +1,234 @@
+<legend>Scenario</legend>
+<div style="padding-right:0px">
+        <div class="table-responsive">
+            <table class="table"  ng-data="ctrl.data">
+                <tbody>
+                    <tr style="padding:9px">
+                        <td class="podsTableTd">Id&nbsp;:</td>
+                        <td class="podsTableLeftTd">{{ctrl.data.scenarios[0]._id}}</td>
+                    </tr>
+                    <tr style="padding:9px">
+                        <td class="podsTableTd">Name&nbsp;:</td>
+                        <td width="90%" class="podsTableLeftTd">{{ctrl.data.scenarios[0].name}}</td>
+                    </tr>
+                    <tr style="padding:9px">
+                            <td class="podsTableTd">Created&nbsp;at&nbsp;:</td>
+                            <td width="90%" class="podsTableLeftTd">{{ctrl.data.scenarios[0].creation_date}}</td>
+                    </tr>
+                    <tr style="padding:9px">
+                            <td class="podsTableTd">Installers</td>
+                            <td width="90%" class="podsTableLeftTd">
+                                    <div class="col-md-1" style="padding:0px">
+                                        <a ng-click="ctrl.expandInstallers()">
+                                                <p ng-if="ctrl.collapeInstallers">Hide</p>
+                                                <p ng-if="!ctrl.collapeInstallers">Show</p>
+                                        </a>
+                                    </div>
+                                    <div class="col-md-1" style="padding:0px">
+                                        <button type="button" class="btn btn-success btn-xs" ng-click="ctrl.openAddInstaller()" ><i class="fa fa-plus"></i>Add</button>
+                                    </div>
+                                    <div ng-class="{ 'hidden' : ! ctrl.collapeInstallers } ">
+                                        <div class="table-responsive">
+                                                <table class="table  "  ng-data="ctrl.data.scenarios[0].installers">
+                                                <tbody ng-repeat="(index, installer) in ctrl.data.scenarios[0].installers">
+                                                <tr style="padding:9px">
+                                                    <td class="podsTableTd">
+                                                            {{index+1}}.&nbsp;Installer:&nbsp;
+                                                    </td>
+                                                    <td class="podsTableLeftTd"  style="width:10%;padding-top: 7px;">
+                                                            <a ng-click="ctrl.expandInstaller(index)">{{installer.installer}}</a>
+                                                    </td>
+                                                    <td  style="width:80%;border: none; padding: 0px;">
+                                                            <button type="button" class="btn btn-danger btn-xs" ng-click="ctrl.openDeleteInstallerModal(installer.installer)" ><i class="fa fa-minus"></i>Delete</button>
+                                                    </td>
+                                                </tr>
+                                                <tr ng-class="{ 'hidden' : ! ctrl.collapeInstaller[index] }">
+                                                    <td class="podsTableTd">
+                                                        Versions:
+                                                    </td>
+                                                    <td width="90%" class="podsTableLeftTd">
+                                                        <div class="col-md-1" style="padding:0px">
+                                                            <a ng-click="ctrl.expandVersions(index)">
+                                                                    <p ng-if="ctrl.collapeVersions[index]">Hide</p>
+                                                                    <p ng-if="!ctrl.collapeVersions[index]">Show</p>
+                                                            </a>
+                                                        </div>
+                                                        <div class="col-md-1" style="padding:0px">
+                                                            <button type="button" class="btn btn-success btn-xs" ng-click="ctrl.openAddVersionModal(installer.installer)" ><i class="fa fa-plus"></i>Add</button>
+                                                        </div>
+                                                        <div ng-class="{ 'hidden' : ! ctrl.collapeVersions[index] } " class="col-md-12">
+                                                            <div class="table-responsive">
+                                                                    <table class="table  "  ng-data="inctrl.data.scenarios[0].installers">
+                                                                    <tbody ng-repeat="(index, version) in installer.versions">
+                                                                    <tr style="padding:9px">
+                                                                        <td class="podsTableTd">
+                                                                            {{index+1}}.&nbsp;Version:
+                                                                        </td>
+                                                                        <td class="podsTableLeftTd"  style="width:10%;padding-top: 7px;">
+                                                                            <a ng-click="ctrl.expandVersion(index)">{{version.version}}</a>
+                                                                        </td>
+                                                                        <td  style="width:80%;border: none; padding: 0px;">
+                                                                                <button type="button" class="btn btn-danger btn-xs" ng-click="ctrl.openDeleteVersionModal(version.version, installer.installer)" ><i class="fa fa-minus"></i>Delete</button>
+                                                                        </td>
+                                                                    </tr>
+                                                                    <tr style="padding:9px" ng-class="{ 'hidden' : ! ctrl.collapeVersion[index] } ">
+                                                                        <td class="podsTableTd">
+                                                                            Owner:
+                                                                        </td>
+                                                                        <td class="podsTableLeftTd" style="width:90%">{{version.owner}}</td>
+                                                                    </tr>
+                                                                    <tr style="padding:9px" ng-class="{ 'hidden' : ! ctrl.collapeVersion[index] }">
+                                                                        <td class="podsTableTd">
+                                                                            Projects:
+                                                                        </td>
+                                                                        <td width="90%" class="podsTableLeftTd">
+                                                                            <div class="col-md-1" style="padding:0px">
+                                                                                <a ng-click="ctrl.expandProjects(index)">
+                                                                                        <p style="width:50%" ng-if="ctrl.collapeProjects[index]">Hide</p>
+                                                                                        <p style="width:50%" ng-if="!ctrl.collapeProjects[index]">Show</p>
+                                                                                </a>
+                                                                            </div>
+                                                                            <div class="col-md-1" style="padding:0px">
+                                                                                <button type="button" class="btn btn-success btn-xs" ng-click="ctrl.openAddProjectModal(version.version,installer.installer)" ><i class="fa fa-plus"></i>Add</button>
+                                                                            </div>
+                                                                            <div ng-class="{ 'hidden' : ! ctrl.collapeProjects[index] } " class="col-md-12">
+                                                                                <div class="table-responsive">
+                                                                                    <table class="table  "  ng-data="version.projects">
+                                                                                    <tbody ng-repeat="(index, project) in version.projects" >
+                                                                                    <tr style="padding:9px">
+                                                                                        <td class="podsTableTd">
+                                                                                                {{index+1}}.&nbsp;Project:
+                                                                                        </td>
+                                                                                        <td class="podsTableLeftTd" style="width:90%">
+                                                                                            <a ng-click="ctrl.expandProject(index)">{{project.project}}</a>
+                                                                                        </td>
+                                                                                    </tr>
+                                                                                    <tr ng-class="{ 'hidden' : ! ctrl.collapeProject[index] }">
+                                                                                        <td class="podsTableTd">
+                                                                                                Trust&nbsp;Indicators:
+                                                                                        </td>
+                                                                                        <td class="podsTableLeftTd" style="width:90%">
+                                                                                            <a ng-click="ctrl.expandTrustIndicator(index)">
+                                                                                                <p ng-if="ctrl.collapeTrustIndicator[index]">Hide</p>
+                                                                                                <p ng-if="!ctrl.collapeTrustIndicator[index]">Show</p>
+                                                                                            </a>
+                                                                                                    <table class="table  "  ng-class="{ 'hidden' : ! ctrl.collapeTrustIndicator[index] } " ng-data="project.trust_indicators">
+                                                                                                    <tbody  ng-repeat="(index, trust_indicator) in project.trust_indicators" >
+                                                                                                    <tr style="padding:9px">
+                                                                                                        <td class="podsTableTd">
+                                                                                                            Status:&nbsp;
+                                                                                                        </td>
+                                                                                                        <td  width="90%" class="podsTableLeftTd">
+                                                                                                                {{trust_indicator.status}}
+                                                                                                        </td>
+                                                                                                    </tr>
+                                                                                                    <tr style="padding:9px">
+                                                                                                            <td class="podsTableTd">
+                                                                                                                    Date:&nbsp;
+                                                                                                            </td>
+                                                                                                            <td  width="90%" class="podsTableLeftTd">
+                                                                                                                {{trust_indicator.date}}
+                                                                                                            </td>
+                                                                                                        </tr>
+                                                                                                    </tbody>
+                                                                                                    <tr>
+                                                                                                        <button type="button" class="btn btn-success btn-xs" ng-click="ctrl.openAddTrustIndicatorModal(project.project,version.version,installer.installer)"  ng-class="{ 'hidden' : !ctrl.collapeTrustIndicator[index]}">
+                                                                                                            <i class="fa fa-plus"></i>Add</button>
+                                                                                                    </tr>
+                                                                                                    </table>
+                                                                                        </td>
+                                                                                    </tr>
+                                                                                    <tr ng-class="{ 'hidden' : ! ctrl.collapeProject[index] }">
+                                                                                        <td class="podsTableTd">
+                                                                                                Scores:
+                                                                                        </td>
+                                                                                        <td class="podsTableLeftTd" style="width:90%">
+                                                                                            <a ng-click="ctrl.expandScore(index)">
+                                                                                                <p ng-if="ctrl.collapeScore[index]">Hide</p>
+                                                                                                <p ng-if="!ctrl.collapeScore[index]">Show</p>
+                                                                                            </a>
+                                                                                                    <table class="table" ng-class="{ 'hidden' : ! ctrl.collapeScore[index] } "  ng-data="project.scores">
+                                                                                                    <tbody ng-repeat="(index, score) in project.scores" >
+                                                                                                    <tr style="padding:9px">
+                                                                                                        <td class="podsTableTd">
+                                                                                                            Score:&nbsp;
+                                                                                                        </td>
+                                                                                                        <td  width="90%" class="podsTableLeftTd">
+                                                                                                                {{score.score}}
+                                                                                                        </td>
+                                                                                                    </tr>
+                                                                                                    <tr style="padding:9px">
+                                                                                                            <td class="podsTableTd">
+                                                                                                               Date:&nbsp;
+                                                                                                            </td>
+                                                                                                            <td  width="90%" class="podsTableLeftTd">
+                                                                                                                {{score.date}}
+                                                                                                            </td>
+                                                                                                    </tr>
+                                                                                                    </tbody>
+                                                                                                    <tr>
+                                                                                                        <button type="button" class="btn btn-success btn-xs" ng-click="ctrl.openAddScoreModal(project.project,version.version,installer.installer)"  ng-class="{ 'hidden' : !ctrl.collapeScore[index]}"><i class="fa fa-plus"></i>Add</button>
+                                                                                                    </tr>
+                                                                                                    </table>
+                                                                                        </td>
+                                                                                    </tr>
+                                                                                    <tr ng-class="{ 'hidden' : ! ctrl.collapeProject[index] }">
+                                                                                        <td class="podsTableTd">
+                                                                                                Customs:
+                                                                                        </td>
+                                                                                        <td  class="podsTableLeftTd" style="width:90%">
+                                                                                            <a ng-click="ctrl.expandCustom(index)">
+                                                                                                    <p ng-if="ctrl.collapeCustom[index]">Hide</p>
+                                                                                                    <p ng-if="!ctrl.collapeCustom[index]">Show</p>
+                                                                                            </a>
+                                                                                                    <table class="table" ng-class="{ 'hidden' : ! ctrl.collapeCustom[index] } " ng-data="project.customs">
+                                                                                                    <tbody>
+                                                                                                    <tr ng-repeat-start="(index, custom) in project.customs" style="padding:9px">
+                                                                                                        <td class="podsTableTd" style="float: none!important;">
+                                                                                                            {{custom}}
+                                                                                                        </td>
+                                                                                                        <td width="90%" class="podsTableLeftTd">
+                                                                                                                <button type="button" class="btn btn-danger btn-xs" ng-click="ctrl.openDeleteCustomModal(custom,project.project,version.version,installer.installer)" ><i class="fa fa-minus"></i>Delete</button>
+                                                                                                        </td>
+                                                                                                    </tr>
+                                                                                                    <tr ng-repeat-end=>
+                                                                                                    </tr>
+                                                                                                    <tr>
+                                                                                                        <button type="button" class="btn btn-success btn-xs" ng-click="ctrl.openAddCustomModal(project.project,version.version,installer.installer)"  ng-class="{ 'hidden' : !ctrl.collapeCustom[index]}"><i class="fa fa-plus"></i>Add</button>
+                                                                                                    </tr>
+                                                                                                    </tbody>
+                                                                                                    </table>
+                                                                                        </td>
+                                                                                    </tr>
+                                                                                    <!-- </div> -->
+                                                                                    <tr ng-repeat-end=>
+                                                                                    </tr>
+                                                                                    </tbody>
+                                                                                    </table>
+                                                                                </div>
+                                                                            </div>
+                                                                        </td>
+                                                                    </tr>
+                                                                    </tbody>
+                                                                    </table>
+                                                                </div>
+                                                        </div>
+                                                    </td>
+                                                </tr>
+                                                </tbody>
+                                                </table>
+                                            </div>
+                                    </div>
+                            </td>
+                    </tr>
+                </tbody>
+            </table>
+        </div>
+    </div>
+<div class="row" style="margin-bottom:24px;"></div>
+<div ng-show="ctrl.showError"  class="alert alert-danger col-md-8" role="alert" style="margin-top:0px">
+        <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
+        <span class="sr-only">Error:</span>
+        {{ctrl.error}}
+</div>
+<div class="row" style="margin-bottom:24px;"></div>
\ No newline at end of file
diff --git a/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js b/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js
new file mode 100644 (file)
index 0000000..eff1930
--- /dev/null
@@ -0,0 +1,724 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+(function () {
+    'use strict';
+
+    angular
+        .module('testapiApp')
+        .controller('ScenarioController', ScenarioController);
+
+        ScenarioController.$inject = [
+        '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert',
+        'confirmModal'
+    ];
+
+    /**
+     * TestAPI Scenario Controller
+     * This controller is for the '/Scenario/:name' page where a user can browse
+     * through Scenario declared in TestAPI.
+     */
+    function ScenarioController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl,
+        raiseAlert, confirmModal) {
+        var ctrl = this;
+        ctrl.name = $state.params['name'];
+        ctrl.url = testapiApiUrl + '/scenarios?name=' + ctrl.name;
+        ctrl.expandInstallers = expandInstallers;
+        ctrl.expandInstaller = expandInstaller;
+        ctrl.expandInstaller = ctrl.expandInstaller;
+        ctrl.expandVersion = expandVersion;
+        ctrl.expandVersions = expandVersions;
+        ctrl.loadDetails = loadDetails;
+        ctrl.expandProjects = expandProjects
+        ctrl.expandProject = expandProject
+        ctrl.expandTrustIndicator = expandTrustIndicator;
+        ctrl.expandScore = expandScore;
+        ctrl.expandCustom = expandCustom;
+        ctrl.collapeVersion = {};
+        ctrl.collapeVersions = {};
+        ctrl.collapeProjects = {};
+        ctrl.collapeProject = {};
+        ctrl.collapeTrustIndicator = {};
+        ctrl.collapeScore = {};
+        ctrl.collapeCustom = {};
+        ctrl.collapeInstaller = {};
+        ctrl.addCustom = addCustom;
+        ctrl.openAddCustomModal = openAddCustomModal;
+        ctrl.openAddTrustIndicatorModal = openAddTrustIndicatorModal;
+        ctrl.addTrustindicator = addTrustindicator;
+        ctrl.addScore = addScore;
+        ctrl.openAddScoreModal = openAddScoreModal;
+        ctrl.openDeleteCustomModal = openDeleteCustomModal;
+        ctrl.deleteCustom = deleteCustom;
+        ctrl.addProject = addProject
+        ctrl.openAddProjectModal = openAddProjectModal
+        ctrl.openAddVersionModal = openAddVersionModal
+        ctrl.addVersion = addVersion
+        ctrl.openDeleteVersionModal = openDeleteVersionModal
+        ctrl.deleteVersion = deleteVersion
+        ctrl.openAddInstaller = openAddInstaller
+        ctrl.addInstaller = addInstaller
+        ctrl.openDeleteInstallerModal = openDeleteInstallerModal
+        ctrl.deleteInstaller = deleteInstaller
+
+        /**
+         * This will contact the TestAPI to get a listing of declared projects.
+         */
+        function loadDetails() {
+            ctrl.showError = false;
+            ctrl.projectsRequest =
+                $http.get(ctrl.url).success(function (data) {
+                    ctrl.data = data;
+                }).catch(function (error) {
+                    ctrl.data = null;
+                    ctrl.showError = true;
+                    ctrl.error = error.statusText
+                });
+        }
+
+        function expandTrustIndicator(index){
+            if(ctrl.collapeTrustIndicator[index]){
+                ctrl.collapeTrustIndicator[index] = false;
+            }else{
+                ctrl.collapeTrustIndicator[index] = true;
+            }
+        }
+
+        function expandScore(index){
+            if(ctrl.collapeScore[index]){
+                ctrl.collapeScore[index] = false;
+            }else{
+                ctrl.collapeScore[index] = true;
+            }
+        }
+
+        function expandCustom(index){
+            if(ctrl.collapeCustom[index]){
+                ctrl.collapeCustom[index] = false;
+            }else{
+                ctrl.collapeCustom[index] = true;
+            }
+        }
+
+        function expandVersion(index){
+            if(ctrl.collapeVersion[index]){
+                ctrl.collapeVersion[index] = false;
+            }else{
+                ctrl.collapeVersion[index] = true;
+            }
+        }
+
+        function expandVersions(index){
+            if(ctrl.collapeVersions[index]){
+                ctrl.collapeVersions[index] = false;
+            }else{
+                ctrl.collapeVersions[index] = true;
+            }
+        }
+
+        function expandProjects(index){
+            if(ctrl.collapeProjects[index]){
+                ctrl.collapeProjects[index] = false;
+            }
+            else{
+                ctrl.collapeProjects[index]= true;
+            }
+        }
+
+        function expandProject(index){
+            if(ctrl.collapeProject[index]){
+                ctrl.collapeProject[index] = false;
+            }
+            else{
+                ctrl.collapeProject[index]= true;
+            }
+        }
+
+        function expandInstaller(index){
+            if(ctrl.collapeInstaller[index]){
+                ctrl.collapeInstaller[index] = false;
+            }
+            else{
+                ctrl.collapeInstaller[index]= true;
+            }
+        }
+
+        function expandInstallers(){
+            if(ctrl.collapeInstallers){
+                ctrl.collapeInstallers= false
+            }else{
+                ctrl.collapeInstallers= true
+            }
+        }
+
+        function deleteInstaller(data){
+            ctrl.installerReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/installers"
+            $http.delete(ctrl.installerReqest, {data: data.installers, headers: {'Content-Type': 'application/json'}}).success(function (data){
+                ctrl.showSuccess = true ;
+                ctrl.success = "Installer is successfully deleted."
+                ctrl.loadDetails();
+            })
+            .catch(function (data) {
+                ctrl.showError = true;
+                ctrl.error = data.statusText;
+            });
+        }
+
+        function openDeleteInstallerModal(installer){
+            var installers = []
+            installers.push(installer)
+            var data = {
+                "installers": installers
+            }
+            confirmModal("Delete",ctrl.deleteInstaller,data);
+        }
+
+        function addInstaller(installer){
+            var installers = []
+            installers.push(installer)
+            ctrl.installerReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/installers"
+            $http.post(ctrl.installerReqest, installers).success(function (data){
+                ctrl.showSuccess = true ;
+                ctrl.success = "Installers are successfully updated."
+                ctrl.loadDetails();
+            })
+            .catch(function (data) {
+                ctrl.showError = true;
+                ctrl.error = data.statusText;
+            });
+        }
+
+        function openAddInstaller(){
+            $uibModal.open({
+                templateUrl: 'testapi-ui/components/scenarios/modals/installerModal.html',
+                controller: 'installerModalCtrl as installerModalCtrl',
+                size: 'md',
+                resolve: {
+                    data: function () {
+                        return {
+                            text: "Add Installer",
+                            successHandler: ctrl.addInstaller
+                        };
+                    }
+                }
+            });
+        }
+
+        function addVersion(versions, installer){
+            ctrl.versionReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/versions?installer="+installer
+            $http.post(ctrl.versionReqest, versions).success(function (data){
+                ctrl.showSuccess = true ;
+                ctrl.success = "Versions are successfully updated."
+                ctrl.loadDetails();
+            })
+            .catch(function (data) {
+                ctrl.showError = true;
+                ctrl.error = data.statusText;
+            });
+        }
+
+        function openDeleteVersionModal(version, installer){
+            var versions = []
+            versions.push(version)
+            var data = {
+                "version": versions,
+                "installer": installer
+            }
+            confirmModal("Delete",ctrl.deleteVersion,data);
+        }
+
+        function deleteVersion(data){
+            ctrl.versionReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/versions?installer="+data.installer
+            $http.delete(ctrl.versionReqest, {data: data.version, headers: {'Content-Type': 'application/json'}}).success(function (data){
+                ctrl.showSuccess = true ;
+                ctrl.success = "Versions are successfully deleted."
+                ctrl.loadDetails();
+            })
+            .catch(function (data) {
+                ctrl.showError = true;
+                ctrl.error = data.statusText;
+            });
+        }
+
+        function openAddVersionModal(installer){
+            $uibModal.open({
+                templateUrl: 'testapi-ui/components/scenarios/modals/versionModal.html',
+                controller: 'versionAddModalCtrl as versionModalCtrl',
+                size: 'md',
+                resolve: {
+                    data: function () {
+                        return {
+                            text: "Add Version",
+                            successHandler: ctrl.addVersion,
+                            installer: installer
+                        };
+                    }
+                }
+            });
+        }
+
+        function addProject(project, version, installer){
+            ctrl.projectReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/projects?installer="+installer+"&version="+version
+            $http.post(ctrl.projectReqest, project).success(function (data){
+                ctrl.showSuccess = true ;
+                ctrl.success = "Projects are successfully updated."
+                ctrl.loadDetails();
+            })
+            .catch(function (data) {
+                ctrl.showError = true;
+                ctrl.error = data.statusText;
+            });
+        }
+
+        function openAddProjectModal(version, installer){
+            $uibModal.open({
+                templateUrl: 'testapi-ui/components/scenarios/modals/projectModal.html',
+                controller: 'projectAddModalCtrl as projectModalCtrl',
+                size: 'md',
+                resolve: {
+                    data: function () {
+                        return {
+                            text: "Add Project",
+                            successHandler: ctrl.addProject,
+                            version: version,
+                            installer: installer
+                        };
+                    }
+                }
+            });
+        }
+
+        function addCustom(custom,project,version,installer){
+            ctrl.customReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/customs?installer="+installer+"&version="+version+"&project="+ project
+            $http.post(ctrl.customReqest, custom).success(function (data){
+                ctrl.showSuccess = true ;
+                ctrl.success = "Customs are successfully updated."
+                ctrl.loadDetails();
+            })
+            .catch(function (data) {
+                ctrl.showError = true;
+                ctrl.error = data.statusText;
+            });
+        }
+
+        function openDeleteCustomModal(custom,project,version,installer){
+            var customs = []
+            customs.push(custom)
+            var data = {
+                "customs": customs,
+                "project": project,
+                "version": version,
+                "installer": installer
+            }
+            confirmModal("Delete",ctrl.deleteCustom,data);
+        }
+
+        function deleteCustom(data){
+            ctrl.customReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/customs?installer="+data.installer+"&version="+data.version+"&project="+ data.project
+            $http.delete(ctrl.customReqest, {data: data.customs, headers: {'Content-Type': 'application/json'}}).success(function (data){
+                ctrl.showSuccess = true ;
+                ctrl.success = "Customs are successfully deleted."
+                ctrl.loadDetails();
+            })
+            .catch(function (data) {
+                ctrl.showError = true;
+                ctrl.error = data.statusText;
+            });
+        }
+
+        function openAddCustomModal(project,version,installer){
+            $uibModal.open({
+                templateUrl: 'testapi-ui/components/scenarios/modals/customModal.html',
+                controller: 'customAddModalCtrl as customModalCtrl',
+                size: 'md',
+                resolve: {
+                    data: function () {
+                        return {
+                            text: "Add Custom",
+                            successHandler: ctrl.addCustom,
+                            project: project,
+                            version: version,
+                            installer: installer
+                        };
+                    }
+                }
+            });
+        }
+
+        function openAddTrustIndicatorModal(project, version, installer){
+            $uibModal.open({
+                templateUrl: 'testapi-ui/components/scenarios/modals/trustIndicatorModal.html',
+                controller: 'trustIndicatorAddModalCtrl as trustIndicatorModalCtrl',
+                size: 'md',
+                resolve: {
+                    data: function () {
+                        return {
+                            text: "Add Trust Indicator",
+                            successHandler: ctrl.addTrustindicator,
+                            project: project,
+                            version: version,
+                            installer: installer
+                        };
+                    }
+                }
+            });
+        }
+
+        function openAddScoreModal(project, version, installer){
+            $uibModal.open({
+                templateUrl: 'testapi-ui/components/scenarios/modals/scoreModal.html',
+                controller: 'scoreAddModalCtrl as scoreModalCtrl',
+                size: 'md',
+                resolve: {
+                    data: function () {
+                        return {
+                            text: "Add Score",
+                            successHandler: ctrl.addScore,
+                            project: project,
+                            version: version,
+                            installer: installer
+                        };
+                    }
+                }
+            });
+        }
+
+        function addTrustindicator(trust_indicator, project, version, installer){
+            ctrl.customReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/trust_indicators?installer="+installer+"&version="+version+"&project="+ project
+            $http.post(ctrl.customReqest,trust_indicator ).success(function (data){
+                ctrl.showSuccess = true ;
+                ctrl.success = "Trust indicators are successfully updated."
+                ctrl.loadDetails();
+            })
+            .catch(function (data) {
+                ctrl.showError = true;
+                ctrl.error = data.statusText;
+            });
+        }
+
+        function addScore(score, project, version, installer){
+            ctrl.customReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/scores?installer="+installer+"&version="+version+"&project="+ project
+            $http.post(ctrl.customReqest,score ).success(function (data){
+                ctrl.showSuccess = true ;
+                ctrl.success = "Scores are successfully updated."
+                ctrl.loadDetails();
+            })
+            .catch(function (data) {
+                ctrl.showError = true;
+                ctrl.error = data.statusText;
+            });
+        }
+
+        ctrl.loadDetails();
+    }
+
+     /**
+     * TestAPI Project  Modal Controller
+     * This controller is for the create modal where a user can create
+     * the project information and for the edit modal where user can
+     * edit the project's details
+     */
+    angular.module('testapiApp').controller('customAddModalCtrl', customAddModalCtrl);
+    customAddModalCtrl.$inject = ['$scope', '$uibModalInstance', 'data'];
+    function customAddModalCtrl($scope, $uibModalInstance, data) {
+        var ctrl = this;
+        ctrl.confirm = confirm;
+        ctrl.cancel = cancel;
+        ctrl.data = angular.copy(data);
+        ctrl.open = open;
+
+
+        /**
+         * Initiate confirmation and call the success handler with the
+         * inputs.
+         */
+        function confirm() {
+            ctrl.customs = []
+            ctrl.customs.push(ctrl.custom)
+            ctrl.data.successHandler(ctrl.customs,ctrl.data.project,ctrl.data.version,ctrl.data.installer);
+            $uibModalInstance.dismiss('cancel');
+
+        }
+
+        /**
+         * Close the confirm modal without initiating changes.
+         */
+        function cancel() {
+            $uibModalInstance.dismiss('cancel');
+        }
+    }
+
+    /**
+     * TestAPI Project  Modal Controller
+     * This controller is for the create modal where a user can create
+     * the project information and for the edit modal where user can
+     * edit the project's details
+     */
+    angular.module('testapiApp').controller('trustIndicatorAddModalCtrl', trustIndicatorAddModalCtrl);
+    trustIndicatorAddModalCtrl.$inject = ['$scope', '$uibModalInstance', 'data'];
+    function trustIndicatorAddModalCtrl($scope, $uibModalInstance, data) {
+        var ctrl = this;
+        ctrl.confirm = confirm;
+        ctrl.cancel = cancel;
+        ctrl.data = angular.copy(data);
+        ctrl.open = open;
+
+
+        /**
+         * Initiate confirmation and call the success handler with the
+         * inputs.
+         */
+        function confirm() {
+            ctrl.data.successHandler(ctrl.ti, ctrl.data.project, ctrl.data.version, ctrl.data.installer);
+            $uibModalInstance.dismiss('cancel');
+
+        }
+
+        /**
+         * Close the confirm modal without initiating changes.
+         */
+        function cancel() {
+            $uibModalInstance.dismiss('cancel');
+        }
+
+        function handleModalData(){
+
+        }
+
+        /**
+         * This is called when the date filter calendar is opened. It
+         * does some event handling, and sets a scope variable so the UI
+         * knows which calendar was opened.
+         * @param {Object} $event - The Event object
+         * @param {String} openVar - Tells which calendar was opened
+         */
+        function open($event, openVar) {
+            $event.preventDefault();
+            $event.stopPropagation();
+            ctrl[openVar] = true;
+        }
+    }
+
+        /**
+     * TestAPI Project  Modal Controller
+     * This controller is for the create modal where a user can create
+     * the project information and for the edit modal where user can
+     * edit the project's details
+     */
+    angular.module('testapiApp').controller('scoreAddModalCtrl', scoreAddModalCtrl);
+    scoreAddModalCtrl.$inject = ['$scope', '$uibModalInstance', 'data'];
+    function scoreAddModalCtrl($scope, $uibModalInstance, data) {
+        var ctrl = this;
+        ctrl.confirm = confirm;
+        ctrl.cancel = cancel;
+        ctrl.data = angular.copy(data);
+        ctrl.open = open;
+
+        /**
+         * Initiate confirmation and call the success handler with the
+         * inputs.
+         */
+        function confirm() {
+            ctrl.data.successHandler(ctrl.score, ctrl.data.project, ctrl.data.version, ctrl.data.installer);
+            $uibModalInstance.dismiss('cancel');
+        }
+
+        /**
+         * Close the confirm modal without initiating changes.
+         */
+        function cancel() {
+            $uibModalInstance.dismiss('cancel');
+        }
+
+        function handleModalData(){
+
+        }
+
+        /**
+         * This is called when the date filter calendar is opened. It
+         * does some event handling, and sets a scope variable so the UI
+         * knows which calendar was opened.
+         * @param {Object} $event - The Event object
+         * @param {String} openVar - Tells which calendar was opened
+         */
+        function open($event, openVar) {
+            $event.preventDefault();
+            $event.stopPropagation();
+            ctrl[openVar] = true;
+        }
+    }
+
+     /**
+     * TestAPI Project  Modal Controller
+     * This controller is for the create modal where a user can create
+     * the project information and for the edit modal where user can
+     * edit the project's details
+    */
+    angular.module('testapiApp').controller('projectAddModalCtrl', projectAddModalCtrl);
+    projectAddModalCtrl.$inject = ['$scope', '$uibModal', '$uibModalInstance', 'data'];
+    function projectAddModalCtrl($scope, $uibModal, $uibModalInstance, data) {
+        var ctrl = this;
+        ctrl.confirm = confirm;
+        ctrl.cancel = cancel;
+        ctrl.data = angular.copy(data);
+        ctrl.openScoreModal = openScoreModal;
+        ctrl.openTrustIndicatorModal = openTrustIndicatorModal;
+        ctrl.openCustomModal = openCustomModal;
+        ctrl.handleScore = handleScore;
+        ctrl.handleModalTrustIndicator = handleModalTrustIndicator;
+        ctrl.handleModalCustom = handleModalCustom;
+        ctrl.projects = []
+        ctrl.project = {
+            "scores": [],
+            "trust_indicators": [],
+            "customs": []
+        }
+
+
+        /**
+         * Initiate confirmation and call the success handler with the
+         * inputs.
+         */
+        function confirm() {
+            ctrl.projects.push(ctrl.project)
+            ctrl.data.successHandler(ctrl.projects, ctrl.data.version, ctrl.data.installer);
+            $uibModalInstance.dismiss('cancel');
+
+        }
+
+        /**
+         * Close the confirm modal without initiating changes.
+         */
+        function cancel() {
+            $uibModalInstance.dismiss('cancel');
+        }
+
+        function handleModalTrustIndicator(trustIndicator){
+            ctrl.project.trust_indicators.push(trustIndicator)
+        }
+
+        function handleScore(score){
+            ctrl.project.scores.push(score);
+        }
+
+        function handleModalCustom(custom){
+            ctrl.project.customs.push(custom);
+        }
+
+        function openScoreModal(){
+            $uibModal.open({
+                templateUrl: 'testapi-ui/components/scenarios/modals/scoreModal.html',
+                controller: 'scoreModalCtrl as scoreModalCtrl',
+                size: 'md',
+                resolve: {
+                    data: function () {
+                        return {
+                            text: "Score",
+                            successHandler: ctrl.handleScore,
+                        };
+                    }
+                }
+            });
+        }
+        function openTrustIndicatorModal(){
+            $uibModal.open({
+                templateUrl: 'testapi-ui/components/scenarios/modals/trustIndicatorModal.html',
+                controller: 'trustIndicatorModalCtrl as trustIndicatorModalCtrl',
+                size: 'md',
+                resolve: {
+                    data: function () {
+                        return {
+                            text: "Trust Indicator",
+                            successHandler: ctrl.handleModalTrustIndicator
+                        };
+                    }
+                }
+            });
+        }
+        function openCustomModal(){
+            $uibModal.open({
+                templateUrl: 'testapi-ui/components/scenarios/modals/customModal.html',
+                controller: 'customModalCtrl as customModalCtrl',
+                size: 'md',
+                resolve: {
+                    data: function () {
+                        return {
+                            text: "Custom",
+                            successHandler: ctrl.handleModalCustom
+                        };
+                    }
+                }
+            });
+        }
+    }
+
+        /**
+     * TestAPI Project  Modal Controller
+     * This controller is for the create modal where a user can create
+     * the project information and for the edit modal where user can
+     * edit the project's details
+    */
+    angular.module('testapiApp').controller('versionAddModalCtrl', versionAddModalCtrl);
+    versionAddModalCtrl.$inject = ['$scope', '$uibModal','$uibModalInstance', 'data'];
+    function versionAddModalCtrl($scope, $uibModal, $uibModalInstance, data) {
+        var ctrl = this;
+        ctrl.confirm = confirm;
+        ctrl.cancel = cancel;
+        ctrl.data = angular.copy(data);
+        ctrl.openProjectModal = openProjectModal;
+        ctrl.handleModalData = handleModalData;
+        ctrl.versions = []
+        ctrl.version = {
+            "projects": []
+        }
+
+        /**
+         * Initiate confirmation and call the success handler with the
+         * inputs.
+         */
+        function confirm() {
+            ctrl.versions.push(ctrl.version)
+            ctrl.data.successHandler(ctrl.versions, ctrl.data.installer);
+            $uibModalInstance.dismiss('cancel');
+
+        }
+
+        /**
+         * Close the confirm modal without initiating changes.
+         */
+        function cancel() {
+            $uibModalInstance.dismiss('cancel');
+        }
+
+        function handleModalData(project){
+            ctrl.version.projects.push(project)
+        }
+        function openProjectModal(){
+            $uibModal.open({
+                templateUrl: 'testapi-ui/components/scenarios/modals/projectModal.html',
+                controller: 'projectModalCtrl as projectModalCtrl',
+                size: 'md',
+                resolve: {
+                    data: function () {
+                        return {
+                            text: "Project",
+                            successHandler: ctrl.handleModalData,
+                        };
+                    }
+                }
+            });
+        }
+    }
+
+})();
diff --git a/testapi/opnfv_testapi/ui/components/scenarios/scenarios.html b/testapi/opnfv_testapi/ui/components/scenarios/scenarios.html
new file mode 100644 (file)
index 0000000..75a21b7
--- /dev/null
@@ -0,0 +1,60 @@
+<h3>Scenarios</h3>
+<div class="row" style="margin-bottom:24px;"></div>
+<div class="row podsTable" style="vertical-align:middle">
+    <div class="col-sm-1 pull-right" ng-class="{ 'hidden': !auth.isAuthenticated }" >
+        <button type="button" class="btn btn-danger" ng-click="ctrl.openBatchDeleteModal()">
+              <i class="fa fa-minus"></i> Delete</button>
+    </div>
+    <div class="col-sm-2 pull-right"  ng-class="{ 'hidden': !auth.isAuthenticated}">
+        <button type="button" class="btn btn-success" ng-click="ctrl.openScenarioModal()">
+          <i class="fa fa-plus"></i>Create&nbsp;Scenario</button>
+    </div>
+</div>
+<div class='clo-md-12'>
+    <div ng-show="ctrl.showError" class="alert alert-danger" role="alert">
+        <span class="pull-right">&nbsp;{{ctrl.error}}</span>
+        <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span>
+    </div>
+    <div ng-show="ctrl.showCreateSuccess" class="alert alert-success" role="alert">
+        <span class="pull-right">&nbsp;{{ctrl.success}}</span>
+        <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span>
+    </div>
+</div>
+<div class='clo-md-12' style="padding-right:0px">
+    <div class="table-responsive">
+        <table class="table table-bordered table-hover"  ng-data="ctrl.data.scenarios">
+        <thead>
+        <tr style="
+        text-align: center;">
+            <th style="width: 1%;">Bulk&nbsp;Select</th>
+            <th style="width: 80%;">Name</th>
+            <th style="width: 19%;" ng-class="{'hidden': !auth.isAuthenticated}">Operations</th>
+        </tr>
+        </thead>
+        <tbody>
+        <tr ng-repeat-start="(index, scenario) in ctrl.data.scenarios" style="padding:9px">
+            <td>
+                <div class="text-center">
+                    <input type="checkbox" value="{{scenario.name}}"  ng-model="ctrl.checkBox[index]" >
+                </div>
+            </td>
+            <td>
+                <a class="text-info" ng-click="ctrl.viewScenario(scenario.name)">
+                    {{scenario.name}}
+                </a>
+            </td>
+            <td ng-class="{'hidden': !auth.isAuthenticated}">
+                <span class="podsTable-col">
+                    <a class="text-warning" ng-click="ctrl.openUpdateModal(scenario.name)" title="Edit Name">
+                        <i class="fa fa-pencil-square-o"></i></a>
+                    <a class="text-danger"  ng-click="ctrl.openDeleteModal(scenario.name)" title="Delete">
+                        <i class="fa fa-trash-o"></i></a>
+                </span>
+            </td>
+        <tr ng-repeat-end=>
+        </tr>
+        </tbody>
+        </table>
+    </div>
+</div>
+
diff --git a/testapi/opnfv_testapi/ui/components/scenarios/scenariosController.js b/testapi/opnfv_testapi/ui/components/scenarios/scenariosController.js
new file mode 100644 (file)
index 0000000..4243e21
--- /dev/null
@@ -0,0 +1,609 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+(function () {
+    'use strict';
+
+    angular
+        .module('testapiApp')
+        .controller('ScenariosController', ScenariosController);
+
+        ScenariosController.$inject = [
+        '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl',
+        'raiseAlert', 'confirmModal'
+    ];
+
+    /**
+     * TestAPI Project Controller
+     * This controller is for the '/projects' page where a user can browse
+     * through projects declared in TestAPI.
+     */
+    function ScenariosController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl,
+        raiseAlert, confirmModal) {
+        var ctrl = this;
+        ctrl.url = testapiApiUrl + '/scenarios';
+
+        ctrl.createScenario = createScenario;
+        ctrl.listScenarios = listScenarios;
+        ctrl.openScenarioModal = openScenarioModal;
+        ctrl.viewScenario = viewScenario;
+        ctrl.openUpdateModal = openUpdateModal;
+        ctrl.updateScenarioName = updateScenarioName;
+        ctrl.openDeleteModal = openDeleteModal;
+        ctrl.deleteScenario = deleteScenario;
+        ctrl.openBatchDeleteModal = openBatchDeleteModal;
+        ctrl.deleteBatchScenario = deleteBatchScenario
+
+        ctrl.checkBox = [];
+
+        function openUpdateModal(name){
+            $uibModal.open({
+                templateUrl: 'testapi-ui/components/scenarios/modals/scenarioNameUpdate.html',
+                controller: 'ScenarioNameUpdateCtrl as ScenarioNameUpdateCtrl',
+                size: 'md',
+                resolve: {
+                    data: function () {
+                        return {
+                            text: "Name Change: Scenario",
+                            successHandler: ctrl.updateScenarioName,
+                            name: name
+                        };
+                    }
+                }
+            });
+        }
+
+        function openDeleteModal(name){
+            confirmModal("Delete",ctrl.deleteScenario,name);
+        }
+
+        function deleteScenario(name){
+            var scenarioURL = ctrl.url+"/"+name;
+            ctrl.scenarioRequest =
+                $http.delete(scenarioURL).success(function (data){
+                    ctrl.showCreateSuccess = true;
+                    ctrl.success = "Scenario is successfully deleted.";
+                    ctrl.listScenarios();
+                }).catch(function (data) {
+                    ctrl.showError = true;
+                    ctrl.error = data.statusText;
+                });
+        }
+
+        function openBatchDeleteModal(){
+            confirmModal("Delete",ctrl.deleteBatchScenario);
+        }
+
+        function deleteBatchScenario(){
+            var index;
+            var checkedBox = [];
+            ctrl.checkBox.forEach(function(project, index){
+                if(!ctrl.showError){
+                    if(project){
+                        deleteScenario(ctrl.data.scenarios[index].name);
+                    }
+                }
+              });
+            ctrl.checkBox = []
+        }
+
+        function updateScenarioName(newName, name){
+            var scenarioURL = ctrl.url+"/"+name
+            var body = {
+                "name": newName
+            }
+            ctrl.scenarioRequest =
+                $http.put(scenarioURL, body).success(function (data){
+                    ctrl.showCreateSuccess = true;
+                    ctrl.success = "Scenario is successfully Updated."
+                    ctrl.listScenarios()
+                }).catch(function (data) {
+                    ctrl.showError = true;
+                    ctrl.error = data.statusText;
+                });
+        }
+
+        function viewScenario(name){
+            $state.go('scenario', {'name':name}, {reload: true});
+        }
+
+        function createScenario(scenario) {
+            console.log(scenario)
+            ctrl.scenarioRequest =
+                $http.post(ctrl.url, scenario).success(function (data){
+                    ctrl.showCreateSuccess = true;
+                    ctrl.success = "Scenario is successfully created."
+                }).catch(function (data) {
+                    ctrl.showError = true;
+                    ctrl.error = data.statusText;
+                });
+        }
+
+       function listScenarios() {
+           ctrl.showError = false;
+           ctrl.resultsRequest =
+               $http.get(ctrl.url).success(function (data) {
+                   ctrl.data = data;
+               }).catch(function (data)  {
+                   ctrl.data = null;
+                   ctrl.showError = true;
+                   ctrl.error = data.statusText;
+               });
+       }
+
+    function openScenarioModal(){
+        $uibModal.open({
+            templateUrl: 'testapi-ui/components/scenarios/modals/scenarioModal.html',
+            controller: 'scenarioModalController as scenarioModalController',
+            size: 'md',
+            resolve: {
+                data: function () {
+                    return {
+                        text: "Scenario",
+                        successHandler: ctrl.createScenario,
+                    };
+                }
+            }
+        });
+    }
+
+       listScenarios();
+    }
+
+
+    /**
+     * TestAPI Project  Modal Controller
+     * This controller is for the create modal where a user can create
+     * the project information and for the edit modal where user can
+     * edit the project's details
+     */
+    angular.module('testapiApp').controller('scenarioModalController', scenarioModalController);
+    scenarioModalController.$inject = ['$scope', '$uibModal', '$uibModalInstance', 'data'];
+    function scenarioModalController($scope, $uibModal, $uibModalInstance, data) {
+        var ctrl = this;
+        ctrl.confirm = confirm;
+        ctrl.cancel = cancel;
+        ctrl.data = angular.copy(data);
+        ctrl.handleModalData = handleModalData;
+        ctrl.openInstallerModal = openInstallerModal;
+        ctrl.scenario = {
+            "installers": [],
+        }
+
+
+        /**
+         * Initiate confirmation and call the success handler with the
+         * inputs.
+         */
+        function confirm() {
+            ctrl.data.successHandler(ctrl.scenario);
+            $uibModalInstance.dismiss('cancel');
+
+        }
+
+        /**
+         * Close the confirm modal without initiating changes.
+         */
+        function cancel() {
+            $uibModalInstance.dismiss('cancel');
+        }
+
+        function handleModalData(installer){
+           ctrl.scenario.installers.push(installer)
+        }
+
+        function openInstallerModal(){
+            $uibModal.open({
+                templateUrl: 'testapi-ui/components/scenarios/modals/installerModal.html',
+                controller: 'installerModalCtrl as installerModalCtrl',
+                size: 'md',
+                resolve: {
+                    data: function () {
+                        return {
+                            text: "Installer",
+                            successHandler: ctrl.handleModalData,
+                        };
+                    }
+                }
+            });
+        }
+    }
+
+    /**
+     * TestAPI Project  Modal Controller
+     * This controller is for the create modal where a user can create
+     * the project information and for the edit modal where user can
+     * edit the project's details
+     */
+    angular.module('testapiApp').controller('installerModalCtrl', installerModalCtrl);
+    installerModalCtrl.$inject = ['$scope', '$uibModal', '$uibModalInstance', 'data'];
+    function installerModalCtrl($scope, $uibModal, $uibModalInstance, data) {
+        var ctrl = this;
+        ctrl.confirm = confirm;
+        ctrl.cancel = cancel;
+        ctrl.data = angular.copy(data);
+        ctrl.openVersionModal = openVersionModal;
+        ctrl.handleModalData = handleModalData;
+        ctrl.installer = {
+            "versions":[]
+        }
+
+
+        /**
+         * Initiate confirmation and call the success handler with the
+         * inputs.
+         */
+        function confirm() {
+            ctrl.data.successHandler(ctrl.installer);
+            $uibModalInstance.dismiss('cancel');
+
+        }
+
+        /**
+         * Close the confirm modal without initiating changes.
+         */
+        function cancel() {
+            $uibModalInstance.dismiss('cancel');
+        }
+
+        function handleModalData(version){
+            ctrl.installer.versions.push(version);
+        }
+
+        function openVersionModal(){
+            console.log("Hello");
+            $uibModal.open({
+                templateUrl: 'testapi-ui/components/scenarios/modals/versionModal.html',
+                controller: 'versionModalCtrl as versionModalCtrl',
+                size: 'md',
+                resolve: {
+                    data: function () {
+                        return {
+                            text: "Version",
+                            successHandler: ctrl.handleModalData,
+                        };
+                    }
+                }
+            });
+        }
+    }
+
+    /**
+     * TestAPI Project  Modal Controller
+     * This controller is for the create modal where a user can create
+     * the project information and for the edit modal where user can
+     * edit the project's details
+    */
+    angular.module('testapiApp').controller('versionModalCtrl', versionModalCtrl);
+    versionModalCtrl.$inject = ['$scope', '$uibModal','$uibModalInstance', 'data'];
+    function versionModalCtrl($scope, $uibModal, $uibModalInstance, data) {
+        var ctrl = this;
+        ctrl.confirm = confirm;
+        ctrl.cancel = cancel;
+        ctrl.data = angular.copy(data);
+        ctrl.openProjectModal = openProjectModal;
+        ctrl.handleModalData = handleModalData;
+        ctrl.version = {
+            "projects": []
+        }
+
+        /**
+         * Initiate confirmation and call the success handler with the
+         * inputs.
+         */
+        function confirm() {
+            ctrl.data.successHandler(ctrl.version);
+            $uibModalInstance.dismiss('cancel');
+
+        }
+
+        /**
+         * Close the confirm modal without initiating changes.
+         */
+        function cancel() {
+            $uibModalInstance.dismiss('cancel');
+        }
+
+        function handleModalData(project){
+            ctrl.version.projects.push(project)
+        }
+        function openProjectModal(){
+            $uibModal.open({
+                templateUrl: 'testapi-ui/components/scenarios/modals/projectModal.html',
+                controller: 'projectModalCtrl as projectModalCtrl',
+                size: 'md',
+                resolve: {
+                    data: function () {
+                        return {
+                            text: "Project",
+                            successHandler: ctrl.handleModalData,
+                        };
+                    }
+                }
+            });
+        }
+    }
+
+    /**
+     * TestAPI Project  Modal Controller
+     * This controller is for the create modal where a user can create
+     * the project information and for the edit modal where user can
+     * edit the project's details
+    */
+    angular.module('testapiApp').controller('projectModalCtrl', projectModalCtrl);
+    projectModalCtrl.$inject = ['$scope', '$uibModal', '$uibModalInstance', 'data'];
+    function projectModalCtrl($scope, $uibModal, $uibModalInstance, data) {
+        var ctrl = this;
+        ctrl.confirm = confirm;
+        ctrl.cancel = cancel;
+        ctrl.data = angular.copy(data);
+        ctrl.openScoreModal = openScoreModal;
+        ctrl.openTrustIndicatorModal = openTrustIndicatorModal;
+        ctrl.openCustomModal = openCustomModal;
+        ctrl.handleScore = handleScore;
+        ctrl.handleModalTrustIndicator = handleModalTrustIndicator;
+        ctrl.handleModalCustom = handleModalCustom;
+        ctrl.project = {
+            "scores": [],
+            "trust_indicators": [],
+            "customs": []
+        }
+
+
+        /**
+         * Initiate confirmation and call the success handler with the
+         * inputs.
+         */
+        function confirm() {
+
+            ctrl.data.successHandler(ctrl.project);
+            $uibModalInstance.dismiss('cancel');
+
+        }
+
+        /**
+         * Close the confirm modal without initiating changes.
+         */
+        function cancel() {
+            $uibModalInstance.dismiss('cancel');
+        }
+
+        function handleModalTrustIndicator(trustIndicator){
+            ctrl.project.trust_indicators.push(trustIndicator)
+        }
+
+        function handleScore(score){
+            ctrl.project.scores.push(score);
+        }
+
+        function handleModalCustom(custom){
+            ctrl.project.customs.push(custom);
+        }
+
+        function openScoreModal(){
+            $uibModal.open({
+                templateUrl: 'testapi-ui/components/scenarios/modals/scoreModal.html',
+                controller: 'scoreModalCtrl as scoreModalCtrl',
+                size: 'md',
+                resolve: {
+                    data: function () {
+                        return {
+                            text: "Score",
+                            successHandler: ctrl.handleScore,
+                        };
+                    }
+                }
+            });
+        }
+        function openTrustIndicatorModal(){
+            $uibModal.open({
+                templateUrl: 'testapi-ui/components/scenarios/modals/trustIndicatorModal.html',
+                controller: 'trustIndicatorModalCtrl as trustIndicatorModalCtrl',
+                size: 'md',
+                resolve: {
+                    data: function () {
+                        return {
+                            text: "Trust Indicator",
+                            successHandler: ctrl.handleModalTrustIndicator
+                        };
+                    }
+                }
+            });
+        }
+        function openCustomModal(){
+            $uibModal.open({
+                templateUrl: 'testapi-ui/components/scenarios/modals/customModal.html',
+                controller: 'customModalCtrl as customModalCtrl',
+                size: 'md',
+                resolve: {
+                    data: function () {
+                        return {
+                            text: "Custom",
+                            successHandler: ctrl.handleModalCustom
+                        };
+                    }
+                }
+            });
+        }
+    }
+
+    /**
+     * TestAPI Project  Modal Controller
+     * This controller is for the create modal where a user can create
+     * the project information and for the edit modal where user can
+     * edit the project's details
+     */
+    angular.module('testapiApp').controller('scoreModalCtrl', scoreModalCtrl);
+    scoreModalCtrl.$inject = ['$scope', '$uibModalInstance', 'data'];
+    function scoreModalCtrl($scope, $uibModalInstance, data) {
+        var ctrl = this;
+        ctrl.confirm = confirm;
+        ctrl.cancel = cancel;
+        ctrl.data = angular.copy(data);
+        ctrl.open = open;
+
+        /**
+         * Initiate confirmation and call the success handler with the
+         * inputs.
+         */
+        function confirm() {
+            ctrl.data.successHandler(ctrl.score);
+            $uibModalInstance.dismiss('cancel');
+        }
+
+        /**
+         * Close the confirm modal without initiating changes.
+         */
+        function cancel() {
+            $uibModalInstance.dismiss('cancel');
+        }
+
+        function handleModalData(){
+
+        }
+
+        /**
+         * This is called when the date filter calendar is opened. It
+         * does some event handling, and sets a scope variable so the UI
+         * knows which calendar was opened.
+         * @param {Object} $event - The Event object
+         * @param {String} openVar - Tells which calendar was opened
+         */
+        function open($event, openVar) {
+            $event.preventDefault();
+            $event.stopPropagation();
+            ctrl[openVar] = true;
+        }
+    }
+
+     /**
+     * TestAPI Project  Modal Controller
+     * This controller is for the create modal where a user can create
+     * the project information and for the edit modal where user can
+     * edit the project's details
+     */
+    angular.module('testapiApp').controller('trustIndicatorModalCtrl', trustIndicatorModalCtrl);
+    trustIndicatorModalCtrl.$inject = ['$scope', '$uibModalInstance', 'data'];
+    function trustIndicatorModalCtrl($scope, $uibModalInstance, data) {
+        var ctrl = this;
+        ctrl.confirm = confirm;
+        ctrl.cancel = cancel;
+        ctrl.data = angular.copy(data);
+        ctrl.open = open;
+
+
+        /**
+         * Initiate confirmation and call the success handler with the
+         * inputs.
+         */
+        function confirm() {
+            ctrl.data.successHandler(ctrl.ti);
+            $uibModalInstance.dismiss('cancel');
+
+        }
+
+        /**
+         * Close the confirm modal without initiating changes.
+         */
+        function cancel() {
+            $uibModalInstance.dismiss('cancel');
+        }
+
+        function handleModalData(){
+
+        }
+
+        /**
+         * This is called when the date filter calendar is opened. It
+         * does some event handling, and sets a scope variable so the UI
+         * knows which calendar was opened.
+         * @param {Object} $event - The Event object
+         * @param {String} openVar - Tells which calendar was opened
+         */
+        function open($event, openVar) {
+            $event.preventDefault();
+            $event.stopPropagation();
+            ctrl[openVar] = true;
+        }
+    }
+
+    /**
+     * TestAPI Project  Modal Controller
+     * This controller is for the create modal where a user can create
+     * the project information and for the edit modal where user can
+     * edit the project's details
+     */
+    angular.module('testapiApp').controller('customModalCtrl', customModalCtrl);
+    customModalCtrl.$inject = ['$scope', '$uibModalInstance', 'data'];
+    function customModalCtrl($scope, $uibModalInstance, data) {
+        var ctrl = this;
+        ctrl.confirm = confirm;
+        ctrl.cancel = cancel;
+        ctrl.data = angular.copy(data);
+        ctrl.open = open;
+
+
+        /**
+         * Initiate confirmation and call the success handler with the
+         * inputs.
+         */
+        function confirm() {
+            ctrl.data.successHandler(ctrl.custom);
+            $uibModalInstance.dismiss('cancel');
+
+        }
+
+        /**
+         * Close the confirm modal without initiating changes.
+         */
+        function cancel() {
+            $uibModalInstance.dismiss('cancel');
+        }
+    }
+
+    /**
+     * TestAPI Project  Modal Controller
+     * This controller is for the create modal where a user can create
+     * the project information and for the edit modal where user can
+     * edit the project's details
+     */
+    angular.module('testapiApp').controller('ScenarioNameUpdateCtrl', ScenarioNameUpdateCtrl);
+    ScenarioNameUpdateCtrl.$inject = ['$scope', '$uibModalInstance', 'data'];
+    function ScenarioNameUpdateCtrl($scope, $uibModalInstance, data) {
+        var ctrl = this;
+        ctrl.confirm = confirm;
+        ctrl.cancel = cancel;
+        ctrl.data = angular.copy(data);
+        ctrl.open = open;
+        ctrl.name = ctrl.data.name;
+
+
+        /**
+         * Initiate confirmation and call the success handler with the
+         * inputs.
+         */
+        function confirm() {
+            ctrl.data.successHandler(ctrl.name,ctrl.data.name);
+            $uibModalInstance.dismiss('cancel');
+
+        }
+
+        /**
+         * Close the confirm modal without initiating changes.
+         */
+        function cancel() {
+            $uibModalInstance.dismiss('cancel');
+        }
+    }
+})();
index 98f1ed8..5f982a2 100644 (file)
@@ -44,6 +44,8 @@
         <script src="testapi-ui/shared/alerts/alertModalFactory.js"></script>
         <script src="testapi-ui/shared/alerts/confirmModalFactory.js"></script>
         <script src="testapi-ui/components/pods/podsController.js"></script>
+        <script src="testapi-ui/components/scenarios/scenario/scenarioController.js"></script>
+        <script src="testapi-ui/components/scenarios/scenariosController.js"></script>
         <script src="testapi-ui/components/pods/pod/podController.js"></script>
         <script src="testapi-ui/components/projects/projectsController.js"></script>
         <script src="testapi-ui/components/projects/project/projectController.js"></script>
index d0501a2..6bbdcb8 100644 (file)
@@ -19,7 +19,8 @@ TestAPI
             <li ng-class="{ active: header.isActive('/about')}"><a ui-sref="about">About</a></li>
             <li ng-class="{ active: header.isActive('/pods')}"><a ui-sref="pods">Pods</a></li>
             <li ng-class="{ active: header.isActive('/projects')}"><a ui-sref="projects">Projects</a></li>
-              <li ng-class="{ active: header.isActive('/results')}"><a ui-sref="results">Results</a></li>
+            <li ng-class="{ active: header.isActive('/results')}"><a ui-sref="results">Results</a></li>
+            <li ng-class="{ active: header.isActive('/scenarios')}"><a ui-sref="scenarios">Scenarios</a></li>
           </ul>
           <ul class="nav navbar-nav navbar-right">
             <li ng-class="{ active: header.isActive('/profile')}" ng-if="auth.isAuthenticated"><a ui-sref="profile">Profile</a></li>
index fbd2e0e..f752a64 100644 (file)
@@ -9,3 +9,4 @@ epydoc>=0.3.1
 six>=1.9.0  # MIT
 motor  # Apache-2.0
 python-cas
+requests[security]
\ No newline at end of file