aboutsummaryrefslogtreecommitdiffstats
path: root/dashboard/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'dashboard/src/components')
-rw-r--r--dashboard/src/components/FormHeader.vue27
-rw-r--r--dashboard/src/components/assignment/Category.vue103
-rw-r--r--dashboard/src/components/assignment/CreateData.vue75
-rw-r--r--dashboard/src/components/assignment/Policy.vue123
-rw-r--r--dashboard/src/components/model/AddCategory.vue126
-rw-r--r--dashboard/src/components/model/AddMetarule.vue111
-rw-r--r--dashboard/src/components/model/Category.vue64
-rw-r--r--dashboard/src/components/model/CreateModel.vue57
-rw-r--r--dashboard/src/components/model/Metarule.vue155
-rw-r--r--dashboard/src/components/model/Model.vue112
-rw-r--r--dashboard/src/components/model/OrphanCategory.vue65
-rw-r--r--dashboard/src/components/model/Orphans.vue79
-rw-r--r--dashboard/src/components/pdp/AddPolicy.vue64
-rw-r--r--dashboard/src/components/pdp/CreatePdp.vue83
-rw-r--r--dashboard/src/components/pdp/Pdp.vue173
-rw-r--r--dashboard/src/components/pdp/UpdatePolicy.vue64
-rw-r--r--dashboard/src/components/policy/AssignPerimeter.vue244
-rw-r--r--dashboard/src/components/policy/CreateData.vue75
-rw-r--r--dashboard/src/components/policy/CreatePerimeter.vue73
-rw-r--r--dashboard/src/components/policy/CreatePolicy.vue84
-rw-r--r--dashboard/src/components/policy/CreateRule.vue213
-rw-r--r--dashboard/src/components/policy/DataList.vue16
-rw-r--r--dashboard/src/components/policy/FilterRules.vue24
-rw-r--r--dashboard/src/components/policy/Policy.vue186
-rw-r--r--dashboard/src/components/policy/Rule.vue231
-rw-r--r--dashboard/src/components/policy/UnusedData.vue89
26 files changed, 2716 insertions, 0 deletions
diff --git a/dashboard/src/components/FormHeader.vue b/dashboard/src/components/FormHeader.vue
new file mode 100644
index 00000000..05419179
--- /dev/null
+++ b/dashboard/src/components/FormHeader.vue
@@ -0,0 +1,27 @@
+<template>
+ <div class="form-inline row">
+ <input
+ type="search"
+ class="form-control filter col-9 mr-auto"
+ :placeholder="placeholder"
+ v-bind:value="value"
+ v-on:input="$emit('input', $event.target.value)"
+ >
+ <div class="col"></div>
+ <button v-if="needButton" type="button" class="btn btn-primary col-auto " @click="$emit('click')">
+ <span class="fa fa-plus"></span>
+ {{ buttonText }}
+ </button>
+ </div>
+</template>
+
+<script>
+export default {
+ props: {
+ value: String,
+ needButton: Boolean,
+ buttonText: String,
+ placeholder: String,
+ }
+}
+</script> \ No newline at end of file
diff --git a/dashboard/src/components/assignment/Category.vue b/dashboard/src/components/assignment/Category.vue
new file mode 100644
index 00000000..0f2f921b
--- /dev/null
+++ b/dashboard/src/components/assignment/Category.vue
@@ -0,0 +1,103 @@
+<template>
+ <details class="list-group" >
+ <summary @click="populatePolicy()">
+ <h4 class="inline-block width-200">
+ {{name}}
+ <i class="fa fa-question-circle" style="margin-left: 2%" v-if="categoryHelpStrings[name.toLowerCase()]" data-toggle="tooltip" :title="categoryHelpStrings[name.toLowerCase()]"></i>
+ </h4>
+ </summary>
+ <div class="assignments-details">
+ <FormHeader
+ :placeholder="placeholder"
+ v-model="filter"
+ needButton
+ :buttonText="buttonText"
+ @click="creatingData"
+ ></FormHeader>
+ <create-data
+ class="m-3"
+ @close="creatingDataOpen = false"
+ :policy="policy"
+ :type="name.toLowerCase()"
+ :categoryId="categoryId"
+ v-if="creatingDataOpen"
+ ></create-data>
+ <br/>
+ <details class="list-group" v-for="item in filteredData" :key="item.id">
+ <summary @click="assignData(name.toLowerCase(), item)">
+ <h4 class="inline-block width-200">{{item.name}}</h4>
+ </summary>
+ <AssignPerimeter :policy="policy" :dataToAssign="dataToAssign"></AssignPerimeter>
+ </details>
+ </div>
+ </details>
+</template>
+
+<script>
+ import AssignPerimeter from "../policy/AssignPerimeter";
+ import FormHeader from "../FormHeader";
+ import CreateData from "./CreateData";
+ import util from "../../services/Util.service";
+ import PolicyService from "../../services/Policy.service";
+ import helpstrings from "../../helpstrings";
+
+ export default {
+ props:{
+ policy: Object,
+ data: Array,
+ name: String
+ },
+ name: "Assignment",
+ components: {
+ AssignPerimeter,
+ FormHeader,
+ CreateData
+ },
+ data() {
+ return{
+ placeholder: "",
+ buttonText: "",
+ creatingDataOpen: false,
+ filter: "",
+ dataToAssign: {},
+ categoryId: "",
+ categoryHelpStrings: {}
+ }
+ },
+ created() {
+ this.categoryHelpStrings = helpstrings.metarule;
+ this.placeholder = "Filter by " + this.name;
+ this.buttonText = "Create " + this.name;
+ if (this.policy.model.meta_rules.length){
+ let category = this.name.toLowerCase()+ "_categories";
+ let metaRule = this.policy.model.meta_rules[0];
+ this.categoryId = metaRule[category][0].id;
+ }
+
+ },
+ methods: {
+ populatePolicy() {
+ PolicyService.populatePolicy(this.policy);
+ },
+ assignData(type, data) {
+ this.dataToAssign = {
+ selectedData: data,
+ selectedDataType: type,
+ };
+ },
+ creatingData(){
+ this.creatingDataOpen = true;
+
+ }
+ },
+ computed: {
+ filteredData() {
+ return util.filterAndSortByName(this.data, this.filter);
+ }
+ }
+ }
+</script>
+
+<style scoped>
+
+</style> \ No newline at end of file
diff --git a/dashboard/src/components/assignment/CreateData.vue b/dashboard/src/components/assignment/CreateData.vue
new file mode 100644
index 00000000..63c69650
--- /dev/null
+++ b/dashboard/src/components/assignment/CreateData.vue
@@ -0,0 +1,75 @@
+<template>
+ <div class="list-group-item row">
+ <form>
+ <div class="form-group">
+ <label for="dataName">Name</label>
+ <input
+ type="text"
+ name="name"
+ v-model="dataCreate.name"
+ v-validate.initial="'alpha_dash|required|min:3'"
+ class="form-control"
+ id="dataName"
+ />
+ </div>
+ <div class="form-group">
+ <label for="dataDescription">Description</label>
+ <textarea
+ name="description"
+ v-model="dataCreate.description"
+ v-validate.initial="'required|min:3'"
+ class="form-control"
+ ></textarea>
+ </div>
+ <ul>
+ <li v-for="error in errors.all()" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ :disabled="errors.any()"
+ class="btn btn-primary"
+ @click="createData()"
+ >Create</button>
+ </form>
+ </div>
+</template>
+
+<script>
+import PolicyService from "./../../services/Policy.service.js";
+
+export default {
+ name: "createData",
+ props: {
+ policy: Object,
+ type: String,
+ categoryId: String,
+ },
+ data: function() {
+ return {
+ dataCreate: {
+ name: "",
+ description: ""
+ }
+ };
+ },
+ methods: {
+ createData() {
+ var self = this;
+ PolicyService.createData(
+ this.type,
+ this.policy,
+ this.categoryId,
+ this.dataCreate
+ ).then(function(datas) {
+ self.$emit("dataCreated", datas[0]);
+ self.close();
+ });
+ },
+ close() {
+ this.$emit("close");
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/assignment/Policy.vue b/dashboard/src/components/assignment/Policy.vue
new file mode 100644
index 00000000..6fd4afb4
--- /dev/null
+++ b/dashboard/src/components/assignment/Policy.vue
@@ -0,0 +1,123 @@
+<template>
+ <div>
+ <template v-if="edit">
+ <form>
+ <div class="form-group" >
+ <label for="policyName">Name</label>
+ <input
+ type="text"
+ name="name"
+ v-model="policyEdit.name"
+ v-validate="'alpha_dash|required|min:3'"
+ class="form-control"
+ id="policyName"
+ />
+ </div>
+ <div class="form-group">
+ <label for="policyDescription">Description</label>
+ <textarea
+ name="description"
+ v-model="policyEdit.description"
+ v-validate="'required|min:3'"
+ class="form-control"
+ ></textarea>
+ </div>
+ <div class="form-group">
+ <label for="policyGenre">Genre</label>
+ <select
+ v-model="policyEdit.genre"
+ class="form-control"
+ id="policyGenre"
+ v-validate.initial="'required'"
+ name="genre"
+ >
+ <option>admin</option>
+ <option>authz</option>
+ </select>
+ </div>
+ <ul>
+ <li v-for="error in errors.all()" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="edit = false">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ :disabled="errors.any()"
+ class="btn btn-primary"
+ @click="updatePolicy()"
+ >Update</button>
+ </form>
+ </template>
+ <template v-else>
+ <h3 class="list-group-item-heading inline " data-toggle="tooltip" data-placement="top" title="Tooltip on top">{{ policy.name }}</h3>
+ <div class="pull-right">
+ <button
+ type="button"
+ class="fa fa-trash btn-dark btn-sm"
+ title="Remove Policy"
+ @click="removePolicy()"
+ ></button>
+ <button
+ type="button"
+ class="fa fa-edit btn-dark btn-sm"
+ title="Edit Policy"
+ @click="updatingPolicy()"
+ ></button>
+ </div>
+ <p class="list-group-item-text">{{ policy.description }}</p>
+
+ <Category :policy="policy" :data="policy.subjectData" name="Subject" ></Category>
+ <Category :policy="policy" :data="policy.objectData" name="Object" ></Category>
+ <Category :policy="policy" :data="policy.actionData" name="Action" ></Category>
+ </template>
+ <hr />
+ </div>
+</template>
+
+<script>
+import PolicyService from "./../../services/Policy.service.js";
+import util from "./../../services/Util.service.js";
+import Category from "./Category";
+
+export default {
+ props: {
+ policy: Object
+ },
+ data() {
+ return {
+ filter: "",
+ edit: false,
+ policyEdit: {},
+ assignments: []
+ };
+ },
+ computed: {
+
+ },
+ components: {
+ Category
+ },
+ methods: {
+
+ removePolicy() {
+ if (
+ confirm(
+ "Are you sure to delete this Policy? (Associated perimeter, data an PDP will be deleted too)"
+ )
+ )
+ PolicyService.removePolicy(this.policy);
+ },
+ updatingPolicy() {
+ this.policyEdit = util.clone(this.policy);
+ this.edit = true;
+ },
+ updatePolicy() {
+ this.edit = false;
+ PolicyService.updatePolicy(this.policyEdit);
+ },
+ showAssignments(data){
+ this.assignments = this.policy[data];
+ }
+ }
+};
+</script> \ No newline at end of file
diff --git a/dashboard/src/components/model/AddCategory.vue b/dashboard/src/components/model/AddCategory.vue
new file mode 100644
index 00000000..c22ab333
--- /dev/null
+++ b/dashboard/src/components/model/AddCategory.vue
@@ -0,0 +1,126 @@
+<template>
+ <div>
+ <template v-if="categories.length > 0">
+ <h4>Select category:</h4>
+ <form data-vv-scope="select">
+ <div class="form-group">
+ <select v-model="selectedCategoryId" v-validate.initial="'required'">
+ <option disabled value>Please select one</option>
+ <option
+ v-for="category in categories"
+ :value="category.id"
+ :key="category.id"
+ >{{category.name}}</option>
+ </select>
+ </div>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ :disabled="errors.any('select')"
+ class="btn btn-primary"
+ @click="addCategory()"
+ >Add</button>
+ </form>
+ <br>
+ <br>
+ <h4>Or create a new one:</h4>
+ </template>
+ <h4 v-else>Create a category:</h4>
+ <form data-vv-scope="create">
+ <div class="form-group">
+ <label for="categoryName">Name</label>
+ <input
+ type="text"
+ name="name"
+ v-model="categoryCreate.name"
+ v-validate.initial="'alpha_dash|required|min:3'"
+ class="form-control"
+ id="categoryName"
+ >
+ </div>
+ <div class="form-group">
+ <label for="modelDescription">Description</label>
+ <textarea
+ name="description"
+ v-model="categoryCreate.description"
+ v-validate="'required|min:3'"
+ class="form-control"
+ ></textarea>
+ </div>
+ <ul>
+ <li v-for="error in errors.all('create')" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ :disabled="errors.any('create')"
+ class="btn btn-primary"
+ @click="createCategory()"
+ >Create</button>
+ </form>
+ </div>
+</template>
+
+<script>
+import ModelService from "./../../services/Model.service.js";
+import util from "./../../services/Util.service.js";
+
+var categoryMap = {
+ subject: {
+ listName: "subject_categories",
+ serviceListName: "subjectCategories"
+ },
+ object: {
+ listName: "object_categories",
+ serviceListName: "objectCategories"
+ },
+ action: {
+ listName: "action_categories",
+ serviceListName: "actionCategories"
+ }
+};
+
+export default {
+ name: "addCategory",
+ data: function() {
+ return {
+ selectedCategoryId: null,
+ categoryCreate: {
+ name: "",
+ description: ""
+ }
+ };
+ },
+ props: {
+ metarule: Object,
+ type: String
+ },
+ methods: {
+ createCategory() {
+ ModelService.createCategory(this.type, this.categoryCreate).then(category => {
+ this.selectedCategoryId = category.id;
+ this.addCategory();
+ });
+ },
+ addCategory() {
+ var category = ModelService.getCategory(this.type, this.selectedCategoryId);
+ var metaRuleCopy = util.clone(this.metarule);
+ metaRuleCopy[categoryMap[this.type].listName].push(category);
+ ModelService.updateMetaRule(metaRuleCopy);
+ this.close();
+ },
+ close() {
+ this.$emit("close");
+ }
+ },
+ computed: {
+ categories() {
+ return ModelService[categoryMap[this.type].serviceListName].filter(
+ el => !this.metarule[categoryMap[this.type].listName].includes(el)
+ );
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/model/AddMetarule.vue b/dashboard/src/components/model/AddMetarule.vue
new file mode 100644
index 00000000..ef6e8503
--- /dev/null
+++ b/dashboard/src/components/model/AddMetarule.vue
@@ -0,0 +1,111 @@
+<template>
+ <div>
+ <hr>
+ <template v-if="metarules.length > 0">
+ <h4>Select metarule:</h4>
+ <form data-vv-scope="select">
+ <div class="form-group">
+ <select v-model="selectedMetaruleId" v-validate.initial="'required'">
+ <option disabled value>Please select one</option>
+ <option
+ v-for="metarule in metarules"
+ :value="metarule.id"
+ :key="metarule.id"
+ >{{metarule.name}}</option>
+ </select>
+ </div>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ :disabled="errors.any('select')"
+ class="btn btn-primary"
+ @click="addMetarule()"
+ >Add</button>
+ </form>
+ <br>
+ <br>
+ <h4>Or create a new one:</h4>
+ </template>
+ <h4 v-else>Create a metarule:</h4>
+ <form data-vv-scope="create">
+ <div class="form-group">
+ <label for="metaruleName">Name</label>
+ <input
+ type="text"
+ name="name"
+ v-model="metaruleCreate.name"
+ v-validate.initial="'alpha_dash|required|min:3'"
+ class="form-control"
+ id="metaruleName"
+ >
+ </div>
+ <div class="form-group">
+ <label for="modelDescription">Description</label>
+ <textarea
+ name="description"
+ v-model="metaruleCreate.description"
+ v-validate="'required|min:3'"
+ class="form-control"
+ ></textarea>
+ </div>
+ <ul>
+ <li v-for="error in errors.all('create')" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ :disabled="errors.any('create')"
+ class="btn btn-primary"
+ @click="createMetarule()"
+ >Create and add</button>
+ </form>
+ </div>
+</template>
+
+<script>
+import ModelService from "./../../services/Model.service.js";
+import util from "./../../services/Util.service.js";
+
+export default {
+ name: "addMetarule",
+ data: function() {
+ return {
+ selectedMetaruleId: null,
+ metaruleCreate: {
+ name: "",
+ description: ""
+ }
+ };
+ },
+ props: {
+ model: Object
+ },
+ methods: {
+ createMetarule() {
+ ModelService.createMetaRule(this.metaruleCreate).then(metarule => {
+ this.selectedMetaruleId = metarule.id;
+ this.addMetarule();
+ });
+ },
+ addMetarule() {
+ var metaRule = ModelService.getMetaRule(this.selectedMetaruleId);
+ var modelCopy = util.clone(this.model);
+ modelCopy.meta_rules.push(metaRule);
+ ModelService.updateModel(modelCopy);
+ this.close();
+ },
+ close() {
+ this.$emit("close");
+ }
+ },
+ computed: {
+ metarules() {
+ return ModelService.metaRules.filter(
+ el => !this.model.meta_rules.includes(el)
+ );
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/model/Category.vue b/dashboard/src/components/model/Category.vue
new file mode 100644
index 00000000..81efb1ed
--- /dev/null
+++ b/dashboard/src/components/model/Category.vue
@@ -0,0 +1,64 @@
+<template>
+ <div>
+ <span :title="category.description">{{ category.name }}</span>
+ <button type="button" class="fa fa-trash pull-right btn btn-dark btn-sm" @click="removeCategory()" title="Remove"></button>
+ <div v-for="attribute in attributes" :key="attribute.id">
+ <b>attributes: </b> {{attribute.id}}
+ </div>
+ </div>
+</template>
+
+<script>
+import ModelService from "./../../services/Model.service.js";
+import util from "./../../services/Util.service.js";
+
+var categoryMap = {
+ subject: {
+ addTitle: "Add Subject Category",
+ removeTitleFromMetaRule:
+ "Are you sure to remove from meta rule this Subject Category?",
+ removeTitle: "Are you sure to remove this Subject Category?",
+ listName: "subject_categories",
+ serviceListName: "subjectCategories"
+ },
+ object: {
+ addTitle: "Add Object Category",
+ removeTitleFromMetaRule:
+ "Are you sure to remove from meta rule this Object Category?",
+ removeTitle: "Are you sure to remove this Object Category?",
+ listName: "object_categories",
+ serviceListName: "objectCategories"
+ },
+ action: {
+ addTitle: "Add Action Category",
+ removeTitleFromMetaRule:
+ "Are you sure to remove from meta rule this Action Category?",
+ removeTitle: "Are you sure to remove this Action Category?",
+ listName: "action_categories",
+ serviceListName: "actionCategories"
+ }
+};
+
+export default {
+ name: "category",
+ props: {
+ metarule: Object,
+ category: Object,
+ attributes: Array,
+ type: String
+ },
+ methods: {
+ removeCategory() {
+ var typeValue = categoryMap[this.type];
+ if (confirm(typeValue.removeTitleFromMetaRule)) {
+ var metaruleCopy = util.clone(this.metarule);
+ metaruleCopy[typeValue.listName].splice(
+ metaruleCopy[typeValue.listName].indexOf(this.category),
+ 1
+ );
+ ModelService.updateMetaRule(metaruleCopy);
+ }
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/model/CreateModel.vue b/dashboard/src/components/model/CreateModel.vue
new file mode 100644
index 00000000..d5403e7b
--- /dev/null
+++ b/dashboard/src/components/model/CreateModel.vue
@@ -0,0 +1,57 @@
+<template>
+ <div class="list-group-item row">
+ <form>
+ <div class="form-group">
+ <label for="modelName">Name</label>
+ <input
+ type="text"
+ name="name"
+ v-model="modelCreate.name"
+ v-validate.initial="'alpha_dash|required|min:3'"
+ class="form-control"
+ id="modelName"
+ >
+ </div>
+ <div class="form-group">
+ <label for="modelDescription">Description</label>
+ <textarea
+ name="description"
+ v-model="modelCreate.description"
+ v-validate.initial="'required|min:3'"
+ class="form-control"
+ ></textarea>
+ </div>
+ <ul>
+ <li v-for="error in errors.all()" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ <span>&nbsp;</span>
+ <button type="button" :disabled="errors.any()" class="btn btn-primary" @click="createModel()">Create</button>
+ </form>
+ </div>
+</template>
+
+<script>
+import ModelService from "./../../services/Model.service.js";
+
+export default {
+ name: "createModel",
+ data: function() {
+ return {
+ modelCreate: {
+ name: "",
+ description: ""
+ }
+ };
+ },
+ methods: {
+ createModel() {
+ ModelService.createModel(this.modelCreate);
+ this.close();
+ },
+ close() {
+ this.$emit("close")
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/model/Metarule.vue b/dashboard/src/components/model/Metarule.vue
new file mode 100644
index 00000000..1cb266bd
--- /dev/null
+++ b/dashboard/src/components/model/Metarule.vue
@@ -0,0 +1,155 @@
+<template>
+ <div class="">
+ <template v-if="edit">
+ <form>
+ <div class="form-group">
+ <label for="metaruleName">Name</label>
+ <input
+ type="text"
+ name="name"
+ v-model="metaruleEdit.name"
+ v-validate="'alpha_dash|required|min:3'"
+ class="form-control"
+ id="metaruleName"
+ >
+ </div>
+ <div class="form-group">
+ <label for="modelDescription">Description</label>
+ <textarea
+ name="description"
+ v-model="metaruleEdit.description"
+ v-validate="'required|min:3'"
+ class="form-control"
+ ></textarea>
+ </div>
+ <ul>
+ <li v-for="error in errors.all()" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="edit = false">Cancel</button>
+ <span>&nbsp;</span>
+ <button type="button" :disabled="errors.any()" class="btn btn-primary" @click="updateMetarule()">Update</button>
+ </form>
+ </template>
+ <template v-else>
+ <h3 class="list-group-item-heading inline">{{ metarule.name }}</h3>
+ <div class="pull-right">
+ <button
+ type="button"
+ class="fa fa-trash btn btn-dark btn-sm"
+ @click="removeMetarule()"
+ title="Remove Meta Rule"
+ ></button>
+ <button
+ type="button"
+ class="fa fa-edit btn btn-dark btn-sm"
+ @click="updatingMetarule()"
+ title="Edit Meta Rule"
+ ></button>
+ </div>
+ <p class="list-group-item-text">{{ metarule.description }}</p>
+ <p class="list-group-item-text"></p>
+ <table class="table categories">
+ <thead>
+ <tr>
+ <th>
+ <span>Subjects</span>
+ <i class="fa fa-question-circle" style="margin-left: 2%" v-if="metaruleHelpStrings.subject" data-toggle="tooltip" :title="metaruleHelpStrings.subject"></i>
+ <button
+ type="button"
+ class="fa fa-plus pull-right btn btn-dark btn-sm"
+ @click="addSubjectCategory = true"
+ title="Add Subject"
+ ></button>
+ </th>
+ <th>
+ <span>Objects</span>
+ <i class="fa fa-question-circle" style="margin-left: 2%" v-if="metaruleHelpStrings.object" data-toggle="tooltip" :title="metaruleHelpStrings.object"></i>
+ <button
+ type="button"
+ class="fa fa-plus pull-right btn btn-dark btn-sm"
+ @click="addObjectCategory = true"
+ title="Add Object"
+ ></button>
+ </th>
+ <th>
+ <span>Actions</span>
+ <i class="fa fa-question-circle" style="margin-left: 2%" v-if="metaruleHelpStrings.action" data-toggle="tooltip" :title="metaruleHelpStrings.action"></i>
+ <button
+ type="button"
+ class="fa fa-plus pull-right btn btn-dark btn-sm"
+ @click="addActionCategory = true"
+ title="Add Action"
+ ></button>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <AddCategory v-if="addSubjectCategory" :metarule="metarule" type="subject" @close="addSubjectCategory = false"></AddCategory>
+ <Category v-else v-for="category in metarule.subject_categories" :key="category.id" :category="category" :metarule="metarule" :attributes="metarule.subjectAttributes" type="subject"></Category>
+ </td>
+ <td>
+ <AddCategory v-if="addObjectCategory" :metarule="metarule" type="object" @close="addObjectCategory = false"></AddCategory>
+ <Category v-else v-for="category in metarule.object_categories" :key="category.id" :category="category" :metarule="metarule" :attributes="metarule.objectAttributes" type="object"></Category>
+ </td>
+ <td>
+ <AddCategory v-if="addActionCategory" :metarule="metarule" type="action" @close="addActionCategory = false"></AddCategory>
+ <Category v-else v-for="category in metarule.action_categories" :key="category.id" :category="category" :metarule="metarule" :attributes="metarule.actionAttributes" type="action"></Category>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </template>
+ </div>
+</template>
+
+<script>
+import Category from './Category.vue'
+import AddCategory from './AddCategory.vue'
+import ModelService from "./../../services/Model.service.js";
+import util from "./../../services/Util.service.js";
+import helpstrings from "../../helpstrings";
+
+export default {
+ name: "metarule",
+ data: function() {
+ return {
+ edit: false,
+ metaruleEdit: {},
+ addSubjectCategory: false,
+ addObjectCategory: false,
+ addActionCategory: false,
+ metaruleHelpStrings: {}
+ };
+ },
+ components: {
+ Category,
+ AddCategory
+ },
+ props: {
+ metarule: Object,
+ model: Object,
+ },
+ mounted() {
+ this.metaruleHelpStrings = helpstrings.metarule;
+ },
+ methods: {
+ updatingMetarule() {
+ this.metaruleEdit = util.clone(this.metarule);
+ this.edit = true;
+ },
+ updateMetarule() {
+ this.edit = false;
+ ModelService.updateMetaRule(this.metaruleEdit);
+ },
+ removeMetarule() {
+ if (confirm('Are you sure to remove this Meta Rule from model?')) {
+ var modelCopy = util.clone(this.model);
+ modelCopy.meta_rules.splice(modelCopy.meta_rules.indexOf(this.metarule), 1);
+ ModelService.updateModel(modelCopy);
+ }
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/model/Model.vue b/dashboard/src/components/model/Model.vue
new file mode 100644
index 00000000..82ad992d
--- /dev/null
+++ b/dashboard/src/components/model/Model.vue
@@ -0,0 +1,112 @@
+<template>
+ <div>
+ <template v-if="edit">
+ <form>
+ <div class="form-group">
+ <label for="modelName">Name</label>
+ <input
+ type="text"
+ name="name"
+ v-model="modelEdit.name"
+ v-validate="'alpha_dash|required|min:3'"
+ class="form-control"
+ id="modelName"
+ >
+ </div>
+ <div class="form-group">
+ <label for="modelDescription">Description</label>
+ <textarea
+ name="description"
+ v-model="modelEdit.description"
+ v-validate="'required|min:3'"
+ class="form-control"
+ ></textarea>
+ </div>
+ <ul>
+ <li v-for="error in errors.all()" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="edit = false">Cancel</button>
+ <span>&nbsp;</span>
+ <button type="button" :disabled="errors.any()" class="btn btn-primary" @click="updateModel()">Update</button>
+ </form>
+ </template>
+ <template v-else>
+ <h3 class="list-group-item-heading inline">{{ model.name }}</h3>
+ <div class="pull-right">
+ <button type="button" class="fa fa-trash btn btn-dark btn-sm" @click="removeModel()" title="Remove Model"></button>
+ <button type="button" class="fa fa-edit btn btn-dark btn-sm" @click="updatingModel()" title="Edit Model"></button>
+ </div>
+ <p class="list-group-item-text">{{ model.description }}</p>
+
+ <AddMetarule v-if="addMetarule" :model="model" @close="addMetarule = false"></AddMetarule>
+ <details class="list-group-item-text" v-else>
+ <summary>
+ <h4 class="inline-block width-200">
+ {{ model.meta_rules.length + ' meta rule' + (model.meta_rules.length > 1 ? 's' : '&nbsp;') }}
+ <i class="fa fa-question-circle" v-if="modelHelpStrings.metarule" data-toggle="tooltip" :title="modelHelpStrings.metarule"></i>
+ </h4>
+ <button
+ type="button"
+ class="fa fa-plus btn btn-dark btn-sm"
+ @click="addMetarule = true"
+ title="Add Meta Rule"
+ ></button>
+ </summary>
+ <div class="list-group">
+ <Metarule
+ v-for="metarule in model.meta_rules"
+ :key="metarule.id"
+ :metarule="metarule"
+ :model="model"
+ ></Metarule>
+ </div>
+ </details>
+ </template>
+ <hr>
+ </div>
+</template>
+
+<script>
+import Metarule from "./Metarule.vue";
+import ModelService from "./../../services/Model.service.js";
+import AddMetarule from "./AddMetarule.vue";
+import util from "./../../services/Util.service.js";
+import helpstrings from "../../helpstrings";
+
+export default {
+ name: "model",
+ data: function() {
+ return {
+ edit: false,
+ addMetarule: false,
+ modelEdit: {},
+ modelHelpStrings: {}
+ };
+ },
+ components: {
+ Metarule,
+ AddMetarule
+ },
+ props: {
+ model: Object
+ },
+ mounted() {
+ this.modelHelpStrings = helpstrings.model;
+ },
+ methods: {
+ updatingModel() {
+ this.modelEdit = util.clone(this.model);
+ this.edit = true;
+ },
+ updateModel() {
+ this.edit = false;
+ ModelService.updateModel(this.modelEdit);
+ },
+ removeModel() {
+ if (confirm('Are you sure to delete this Model?')) {
+ ModelService.removeModel(this.model);
+ }
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/model/OrphanCategory.vue b/dashboard/src/components/model/OrphanCategory.vue
new file mode 100644
index 00000000..316b8095
--- /dev/null
+++ b/dashboard/src/components/model/OrphanCategory.vue
@@ -0,0 +1,65 @@
+<template>
+ <div class="list-group col-lg-3">
+ <h3 class="list-group-item active">{{title}}</h3>
+ <div v-for="category in categories" class="list-group-item" :key="category.id">
+ <h4 class="list-group-item-heading inline">{{ category.name }}</h4>
+ <button
+ type="button"
+ class="fa fa-trash pull-right btn btn-dark btn-sm"
+ @click="removeCategory(category)"
+ :title="buttonTitle"
+ ></button>
+ <p class="list-group-item-text">{{ category.description }}</p>
+ </div>
+ </div>
+</template>
+
+<script>
+import ModelService from "./../../services/Model.service.js";
+
+var categoryMap = {
+ subject: {
+ title: "Orphan Subject categories",
+ removeButtonTitle: "Remove Subject category",
+ removeTitle: "Are you sure to remove this Subject Category?",
+ listName: "subject_categories",
+ serviceListName: "subjectCategories"
+ },
+ object: {
+ title: "Orphan Object categories",
+ removeButtonTitle: "Remove Object category",
+ removeTitle: "Are you sure to remove this Object Category?",
+ listName: "object_categories",
+ serviceListName: "objectCategories"
+ },
+ action: {
+ title: "Orphan Action categories",
+ removeButtonTitle: "Remove Action category",
+ removeTitle: "Are you sure to remove this Action Category?",
+ listName: "action_categories",
+ serviceListName: "actionCategories"
+ }
+};
+
+export default {
+ props: {
+ categories: Array,
+ type: String
+ },
+ computed: {
+ title() {
+ return categoryMap[this.type].title;
+ },
+ buttonTitle() {
+ return categoryMap[this.type].removeButtonTitle;
+ }
+ },
+ methods: {
+ removeCategory(category) {
+ if (confirm(categoryMap[this.type].removeTitle)) {
+ ModelService.removeCategory(this.type, category);
+ }
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/model/Orphans.vue b/dashboard/src/components/model/Orphans.vue
new file mode 100644
index 00000000..b3c1c524
--- /dev/null
+++ b/dashboard/src/components/model/Orphans.vue
@@ -0,0 +1,79 @@
+<template>
+ <div>
+ <div class="alert alert-dismissable alert-warning">
+ <button type="button" class="close" data-dismiss="alert" @click="showOrphan = false; $emit('close')">×</button>
+ <h4>Warning!</h4>
+ <p>
+ Some metarules or categories are orphan, please check them and delete them if necessary.
+ <a
+ href
+ @click.prevent="showOrphan = true"
+ v-show="!showOrphan"
+ >Show orphans</a>
+ <a href @click.prevent="showOrphan = false" v-show="showOrphan">Hide orphans</a>
+ </p>
+ </div>
+
+ <div class="row" v-show="showOrphan">
+ <div class="list-group col-lg-3" v-if="orphanMetaRules.length">
+ <h3 class="list-group-item active">Orphan Meta rules</h3>
+ <div v-for="metaRule in orphanMetaRules" class="list-group-item" :key="metaRule.id">
+ <h4 class="list-group-item-heading inline">{{ metaRule.name }}</h4>
+ <button
+ type="button"
+ class="fa fa-trash pull-right btn btn-dark btn-sm"
+ @click="removeMetarule(metaRule)"
+ title="Remove Meta rule"
+ ></button>
+ <p class="list-group-item-text">{{ metaRule.description }}</p>
+ </div>
+ </div>
+
+ <OrphanCategory
+ v-if="orphanSubjectCategories.length"
+ type="subject"
+ :categories="orphanSubjectCategories"
+ ></OrphanCategory>
+ <OrphanCategory
+ v-if="orphanObjectCategories.length"
+ type="object"
+ :categories="orphanObjectCategories"
+ ></OrphanCategory>
+ <OrphanCategory
+ v-if="orphanActionCategories.length"
+ type="action"
+ :categories="orphanActionCategories"
+ ></OrphanCategory>
+ </div>
+ </div>
+</template>
+
+<script>
+import ModelService from "./../../services/Model.service.js";
+import OrphanCategory from "./OrphanCategory.vue";
+
+export default {
+ props: {
+ orphanMetaRules: Array,
+ orphanSubjectCategories: Array,
+ orphanObjectCategories: Array,
+ orphanActionCategories: Array
+ },
+ components: {
+ OrphanCategory,
+ },
+ data() {
+ return {
+ showOrphan: false,
+ allowAlert: true
+ };
+ },
+ methods: {
+ removeMetarule(metarule) {
+ if (confirm("Are you sure to remove this Meta Rule?")) {
+ ModelService.removeMetaRule(metarule);
+ }
+ }
+ }
+};
+</script> \ No newline at end of file
diff --git a/dashboard/src/components/pdp/AddPolicy.vue b/dashboard/src/components/pdp/AddPolicy.vue
new file mode 100644
index 00000000..82ad07e2
--- /dev/null
+++ b/dashboard/src/components/pdp/AddPolicy.vue
@@ -0,0 +1,64 @@
+<template>
+ <div>
+ <hr>
+ <h4>Select policy:</h4>
+ <form data-vv-scope="select">
+ <div class="form-group">
+ <select v-model="selectedPolicyId" v-validate.initial="'required'">
+ <option disabled value>Please select one</option>
+ <option
+ v-for="policy in policies"
+ :value="policy.id"
+ :key="policy.id"
+ >{{policy.name}}</option>
+ </select>
+ </div>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ :disabled="errors.any('select')"
+ class="btn btn-primary"
+ @click="addPolicy()"
+ >Add</button>
+ </form>
+ <br>
+ <br>
+ </div>
+</template>
+
+<script>
+import PdpService from "./../../services/Pdp.service.js";
+import util from "./../../services/Util.service.js";
+
+export default {
+ name: "addPolicy",
+ data: function() {
+ return {
+ selectedPolicyId: null,
+ };
+ },
+ props: {
+ pdp: Object
+ },
+ methods: {
+ addPolicy() {
+ var policy = PdpService.getPolicy(this.selectedPolicyId);
+ var pdpCopy = util.clone(this.pdp);
+ pdpCopy.security_pipeline.push(policy);
+ PdpService.updatePdp(pdpCopy);
+ this.close();
+ },
+ close() {
+ this.$emit("close");
+ }
+ },
+ computed: {
+ policies() {
+ return PdpService.policies.filter(
+ el => !this.pdp.security_pipeline.includes(el)
+ );
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/pdp/CreatePdp.vue b/dashboard/src/components/pdp/CreatePdp.vue
new file mode 100644
index 00000000..aca46413
--- /dev/null
+++ b/dashboard/src/components/pdp/CreatePdp.vue
@@ -0,0 +1,83 @@
+<template>
+ <div class="list-group-item row">
+ <form>
+ <div class="form-group">
+ <label for="modelName">Name</label>
+ <input
+ type="text"
+ name="name"
+ v-model="pdpCreate.name"
+ v-validate.initial="'alpha_dash|required|min:3'"
+ class="form-control"
+ id="modelName"
+ >
+ </div>
+ <div class="form-group">
+ <label for="modelDescription">Description</label>
+ <textarea
+ name="description"
+ v-model="pdpCreate.description"
+ v-validate.initial="'required|min:3'"
+ class="form-control"
+ ></textarea>
+ </div>
+ <div class="form-group">
+ <label for="pdpVpi">Vim project id</label>
+ <input
+ type="text"
+ name="vim_project_id"
+ v-model="pdpCreate.vim_project_id"
+ class="form-control"
+ id="pdpVpi"
+ >
+ </div>
+ <div class="form-group">
+ <label for="pdpPolicy">Policy</label>
+ <select v-model="selectedPolicy" class="form-control" id="pdpPolicy" v-validate.initial="'required'" name="policy">
+ <option v-for="policy in policies" :key="policy.id" :value="policy.id">{{ policy.name }}</option>
+ </select>
+ </div>
+ <ul>
+ <li v-for="error in errors.all()" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ <span>&nbsp;</span>
+ <button type="button" :disabled="errors.any()" class="btn btn-primary" @click="createModel()">Create</button>
+ </form>
+ </div>
+</template>
+
+<script>
+import PdpService from "./../../services/Pdp.service.js";
+import PolicyService from "../../services/Policy.service";
+import util from "../../services/Util.service";
+
+export default {
+ data: function() {
+ return {
+ selectedPolicy: null,
+ pdpCreate: {
+ name: "",
+ description: "",
+ security_pipeline: [],
+ vim_project_id: ""
+ }
+ };
+ },
+ computed:{
+ policies() {
+ return util.sortByName(PolicyService.policies);
+ }
+ },
+ methods: {
+ createModel() {
+ this.pdpCreate.security_pipeline.push(this.selectedPolicy);
+ PdpService.createPdp(this.pdpCreate);
+ this.close();
+ },
+ close() {
+ this.$emit("close")
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/pdp/Pdp.vue b/dashboard/src/components/pdp/Pdp.vue
new file mode 100644
index 00000000..3aba3fed
--- /dev/null
+++ b/dashboard/src/components/pdp/Pdp.vue
@@ -0,0 +1,173 @@
+<template>
+ <div class="">
+ <template v-if="edit">
+ <form>
+ <div class="form-group">
+ <label for="pdpName">Name</label>
+ <input
+ type="text"
+ name="name"
+ v-model="pdpEdit.name"
+ v-validate="'alpha_dash|required|min:3'"
+ class="form-control"
+ id="pdpName"
+ >
+ </div>
+ <div class="form-group">
+ <label for="pdpDescription">Description</label>
+ <textarea
+ name="description"
+ v-model="pdpEdit.description"
+ v-validate="'required|min:3'"
+ class="form-control"
+ id="pdpDescription"
+ ></textarea>
+ </div>
+ <ul>
+ <li v-for="error in errors.all()" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="edit = false">Cancel</button>
+ <span>&nbsp;</span>
+ <button type="button" :disabled="errors.any()" class="btn btn-primary" @click="updatePdp()">Update</button>
+ </form>
+ </template>
+ <template v-else>
+ <div>
+ <h3 class="list-group-item-heading inline">{{ pdp.name }}</h3>
+ <div class="pull-right">
+ <button
+ type="button"
+ class="fa fa-trash btn btn-dark btn-sm"
+ @click="removePdp(pdp)"
+ title="Remove PDP"
+ ></button>
+ <button
+ type="button"
+ class="fa fa-edit btn btn-dark btn-sm"
+ @click="updatingPdp(pdp)"
+ title="Edit PDP"
+ ></button>
+ </div>
+ <p class="list-group-item-text">{{ pdp.description }}</p>
+ <h4 class="list-group-item-text">
+ <div v-if="!changeProject">
+ Project: {{ pdp.project ? pdp.project : 'none' }}
+ <button
+ type="button"
+ class="fa fa-edit btn btn-dark btn-sm"
+ @click="changingProject()"
+ title="Change project"
+ ></button>
+ </div>
+ <form class="form-inline" v-else>
+ <label for="projectId">Project ID: </label>
+ &nbsp;
+ <input
+ type="text"
+ name="id"
+ v-model="project"
+ class="form-control"
+ id="projectId"
+ >
+ &nbsp;
+ <button type="button" class="btn btn-secondary" @click="changeProject = false">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ class="btn btn-primary"
+ @click="setProject()"
+ >OK</button>
+ </form>
+ </h4>
+
+ <UpdatePolicy v-if="updatePolicy" :pdp="pdp" @close="updatePolicy = false"></UpdatePolicy>
+ <details class="list-group-item-text" v-else>
+ <summary>
+ <h4 class="inline">
+ {{ pdp.security_pipeline.length }} {{ (pdp.security_pipeline.length > 1) ? "policies" : "policy"}}
+ </h4>
+ <button
+ type="button"
+ class="fa fa-edit btn btn-dark btn-sm"
+ @click="updatePolicy = true"
+ title="Change Policy"
+ ></button>
+ </summary>
+ <div class="list-group">
+ <div
+ v-for="policy in pdp.security_pipeline" :key="policy.id"
+ >
+ <h3 class="list-group-item-heading inline">{{ policy.name }}</h3>
+ <!--<button
+ type="button"
+ class="fa fa-trash pull-right btn btn-dark btn-sm"
+ @click="removePolicyFromPdp(policy)"
+ title="Remove Policy"
+ ></button>-->
+ <p class="list-group-item-text">{{ policy.description }}</p>
+ </div>
+ </div>
+ </details>
+ </div>
+ </template>
+ <hr>
+ </div>
+</template>
+
+<script>
+import PdpService from './../../services/Pdp.service.js';
+//import AddPolicy from "./AddPolicy.vue";
+import UpdatePolicy from "./UpdatePolicy";
+import util from "./../../services/Util.service.js";
+
+export default {
+ name: "pdp",
+ data: function() {
+ return {
+ edit: false,
+ updatePolicy: false,
+ changeProject: false,
+ project: "",
+ pdpEdit: {}
+ };
+ },
+ props: {
+ pdp: Object
+ },
+ components: {
+ //AddPolicy
+ UpdatePolicy
+ },
+ methods: {
+ changingProject() {
+ this.project = this.pdp.project;
+ this.changeProject = true;
+ },
+ removePdp() {
+ if (confirm('Are you sure to delete this PDP?'))
+ PdpService.removePdp(this.pdp);
+ },
+ updatingPdp() {
+ this.pdpEdit = util.clone(this.pdp);
+ this.edit = true;
+ },
+ updatePdp() {
+ this.edit = false;
+ PdpService.updatePdp(this.pdpEdit);
+ },
+ removePolicyFromPdp(policy) {
+ if (confirm('Are you sure to remove this Policy from PDP?')) {
+ //var pdpCopy = util.clone(this.pdp);
+ this.pdp.security_pipeline.splice(this.pdp.security_pipeline.indexOf(policy), 1);
+ PdpService.updatePdp(this.pdp);
+ }
+ },
+ setProject() {
+ var pdpCopy = util.clone(this.pdp);
+ pdpCopy.project = this.project;
+ PdpService.updatePdp(pdpCopy);
+ this.changeProject = false;
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/pdp/UpdatePolicy.vue b/dashboard/src/components/pdp/UpdatePolicy.vue
new file mode 100644
index 00000000..f84cf37e
--- /dev/null
+++ b/dashboard/src/components/pdp/UpdatePolicy.vue
@@ -0,0 +1,64 @@
+<template>
+ <div>
+ <hr>
+ <h4>Select policy:</h4>
+ <form data-vv-scope="select">
+ <div class="form-group">
+ <select v-model="selectedPolicyId" v-validate.initial="'required'">
+ <option disabled value>Please select one</option>
+ <option
+ v-for="policy in policies"
+ :value="policy.id"
+ :key="policy.id"
+ >{{policy.name}}</option>
+ </select>
+ </div>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ :disabled="errors.any('select')"
+ class="btn btn-primary"
+ @click="updatePolicy()"
+ >Update</button>
+ </form>
+ <br>
+ <br>
+ </div>
+</template>
+
+<script>
+import PdpService from "./../../services/Pdp.service.js";
+import util from "./../../services/Util.service.js";
+
+export default {
+ name: "updatePolicy",
+ data: function() {
+ return {
+ selectedPolicyId: null,
+ };
+ },
+ props: {
+ pdp: Object
+ },
+ methods: {
+ updatePolicy() {
+ var policy = PdpService.getPolicy(this.selectedPolicyId);
+ var pdpCopy = util.clone(this.pdp);
+ pdpCopy.security_pipeline = [policy];
+ PdpService.updatePdp(pdpCopy);
+ this.close();
+ },
+ close() {
+ this.$emit("close");
+ }
+ },
+ computed: {
+ policies() {
+ return PdpService.policies.filter(
+ el => !this.pdp.security_pipeline.includes(el)
+ );
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/policy/AssignPerimeter.vue b/dashboard/src/components/policy/AssignPerimeter.vue
new file mode 100644
index 00000000..07814075
--- /dev/null
+++ b/dashboard/src/components/policy/AssignPerimeter.vue
@@ -0,0 +1,244 @@
+<template>
+ <div >
+ <div v-if="selectedData && loading" class="row padding-10">
+ <h4>Loading...</h4>
+ </div>
+ <div v-if="selectedData && !loading">
+ <div class="p-2">
+ <h3>Assign perimeters to {{ selectedData.name }}</h3>
+ <form-header
+ placeholder="Filter"
+ buttonText="Create Perimeter"
+ @click="creatingPerimeter = true"
+ v-model="filterPerimeter"
+ need-button
+ ></form-header>
+ </div>
+ <create-perimeter
+ v-if="creatingPerimeter"
+ :policy="policy"
+ :type="selectedDataType"
+ @close="creatingPerimeter = false"
+ @perimeterCreated="createPerimeter"
+ ></create-perimeter>
+ <div class="row mt-3" v-else>
+ <div class="col-sm">
+ <h4>
+ All perimeters
+ <i class="fa fa-question-circle" style="margin-left: 2%" v-if="assignPerimeterHelpStrings.allPerimeters" data-toggle="tooltip" :title="assignPerimeterHelpStrings.allPerimeters"></i>
+ </h4>
+ <div class="w-100 height-200 scroll list-group border">
+ <button
+ class="list-group-item"
+ v-for="perimeter in allPerimetersFiltered"
+ :title="perimeter.description"
+ :key="perimeter.id"
+ @click="addPerimeter(perimeter)"
+ >{{ perimeter.name }}</button>
+ </div>
+ <p>Click to add</p>
+ </div>
+ <div class="col-sm">
+ <h4>
+ Policy perimeters
+ <i class="fa fa-question-circle" style="margin-left: 2%" v-if="assignPerimeterHelpStrings.policyPerimeters" data-toggle="tooltip" :title="assignPerimeterHelpStrings.policyPerimeters"></i>
+ </h4>
+ <div class="w-100 height-200 scroll list-group list-group-flush border">
+ <div
+ @click="assign(perimeter)"
+ class="list-group-item"
+ :key="perimeter.id"
+ v-for="perimeter in perimetersFiltered"
+ >
+ <span :title="perimeter.description">{{ perimeter.name }}</span>
+ <button
+ type="button"
+ class="fa fa-trash pull-right btn-dark btn-sm"
+ @click.stop="removePerimeterFromPolicy(perimeter)"
+ title="Remove Perimeter"
+ ></button>
+ </div>
+ </div>
+ <p>Click to assign</p>
+ </div>
+ <div class="col-sm">
+ <h4>
+ Assigned perimeters
+ <i class="fa fa-question-circle" style="margin-left: 2%" v-if="assignPerimeterHelpStrings.assignedPerimeters" data-toggle="tooltip" :title="assignPerimeterHelpStrings.assignedPerimeters"></i>
+ </h4>
+ <div class="w-100 list-group border height-200 scroll">
+ <button
+ class="list-group-item"
+ :key="perimeter.id"
+ v-for="perimeter in assignmentsFiltered"
+ :title="perimeter.description"
+ @click="unassign(perimeter)"
+ >{{ perimeter.name }}</button>
+ </div>
+ <p>Click to unassign</p>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import PolicyService from "./../../services/Policy.service.js";
+import util from "./../../services/Util.service.js";
+import FormHeader from "./../FormHeader.vue";
+import CreatePerimeter from "./CreatePerimeter.vue";
+import helpstrings from "../../helpstrings";
+
+var categoryMap = {
+ subject: {
+ perimeterId: "subject_id"
+ },
+ object: {
+ perimeterId: "object_id"
+ },
+ action: {
+ perimeterId: "action_id"
+ }
+};
+
+export default {
+ props: {
+ dataToAssign: Object,
+ policy: Object
+ },
+ components: {
+ FormHeader,
+ CreatePerimeter
+ },
+ data() {
+ return {
+ selectedData: null,
+ selectedDataType: "",
+ loading: false,
+ perimeters: [],
+ allPerimeters: [],
+ assignments: [],
+ filterPerimeter: "",
+ creatingPerimeter: false,
+ assignPerimeterHelpStrings: {}
+ };
+ },
+ mounted() {
+ this.assignPerimeterHelpStrings = helpstrings.assignPerimeter;
+ },
+ computed: {
+ allPerimetersFiltered() {
+ return util.filterAndSortByName(this.allPerimeters, this.filterPerimeter);
+ },
+ perimetersFiltered() {
+ return util.filterAndSortByName(this.perimeters, this.filterPerimeter);
+ },
+ assignmentsFiltered() {
+ return util.filterAndSortByName(this.assignments, this.filterPerimeter);
+ }
+ },
+ watch: {
+ dataToAssign() {
+ this.selectedData = this.dataToAssign.selectedData;
+ this.selectedDataType = this.dataToAssign.selectedDataType;
+ if (this.selectedData) {
+ this.loadPerimeter();
+ }
+ }
+ },
+ methods: {
+ createPerimeter(perimeters) {
+ util.pushAll(this.perimeters, perimeters);
+ },
+ addPerimeter(perimeter) {
+ var self = this;
+ PolicyService.addPerimeterToPolicy(
+ self.selectedDataType,
+ self.policy,
+ perimeter
+ ).then(function() {
+ self.allPerimeters.splice(self.allPerimeters.indexOf(perimeter), 1);
+ self.perimeters.push(perimeter);
+ });
+ },
+ assign(perimeter) {
+ var self = this;
+ PolicyService.createAssignment(
+ self.selectedDataType,
+ self.policy,
+ perimeter,
+ self.selectedData
+ ).then(function() {
+ self.assignments.push(perimeter);
+ self.perimeters.splice(self.perimeters.indexOf(perimeter), 1);
+ });
+ },
+ unassign(perimeter) {
+ var self = this;
+ PolicyService.removeAssignment(
+ self.selectedDataType,
+ self.policy,
+ perimeter,
+ self.selectedData
+ ).then(function() {
+ self.perimeters.push(perimeter);
+ self.assignments.splice(self.assignments.indexOf(perimeter), 1);
+ });
+ },
+ removePerimeterFromPolicy(perimeter) {
+ if (
+ confirm(
+ "Are you sure to delete this Perimeter? (Associated assignments will be deleted too)"
+ )
+ ) {
+ var self = this;
+ PolicyService.removePerimeterFromPolicy(
+ self.selectedDataType,
+ self.policy,
+ perimeter
+ ).then(function() {
+ self.perimeters.splice(self.perimeters.indexOf(perimeter), 1);
+ perimeter.policy_list.splice(
+ perimeter.policy_list.indexOf(self.policy.id),
+ 1
+ );
+ if (perimeter.policy_list.length > 0) {
+ self.allPerimeters.push(perimeter);
+ }
+ });
+ }
+ },
+ loadPerimeter() {
+ var self = this;
+ self.loading = true;
+ self.perimeters = [];
+ self.allPerimeters = [];
+ self.assignments = [];
+
+ PolicyService.loadPerimetersAndAssignments(
+ self.selectedDataType,
+ self.policy
+ ).then(function(values) {
+ var category = categoryMap[self.selectedDataType];
+ self.loading = false;
+ self.perimeters = values.perimeters;
+ var index, perimeter;
+ for (index = 0; index < values.allPerimeters.length; index++) {
+ perimeter = values.allPerimeters[index];
+ if (perimeter.policy_list.indexOf(self.policy.id) < 0) {
+ self.allPerimeters.push(perimeter);
+ }
+ }
+ for (index = 0; index < values.assignments.length; index++) {
+ var assignment = values.assignments[index];
+ if (assignment.assignments.indexOf(self.selectedData.id) >= 0) {
+ perimeter = values.perimetersMap[assignment[category.perimeterId]];
+ self.assignments.push(perimeter);
+ self.perimeters.splice(self.perimeters.indexOf(perimeter), 1);
+ }
+ }
+ });
+ }
+ }
+};
+</script> \ No newline at end of file
diff --git a/dashboard/src/components/policy/CreateData.vue b/dashboard/src/components/policy/CreateData.vue
new file mode 100644
index 00000000..ca3c5183
--- /dev/null
+++ b/dashboard/src/components/policy/CreateData.vue
@@ -0,0 +1,75 @@
+<template>
+ <div class="list-group-item row">
+ <form>
+ <div class="form-group">
+ <label for="dataName">Name</label>
+ <input
+ type="text"
+ name="name"
+ v-model="dataCreate.name"
+ v-validate.initial="'alpha_dash|required|min:3'"
+ class="form-control"
+ id="dataName"
+ />
+ </div>
+ <div class="form-group">
+ <label for="dataDescription">Description</label>
+ <textarea
+ name="description"
+ v-model="dataCreate.description"
+ v-validate.initial="'required|min:3'"
+ class="form-control"
+ ></textarea>
+ </div>
+ <ul>
+ <li v-for="error in errors.all()" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ :disabled="errors.any()"
+ class="btn btn-primary"
+ @click="createData()"
+ >Create</button>
+ </form>
+ </div>
+</template>
+
+<script>
+import PolicyService from "./../../services/Policy.service.js";
+
+export default {
+ name: "createData",
+ props: {
+ policy: Object,
+ type: String,
+ category: Object,
+ },
+ data: function() {
+ return {
+ dataCreate: {
+ name: "",
+ description: ""
+ }
+ };
+ },
+ methods: {
+ createData() {
+ var self = this;
+ PolicyService.createData(
+ this.type,
+ this.policy,
+ this.category.id,
+ this.dataCreate
+ ).then(function(datas) {
+ self.$emit("dataCreated", datas[0]);
+ self.close();
+ });
+ },
+ close() {
+ this.$emit("close");
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/policy/CreatePerimeter.vue b/dashboard/src/components/policy/CreatePerimeter.vue
new file mode 100644
index 00000000..b8a9d532
--- /dev/null
+++ b/dashboard/src/components/policy/CreatePerimeter.vue
@@ -0,0 +1,73 @@
+<template>
+ <div class="list-group-item row">
+ <form>
+ <div class="form-group">
+ <label for="perimeterName">Name</label>
+ <input
+ type="text"
+ name="name"
+ v-model="perimeterCreate.name"
+ v-validate.initial="'alpha_dash|required|min:3'"
+ class="form-control"
+ id="perimeterName"
+ />
+ </div>
+ <div class="form-group">
+ <label for="perimeterDescription">Description</label>
+ <textarea
+ name="description"
+ v-model="perimeterCreate.description"
+ v-validate.initial="'required|min:3'"
+ class="form-control"
+ ></textarea>
+ </div>
+ <ul>
+ <li v-for="error in errors.all()" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ :disabled="errors.any()"
+ class="btn btn-primary"
+ @click="createPerimeter()"
+ >Create</button>
+ </form>
+ </div>
+</template>
+
+<script>
+import PolicyService from "./../../services/Policy.service.js";
+
+export default {
+ name: "createPerimeter",
+ props: {
+ policy: Object,
+ type: String
+ },
+ data: function() {
+ return {
+ perimeterCreate: {
+ name: "",
+ description: ""
+ }
+ };
+ },
+ methods: {
+ createPerimeter() {
+ var self = this;
+ PolicyService.createPerimeter(
+ this.type,
+ this.policy,
+ this.perimeterCreate
+ ).then(function(perimeters) {
+ self.$emit("perimeterCreated", perimeters);
+ self.close();
+ });
+ },
+ close() {
+ this.$emit("close");
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/policy/CreatePolicy.vue b/dashboard/src/components/policy/CreatePolicy.vue
new file mode 100644
index 00000000..b3e90c2d
--- /dev/null
+++ b/dashboard/src/components/policy/CreatePolicy.vue
@@ -0,0 +1,84 @@
+<template>
+ <div class="list-group-item row">
+ <form>
+ <div class="form-group">
+ <label for="policyName">Name</label>
+ <input
+ type="text"
+ name="name"
+ v-model="policyCreate.name"
+ v-validate.initial="'alpha_dash|required|min:3'"
+ class="form-control"
+ id="policyName"
+ />
+ </div>
+ <div class="form-group">
+ <label for="policyDescription">Description</label>
+ <textarea
+ name="description"
+ v-model="policyCreate.description"
+ v-validate.initial="'required|min:3'"
+ class="form-control"
+ ></textarea>
+ </div>
+ <div class="form-group">
+ <label for="policyGenre">Genre</label>
+ <select v-model="policyCreate.genre" class="form-control" id="policyGenre" v-validate.initial="'required'" name="genre">
+ <option>admin</option>
+ <option>authz</option>
+ </select>
+ </div>
+ <div class="form-group">
+ <label for="policyModel">Model</label>
+ <select v-model="policyCreate.model_id" class="form-control" id="policyModel" v-validate.initial="'required'" name="model">
+ <option v-for="model in models" :key="model.id" :value="model.id">{{ model.name }}</option>
+ </select>
+ </div>
+ <ul>
+ <li v-for="error in errors.all()" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ :disabled="errors.any()"
+ class="btn btn-primary"
+ @click="createPolicy()"
+ >Create</button>
+ </form>
+ </div>
+</template>
+
+<script>
+import PolicyService from "./../../services/Policy.service.js";
+import ModelService from "./../../services/Model.service.js";
+import util from "./../../services/Util.service.js";
+
+export default {
+ name: "createPolicy",
+ data: function() {
+ return {
+ policyCreate: {
+ name: "",
+ description: "",
+ genre: "",
+ model_id: ""
+ }
+ };
+ },
+ computed: {
+ models() {
+ return util.sortByName(ModelService.models);
+ }
+ },
+ methods: {
+ createPolicy() {
+ PolicyService.createPolicy(this.policyCreate);
+ this.close();
+ },
+ close() {
+ this.$emit("close");
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/policy/CreateRule.vue b/dashboard/src/components/policy/CreateRule.vue
new file mode 100644
index 00000000..656fa39a
--- /dev/null
+++ b/dashboard/src/components/policy/CreateRule.vue
@@ -0,0 +1,213 @@
+<template>
+ <div class="list-group-item row">
+ <form v-if="!metaruleId">
+ <div class="form-group">
+ <label for="metarule">Select a Metarule:</label>
+ <select v-model="metaruleId" class="form-control" id="metarule" name="metarule">
+ <option
+ v-for="metarule in policy.model.meta_rules"
+ :key="metarule.id"
+ :value="metarule.id"
+ >{{ metarule.name }}</option>
+ </select>
+ </div>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ </form>
+ <form v-else>
+ <div
+ class="form-group"
+ v-for="(categoryWrapper, index) in ruleData"
+ :key="categoryWrapper.id"
+ >
+ <label
+ :for="categoryWrapper.category.name"
+ >{{ 'Select ' + categoryWrapper.type + ' data of ' + categoryWrapper.category.name + ' category' }}</label>
+ <select
+ v-model="ruleCreate.rule[index]"
+ class="form-control"
+ :id="categoryWrapper.category.name"
+ :name="categoryWrapper.category.name"
+ v-validate.initial="'required'"
+ >
+ <option
+ v-for="data in categoryWrapper.data"
+ :key="data.id"
+ :value="data.id"
+ >{{ data.name }}</option>
+ </select>
+ <create-data
+ class="m-3"
+ @close="creatingDataCategory = null"
+ @dataCreated="dataCreated(categoryWrapper, $event, index)"
+ :policy="policy"
+ :type="categoryWrapper.type"
+ :category="categoryWrapper.category"
+ v-if="creatingDataCategory == categoryWrapper.category"
+ ></create-data>
+ <button
+ v-else
+ type="button"
+ class="btn btn-primary mt-3"
+ @click="creatingDataCategory = categoryWrapper.category"
+ >Or Create one</button>
+ </div>
+ <div v-for='(attribute, index) in policy.attributes' :key="attribute.id" class="form-group">
+ <label for="ruleAttributes">Attribute {{attribute.id}}</label>
+ <select
+ v-model="attributes[index]"
+ class="form-control"
+ v-validate.initial="'required'"
+ >
+ <option
+ v-for="value in attribute.values"
+ :key="value"
+ :value="value"
+ >{{ value }}</option>
+ </select>
+ </div>
+ <div class="form-group">
+ <label for="ruleInstructions">Instructions</label>
+ <select
+ v-model="ruleCreate.instructions"
+ class="form-control"
+ v-validate.initial="'required'"
+ >
+ <option
+ v-for="data in instructions"
+ :key="data"
+ :value="data"
+ >{{ data }}</option>
+ </select>
+ </div>
+ <ul>
+ <li v-for="error in errors.all()" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ :disabled="errors.any()"
+ class="btn btn-primary"
+ @click="createRule()"
+ >Create</button>
+ </form>
+ </div>
+</template>
+
+<script>
+import PolicyService from "./../../services/Policy.service.js";
+import ModelService from "./../../services/Model.service.js";
+import CreateData from "./CreateData.vue";
+
+function addCategories(type, categories, data, mapArray, initArray) {
+ var dataFiltered = [];
+
+ for (var i = 0; i < categories.length; i++) {
+ var category = categories[i];
+ for (var j = 0; j < data.length; j++) {
+ var element = data[j];
+ if (element.category_id == category.id) {
+ dataFiltered.push(element);
+ }
+ }
+
+ mapArray.push({
+ id: category.id,
+ category: category,
+ data: dataFiltered,
+ type: type
+ });
+ initArray.push(dataFiltered.length > 0 ? dataFiltered[0].id : null);
+ }
+}
+
+
+export default {
+ name: "createRule",
+ props: {
+ policy: Object
+ },
+ components: {
+ CreateData
+ },
+ data: function() {
+ return {
+ metarule: null,
+ metaruleId: null,
+ creatingDataCategory: null,
+ ruleData: [],
+ ruleCreate: {
+ instructions: 'grant',
+ rule: [],
+ },
+ instructions: ['grant', 'deny'],
+ attributes: [],
+ attribute: '',
+ };
+ },
+ watch: {
+ policy() {
+ if (this.policy) {
+ this.metaruleId = null;
+ if (this.policy.model.meta_rules.length == 1) {
+ this.metaruleId = this.policy.model.meta_rules[0].id;
+ }
+ }
+ },
+ metaruleId() {
+ if (this.metaruleId) {
+ this.metarule = ModelService.getMetaRule(this.metaruleId);
+ if (this.metarule){
+ for (let i = 0; i < this.policy.attributes.length; i++){
+ let attrs = this.policy.attributes[i].default;
+ this.attributes.push(attrs);
+ }
+ }
+ addCategories(
+ "subject",
+ this.metarule.subject_categories,
+ this.policy.subjectData,
+ this.ruleData,
+ this.ruleCreate.rule
+ );
+ addCategories(
+ "object",
+ this.metarule.object_categories,
+ this.policy.objectData,
+ this.ruleData,
+ this.ruleCreate.rule
+ );
+ addCategories(
+ "action",
+ this.metarule.action_categories,
+ this.policy.actionData,
+ this.ruleData,
+ this.ruleCreate.rule
+ );
+ }
+ }
+ },
+ methods: {
+ createRule() {
+ this.ruleCreate.enabled = true;
+ const instruction = "[{\n\t\"decision\": " + "\"" + this.ruleCreate.instructions + "\"" + "\n}]";
+ this.ruleCreate.instructions = JSON.parse(instruction);
+ this.ruleCreate.meta_rule_id = this.metarule.id;
+ this.ruleCreate.policy_id = this.policy.id;
+ for (let i = 0; i < this.attributes.length; i++) {
+ this.ruleCreate.rule.push("attributes:" + this.attributes[i]);
+ }
+
+ PolicyService.addRuleToPolicy(this.policy, this.ruleCreate);
+ this.close();
+ },
+ dataCreated(wrapper, data, index) {
+ wrapper.data.push(data);
+ this.$set(this.ruleCreate.rule, index, data.id);
+ },
+ close() {
+ this.$emit("close");
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/policy/DataList.vue b/dashboard/src/components/policy/DataList.vue
new file mode 100644
index 00000000..40f384f3
--- /dev/null
+++ b/dashboard/src/components/policy/DataList.vue
@@ -0,0 +1,16 @@
+<template>
+ <span>
+ <span v-for="(data, index) in list" :key="data.id">
+ <span v-if="index > 0">,</span>
+ <span>{{ data.name }}</span>
+ </span>
+ </span>
+</template>
+
+<script>
+export default {
+ props: {
+ list: Array
+ }
+}
+</script> \ No newline at end of file
diff --git a/dashboard/src/components/policy/FilterRules.vue b/dashboard/src/components/policy/FilterRules.vue
new file mode 100644
index 00000000..5d685952
--- /dev/null
+++ b/dashboard/src/components/policy/FilterRules.vue
@@ -0,0 +1,24 @@
+<template>
+ <div class="form-inline">
+ <input
+ type="search"
+ class="form-control filter col mr-auto"
+ placeholder="Filter rules"
+ v-bind:value="value"
+ v-on:input="$emit('input', $event.target.value)"
+ >
+ </div>
+</template>
+
+<script>
+ export default {
+ name: "FilterRules",
+ props: {
+ value: String
+ }
+ }
+</script>
+
+<style scoped>
+
+</style> \ No newline at end of file
diff --git a/dashboard/src/components/policy/Policy.vue b/dashboard/src/components/policy/Policy.vue
new file mode 100644
index 00000000..415f6b02
--- /dev/null
+++ b/dashboard/src/components/policy/Policy.vue
@@ -0,0 +1,186 @@
+<template>
+ <div>
+ <template v-if="edit">
+ <form>
+ <div class="form-group" >
+ <label for="policyName">Name</label>
+ <input
+ type="text"
+ name="name"
+ v-model="policyEdit.name"
+ v-validate="'alpha_dash|required|min:3'"
+ class="form-control"
+ id="policyName"
+ />
+ </div>
+ <div class="form-group">
+ <label for="policyDescription">Description</label>
+ <textarea
+ name="description"
+ v-model="policyEdit.description"
+ v-validate="'required|min:3'"
+ class="form-control"
+ ></textarea>
+ </div>
+ <div class="form-group">
+ <label for="policyGenre">Genre</label>
+ <select
+ v-model="policyEdit.genre"
+ class="form-control"
+ id="policyGenre"
+ v-validate.initial="'required'"
+ name="genre"
+ >
+ <option>admin</option>
+ <option>authz</option>
+ </select>
+ </div>
+ <ul>
+ <li v-for="error in errors.all()" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="edit = false">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ :disabled="errors.any()"
+ class="btn btn-primary"
+ @click="updatePolicy()"
+ >Update</button>
+ </form>
+ </template>
+ <template v-else>
+ <h3 class="list-group-item-heading inline " >{{ policy.name }}</h3>
+ <div class="pull-right">
+ <button
+ type="button"
+ class="fa fa-trash btn-dark btn-sm"
+ title="Remove Policy"
+ @click="removePolicy()"
+ ></button>
+ <button
+ type="button"
+ class="fa fa-edit btn-dark btn-sm"
+ title="Edit Policy"
+ @click="updatingPolicy()"
+ ></button>
+ </div>
+ <p class="list-group-item-text">{{ policy.description }}</p>
+
+ <unused-data :policy="policy" v-if="showAlert" @close="allowAlert = false"></unused-data>
+
+ <details class="list-group-item-text">
+ <summary @click="populatePolicy()">
+ <h4 class="inline-block width-200">
+ Rules
+ <i class="fa fa-question-circle" style="margin-left: 2%" v-if="policyHelpStrings.rules" data-toggle="tooltip" :title="policyHelpStrings.rules"></i>
+ </h4>
+ <button
+ type="button"
+ class="fa fa-plus btn-dark btn-sm"
+ @click="creatingRule = true"
+ title="Add Rule"
+ ></button>
+ </summary>
+ <create-rule v-if="creatingRule" @close="creatingRule = false" :policy="policy"></create-rule>
+ <div class="list-group" v-else>
+ <filter-rules v-model="filter" ></filter-rules>
+ <br/>
+ <p v-if="!policy.rulesPopulated" class="list-group-item-text">Loading rules...</p>
+ <div v-else>
+ <rule
+ v-for="rule in filteredRules"
+ :key="rule.id"
+ :rule="rule"
+ :selected="selectedRule == rule"
+ :policy="policy"
+ @show="selectRule($event)"
+ ></rule>
+ </div>
+ </div>
+ </details>
+ </template>
+ <hr />
+ </div>
+</template>
+
+<script>
+import UnusedData from "./UnusedData.vue";
+import PolicyService from "./../../services/Policy.service.js";
+import util from "./../../services/Util.service.js";
+import Rule from "./Rule.vue";
+import CreateRule from "./CreateRule.vue";
+import FilterRules from "./FilterRules.vue";
+
+import Vue from "vue";
+import helpstrings from "../../helpstrings";
+
+var selectedRule = new Vue({data: {rule: null}});
+
+export default {
+ props: {
+ policy: Object
+ },
+ data() {
+ return {
+ filter: "",
+ edit: false,
+ creatingRule: false,
+ allowAlert: true,
+ policyEdit: {},
+ policyHelpStrings: {}
+ };
+ },
+ mounted() {
+ this.policyHelpStrings = helpstrings.policy;
+ },
+ computed: {
+ filteredRules() {
+ let filteredRules = PolicyService.filterByRules(this.policy.rules, this.filter);
+
+
+ return filteredRules;
+ },
+ selectedRule() {
+ return selectedRule.rule;
+ },
+ showAlert() {
+ return (
+ this.allowAlert &&
+ (this.policy.unusedSubjectData.length ||
+ this.policy.unusedObjectData.length ||
+ this.policy.unusedActionData.length)
+ );
+ },
+ },
+ components: {
+ UnusedData,
+ Rule,
+ CreateRule,
+ FilterRules
+ },
+ methods: {
+ populatePolicy() {
+ PolicyService.populatePolicy(this.policy);
+ },
+ removePolicy() {
+ if (
+ confirm(
+ "Are you sure to delete this Policy? (Associated perimeter, data an PDP will be deleted too)"
+ )
+ )
+ PolicyService.removePolicy(this.policy);
+ },
+ updatingPolicy() {
+ this.policyEdit = util.clone(this.policy);
+ this.edit = true;
+ },
+ updatePolicy() {
+ this.edit = false;
+ PolicyService.updatePolicy(this.policyEdit);
+ },
+ selectRule(rule) {
+ selectedRule.rule = rule;
+ }
+ }
+};
+</script> \ No newline at end of file
diff --git a/dashboard/src/components/policy/Rule.vue b/dashboard/src/components/policy/Rule.vue
new file mode 100644
index 00000000..c8889b86
--- /dev/null
+++ b/dashboard/src/components/policy/Rule.vue
@@ -0,0 +1,231 @@
+<template>
+ <div class="list-group-item">
+ <details >
+ <summary class="list-group-item-heading" :style="ruleIsGrant ? 'background-color: var(--green)' : 'background-color: Tomato'" >
+
+ <b>Rule: </b>
+ <data-list :list="rule.subjectData"></data-list> |
+ <data-list :list="rule.actionData"></data-list> |
+ <data-list :list="rule.objectData"></data-list>
+ <span v-if="rule.attributeData.length"> | <data-list :list="rule.attributeData"></data-list></span>
+ <div class="pull-right" style="background-color: white">
+ <button
+ type="button"
+ class="fa fa-trash pull-right btn-dark btn-sm"
+ @click="removeRuleFromPolicy()"
+ title="Remove Rule"
+ ></button>
+ <button type="button"
+ :class="ruleIsGrant ? buttonRuleIsGrant : buttonRuleIsDeny"
+ @click="changeRuleDecision()"
+ title="Change Decision"
+ ></button>
+ </div>
+ </summary>
+ <div >
+ <p class="list-group-item-text"></p>
+ <table class="table">
+ <thead>
+ <tr>
+ <th>
+ <span>
+ Subjects data
+ <i class="fa fa-question-circle" v-if="ruleHelpStrings.subjectsData" data-toggle="tooltip" :title="ruleHelpStrings.subjectsData"></i>
+ </span>
+ </th>
+ <th>
+ <span>
+ Objects data
+ <i class="fa fa-question-circle" v-if="ruleHelpStrings.objectsData" data-toggle="tooltip" :title="ruleHelpStrings.objectsData"></i>
+ </span>
+ </th>
+ <th>
+ <span>
+ Actions data
+ <i class="fa fa-question-circle" v-if="ruleHelpStrings.actionsData" data-toggle="tooltip" :title="ruleHelpStrings.actionsData"></i>
+ </span>
+ </th>
+ <th v-if="rule.attributeData.length">
+ <span>
+ Attributes
+ <i class="fa fa-question-circle" v-if="ruleHelpStrings.attributes" data-toggle="tooltip" :title="ruleHelpStrings.attributes"></i>
+ </span>
+ </th>
+ <th>
+ <span>
+ Instructions
+ <i class="fa fa-question-circle" v-if="ruleHelpStrings.instructions" data-toggle="tooltip" :title="ruleHelpStrings.instructions"></i>
+ </span>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <p
+ v-for="data in rule.subjectData"
+ :key="data.id"
+ :class="{'selected-data': selectedData == data}"
+ >
+ <span :title="data.description">{{ data.name }}</span>
+ <button
+ v-if="selectedData != data"
+ type="button"
+ class="fa fa-exchange pull-right btn-dark btn-sm"
+ @click="assignData('subject', data)"
+ title="Assign to perimeters"
+ ></button>
+ <button
+ v-if="selectedData == data"
+ type="button"
+ class="fa fa-times pull-right btn-dark btn-sm"
+ @click="unassignData()"
+ title="Close"
+ ></button>
+ </p>
+ </td>
+ <td>
+ <p
+ v-for="data in rule.objectData"
+ :key="data.id"
+ :class="{'selected-data': selectedData == data}"
+ >
+ <span :title="data.description">{{ data.name }}</span>
+ <button
+ v-if="selectedData != data"
+ type="button"
+ class="fa fa-exchange pull-right btn-dark btn-sm"
+ @click="assignData('object', data)"
+ title="Assign to perimeters"
+ ></button>
+ <button
+ v-if="selectedData == data"
+ type="button"
+ class="fa fa-times pull-right btn-dark btn-sm"
+ @click="unassignData()"
+ title="Close"
+ ></button>
+ </p>
+ </td>
+ <td>
+ <p
+ v-for="data in rule.actionData"
+ :key="data.id"
+ :class="{'selected-data': selectedData == data}"
+ >
+ <span :title="data.description">{{ data.name }}</span>
+ <button
+ v-if="selectedData != data"
+ type="button"
+ class="fa fa-exchange pull-right btn-dark btn-sm"
+ @click="assignData('action', data)"
+ title="Assign to perimeters"
+ ></button>
+ <button
+ v-if="selectedData == data"
+ type="button"
+ class="fa fa-times pull-right btn-dark btn-sm"
+ @click="unassignData()"
+ title="Close"
+ ></button>
+ </p>
+ </td>
+ <td v-if="rule.attributeData.length">
+ <p
+ v-for="data in rule.attributeData"
+ :key="data.id"
+ :class="{'selected-data': selectedData == data}"
+ >
+ <span :title="data.description">{{data.id}} : {{ data.name }}</span>
+ </p>
+ </td>
+ <td>
+ <pre><code>{{rule.instructions}}</code></pre>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <assign-perimeter :policy="policy" :dataToAssign="dataToAssign"></assign-perimeter>
+
+ </div>
+ </details>
+ </div>
+</template>
+
+<script>
+ import AttributeService from "./../../services/Attribute.service"
+ import PolicyService from "./../../services/Policy.service.js";
+ import DataList from "./DataList.vue";
+ import AssignPerimeter from "./AssignPerimeter.vue";
+ import helpstrings from "../../helpstrings";
+
+ export default {
+ props: {
+ rule: Object,
+ selected: Boolean,
+ policy: Object
+ },
+ data() {
+ return {
+ dataToAssign: {
+ selectedData: null,
+ selectedDataType: "",
+ },
+ selectedData: null,
+ ruleIsGrant: false,
+ buttonRuleIsGrant: 'fa fa-toggle-on pull-right btn-dark btn-sm',
+ buttonRuleIsDeny: 'fa fa-toggle-off pull-right btn-dark btn-sm',
+ ruleHelpStrings: {}
+
+ }
+ },
+ components: {
+ DataList,
+ AssignPerimeter,
+ },
+ created() {
+ AttributeService.initialize();
+ },
+ mounted() {
+ this.ruleIsGrant = ("grant".localeCompare(this.rule.instructions[0].decision) == 0);
+ this.ruleHelpStrings = helpstrings.rule;
+ },
+ watch: {
+ selected() {
+ if (!this.selected)
+ this.unassignData();
+ }
+ },
+ methods: {
+ changeRuleDecision() {
+ var decision = ("grant".localeCompare(this.rule.instructions[0].decision) == 0) ? "deny" : "grant";
+ PolicyService.updateRule(this.policy, this.rule, decision).then(res => {
+ this.ruleIsGrant = !this.ruleIsGrant;
+ this.rule.instructions = res;
+ });
+
+ },
+ showRule() {
+ this.$emit("show", this.selected ? null : this.rule);
+ },
+ removeRuleFromPolicy() {
+ if (confirm("Are you sure to delete this Rule?"))
+ PolicyService.removeRuleFromPolicy(this.policy, this.rule);
+ },
+ assignData(type, data) {
+ this.dataToAssign = {
+ selectedData: data,
+ selectedDataType: type,
+ };
+ this.selectedData = data;
+ },
+ unassignData() {
+ this.assignData("", null);
+ }
+ }
+ };
+</script>
+
+<style scoped>
+
+</style> \ No newline at end of file
diff --git a/dashboard/src/components/policy/UnusedData.vue b/dashboard/src/components/policy/UnusedData.vue
new file mode 100644
index 00000000..48b8b642
--- /dev/null
+++ b/dashboard/src/components/policy/UnusedData.vue
@@ -0,0 +1,89 @@
+<template>
+ <div>
+ <div
+ v-if="policy.unusedSubjectData.length
+ || policy.unusedObjectData.length
+ || policy.unusedActionData.length"
+ class="alert alert-dismissable alert-warning"
+ >
+ <button type="button" class="close" data-dismiss="alert" @click="showUnused = false; $emit('close')">×</button>
+ <h4>Warning!</h4>
+ <p>
+ Some data are unused, please check them and delete them if necessary.
+ <a
+ href
+ @click.prevent="showUnused = true"
+ v-show="!showUnused"
+ >Show unused data</a>
+ <a href @click.prevent="showUnused = false" v-show="showUnused">Hide unused data</a>
+ </p>
+ </div>
+
+ <div v-if="showUnused" class="row overflow-hidden mb-3">
+ <div class="list-group col" v-if="policy.unusedSubjectData.length">
+ <h3 class="list-group-item active">Unused Subject data</h3>
+ <div v-for="subject in policy.unusedSubjectData" :key="subject.id" class="list-group-item">
+ <h4 class="list-group-item-heading inline" :title="subject.description">{{ subject.name }}</h4>
+ <button
+ type="button"
+ class="fa fa-trash pull-right btn-dark btn-sm"
+ @click="removeData('subject', policy, subject)"
+ title="Remove Subject data"
+ ></button>
+ </div>
+ </div>
+
+ <div class="list-group col" v-if="policy.unusedObjectData.length">
+ <h3 class="list-group-item active">Unused Object data</h3>
+ <div v-for="object in policy.unusedObjectData" :key="object.id" class="list-group-item">
+ <h4 class="list-group-item-heading inline" :title="object.description">{{ object.name }}</h4>
+ <button
+ type="button"
+ class="fa fa-trash pull-right btn-dark btn-sm"
+ @click="removeData('object', policy, object)"
+ title="Remove Object data"
+ ></button>
+ </div>
+ </div>
+
+ <div class="list-group col" v-if="policy.unusedActionData.length">
+ <h3 class="list-group-item active">Unused Action data</h3>
+ <div v-for="action in policy.unusedActionData" :key="action.id" class="list-group-item">
+ <h4 class="list-group-item-heading inline" :title="action.description">{{ action.name }}</h4>
+ <button
+ type="button"
+ class="fa fa-trash pull-right btn-dark btn-sm"
+ @click="removeData('action', policy, action)"
+ title="Remove Action data"
+ ></button>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import PolicyService from "./../../services/Policy.service.js";
+
+
+export default {
+ props: {
+ policy: Object
+ },
+ data() {
+ return {
+ showUnused: false
+ };
+ },
+ methods: {
+ removeData(type, policy, data) {
+ if (
+ confirm(
+ "Are you sure to delete this Data? (Associated assignments and rules will be deleted too)"
+ )
+ )
+ PolicyService.removeData(type, policy, data);
+ }
+ }
+};
+</script> \ No newline at end of file