Skip to content

Commit

Permalink
Merge pull request #1 from maastrichtlawtech/dev
Browse files Browse the repository at this point in the history
Merge of dev
  • Loading branch information
eensander authored Jun 21, 2022
2 parents 5bcb3fa + edb9db9 commit 0ae26c3
Show file tree
Hide file tree
Showing 18 changed files with 744 additions and 602 deletions.
2 changes: 2 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ module.exports = {

'prefer-const': 'warn',

'@typescript-eslint/no-unused-vars': 'off'

// '@typescript-eslint/ban-ts-comment': 'off',
// 'vue/script-setup-uses-vars': 'error',
}
Expand Down
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2022 Maastricht Law & Tech Lab

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "GraphDoc",
"version": "1.0.0",
"version": "1.6.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
Expand Down
9 changes: 3 additions & 6 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,13 @@
import { defineComponent } from 'vue';
// import GraphModeler from './components/GraphModeler.vue';
import GraphEditorComponent from './components/graph/GraphEditorComponent.vue';
import Test from './components/Test.vue';
</script>

<style lang="scss">
#app {
// font-family: Avenir, Helvetica, Arial, sans-serif;
// -webkit-font-smoothing: antialiased;
// -moz-osx-font-smoothing: grayscale;
// text-align: center;
// color: #2c3e50;
margin-top: 60px;
margin: 1rem;
margin-top: 30px;
}
</style>
236 changes: 193 additions & 43 deletions src/components/graph/GraphModeler.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,43 +27,45 @@
<GraphModelerToolbar
:graph="graph"
:docassemble_cont_update="docassemble_cont_update"
:init_modeler="init_modeler"
/>
</div>
<div class="w-full flex" style="height: 500px;">
<div class="w-20 bg-gray-100 border-t border-gray-200">
<div class="w-20 flex-initial bg-gray-100 border-t border-gray-200">
<GraphModelerElementsBar v-if="graph !== null" :graph="graph"></GraphModelerElementsBar>
</div>
<div class="w-32 flex-grow border border-b-0 border-gray-200">
<div class="relative h-full" id="modeler-container"></div>
<div id="modeler-container-box" class="flex flex-grow border-4 border-b-0 border-gray-300" >
<!-- <div id="modeler-container-box" class="flex w-full h-full" > -->
<!-- <div id="modeler-container" class="relative h-full"></div> -->
<!-- <div id="modeler-container" class="relative h-full flex-grow border-4 border-b-0 border-gray-300" style="flex: 1"></div> -->
<div id="modeler-container" style="flex: 1"></div>
</div>
<div class="w-64 bg-gray-100 border-t border-gray-200 overflow-y-auto">
<GraphModelerConfigBar :default_edge_label="default_edge_label" :cell="selected_cell"></GraphModelerConfigBar>
<div class="w-64 flex-initial bg-gray-100 border-t border-gray-200 overflow-y-auto">
<GraphModelerConfigBar :cell="selected_cell"></GraphModelerConfigBar>
</div>
</div>
</div>
<div class="border border-gray-500 rounded mt-4 mb-2 py-2 px-3" :class="{ 'bg-red-50': docassemble_validation_errors.length > 0 }">
<template v-if="docassemble_validation_errors.length > 0">
<span class="block underline">Validation errors</span>
<ul class="list-disc list-inside">
<li class="text-red-900" v-for="validation_error in docassemble_validation_errors" :key="validation_error">
{{ validation_error }}
</li>
</ul>
</template>
<span v-else class="block text-green-800">Graph contains no errors</span>
</div>

<GraphValidationErrors :formatted_validation_errors="formatted_validation_errors" />

<div class="my-4">
<span>Docassemble out:</span>
<div class="w-full min-h-4 font-mono border rounded p-2 mt-1 whitespace-pre-wrap">
{{ docassemble_cont }}
<span class="text-lg block mb-1">Docassemble interview output</span>
<label class="text-sm text-gray-700">
<input type="checkbox" class="mr-1" v-model="docassemble_out_options.include_json_export" /> Include a copy of the model
</label>
<div class="relative">
<div class="w-full min-h-4 font-mono border rounded p-2 mt-1 whitespace-pre-wrap" id="docassemble_out_container">
{{ docassemble_cont }}
</div>
<span class="copy-button" @click="copy_docassemble_out()">{{ copy_button_content }}</span>
</div>
</div>

</template>

<script lang="ts" setup>
import { computed, onMounted, reactive, Ref, ref, watch } from 'vue';
import { computed, h, onMounted, reactive, Ref, ref, VNode, watch } from 'vue';
import { useToast } from "vue-toastification";
Expand All @@ -73,10 +75,12 @@
import GraphModelerConfigBar from './GraphModelerConfigBar.vue'
import GraphModelerElementsBar from './GraphModelerElementsBar.vue'
import GraphModelerToolbar from './GraphModelerToolbar.vue'
import GraphValidationErrors from './GraphValidationErrors.vue'
import Transformer from '@/utils/transformer'
import { graph_options_defaults, graph_register_defaults } from '@/utils/model'
import { DocassembleTransformer } from '@/utils/transformer/docassemble';
import { default_edge_label, graph_options_defaults, graph_register_defaults } from '@/utils/antv-model'
import { DocassembleTransformer, validationErrorList } from '@/utils/transformer/docassemble';
import { Node, Edge } from '@/utils/graph';
const read_more = ref(false);
Expand All @@ -91,38 +95,129 @@
const graph: Ref<Graph | undefined> = ref();
const selected_cell: Ref<Cell | undefined> = ref();
const default_edge_label = (text = '') => {
return {
attrs: {
text: {
text: text,
}
},
position: {
distance: .3,
},
function select_cell(cell: Cell | undefined) {
if (typeof cell !== 'undefined') {
selected_cell.value = cell;
graph.value?.select(cell);
graph.value?.scrollToCell(cell);
}
};
}
const docassemble_validation_errors: Ref<string[]> = ref([]);
const docassemble_validation_errors: Ref<validationErrorList> = ref([]);
const formatted_validation_errors: Ref<(string | VNode)[][]> = ref([]);
const docassemble_cont: Ref<string> = ref('');
const docassemble_out_options = reactive({
include_json_export: true,
});
watch(() => docassemble_out_options, (val => {
console.log("options updated")
docassemble_cont_update();
}), { deep: true })
// type NotFunction<T> = T extends Node | Edge ? never : T;
const docassemble_cont_update = () => {
if (typeof graph.value == "undefined")
return;
const transformer = (new Transformer()).in_antv(graph.value);
docassemble_validation_errors.value = (new DocassembleTransformer()).validate_graph(transformer.graph);
if(docassemble_validation_errors.value.length == 0)
docassemble_cont.value = (new Transformer()).in_antv(graph.value).out_docassemble();
else
// remove cells from all errors
graph.value.getCells().forEach(cell =>
typeof cell.getData()?.errors !== 'undefined' &&
cell.setData({'errors': false}, {no_da_update: true}));
// graph.value.getCells().forEach(cell => console.log(typeof cell.getData()?.errors, cell.getData()));
// console.log(docassemble_validation_errors.value)
// this part formats the conversion errors, which contain Node and Edge
// objects, to a clickable span as a VNode
formatted_validation_errors.value = docassemble_validation_errors.value.map((val_error) => {
return val_error.map(error_part => {
if (typeof error_part === "string") {
return error_part;
} else if (error_part.is_node()) {
const error_node = (error_part as Node);
const antv_node = graph.value?.getCellById(error_node.id);
if (typeof antv_node !== 'undefined') {
antv_node.setData({errors: true}, {no_da_update: true});
return h('span', {
onClick(event: any) {
select_cell(antv_node);
},
class: 'clickable-entity'
}, error_node.get_label());
} else {
return `"${ error_node.get_label() }""`
}
} else if (error_part.is_edge()) {
const error_edge = (error_part as Edge);
const antv_edge = graph.value?.getCellById(error_edge.id);
const error_edge_content = error_edge.gd.content ?
`with content ${error_edge.gd.content}` :
`leaving from node ${ error_edge.get_node_from().get_label() }`;
if (typeof antv_edge !== 'undefined') {
return h('span', {
onClick(event: any) {
select_cell(graph.value?.getCellById(error_edge.gd.content ? error_edge.id : error_edge.node_from_id));
},
class: 'clickable-entity'
}, error_edge_content);
} else {
return `"${ error_edge_content }"`
}
} else {
return ''
}
});
});
// console.log(formatted_validation_errors.value)
// const transformer = new Transformer()).in_antv(graph.value);
if(formatted_validation_errors.value.length == 0) {
docassemble_cont.value = transformer.out_docassemble()
if (docassemble_cont.value && docassemble_out_options.include_json_export) {
docassemble_cont.value = docassemble_cont.value
.concat("\n---\n# [START INLINE GRAPHDOC EXPORT]")
.concat("\n# ").concat(JSON.stringify(transformer.out_json()))
.concat("\n# [END INLINE GRAPHDOC EXPORT]");
}
} else {
docassemble_cont.value = '-';
}
// docassemble_cont.value = JSON.stringify((new Transformer()).in_antv(graph.value).out_json());
// docassemble_cont.value = JSON.stringify(graph.value.toJSON());
};
const copy_button_content = ref('COPY');
const copy_docassemble_out = () => {
(window as any).getSelection().selectAllChildren(
document.getElementById('docassemble_out_container')
);
// source: https://stackoverflow.com/a/67008779/17864167
navigator.clipboard.writeText(docassemble_cont.value)
.then(() => {
copy_button_content.value = 'COPIED!';
setTimeout(() => { copy_button_content.value = 'COPY' }, 1200)
})
.catch(err => {
copy_button_content.value = 'FAILED';
setTimeout(() => { copy_button_content.value = 'COPY' }, 1200)
console.log('Failed to copy', err);
});
}
const remote_load = (remote_data: any) => {
// graph.value?.fromJSON((new Transformer()).in_json(remote_data).out_antv());
Expand All @@ -142,7 +237,23 @@
// if (typeof graph.value === "undefined")
// return false;
graph.on('cell:change:*', docassemble_cont_update)
// graph.on('cell:change:*', docassemble_cont_update)
// graph.on('cell:change:*', ())
graph.on('cell:change:*', (args) => {
// console.log(args)
if (!(args.options.no_da_update ?? false)) {
if (args.key == 'target') {
// when target hits, it changes from {x: n, y: n} to Cell, which we will catch here.
if (typeof args.current.cell != typeof args.previous.cell)
docassemble_cont_update()
// other changes to ignore:
} else if (!['target', 'zIndex', 'tools', 'position'].includes(args.key as string))
docassemble_cont_update()
}
})
graph.on('cell:removed', docassemble_cont_update)
graph.on('cell:added', docassemble_cont_update)
Expand All @@ -165,24 +276,63 @@
const init_modeler = () => {
let container = document.getElementById('modeler-container')!;
// let container_box = document.getElementById('modeler-container-box')!;
// // for resetting
// // container.innerHTML = "";
// // container_box.innerHTML = "";
// // container_box.appendChild(container);
let width = container.scrollWidth;
let height = container.scrollHeight || 500;
graph.value = new Graph({
...graph_options_defaults,
container: container,
width,
height,
autoResize: true,
// width,
// height,
})
// graph.value.resize()
if(graph.value != undefined)
{
graph_register_defaults(graph.value)
register_events(graph.value)
graph_register_defaults(graph.value);
register_events(graph.value);
docassemble_cont_update()
// window.graph_main = this.graph;
}
};
</script>

<style lang="scss">
.validation-error {
span.clickable-entity {
@apply font-mono text-sm;
color: rgb(63, 19, 19);
cursor: pointer;
text-decoration: underline;
text-underline-offset: 4px;
&:hover {
// @apply text-black;
text-decoration: initial;
}
}
}
.copy-button {
@apply absolute top-0 right-0 m-2 px-2 py-0.5 rounded border bg-gray-100;
@apply text-sm uppercase font-bold text-gray-600 ;
&:hover {
@apply ring-2 ring-gray-200 border-gray-300 cursor-pointer
}
}
</style>
Loading

0 comments on commit 0ae26c3

Please sign in to comment.