Browse Source

feat/Added basic erd support

pull/3612/head
Muhammed Mustafa 2 years ago
parent
commit
e3ef8a8ff0
  1. 7
      packages/nc-gui/assets/style.scss
  2. 140
      packages/nc-gui/components/dashboard/settings/Erd.vue
  3. 5
      packages/nc-gui/components/dashboard/settings/Modal.vue
  4. 120
      packages/nc-gui/components/dashboard/settings/erd/RelationEdge.vue
  5. 54
      packages/nc-gui/components/dashboard/settings/erd/TableNode.vue
  6. 6
      packages/nc-gui/composables/useMetas.ts
  7. 359
      packages/nc-gui/package-lock.json
  8. 3
      packages/nc-gui/package.json

7
packages/nc-gui/assets/style.scss

@ -1,4 +1,6 @@
@import 'ant-design-vue/dist/antd.variable.min.css';
@import 'https://cdn.jsdelivr.net/npm/@braks/vue-flow@0.4.39/dist/style.css';
@import 'https://cdn.jsdelivr.net/npm/@braks/vue-flow@0.4.39/dist/theme-default.css';
:root {
--header-height: 42px;
@ -242,3 +244,8 @@ a {
.ant-dropdown-menu-submenu-title{
@apply !pr-2;
}
.vue-flow__minimap {
transform: scale(75%);
transform-origin: bottom right;
}

140
packages/nc-gui/components/dashboard/settings/Erd.vue

@ -0,0 +1,140 @@
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
import type { Edge, Node } from '@braks/vue-flow'
import { Background, MarkerType, VueFlow, isNode, useVueFlow } from '@braks/vue-flow'
import { ref } from 'vue'
import { ColumnType, UITypes } from 'nocodb-sdk'
import dagre from 'dagre'
import TableNode from './erd/TableNode.vue'
import RelationEdge from './erd/RelationEdge.vue'
import { useNuxtApp, useProject } from '#imports'
const dagreGraph = new dagre.graphlib.Graph()
dagreGraph.setDefaultEdgeLabel(() => ({}))
const { updateNodeInternals } = useVueFlow()
const { $api } = useNuxtApp()
const { project, tables } = useProject()
const { t } = useI18n()
const { metas, getMeta, metasWithId } = useMetas()
const nodes = ref<Node[]>([])
const edges = ref<Edge[]>([])
let isLoading = $ref(true)
const loadMetasOfTablesNotInMetas = async () => {
await Promise.all(
tables.value
.filter((table) => !metas.value[table.id!])
.map(async (table) => {
await getMeta(table.id!)
}),
)
}
const populateTables = () => {
Object.keys(metasWithId.value).forEach((tableId) => {
nodes.value.push({
id: tableId,
data: metasWithId.value[tableId],
type: 'custom',
})
dagreGraph.setNode(tableId, { width: 250, height: 30 * metasWithId.value[tableId].columns.length })
})
dagreGraph.setGraph({ rankdir: 'LR' })
}
const populateRelations = () => {
const ltarColumns = Object.keys(metasWithId.value).reduce((acc, tableId) => {
const table = metasWithId.value[tableId]
const ltarColumns = table.columns.filter((column) => column.uidt === UITypes.LinkToAnotherRecord)
ltarColumns.forEach((column) => {
if (column.colOptions.type === 'hm') {
acc.push(column)
}
if (column.colOptions.type === 'mm') {
// Remove duplicate relations
const relatedColumnId = column.colOptions.fk_child_column_id
if (!acc.find((col) => col.id === relatedColumnId)) {
acc.push(column)
}
}
})
return acc
}, [])
edges.value = ltarColumns.map((column: any) => {
const source = column.fk_model_id
const target = column.colOptions.fk_related_model_id
dagreGraph.setEdge(source, target)
return {
id: `e${source}-${target}`,
source: `${source}`,
target: `${target}`,
sourceHandle: `s-${column.id}-${source}`,
targetHandle: `d-${column.id}-${target}`,
type: 'custom',
data: { column, table: metasWithId.value[source], relatedTable: metasWithId.value[target] },
markerEnd: MarkerType.ArrowClosed,
}
})
// console.log('json:elements', JSON.parse(JSON.stringify(elements)))
// console.log('elements', elements)
}
const layoutNodes = () => {
dagre.layout(dagreGraph)
nodes.value = nodes.value.map((node) => {
const nodeWithPosition = dagreGraph.node(node.id)
if (!nodeWithPosition) return node
return { ...node, position: { x: nodeWithPosition.x, y: nodeWithPosition.y } }
})
}
const populateElements = () => {
populateTables()
}
onMounted(async () => {
if (isLoading) {
await loadMetasOfTablesNotInMetas()
populateElements()
populateRelations()
layoutNodes()
console.log('nodes', nodes.value)
console.log('edges', edges.value)
updateNodeInternals(nodes.value as any)
isLoading = false
}
})
</script>
<template>
<div style="height: 650px">
<div v-if="isLoading"></div>
<VueFlow v-else :nodes="nodes" :edges="edges" :fit-view-on-init="true" :default-edge-options="{ type: 'step' }">
<template #node-custom="props">
<TableNode :data="props.data" />
</template>
<template #edge-custom="props">
<RelationEdge v-bind="props" />
</template>
<Background />
</VueFlow>
</div>
</template>

5
packages/nc-gui/components/dashboard/settings/Modal.vue

@ -5,6 +5,7 @@ import AppStore from './AppStore.vue'
import Metadata from './Metadata.vue'
import UIAcl from './UIAcl.vue'
import Misc from './Misc.vue'
import Erd from './Erd.vue'
import { useNuxtApp } from '#app'
import { useI18n, useUIPermission, useVModel, watch } from '#imports'
import ApiTokenManagement from '~/components/tabs/auth/ApiTokenManagement.vue'
@ -112,6 +113,10 @@ const tabsInfo: TabGroup = {
title: t('general.misc'),
body: Misc,
},
erd: {
title: t('title.erd'),
body: Erd,
},
},
onClick: () => {
$e('c:settings:proj-metadata')

120
packages/nc-gui/components/dashboard/settings/erd/RelationEdge.vue

@ -0,0 +1,120 @@
<script setup>
import { EdgeText, getBezierCenter, getBezierPath, getEdgeCenter } from '@braks/vue-flow'
import { computed } from 'vue'
const props = defineProps({
id: {
type: String,
required: true,
},
sourceX: {
type: Number,
required: true,
},
sourceY: {
type: Number,
required: true,
},
targetX: {
type: Number,
required: true,
},
targetY: {
type: Number,
required: true,
},
sourcePosition: {
type: String,
required: true,
},
targetPosition: {
type: String,
required: true,
},
data: {
type: Object,
required: false,
},
markerEnd: {
type: String,
required: false,
},
style: {
type: Object,
required: false,
},
sourceHandleId: {
type: String,
required: false,
},
targetHandleId: {
type: String,
required: false,
},
})
const isHovered = ref(false)
const { column, relatedTable, table } = props.data
const edgePath = computed(() =>
getBezierPath({
sourceX: props.sourceX,
sourceY: props.sourceY,
sourcePosition: props.sourcePosition,
targetX: props.targetX,
targetY: props.targetY,
targetPosition: props.targetPosition,
}),
)
const center = computed(() =>
getEdgeCenter({
sourceX: props.sourceX,
sourceY: props.sourceY,
sourcePosition: props.sourcePosition,
targetX: props.targetX,
targetY: props.targetY,
targetPosition: props.targetPosition,
}),
)
watch(
() => isHovered.value,
(val) => {
console.log(val)
},
)
</script>
<script>
export default {
inheritAttrs: false,
}
</script>
<template>
<circle :cx="sourceX" :cy="sourceY" fill="#fff" :r="5" stroke="#6F3381" :stroke-width="1.5" />
<path
:id="id"
:style="style"
class="stroke-gray-500 p-4 hover:stroke-green-500 hover:cursor-pointer"
:class="{ 'stroke-green-500': isHovered }"
:stroke-width="2.5"
fill="none"
:d="edgePath"
:marker-end="markerEnd"
onmouseover="isHovered = true"
onmouseout="isHovered = false"
/>
<EdgeText
:x="center[0]"
:y="center[1]"
label="Text"
:label-style="{ fill: 'white' }"
:label-show-bg="true"
:label-bg-style="{ fill: '#10b981' }"
:label-bg-padding="[2, 4]"
:label-bg-border-radius="2"
/>
<circle :cx="targetX" :cy="targetY" fill="#fff" :r="5" stroke="#6F3381" :stroke-width="1.5" />
</template>

54
packages/nc-gui/components/dashboard/settings/erd/TableNode.vue

@ -0,0 +1,54 @@
<script setup>
import { Handle, Position } from '@braks/vue-flow'
import { UITypes, isVirtualCol } from 'nocodb-sdk'
const props = defineProps({
data: {
type: Object,
required: true,
},
})
const { data: table } = props
const columns = table.columns
// console.log(table)
const pkColumn = computed(() => {
return columns.find((col) => col.pk)
})
const nonPkColumns = computed(() => {
return columns.filter((col) => !col.pk && col.uidt !== UITypes.ForeignKey)
})
</script>
<template>
<div class="h-full flex flex-col min-w-16 bg-gray-50 rounded-lg border-1">
<div class="text-gray-600 text-md py-2 border-b-2 border-gray-100 w-full pl-3 bg-gray-100 font-semibold">
{{ table.title }}
</div>
<div class="mx-1">
<div class="w-full border-b-1 py-2 border-gray-100">
<SmartsheetHeaderCell v-if="pkColumn" :column="pkColumn" :hide-menu="true" />
</div>
<div v-for="col in nonPkColumns" :key="col.title">
<div class="w-full h-full flex items-center min-w-32 border-b-1 border-gray-100 py-2">
<div v-if="col.uidt === UITypes.LinkToAnotherRecord" class="flex relative w-full">
<Handle :id="`s-${col.id}-${table.id}`" class="-right-4" type="source" :position="Position.Right" :hidden="false" />
<Handle
:id="`d-${col.id}-${table.id}`"
class="-left-1"
type="destination"
:position="Position.Left"
:hidden="false"
/>
<SmartsheetHeaderVirtualCell :column="col" :hide-menu="true" />
</div>
<SmartsheetHeaderVirtualCell v-else-if="isVirtualCol(col)" :column="col" :hide-menu="true" />
<SmartsheetHeaderCell v-else :column="col" :hide-menu="true" />
</div>
</div>
</div>
</div>
</template>

6
packages/nc-gui/composables/useMetas.ts

@ -10,6 +10,10 @@ export function useMetas() {
const { tables } = useProject()
const metas = useState<{ [idOrTitle: string]: TableType | any }>('metas', () => ({}))
const metasWithId = computed(() => {
const idEntries = Object.entries(metas.value).filter(([k, v]) => k === v.id)
return Object.fromEntries(idEntries)
})
const loadingState = useState<Record<string, boolean>>('metas-loading-state', () => ({}))
const setMeta = async (model: any) => {
@ -91,5 +95,5 @@ export function useMetas() {
}
}
return { getMeta, clearAllMeta, metas, removeMeta, setMeta }
return { getMeta, clearAllMeta, metas, metasWithId, removeMeta, setMeta }
}

359
packages/nc-gui/package-lock.json generated

@ -6,12 +6,14 @@
"": {
"hasInstallScript": true,
"dependencies": {
"@braks/vue-flow": "^0.4.39",
"@ckpack/vue-color": "^1.2.0",
"@vuelidate/core": "^2.0.0-alpha.44",
"@vuelidate/validators": "^2.0.0-alpha.31",
"@vueuse/core": "^9.0.2",
"@vueuse/integrations": "^9.0.2",
"ant-design-vue": "^3.2.11",
"dagre": "^0.8.5",
"dayjs": "^1.11.3",
"file-saver": "^2.0.5",
"httpsnippet": "^2.0.0",
@ -28,6 +30,7 @@
"tinycolor2": "^1.4.2",
"unique-names-generator": "^4.7.1",
"vue-dompurify-html": "^3.0.0",
"vue-flow": "^0.3.0",
"vue-github-button": "^3.0.3",
"vue-i18n": "^9.2.2",
"vuedraggable": "^4.1.0",
@ -878,6 +881,103 @@
"node": ">=6.9.0"
}
},
"node_modules/@braks/vue-flow": {
"version": "0.4.39",
"resolved": "https://registry.npmjs.org/@braks/vue-flow/-/vue-flow-0.4.39.tgz",
"integrity": "sha512-ZWKEwvEDKZe0Yw2sS8RxmxLs1k3O9DGFF0rk5xj+zWlExm15uBBhHAf8rWIRVULEbkjOmDwJEJ4bQrqwHn4pdA==",
"dependencies": {
"@vueuse/core": "^9.1.0",
"d3-drag": "^3.0.0",
"d3-selection": "^3.0.0",
"d3-zoom": "^3.0.0"
},
"peerDependencies": {
"vue": "^3.2.25"
}
},
"node_modules/@braks/vue-flow/node_modules/@vueuse/core": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.2.0.tgz",
"integrity": "sha512-/MZ6qpz6uSyaXrtoeBWQzAKRG3N7CvfVWvQxiM3ei3Xe5ydOjjtVbo7lGl9p8dECV93j7W8s63A8H0kFLpLyxg==",
"dependencies": {
"@types/web-bluetooth": "^0.0.15",
"@vueuse/metadata": "9.2.0",
"@vueuse/shared": "9.2.0",
"vue-demi": "*"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@braks/vue-flow/node_modules/@vueuse/core/node_modules/vue-demi": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@braks/vue-flow/node_modules/@vueuse/metadata": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.2.0.tgz",
"integrity": "sha512-exN4KE6iquxDCdt72BgEhb3tlOpECtD61AUdXnUqBTIUCl70x1Ar/QXo3bYcvxmdMS2/peQyfeTzBjRTpvL5xw==",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@braks/vue-flow/node_modules/@vueuse/shared": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.2.0.tgz",
"integrity": "sha512-NnRp/noSWuXW0dKhZK5D0YLrDi0nmZ18UeEgwXQq7Ul5TTP93lcNnKjrHtd68j2xFB/l59yPGFlCryL692bnrA==",
"dependencies": {
"vue-demi": "*"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@braks/vue-flow/node_modules/@vueuse/shared/node_modules/vue-demi": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@ckpack/vue-color": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ckpack/vue-color/-/vue-color-1.2.0.tgz",
@ -5144,6 +5244,111 @@
"integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==",
"dev": true
},
"node_modules/d3-color": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-dispatch": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
"integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-drag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
"integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
"dependencies": {
"d3-dispatch": "1 - 3",
"d3-selection": "3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-ease": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-interpolate": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
"dependencies": {
"d3-color": "1 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-selection": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-timer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-transition": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
"integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
"dependencies": {
"d3-color": "1 - 3",
"d3-dispatch": "1 - 3",
"d3-ease": "1 - 3",
"d3-interpolate": "1 - 3",
"d3-timer": "1 - 3"
},
"engines": {
"node": ">=12"
},
"peerDependencies": {
"d3-selection": "2 - 3"
}
},
"node_modules/d3-zoom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
"integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
"dependencies": {
"d3-dispatch": "1 - 3",
"d3-drag": "2 - 3",
"d3-interpolate": "1 - 3",
"d3-selection": "2 - 3",
"d3-transition": "2 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/dagre": {
"version": "0.8.5",
"resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz",
"integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==",
"dependencies": {
"graphlib": "^2.1.8",
"lodash": "^4.17.15"
}
},
"node_modules/data-uri-to-buffer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
@ -7882,6 +8087,14 @@
"integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
"dev": true
},
"node_modules/graphlib": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz",
"integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==",
"dependencies": {
"lodash": "^4.17.15"
}
},
"node_modules/gzip-size": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-7.0.0.tgz",
@ -14630,6 +14843,11 @@
"node": ">=4.0"
}
},
"node_modules/vue-flow": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/vue-flow/-/vue-flow-0.3.0.tgz",
"integrity": "sha512-J/I6z8ErkWiPCEicdZXTUEBt5MfW1GoFNs2/spGSLuzBKAOUF/MlghKAZZ4feDDjmpg/B00EviSG1fJ0PIGwVg=="
},
"node_modules/vue-github-button": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/vue-github-button/-/vue-github-button-3.0.3.tgz",
@ -15831,6 +16049,59 @@
"to-fast-properties": "^2.0.0"
}
},
"@braks/vue-flow": {
"version": "0.4.39",
"resolved": "https://registry.npmjs.org/@braks/vue-flow/-/vue-flow-0.4.39.tgz",
"integrity": "sha512-ZWKEwvEDKZe0Yw2sS8RxmxLs1k3O9DGFF0rk5xj+zWlExm15uBBhHAf8rWIRVULEbkjOmDwJEJ4bQrqwHn4pdA==",
"requires": {
"@vueuse/core": "^9.1.0",
"d3-drag": "^3.0.0",
"d3-selection": "^3.0.0",
"d3-zoom": "^3.0.0"
},
"dependencies": {
"@vueuse/core": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.2.0.tgz",
"integrity": "sha512-/MZ6qpz6uSyaXrtoeBWQzAKRG3N7CvfVWvQxiM3ei3Xe5ydOjjtVbo7lGl9p8dECV93j7W8s63A8H0kFLpLyxg==",
"requires": {
"@types/web-bluetooth": "^0.0.15",
"@vueuse/metadata": "9.2.0",
"@vueuse/shared": "9.2.0",
"vue-demi": "*"
},
"dependencies": {
"vue-demi": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"requires": {}
}
}
},
"@vueuse/metadata": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.2.0.tgz",
"integrity": "sha512-exN4KE6iquxDCdt72BgEhb3tlOpECtD61AUdXnUqBTIUCl70x1Ar/QXo3bYcvxmdMS2/peQyfeTzBjRTpvL5xw=="
},
"@vueuse/shared": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.2.0.tgz",
"integrity": "sha512-NnRp/noSWuXW0dKhZK5D0YLrDi0nmZ18UeEgwXQq7Ul5TTP93lcNnKjrHtd68j2xFB/l59yPGFlCryL692bnrA==",
"requires": {
"vue-demi": "*"
},
"dependencies": {
"vue-demi": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"requires": {}
}
}
}
}
},
"@ckpack/vue-color": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ckpack/vue-color/-/vue-color-1.2.0.tgz",
@ -19096,6 +19367,81 @@
"integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==",
"dev": true
},
"d3-color": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="
},
"d3-dispatch": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
"integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg=="
},
"d3-drag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
"integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
"requires": {
"d3-dispatch": "1 - 3",
"d3-selection": "3"
}
},
"d3-ease": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="
},
"d3-interpolate": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
"requires": {
"d3-color": "1 - 3"
}
},
"d3-selection": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="
},
"d3-timer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="
},
"d3-transition": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
"integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
"requires": {
"d3-color": "1 - 3",
"d3-dispatch": "1 - 3",
"d3-ease": "1 - 3",
"d3-interpolate": "1 - 3",
"d3-timer": "1 - 3"
}
},
"d3-zoom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
"integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
"requires": {
"d3-dispatch": "1 - 3",
"d3-drag": "2 - 3",
"d3-interpolate": "1 - 3",
"d3-selection": "2 - 3",
"d3-transition": "2 - 3"
}
},
"dagre": {
"version": "0.8.5",
"resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz",
"integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==",
"requires": {
"graphlib": "^2.1.8",
"lodash": "^4.17.15"
}
},
"data-uri-to-buffer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
@ -21041,6 +21387,14 @@
"integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
"dev": true
},
"graphlib": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz",
"integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==",
"requires": {
"lodash": "^4.17.15"
}
},
"gzip-size": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-7.0.0.tgz",
@ -26085,6 +26439,11 @@
}
}
},
"vue-flow": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/vue-flow/-/vue-flow-0.3.0.tgz",
"integrity": "sha512-J/I6z8ErkWiPCEicdZXTUEBt5MfW1GoFNs2/spGSLuzBKAOUF/MlghKAZZ4feDDjmpg/B00EviSG1fJ0PIGwVg=="
},
"vue-github-button": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/vue-github-button/-/vue-github-button-3.0.3.tgz",

3
packages/nc-gui/package.json

@ -15,12 +15,14 @@
"postinstall": "node scripts/updateNuxtRouting.js"
},
"dependencies": {
"@braks/vue-flow": "^0.4.39",
"@ckpack/vue-color": "^1.2.0",
"@vuelidate/core": "^2.0.0-alpha.44",
"@vuelidate/validators": "^2.0.0-alpha.31",
"@vueuse/core": "^9.0.2",
"@vueuse/integrations": "^9.0.2",
"ant-design-vue": "^3.2.11",
"dagre": "^0.8.5",
"dayjs": "^1.11.3",
"file-saver": "^2.0.5",
"httpsnippet": "^2.0.0",
@ -37,6 +39,7 @@
"tinycolor2": "^1.4.2",
"unique-names-generator": "^4.7.1",
"vue-dompurify-html": "^3.0.0",
"vue-flow": "^0.3.0",
"vue-github-button": "^3.0.3",
"vue-i18n": "^9.2.2",
"vuedraggable": "^4.1.0",

Loading…
Cancel
Save