mirror of
https://github.com/lana-k/sqliteviz.git
synced 2026-03-22 05:56:16 +08:00
Compare commits
12 Commits
4e5adc147f
...
0.29.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2c376219f | ||
|
|
0199415dde | ||
|
|
534b186d76 | ||
|
|
4f6efb5bda | ||
|
|
2c0b8f9124 | ||
|
|
5265f5493e | ||
|
|
c0e59f6fb8 | ||
|
|
7471744633 | ||
|
|
e6e5efa8c6 | ||
|
|
57c36b3900 | ||
|
|
1e8c1761e6 | ||
|
|
dd30e17ff5 |
@@ -92,11 +92,23 @@ module.exports = function (config) {
|
|||||||
'dom.w3c_touch_events.enabled': 1,
|
'dom.w3c_touch_events.enabled': 1,
|
||||||
'dom.events.asyncClipboard.clipboardItem': true
|
'dom.events.asyncClipboard.clipboardItem': true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
ChromiumHeadlessWebGL: {
|
||||||
|
base: 'ChromiumHeadless',
|
||||||
|
flags: [
|
||||||
|
'--headless=new',
|
||||||
|
'--use-angle=swiftshader',
|
||||||
|
'--use-gl=angle',
|
||||||
|
'--enable-webgl',
|
||||||
|
'--ignore-gpu-blocklist',
|
||||||
|
'--disable-gpu-sandbox',
|
||||||
|
'--no-sandbox'
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// start these browsers
|
// start these browsers
|
||||||
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
|
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
|
||||||
browsers: ['ChromiumHeadless', 'FirefoxHeadlessTouch'],
|
browsers: ['ChromiumHeadlessWebGL', 'FirefoxHeadlessTouch'],
|
||||||
|
|
||||||
// Continuous Integration mode
|
// Continuous Integration mode
|
||||||
// if true, Karma captures browsers, runs the tests and exits
|
// if true, Karma captures browsers, runs the tests and exits
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sqliteviz",
|
"name": "sqliteviz",
|
||||||
"version": "0.28.2",
|
"version": "0.29.0",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -13,16 +13,16 @@
|
|||||||
:style="movableSplitterStyle"
|
:style="movableSplitterStyle"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
|
v-show="!before.hidden"
|
||||||
ref="left"
|
ref="left"
|
||||||
class="splitpanes-pane"
|
class="splitpanes-pane"
|
||||||
:size="paneBefore.size"
|
|
||||||
max-size="30"
|
|
||||||
:style="styles.before"
|
:style="styles.before"
|
||||||
>
|
>
|
||||||
<slot name="left-pane" />
|
<slot name="left-pane" />
|
||||||
</div>
|
</div>
|
||||||
<!-- Splitter start-->
|
<!-- Splitter start-->
|
||||||
<div
|
<div
|
||||||
|
v-show="!before.hidden && !after.hidden"
|
||||||
class="splitpanes-splitter"
|
class="splitpanes-splitter"
|
||||||
@mousedown="bindEvents"
|
@mousedown="bindEvents"
|
||||||
@touchstart="bindEvents"
|
@touchstart="bindEvents"
|
||||||
@@ -64,7 +64,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- splitter end -->
|
<!-- splitter end -->
|
||||||
<div ref="right" class="splitpanes-pane" :style="styles.after">
|
<div
|
||||||
|
v-show="!after.hidden"
|
||||||
|
ref="right"
|
||||||
|
class="splitpanes-pane"
|
||||||
|
:style="styles.after"
|
||||||
|
>
|
||||||
<slot name="right-pane" />
|
<slot name="right-pane" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -114,10 +119,12 @@ export default {
|
|||||||
styles() {
|
styles() {
|
||||||
return {
|
return {
|
||||||
before: {
|
before: {
|
||||||
[this.horizontal ? 'height' : 'width']: `${this.paneBefore.size}%`
|
[this.horizontal ? 'height' : 'width']:
|
||||||
|
`${this.after.hidden ? 100 : this.paneBefore.size}%`
|
||||||
},
|
},
|
||||||
after: {
|
after: {
|
||||||
[this.horizontal ? 'height' : 'width']: `${this.paneAfter.size}%`
|
[this.horizontal ? 'height' : 'width']:
|
||||||
|
`${this.before.hidden ? 100 : this.paneAfter.size}%`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
:initOptions="initOptionsByMode[mode]"
|
:initOptions="initOptionsByMode[mode]"
|
||||||
:data-sources="dataSource"
|
:data-sources="dataSource"
|
||||||
:showViewSettings="showViewSettings"
|
:showViewSettings="showViewSettings"
|
||||||
|
:showValueViewer="viewValuePanelVisible"
|
||||||
@loading-image-completed="loadingImage = false"
|
@loading-image-completed="loadingImage = false"
|
||||||
@update="$emit('update')"
|
@update="$emit('update')"
|
||||||
/>
|
/>
|
||||||
@@ -56,6 +57,17 @@
|
|||||||
<settings-icon />
|
<settings-icon />
|
||||||
</icon-button>
|
</icon-button>
|
||||||
|
|
||||||
|
<icon-button
|
||||||
|
v-if="mode === 'graph'"
|
||||||
|
ref="viewNodeOrEdgeBtn"
|
||||||
|
tooltip="View node or edge details"
|
||||||
|
tooltipPosition="top-left"
|
||||||
|
:active="viewValuePanelVisible"
|
||||||
|
@click="viewValuePanelVisible = !viewValuePanelVisible"
|
||||||
|
>
|
||||||
|
<view-cell-value-icon />
|
||||||
|
</icon-button>
|
||||||
|
|
||||||
<div class="side-tool-bar-divider" />
|
<div class="side-tool-bar-divider" />
|
||||||
|
|
||||||
<icon-button
|
<icon-button
|
||||||
@@ -126,6 +138,7 @@ import HtmlIcon from '@/components/svg/html'
|
|||||||
import ExportToSvgIcon from '@/components/svg/exportToSvg'
|
import ExportToSvgIcon from '@/components/svg/exportToSvg'
|
||||||
import PngIcon from '@/components/svg/png'
|
import PngIcon from '@/components/svg/png'
|
||||||
import ClipboardIcon from '@/components/svg/clipboard'
|
import ClipboardIcon from '@/components/svg/clipboard'
|
||||||
|
import ViewCellValueIcon from '@/components/svg/viewCellValue'
|
||||||
import cIo from '@/lib/utils/clipboardIo'
|
import cIo from '@/lib/utils/clipboardIo'
|
||||||
import loadingDialog from '@/components/Common/LoadingDialog.vue'
|
import loadingDialog from '@/components/Common/LoadingDialog.vue'
|
||||||
import time from '@/lib/utils/time'
|
import time from '@/lib/utils/time'
|
||||||
@@ -144,6 +157,7 @@ export default {
|
|||||||
GraphIcon,
|
GraphIcon,
|
||||||
SettingsIcon,
|
SettingsIcon,
|
||||||
ExportToSvgIcon,
|
ExportToSvgIcon,
|
||||||
|
ViewCellValueIcon,
|
||||||
PngIcon,
|
PngIcon,
|
||||||
HtmlIcon,
|
HtmlIcon,
|
||||||
ClipboardIcon,
|
ClipboardIcon,
|
||||||
@@ -172,7 +186,8 @@ export default {
|
|||||||
graph: this.initMode === 'graph' ? this.initOptions : null
|
graph: this.initMode === 'graph' ? this.initOptions : null
|
||||||
},
|
},
|
||||||
showLoadingDialog: false,
|
showLoadingDialog: false,
|
||||||
showViewSettings: true
|
showViewSettings: true,
|
||||||
|
viewValuePanelVisible: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|||||||
@@ -67,6 +67,15 @@
|
|||||||
@color-change="settings.style.backgroundColor = $event"
|
@color-change="settings.style.backgroundColor = $event"
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
|
<Field label="Highlight mode">
|
||||||
|
<Dropdown
|
||||||
|
:options="highlightModeOptions"
|
||||||
|
:value="settings.style.highlightMode"
|
||||||
|
className="test_highlight_mode_select"
|
||||||
|
@change="updateHighlightNodeMode"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
</Fold>
|
</Fold>
|
||||||
</Panel>
|
</Panel>
|
||||||
<Panel group="Style" name="Nodes">
|
<Panel group="Style" name="Nodes">
|
||||||
@@ -237,7 +246,9 @@ import {
|
|||||||
buildNodes,
|
buildNodes,
|
||||||
buildEdges,
|
buildEdges,
|
||||||
updateNodes,
|
updateNodes,
|
||||||
updateEdges
|
updateEdges,
|
||||||
|
reduceNodes,
|
||||||
|
reduceEdges
|
||||||
} from '@/lib/graphHelper'
|
} from '@/lib/graphHelper'
|
||||||
import Graph from 'graphology'
|
import Graph from 'graphology'
|
||||||
import { circular, random, circlepack } from 'graphology-layout'
|
import { circular, random, circlepack } from 'graphology-layout'
|
||||||
@@ -277,7 +288,7 @@ export default {
|
|||||||
initOptions: Object,
|
initOptions: Object,
|
||||||
showViewSettings: Boolean
|
showViewSettings: Boolean
|
||||||
},
|
},
|
||||||
emits: ['update'],
|
emits: ['update', 'selectItem', 'clearSelection'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
graph: new Graph({ multi: true, allowSelfLoops: true }),
|
graph: new Graph({ multi: true, allowSelfLoops: true }),
|
||||||
@@ -300,7 +311,10 @@ export default {
|
|||||||
circlepack: CirclePackLayoutSettings,
|
circlepack: CirclePackLayoutSettings,
|
||||||
forceAtlas2: ForceAtlasLayoutSettings
|
forceAtlas2: ForceAtlasLayoutSettings
|
||||||
}),
|
}),
|
||||||
|
selectedNodeId: undefined,
|
||||||
|
hoveredNodeId: undefined,
|
||||||
|
selectedEdgeId: undefined,
|
||||||
|
hoveredEdgeId: undefined,
|
||||||
settings: this.initOptions
|
settings: this.initOptions
|
||||||
? JSON.parse(JSON.stringify(this.initOptions))
|
? JSON.parse(JSON.stringify(this.initOptions))
|
||||||
: {
|
: {
|
||||||
@@ -312,6 +326,7 @@ export default {
|
|||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: 'white',
|
backgroundColor: 'white',
|
||||||
|
highlightMode: 'node_and_neighbors',
|
||||||
nodes: {
|
nodes: {
|
||||||
size: {
|
size: {
|
||||||
type: 'constant',
|
type: 'constant',
|
||||||
@@ -352,7 +367,15 @@ export default {
|
|||||||
random: null,
|
random: null,
|
||||||
circlepack: null,
|
circlepack: null,
|
||||||
forceAtlas2: null
|
forceAtlas2: null
|
||||||
}
|
},
|
||||||
|
highlightModeOptions: markRaw([
|
||||||
|
{ label: 'Node alone', value: 'node_alone' },
|
||||||
|
{ label: 'Node and neighbors', value: 'node_and_neighbors' },
|
||||||
|
{
|
||||||
|
label: 'Include edges between neighbors',
|
||||||
|
value: 'include_neighbor_edges'
|
||||||
|
}
|
||||||
|
])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -379,6 +402,46 @@ export default {
|
|||||||
}, new Set())
|
}, new Set())
|
||||||
|
|
||||||
return Array.from(keySet)
|
return Array.from(keySet)
|
||||||
|
},
|
||||||
|
neighborsOfSelectedNode() {
|
||||||
|
if (this.settings.style.highlightMode === 'node_alone') {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return this.selectedNodeId
|
||||||
|
? new Set(this.graph.neighbors(this.selectedNodeId))
|
||||||
|
: undefined
|
||||||
|
},
|
||||||
|
neighborsOfHoveredNode() {
|
||||||
|
if (this.settings.style.highlightMode === 'node_alone') {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return this.hoveredNodeId
|
||||||
|
? new Set(this.graph.neighbors(this.hoveredNodeId))
|
||||||
|
: undefined
|
||||||
|
},
|
||||||
|
hoveredEdgeExtremities() {
|
||||||
|
return this.hoveredEdgeId
|
||||||
|
? this.graph.extremities(this.hoveredEdgeId)
|
||||||
|
: []
|
||||||
|
},
|
||||||
|
selectedEdgeExtremities() {
|
||||||
|
return this.selectedEdgeId
|
||||||
|
? this.graph.extremities(this.selectedEdgeId)
|
||||||
|
: []
|
||||||
|
},
|
||||||
|
interactionState() {
|
||||||
|
return {
|
||||||
|
selectedNodeId: this.selectedNodeId,
|
||||||
|
hoveredNodeId: this.hoveredNodeId,
|
||||||
|
selectedEdgeId: this.selectedEdgeId,
|
||||||
|
hoveredEdgeId: this.hoveredEdgeId,
|
||||||
|
|
||||||
|
neighborsOfSelectedNode: this.neighborsOfSelectedNode,
|
||||||
|
neighborsOfHoveredNode: this.neighborsOfHoveredNode,
|
||||||
|
|
||||||
|
hoveredEdgeExtremities: this.hoveredEdgeExtremities,
|
||||||
|
selectedEdgeExtremities: this.selectedEdgeExtremities
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -423,6 +486,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
buildGraph() {
|
buildGraph() {
|
||||||
|
this.clearSelection()
|
||||||
if (this.renderer) {
|
if (this.renderer) {
|
||||||
this.renderer.kill()
|
this.renderer.kill()
|
||||||
}
|
}
|
||||||
@@ -440,12 +504,85 @@ export default {
|
|||||||
renderEdgeLabels: true,
|
renderEdgeLabels: true,
|
||||||
allowInvalidContainer: true,
|
allowInvalidContainer: true,
|
||||||
labelColor: { attribute: 'labelColor', color: '#444444' },
|
labelColor: { attribute: 'labelColor', color: '#444444' },
|
||||||
edgeLabelColor: { attribute: 'labelColor', color: '#a2b1c6' }
|
edgeLabelColor: { attribute: 'labelColor', color: '#a2b1c6' },
|
||||||
|
enableEdgeEvents: true,
|
||||||
|
zIndex: true,
|
||||||
|
nodeReducer: (node, data) =>
|
||||||
|
reduceNodes(node, data, this.interactionState, this.settings),
|
||||||
|
edgeReducer: (edge, data) =>
|
||||||
|
reduceEdges(
|
||||||
|
edge,
|
||||||
|
data,
|
||||||
|
this.interactionState,
|
||||||
|
this.settings,
|
||||||
|
this.graph
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
this.renderer.on('clickNode', ({ node }) => {
|
||||||
|
this.selectedNodeId = node
|
||||||
|
this.selectedEdgeId = undefined
|
||||||
|
this.$emit('selectItem', this.graph.getNodeAttributes(node).data)
|
||||||
|
this.renderer.refresh({
|
||||||
|
skipIndexation: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.renderer.on('clickEdge', ({ edge }) => {
|
||||||
|
this.selectedEdgeId = edge
|
||||||
|
this.selectedNodeId = undefined
|
||||||
|
this.$emit('selectItem', this.graph.getEdgeAttributes(edge).data)
|
||||||
|
this.renderer.refresh({
|
||||||
|
skipIndexation: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.renderer.on('clickStage', () => {
|
||||||
|
this.clearSelection()
|
||||||
|
this.renderer.refresh({
|
||||||
|
skipIndexation: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.renderer.on('enterNode', ({ node }) => {
|
||||||
|
this.hoveredNodeId = node
|
||||||
|
this.renderer.refresh({
|
||||||
|
skipIndexation: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.renderer.on('enterEdge', ({ edge }) => {
|
||||||
|
this.hoveredEdgeId = edge
|
||||||
|
this.renderer.refresh({
|
||||||
|
skipIndexation: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.renderer.on('leaveNode', () => {
|
||||||
|
this.hoveredNodeId = undefined
|
||||||
|
this.renderer.refresh({
|
||||||
|
skipIndexation: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.renderer.on('leaveEdge', () => {
|
||||||
|
this.hoveredEdgeId = undefined
|
||||||
|
this.renderer.refresh({
|
||||||
|
skipIndexation: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
if (this.settings.layout.type === 'forceAtlas2') {
|
if (this.settings.layout.type === 'forceAtlas2') {
|
||||||
this.autoRunFA2Layout()
|
this.autoRunFA2Layout()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
clearSelection() {
|
||||||
|
this.selectedNodeId = undefined
|
||||||
|
this.selectedEdgeId = undefined
|
||||||
|
this.$emit('clearSelection')
|
||||||
|
},
|
||||||
|
updateHighlightNodeMode(mode) {
|
||||||
|
this.settings.style.highlightMode = mode
|
||||||
|
|
||||||
|
if (this.renderer) {
|
||||||
|
this.renderer.refresh({
|
||||||
|
skipIndexation: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
updateStructure(attributeName, value) {
|
updateStructure(attributeName, value) {
|
||||||
this.settings.structure[attributeName] = value
|
this.settings.structure[attributeName] = value
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,21 +13,38 @@
|
|||||||
documentation</a
|
documentation</a
|
||||||
>.
|
>.
|
||||||
</div>
|
</div>
|
||||||
<div
|
<splitpanes
|
||||||
|
:before="{ size: 70, max: 100 }"
|
||||||
|
:after="{ size: 30, max: 50, hidden: !showValueViewer }"
|
||||||
|
:default="{ before: 70, after: 30 }"
|
||||||
class="graph"
|
class="graph"
|
||||||
:style="{
|
:style="{
|
||||||
height:
|
height:
|
||||||
!dataSources || !dataSourceIsValid ? 'calc(100% - 40px)' : '100%'
|
!dataSources || !dataSourceIsValid ? 'calc(100% - 40px)' : '100%'
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<GraphEditor
|
<template #left-pane>
|
||||||
ref="graphEditor"
|
<div ref="graphEditorContainer" :style="{ height: '100%' }">
|
||||||
:dataSources="dataSources"
|
<GraphEditor
|
||||||
:initOptions="initOptions"
|
ref="graphEditor"
|
||||||
:showViewSettings="showViewSettings"
|
:dataSources="dataSources"
|
||||||
@update="$emit('update')"
|
:initOptions="initOptions"
|
||||||
/>
|
:showViewSettings="showViewSettings"
|
||||||
</div>
|
@update="$emit('update')"
|
||||||
|
@select-item="selectedItem = $event"
|
||||||
|
@clear-selection="selectedItem = null"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-if="showValueViewer" #right-pane>
|
||||||
|
<value-viewer
|
||||||
|
:empty="!selectedItem"
|
||||||
|
emptyMessage="No node or edge selected to view"
|
||||||
|
:value="JSON.stringify(selectedItem)"
|
||||||
|
defaultFormat="json"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</splitpanes>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -35,17 +52,20 @@
|
|||||||
import 'react-chart-editor/lib/react-chart-editor.css'
|
import 'react-chart-editor/lib/react-chart-editor.css'
|
||||||
import GraphEditor from '@/components/Graph/GraphEditor.vue'
|
import GraphEditor from '@/components/Graph/GraphEditor.vue'
|
||||||
import { dataSourceIsValid } from '@/lib/graphHelper'
|
import { dataSourceIsValid } from '@/lib/graphHelper'
|
||||||
|
import ValueViewer from '@/components/ValueViewer.vue'
|
||||||
|
import Splitpanes from '@/components/Common/Splitpanes'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Graph',
|
name: 'Graph',
|
||||||
components: { GraphEditor },
|
components: { GraphEditor, ValueViewer, Splitpanes },
|
||||||
props: {
|
props: {
|
||||||
dataSources: Object,
|
dataSources: Object,
|
||||||
initOptions: Object,
|
initOptions: Object,
|
||||||
exportToPngEnabled: Boolean,
|
exportToPngEnabled: Boolean,
|
||||||
exportToSvgEnabled: Boolean,
|
exportToSvgEnabled: Boolean,
|
||||||
exportToHtmlEnabled: Boolean,
|
exportToHtmlEnabled: Boolean,
|
||||||
showViewSettings: Boolean
|
showViewSettings: Boolean,
|
||||||
|
showValueViewer: Boolean
|
||||||
},
|
},
|
||||||
emits: [
|
emits: [
|
||||||
'update:exportToSvgEnabled',
|
'update:exportToSvgEnabled',
|
||||||
@@ -57,7 +77,8 @@ export default {
|
|||||||
],
|
],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
resizeObserver: null
|
resizeObserver: null,
|
||||||
|
selectedItem: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -83,10 +104,10 @@ export default {
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.resizeObserver = new ResizeObserver(this.handleResize)
|
this.resizeObserver = new ResizeObserver(this.handleResize)
|
||||||
this.resizeObserver.observe(this.$refs.graphContainer)
|
this.resizeObserver.observe(this.$refs.graphEditorContainer)
|
||||||
},
|
},
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
this.resizeObserver.unobserve(this.$refs.graphContainer)
|
this.resizeObserver.unobserve(this.$refs.graphEditorContainer)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getOptionsForSave() {
|
getOptionsForSave() {
|
||||||
@@ -100,7 +121,7 @@ export default {
|
|||||||
return this.$refs.graphEditor.prepareCopy()
|
return this.$refs.graphEditor.prepareCopy()
|
||||||
},
|
},
|
||||||
async handleResize() {
|
async handleResize() {
|
||||||
const renderer = this.$refs.graphEditor.renderer
|
const renderer = this.$refs.graphEditor?.renderer
|
||||||
if (renderer) {
|
if (renderer) {
|
||||||
renderer.refresh()
|
renderer.refresh()
|
||||||
renderer.getCamera().animatedReset({ duration: 600 })
|
renderer.getCamera().animatedReset({ duration: 600 })
|
||||||
|
|||||||
@@ -1,40 +1,66 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="runResultPanel" class="run-result-panel">
|
<div ref="runResultPanel" class="run-result-panel">
|
||||||
<component
|
<splitpanes
|
||||||
:is="viewValuePanelVisible ? 'splitpanes' : 'div'"
|
|
||||||
:before="{ size: 50, max: 100 }"
|
:before="{ size: 50, max: 100 }"
|
||||||
:after="{ size: 50, max: 100 }"
|
:after="{ size: 50, max: 100, hidden: !viewValuePanelVisible }"
|
||||||
:default="{ before: 50, after: 50 }"
|
:default="{ before: 50, after: 50 }"
|
||||||
class="run-result-panel-content"
|
class="run-result-panel-content"
|
||||||
>
|
>
|
||||||
<template #left-pane>
|
<template #left-pane>
|
||||||
<div
|
<div class="result-set-container">
|
||||||
:id="'run-result-left-pane-' + tab.id"
|
<div
|
||||||
class="result-set-container"
|
v-show="result === null && !isGettingResults && !error"
|
||||||
/>
|
class="table-preview result-before"
|
||||||
</template>
|
>
|
||||||
<div
|
Run your query and get results here
|
||||||
:id="'run-result-result-set-' + tab.id"
|
|
||||||
class="result-set-container"
|
|
||||||
/>
|
|
||||||
<template v-if="viewValuePanelVisible" #right-pane>
|
|
||||||
<div class="value-viewer-container">
|
|
||||||
<value-viewer
|
|
||||||
v-show="selectedCell"
|
|
||||||
:cellValue="
|
|
||||||
selectedCell
|
|
||||||
? result.values[result.columns[selectedCell.dataset.col]][
|
|
||||||
selectedCell.dataset.row
|
|
||||||
]
|
|
||||||
: ''
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
<div v-show="!selectedCell" class="table-preview">
|
|
||||||
No cell selected to view
|
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="isGettingResults" class="table-preview result-in-progress">
|
||||||
|
<loading-indicator :size="30" />
|
||||||
|
Fetching results...
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-show="result === undefined && !isGettingResults && !error"
|
||||||
|
class="table-preview result-empty"
|
||||||
|
>
|
||||||
|
No rows retrieved according to your query
|
||||||
|
</div>
|
||||||
|
<logs v-if="error" :messages="[error]" />
|
||||||
|
<sql-table
|
||||||
|
v-if="result && !viewRecord"
|
||||||
|
:data-set="result"
|
||||||
|
:time="time"
|
||||||
|
:pageSize="pageSize"
|
||||||
|
:page="defaultPage"
|
||||||
|
:selectedCellCoordinates="defaultSelectedCell"
|
||||||
|
class="straight"
|
||||||
|
@update-selected-cell="onUpdateSelectedCell"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<record
|
||||||
|
v-if="result && viewRecord"
|
||||||
|
ref="recordView"
|
||||||
|
:data-set="result"
|
||||||
|
:time="time"
|
||||||
|
:selectedColumnIndex="selectedCell ? +selectedCell.dataset.col : 0"
|
||||||
|
:rowIndex="selectedCell ? +selectedCell.dataset.row : 0"
|
||||||
|
@update-selected-cell="onUpdateSelectedCell"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</component>
|
<template v-if="viewValuePanelVisible" #right-pane>
|
||||||
|
<value-viewer
|
||||||
|
:empty="!selectedCell"
|
||||||
|
emptyMessage="No cell selected to view"
|
||||||
|
:value="
|
||||||
|
selectedCell
|
||||||
|
? result.values[result.columns[selectedCell.dataset.col]][
|
||||||
|
selectedCell.dataset.row
|
||||||
|
]
|
||||||
|
: ''
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</splitpanes>
|
||||||
|
|
||||||
<side-tool-bar panel="table" @switch-to="$emit('switchTo', $event)">
|
<side-tool-bar panel="table" @switch-to="$emit('switchTo', $event)">
|
||||||
<icon-button
|
<icon-button
|
||||||
@@ -89,48 +115,6 @@
|
|||||||
@action="copyToClipboard"
|
@action="copyToClipboard"
|
||||||
@cancel="cancelCopy"
|
@cancel="cancelCopy"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<teleport defer :to="resultSetTeleportTarget" :disabled="!enableTeleport">
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
v-show="result === null && !isGettingResults && !error"
|
|
||||||
class="table-preview result-before"
|
|
||||||
>
|
|
||||||
Run your query and get results here
|
|
||||||
</div>
|
|
||||||
<div v-if="isGettingResults" class="table-preview result-in-progress">
|
|
||||||
<loading-indicator :size="30" />
|
|
||||||
Fetching results...
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-show="result === undefined && !isGettingResults && !error"
|
|
||||||
class="table-preview result-empty"
|
|
||||||
>
|
|
||||||
No rows retrieved according to your query
|
|
||||||
</div>
|
|
||||||
<logs v-if="error" :messages="[error]" />
|
|
||||||
<sql-table
|
|
||||||
v-if="result && !viewRecord"
|
|
||||||
:data-set="result"
|
|
||||||
:time="time"
|
|
||||||
:pageSize="pageSize"
|
|
||||||
:page="defaultPage"
|
|
||||||
:selectedCellCoordinates="defaultSelectedCell"
|
|
||||||
class="straight"
|
|
||||||
@update-selected-cell="onUpdateSelectedCell"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<record
|
|
||||||
v-if="result && viewRecord"
|
|
||||||
ref="recordView"
|
|
||||||
:data-set="result"
|
|
||||||
:time="time"
|
|
||||||
:selectedColumnIndex="selectedCell ? +selectedCell.dataset.col : 0"
|
|
||||||
:rowIndex="selectedCell ? +selectedCell.dataset.row : 0"
|
|
||||||
@update-selected-cell="onUpdateSelectedCell"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</teleport>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -151,7 +135,7 @@ import cIo from '@/lib/utils/clipboardIo'
|
|||||||
import time from '@/lib/utils/time'
|
import time from '@/lib/utils/time'
|
||||||
import loadingDialog from '@/components/Common/LoadingDialog'
|
import loadingDialog from '@/components/Common/LoadingDialog'
|
||||||
import events from '@/lib/utils/events'
|
import events from '@/lib/utils/events'
|
||||||
import ValueViewer from './ValueViewer'
|
import ValueViewer from '@/components/ValueViewer'
|
||||||
import Record from './Record/index.vue'
|
import Record from './Record/index.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -172,7 +156,6 @@ export default {
|
|||||||
Splitpanes
|
Splitpanes
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
tab: Object,
|
|
||||||
result: Object,
|
result: Object,
|
||||||
isGettingResults: Boolean,
|
isGettingResults: Boolean,
|
||||||
error: Object,
|
error: Object,
|
||||||
@@ -194,20 +177,6 @@ export default {
|
|||||||
showLoadingDialog: false
|
showLoadingDialog: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
resultSetTeleportTarget() {
|
|
||||||
if (!this.enableTeleport) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
const base = `#${
|
|
||||||
this.viewValuePanelVisible
|
|
||||||
? 'run-result-left-pane'
|
|
||||||
: 'run-result-result-set'
|
|
||||||
}`
|
|
||||||
const tabIdPostfix = `-${this.tab.id}`
|
|
||||||
return base + tabIdPostfix
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
watch: {
|
||||||
result() {
|
result() {
|
||||||
this.defaultSelectedCell = null
|
this.defaultSelectedCell = null
|
||||||
@@ -332,19 +301,12 @@ export default {
|
|||||||
width: 0;
|
width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.result-set-container,
|
.result-set-container {
|
||||||
.result-set-container > div {
|
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
.value-viewer-container {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
background-color: var(--color-white);
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-preview {
|
.table-preview {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
@@ -37,7 +37,6 @@
|
|||||||
:disabled="!enableTeleport"
|
:disabled="!enableTeleport"
|
||||||
>
|
>
|
||||||
<run-result
|
<run-result
|
||||||
:tab="tab"
|
|
||||||
:result="tab.result"
|
:result="tab.result"
|
||||||
:isGettingResults="tab.isGettingResults"
|
:isGettingResults="tab.isGettingResults"
|
||||||
:error="tab.error"
|
:error="tab.error"
|
||||||
|
|||||||
@@ -1,48 +1,56 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="value-viewer">
|
<div class="value-viewer">
|
||||||
<div class="value-viewer-toolbar">
|
<template v-if="!empty">
|
||||||
<button
|
<div class="value-viewer-toolbar">
|
||||||
v-for="format in formats"
|
<button
|
||||||
:key="format.value"
|
v-for="format in formats"
|
||||||
type="button"
|
:key="format.value"
|
||||||
:aria-selected="currentFormat === format.value"
|
type="button"
|
||||||
:class="format.value"
|
:aria-selected="currentFormat === format.value"
|
||||||
@click="currentFormat = format.value"
|
:class="format.value"
|
||||||
>
|
@click="currentFormat = format.value"
|
||||||
{{ format.text }}
|
>
|
||||||
</button>
|
{{ format.text }}
|
||||||
|
</button>
|
||||||
|
|
||||||
<button type="button" class="copy" @click="copyToClipboard">Copy</button>
|
<button type="button" class="copy" @click="copyToClipboard">
|
||||||
<button
|
Copy
|
||||||
type="button"
|
</button>
|
||||||
class="line-wrap"
|
<button
|
||||||
:aria-selected="lineWrapping === true"
|
type="button"
|
||||||
@click="lineWrapping = !lineWrapping"
|
class="line-wrap"
|
||||||
>
|
:aria-selected="lineWrapping === true"
|
||||||
Line wrap
|
@click="lineWrapping = !lineWrapping"
|
||||||
</button>
|
>
|
||||||
</div>
|
Line wrap
|
||||||
<div class="value-body">
|
</button>
|
||||||
<codemirror
|
</div>
|
||||||
v-if="currentFormat === 'json' && formattedJson"
|
<div class="value-body">
|
||||||
:value="formattedJson"
|
<codemirror
|
||||||
:options="cmOptions"
|
v-if="currentFormat === 'json' && formattedJson"
|
||||||
class="json-value original-style"
|
:value="formattedJson"
|
||||||
/>
|
:options="cmOptions"
|
||||||
<pre
|
class="json-value original-style"
|
||||||
v-if="currentFormat === 'text'"
|
/>
|
||||||
:class="[
|
<pre
|
||||||
'text-value',
|
v-if="currentFormat === 'text'"
|
||||||
{ 'meta-value': isNull || isBlob },
|
:class="[
|
||||||
{ 'line-wrap': lineWrapping }
|
'text-value',
|
||||||
]"
|
{ 'meta-value': isNull || isBlob },
|
||||||
>{{ cellText }}</pre
|
{ 'line-wrap': lineWrapping }
|
||||||
>
|
]"
|
||||||
<logs
|
>{{ cellText }}</pre
|
||||||
v-if="messages && messages.length > 0"
|
>
|
||||||
:messages="messages"
|
<logs
|
||||||
class="messages"
|
v-if="messages && messages.length > 0"
|
||||||
/>
|
:messages="messages"
|
||||||
|
class="messages"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div v-show="empty" class="empty-message">
|
||||||
|
{{ emptyMessage }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -60,12 +68,19 @@ import cIo from '@/lib/utils/clipboardIo'
|
|||||||
import Logs from '@/components/Common/Logs'
|
import Logs from '@/components/Common/Logs'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
name: 'ValueViewer',
|
||||||
components: {
|
components: {
|
||||||
Codemirror,
|
Codemirror,
|
||||||
Logs
|
Logs
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
cellValue: [String, Number, Uint8Array]
|
value: [String, Number, Uint8Array],
|
||||||
|
empty: Boolean,
|
||||||
|
emptyMessage: String,
|
||||||
|
defaultFormat: {
|
||||||
|
type: String,
|
||||||
|
default: 'text'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -73,7 +88,7 @@ export default {
|
|||||||
{ text: 'Text', value: 'text' },
|
{ text: 'Text', value: 'text' },
|
||||||
{ text: 'JSON', value: 'json' }
|
{ text: 'JSON', value: 'json' }
|
||||||
],
|
],
|
||||||
currentFormat: 'text',
|
currentFormat: this.defaultFormat,
|
||||||
lineWrapping: false,
|
lineWrapping: false,
|
||||||
formattedJson: '',
|
formattedJson: '',
|
||||||
messages: []
|
messages: []
|
||||||
@@ -94,13 +109,13 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
isBlob() {
|
isBlob() {
|
||||||
return this.cellValue && ArrayBuffer.isView(this.cellValue)
|
return this.value && ArrayBuffer.isView(this.value)
|
||||||
},
|
},
|
||||||
isNull() {
|
isNull() {
|
||||||
return this.cellValue === null
|
return this.value === null
|
||||||
},
|
},
|
||||||
cellText() {
|
cellText() {
|
||||||
const value = this.cellValue
|
const value = this.value
|
||||||
if (this.isNull) {
|
if (this.isNull) {
|
||||||
return 'NULL'
|
return 'NULL'
|
||||||
}
|
}
|
||||||
@@ -111,17 +126,23 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
currentFormat() {
|
currentFormat: {
|
||||||
this.messages = []
|
immediate: true,
|
||||||
this.formattedJson = ''
|
handler() {
|
||||||
if (this.currentFormat === 'json') {
|
this.messages = []
|
||||||
this.formatJson(this.cellValue)
|
this.formattedJson = ''
|
||||||
|
if (this.currentFormat === 'json') {
|
||||||
|
this.formatJson(this.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
cellValue() {
|
value: {
|
||||||
this.messages = []
|
immediate: true,
|
||||||
if (this.currentFormat === 'json') {
|
handler() {
|
||||||
this.formatJson(this.cellValue)
|
this.messages = []
|
||||||
|
if (this.currentFormat === 'json') {
|
||||||
|
this.formatJson(this.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -141,7 +162,7 @@ export default {
|
|||||||
},
|
},
|
||||||
copyToClipboard() {
|
copyToClipboard() {
|
||||||
cIo.copyText(
|
cIo.copyText(
|
||||||
this.currentFormat === 'json' ? this.formattedJson : this.cellValue,
|
this.currentFormat === 'json' ? this.formattedJson : this.value,
|
||||||
'The value is copied to clipboard.'
|
'The value is copied to clipboard.'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -153,8 +174,10 @@ export default {
|
|||||||
.value-viewer {
|
.value-viewer {
|
||||||
background-color: var(--color-white);
|
background-color: var(--color-white);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
.value-viewer-toolbar {
|
.value-viewer-toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -219,4 +242,14 @@ export default {
|
|||||||
width: 1px;
|
width: 1px;
|
||||||
background: var(--color-text-base);
|
background: var(--color-text-base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.empty-message {
|
||||||
|
position: absolute;
|
||||||
|
top: 40%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
color: var(--color-text-base);
|
||||||
|
font-size: 13px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -127,6 +127,119 @@ export function updateEdges(graph, attributeUpdates) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function reduceNodes(nodeId, nodeData, interactionState, settings) {
|
||||||
|
const {
|
||||||
|
selectedNodeId,
|
||||||
|
hoveredNodeId,
|
||||||
|
selectedEdgeId,
|
||||||
|
hoveredEdgeId,
|
||||||
|
neighborsOfSelectedNode,
|
||||||
|
neighborsOfHoveredNode,
|
||||||
|
selectedEdgeExtremities,
|
||||||
|
hoveredEdgeExtremities
|
||||||
|
} = interactionState
|
||||||
|
|
||||||
|
const res = { ...nodeData }
|
||||||
|
|
||||||
|
if (selectedNodeId || hoveredNodeId || hoveredEdgeId || selectedEdgeId) {
|
||||||
|
res.zIndex = 2
|
||||||
|
res.highlighted = nodeId === selectedNodeId || nodeId === hoveredNodeId
|
||||||
|
|
||||||
|
const isInHoveredFamily =
|
||||||
|
nodeId === hoveredNodeId ||
|
||||||
|
neighborsOfHoveredNode?.has(nodeId) ||
|
||||||
|
hoveredEdgeExtremities.includes(nodeId)
|
||||||
|
const isInSelectedFamily =
|
||||||
|
nodeId === selectedNodeId ||
|
||||||
|
neighborsOfSelectedNode?.has(nodeId) ||
|
||||||
|
selectedEdgeExtremities.includes(nodeId)
|
||||||
|
if (isInSelectedFamily || isInHoveredFamily) {
|
||||||
|
res.forceLabel = true
|
||||||
|
} else {
|
||||||
|
res.color = getDiminishedColor(
|
||||||
|
nodeData.color,
|
||||||
|
settings.style.backgroundColor
|
||||||
|
)
|
||||||
|
res.label = ''
|
||||||
|
res.zIndex = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
export function reduceEdges(
|
||||||
|
edgeId,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
) {
|
||||||
|
const {
|
||||||
|
selectedNodeId,
|
||||||
|
hoveredNodeId,
|
||||||
|
selectedEdgeId,
|
||||||
|
hoveredEdgeId,
|
||||||
|
neighborsOfSelectedNode,
|
||||||
|
neighborsOfHoveredNode
|
||||||
|
} = interactionState
|
||||||
|
|
||||||
|
const res = { ...edgeData }
|
||||||
|
if (hoveredEdgeId || selectedEdgeId || selectedNodeId || hoveredNodeId) {
|
||||||
|
const extremities = graph.extremities(edgeId)
|
||||||
|
res.zIndex = 2
|
||||||
|
const isHighlighted = hoveredEdgeId === edgeId || selectedEdgeId === edgeId
|
||||||
|
|
||||||
|
let isVisible
|
||||||
|
if (settings.style.highlightMode === 'node_alone') {
|
||||||
|
isVisible = isHighlighted
|
||||||
|
} else if (settings.style.highlightMode === 'node_and_neighbors') {
|
||||||
|
isVisible =
|
||||||
|
isHighlighted ||
|
||||||
|
(selectedNodeId && extremities.includes(selectedNodeId)) ||
|
||||||
|
(hoveredNodeId && extremities.includes(hoveredNodeId))
|
||||||
|
} else {
|
||||||
|
isVisible =
|
||||||
|
isHighlighted ||
|
||||||
|
(selectedNodeId &&
|
||||||
|
extremities.every(
|
||||||
|
n => n === selectedNodeId || neighborsOfSelectedNode.has(n)
|
||||||
|
)) ||
|
||||||
|
(hoveredNodeId &&
|
||||||
|
extremities.every(
|
||||||
|
n => n === hoveredNodeId || neighborsOfHoveredNode.has(n)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
if (isHighlighted) {
|
||||||
|
res.size = res.size * 2
|
||||||
|
res.forceLabel = true
|
||||||
|
} else if (!isVisible) {
|
||||||
|
res.color = getDiminishedColor(
|
||||||
|
edgeData.color,
|
||||||
|
settings.style.backgroundColor
|
||||||
|
)
|
||||||
|
res.zIndex = 1
|
||||||
|
res.label = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDiminishedColor(color, bgColor) {
|
||||||
|
const colorObj = tinycolor(color)
|
||||||
|
const colorOpacity = colorObj.getAlpha()
|
||||||
|
colorObj.setAlpha(0.25 * colorOpacity)
|
||||||
|
|
||||||
|
const fg = colorObj.toRgb()
|
||||||
|
const bg = tinycolor(bgColor).toRgb()
|
||||||
|
|
||||||
|
const r = Math.round(fg.r * fg.a + bg.r * (1 - fg.a))
|
||||||
|
const g = Math.round(fg.g * fg.a + bg.g * (1 - fg.a))
|
||||||
|
const b = Math.round(fg.b * fg.a + bg.b * (1 - fg.a))
|
||||||
|
|
||||||
|
return tinycolor({ r, g, b, a: 1 }).toHexString()
|
||||||
|
}
|
||||||
|
|
||||||
function getUpdateLabelMethod(labelSettings) {
|
function getUpdateLabelMethod(labelSettings) {
|
||||||
const { source, color } = labelSettings
|
const { source, color } = labelSettings
|
||||||
return attributes => {
|
return attributes => {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export default {
|
|||||||
inquiries.forEach(inquiry => {
|
inquiries.forEach(inquiry => {
|
||||||
if (inquiry.viewType === 'graph') {
|
if (inquiry.viewType === 'graph') {
|
||||||
inquiry.viewOptions.style.nodes.color.opacity = 100
|
inquiry.viewOptions.style.nodes.color.opacity = 100
|
||||||
|
inquiry.viewOptions.style.highlightMode = 'node_and_neighbors'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ export default {
|
|||||||
// Turn data into array if they are not
|
// Turn data into array if they are not
|
||||||
inquiryList = !Array.isArray(inquiries) ? [inquiries] : inquiries
|
inquiryList = !Array.isArray(inquiries) ? [inquiries] : inquiries
|
||||||
inquiryList = migrate(1, inquiryList)
|
inquiryList = migrate(1, inquiryList)
|
||||||
|
} else if (inquiries.version === 2) {
|
||||||
|
inquiryList = migrate(2, inquiries.inquiries)
|
||||||
} else {
|
} else {
|
||||||
inquiryList = inquiries.inquiries || []
|
inquiryList = inquiries.inquiries || []
|
||||||
}
|
}
|
||||||
@@ -108,6 +110,8 @@ export default {
|
|||||||
|
|
||||||
if (!data.version) {
|
if (!data.version) {
|
||||||
return data.length > 0 ? migrate(1, data) : []
|
return data.length > 0 ? migrate(1, data) : []
|
||||||
|
} else if (data.version === 2) {
|
||||||
|
return migrate(2, data.inquiries)
|
||||||
} else {
|
} else {
|
||||||
return data.inquiries
|
return data.inquiries
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,41 @@ describe('Splitpanes.vue', () => {
|
|||||||
).to.equal('40%')
|
).to.equal('40%')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('renders correctly with hidden panels', async () => {
|
||||||
|
// mount the component
|
||||||
|
const wrapper = shallowMount(Splitpanes, {
|
||||||
|
attachTo: document.body,
|
||||||
|
slots: {
|
||||||
|
leftPane: '<div />',
|
||||||
|
rightPane: '<div />'
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
before: { size: 60, max: 100, hidden: true },
|
||||||
|
after: { size: 40, max: 100 },
|
||||||
|
horizontal: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(wrapper.findAll('.splitpanes-pane')[0].isVisible()).to.equal(false)
|
||||||
|
expect(wrapper.find('.splitpanes-splitter').isVisible()).to.equal(false)
|
||||||
|
expect(
|
||||||
|
wrapper.findAll('.splitpanes-pane')[1].element.style.height
|
||||||
|
).to.equal('100%')
|
||||||
|
|
||||||
|
await wrapper.setProps({
|
||||||
|
before: { size: 60, max: 100 },
|
||||||
|
after: { size: 40, max: 100, hidden: true }
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(wrapper.findAll('.splitpanes-pane')[1].isVisible()).to.equal(false)
|
||||||
|
expect(wrapper.find('.splitpanes-splitter').isVisible()).to.equal(false)
|
||||||
|
expect(
|
||||||
|
wrapper.findAll('.splitpanes-pane')[0].element.style.height
|
||||||
|
).to.equal('100%')
|
||||||
|
|
||||||
|
wrapper.unmount()
|
||||||
|
})
|
||||||
|
|
||||||
it('toggles correctly - no maximized initially', async () => {
|
it('toggles correctly - no maximized initially', async () => {
|
||||||
// mount the component
|
// mount the component
|
||||||
const wrapper = shallowMount(Splitpanes, {
|
const wrapper = shallowMount(Splitpanes, {
|
||||||
|
|||||||
@@ -418,4 +418,52 @@ describe('DataView.vue', () => {
|
|||||||
wrapper.findComponent({ name: 'graph' }).props('initOptions')
|
wrapper.findComponent({ name: 'graph' }).props('initOptions')
|
||||||
).to.eql({ test_options: 'latest_graph_options' })
|
).to.eql({ test_options: 'latest_graph_options' })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('switches visibility of node or edge in graph mode', async () => {
|
||||||
|
const wrapper = mount(DataView, {
|
||||||
|
global: {
|
||||||
|
mocks: { $store },
|
||||||
|
provide: {
|
||||||
|
tabLayout: { dataView: 'above' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// viewNodeOrEdgeBtn is not disaplyed in chart mode
|
||||||
|
expect(
|
||||||
|
wrapper.findComponent({ ref: 'viewNodeOrEdgeBtn' }).exists()
|
||||||
|
).to.equal(false)
|
||||||
|
|
||||||
|
// Switch to pivot
|
||||||
|
const pivotBtn = wrapper.findComponent({ ref: 'pivotBtn' })
|
||||||
|
await pivotBtn.trigger('click')
|
||||||
|
|
||||||
|
// viewNodeOrEdgeBtn is not disaplyed in pivot mode
|
||||||
|
expect(
|
||||||
|
wrapper.findComponent({ ref: 'viewNodeOrEdgeBtn' }).exists()
|
||||||
|
).to.equal(false)
|
||||||
|
|
||||||
|
// Switch to graph
|
||||||
|
const graphBtn = wrapper.findComponent({ ref: 'graphBtn' })
|
||||||
|
await graphBtn.trigger('click')
|
||||||
|
|
||||||
|
// viewNodeOrEdgeBtn is disaplyed in graph mode
|
||||||
|
const viewNodeOrEdgeBtn = wrapper.findComponent({
|
||||||
|
ref: 'viewNodeOrEdgeBtn'
|
||||||
|
})
|
||||||
|
expect(viewNodeOrEdgeBtn.exists()).to.equal(true)
|
||||||
|
|
||||||
|
// by default node viewer is hidden
|
||||||
|
expect(wrapper.findComponent({ name: 'value-viewer' }).exists()).to.equal(
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
// Click to show node viewer
|
||||||
|
await viewNodeOrEdgeBtn.trigger('click')
|
||||||
|
expect(wrapper.findComponent({ name: 'value-viewer' }).exists()).to.equal(
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
wrapper.unmount()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { expect } from 'chai'
|
|||||||
import sinon from 'sinon'
|
import sinon from 'sinon'
|
||||||
import { mount, flushPromises } from '@vue/test-utils'
|
import { mount, flushPromises } from '@vue/test-utils'
|
||||||
import Graph from '@/components/Graph/index.vue'
|
import Graph from '@/components/Graph/index.vue'
|
||||||
|
import { nextTick } from 'vue'
|
||||||
|
|
||||||
function getPixels(canvas) {
|
function getPixels(canvas) {
|
||||||
const context = canvas.getContext('webgl2')
|
const context = canvas.getContext('webgl2')
|
||||||
@@ -163,6 +164,326 @@ describe('Graph.vue', () => {
|
|||||||
wrapper.unmount()
|
wrapper.unmount()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('the graph resizes when node viewer visibillity togglles', async () => {
|
||||||
|
const wrapper = mount(Graph, {
|
||||||
|
attachTo: document.body,
|
||||||
|
props: {
|
||||||
|
dataSources: {
|
||||||
|
doc: [
|
||||||
|
'{"object_type":0,"node_id":"Gryffindor"}',
|
||||||
|
'{"object_type":0,"node_id":"Hufflepuff"}'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
initOptions: {
|
||||||
|
structure: {
|
||||||
|
nodeId: 'node_id',
|
||||||
|
objectType: 'object_type',
|
||||||
|
edgeSource: 'source',
|
||||||
|
edgeTarget: 'target'
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
backgroundColor: 'white',
|
||||||
|
nodes: {
|
||||||
|
size: {
|
||||||
|
type: 'constant',
|
||||||
|
value: 10
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: 'constant',
|
||||||
|
value: '#1F77B4'
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
source: null,
|
||||||
|
color: '#444444'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
edges: {
|
||||||
|
showDirection: true,
|
||||||
|
size: {
|
||||||
|
type: 'constant',
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: 'constant',
|
||||||
|
value: '#a2b1c6'
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
source: null,
|
||||||
|
color: '#a2b1c6'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
layout: {
|
||||||
|
type: 'circular',
|
||||||
|
options: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showValueViewer: false
|
||||||
|
},
|
||||||
|
global: {
|
||||||
|
mocks: { $store },
|
||||||
|
provide: {
|
||||||
|
tabLayout: { dataView: 'above' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const canvas = wrapper.find('canvas.sigma-nodes').wrapperElement
|
||||||
|
const initialCanvasWidth = canvas.scrollWidth
|
||||||
|
|
||||||
|
await wrapper.setProps({ showValueViewer: true })
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(canvas.scrollWidth).not.to.equal(initialCanvasWidth)
|
||||||
|
|
||||||
|
await wrapper.setProps({ showValueViewer: false })
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(canvas.scrollWidth).to.equal(initialCanvasWidth)
|
||||||
|
|
||||||
|
wrapper.unmount()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('the graph resizes when the split pane resizes', async () => {
|
||||||
|
const wrapper = mount(Graph, {
|
||||||
|
attachTo: document.body,
|
||||||
|
props: {
|
||||||
|
dataSources: {
|
||||||
|
doc: [
|
||||||
|
'{"object_type":0,"node_id":"Gryffindor"}',
|
||||||
|
'{"object_type":0,"node_id":"Hufflepuff"}'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
initOptions: {
|
||||||
|
structure: {
|
||||||
|
nodeId: 'node_id',
|
||||||
|
objectType: 'object_type',
|
||||||
|
edgeSource: 'source',
|
||||||
|
edgeTarget: 'target'
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
backgroundColor: 'white',
|
||||||
|
nodes: {
|
||||||
|
size: {
|
||||||
|
type: 'constant',
|
||||||
|
value: 10
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: 'constant',
|
||||||
|
value: '#1F77B4'
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
source: null,
|
||||||
|
color: '#444444'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
edges: {
|
||||||
|
showDirection: true,
|
||||||
|
size: {
|
||||||
|
type: 'constant',
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: 'constant',
|
||||||
|
value: '#a2b1c6'
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
source: null,
|
||||||
|
color: '#a2b1c6'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
layout: {
|
||||||
|
type: 'circular',
|
||||||
|
options: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showValueViewer: true
|
||||||
|
},
|
||||||
|
global: {
|
||||||
|
mocks: { $store },
|
||||||
|
provide: {
|
||||||
|
tabLayout: { dataView: 'above' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const container =
|
||||||
|
wrapper.find('.graph-container').wrapperElement.parentElement
|
||||||
|
const canvas = wrapper.find('canvas.sigma-nodes').wrapperElement
|
||||||
|
|
||||||
|
const initialContainerWidth = container.scrollWidth
|
||||||
|
const initialCanvasWidth = canvas.scrollWidth
|
||||||
|
await wrapper.find('.splitpanes-splitter').trigger('mousedown')
|
||||||
|
document.dispatchEvent(
|
||||||
|
new MouseEvent('mousemove', {
|
||||||
|
clientX: initialContainerWidth / 2,
|
||||||
|
clientY: 80
|
||||||
|
})
|
||||||
|
)
|
||||||
|
document.dispatchEvent(new MouseEvent('mouseup'))
|
||||||
|
await nextTick()
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(canvas.scrollWidth).not.to.equal(initialCanvasWidth)
|
||||||
|
|
||||||
|
wrapper.unmount()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('opens and closes node viewer', async () => {
|
||||||
|
const wrapper = mount(Graph, {
|
||||||
|
props: {
|
||||||
|
dataSources: {
|
||||||
|
doc: [
|
||||||
|
'{"object_type":0,"node_id":"Gryffindor"}',
|
||||||
|
'{"object_type":0,"node_id":"Hufflepuff"}'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
initOptions: {
|
||||||
|
structure: {
|
||||||
|
nodeId: 'node_id',
|
||||||
|
objectType: 'object_type',
|
||||||
|
edgeSource: 'source',
|
||||||
|
edgeTarget: 'target'
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
backgroundColor: 'white',
|
||||||
|
nodes: {
|
||||||
|
size: {
|
||||||
|
type: 'constant',
|
||||||
|
value: 10
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: 'constant',
|
||||||
|
value: '#1F77B4'
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
source: null,
|
||||||
|
color: '#444444'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
edges: {
|
||||||
|
showDirection: true,
|
||||||
|
size: {
|
||||||
|
type: 'constant',
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: 'constant',
|
||||||
|
value: '#a2b1c6'
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
source: null,
|
||||||
|
color: '#a2b1c6'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
layout: {
|
||||||
|
type: 'circular',
|
||||||
|
options: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showValueViewer: false
|
||||||
|
},
|
||||||
|
global: {
|
||||||
|
mocks: { $store },
|
||||||
|
provide: {
|
||||||
|
tabLayout: { dataView: 'above' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(wrapper.text()).not.contain('No node or edge selected to view')
|
||||||
|
await wrapper.setProps({ showValueViewer: true })
|
||||||
|
expect(wrapper.text()).contains('No node or edge selected to view')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('passes selected item to node viewer', async () => {
|
||||||
|
const wrapper = mount(Graph, {
|
||||||
|
attachTo: document.body,
|
||||||
|
props: {
|
||||||
|
dataSources: {
|
||||||
|
doc: [
|
||||||
|
'{"object_type":0,"node_id":"Gryffindor"}',
|
||||||
|
'{"object_type":0,"node_id":"Hufflepuff"}'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
initOptions: {
|
||||||
|
structure: {
|
||||||
|
nodeId: 'node_id',
|
||||||
|
objectType: 'object_type',
|
||||||
|
edgeSource: 'source',
|
||||||
|
edgeTarget: 'target'
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
backgroundColor: 'white',
|
||||||
|
nodes: {
|
||||||
|
size: {
|
||||||
|
type: 'constant',
|
||||||
|
value: 10
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: 'constant',
|
||||||
|
value: '#1F77B4'
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
source: null,
|
||||||
|
color: '#444444'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
edges: {
|
||||||
|
showDirection: true,
|
||||||
|
size: {
|
||||||
|
type: 'constant',
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: 'constant',
|
||||||
|
value: '#a2b1c6'
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
source: null,
|
||||||
|
color: '#a2b1c6'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
layout: {
|
||||||
|
type: 'circular',
|
||||||
|
options: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showValueViewer: true
|
||||||
|
},
|
||||||
|
global: {
|
||||||
|
mocks: { $store },
|
||||||
|
provide: {
|
||||||
|
tabLayout: { dataView: 'above' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(wrapper.find('.value-viewer .value-body').exists()).to.equal(false)
|
||||||
|
await wrapper
|
||||||
|
.findComponent({ ref: 'graphEditor' })
|
||||||
|
.vm.$emit('selectItem', { object_type: 0, node_id: 'Gryffindor' })
|
||||||
|
|
||||||
|
expect(wrapper.find('.value-viewer .value-body').text()).contains(
|
||||||
|
'"object_type": 0,'
|
||||||
|
)
|
||||||
|
expect(wrapper.find('.value-viewer .value-body').text()).contains(
|
||||||
|
'"node_id": "Gryffindor"'
|
||||||
|
)
|
||||||
|
|
||||||
|
await wrapper
|
||||||
|
.findComponent({ ref: 'graphEditor' })
|
||||||
|
.vm.$emit('clearSelection')
|
||||||
|
expect(wrapper.find('.value-viewer .value-body').exists()).to.equal(false)
|
||||||
|
|
||||||
|
wrapper.unmount()
|
||||||
|
})
|
||||||
|
|
||||||
it('nodes and edges are rendered', async () => {
|
it('nodes and edges are rendered', async () => {
|
||||||
const wrapper = mount(Graph, {
|
const wrapper = mount(Graph, {
|
||||||
attachTo: document.body,
|
attachTo: document.body,
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ describe('RunResult.vue', () => {
|
|||||||
sinon.spy(window, 'alert')
|
sinon.spy(window, 'alert')
|
||||||
const wrapper = mount(RunResult, {
|
const wrapper = mount(RunResult, {
|
||||||
props: {
|
props: {
|
||||||
tab: { id: 1 },
|
|
||||||
result: {
|
result: {
|
||||||
columns: ['id', 'name'],
|
columns: ['id', 'name'],
|
||||||
values: {
|
values: {
|
||||||
@@ -54,7 +53,6 @@ describe('RunResult.vue', () => {
|
|||||||
const wrapper = mount(RunResult, {
|
const wrapper = mount(RunResult, {
|
||||||
attachTo: document.body,
|
attachTo: document.body,
|
||||||
props: {
|
props: {
|
||||||
tab: { id: 1 },
|
|
||||||
result: {
|
result: {
|
||||||
columns: ['id', 'name'],
|
columns: ['id', 'name'],
|
||||||
values: {
|
values: {
|
||||||
@@ -114,7 +112,6 @@ describe('RunResult.vue', () => {
|
|||||||
const wrapper = mount(RunResult, {
|
const wrapper = mount(RunResult, {
|
||||||
attachTo: document.body,
|
attachTo: document.body,
|
||||||
props: {
|
props: {
|
||||||
tab: { id: 1 },
|
|
||||||
result: {
|
result: {
|
||||||
columns: ['id', 'name'],
|
columns: ['id', 'name'],
|
||||||
values: {
|
values: {
|
||||||
@@ -154,7 +151,6 @@ describe('RunResult.vue', () => {
|
|||||||
const wrapper = mount(RunResult, {
|
const wrapper = mount(RunResult, {
|
||||||
attachTo: document.body,
|
attachTo: document.body,
|
||||||
props: {
|
props: {
|
||||||
tab: { id: 1 },
|
|
||||||
result: {
|
result: {
|
||||||
columns: ['id', 'name'],
|
columns: ['id', 'name'],
|
||||||
values: {
|
values: {
|
||||||
@@ -196,7 +192,6 @@ describe('RunResult.vue', () => {
|
|||||||
it('shows value of selected cell - result set', async () => {
|
it('shows value of selected cell - result set', async () => {
|
||||||
const wrapper = mount(RunResult, {
|
const wrapper = mount(RunResult, {
|
||||||
props: {
|
props: {
|
||||||
tab: { id: 1 },
|
|
||||||
result: {
|
result: {
|
||||||
columns: ['id', 'name'],
|
columns: ['id', 'name'],
|
||||||
values: {
|
values: {
|
||||||
@@ -250,9 +245,9 @@ describe('RunResult.vue', () => {
|
|||||||
|
|
||||||
// Click on 'bar' cell again
|
// Click on 'bar' cell again
|
||||||
await rows[1].findAll('td')[1].trigger('click')
|
await rows[1].findAll('td')[1].trigger('click')
|
||||||
expect(
|
expect(wrapper.find('.value-viewer').text()).to.equals(
|
||||||
wrapper.find('.value-viewer-container .table-preview').text()
|
'No cell selected to view'
|
||||||
).to.equals('No cell selected to view')
|
)
|
||||||
wrapper.unmount()
|
wrapper.unmount()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -260,7 +255,6 @@ describe('RunResult.vue', () => {
|
|||||||
const wrapper = mount(RunResult, {
|
const wrapper = mount(RunResult, {
|
||||||
attachTo: document.body,
|
attachTo: document.body,
|
||||||
props: {
|
props: {
|
||||||
tab: { id: 1 },
|
|
||||||
result: {
|
result: {
|
||||||
columns: ['id', 'name'],
|
columns: ['id', 'name'],
|
||||||
values: {
|
values: {
|
||||||
@@ -323,9 +317,9 @@ describe('RunResult.vue', () => {
|
|||||||
|
|
||||||
// Click on 'foo' cell again
|
// Click on 'foo' cell again
|
||||||
await rows[1].find('td').trigger('click')
|
await rows[1].find('td').trigger('click')
|
||||||
expect(
|
expect(wrapper.find('.value-viewer').text()).to.equals(
|
||||||
wrapper.find('.value-viewer-container .table-preview').text()
|
'No cell selected to view'
|
||||||
).to.equals('No cell selected to view')
|
)
|
||||||
wrapper.unmount()
|
wrapper.unmount()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -333,7 +327,6 @@ describe('RunResult.vue', () => {
|
|||||||
const wrapper = mount(RunResult, {
|
const wrapper = mount(RunResult, {
|
||||||
attachTo: document.body,
|
attachTo: document.body,
|
||||||
props: {
|
props: {
|
||||||
tab: { id: 1 },
|
|
||||||
result: {
|
result: {
|
||||||
columns: ['id', 'name'],
|
columns: ['id', 'name'],
|
||||||
values: {
|
values: {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import ValueViewer from '@/components/RunResult/ValueViewer.vue'
|
import ValueViewer from '@/components/ValueViewer.vue'
|
||||||
import sinon from 'sinon'
|
import sinon from 'sinon'
|
||||||
|
|
||||||
describe('ValueViewer.vue', () => {
|
describe('ValueViewer.vue', () => {
|
||||||
@@ -11,28 +11,45 @@ describe('ValueViewer.vue', () => {
|
|||||||
it('shows value in text mode', () => {
|
it('shows value in text mode', () => {
|
||||||
const wrapper = mount(ValueViewer, {
|
const wrapper = mount(ValueViewer, {
|
||||||
props: {
|
props: {
|
||||||
cellValue: 'foo'
|
value: 'foo'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(wrapper.find('.value-body').text()).to.equals('foo')
|
expect(wrapper.find('.value-body').text()).to.equals('foo')
|
||||||
|
expect(wrapper.find('button.text').attributes('aria-selected')).to.equal(
|
||||||
|
'true'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows meta values', async () => {
|
||||||
|
const wrapper = mount(ValueViewer, {
|
||||||
|
props: {
|
||||||
|
value: new Uint8Array()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(wrapper.find('.value-body').text()).to.equals('BLOB')
|
||||||
|
|
||||||
|
await wrapper.setProps({ value: null })
|
||||||
|
expect(wrapper.find('.value-body').text()).to.equals('NULL')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('shows error in json mode if the value is not json', async () => {
|
it('shows error in json mode if the value is not json', async () => {
|
||||||
const wrapper = mount(ValueViewer, {
|
const wrapper = mount(ValueViewer, {
|
||||||
props: {
|
props: {
|
||||||
cellValue: 'foo'
|
value: 'foo',
|
||||||
|
defaultFormat: 'json'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
await wrapper.find('button.json').trigger('click')
|
|
||||||
expect(wrapper.find('.value-body').text()).to.equals("Can't parse JSON.")
|
expect(wrapper.find('.value-body').text()).to.equals("Can't parse JSON.")
|
||||||
|
expect(wrapper.find('button[aria-selected="true"]').text()).contains('JSON')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('copy to clipboard', async () => {
|
it('copy to clipboard', async () => {
|
||||||
sinon.stub(window.navigator.clipboard, 'writeText').resolves()
|
sinon.stub(window.navigator.clipboard, 'writeText').resolves()
|
||||||
const wrapper = mount(ValueViewer, {
|
const wrapper = mount(ValueViewer, {
|
||||||
props: {
|
props: {
|
||||||
cellValue: 'foo'
|
value: 'foo'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -41,13 +58,20 @@ describe('ValueViewer.vue', () => {
|
|||||||
expect(window.navigator.clipboard.writeText.calledOnceWith('foo')).to.equal(
|
expect(window.navigator.clipboard.writeText.calledOnceWith('foo')).to.equal(
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
await wrapper.setProps({ value: '{"foo": "bar"}' })
|
||||||
|
await wrapper.find('button.json').trigger('click')
|
||||||
|
await wrapper.find('button.copy').trigger('click')
|
||||||
|
expect(window.navigator.clipboard.writeText.args[1][0]).to.equal(
|
||||||
|
'{\n "foo": "bar"\n}'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('wraps lines', async () => {
|
it('wraps lines', async () => {
|
||||||
const wrapper = mount(ValueViewer, {
|
const wrapper = mount(ValueViewer, {
|
||||||
attachTo: document.body,
|
attachTo: document.body,
|
||||||
props: {
|
props: {
|
||||||
cellValue: 'foo'
|
value: 'foo'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -55,7 +79,7 @@ describe('ValueViewer.vue', () => {
|
|||||||
const valueBody = wrapper.find('.value-body').wrapperElement
|
const valueBody = wrapper.find('.value-body').wrapperElement
|
||||||
expect(valueBody.scrollWidth).to.equal(valueBody.clientWidth)
|
expect(valueBody.scrollWidth).to.equal(valueBody.clientWidth)
|
||||||
|
|
||||||
await wrapper.setProps({ cellValue: 'foo'.repeat(100) })
|
await wrapper.setProps({ value: 'foo'.repeat(100) })
|
||||||
expect(valueBody.scrollWidth).not.to.equal(valueBody.clientWidth)
|
expect(valueBody.scrollWidth).not.to.equal(valueBody.clientWidth)
|
||||||
|
|
||||||
await wrapper.find('button.line-wrap').trigger('click')
|
await wrapper.find('button.line-wrap').trigger('click')
|
||||||
@@ -67,7 +91,7 @@ describe('ValueViewer.vue', () => {
|
|||||||
const wrapper = mount(ValueViewer, {
|
const wrapper = mount(ValueViewer, {
|
||||||
attachTo: document.body,
|
attachTo: document.body,
|
||||||
props: {
|
props: {
|
||||||
cellValue: '{"foo": "foofoofoofoofoofoofoofoofoofoo"}'
|
value: '{"foo": "foofoofoofoofoofoofoofoofoofoo"}'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -83,4 +107,15 @@ describe('ValueViewer.vue', () => {
|
|||||||
expect(codeMirrorScroll.scrollWidth).to.equal(codeMirrorScroll.clientWidth)
|
expect(codeMirrorScroll.scrollWidth).to.equal(codeMirrorScroll.clientWidth)
|
||||||
wrapper.unmount()
|
wrapper.unmount()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('shows empty message if empty is true', () => {
|
||||||
|
const wrapper = mount(ValueViewer, {
|
||||||
|
props: {
|
||||||
|
empty: true,
|
||||||
|
emptyMessage: 'I am empty'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(wrapper.find('.value-viewer').text()).to.equals('I am empty')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
@@ -1215,4 +1215,982 @@ describe('graphHelper.js', () => {
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('getDiminishedColor', () => {
|
||||||
|
const diminishedColor = graphHelper.getDiminishedColor(
|
||||||
|
'#FF0000CC',
|
||||||
|
'#0000FF'
|
||||||
|
)
|
||||||
|
expect(diminishedColor).to.equal('#3300cc')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('reduceNodes', () => {
|
||||||
|
const settings = {
|
||||||
|
style: {
|
||||||
|
backgroundColor: '#0000FF'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const nodeData = { color: '#FF0000CC', label: 'Node label' }
|
||||||
|
|
||||||
|
let interactionState = {
|
||||||
|
selectedNodeId: 'node-1',
|
||||||
|
hoveredNodeId: 'node-2',
|
||||||
|
selectedEdgeId: null,
|
||||||
|
hoveredEdgeId: null,
|
||||||
|
neighborsOfSelectedNode: new Set(['node-1.1']),
|
||||||
|
neighborsOfHoveredNode: new Set(['node-2.1']),
|
||||||
|
selectedEdgeExtremities: [],
|
||||||
|
hoveredEdgeExtremities: []
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-1', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label',
|
||||||
|
zIndex: 2,
|
||||||
|
highlighted: true,
|
||||||
|
forceLabel: true
|
||||||
|
})
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-2', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label',
|
||||||
|
zIndex: 2,
|
||||||
|
highlighted: true,
|
||||||
|
forceLabel: true
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-1.1', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label',
|
||||||
|
zIndex: 2,
|
||||||
|
highlighted: false,
|
||||||
|
forceLabel: true
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-2.1', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label',
|
||||||
|
zIndex: 2,
|
||||||
|
highlighted: false,
|
||||||
|
forceLabel: true
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-3', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#3300cc',
|
||||||
|
label: '',
|
||||||
|
zIndex: 1,
|
||||||
|
highlighted: false
|
||||||
|
})
|
||||||
|
|
||||||
|
interactionState = {
|
||||||
|
selectedNodeId: 'node-1',
|
||||||
|
hoveredNodeId: null,
|
||||||
|
selectedEdgeId: null,
|
||||||
|
hoveredEdgeId: 'edge-2-2.1',
|
||||||
|
neighborsOfSelectedNode: new Set(['node-1.1']),
|
||||||
|
neighborsOfHoveredNode: undefined,
|
||||||
|
selectedEdgeExtremities: [],
|
||||||
|
hoveredEdgeExtremities: ['node-2', 'node-2.1']
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-1', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label',
|
||||||
|
zIndex: 2,
|
||||||
|
highlighted: true,
|
||||||
|
forceLabel: true
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-2', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label',
|
||||||
|
zIndex: 2,
|
||||||
|
highlighted: false,
|
||||||
|
forceLabel: true
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-1.1', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label',
|
||||||
|
zIndex: 2,
|
||||||
|
highlighted: false,
|
||||||
|
forceLabel: true
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-1.1', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label',
|
||||||
|
zIndex: 2,
|
||||||
|
highlighted: false,
|
||||||
|
forceLabel: true
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-3', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#3300cc',
|
||||||
|
label: '',
|
||||||
|
zIndex: 1,
|
||||||
|
highlighted: false
|
||||||
|
})
|
||||||
|
|
||||||
|
interactionState = {
|
||||||
|
selectedNodeId: null,
|
||||||
|
hoveredNodeId: null,
|
||||||
|
selectedEdgeId: 'edge-1-1.1',
|
||||||
|
hoveredEdgeId: 'edge-2-2.1',
|
||||||
|
neighborsOfSelectedNode: undefined,
|
||||||
|
neighborsOfHoveredNode: undefined,
|
||||||
|
selectedEdgeExtremities: ['node-1', 'node-1.1'],
|
||||||
|
hoveredEdgeExtremities: ['node-2', 'node-2.1']
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-1', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label',
|
||||||
|
zIndex: 2,
|
||||||
|
highlighted: false,
|
||||||
|
forceLabel: true
|
||||||
|
})
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-2', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label',
|
||||||
|
zIndex: 2,
|
||||||
|
highlighted: false,
|
||||||
|
forceLabel: true
|
||||||
|
})
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-1.1', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label',
|
||||||
|
zIndex: 2,
|
||||||
|
highlighted: false,
|
||||||
|
forceLabel: true
|
||||||
|
})
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-2.1', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label',
|
||||||
|
zIndex: 2,
|
||||||
|
highlighted: false,
|
||||||
|
forceLabel: true
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-3', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#3300cc',
|
||||||
|
label: '',
|
||||||
|
zIndex: 1,
|
||||||
|
highlighted: false
|
||||||
|
})
|
||||||
|
|
||||||
|
interactionState = {
|
||||||
|
selectedNodeId: null,
|
||||||
|
hoveredNodeId: 'node-2',
|
||||||
|
selectedEdgeId: 'edge-1',
|
||||||
|
hoveredEdgeId: null,
|
||||||
|
neighborsOfSelectedNode: undefined,
|
||||||
|
neighborsOfHoveredNode: new Set(['node-2.1']),
|
||||||
|
selectedEdgeExtremities: ['node-1', 'node-1.1'],
|
||||||
|
hoveredEdgeExtremities: []
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-1', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label',
|
||||||
|
zIndex: 2,
|
||||||
|
highlighted: false,
|
||||||
|
forceLabel: true
|
||||||
|
})
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-2', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label',
|
||||||
|
zIndex: 2,
|
||||||
|
highlighted: true,
|
||||||
|
forceLabel: true
|
||||||
|
})
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-1.1', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label',
|
||||||
|
zIndex: 2,
|
||||||
|
highlighted: false,
|
||||||
|
forceLabel: true
|
||||||
|
})
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-2.1', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label',
|
||||||
|
zIndex: 2,
|
||||||
|
highlighted: false,
|
||||||
|
forceLabel: true
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-3', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#3300cc',
|
||||||
|
label: '',
|
||||||
|
zIndex: 1,
|
||||||
|
highlighted: false
|
||||||
|
})
|
||||||
|
|
||||||
|
interactionState = {
|
||||||
|
selectedNodeId: null,
|
||||||
|
hoveredNodeId: null,
|
||||||
|
selectedEdgeId: null,
|
||||||
|
hoveredEdgeId: null,
|
||||||
|
neighborsOfSelectedNode: undefined,
|
||||||
|
neighborsOfHoveredNode: undefined,
|
||||||
|
selectedEdgeExtremities: [],
|
||||||
|
hoveredEdgeExtremities: []
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-1', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label'
|
||||||
|
})
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-2', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label'
|
||||||
|
})
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-1.1', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label'
|
||||||
|
})
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-2.1', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label'
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceNodes('node-3', nodeData, interactionState, settings)
|
||||||
|
).to.eql({
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Node label'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('reduceEdges - node_alone', () => {
|
||||||
|
const settings = {
|
||||||
|
style: {
|
||||||
|
backgroundColor: '#0000FF',
|
||||||
|
highlightMode: 'node_alone'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const edgeData = { color: '#FF0000CC', label: 'Edge label', size: 3 }
|
||||||
|
const graph = new Graph()
|
||||||
|
graph.addNode('node-1.1')
|
||||||
|
graph.addNode('node-1.2')
|
||||||
|
graph.addNode('node-1.3')
|
||||||
|
graph.addNode('node-2.1')
|
||||||
|
graph.addNode('node-2.2')
|
||||||
|
const edge1112 = graph.addEdge('node-1.1', 'node-1.2', edgeData)
|
||||||
|
const edge1113 = graph.addEdge('node-1.1', 'node-1.3', edgeData)
|
||||||
|
const edge1213 = graph.addEdge('node-1.2', 'node-1.3', edgeData)
|
||||||
|
const edge2122 = graph.addEdge('node-2.1', 'node-2.2', edgeData)
|
||||||
|
|
||||||
|
const hiddenEdgeStyle = { color: '#3300cc', label: '', zIndex: 1, size: 3 }
|
||||||
|
const highlightedEdgeStyle = {
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Edge label',
|
||||||
|
zIndex: 2,
|
||||||
|
size: 6,
|
||||||
|
forceLabel: true
|
||||||
|
}
|
||||||
|
|
||||||
|
let interactionState = {
|
||||||
|
selectedNodeId: null,
|
||||||
|
hoveredNodeId: null,
|
||||||
|
selectedEdgeId: edge2122,
|
||||||
|
hoveredEdgeId: edge1112,
|
||||||
|
neighborsOfSelectedNode: undefined,
|
||||||
|
neighborsOfHoveredNode: undefined,
|
||||||
|
selectedEdgeExtremities: ['node-2.1', 'node-2.2'],
|
||||||
|
hoveredEdgeExtremities: ['node-1.1', 'node-1.2']
|
||||||
|
}
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge2122,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(highlightedEdgeStyle)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1112,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(highlightedEdgeStyle)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1113,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1213,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
|
||||||
|
interactionState = {
|
||||||
|
selectedNodeId: 'node-1.1',
|
||||||
|
hoveredNodeId: null,
|
||||||
|
selectedEdgeId: null,
|
||||||
|
hoveredEdgeId: null,
|
||||||
|
neighborsOfSelectedNode: new Set(['node-1.2', 'node-1.3']),
|
||||||
|
neighborsOfHoveredNode: undefined,
|
||||||
|
selectedEdgeExtremities: [],
|
||||||
|
hoveredEdgeExtremities: []
|
||||||
|
}
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge2122,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1112,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1113,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1213,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
|
||||||
|
interactionState = {
|
||||||
|
selectedNodeId: null,
|
||||||
|
hoveredNodeId: 'node-1.1',
|
||||||
|
selectedEdgeId: null,
|
||||||
|
hoveredEdgeId: null,
|
||||||
|
neighborsOfSelectedNode: undefined,
|
||||||
|
neighborsOfHoveredNode: new Set(['node-1.2', 'node-1.3']),
|
||||||
|
selectedEdgeExtremities: [],
|
||||||
|
hoveredEdgeExtremities: []
|
||||||
|
}
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge2122,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1112,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1113,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1213,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
|
||||||
|
interactionState = {
|
||||||
|
selectedNodeId: null,
|
||||||
|
hoveredNodeId: null,
|
||||||
|
selectedEdgeId: null,
|
||||||
|
hoveredEdgeId: null,
|
||||||
|
neighborsOfSelectedNode: undefined,
|
||||||
|
neighborsOfHoveredNode: undefined,
|
||||||
|
selectedEdgeExtremities: [],
|
||||||
|
hoveredEdgeExtremities: []
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge2122,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(edgeData)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1112,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(edgeData)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1113,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(edgeData)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1213,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(edgeData)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('reduceEdges - node_and_neighbors', () => {
|
||||||
|
const settings = {
|
||||||
|
style: {
|
||||||
|
backgroundColor: '#0000FF',
|
||||||
|
highlightMode: 'node_and_neighbors'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const edgeData = { color: '#FF0000CC', label: 'Edge label', size: 3 }
|
||||||
|
const graph = new Graph()
|
||||||
|
graph.addNode('node-1.1')
|
||||||
|
graph.addNode('node-1.2')
|
||||||
|
graph.addNode('node-1.3')
|
||||||
|
graph.addNode('node-2.1')
|
||||||
|
graph.addNode('node-2.2')
|
||||||
|
const edge1112 = graph.addEdge('node-1.1', 'node-1.2', edgeData)
|
||||||
|
const edge1113 = graph.addEdge('node-1.1', 'node-1.3', edgeData)
|
||||||
|
const edge1213 = graph.addEdge('node-1.2', 'node-1.3', edgeData)
|
||||||
|
const edge2122 = graph.addEdge('node-2.1', 'node-2.2', edgeData)
|
||||||
|
|
||||||
|
const hiddenEdgeStyle = { color: '#3300cc', label: '', zIndex: 1, size: 3 }
|
||||||
|
const highlightedEdgeStyle = {
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Edge label',
|
||||||
|
zIndex: 2,
|
||||||
|
size: 6,
|
||||||
|
forceLabel: true
|
||||||
|
}
|
||||||
|
const visibleEdgeStyle = {
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Edge label',
|
||||||
|
zIndex: 2,
|
||||||
|
size: 3
|
||||||
|
}
|
||||||
|
|
||||||
|
let interactionState = {
|
||||||
|
selectedNodeId: null,
|
||||||
|
hoveredNodeId: null,
|
||||||
|
selectedEdgeId: edge2122,
|
||||||
|
hoveredEdgeId: edge1112,
|
||||||
|
neighborsOfSelectedNode: undefined,
|
||||||
|
neighborsOfHoveredNode: undefined,
|
||||||
|
selectedEdgeExtremities: ['node-2.1', 'node-2.2'],
|
||||||
|
hoveredEdgeExtremities: ['node-1.1', 'node-1.2']
|
||||||
|
}
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge2122,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(highlightedEdgeStyle)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1112,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(highlightedEdgeStyle)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1113,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1213,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
|
||||||
|
interactionState = {
|
||||||
|
selectedNodeId: 'node-1.1',
|
||||||
|
hoveredNodeId: null,
|
||||||
|
selectedEdgeId: null,
|
||||||
|
hoveredEdgeId: null,
|
||||||
|
neighborsOfSelectedNode: new Set(['node-1.2', 'node-1.3']),
|
||||||
|
neighborsOfHoveredNode: undefined,
|
||||||
|
selectedEdgeExtremities: [],
|
||||||
|
hoveredEdgeExtremities: []
|
||||||
|
}
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge2122,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1112,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(visibleEdgeStyle)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1113,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(visibleEdgeStyle)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1213,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
|
||||||
|
interactionState = {
|
||||||
|
selectedNodeId: null,
|
||||||
|
hoveredNodeId: 'node-1.1',
|
||||||
|
selectedEdgeId: null,
|
||||||
|
hoveredEdgeId: null,
|
||||||
|
neighborsOfSelectedNode: undefined,
|
||||||
|
neighborsOfHoveredNode: new Set(['node-1.2', 'node-1.3']),
|
||||||
|
selectedEdgeExtremities: [],
|
||||||
|
hoveredEdgeExtremities: []
|
||||||
|
}
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge2122,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1112,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(visibleEdgeStyle)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1113,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(visibleEdgeStyle)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1213,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
|
||||||
|
interactionState = {
|
||||||
|
selectedNodeId: null,
|
||||||
|
hoveredNodeId: null,
|
||||||
|
selectedEdgeId: null,
|
||||||
|
hoveredEdgeId: null,
|
||||||
|
neighborsOfSelectedNode: undefined,
|
||||||
|
neighborsOfHoveredNode: undefined,
|
||||||
|
selectedEdgeExtremities: [],
|
||||||
|
hoveredEdgeExtremities: []
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge2122,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(edgeData)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1112,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(edgeData)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1113,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(edgeData)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1213,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(edgeData)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('reduceEdges - include_neighbor_edges', () => {
|
||||||
|
const settings = {
|
||||||
|
style: {
|
||||||
|
backgroundColor: '#0000FF',
|
||||||
|
highlightMode: 'include_neighbor_edges'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const edgeData = { color: '#FF0000CC', label: 'Edge label', size: 3 }
|
||||||
|
const graph = new Graph()
|
||||||
|
graph.addNode('node-1.1')
|
||||||
|
graph.addNode('node-1.2')
|
||||||
|
graph.addNode('node-1.3')
|
||||||
|
graph.addNode('node-2.1')
|
||||||
|
graph.addNode('node-2.2')
|
||||||
|
const edge1112 = graph.addEdge('node-1.1', 'node-1.2', edgeData)
|
||||||
|
const edge1113 = graph.addEdge('node-1.1', 'node-1.3', edgeData)
|
||||||
|
const edge1213 = graph.addEdge('node-1.2', 'node-1.3', edgeData)
|
||||||
|
const edge2122 = graph.addEdge('node-2.1', 'node-2.2', edgeData)
|
||||||
|
|
||||||
|
const hiddenEdgeStyle = { color: '#3300cc', label: '', zIndex: 1, size: 3 }
|
||||||
|
const highlightedEdgeStyle = {
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Edge label',
|
||||||
|
zIndex: 2,
|
||||||
|
size: 6,
|
||||||
|
forceLabel: true
|
||||||
|
}
|
||||||
|
const visibleEdgeStyle = {
|
||||||
|
color: '#FF0000CC',
|
||||||
|
label: 'Edge label',
|
||||||
|
zIndex: 2,
|
||||||
|
size: 3
|
||||||
|
}
|
||||||
|
|
||||||
|
let interactionState = {
|
||||||
|
selectedNodeId: null,
|
||||||
|
hoveredNodeId: null,
|
||||||
|
selectedEdgeId: edge2122,
|
||||||
|
hoveredEdgeId: edge1112,
|
||||||
|
neighborsOfSelectedNode: undefined,
|
||||||
|
neighborsOfHoveredNode: undefined,
|
||||||
|
selectedEdgeExtremities: ['node-2.1', 'node-2.2'],
|
||||||
|
hoveredEdgeExtremities: ['node-1.1', 'node-1.2']
|
||||||
|
}
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge2122,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(highlightedEdgeStyle)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1112,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(highlightedEdgeStyle)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1113,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1213,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
|
||||||
|
interactionState = {
|
||||||
|
selectedNodeId: 'node-1.1',
|
||||||
|
hoveredNodeId: null,
|
||||||
|
selectedEdgeId: null,
|
||||||
|
hoveredEdgeId: null,
|
||||||
|
neighborsOfSelectedNode: new Set(['node-1.2', 'node-1.3']),
|
||||||
|
neighborsOfHoveredNode: undefined,
|
||||||
|
selectedEdgeExtremities: [],
|
||||||
|
hoveredEdgeExtremities: []
|
||||||
|
}
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge2122,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1112,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(visibleEdgeStyle)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1113,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(visibleEdgeStyle)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1213,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(visibleEdgeStyle)
|
||||||
|
|
||||||
|
interactionState = {
|
||||||
|
selectedNodeId: null,
|
||||||
|
hoveredNodeId: 'node-1.1',
|
||||||
|
selectedEdgeId: null,
|
||||||
|
hoveredEdgeId: null,
|
||||||
|
neighborsOfSelectedNode: undefined,
|
||||||
|
neighborsOfHoveredNode: new Set(['node-1.2', 'node-1.3']),
|
||||||
|
selectedEdgeExtremities: [],
|
||||||
|
hoveredEdgeExtremities: []
|
||||||
|
}
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge2122,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(hiddenEdgeStyle)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1112,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(visibleEdgeStyle)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1113,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(visibleEdgeStyle)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1213,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(visibleEdgeStyle)
|
||||||
|
|
||||||
|
interactionState = {
|
||||||
|
selectedNodeId: null,
|
||||||
|
hoveredNodeId: null,
|
||||||
|
selectedEdgeId: null,
|
||||||
|
hoveredEdgeId: null,
|
||||||
|
neighborsOfSelectedNode: undefined,
|
||||||
|
neighborsOfHoveredNode: undefined,
|
||||||
|
selectedEdgeExtremities: [],
|
||||||
|
hoveredEdgeExtremities: []
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge2122,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(edgeData)
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1112,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(edgeData)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1113,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(edgeData)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
graphHelper.reduceEdges(
|
||||||
|
edge1213,
|
||||||
|
edgeData,
|
||||||
|
interactionState,
|
||||||
|
settings,
|
||||||
|
graph
|
||||||
|
)
|
||||||
|
).to.eql(edgeData)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -39,4 +39,101 @@ describe('_migrations.js', () => {
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('migrates from version 2 to the current', () => {
|
||||||
|
const oldInquiries = [
|
||||||
|
{
|
||||||
|
id: '123',
|
||||||
|
name: 'foo',
|
||||||
|
query: 'SELECT * FROM foo',
|
||||||
|
viewType: 'chart',
|
||||||
|
viewOptions: { here_are: 'foo chart settings' },
|
||||||
|
createdAt: '2021-05-06T11:05:50.877Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '456',
|
||||||
|
name: 'bar',
|
||||||
|
query: 'SELECT * FROM bar',
|
||||||
|
viewType: 'graph',
|
||||||
|
viewOptions: {
|
||||||
|
structure: {
|
||||||
|
nodeId: 'node_id',
|
||||||
|
objectType: 'object_type',
|
||||||
|
edgeSource: 'source',
|
||||||
|
edgeTarget: 'target'
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
backgroundColor: 'white',
|
||||||
|
nodes: {
|
||||||
|
size: { type: 'constant', value: 10 },
|
||||||
|
color: {
|
||||||
|
type: 'calculated',
|
||||||
|
method: 'degree',
|
||||||
|
colorscale: null,
|
||||||
|
mode: 'continious',
|
||||||
|
colorscaleDirection: 'reversed'
|
||||||
|
},
|
||||||
|
label: { source: 'label', color: '#444444' }
|
||||||
|
},
|
||||||
|
edges: {
|
||||||
|
showDirection: true,
|
||||||
|
size: { type: 'constant', value: 2 },
|
||||||
|
color: { type: 'constant', value: '#a2b1c6' },
|
||||||
|
label: { source: null, color: '#a2b1c6' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
layout: { type: 'circular', options: null }
|
||||||
|
},
|
||||||
|
createdAt: '2021-05-07T11:05:50.877Z'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
expect(migrations._migrate(2, oldInquiries)).to.eql([
|
||||||
|
{
|
||||||
|
id: '123',
|
||||||
|
name: 'foo',
|
||||||
|
query: 'SELECT * FROM foo',
|
||||||
|
viewType: 'chart',
|
||||||
|
viewOptions: { here_are: 'foo chart settings' },
|
||||||
|
createdAt: '2021-05-06T11:05:50.877Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '456',
|
||||||
|
name: 'bar',
|
||||||
|
query: 'SELECT * FROM bar',
|
||||||
|
viewType: 'graph',
|
||||||
|
viewOptions: {
|
||||||
|
structure: {
|
||||||
|
nodeId: 'node_id',
|
||||||
|
objectType: 'object_type',
|
||||||
|
edgeSource: 'source',
|
||||||
|
edgeTarget: 'target'
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
backgroundColor: 'white',
|
||||||
|
highlightMode: 'node_and_neighbors',
|
||||||
|
nodes: {
|
||||||
|
size: { type: 'constant', value: 10 },
|
||||||
|
color: {
|
||||||
|
type: 'calculated',
|
||||||
|
method: 'degree',
|
||||||
|
colorscale: null,
|
||||||
|
mode: 'continious',
|
||||||
|
colorscaleDirection: 'reversed',
|
||||||
|
opacity: 100
|
||||||
|
},
|
||||||
|
label: { source: 'label', color: '#444444' }
|
||||||
|
},
|
||||||
|
edges: {
|
||||||
|
showDirection: true,
|
||||||
|
size: { type: 'constant', value: 2 },
|
||||||
|
color: { type: 'constant', value: '#a2b1c6' },
|
||||||
|
label: { source: null, color: '#a2b1c6' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
layout: { type: 'circular', options: null }
|
||||||
|
},
|
||||||
|
createdAt: '2021-05-07T11:05:50.877Z'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ describe('storedInquiries.js', () => {
|
|||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: 'white',
|
backgroundColor: 'white',
|
||||||
|
highlightMode: 'node_and_neighbors',
|
||||||
nodes: {
|
nodes: {
|
||||||
size: { type: 'constant', value: 10 },
|
size: { type: 'constant', value: 10 },
|
||||||
color: {
|
color: {
|
||||||
@@ -256,7 +257,7 @@ describe('storedInquiries.js', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('deserialiseInquiries migrates inquiries', () => {
|
it('deserialiseInquiries migrates inquiries of v1', () => {
|
||||||
const str = `[
|
const str = `[
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
@@ -295,7 +296,110 @@ describe('storedInquiries.js', () => {
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('deserialiseInquiries return array for one inquiry of v1', () => {
|
it('deserialiseInquiries migrates inquiries of v2', () => {
|
||||||
|
const str = `{
|
||||||
|
"version": 2,
|
||||||
|
"inquiries": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "foo",
|
||||||
|
"query": "select * from foo",
|
||||||
|
"viewType": "chart",
|
||||||
|
"viewOptions": [],
|
||||||
|
"createdAt": "2020-11-03T14:17:49.524Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Xh1Hc9v7P3mRPZVM59QiC",
|
||||||
|
"query": "SELECT * from doc",
|
||||||
|
"viewType": "graph",
|
||||||
|
"viewOptions": {
|
||||||
|
"structure": {
|
||||||
|
"nodeId": "node_id",
|
||||||
|
"objectType": "object_type",
|
||||||
|
"edgeSource": "source",
|
||||||
|
"edgeTarget": "target"
|
||||||
|
},
|
||||||
|
"style": {
|
||||||
|
"backgroundColor": "white",
|
||||||
|
"nodes": {
|
||||||
|
"size": { "type": "constant", "value": 10 },
|
||||||
|
"color": {
|
||||||
|
"type": "calculated",
|
||||||
|
"method": "degree",
|
||||||
|
"colorscale": null,
|
||||||
|
"mode": "continious",
|
||||||
|
"colorscaleDirection": "reversed"
|
||||||
|
},
|
||||||
|
"label": { "source": "label", "color": "#444444" }
|
||||||
|
},
|
||||||
|
"edges": {
|
||||||
|
"showDirection": true,
|
||||||
|
"size": { "type": "constant", "value": 2 },
|
||||||
|
"color": { "type": "constant", "value": "#a2b1c6" },
|
||||||
|
"label": { "source": null, "color": "#a2b1c6" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"layout": { "type": "circular", "options": null }
|
||||||
|
},
|
||||||
|
"name": "student graph",
|
||||||
|
"createdAt": "2026-01-19T21:46:13.899Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const inquiry = storedInquiries.deserialiseInquiries(str)
|
||||||
|
expect(inquiry).to.eql([
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'foo',
|
||||||
|
query: 'select * from foo',
|
||||||
|
viewType: 'chart',
|
||||||
|
viewOptions: [],
|
||||||
|
createdAt: '2020-11-03T14:17:49.524Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Xh1Hc9v7P3mRPZVM59QiC',
|
||||||
|
query: 'SELECT * from doc',
|
||||||
|
viewType: 'graph',
|
||||||
|
viewOptions: {
|
||||||
|
structure: {
|
||||||
|
nodeId: 'node_id',
|
||||||
|
objectType: 'object_type',
|
||||||
|
edgeSource: 'source',
|
||||||
|
edgeTarget: 'target'
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
backgroundColor: 'white',
|
||||||
|
highlightMode: 'node_and_neighbors',
|
||||||
|
nodes: {
|
||||||
|
size: { type: 'constant', value: 10 },
|
||||||
|
color: {
|
||||||
|
type: 'calculated',
|
||||||
|
method: 'degree',
|
||||||
|
colorscale: null,
|
||||||
|
mode: 'continious',
|
||||||
|
colorscaleDirection: 'reversed',
|
||||||
|
opacity: 100
|
||||||
|
},
|
||||||
|
label: { source: 'label', color: '#444444' }
|
||||||
|
},
|
||||||
|
edges: {
|
||||||
|
showDirection: true,
|
||||||
|
size: { type: 'constant', value: 2 },
|
||||||
|
color: { type: 'constant', value: '#a2b1c6' },
|
||||||
|
label: { source: null, color: '#a2b1c6' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
layout: { type: 'circular', options: null }
|
||||||
|
},
|
||||||
|
name: 'student graph',
|
||||||
|
createdAt: '2026-01-19T21:46:13.899Z'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('deserialiseInquiries returns array for one inquiry of v1', () => {
|
||||||
const str = `
|
const str = `
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
@@ -407,7 +511,7 @@ describe('storedInquiries.js', () => {
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('readPredefinedInquiries old', async () => {
|
it('readPredefinedInquiries v1', async () => {
|
||||||
const str = `[
|
const str = `[
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
@@ -432,18 +536,55 @@ describe('storedInquiries.js', () => {
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('readPredefinedInquiries', async () => {
|
it('readPredefinedInquiries v2', async () => {
|
||||||
const str = `{
|
const str = `{
|
||||||
"version": 3,
|
"version": 2,
|
||||||
"inquiries": [
|
"inquiries": [
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"query": "select * from foo",
|
"query": "select * from foo",
|
||||||
"viewType": "chart",
|
"viewType": "chart",
|
||||||
"viewOptions": [],
|
"viewOptions": [],
|
||||||
"createdAt": "2020-11-03T14:17:49.524Z"
|
"createdAt": "2020-11-03T14:17:49.524Z"
|
||||||
}]
|
},
|
||||||
|
{
|
||||||
|
"id": "Xh1Hc9v7P3mRPZVM59QiC",
|
||||||
|
"query": "SELECT * from doc",
|
||||||
|
"viewType": "graph",
|
||||||
|
"viewOptions": {
|
||||||
|
"structure": {
|
||||||
|
"nodeId": "node_id",
|
||||||
|
"objectType": "object_type",
|
||||||
|
"edgeSource": "source",
|
||||||
|
"edgeTarget": "target"
|
||||||
|
},
|
||||||
|
"style": {
|
||||||
|
"backgroundColor": "white",
|
||||||
|
"nodes": {
|
||||||
|
"size": { "type": "constant", "value": 10 },
|
||||||
|
"color": {
|
||||||
|
"type": "calculated",
|
||||||
|
"method": "degree",
|
||||||
|
"colorscale": null,
|
||||||
|
"mode": "continious",
|
||||||
|
"colorscaleDirection": "reversed"
|
||||||
|
},
|
||||||
|
"label": { "source": "label", "color": "#444444" }
|
||||||
|
},
|
||||||
|
"edges": {
|
||||||
|
"showDirection": true,
|
||||||
|
"size": { "type": "constant", "value": 2 },
|
||||||
|
"color": { "type": "constant", "value": "#a2b1c6" },
|
||||||
|
"label": { "source": null, "color": "#a2b1c6" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"layout": { "type": "circular", "options": null }
|
||||||
|
},
|
||||||
|
"name": "student graph",
|
||||||
|
"createdAt": "2026-01-19T21:46:13.899Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
sinon.stub(fu, 'readFile').returns(Promise.resolve(new Response(str)))
|
sinon.stub(fu, 'readFile').returns(Promise.resolve(new Response(str)))
|
||||||
@@ -457,6 +598,90 @@ describe('storedInquiries.js', () => {
|
|||||||
viewType: 'chart',
|
viewType: 'chart',
|
||||||
viewOptions: [],
|
viewOptions: [],
|
||||||
createdAt: '2020-11-03T14:17:49.524Z'
|
createdAt: '2020-11-03T14:17:49.524Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Xh1Hc9v7P3mRPZVM59QiC',
|
||||||
|
query: 'SELECT * from doc',
|
||||||
|
viewType: 'graph',
|
||||||
|
viewOptions: {
|
||||||
|
structure: {
|
||||||
|
nodeId: 'node_id',
|
||||||
|
objectType: 'object_type',
|
||||||
|
edgeSource: 'source',
|
||||||
|
edgeTarget: 'target'
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
backgroundColor: 'white',
|
||||||
|
highlightMode: 'node_and_neighbors',
|
||||||
|
nodes: {
|
||||||
|
size: { type: 'constant', value: 10 },
|
||||||
|
color: {
|
||||||
|
type: 'calculated',
|
||||||
|
method: 'degree',
|
||||||
|
colorscale: null,
|
||||||
|
mode: 'continious',
|
||||||
|
colorscaleDirection: 'reversed',
|
||||||
|
opacity: 100
|
||||||
|
},
|
||||||
|
label: { source: 'label', color: '#444444' }
|
||||||
|
},
|
||||||
|
edges: {
|
||||||
|
showDirection: true,
|
||||||
|
size: { type: 'constant', value: 2 },
|
||||||
|
color: { type: 'constant', value: '#a2b1c6' },
|
||||||
|
label: { source: null, color: '#a2b1c6' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
layout: { type: 'circular', options: null }
|
||||||
|
},
|
||||||
|
name: 'student graph',
|
||||||
|
createdAt: '2026-01-19T21:46:13.899Z'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('readPredefinedInquiries', async () => {
|
||||||
|
const str = `{
|
||||||
|
"version": 3,
|
||||||
|
"inquiries": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "foo",
|
||||||
|
"query": "select * from foo",
|
||||||
|
"viewType": "chart",
|
||||||
|
"viewOptions": [],
|
||||||
|
"createdAt": "2020-11-03T14:17:49.524Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "boo",
|
||||||
|
"query": "select * from boo",
|
||||||
|
"viewType": "graph",
|
||||||
|
"viewOptions": {},
|
||||||
|
"createdAt": "2020-11-03T14:17:49.524Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`
|
||||||
|
sinon.stub(fu, 'readFile').returns(Promise.resolve(new Response(str)))
|
||||||
|
const inquiries = await storedInquiries.readPredefinedInquiries()
|
||||||
|
expect(fu.readFile.calledOnceWith('./inquiries.json')).to.equal(true)
|
||||||
|
expect(inquiries).to.eql([
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'foo',
|
||||||
|
query: 'select * from foo',
|
||||||
|
viewType: 'chart',
|
||||||
|
viewOptions: [],
|
||||||
|
createdAt: '2020-11-03T14:17:49.524Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'boo',
|
||||||
|
query: 'select * from boo',
|
||||||
|
viewType: 'graph',
|
||||||
|
viewOptions: {},
|
||||||
|
createdAt: '2020-11-03T14:17:49.524Z'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user