-
+
[SubProject Dependencies]
diff --git a/app/cdash/tests/CMakeLists.txt b/app/cdash/tests/CMakeLists.txt
index 6b5117bc20..3a7743b0ee 100644
--- a/app/cdash/tests/CMakeLists.txt
+++ b/app/cdash/tests/CMakeLists.txt
@@ -228,6 +228,7 @@ add_php_test(redundanttests)
add_php_test(configureappend)
add_php_test(notesparsererrormessages)
add_php_test(viewsubprojectslinkoption)
+add_laravel_test(/Feature/SubProjectDependencies)
add_subdirectory(ctest)
diff --git a/app/cdash/tests/js/e2e_tests/CMakeLists.txt b/app/cdash/tests/js/e2e_tests/CMakeLists.txt
index 95ad86e83c..e13fa2e575 100644
--- a/app/cdash/tests/js/e2e_tests/CMakeLists.txt
+++ b/app/cdash/tests/js/e2e_tests/CMakeLists.txt
@@ -18,6 +18,7 @@ function(add_protractor_test test_name)
endfunction()
add_cypress_test(manage-overview)
+add_cypress_test(sub-project-dependencies)
add_protractor_test(manageBuildGroup)
add_protractor_test(manageSubProject)
add_protractor_test(viewBuildError)
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
index c777216d9d..61a92e37ee 100644
--- a/phpstan-baseline.neon
+++ b/phpstan-baseline.neon
@@ -2420,11 +2420,6 @@ parameters:
count: 2
path: app/Http/Controllers/SubProjectController.php
- -
- message: "#^Method App\\\\Http\\\\Controllers\\\\SubProjectController\\:\\:dependenciesGraph\\(\\) never returns Illuminate\\\\Http\\\\RedirectResponse so it can be removed from the return type\\.$#"
- count: 1
- path: app/Http/Controllers/SubProjectController.php
-
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 1
diff --git a/resources/js/app.js b/resources/js/app.js
index 14266a059e..d8cf7145dd 100755
--- a/resources/js/app.js
+++ b/resources/js/app.js
@@ -21,6 +21,7 @@ import HeaderMenu from './components/page-header/HeaderMenu.vue';
import HeaderLogo from './components/page-header/HeaderLogo.vue';
import ViewDynamicAnalysis from './components/ViewDynamicAnalysis.vue';
import AllProjects from './components/AllProjects.vue';
+import SubProjectDependencies from './components/SubProjectDependencies.vue';
const cdash_components = {
BuildConfigure,
@@ -38,6 +39,7 @@ const cdash_components = {
HeaderLogo,
ViewDynamicAnalysis,
AllProjects,
+ SubProjectDependencies,
};
/**
diff --git a/resources/js/components/SubProjectDependencies.vue b/resources/js/components/SubProjectDependencies.vue
new file mode 100644
index 0000000000..3281b8b320
--- /dev/null
+++ b/resources/js/components/SubProjectDependencies.vue
@@ -0,0 +1,339 @@
+
+
+
{{ cdash.error }}
+
+
+
+
+ This circle plot captures the interrelationships among subgroups. Mouse over any of the subgroup in this graph to see incoming links (dependents) in green and the outgoing links (dependencies) in red.
+
+
+
+
+
+
- This circle plot captures the interrelationships among subgroups. Mouse over any of the subgroup in this graph to see incoming links (dependents) in green and the outgoing links (dependencies) in red.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@endsection
diff --git a/routes/api.php b/routes/api.php
index 0fb9a60f5a..d4ac331f89 100755
--- a/routes/api.php
+++ b/routes/api.php
@@ -41,6 +41,8 @@
Route::get('/v1/viewSubProjects.php', 'SubProjectController@apiViewSubProjects');
+Route::get('/v1/getSubProjectDependencies.php', 'SubProjectController@apiDependenciesGraph');
+
Route::get('/v1/viewDynamicAnalysis.php', 'DynamicAnalysisController@apiViewDynamicAnalysis');
Route::get('/v1/viewDynamicAnalysisFile.php', 'DynamicAnalysisController@apiViewDynamicAnalysisFile');
diff --git a/routes/web.php b/routes/web.php
index 206e61dfb1..440104dbe0 100755
--- a/routes/web.php
+++ b/routes/web.php
@@ -175,9 +175,11 @@
Route::get('/manageSubProject.php', 'SubProjectController@manageSubProject');
-Route::get('/viewSubProjectDependenciesGraph.php', 'SubProjectController@dependenciesGraph');
-// TODO: (williamjallen) Replace this /ajax route with an equivalent /api route
-Route::get('/ajax/getsubprojectdependencies.php', 'SubProjectController@ajaxDependenciesGraph');
+Route::get('/projects/{project}/subprojects/dependencies', 'SubProjectController@dependenciesGraph');
+Route::get('/viewSubProjectDependenciesGraph.php', function (Request $request) {
+ $project = $request->string('project');
+ return redirect("/projects/{$project}/subprojects/dependencies", 301);
+});
Route::match(['get', 'post'], '/sites/{siteid}', 'SiteController@viewSite')->whereNumber('siteid');
Route::get('/viewSite.php', function (Request $request) {
diff --git a/tests/Feature/SubProjectDependencies.php b/tests/Feature/SubProjectDependencies.php
new file mode 100644
index 0000000000..2638e726a1
--- /dev/null
+++ b/tests/Feature/SubProjectDependencies.php
@@ -0,0 +1,37 @@
+getJson($api_route)->assertJsonStructure([
+ 'error',
+ 'code',
+ ]);
+ $_GET['project'] = 'NoSuchProject'; // hack until we migrate to laravel
+ $this->getJson($api_route)->assertJsonStructure([
+ 'error',
+ 'code',
+ ]);
+
+ // verify api response for non-empty project
+ $_GET['project'] = 'SubProjectExample'; // hack until we migrate to laravel
+ $_GET['date'] = '2009-08-06 12:19:56';
+ $this->getJson($api_route)->assertJsonStructure([
+ 'dependencies' => [
+ [
+ "name",
+ "id",
+ "depends",
+ ],
+ ],
+ ]);
+ }
+}
diff --git a/tests/cypress/e2e/sub-project-dependencies.cy.js b/tests/cypress/e2e/sub-project-dependencies.cy.js
new file mode 100644
index 0000000000..9459e04e2f
--- /dev/null
+++ b/tests/cypress/e2e/sub-project-dependencies.cy.js
@@ -0,0 +1,34 @@
+describe('SubProjectDependencies', () => {
+ it('loads the dependency graph', () => {
+ cy.visit('projects/SubProjectExample/subprojects/dependencies?2015-01-28%2014:36:08');
+
+ cy.get('[data-cy="svg-wrapper"]').should('have.descendants', 'svg');
+ });
+
+
+ it('can interact with the dependency graph', () => {
+ cy.visit('projects/SubProjectExample/subprojects/dependencies?2015-01-28%2014:36:08');
+
+ // check that the graph sorting works
+ cy.get('[data-cy="select-sorting-order"]').find('option').contains('subproject name').should('be.selected');
+ cy.get('text.node').first().should('contain', 'Amesos');
+ cy.get('[data-cy="select-sorting-order"]').select('subproject id');
+ cy.get('text.node').first().should('contain', 'Teuchos');
+ cy.get('[data-cy="select-sorting-order"]').select('subproject name'); // restore to default
+
+ // check tooltip displays as expected
+ cy.get('[data-cy="tooltip"]').should('have.css', 'opacity', '0'); // initially hidden
+ cy.get('text.node').first().trigger('mouseover').then((d) => {
+ // tooltip becomes visible on hover
+ cy.get('[data-cy="tooltip"]').should('have.css', 'opacity', '0.9');
+ cy.get('[data-cy="tooltip-name-header"]').should('contain', 'Amesos');
+ // 'Anasazi' is known to be a dependent of 'Amesos'
+ cy.get('text.node').filter(':contains("Anasazi")').first().should('have.class', 'node--source');
+ // 'Amesos' is known to depend on 'Teuchos'
+ cy.get('text.node').filter(':contains("Teuchos")').first().should('have.class', 'node--target');
+ });
+ cy.get('text.node').first().trigger('mouseout').then((d) => {
+ cy.get('[data-cy="tooltip"]').should('have.css', 'opacity', '0'); // should be hidden again
+ });
+ });
+});