Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"occurred_on": "Occurred On",
"risk_type": "Risk Type",
"project_name": "Project Name",
"tag_name": "Tag Name",
"version": "Version",
"last_bom_import": "Last BOM Import",
"bom_format": "BOM Format",
Expand Down Expand Up @@ -228,6 +229,7 @@
"component_details": "Component Details",
"snapshot_notification": "Snapshot Notification",
"select_project": "Select Project",
"select_tag": "Select Tag",
"select": "Select",
"identity": "Identity",
"extended": "Extended",
Expand Down Expand Up @@ -471,6 +473,7 @@
"delete_alert": "Delete Alert",
"limit_to": "Limit To",
"limit_to_projects": "Limit to projects",
"limit_to_tags": "Limit to Tags",
"alert_created": "Alert created",
"alert_deleted": "Alert deleted",
"change_password_next_login": "User must change password at next login",
Expand Down
1 change: 1 addition & 0 deletions src/shared/api.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"URL_USER_SELF": "api/v1/user/self",
"URL_PERMISSION": "api/v1/permission",
"URL_PROJECT": "api/v1/project",
"URL_TAG": "api/v1/tag",
"URL_FINDING": "api/v1/finding",
"URL_LICENSE": "api/v1/license",
"URL_LICENSE_CONCISE": "api/v1/license/concise",
Expand Down
54 changes: 47 additions & 7 deletions src/views/policy/PolicyList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import PolicyCondition from "./PolicyCondition";
import BToggleableDisplayButton from "@/views/components/BToggleableDisplayButton";
import SelectProjectModal from "@/views/portfolio/projects/SelectProjectModal";
import SelectTagModal from "@/views/portfolio/tags/SelectTagModal";

export default {
mixins: [permissionsMixin, bootstrapTableMixin],
Expand Down Expand Up @@ -128,11 +129,19 @@
<b-form-group v-if="limitToVisible === true" id="projectLimitsList" :label="this.$t('admin.limit_to_projects')">
<div class="list-group">
<span v-for="project in projects">
<actionable-list-group-item :value="formatProjectLabel(project.name, project.version)" :delete-icon="true" v-on:actionClicked="deleteLimiter(project.uuid)"/>
<actionable-list-group-item :value="formatLabel(project.name, project.version)" :delete-icon="true" v-on:actionClicked="deleteProjectLimiter(project.uuid)"/>
</span>
<actionable-list-group-item :add-icon="true" v-on:actionClicked="$root.$emit('bv::show::modal', 'selectProjectModal')"/>
</div>
</b-form-group>
<b-form-group v-if="limitToVisible === true" id="tagLimitsList" :label="this.$t('admin.limit_to_tags')">
<div class="list-group">
<span v-for="tag in tags">
<actionable-list-group-item :value="formatLabel(tag.name, tag.id)" :delete-icon="true" v-on:actionClicked="deleteTagLimiter(tag.name)"/>
</span>
<actionable-list-group-item :add-icon="true" v-on:actionClicked="$root.$emit('bv::show::modal', 'selectTagModal')"/>
</div>
</b-form-group>
<div style="text-align:right">
<b-toggleable-display-button variant="outline-primary" :label="$t('admin.limit_to')"
v-permission="PERMISSIONS.VIEW_PORTFOLIO" v-on:toggle="limitToVisible = !limitToVisible" />
Expand All @@ -141,6 +150,7 @@
</b-col>
</b-row>
<select-project-modal v-on:selection="updateProjectSelection"/>
<select-tag-modal :policy="policy" v-on:selection="updateTagSelection"/>
</div>
`,
mixins: [permissionsMixin],
Expand All @@ -150,6 +160,7 @@
BInputGroupFormSelect,
BToggleableDisplayButton,
SelectProjectModal,
SelectTagModal,
PolicyCondition
},
data() {
Expand All @@ -169,15 +180,16 @@
{ value: 'FAIL', text: this.$t('violation.fail') }
],
projects: row.projects,
limitToVisible: false
limitToVisible: false,
tags: row.tags
}
},
methods: {
formatProjectLabel: function(projectName, projectVersion) {
if (projectName && projectVersion) {
return projectName + " " + projectVersion;
formatLabel: function(labelName, labelProperty) {
if (labelName && labelProperty) {
return labelName + " " + labelProperty;
} else {
return projectName;
return labelName;
}
},
addCondition: function() {
Expand Down Expand Up @@ -229,7 +241,7 @@
this.violationState = policy.violationState;
this.conditions = policy.policyConditions;
},
deleteLimiter: function(projectUuid) {
deleteProjectLimiter: function(projectUuid) {
let url = `${this.$api.BASE_URL}/${this.$api.URL_POLICY}/${this.policy.uuid}/project/${projectUuid}`;
this.axios.delete(url).then((response) => {
let p = [];
Expand All @@ -244,6 +256,21 @@
this.$toastr.w(this.$t('condition.unsuccessful_action'));
});
},
deleteTagLimiter: function(tagName) {
let url = `${this.$api.BASE_URL}/${this.$api.URL_POLICY}/${this.policy.uuid}/tag/${tagName}`;
this.axios.delete(url).then((response) => {
let p = [];
for (let i=0; i<this.tags.length; i++) {
if (this.tags[i].name !== tagName) {
p.push(this.tags[i]);
}
}
this.tags = p;
this.$toastr.s(this.$t('message.updated'));
}).catch((error) => {
this.$toastr.w(this.$t('condition.unsuccessful_action'));
});
},
updateProjectSelection: function(selections) {
this.$root.$emit('bv::hide::modal', 'selectProjectModal');
for (let i=0; i<selections.length; i++) {
Expand All @@ -260,6 +287,19 @@
}
});
}
},
updateTagSelection: function(selections) {
this.$root.$emit('bv::hide::modal', 'selectTagModal');
for (let i=0; i<selections.length; i++) {
let selection = selections[i];
let url = `${this.$api.BASE_URL}/${this.$api.URL_POLICY}/${this.policy.uuid}/tag/${selection.name}`;
this.axios.post(url).then((response) => {
this.tags.push(selection);
this.$toastr.s(this.$t('message.updated'));
}).catch((error) => {
this.$toastr.w(this.$t('condition.unsuccessful_action'));
});
}
}
},
watch: {
Expand Down
90 changes: 90 additions & 0 deletions src/views/portfolio/tags/SelectTagModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<template>
<b-modal id="selectTagModal" size="lg" hide-header-close no-stacking
v-permission="'VIEW_PORTFOLIO'" :title="$t('message.select_tag')">
<bootstrap-table
ref="table"
:columns="columns"
:data="data"
:options="options">
</bootstrap-table>
<template v-slot:modal-footer="{ cancel }">
<b-button size="md" variant="secondary" @click="cancel()">{{ $t('message.cancel') }}</b-button>
<b-button size="md" variant="primary" @click="$emit('selection', $refs.table.getSelections())">{{ $t('message.select') }}</b-button>
</template>
</b-modal>
</template>

<script>
import xssFilters from "xss-filters";
import permissionsMixin from "../../../mixins/permissionsMixin";
import common from "../../../shared/common";

export default {
props: {
policy: Object
},
mixins: [permissionsMixin],
methods: {
apiUrl: function () {
let url = `${this.$api.BASE_URL}/${this.$api.URL_TAG}/${this.policy.uuid}`;
return url;
},
refreshTable: function() {
this.$refs.table.refresh({
url: this.apiUrl(),
silent: true
});
}
},
watch:{
showInactiveTags() {
this.refreshTable();
}
},
data() {
return {
showInactiveTags: false,
labelIcon: {
dataOn: '\u2713',
dataOff: '\u2715'
},
columns: [
{
field: "state",
checkbox: true,
align: "center"
},
{
title: this.$t('message.tag_name'),
field: "name",
sortable: true,
formatter(value) {
return xssFilters.inHTMLData(common.valueWithDefault(value, ""));
}
}
],
data: [],
options: {
search: true,
showColumns: true,
showRefresh: true,
pagination: true,
silentSort: false,
sidePagination: 'server',
queryParamsType: 'pageSize',
pageList: '[10, 25, 50, 100]',
pageSize: 10,
icons: {
refresh: 'fa-refresh'
},
toolbar: '#tagsToolbar',
responseHandler: function (res, xhr) {
res.total = xhr.getResponseHeader("X-Total-Count");
return res;
},
url: this.apiUrl()
}
};
}
}
</script>