From 053f6fa9ce597a39dcfa65c992bb39a45aa63d02 Mon Sep 17 00:00:00 2001 From: rbt-mm <113189967+rbt-mm@users.noreply.github.com> Date: Wed, 28 Sep 2022 13:24:38 +0200 Subject: [PATCH 1/9] Update ci-build.yaml Workflow now starts on every pull request, if the branch name contains 'master' in it. Signed-off-by: RBickert --- .github/workflows/ci-build.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-build.yaml b/.github/workflows/ci-build.yaml index 6f17f7696..e0a29984e 100644 --- a/.github/workflows/ci-build.yaml +++ b/.github/workflows/ci-build.yaml @@ -3,10 +3,10 @@ name: Build CI on: push: branches: - - 'master' # Default branch + - '**master**' # Default branch pull_request: branches: - - 'master' # Default branch + - '**master**' # Default branch workflow_dispatch: jobs: From b05a11cb7adaa16af73d15c0a86d9a8a66ccf448 Mon Sep 17 00:00:00 2001 From: RBickert Date: Mon, 19 Sep 2022 16:53:00 +0200 Subject: [PATCH 2/9] Add parent in project creation and detail view Display list of every project in `Create Project` and `View Project` to select a parent project for the new or current project. Send selected parent in project creation via API call to backend to create a persistent parent-child-relationship. Signed-off-by: RBickert --- src/i18n/locales/en.json | 1 + .../projects/ProjectCreateProjectModal.vue | 23 +++++++++++++ .../projects/ProjectDetailsModal.vue | 32 +++++++++++++++++++ src/views/portfolio/projects/ProjectList.vue | 16 +++++++++- 4 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 2ea4dea73..6bd9effe9 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -232,6 +232,7 @@ "snapshot_notification": "Snapshot Notification", "select_project": "Select Project", "select_tag": "Select Tag", + "parent": "Parent", "select": "Select", "identity": "Identity", "extended": "Extended", diff --git a/src/views/portfolio/projects/ProjectCreateProjectModal.vue b/src/views/portfolio/projects/ProjectCreateProjectModal.vue index 5cafff126..bcd680bde 100644 --- a/src/views/portfolio/projects/ProjectCreateProjectModal.vue +++ b/src/views/portfolio/projects/ProjectCreateProjectModal.vue @@ -14,6 +14,9 @@ + { + for (let i = 0; i < response.data.length; i++) { + let project = response.data[i]; + this.availableParents.push({value: project, text: project.name + ' : ' + project.version}); + if (this.project.parent && this.project.parent.uuid === project.uuid ) { + this.selectedParent = project; + } + } + }).catch((error) => { + this.$toastr.w(this.$t('condition.unsuccessful_action')); + }); + }, resetValues: function () { this.project = {}; this.tag = ""; diff --git a/src/views/portfolio/projects/ProjectDetailsModal.vue b/src/views/portfolio/projects/ProjectDetailsModal.vue index a8137812d..4d61f0068 100644 --- a/src/views/portfolio/projects/ProjectDetailsModal.vue +++ b/src/views/portfolio/projects/ProjectDetailsModal.vue @@ -17,6 +17,9 @@ v-model="project.classifier" :options="availableClassifiers" :label="$t('message.classifier')" :tooltip="$t('message.component_classifier_desc')" :readonly="this.isNotPermitted(PERMISSIONS.PORTFOLIO_MANAGEMENT)" /> + {{ $t('message.add_version') }} {{ $t('message.close') }} {{ $t('message.update') }} + @@ -115,6 +119,10 @@ { value: 'FIRMWARE', text: this.$i18n.t('message.component_firmware') }, { value: 'FILE', text: this.$i18n.t('message.component_file') } ], + selectedParent: null, + availableParents: [ + { value: null, text: ''} + ], tag: '', // The contents of a tag as its being typed into the vue-tag-input tags: [], // An array of tags bound to the vue-tag-input addOnKeys: [9, 13, 32, ':', ';', ','], // Separators used when typing tags into the vue-tag-input @@ -131,6 +139,9 @@ this.readOnlyProjectName = this.project.name; this.readOnlyProjectVersion = this.project.version; }, + created() { + this.retrieveParents(); + }, methods: { syncReadOnlyNameField: function(value) { this.readOnlyProjectName = value; @@ -151,6 +162,7 @@ version: this.project.version, description: this.project.description, classifier: this.project.classifier, + parent: this.selectedParent, cpe: this.project.cpe, purl: this.project.purl, swidTagId: this.project.swidTagId, @@ -174,6 +186,26 @@ }).catch((error) => { this.$toastr.w(this.$t('condition.unsuccessful_action')); }); + }, + debugProject: function (){ + console.log('Selected Parent: ' + JSON.stringify(this.selectedParent)) + console.log('this.project: ' + JSON.stringify(this.project)); + console.log('this.project.parent: ' + JSON.stringify(this.project.parent)); + }, + retrieveParents: function() { + let url = `${this.$api.BASE_URL}/${this.$api.URL_PROJECT}`; + console.log('retrieveParents project:' + JSON.stringify(this.project)) + this.axios.get(url).then((response) => { + for (let i = 0; i < response.data.length; i++) { + let project = response.data[i]; + this.availableParents.push({value: project, text: project.name + ' : ' + project.version}); + if (this.project.parent && this.project.parent.uuid === project.uuid ) { + this.selectedParent = project; + } + } + }).catch((error) => { + this.$toastr.w(this.$t('condition.unsuccessful_action')); + }); } } } diff --git a/src/views/portfolio/projects/ProjectList.vue b/src/views/portfolio/projects/ProjectList.vue index a9b58f383..8191786fd 100644 --- a/src/views/portfolio/projects/ProjectList.vue +++ b/src/views/portfolio/projects/ProjectList.vue @@ -190,7 +190,21 @@ res.total = xhr.getResponseHeader("X-Total-Count"); return res; }, - url: this.apiUrl() + url: this.apiUrl(), + onClickRow: function (row){ + console.log('The row ' + row.name + ' : ' + row.version + ' was clicked'); + if (row.hasOwnProperty('parent') && row.parent){ + console.log(row.name + ' : ' + row.version + ' has the following parent:'); + console.log(row.parent.name + ' : ' + row.parent.version) + } + if (row.hasOwnProperty('children') && row.children){ + console.log(row.name + ' : ' + row.version + ' has the following children:'); + for (let child of row.children){ + console.log(child.name + ' : ' + child.version); + } + } + + } } }; } From ee966856bc2ce6e32445859c0e811646720228a4 Mon Sep 17 00:00:00 2001 From: RBickert Date: Tue, 20 Sep 2022 17:03:51 +0200 Subject: [PATCH 3/9] Add persistent selection of parent to detail view Send selected parent in project detail view via API call to backend to create a persistent parent-child-relationship. Signed-off-by: RBickert --- src/views/portfolio/projects/Project.vue | 2 -- .../projects/ProjectCreateProjectModal.vue | 6 +++--- .../portfolio/projects/ProjectDetailsModal.vue | 16 ++++++---------- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/views/portfolio/projects/Project.vue b/src/views/portfolio/projects/Project.vue index b5e0c6b75..5786e802c 100644 --- a/src/views/portfolio/projects/Project.vue +++ b/src/views/portfolio/projects/Project.vue @@ -244,8 +244,6 @@ }, beforeMount() { this.uuid = this.$route.params.uuid; - }, - mounted() { this.initialize(); }, watch:{ diff --git a/src/views/portfolio/projects/ProjectCreateProjectModal.vue b/src/views/portfolio/projects/ProjectCreateProjectModal.vue index bcd680bde..6429c8434 100644 --- a/src/views/portfolio/projects/ProjectCreateProjectModal.vue +++ b/src/views/portfolio/projects/ProjectCreateProjectModal.vue @@ -164,7 +164,7 @@ group: this.project.group, description: this.project.description, //license: this.selectedLicense, - parent: this.selectedParent, + parent: {uuid: this.selectedParent}, classifier: this.project.classifier, purl: this.project.purl, cpe: this.project.cpe, @@ -200,9 +200,9 @@ this.axios.get(url).then((response) => { for (let i = 0; i < response.data.length; i++) { let project = response.data[i]; - this.availableParents.push({value: project, text: project.name + ' : ' + project.version}); + this.availableParents.push({value: project.uuid, text: project.name + ' : ' + project.version}); if (this.project.parent && this.project.parent.uuid === project.uuid ) { - this.selectedParent = project; + this.selectedParent = project.uuid; } } }).catch((error) => { diff --git a/src/views/portfolio/projects/ProjectDetailsModal.vue b/src/views/portfolio/projects/ProjectDetailsModal.vue index 4d61f0068..d676bfa4d 100644 --- a/src/views/portfolio/projects/ProjectDetailsModal.vue +++ b/src/views/portfolio/projects/ProjectDetailsModal.vue @@ -139,7 +139,7 @@ this.readOnlyProjectName = this.project.name; this.readOnlyProjectVersion = this.project.version; }, - created() { + mounted() { this.retrieveParents(); }, methods: { @@ -162,7 +162,7 @@ version: this.project.version, description: this.project.description, classifier: this.project.classifier, - parent: this.selectedParent, + parent: {uuid: this.selectedParent}, cpe: this.project.cpe, purl: this.project.purl, swidTagId: this.project.swidTagId, @@ -187,20 +187,16 @@ this.$toastr.w(this.$t('condition.unsuccessful_action')); }); }, - debugProject: function (){ - console.log('Selected Parent: ' + JSON.stringify(this.selectedParent)) - console.log('this.project: ' + JSON.stringify(this.project)); - console.log('this.project.parent: ' + JSON.stringify(this.project.parent)); - }, retrieveParents: function() { let url = `${this.$api.BASE_URL}/${this.$api.URL_PROJECT}`; - console.log('retrieveParents project:' + JSON.stringify(this.project)) this.axios.get(url).then((response) => { for (let i = 0; i < response.data.length; i++) { let project = response.data[i]; - this.availableParents.push({value: project, text: project.name + ' : ' + project.version}); + if (project.uuid !== this.project.uuid){ + this.availableParents.push({value: project.uuid, text: project.name + ' : ' + project.version}); + } if (this.project.parent && this.project.parent.uuid === project.uuid ) { - this.selectedParent = project; + this.selectedParent = project.uuid; } } }).catch((error) => { From 11c7eab4afad0283780139fedcf70994e0dc9867 Mon Sep 17 00:00:00 2001 From: RBickert Date: Fri, 23 Sep 2022 16:28:37 +0200 Subject: [PATCH 4/9] Add hierarchical view in project list Added CSwitch in project list to switch between current flat view (default) and a new hierarchical view (shows root projects and their children in the detail view of a row). Project detail view only shows viable projects as selectable parent. Hierarchical project list shows inactive projects for children and children are sortable. Signed-off-by: RBickert --- src/i18n/locales/en.json | 1 + .../projects/ProjectCreateProjectModal.vue | 9 +- .../projects/ProjectDetailsModal.vue | 20 ++- src/views/portfolio/projects/ProjectList.vue | 129 +++++++++++++++--- 4 files changed, 132 insertions(+), 27 deletions(-) diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 6bd9effe9..69bc61aaa 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -105,6 +105,7 @@ "property_deleted": "Property deleted", "create_project": "Create Project", "show_inactive_projects": "Show inactive projects", + "hierarchical_view": "Hierarchical view", "create_project_property": "Create Project Property", "group_name": "Group Name", "property_name": "Property Name", diff --git a/src/views/portfolio/projects/ProjectCreateProjectModal.vue b/src/views/portfolio/projects/ProjectCreateProjectModal.vue index 6429c8434..dd4a28d4f 100644 --- a/src/views/portfolio/projects/ProjectCreateProjectModal.vue +++ b/src/views/portfolio/projects/ProjectCreateProjectModal.vue @@ -157,6 +157,10 @@ createProject: function() { let url = `${this.$api.BASE_URL}/${this.$api.URL_PROJECT}`; let tagsNode = []; + let parent = {uuid: this.selectedParent}; + if (this.selectedParent == null){ + parent = null; + } this.tags.forEach((tag) => tagsNode.push({name: tag.text})); this.axios.put(url, { name: this.project.name, @@ -164,7 +168,7 @@ group: this.project.group, description: this.project.description, //license: this.selectedLicense, - parent: {uuid: this.selectedParent}, + parent: parent, classifier: this.project.classifier, purl: this.project.purl, cpe: this.project.cpe, @@ -213,6 +217,9 @@ this.project = {}; this.tag = ""; this.tags = []; + this.selectedParent = null; + this.availableParents = [{ value: null, text: ''}] + this.retrieveParents(); } } } diff --git a/src/views/portfolio/projects/ProjectDetailsModal.vue b/src/views/portfolio/projects/ProjectDetailsModal.vue index d676bfa4d..9fd1c9ed9 100644 --- a/src/views/portfolio/projects/ProjectDetailsModal.vue +++ b/src/views/portfolio/projects/ProjectDetailsModal.vue @@ -80,7 +80,6 @@ {{ $t('message.add_version') }} {{ $t('message.close') }} {{ $t('message.update') }} - @@ -188,22 +187,33 @@ }); }, retrieveParents: function() { - let url = `${this.$api.BASE_URL}/${this.$api.URL_PROJECT}`; + let url = `${this.$api.BASE_URL}/${this.$api.URL_PROJECT}/parents`; this.axios.get(url).then((response) => { for (let i = 0; i < response.data.length; i++) { let project = response.data[i]; - if (project.uuid !== this.project.uuid){ + if (project.uuid !== this.project.uuid && !this.isChild(project, this.project.uuid)){ this.availableParents.push({value: project.uuid, text: project.name + ' : ' + project.version}); } - if (this.project.parent && this.project.parent.uuid === project.uuid ) { + if (this.project.parent && this.project.parent.uuid === project.uuid ) { this.selectedParent = project.uuid; } } }).catch((error) => { this.$toastr.w(this.$t('condition.unsuccessful_action')); }); + }, + isChild: function (project, uuid) { + let bool = false; + if (project.parent) { + if (project.parent.uuid === uuid) { + return true; + } else { + bool = this.isChild(project.parent, uuid) + } + } + return bool; + } } - } } diff --git a/src/views/portfolio/projects/ProjectList.vue b/src/views/portfolio/projects/ProjectList.vue index 8191786fd..891f19a58 100644 --- a/src/views/portfolio/projects/ProjectList.vue +++ b/src/views/portfolio/projects/ProjectList.vue @@ -6,8 +6,9 @@ {{ $t('message.create_project') }} {{ $t('message.show_inactive_projects') }} + {{ $t('message.hierarchical_view') }} - + `, + mixins: [permissionsMixin, bootstrapTableMixin], + methods: { + apiUrl: function (uuid) { + let url = `${api.BASE_URL}/${api.URL_PROJECT}/${uuid}/children`; + let tag = route.query.tag; + if (tag) { + url += "/tag/" + encodeURIComponent(tag); + } + let classifier = route.query.classifier; + if (classifier) { + url += "/classifier/" + encodeURIComponent(classifier); + } + if (showInactiveProjects === undefined) { + url += "?excludeInactive=true"; + } else { + url += "?excludeInactive=" + !showInactiveProjects; + } + return url; + }, + }, + data(){ + return{ + columns: columns, + data: [], + options: { + url: this.apiUrl(row.uuid), + sidePagination: 'server', + queryParamsType: 'pageSize', + detailView: true, + detailFilter: detailFilter, + detailFormatter: (index, row) => { + return this.vueFormatter(vueFormatterObject(index, row)); + }, + onExpandRow: this.vueFormatterInit + } + } + } + + } + } + + function detailFilter(index, row){ + return (row.hasOwnProperty('children') && row.children) + } export default { - mixins: [permissionsMixin], + mixins: [permissionsMixin, bootstrapTableMixin], components: { cSwitch, ProjectCreateProjectModal, PortfolioWidgetRow }, + mounted() { + showInactiveProjects = this.showInactiveProjects; + api = this.$api; + route = this.$route; + columns = this.columns; + }, methods: { apiUrl: function () { - let url = `${this.$api.BASE_URL}/${this.$api.URL_PROJECT}`; + let url; + api = this.$api; + route = this.$route; + if (this.showHierarchy){ + url = `${api.BASE_URL}/${api.URL_PROJECT}/root`; + }else{ + url = `${api.BASE_URL}/${api.URL_PROJECT}`; + } let tag = this.$route.query.tag; if (tag) { url += "/tag/" + encodeURIComponent(tag); @@ -65,12 +135,18 @@ this.refreshTable(); }, showInactiveProjects() { + showInactiveProjects = !showInactiveProjects this.refreshTable(); + }, + showHierarchy(){ + this.options.detailView = !this.options.detailView; + this.options.url = this.apiUrl(); } }, data() { return { showInactiveProjects: false, + showHierarchy: false, labelIcon: { dataOn: '\u2713', dataOff: '\u2715' @@ -80,6 +156,8 @@ title: this.$t('message.project_name'), field: "name", sortable: true, + widthUnit: '%', + width: '15.23', formatter(value, row, index) { let url = xssFilters.uriInUnQuotedAttr("../projects/" + row.uuid); return `${xssFilters.inHTMLData(value)}`; @@ -89,6 +167,8 @@ title: this.$t('message.version'), field: "version", sortable: true, + widthUnit: '%', + width: '10,27', formatter(value, row, index) { return xssFilters.inHTMLData(common.valueWithDefault(value, "")); } @@ -97,12 +177,16 @@ title: this.$t('message.classifier'), field: "classifier", sortable: true, + widthUnit: '%', + width: '8.96', formatter: common.componentClassifierLabelProjectUrlFormatter(this), }, { title: this.$t('message.last_bom_import'), field: "lastBomImport", sortable: true, + widthUnit: '%', + width: '14.71', formatter(timestamp, row, index) { return typeof timestamp === "number" ? common.formatTimestamp(timestamp, true) @@ -112,12 +196,16 @@ { title: this.$t('message.bom_format'), field: "lastBomImportFormat", - sortable: true + sortable: true, + widthUnit: '%', + width: '11.14', }, { title: this.$t('message.risk_score'), field: "lastInheritedRiskScore", - sortable: true + sortable: true, + widthUnit: '%', + width: '9.75', }, { title: this.$t('message.active'), @@ -126,11 +214,15 @@ return value === true ? '' : ""; }, align: "center", - sortable: true + sortable: true, + widthUnit: '%', + width: '7.40', }, { title: this.$t('message.policy_violations'), field: "metrics", + widthUnit: '%', + width: '11.84', formatter: function (metrics) { if (typeof metrics === "undefined") { return "-"; // No vulnerability info available @@ -150,6 +242,8 @@ title: this.$t('message.vulnerabilities'), field: "metrics", sortable: false, + widthUnit: '%', + width: '10.70', formatter(metrics, row, index) { if (typeof metrics === "undefined") { return "-"; // No vulnerability info available @@ -173,6 +267,12 @@ ], data: [], options: { + detailView: false, + detailFilter: detailFilter, + detailFormatter: (index, row) => { + return this.vueFormatter(vueFormatterObject(index, row)) + }, + onExpandRow: this.vueFormatterInit, search: true, showColumns: true, showRefresh: true, @@ -182,6 +282,7 @@ queryParamsType: 'pageSize', pageList: '[10, 25, 50, 100]', pageSize: 10, + pageNumber: 1, icons: { refresh: 'fa-refresh' }, @@ -190,21 +291,7 @@ res.total = xhr.getResponseHeader("X-Total-Count"); return res; }, - url: this.apiUrl(), - onClickRow: function (row){ - console.log('The row ' + row.name + ' : ' + row.version + ' was clicked'); - if (row.hasOwnProperty('parent') && row.parent){ - console.log(row.name + ' : ' + row.version + ' has the following parent:'); - console.log(row.parent.name + ' : ' + row.parent.version) - } - if (row.hasOwnProperty('children') && row.children){ - console.log(row.name + ' : ' + row.version + ' has the following children:'); - for (let child of row.children){ - console.log(child.name + ' : ' + child.version); - } - } - - } + url: this.apiUrl() } }; } From 87a9d8c268c1acbe5f328213e7b40e52806a2048 Mon Sep 17 00:00:00 2001 From: RBickert Date: Thu, 29 Sep 2022 16:37:23 +0200 Subject: [PATCH 5/9] Fix switching parent to inactive A parent project cannot be set to inactive if any of his children are set to active Signed-off-by: RBickert --- src/i18n/locales/en.json | 3 ++- .../portfolio/projects/ProjectDetailsModal.vue | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 69bc61aaa..ac6df07e0 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -374,7 +374,8 @@ "component_device": "Device", "component_firmware": "Firmware", "component_file": "File", - "dates": "Dates" + "dates": "Dates", + "inactive_active_children": "The project cannot be set to inactive if it has active children" }, "admin": { "configuration": "Configuration", diff --git a/src/views/portfolio/projects/ProjectDetailsModal.vue b/src/views/portfolio/projects/ProjectDetailsModal.vue index 9fd1c9ed9..f8acf5cf3 100644 --- a/src/views/portfolio/projects/ProjectDetailsModal.vue +++ b/src/views/portfolio/projects/ProjectDetailsModal.vue @@ -36,7 +36,9 @@ style="max-width:none; background-color:transparent;" :readonly="this.isNotPermitted(PERMISSIONS.PORTFOLIO_MANAGEMENT)" /> - {{$t('message.active')}} + {{$t('message.active')}}

From d7b8d69b9a50ea8d52c0bd5a2ea92839b3c91b40 Mon Sep 17 00:00:00 2001 From: RBickert Date: Fri, 30 Sep 2022 16:27:18 +0200 Subject: [PATCH 6/9] Filter detail view parents in backend Available parents in a project detail view are now filtered in the backend instead of the UI Signed-off-by: RBickert --- src/views/portfolio/projects/Project.vue | 2 +- .../projects/ProjectDetailsModal.vue | 24 +++++++------------ src/views/portfolio/projects/ProjectList.vue | 12 +++++----- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/views/portfolio/projects/Project.vue b/src/views/portfolio/projects/Project.vue index 5786e802c..384fc0889 100644 --- a/src/views/portfolio/projects/Project.vue +++ b/src/views/portfolio/projects/Project.vue @@ -125,7 +125,7 @@ - + diff --git a/src/views/portfolio/projects/ProjectDetailsModal.vue b/src/views/portfolio/projects/ProjectDetailsModal.vue index f8acf5cf3..a4a7a4b20 100644 --- a/src/views/portfolio/projects/ProjectDetailsModal.vue +++ b/src/views/portfolio/projects/ProjectDetailsModal.vue @@ -104,7 +104,8 @@ cSwitch }, props: { - project: Object + project: Object, + uuid: String }, data() { return { @@ -189,12 +190,16 @@ }); }, retrieveParents: function() { - let url = `${this.$api.BASE_URL}/${this.$api.URL_PROJECT}/parents`; + let url = `${this.$api.BASE_URL}/${this.$api.URL_PROJECT}/withoutDescendantsOf/${this.$props.uuid}`; this.axios.get(url).then((response) => { for (let i = 0; i < response.data.length; i++) { let project = response.data[i]; - if (project.uuid !== this.project.uuid && !this.isChild(project, this.project.uuid)){ - this.availableParents.push({value: project.uuid, text: project.name + ' : ' + project.version}); + if (project.uuid !== this.project.uuid){ + if (project.version){ + this.availableParents.push({value: project.uuid, text: project.name + ' : ' + project.version}); + } else { + this.availableParents.push({value: project.uuid, text: project.name}); + } } if (this.project.parent && this.project.parent.uuid === project.uuid ) { this.selectedParent = project.uuid; @@ -204,17 +209,6 @@ this.$toastr.w(this.$t('condition.unsuccessful_action')); }); }, - isChild: function (project, uuid) { - let bool = false; - if (project.parent) { - if (project.parent.uuid === uuid) { - return true; - } else { - bool = this.isChild(project.parent, uuid) - } - } - return bool; - }, hasActiveChild: function (project) { let bool = false; if (project.children){ diff --git a/src/views/portfolio/projects/ProjectList.vue b/src/views/portfolio/projects/ProjectList.vue index 891f19a58..124fc7197 100644 --- a/src/views/portfolio/projects/ProjectList.vue +++ b/src/views/portfolio/projects/ProjectList.vue @@ -100,14 +100,9 @@ }, methods: { apiUrl: function () { - let url; api = this.$api; route = this.$route; - if (this.showHierarchy){ - url = `${api.BASE_URL}/${api.URL_PROJECT}/root`; - }else{ - url = `${api.BASE_URL}/${api.URL_PROJECT}`; - } + let url = `${api.BASE_URL}/${api.URL_PROJECT}`; let tag = this.$route.query.tag; if (tag) { url += "/tag/" + encodeURIComponent(tag); @@ -121,6 +116,11 @@ } else { url += "?excludeInactive=" + !this.showInactiveProjects; } + if (this.showHierarchy === undefined) { + url += "&onlyRoot=false" + } else { + url += "&onlyRoot=" + this.showHierarchy + } return url; }, refreshTable: function() { From a79d5351362d5520136c62ee91640ffebd12dd56 Mon Sep 17 00:00:00 2001 From: RBickert Date: Tue, 4 Oct 2022 17:03:10 +0200 Subject: [PATCH 7/9] Revert "Update ci-build.yaml" This reverts commit aeccadc6debf131ee6d266ed1caac60730dc6536. Signed-off-by: RBickert --- .github/workflows/ci-build.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-build.yaml b/.github/workflows/ci-build.yaml index e0a29984e..6f17f7696 100644 --- a/.github/workflows/ci-build.yaml +++ b/.github/workflows/ci-build.yaml @@ -3,10 +3,10 @@ name: Build CI on: push: branches: - - '**master**' # Default branch + - 'master' # Default branch pull_request: branches: - - '**master**' # Default branch + - 'master' # Default branch workflow_dispatch: jobs: From dbb34d3d59047e02c1a0fbf72c737c37120e01a6 Mon Sep 17 00:00:00 2001 From: RBickert Date: Tue, 4 Oct 2022 17:56:55 +0200 Subject: [PATCH 8/9] Change prototype method in project list Do not access Object.prototype method 'hasOwnProperty' from target object. Only show project name in create project modal, if a project does not have a version Signed-off-by: RBickert --- src/views/portfolio/projects/ProjectCreateProjectModal.vue | 6 +++++- src/views/portfolio/projects/ProjectList.vue | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/views/portfolio/projects/ProjectCreateProjectModal.vue b/src/views/portfolio/projects/ProjectCreateProjectModal.vue index dd4a28d4f..0191397c2 100644 --- a/src/views/portfolio/projects/ProjectCreateProjectModal.vue +++ b/src/views/portfolio/projects/ProjectCreateProjectModal.vue @@ -204,7 +204,11 @@ this.axios.get(url).then((response) => { for (let i = 0; i < response.data.length; i++) { let project = response.data[i]; - this.availableParents.push({value: project.uuid, text: project.name + ' : ' + project.version}); + if (project.version) { + this.availableParents.push({value: project.uuid, text: project.name + ' : ' + project.version}); + } else { + this.availableParents.push({value: project.uuid, text: project.name}); + } if (this.project.parent && this.project.parent.uuid === project.uuid ) { this.selectedParent = project.uuid; } diff --git a/src/views/portfolio/projects/ProjectList.vue b/src/views/portfolio/projects/ProjectList.vue index 124fc7197..f58786296 100644 --- a/src/views/portfolio/projects/ProjectList.vue +++ b/src/views/portfolio/projects/ProjectList.vue @@ -82,7 +82,7 @@ } function detailFilter(index, row){ - return (row.hasOwnProperty('children') && row.children) + return (Object.prototype.hasOwnProperty.call(row, 'children') && row.children) } export default { From abfe53c66eb338e75a0857dddda685a3ffdc49b4 Mon Sep 17 00:00:00 2001 From: rbt-mm <113189967+rbt-mm@users.noreply.github.com> Date: Tue, 18 Oct 2022 17:05:21 +0200 Subject: [PATCH 9/9] Hide detail view button when no active child Signed-off-by: RBickert Co-authored-by: Niklas Signed-off-by: RBickert --- src/views/portfolio/projects/ProjectList.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/portfolio/projects/ProjectList.vue b/src/views/portfolio/projects/ProjectList.vue index f58786296..65a2a1b32 100644 --- a/src/views/portfolio/projects/ProjectList.vue +++ b/src/views/portfolio/projects/ProjectList.vue @@ -82,7 +82,7 @@ } function detailFilter(index, row){ - return (Object.prototype.hasOwnProperty.call(row, 'children') && row.children) + return (Object.prototype.hasOwnProperty.call(row, 'children') && row.children && row.children.some(child => child.active)); } export default {