Skip to content

Commit

Permalink
* Fixed some routing bugs
Browse files Browse the repository at this point in the history
* Made project list reusable independent from the project list view
* Reused project list to show children of collection projects in project view
* Hide tabs without function in collection projects, show child projects instead
* visually mark collection projects in project header and explain logic used in tooltip

Signed-off-by: Ralf King <[email protected]>
  • Loading branch information
rkg-mm committed Sep 14, 2024
1 parent bb23172 commit 9088f24
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 14 deletions.
1 change: 1 addition & 0 deletions src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@
"close": "Close",
"code_not_present": "Code not present",
"code_not_reachable": "Code not reachable",
"collection_projects": "Collection Projects",
"collectionLogic": "Project Collection Logic",
"collection_indicator_tooltip": "Collection project with values calculated based on children.",
"comment": "Comment",
Expand Down
1 change: 1 addition & 0 deletions src/plugins/table.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'bootstrap';
import 'jquery-treegrid/js/jquery.treegrid.min.js';
import 'bootstrap-table/dist/bootstrap-table.js';
import 'bootstrap-table/dist/extensions/treegrid/bootstrap-table-treegrid.min.js';
import 'bootstrap-table/dist/extensions/defer-url/bootstrap-table-defer-url.js';
import BootstrapTable from 'bootstrap-table/dist/bootstrap-table-vue.esm.js';

Vue.component('BootstrapTable', BootstrapTable);
5 changes: 3 additions & 2 deletions src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const DefaultContainer = () => import('@/containers/DefaultContainer');

// Views
const Dashboard = () => import('@/views/Dashboard');
const ProjectList = () => import('@/views/portfolio/projects/ProjectList');
const ProjectListView = () => import('@/views/portfolio/projects/ProjectListView');
const TagList = () => import('@/views/portfolio/tags/TagList.vue');
const ComponentSearch = () =>
import('@/views/portfolio/components/ComponentSearch');
Expand Down Expand Up @@ -130,7 +130,7 @@ function configRoutes() {
{
path: 'projects',
name: 'Projects',
component: ProjectList,
component: ProjectListView,
meta: {
title: i18n.t('message.projects'),
i18n: 'message.projects',
Expand All @@ -144,6 +144,7 @@ function configRoutes() {
alias: [
'projects/:uuid/overview',
'projects/:uuid/components',
'projects/:uuid/collectionprojects',
'projects/:uuid/services',
'projects/:uuid/dependencyGraph',
'projects/:uuid/findings',
Expand Down
6 changes: 5 additions & 1 deletion src/shared/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,11 @@ $common.componentClassifierLabelFormatter = (i18n) => {
*/
$common.componentClassifierLabelProjectUrlFormatter = (i18n) => {
return function (value) {
let url = '../projects/?classifier=' + value;
// if column defines a routerFunc returning the router we use a more robust solution
let url = !this.routerFunc ?
'../projects/?classifier=' + value :
this.routerFunc().resolve({name: 'Projects', query: {'classifier': value}}).href;

switch (value) {
case 'APPLICATION':
case 'FRAMEWORK':
Expand Down
67 changes: 60 additions & 7 deletions src/views/portfolio/projects/Project.vue
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
</li>
</ol>
{{ project.version }}
<i v-if="isCollectionProject()" class="fa fa-calculator fa-fw collectionlogic-icon" v-b-tooltip.hover="{title: getCollectionLogicText(project)}"></i>
</b-col>
<b-badge v-if="!this.project.active" :variant="'tab-warn'">
{{ $t('message.inactive').toUpperCase() }}
Expand Down Expand Up @@ -220,7 +221,7 @@
style="border-left: 0; border-right: 0; border-top: 0"
/>
</b-tab>
<b-tab ref="components" @click="routeTo('components')">
<b-tab ref="components" @click="routeTo('components')" v-if="isShowComponents()">
<template v-slot:title
><i class="fa fa-cubes"></i> {{ $t('message.components') }}
<b-badge variant="tab-total">{{ totalComponents }}</b-badge></template
Expand All @@ -232,9 +233,19 @@
v-on:total="totalComponents = $event"
/>
</b-tab>
<b-tab ref="services" @click="routeTo('services')">
<b-tab ref="collectionprojects" @click="routeTo('collectionprojects')" v-if="isShowCollectionProjects()" lazy>
<template v-slot:title
><i class="fa fa-exchange"></i> {{ $t('message.services') }}
><i class="fa fa-sitemap"></i> {{ $t('message.collection_projects') }}</template
>
<project-collection-projects
:key="this.uuid"
:uuid="this.uuid"
:project="this.project"
/>
</b-tab>
<b-tab ref="services" @click="routeTo('services')" v-if="isShowServices()">
<template v-slot:title
><i class="fa fa-exchange"></i> {{ $t('message.services') }}
<b-badge variant="tab-total">{{ totalServices }}</b-badge></template
>
<project-services
Expand All @@ -243,7 +254,7 @@
v-on:total="totalServices = $event"
/>
</b-tab>
<b-tab ref="dependencygraph" @click="routeTo('dependencyGraph')">
<b-tab ref="dependencygraph" @click="routeTo('dependencyGraph')" v-if="isShowDependencyGraph()">
<template v-slot:title
><i class="fa fa-sitemap"></i> {{ $t('message.dependency_graph') }}
<b-badge variant="tab-total">{{
Expand All @@ -259,7 +270,7 @@
</b-tab>
<b-tab
ref="findings"
v-if="isPermitted(PERMISSIONS.VIEW_VULNERABILITY)"
v-if="isShowFindings()"
@click="routeTo('findings')"
>
<template v-slot:title>
Expand All @@ -285,7 +296,7 @@
</b-tab>
<b-tab
ref="epss"
v-if="isPermitted(PERMISSIONS.VIEW_VULNERABILITY)"
v-if="isShowFindings()"
@click="routeTo('epss')"
>
<template v-slot:title
Expand All @@ -300,7 +311,7 @@
</b-tab>
<b-tab
ref="policyviolations"
v-if="isPermitted(PERMISSIONS.VIEW_POLICY_VIOLATION)"
v-if="isShowPolicyViolations()"
@click="routeTo('policyViolations')"
>
<template v-slot:title
Expand Down Expand Up @@ -370,6 +381,7 @@ import { cloneDeep } from 'lodash-es';
import { getStyle } from '@coreui/coreui/dist/js/coreui-utilities';
import VueEasyPieChart from 'vue-easy-pie-chart';
import ProjectComponents from './ProjectComponents';
import ProjectCollectionProjects from './ProjectCollectionProjects';
import ProjectDependencyGraph from './ProjectDependencyGraph';
import ProjectServices from './ProjectServices';
import PortfolioWidgetRow from '../../dashboard/PortfolioWidgetRow';
Expand All @@ -385,6 +397,7 @@ import ProjectFindings from './ProjectFindings';
import ProjectPolicyViolations from './ProjectPolicyViolations';
import ProjectEpss from './ProjectEpss';
import ExternalReferencesDropdown from '../../components/ExternalReferencesDropdown.vue';
import xssFilters from 'xss-filters';
export default {
mixins: [permissionsMixin],
Expand All @@ -396,6 +409,7 @@ export default {
ProjectPropertiesModal,
ProjectDetailsModal,
ProjectComponents,
ProjectCollectionProjects,
ProjectDependencyGraph,
ProjectServices,
SeverityBarChart,
Expand Down Expand Up @@ -572,6 +586,45 @@ export default {
let tab = pattern.exec(this.$route.fullPath.toLowerCase());
return this.$refs[tab && tab[1] ? tab[1].toLowerCase() : 'overview'];
},
getCollectionLogicText: function(project) {
let title = 'Metrics of collection project are calculated '
switch (project.collectionLogic) {
case 'NONE':
return '';
case 'AGGREGATE_DIRECT_CHILDREN':
title += 'by aggregating numbers of all direct children.';
break;
case 'AGGREGATE_DIRECT_CHILDREN_WITH_TAG':
const tag = !project.collectionTag ? '' : xssFilters.inDoubleQuotedAttr(project.collectionTag.name);
title += `by aggregating numbers of direct children with tag '${tag}'.`;
break;
case 'HIGHEST_SEMVER_CHILD':
title += 'by using the child with highest SemVer version.'
break;
}
return title;
},
isCollectionProject: function() {
return this.project.collectionLogic !== 'NONE';
},
isShowComponents: function() {
return !this.isCollectionProject();
},
isShowCollectionProjects: function() {
return this.isCollectionProject();
},
isShowServices: function() {
return !this.isCollectionProject();
},
isShowDependencyGraph: function() {
return !this.isCollectionProject();
},
isShowFindings: function() {
return !this.isCollectionProject() && this.isPermitted(this.PERMISSIONS.VIEW_VULNERABILITY)
},
isShowPolicyViolations: function() {
return !this.isCollectionProject() && this.isPermitted(this.PERMISSIONS.VIEW_POLICY_VIOLATION)
}
},
beforeMount() {
this.uuid = this.$route.params.uuid;
Expand Down
17 changes: 17 additions & 0 deletions src/views/portfolio/projects/ProjectCollectionProjects.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<template>
<project-list :parentProject="this.project" :uuid="this.uuid"></project-list>
</template>

<script>
import ProjectList from "@/views/portfolio/projects/ProjectList.vue";
export default {
components: {
ProjectList
},
props: {
uuid: String,
project: Object,
}
};
</script>
22 changes: 18 additions & 4 deletions src/views/portfolio/projects/ProjectList.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<template>
<div class="animated fadeIn" v-permission="'VIEW_PORTFOLIO'">
<portfolio-widget-row :fetch="true" />
<div>
<div id="projectsToolbar" class="bs-table-custom-toolbar">
<b-button
size="md"
Expand Down Expand Up @@ -38,7 +37,6 @@
:columns="columns"
:data="data"
:options="options"
@on-load-success="onLoadSuccess"
@on-pre-body="onPreBody"
@on-post-body="onPostBody"
>
Expand Down Expand Up @@ -68,6 +66,13 @@ export default {
ProjectCreateProjectModal,
PortfolioWidgetRow,
},
props: {
/**
* If only children from a specific project shall be shown this must be set to the corresponding project
*/
parentProject: Object,
uuid: String
},
beforeCreate() {
this.showInactiveProjects =
localStorage &&
Expand All @@ -84,6 +89,11 @@ export default {
this.$root.$emit('initializeProjectCreateProjectModal');
},
apiUrl: function (uuid) {
// if we only want to show children of a specific parent we force the base call to fetch its children
if(this.uuid && !uuid) {
uuid = this.uuid;
}
let url = `${this.$api.BASE_URL}/${this.$api.URL_PROJECT}`;
if (uuid) {
url += `/${uuid}/children`;
Expand Down Expand Up @@ -241,8 +251,11 @@ export default {
title: this.$t('message.project_name'),
field: 'name',
sortable: true,
routerFunc: () => this.$router,
formatter(value, row, index) {
let url = xssFilters.uriInUnQuotedAttr('../projects/' + row.uuid);
let url = xssFilters.uriInUnQuotedAttr(
this.routerFunc().resolve({name: 'Project', params: {'uuid': row.uuid}}).href
);
let collectionIcon = '';
if(row.collectionLogic !== 'NONE') {
let title = 'Metrics of collection project are calculated '
Expand Down Expand Up @@ -303,6 +316,7 @@ export default {
title: this.$t('message.classifier'),
field: 'classifier',
sortable: true,
routerFunc: () => this.$router, // needed by formatter
formatter: common.componentClassifierLabelProjectUrlFormatter(this),
},
{
Expand Down
16 changes: 16 additions & 0 deletions src/views/portfolio/projects/ProjectListView.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<div class="animated fadeIn" v-permission="'VIEW_PORTFOLIO'">
<portfolio-widget-row :fetch="true" />
<project-list></project-list>
</div>
</template>

<script>
import PortfolioWidgetRow from "@/views/dashboard/PortfolioWidgetRow.vue";
import ProjectList from "@/views/portfolio/projects/ProjectList.vue";
export default {
components: {ProjectList, PortfolioWidgetRow}
}
</script>

0 comments on commit 9088f24

Please sign in to comment.