Select Git revision
create-json-schema.js
-
Rhys Arkins authoredRhys Arkins authored
Tree.vue 9.00 KiB
<template>
<div id="toe-container" class="container">
<div class="box info-box" v-show="hoveredNode">
<div class="close-button">
<i @click="infoBoxClose" title="Close" class="fa fa-solid fa-xmark"></i>
</div>
<p v-if="hoveredNode?.name != null">
<b>Name:</b> {{ hoveredNode.name }}
</p>
<p v-if="hoveredNode?.state == 'UNSET'">
<b>State:</b> No evidence obtained
</p>
<p v-if="hoveredNode?.state == 'UNSELECTED'"><b>State:</b> Unselected</p>
<p v-if="hoveredNode?.state == 'SET' && hoveredNode?.conformant">
<b>State:</b> Compliant
</p>
<p v-if="hoveredNode?.state == 'SET' && !hoveredNode?.conformant">
<b>State:</b> Non compliant
</p>
<p
v-if="hoveredNode?.code != null && hoveredNode.code != hoveredNode.name"
>
<b>Code:</b> {{ hoveredNode.code }}
</p>
<p v-if="hoveredNode?.timestamp != null">
<b>Timestamp:</b> {{ formatDate(hoveredNode.timestamp) }}
</p>
<p v-if="hoveredNode?.id != null">
<b>Assesment result id:</b> {{ hoveredNode.id }}
</p>
<p v-if="hoveredNode?.metricId != null">
<b>Metric id:</b> {{ hoveredNode.metricId }}
</p>
<p v-if="hoveredNode?.assessmentResult != null">
<b>Assessment result:</b> {{ hoveredNode.assessmentResult }}
</p>
<p v-if="hoveredNode?.evidenceId != null">
<b>Evidence id:</b> {{ hoveredNode.evidenceId }}
</p>
<p v-if="hoveredNode?.targetValue != null">
<b>Target value:</b> {{ hoveredNode.targetValue }}
</p>
<p v-if="hoveredNode?.noncomplianceComments != null">
<b>Noncompliance comments:</b> {{ hoveredNode.noncomplianceComments }}
</p>
<p v-if="hoveredNode?.value != null">
<b>Value:</b> {{ hoveredNode.value }}
</p>
<p v-if="hoveredNode?.weight != null">
<b>Weight:</b> {{ hoveredNode.weight }}
</p>
<p v-if="hoveredNode?.threshold != null">
<b>Threshold:</b> {{ hoveredNode.threshold }}
</p>
<p v-if="hoveredNode?.resource?.id != null">
<b>Resource id:</b> {{ hoveredNode.resource.id }}
</p>
<p v-if="hoveredNode?.resource?.resourceType != null">
<b>Resource type:</b> {{ hoveredNode.resource.resourceType }}
</p>
<p v-if="hoveredNode?.resource?.weight != null">
<b>Resource weight:</b> {{ hoveredNode.resource.weight }}
</p>
<p v-if="hoveredNode?.description != null">
<b>Description:</b> {{ hoveredNode.description }}
</p>
</div>
<div>
<span class="btn-group">
<button class="btn btn-outline-primary" @click="controlScale('bigger')">
Zoom in
</button>
<button
class="btn btn-outline-primary"
@click="controlScale('smaller')"
>
Zoom out
</button>
<button
class="btn btn-outline-primary"
@click="controlScale('restore')"
>
Reset zoom
</button>
</span>
<span class="btn-group">
<button class="btn btn-outline-primary" @click="collapseAll">
Collapse all
</button>
<button class="btn btn-outline-primary" @click="expandAll">
Expand all
</button>
</span>
<span class="btn-group">
<button class="btn btn-outline-success" @click="toogleInstructions">
Instructions
</button>
</span>
</div>
<div class="box" id="instructions" v-show="showInstructions">
<div class="close-button">
<i
@click="toogleInstructions"
title="Close"
class="fa fa-solid fa-xmark"
></i>
</div>
<ul>
<li><b>left click:</b> hide/show node children</li>
<li><b>right click:</b> permanently open node details</li>
</ul>
</div>
<vue-tree
v-if="treeData"
ref="scaleTree"
style="width: 100%; height: 900px; border: 1px solid gray"
:dataset="treeData"
:config="treeConfig"
:collapse-enabled="true"
>
<template v-slot:node="{ node, collapsed }">
<div
class="rich-media-node"
:class="{
'node-unselected': node.state == 'UNSELECTED',
'node-unset': node.state == 'UNSET',
'node-set-conformant': node.state == 'SET' && node.conformant,
'node-set-unconformant': node.state == 'SET' && !node.conformant,
}"
:style="{ border: collapsed ? '3px solid black' : '' }"
@mouseover="infoBoxTemporarilyShow(node, $event.target)"
@mouseleave="infoBoxHide($event.target)"
@mousedown.right="infoBoxPermanentlyShowed(node, $event.target)"
@contextmenu.prevent
>
<span
style="
padding: 4px 0;
font-weight: bold;
word-break: break-word;
overflow-wrap: break-word;
"
>{{ node.name }}</span
>
</div>
</template>
</vue-tree>
</div>
</template>
<script>
import VueTree from "@ssthouse/vue3-tree-chart";
import "@ssthouse/vue3-tree-chart/dist/vue3-tree-chart.css";
import { formatDateHelper } from "@/helpers/helpers";
import $ from "jquery";
import { collapseExpandTree } from "@/mixins/collapseExpandTree";
export default {
name: "Tree",
components: {
"vue-tree": VueTree,
},
props: ["treeData"],
mixins: [collapseExpandTree],
data() {
return {
treeConfig: { nodeWidth: 230, nodeHeight: 80, levelHeight: 200 },
hoveredNode: null,
infoBoxPermanentlyShowedNodeElement: null,
showInstructions: false,
};
},
methods: {
controlScale(command) {
switch (command) {
case "bigger":
this.$refs.scaleTree.zoomIn();
break;
case "smaller":
this.$refs.scaleTree.zoomOut();
break;
case "restore":
this.$refs.scaleTree.restoreScale();
break;
}
},
infoBoxShow(node) {
this.hoveredNode = node;
},
infoBoxHide(el) {
if (!this.infoBoxPermanentlyShowedNodeElement) {
$(el).removeClass("selected");
this.hoveredNode = null;
}
},
infoBoxTemporarilyShow(node, el) {
if (!this.infoBoxPermanentlyShowedNodeElement) {
$(el).parent().addClass("selected");
this.infoBoxShow(node);
}
},
infoBoxPermanentlyShowed(node, el) {
if (this.infoBoxPermanentlyShowedNodeElement != null) {
this.infoBoxPermanentlyShowedNodeElement.removeClass("selected");
}
this.infoBoxPermanentlyShowedNodeElement = $(el).parent();
$(el).parent().addClass("selected");
this.infoBoxShow(node);
},
infoBoxClose() {
var el = this.infoBoxPermanentlyShowedNodeElement;
this.infoBoxPermanentlyShowedNodeElement = null;
this.infoBoxHide(el);
},
collapseAll() {
this.collapseRecursively(this.$refs.scaleTree.nodeDataList[0].data);
this.$refs.scaleTree.draw();
},
expandAll() {
this.expandRecursively(this.$refs.scaleTree.nodeDataList[0].data);
this.$refs.scaleTree.draw();
},
toogleInstructions() {
this.showInstructions = !this.showInstructions;
},
formatDate(date) {
return formatDateHelper(date);
},
},
watch: {
treeData() {
this.infoBoxClose();
},
},
};
</script>
<style scoped lang="scss">
@import "@/styles/_variables.scss";
.container {
display: flex;
flex-direction: column;
align-items: center;
max-width: 5000px;
}
#toe-container {
position: relative;
padding-bottom: 20px;
}
.tree-container {
background: white;
margin-top: 20px;
}
.rich-media-node {
width: auto;
max-width: 200px;
margin: 8px;
padding: 8px;
display: flex;
flex-direction: column;
align-items: flex-start;
text-align: center;
justify-content: center;
color: black;
border-radius: 4px;
font-size: 14px;
}
.box {
p {
padding: 0px 10px;
}
padding-top: 10px;
position: fixed;
top: 134px;
min-width: 340px;
background-color: white;
border: 1px solid;
border-radius: 0;
font-size: 14px;
text-align: left;
max-width: 25%;
.close-button {
font-size: 20px;
text-align: right;
padding-right: 14px;
}
&.info-box {
position: absolute;
border-color: $color-blue;
z-index: 10;
left: 12px;
top: 74px;
}
&#instructions {
border-color: $color-green;
z-index: 11;
}
}
.btn-group {
margin: 3px 3px;
.btn {
margin: 5px 5px;
}
}
.node-unset {
background-color: $node-yellow-background;
&.selected {
background-color: $node-yellow-dark-background;
}
}
.node-set-conformant {
background-color: $node-green-background;
&.selected {
background-color: $node-green-dark-background;
}
}
.node-set-unconformant {
background-color: $node-red-background;
&.selected {
background-color: $node-red-dark-background;
}
}
.node-unselected {
background-color: $node-gray-background;
&.selected {
background-color: $node-gray-dark-background;
}
}
</style>