This is an automated email from the ASF dual-hosted git repository. marat pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit 8a2f0fedabf7abaf5adab5e433205dcdf69f0977 Author: Marat Gubaidullin <ma...@talismancloud.io> AuthorDate: Fri Sep 15 18:14:36 2023 -0400 First prototype #893 --- karavan-core/src/core/api/CamelDisplayUtil.ts | 58 +- karavan-core/src/core/api/TopologyUtils.ts | 218 ++++++ karavan-core/src/core/model/TopologyDefinition.ts | 87 +++ karavan-core/test/topology.spec.ts | 36 + karavan-core/test/topology1.camel.yaml | 56 ++ karavan-core/test/topology2.camel.yaml | 44 ++ karavan-designer/package-lock.json | 845 ++++++++++++++++++++- karavan-designer/package.json | 1 + .../src/designer/route/DslConnections.tsx | 16 +- karavan-designer/src/designer/route/DslElement.tsx | 6 +- .../src/designer/route/DslProperties.tsx | 5 +- karavan-designer/src/designer/utils/CamelUi.tsx | 74 +- .../karavan-app/src/main/webui/package-lock.json | 673 +++++++++++++++- .../karavan-app/src/main/webui/package.json | 4 + .../main/webui/src/designer/KaravanDesigner.tsx | 2 - .../webui/src/designer/route/DslConnections.tsx | 8 +- .../src/main/webui/src/designer/utils/CamelUi.tsx | 59 +- .../src/main/webui/src/project/ProjectPage.tsx | 1 + .../src/main/webui/src/project/ProjectPanel.tsx | 18 +- .../main/webui/src/project/topology/CustomNode.tsx | 42 + .../webui/src/project/topology/TopologyApi.tsx | 168 ++++ .../webui/src/project/topology/TopologyTab.tsx | 74 ++ .../webui/src/project/topology/TopologyToolbar.tsx | 49 ++ .../main/webui/src/project/topology/topology.css | 4 + 24 files changed, 2369 insertions(+), 179 deletions(-) diff --git a/karavan-core/src/core/api/CamelDisplayUtil.ts b/karavan-core/src/core/api/CamelDisplayUtil.ts index eee33ccb..0e0c79e2 100644 --- a/karavan-core/src/core/api/CamelDisplayUtil.ts +++ b/karavan-core/src/core/api/CamelDisplayUtil.ts @@ -18,21 +18,37 @@ import { Integration, CamelElement } from '../model/IntegrationDefinition'; import { CamelUtil } from './CamelUtil'; import { CamelDefinitionApi } from './CamelDefinitionApi'; import { CamelDefinitionApiExt } from './CamelDefinitionApiExt'; +import { KameletModel } from '../model/KameletModels'; +import { RouteDefinition } from '../model/CamelDefinition'; +import { ComponentApi } from './ComponentApi'; +import { CamelMetadataApi } from '../model/CamelMetadata'; export class CamelDisplayUtil { private constructor() {} - static isStepDefinitionExpanded = ( - integration: Integration, - stepUuid: string, - selectedUuid: string | undefined, - ): boolean => { + static getTitle = (element: CamelElement): string => { + const k: KameletModel | undefined = CamelUtil.getKamelet(element); + if (k) { + return k.title(); + } else if (element.dslName === 'RouteDefinition') { + const routeId = (element as RouteDefinition).id + return routeId ? routeId : CamelUtil.capitalizeName((element as any).stepName); + } else if ((element as any).uri && (['ToDefinition', 'FromDefinition'].includes(element.dslName))) { + const uri = (element as any).uri + return ComponentApi.getComponentTitleFromUri(uri) || ''; + } else { + const title = CamelMetadataApi.getCamelModelMetadataByClassName(element.dslName); + return title ? title.title : CamelUtil.capitalizeName((element as any).stepName); + } + } + + static isStepDefinitionExpanded = (integration: Integration, stepUuid: string, selectedUuid: string | undefined): boolean => { const expandedUuids: string[] = []; if (selectedUuid) { expandedUuids.push(...CamelDisplayUtil.getParentStepDefinitions(integration, selectedUuid)); } return expandedUuids.includes(stepUuid); - }; + } static getParentStepDefinitions = (integration: Integration, uuid: string): string[] => { const result: string[] = []; @@ -50,7 +66,7 @@ export class CamelDisplayUtil { } } return result; - }; + } static setIntegrationVisibility = (integration: Integration, selectedUuid: string | undefined): Integration => { const clone: Integration = CamelUtil.cloneIntegration(integration); @@ -73,7 +89,7 @@ export class CamelDisplayUtil { clone.spec.flows = flows; return clone; - }; + } static setElementVisibility = (step: CamelElement, showChildren: boolean, expandedUuids: string[]): CamelElement => { const result = CamelDefinitionApi.createStep(step.dslName, step); @@ -82,34 +98,22 @@ export class CamelDisplayUtil { showChildren = expandedUuids.includes(result.uuid); } - const elementChildDefiniton = CamelDefinitionApiExt.getElementChildrenDefinition(step.dslName); - for (const element of elementChildDefiniton) { + const elementChildDefinition = CamelDefinitionApiExt.getElementChildrenDefinition(step.dslName); + for (const element of elementChildDefinition) { const camelElement = CamelDefinitionApiExt.getElementChildren(step, element); if (element.multiple) { - (result as any)[element.name] = CamelDisplayUtil.setElementsVisibility( - (result as any)[element.name], - showChildren, - expandedUuids, - ); + (result as any)[element.name] = CamelDisplayUtil.setElementsVisibility((result as any)[element.name], showChildren, expandedUuids) } else { const prop = (result as any)[element.name]; if (prop && prop.hasOwnProperty('uuid')) { - (result as any)[element.name] = CamelDisplayUtil.setElementVisibility( - camelElement[0], - showChildren, - expandedUuids, - ); + (result as any)[element.name] = CamelDisplayUtil.setElementVisibility(camelElement[0], showChildren,expandedUuids) } } } return result; - }; + } - static setElementsVisibility = ( - steps: CamelElement[] | undefined, - showChildren: boolean, - expandedUuids: string[], - ): CamelElement[] => { + static setElementsVisibility = (steps: CamelElement[] | undefined, showChildren: boolean, expandedUuids: string[]): CamelElement[] => { const result: CamelElement[] = []; if (steps) { for (const step of steps) { @@ -117,5 +121,5 @@ export class CamelDisplayUtil { } } return result; - }; + } } diff --git a/karavan-core/src/core/api/TopologyUtils.ts b/karavan-core/src/core/api/TopologyUtils.ts new file mode 100644 index 00000000..29ede6bb --- /dev/null +++ b/karavan-core/src/core/api/TopologyUtils.ts @@ -0,0 +1,218 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { CamelMetadataApi} from '../model/CamelMetadata'; +import { + DeleteDefinition, + FromDefinition, + GetDefinition, + HeadDefinition, + PatchDefinition, + PostDefinition, + PutDefinition, + RestDefinition, SagaDefinition, +} from '../model/CamelDefinition'; +import { + CamelElement, + CamelElementMeta, + Integration, +} from '../model/IntegrationDefinition'; +import { CamelDefinitionApi } from './CamelDefinitionApi'; +import { + TopologyIncomingNode, + TopologyOutgoingNode, + TopologyRestNode, + TopologyRouteNode, +} from '../model/TopologyDefinition'; +import { ComponentApi } from './ComponentApi'; +import { CamelDefinitionApiExt } from './CamelDefinitionApiExt'; +import { CamelDisplayUtil } from './CamelDisplayUtil'; + +const outgoingDefinitions: string[] = ['ToDefinition', 'KameletDefinition', 'ToDynamicDefinition', "PollEnrichDefinition", "EnrichDefinition", "WireTapDefinition", "SagaDefinition"]; + +export class ChildElement { + constructor(public name: string = '', public className: string = '', public multiple: boolean = false) {} +} + +export class TopologyUtils { + private constructor() {} + + static getOutgoingDefinitions = (): string[] => { + return outgoingDefinitions; + } + + static isElementInternalComponent = (element: CamelElement): boolean => { + const uri = (element as any).uri; + const component = ComponentApi.findByName(uri); + return component !== undefined && + (TopologyUtils.isComponentInternal(component.component.label) || TopologyUtils.hasInternalUri(element)); + } + + static isComponentInternal = (label: string): boolean => { + const labels = label.split(","); + if (labels.includes('core') && ( + labels.includes('transformation') + || labels.includes('testing') + || labels.includes('scheduling') + || labels.includes('monitoring') + || labels.includes('transformation') + || labels.includes('java') + || labels.includes('endpoint') + || labels.includes('script') + || labels.includes('validation') + )) { + return true; + } else if (label === 'transformation') { + return true; + } + return false; + } + + static hasInternalUri = (element: CamelElement): boolean => { + return this.hasDirectUri(element) || this.hasSedaUri(element); + } + + static hasDirectUri = (element: CamelElement): boolean => { + return this.hasUriStartWith(element, 'direct'); + } + + static hasSedaUri = (element: CamelElement): boolean => { + return this.hasUriStartWith(element, 'seda'); + } + + static hasUriStartWith = (element: CamelElement, text: string): boolean => { + if ((element as any).uri && typeof (element as any).uri === 'string') { + return (element as any).uri.startsWith(text); + } else if (element.dslName === 'SagaDefinition') { + const completion = (element as SagaDefinition).completion || ''; + const compensation = (element as SagaDefinition).compensation || ''; + return completion.startsWith(text) || compensation.startsWith(text); + } else { + return false; + } + } + + static findTopologyRestNodes = (integration: Integration[]): TopologyRestNode[] => { + const result:TopologyRestNode[] = []; + integration.forEach(i => { + const filename = i.metadata.name; + const routeIds: string[] = []; + const routes = i.spec.flows?.filter(flow => flow.dslName === 'RestDefinition'); + routes?.forEach((rest: RestDefinition) => { + rest?.get?.forEach((d: GetDefinition) => { + if (d.to) routeIds.push(d.to); + }); + rest?.post?.forEach((d: PostDefinition) => { + if (d.to) routeIds.push(d.to); + }); + rest?.put?.forEach((d: PutDefinition) => { + if (d.to) routeIds.push(d.to); + }); + rest?.delete?.forEach((d: DeleteDefinition) => { + if (d.to) routeIds.push(d.to); + }); + rest?.patch?.forEach((d: PatchDefinition) => { + if (d.to) routeIds.push(d.to); + }); + rest?.head?.forEach((d: HeadDefinition) => { + if (d.to) routeIds.push(d.to); + }); + const title = 'REST: ' + (rest.description ? rest.description : rest.id); + result.push(new TopologyRestNode(rest.path || '', '' + rest.id, routeIds, title, filename)) + }) + }) + return result; + }; + + static findTopologyIncomingNodes = (integration: Integration[]): TopologyIncomingNode[] => { + const result:TopologyIncomingNode[] = []; + integration.forEach(i => { + const filename = i.metadata.name; + const routes = i.spec.flows?.filter(flow => flow.dslName === 'RouteDefinition'); + const routeElements = routes?.map(r => { + const id = 'incoming-' + r.id; + const title = CamelDisplayUtil.getTitle(r.from); + const type = TopologyUtils.isElementInternalComponent(r.from) ? 'internal' : 'external'; + return new TopologyIncomingNode(id, type, r.id, title, filename, r.from); + }) || []; + result.push(...routeElements) + }) + return result; + } + + static findTopologyRouteNodes = (integration: Integration[]): TopologyRouteNode[] => { + const result:TopologyRouteNode[] = []; + integration.forEach(i => { + const filename = i.metadata.name; + const routes = i.spec.flows?.filter(flow => flow.dslName === 'RouteDefinition'); + const routeElements = routes?.map(r => { + const id = 'route-' + r.id; + const title = '' + (r.description ? r.description : r.id) + return new TopologyRouteNode(id, r.id, title, filename, r.from); + }) || []; + result.push(...routeElements) + }) + return result; + } + + static findTopologyOutgoingNodes = (integration: Integration[]): TopologyOutgoingNode[] => { + const result:TopologyOutgoingNode[] = []; + integration.forEach(i => { + const filename = i.metadata.name; + const routes = i.spec.flows?.filter(flow => flow.dslName === 'RouteDefinition'); + routes?.forEach(route => { + const from: FromDefinition = route.from; + const elements = TopologyUtils.findOutgoingInStep(from, []); + elements.forEach((e: any) => { + const id = 'outgoing-' + route.id + '-' + e.id; + const title = CamelDisplayUtil.getTitle(e); + const type = TopologyUtils.isElementInternalComponent(e) ? 'internal' : 'external'; + result.push(new TopologyOutgoingNode(id, type, route.id, title, filename, e)); + }) + }) + + }) + return result; + } + + static findOutgoingInStep = (step: CamelElement, result: CamelElement[]): CamelElement[] => { + if (step !== undefined) { + const el = (step as any); + if (outgoingDefinitions.includes(el.dslName)) { + result.push(step); + } else { + const childElements = CamelDefinitionApiExt.getElementChildrenDefinition(el.dslName); + childElements.forEach(child => { + if (child.multiple) { + const sub = (el[child.name] as CamelElement[]); + TopologyUtils.findOutgoingInSteps(sub, result); + } else { + const sub = (el[child.name] as CamelElement); + TopologyUtils.findOutgoingInStep(sub, result); + } + }) + } + } + return result; + } + + static findOutgoingInSteps = (steps: CamelElement[], result: CamelElement[]): CamelElement[] => { + if (steps !== undefined && steps.length > 0) { + steps.forEach(step => TopologyUtils.findOutgoingInStep(step, result)) + } + return result; + } +} diff --git a/karavan-core/src/core/model/TopologyDefinition.ts b/karavan-core/src/core/model/TopologyDefinition.ts new file mode 100644 index 00000000..2ba9142f --- /dev/null +++ b/karavan-core/src/core/model/TopologyDefinition.ts @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CamelElement } from './IntegrationDefinition'; +import { FromDefinition } from './CamelDefinition'; + +export class TopologyRestNode { + path: string; + id: string; + routeIds: string[]; + title: string; + fileName: string; + + constructor(path: string, id: string, routeIds: string[], title: string, fileName: string) { + this.path = path; + this.id = id; + this.routeIds = routeIds; + this.title = title; + this.fileName = fileName; + } +} + +export class TopologyIncomingNode { + id: string; + type: 'internal' | 'external'; + routeId: string; + title: string; + fileName: string; + from: FromDefinition; + + constructor(id: string, type: 'internal' | 'external', routeId: string, title: string, fileName: string, from: FromDefinition) { + this.id = id; + this.type = type; + this.routeId = routeId; + this.title = title; + this.fileName = fileName; + this.from = from; + } +} + +export class TopologyRouteNode { + id: string; + routeId: string; + title: string; + fileName: string; + from: FromDefinition; + + constructor(id: string, routeId: string, title: string, fileName: string, from: FromDefinition) { + this.id = id; + this.routeId = routeId; + this.title = title; + this.fileName = fileName; + this.from = from; + } +} + +export class TopologyOutgoingNode { + id: string; + type: 'internal' | 'external'; + routeId: string; + title: string; + fileName: string; + step: CamelElement; + + constructor(id: string, type: 'internal' | 'external', routeId: string, title: string, fileName: string, step: CamelElement) { + this.id = id; + this.type = type + this.routeId = routeId; + this.title = title; + this.fileName = fileName; + this.step = step; + } +} \ No newline at end of file diff --git a/karavan-core/test/topology.spec.ts b/karavan-core/test/topology.spec.ts new file mode 100644 index 00000000..e76ead2b --- /dev/null +++ b/karavan-core/test/topology.spec.ts @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as fs from 'fs'; +import 'mocha'; +import {CamelDefinitionYaml} from "../src/core/api/CamelDefinitionYaml"; +import { TopologyUtils } from '../src/core/api/TopologyUtils'; + + +describe('Topology functions', () => { + + it('Topology find', () => { + const yaml1 = fs.readFileSync('test/topology1.camel.yaml',{encoding:'utf8', flag:'r'}); + const yaml2 = fs.readFileSync('test/topology2.camel.yaml',{encoding:'utf8', flag:'r'}); + const i1 = CamelDefinitionYaml.yamlToIntegration("test1.yaml", yaml1); + const i2 = CamelDefinitionYaml.yamlToIntegration("test1.yaml", yaml2); + const tin = TopologyUtils.findTopologyIncomingNodes([i1, i2]); + const trn = TopologyUtils.findTopologyRestNodes([i1, i2]); + const ton = TopologyUtils.findTopologyOutgoingNodes([i1, i2]); + console.log(tin) + }); + +}); diff --git a/karavan-core/test/topology1.camel.yaml b/karavan-core/test/topology1.camel.yaml new file mode 100644 index 00000000..46633080 --- /dev/null +++ b/karavan-core/test/topology1.camel.yaml @@ -0,0 +1,56 @@ +- route: + id: route-c67f1 + description: Timer Scheduler + from: + uri: kamelet:timer-source + id: from-b4181 + parameters: + message: Hello + steps: + - log: + message: ${body} + id: log-a68a1 +- route: + id: route-2cbd1 + from: + uri: kamelet:aws-cloudtrail-source + id: from-a3f61 + parameters: + region: fff + steps: + - to: + uri: kamelet:google-pubsub-sink + id: to-c27f1 +- route: + id: route-de2b1 + from: + uri: amqp + id: from-1e661 + steps: + - to: + uri: direct + id: to-6a041 + parameters: + name: xxxx +- route: + id: route-ec4e1 + from: + uri: direct + id: from-e9181 + parameters: + name: xxx + steps: + - to: + uri: kamelet:kafka-not-secured-sink + id: to-a47b1 +- rest: + id: rest-b499 + get: + - to: direct:xxx + id: get-cb63 + post: + - to: direct:xxx + id: post-07e4 + put: + - to: direct:xxx + id: put-8271 \ No newline at end of file diff --git a/karavan-core/test/topology2.camel.yaml b/karavan-core/test/topology2.camel.yaml new file mode 100644 index 00000000..49cb6eed --- /dev/null +++ b/karavan-core/test/topology2.camel.yaml @@ -0,0 +1,44 @@ +- route: + id: route-c67f + from: + uri: kamelet:timer-source + id: from-b418 + parameters: + message: Hello + steps: + - log: + message: ${body} + id: log-a68a +- route: + id: route-2cbd + from: + uri: kamelet:aws-cloudtrail-source + id: from-a3f6 + parameters: + region: fff + steps: + - to: + uri: kamelet:google-pubsub-sink + id: to-c27f +- route: + id: route-de2b + from: + uri: amqp + id: from-1e66 + steps: + - to: + uri: direct + id: to-6a04 + parameters: + name: xxxx +- route: + id: route-ec4e + from: + uri: direct + id: from-e918 + parameters: + name: xxx + steps: + - to: + uri: kamelet:kafka-not-secured-sink + id: to-a47b diff --git a/karavan-designer/package-lock.json b/karavan-designer/package-lock.json index 96126a8c..654708b7 100644 --- a/karavan-designer/package-lock.json +++ b/karavan-designer/package-lock.json @@ -13,6 +13,7 @@ "@patternfly/patternfly": "^5.0.2", "@patternfly/react-core": "^5.0.0", "@patternfly/react-table": "^5.0.0", + "@patternfly/react-topology": "^5.0.0", "@types/js-yaml": "4.0.5", "@types/node": "18.16.3", "@types/uuid": "9.0.1", @@ -2074,7 +2075,6 @@ "version": "7.22.15", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz", "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==", - "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -3475,6 +3475,48 @@ "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-5.0.1.tgz", "integrity": "sha512-YafAGJYvxDP4GaQ0vMybalWmx7MJ+etUf1cGoaMh0wRD2eswltT/RckygtEBKR/M61qXbgG+CxKmMyY8leoiDw==" }, + "node_modules/@patternfly/react-topology": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-topology/-/react-topology-5.0.0.tgz", + "integrity": "sha512-DW1dXXff5X+5K3ZW8rn1eqSggGfq5My/BMMcyhO6ankgAxAA4uK96/DbWaUMmSxkeHDSF6tD5jTd/SiglQzR1A==", + "dependencies": { + "@patternfly/react-core": "^5.0.0", + "@patternfly/react-icons": "^5.0.0", + "@patternfly/react-styles": "^5.0.0", + "@types/d3": "^7.4.0", + "@types/d3-force": "^1.2.1", + "@types/dagre": "0.7.42", + "@types/react-measure": "^2.0.6", + "d3": "^7.8.0", + "dagre": "0.8.2", + "lodash": "^4.17.19", + "mobx": "^6.9.0", + "mobx-react": "^7.6.0", + "point-in-svg-path": "^1.0.1", + "popper.js": "^1.16.1", + "react-measure": "^2.3.0", + "tslib": "^2.0.0", + "webcola": "3.4.0" + }, + "peerDependencies": { + "react": "^17 || ^18", + "react-dom": "^17 || ^18" + } + }, + "node_modules/@patternfly/react-topology/node_modules/@types/dagre": { + "version": "0.7.42", + "resolved": "https://registry.npmjs.org/@types/dagre/-/dagre-0.7.42.tgz", + "integrity": "sha512-knVdi1Ul8xYgJ0wdhQ+/2YGJFKJFa/5srcPII9zvOs4KhsHfpnFrSTQXATYmjslglxRMif3Lg+wEZ0beag+94A==" + }, + "node_modules/@patternfly/react-topology/node_modules/dagre": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.2.tgz", + "integrity": "sha512-TEOOGZOkCOgCG7AoUIq64sJ3d21SMv8tyoqteLpX+UsUsS9Qw8iap4hhogXY4oB3r0bbZuAjO0atAilgCmsE0Q==", + "dependencies": { + "graphlib": "^2.1.5", + "lodash": "^4.17.4" + } + }, "node_modules/@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.11", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.11.tgz", @@ -3996,6 +4038,228 @@ "@types/node": "*" } }, + "node_modules/@types/d3": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.0.tgz", + "integrity": "sha512-jIfNVK0ZlxcuRDKtRS/SypEyOQ6UHaFQBKv032X45VvxSJ6Yi5G9behy9h6tNTHTDGh5Vq+KbmBjUWLgY4meCA==", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.7.tgz", + "integrity": "sha512-4/Q0FckQ8TBjsB0VdGFemJOG8BLXUB2KKlL0VmZ+eOYeOnTb/wDRQqYWpBmQ6IlvWkXwkYiot+n9Px2aTJ7zGQ==" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.3.tgz", + "integrity": "sha512-SE3x/pLO/+GIHH17mvs1uUVPkZ3bHquGzvZpPAh4yadRy71J93MJBpgK/xY8l9gT28yTN1g9v3HfGSFeBMmwZw==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.3.tgz", + "integrity": "sha512-MQ1/M/B5ifTScHSe5koNkhxn2mhUPqXjGuKjjVYckplAPjP9t2I2sZafb/YVHDwhoXWZoSav+Q726eIbN3qprA==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.3.tgz", + "integrity": "sha512-keuSRwO02c7PBV3JMWuctIfdeJrVFI7RpzouehvBWL4/GGUB3PBNg/9ZKPZAgJphzmS2v2+7vr7BGDQw1CAulw==" + }, + "node_modules/@types/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.3.tgz", + "integrity": "sha512-x7G/tdDZt4m09XZnG2SutbIuQqmkNYqR9uhDMdPlpJbcwepkEjEWG29euFcgVA1k6cn92CHdDL9Z+fOnxnbVQw==", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.1.tgz", + "integrity": "sha512-tLxQ2sfT0p6sxdG75c6f/ekqxjyYR0+LwPrsO1mbC9YDBzPJhs2HbJJRrn8Ez1DBoHRo2yx7YEATI+8V1nGMnQ==" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.3.tgz", + "integrity": "sha512-Df7KW3Re7G6cIpIhQtqHin8yUxUHYAqiE41ffopbmU5+FifYUNV7RVyTg8rQdkEagg83m14QtS8InvNb95Zqug==" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.3.tgz", + "integrity": "sha512-82AuQMpBQjuXeIX4tjCYfWjpm3g7aGCfx6dFlxX2JlRaiME/QWcHzBsINl7gbHCODA2anPYlL31/Trj/UnjK9A==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.2.tgz", + "integrity": "sha512-DooW5AOkj4AGmseVvbwHvwM/Ltu0Ks0WrhG6r5FG9riHT5oUUTHz6xHsHqJSVU8ZmPkOqlUEY2obS5C9oCIi2g==" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.0.tgz", + "integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.3.tgz", + "integrity": "sha512-/EsDKRiQkby3Z/8/AiZq8bsuLDo/tYHnNIZkUpSeEHWV7fHUl6QFBjvMPbhkKGk9jZutzfOkGygCV7eR/MkcXA==", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-1.2.4.tgz", + "integrity": "sha512-fkorLTKvt6AQbFBQwn4aq7h9rJ4c7ZVcPMGB8X6eFFveAyMZcv7t7m6wgF4Eg93rkPgPORU7sAho1QSHNcZu6w==" + }, + "node_modules/@types/d3-format": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.1.tgz", + "integrity": "sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==" + }, + "node_modules/@types/d3-geo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.0.4.tgz", + "integrity": "sha512-kmUK8rVVIBPKJ1/v36bk2aSgwRj2N/ZkjDT+FkMT5pgedZoPlyhaG62J+9EgNIgUXE6IIL0b7bkLxCzhE6U4VQ==", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.3.tgz", + "integrity": "sha512-GpSK308Xj+HeLvogfEc7QsCOcIxkDwLhFYnOoohosEzOqv7/agxwvJER1v/kTC+CY1nfazR0F7gnHo7GE41/fw==" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz", + "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.0.tgz", + "integrity": "sha512-D49z4DyzTKXM0sGKVqiTDTYr+DHg/uxsiWDAkNrwXYuiZVd9o9wXZIo+YsHkifOiyBkmSWlEngHCQme54/hnHw==" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.2.tgz", + "integrity": "sha512-QNcK8Jguvc8lU+4OfeNx+qnVy7c0VrDJ+CCVFS9srBo2GL9Y18CnIxBdTF3v38flrGy5s1YggcoAiu6s4fLQIw==" + }, + "node_modules/@types/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-IIE6YTekGczpLYo/HehAy3JGF1ty7+usI97LqraNa8IiDur+L44d0VOjAvFQWJVdZOJHukUJw+ZdZBlgeUsHOQ==" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.4.tgz", + "integrity": "sha512-eq1ZeTj0yr72L8MQk6N6heP603ubnywSDRfNpi5enouR112HzGLS6RIvExCzZTraFF4HdzNpJMwA/zGiMoHUUw==", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.6.tgz", + "integrity": "sha512-2ACr96USZVjXR9KMD9IWi1Epo4rSDKnUtYn6q2SPhYxykvXTw9vR77lkFNruXVg4i1tzQtBxeDMx0oNvJWbF1w==" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.2.tgz", + "integrity": "sha512-NN4CXr3qeOUNyK5WasVUV8NCSAx/CRVcwcb0BuuS1PiTqwIm6ABi1SyasLZ/vsVCFDArF+W4QiGzSry1eKYQ7w==", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz", + "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.0.tgz", + "integrity": "sha512-yjfBUe6DJBsDin2BMIulhSHmr5qNR5Pxs17+oW4DoVPyVIXZ+m6bs7j1UVKP08Emv6jRmYrYqxYzO63mQxy1rw==" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.0.tgz", + "integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.4.tgz", + "integrity": "sha512-512a4uCOjUzsebydItSXsHrPeQblCVk8IKjqCUmrlvBWkkVh3donTTxmURDo1YPwIVDh5YVwCAO6gR4sgimCPQ==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.4.tgz", + "integrity": "sha512-cqkuY1ah9ZQre2POqjSLcM8g40UVya/qwEUrNYP2/rCVljbmqKCVcv+ebvwhlI5azIbSEL7m+os6n+WlYA43aA==", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, "node_modules/@types/dagre": { "version": "0.7.49", "resolved": "https://registry.npmjs.org/@types/dagre/-/dagre-0.7.49.tgz", @@ -4052,6 +4316,11 @@ "@types/send": "*" } }, + "node_modules/@types/geojson": { + "version": "7946.0.10", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", + "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==" + }, "node_modules/@types/graceful-fs": { "version": "4.1.6", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", @@ -4149,8 +4418,7 @@ "node_modules/@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "devOptional": true + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "node_modules/@types/qs": { "version": "6.9.8", @@ -4168,7 +4436,6 @@ "version": "18.2.21", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz", "integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==", - "devOptional": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -4184,6 +4451,14 @@ "@types/react": "*" } }, + "node_modules/@types/react-measure": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@types/react-measure/-/react-measure-2.0.8.tgz", + "integrity": "sha512-Pu4/hQ/1AKVN6efoawtcM+l376WYOI8e1fiM6ir4pdLkHilDCkJLjUGvAm0mWKJ0GE6hzu55yCrcJ/xNyEdFwA==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -4202,8 +4477,7 @@ "node_modules/@types/scheduler": { "version": "0.16.3", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", - "devOptional": true + "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" }, "node_modules/@types/semver": { "version": "7.5.1", @@ -6755,8 +7029,385 @@ "node_modules/csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "devOptional": true + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + }, + "node_modules/d3": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.5.tgz", + "integrity": "sha512-JgoahDG51ncUfJu6wX/1vWQEqOflgXyl4MaHqlcSruTez7yhaRKR9i8VjjcQGeS2en/jnFivXuaIMnseMMt0XA==", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "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-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dependencies": { + "delaunator": "5" + }, + "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-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "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-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "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-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "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-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "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", @@ -6868,6 +7519,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delaunator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", + "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "dependencies": { + "robust-predicates": "^3.0.0" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -8924,6 +9583,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-node-dimensions": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-node-dimensions/-/get-node-dimensions-1.2.1.tgz", + "integrity": "sha512-2MSPMu7S1iOTL+BOa6K1S62hB2zUAYNF/lV0gSVlOaacd087lc6nR1H1r0e3B1CerTo+RceOmi1iJW+vp21xcQ==" + }, "node_modules/get-own-enumerable-property-symbols": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", @@ -9510,7 +10174,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -9647,6 +10310,14 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/ipaddr.js": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", @@ -13039,6 +13710,60 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mobx": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.10.2.tgz", + "integrity": "sha512-B1UGC3ieK3boCjnMEcZSwxqRDMdzX65H/8zOHbuTY8ZhvrIjTUoLRR2TP2bPqIgYRfb3+dUigu8yMZufNjn0LQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + } + }, + "node_modules/mobx-react": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-7.6.0.tgz", + "integrity": "sha512-+HQUNuh7AoQ9ZnU6c4rvbiVVl+wEkb9WqYsVDzGLng+Dqj1XntHu79PvEWKtSMoMj67vFp/ZPXcElosuJO8ckA==", + "dependencies": { + "mobx-react-lite": "^3.4.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.1.0", + "react": "^16.8.0 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/mobx-react-lite": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-3.4.3.tgz", + "integrity": "sha512-NkJREyFTSUXR772Qaai51BnE1voWx56LOL80xG7qkZr6vo8vEaLF3sz1JNUVh+rxmUzxYaqOhfuxTfqUh0FXUg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.1.0", + "react": "^16.8.0 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/monaco-editor": { "version": "0.43.0", "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.43.0.tgz", @@ -13765,6 +14490,24 @@ "node": ">=4" } }, + "node_modules/point-in-svg-path": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/point-in-svg-path/-/point-in-svg-path-1.0.2.tgz", + "integrity": "sha512-+Smsf7B9e7eRFHIwpN+4rE8inF2APbFWeywPfUgbeh02xdJSkbTz6Pqdt7A36wVCR+CnLbaNkRnBjgOpF5RMVQ==", + "engines": { + "node": ">=8.x.x" + } + }, + "node_modules/popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", + "deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/postcss": { "version": "8.4.29", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz", @@ -15528,6 +16271,21 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-measure": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/react-measure/-/react-measure-2.5.2.tgz", + "integrity": "sha512-M+rpbTLWJ3FD6FXvYV6YEGvQ5tMayQ3fGrZhRPHrE9bVlBYfDCLuDcgNttYfk8IqfOI03jz6cbpqMRTUclQnaA==", + "dependencies": { + "@babel/runtime": "^7.2.0", + "get-node-dimensions": "^1.2.1", + "prop-types": "^15.6.2", + "resize-observer-polyfill": "^1.5.0" + }, + "peerDependencies": { + "react": ">0.13.0", + "react-dom": ">0.13.0" + } + }, "node_modules/react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", @@ -15731,8 +16489,7 @@ "node_modules/regenerator-runtime": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", - "dev": true + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "node_modules/regenerator-transform": { "version": "0.15.2", @@ -15850,6 +16607,11 @@ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, "node_modules/resolve": { "version": "1.22.4", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", @@ -16000,6 +16762,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + }, "node_modules/rollup": { "version": "2.79.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", @@ -16098,6 +16865,11 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, "node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -16161,8 +16933,7 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sanitize.css": { "version": "13.0.0", @@ -17838,6 +18609,54 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/webcola": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/webcola/-/webcola-3.4.0.tgz", + "integrity": "sha512-4BiLXjXw3SJHo3Xd+rF+7fyClT6n7I+AR6TkBqyQ4kTsePSAMDLRCXY1f3B/kXJeP9tYn4G1TblxTO+jAt0gaw==", + "dependencies": { + "d3-dispatch": "^1.0.3", + "d3-drag": "^1.0.4", + "d3-shape": "^1.3.5", + "d3-timer": "^1.0.5" + } + }, + "node_modules/webcola/node_modules/d3-dispatch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", + "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==" + }, + "node_modules/webcola/node_modules/d3-drag": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.5.tgz", + "integrity": "sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==", + "dependencies": { + "d3-dispatch": "1", + "d3-selection": "1" + } + }, + "node_modules/webcola/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" + }, + "node_modules/webcola/node_modules/d3-selection": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz", + "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==" + }, + "node_modules/webcola/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/webcola/node_modules/d3-timer": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", + "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==" + }, "node_modules/webidl-conversions": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", diff --git a/karavan-designer/package.json b/karavan-designer/package.json index 92534f5b..47cec418 100644 --- a/karavan-designer/package.json +++ b/karavan-designer/package.json @@ -30,6 +30,7 @@ "@patternfly/patternfly": "^5.0.2", "@patternfly/react-core": "^5.0.0", "@patternfly/react-table": "^5.0.0", + "@patternfly/react-topology": "^5.0.0", "@types/js-yaml": "4.0.5", "@types/node": "18.16.3", "@types/uuid": "9.0.1", diff --git a/karavan-designer/src/designer/route/DslConnections.tsx b/karavan-designer/src/designer/route/DslConnections.tsx index c9d85ccb..44f23042 100644 --- a/karavan-designer/src/designer/route/DslConnections.tsx +++ b/karavan-designer/src/designer/route/DslConnections.tsx @@ -23,9 +23,9 @@ import {SagaDefinition} from "karavan-core/lib/model/CamelDefinition"; import {useConnectionsStore, useDesignerStore, useIntegrationStore} from "../KaravanStore"; import {shallow} from "zustand/shallow"; import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt"; +import {TopologyUtils} from "karavan-core/lib/api/TopologyUtils"; const overlapGap: number = 40; -const outgoingDefinitions: string[] = ['ToDefinition', 'KameletDefinition', 'ToDynamicDefinition', "PollEnrichDefinition", "EnrichDefinition", "WireTapDefinition", "SagaDefinition"]; export function DslConnections() { @@ -61,8 +61,8 @@ export function DslConnections() { function getIncomings() { let outs: [string, number][] = Array.from(steps.values()) .filter(pos => ["FromDefinition"].includes(pos.step.dslName)) - .filter(pos => !CamelUi.isElementInternalComponent(pos.step)) - .filter(pos => !(pos.step.dslName === 'FromDefinition' && CamelUi.hasInternalUri(pos.step))) + .filter(pos => !TopologyUtils.isElementInternalComponent(pos.step)) + .filter(pos => !(pos.step.dslName === 'FromDefinition' && TopologyUtils.hasInternalUri(pos.step))) .sort((pos1: DslPosition, pos2: DslPosition) => { const y1 = pos1.headerRect.y + pos1.headerRect.height / 2; const y2 = pos2.headerRect.y + pos2.headerRect.height / 2; @@ -135,11 +135,12 @@ export function DslConnections() { function getOutgoings(): [string, number][] { + const outgoingDefinitions = TopologyUtils.getOutgoingDefinitions(); let outs: [string, number][] = Array.from(steps.values()) .filter(pos => outgoingDefinitions.includes(pos.step.dslName)) .filter(pos => pos.step.dslName !== 'KameletDefinition' || (pos.step.dslName === 'KameletDefinition' && !CamelUi.isActionKamelet(pos.step))) - .filter(pos => pos.step.dslName === 'ToDefinition' && !CamelUi.isActionKamelet(pos.step) && !CamelUi.isElementInternalComponent(pos.step)) - .filter(pos => !(outgoingDefinitions.includes(pos.step.dslName) && CamelUi.hasInternalUri(pos.step))) + .filter(pos => pos.step.dslName === 'ToDefinition' && !CamelUi.isActionKamelet(pos.step) && !TopologyUtils.isElementInternalComponent(pos.step)) + .filter(pos => !(outgoingDefinitions.includes(pos.step.dslName) && TopologyUtils.hasInternalUri(pos.step))) .filter(pos => pos.step.dslName !== 'SagaDefinition') .sort((pos1: DslPosition, pos2: DslPosition) => { const y1 = pos1.headerRect.y + pos1.headerRect.height / 2; @@ -203,8 +204,9 @@ export function DslConnections() { } function getInternals(): [string, number, boolean][] { + const outgoingDefinitions = TopologyUtils.getOutgoingDefinitions(); let outs: [string, number, boolean][] = Array.from(steps.values()) - .filter(pos => outgoingDefinitions.includes(pos.step.dslName) && CamelUi.hasInternalUri(pos.step)) + .filter(pos => outgoingDefinitions.includes(pos.step.dslName) && TopologyUtils.hasInternalUri(pos.step)) .sort((pos1: DslPosition, pos2: DslPosition) => { const y1 = pos1.headerRect.y + pos1.headerRect.height / 2; const y2 = pos2.headerRect.y + pos2.headerRect.height / 2; @@ -222,7 +224,7 @@ export function DslConnections() { const fromX = pos.headerRect.x + pos.headerRect.width / 2 - left; const fromY = pos.headerRect.y + pos.headerRect.height / 2 - top; const r = pos.headerRect.height / 2; - const className = (CamelUi.hasDirectUri(pos.step) ? "path-direct" : "path-seda") + (data[2] ? "-selected" : ""); + const className = (TopologyUtils.hasDirectUri(pos.step) ? "path-direct" : "path-seda") + (data[2] ? "-selected" : ""); return getInternalLine(uri, key, className, fromX, fromY, r, data[1]); } else if (pos?.step.dslName === 'SagaDefinition'){ const saga = (pos?.step as SagaDefinition); diff --git a/karavan-designer/src/designer/route/DslElement.tsx b/karavan-designer/src/designer/route/DslElement.tsx index 9aaf6735..489c675d 100644 --- a/karavan-designer/src/designer/route/DslElement.tsx +++ b/karavan-designer/src/designer/route/DslElement.tsx @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, {CSSProperties, useEffect, useMemo, useRef, useState} from 'react'; +import React, {CSSProperties, useMemo, useState} from 'react'; import { Button, Flex, @@ -377,7 +377,7 @@ export function DslElement(props: Props) { if (hideAddButton) return (<></>) else return ( <Tooltip position={"bottom"} - content={<div>{"Add step to " + CamelUi.getTitle(step)}</div>}> + content={<div>{"Add step to " + CamelDisplayUtil.getTitle(step)}</div>}> <button type="button" aria-label="Add" onClick={e => onOpenSelector(e)} className={isAddStepButtonLeft() ? "add-button add-button-left" : "add-button add-button-bottom"}> <AddIcon/> @@ -388,7 +388,7 @@ export function DslElement(props: Props) { function getAddElementButton() { return ( - <Tooltip position={"bottom"} content={<div>{"Add DSL element to " + CamelUi.getTitle(props.step)}</div>}> + <Tooltip position={"bottom"} content={<div>{"Add DSL element to " + CamelDisplayUtil.getTitle(props.step)}</div>}> <button type="button" aria-label="Add" diff --git a/karavan-designer/src/designer/route/DslProperties.tsx b/karavan-designer/src/designer/route/DslProperties.tsx index 337e12c0..69729121 100644 --- a/karavan-designer/src/designer/route/DslProperties.tsx +++ b/karavan-designer/src/designer/route/DslProperties.tsx @@ -33,6 +33,7 @@ import CloneIcon from "@patternfly/react-icons/dist/esm/icons/clone-icon"; import {useDesignerStore, useIntegrationStore} from "../KaravanStore"; import {shallow} from "zustand/shallow"; import {usePropertiesHook} from "./usePropertiesHook"; +import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil"; interface Props { isRouteDesigner: boolean @@ -52,7 +53,7 @@ export function DslProperties(props: Props) { const [isDescriptionExpanded, setIsDescriptionExpanded] = useState<boolean>(false); function getRouteHeader(): JSX.Element { - const title = selectedStep && CamelUi.getTitle(selectedStep) + const title = selectedStep && CamelDisplayUtil.getTitle(selectedStep) const description = selectedStep && CamelUi.getDescription(selectedStep); const descriptionLines: string [] = description ? description?.split("\n") : [""]; return ( @@ -73,7 +74,7 @@ export function DslProperties(props: Props) { } function getClonableElementHeader(): JSX.Element { - const title = selectedStep && CamelUi.getTitle(selectedStep); + const title = selectedStep && CamelDisplayUtil.getTitle(selectedStep); const description = selectedStep?.dslName ? CamelMetadataApi.getCamelModelMetadataByClassName(selectedStep?.dslName)?.description : title; const descriptionLines: string [] = description ? description?.split("\n") : [""]; return ( diff --git a/karavan-designer/src/designer/utils/CamelUi.tsx b/karavan-designer/src/designer/utils/CamelUi.tsx index c5d63801..b3a098c7 100644 --- a/karavan-designer/src/designer/utils/CamelUi.tsx +++ b/karavan-designer/src/designer/utils/CamelUi.tsx @@ -88,6 +88,8 @@ import { WorkflowIcon } from "./KaravanIcons"; import React from "react"; +import {TopologyUtils} from "karavan-core/lib/api/TopologyUtils"; +import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil"; const StepElements: string[] = [ "AggregateDefinition", @@ -300,30 +302,6 @@ export class CamelUi { else return false; } - static hasInternalUri = (element: CamelElement): boolean => { - return this.hasDirectUri(element) || this.hasSedaUri(element); - } - - static hasDirectUri = (element: CamelElement): boolean => { - return this.hasUriStartWith(element, 'direct'); - } - - static hasSedaUri = (element: CamelElement): boolean => { - return this.hasUriStartWith(element, 'seda'); - } - - static hasUriStartWith = (element: CamelElement, text: string): boolean => { - if ((element as any).uri && typeof (element as any).uri === 'string') { - return (element as any).uri.startsWith(text); - } else if (element.dslName === 'SagaDefinition') { - const completion = (element as SagaDefinition).completion || ''; - const compensation = (element as SagaDefinition).compensation || ''; - return completion.startsWith(text) || compensation.startsWith(text); - } else { - return false; - } - } - static getInternalRouteUris = (integration: Integration, componentName: string, showComponentName: boolean = true): string[] => { const result: string[] = []; integration.spec.flows?.filter(f => f.dslName === 'RouteDefinition') @@ -351,22 +329,6 @@ export class CamelUi { } } - static getTitle = (element: CamelElement): string => { - const k: KameletModel | undefined = CamelUtil.getKamelet(element); - if (k) { - return k.title(); - } else if (element.dslName === 'RouteDefinition') { - const routeId = (element as RouteDefinition).id - return routeId ? routeId : CamelUtil.capitalizeName((element as any).stepName); - } else if ((element as any).uri && (['ToDefinition', 'FromDefinition'].includes(element.dslName))) { - const uri = (element as any).uri - return ComponentApi.getComponentTitleFromUri(uri) || ''; - } else { - const title = CamelMetadataApi.getCamelModelMetadataByClassName(element.dslName); - return title ? title.title : CamelUtil.capitalizeName((element as any).stepName); - } - } - static getDescription = (element: CamelElement): string => { const kamelet: KameletModel | undefined = CamelUtil.getKamelet(element); if (kamelet) { @@ -376,7 +338,7 @@ export class CamelUi { return ComponentApi.getComponentDescriptionFromUri(uri) || ''; } else { const description = CamelMetadataApi.getCamelModelMetadataByClassName(element.dslName)?.description; - return description ? description : CamelUi.getTitle(element); + return description ? description : CamelDisplayUtil.getTitle(element); } } @@ -669,43 +631,17 @@ export class CamelUi { } } - static isElementInternalComponent = (element: CamelElement): boolean => { - const uri = (element as any).uri; - const component = ComponentApi.findByName(uri); - return component !== undefined && CamelUi.isComponentInternal(component.component.label); - } - - static isComponentInternal = (label: string): boolean => { - const labels = label.split(","); - if (labels.includes('core') && ( - labels.includes('transformation') - || labels.includes('testing') - || labels.includes('scheduling') - || labels.includes('monitoring') - || labels.includes('transformation') - || labels.includes('java') - || labels.includes('endpoint') - || labels.includes('script') - || labels.includes('validation') - )) { - return true; - } else if (label === 'transformation') { - return true; - } - return false; - } - static getIconForElement = (element: CamelElement): JSX.Element => { const uri = (element as any).uri; const component = ComponentApi.findByName(uri); const k: KameletModel | undefined = CamelUtil.getKamelet(element); if (["FromDefinition", "KameletDefinition"].includes(element.dslName) && k !== undefined) { return k ? this.getIconFromSource(k.icon()) : CamelUi.getIconForDslName(element.dslName); - } else if ("FromDefinition" === element.dslName && component !== undefined && CamelUi.isComponentInternal(component.component.label)) { + } else if ("FromDefinition" === element.dslName && component !== undefined && TopologyUtils.isComponentInternal(component.component.label)) { return this.getIconForComponent(component?.component.title, component?.component.label); } else if (element.dslName === "ToDefinition" && (element as ToDefinition).uri?.startsWith("kamelet:")) { return k ? this.getIconFromSource(k.icon()) : CamelUi.getIconForDslName(element.dslName); - } else if (element.dslName === "ToDefinition" && component && CamelUi.isComponentInternal(component.component.label)) { + } else if (element.dslName === "ToDefinition" && component && TopologyUtils.isComponentInternal(component.component.label)) { return this.getIconForComponent(component?.component.title, component?.component.label); } else { return this.getIconForDslName(element.dslName); diff --git a/karavan-web/karavan-app/src/main/webui/package-lock.json b/karavan-web/karavan-app/src/main/webui/package-lock.json index 6af49aad..a87a8bcd 100644 --- a/karavan-web/karavan-app/src/main/webui/package-lock.json +++ b/karavan-web/karavan-app/src/main/webui/package-lock.json @@ -15,6 +15,7 @@ "@patternfly/react-core": "^5.0.0", "@patternfly/react-log-viewer": "^5.0.0", "@patternfly/react-table": "^5.0.0", + "@patternfly/react-topology": "^5.0.0", "@types/js-yaml": "4.0.5", "@types/node": "18.16.3", "@types/uuid": "9.0.1", @@ -2081,7 +2082,6 @@ "version": "7.22.15", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz", "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==", - "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -3535,6 +3535,48 @@ "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-5.0.1.tgz", "integrity": "sha512-YafAGJYvxDP4GaQ0vMybalWmx7MJ+etUf1cGoaMh0wRD2eswltT/RckygtEBKR/M61qXbgG+CxKmMyY8leoiDw==" }, + "node_modules/@patternfly/react-topology": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-topology/-/react-topology-5.0.0.tgz", + "integrity": "sha512-DW1dXXff5X+5K3ZW8rn1eqSggGfq5My/BMMcyhO6ankgAxAA4uK96/DbWaUMmSxkeHDSF6tD5jTd/SiglQzR1A==", + "dependencies": { + "@patternfly/react-core": "^5.0.0", + "@patternfly/react-icons": "^5.0.0", + "@patternfly/react-styles": "^5.0.0", + "@types/d3": "^7.4.0", + "@types/d3-force": "^1.2.1", + "@types/dagre": "0.7.42", + "@types/react-measure": "^2.0.6", + "d3": "^7.8.0", + "dagre": "0.8.2", + "lodash": "^4.17.19", + "mobx": "^6.9.0", + "mobx-react": "^7.6.0", + "point-in-svg-path": "^1.0.1", + "popper.js": "^1.16.1", + "react-measure": "^2.3.0", + "tslib": "^2.0.0", + "webcola": "3.4.0" + }, + "peerDependencies": { + "react": "^17 || ^18", + "react-dom": "^17 || ^18" + } + }, + "node_modules/@patternfly/react-topology/node_modules/@types/dagre": { + "version": "0.7.42", + "resolved": "https://registry.npmjs.org/@types/dagre/-/dagre-0.7.42.tgz", + "integrity": "sha512-knVdi1Ul8xYgJ0wdhQ+/2YGJFKJFa/5srcPII9zvOs4KhsHfpnFrSTQXATYmjslglxRMif3Lg+wEZ0beag+94A==" + }, + "node_modules/@patternfly/react-topology/node_modules/dagre": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.2.tgz", + "integrity": "sha512-TEOOGZOkCOgCG7AoUIq64sJ3d21SMv8tyoqteLpX+UsUsS9Qw8iap4hhogXY4oB3r0bbZuAjO0atAilgCmsE0Q==", + "dependencies": { + "graphlib": "^2.1.5", + "lodash": "^4.17.4" + } + }, "node_modules/@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.11", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.11.tgz", @@ -4064,21 +4106,142 @@ "@types/node": "*" } }, + "node_modules/@types/d3": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.0.tgz", + "integrity": "sha512-jIfNVK0ZlxcuRDKtRS/SypEyOQ6UHaFQBKv032X45VvxSJ6Yi5G9behy9h6tNTHTDGh5Vq+KbmBjUWLgY4meCA==", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, "node_modules/@types/d3-array": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.7.tgz", "integrity": "sha512-4/Q0FckQ8TBjsB0VdGFemJOG8BLXUB2KKlL0VmZ+eOYeOnTb/wDRQqYWpBmQ6IlvWkXwkYiot+n9Px2aTJ7zGQ==" }, + "node_modules/@types/d3-axis": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.3.tgz", + "integrity": "sha512-SE3x/pLO/+GIHH17mvs1uUVPkZ3bHquGzvZpPAh4yadRy71J93MJBpgK/xY8l9gT28yTN1g9v3HfGSFeBMmwZw==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.3.tgz", + "integrity": "sha512-MQ1/M/B5ifTScHSe5koNkhxn2mhUPqXjGuKjjVYckplAPjP9t2I2sZafb/YVHDwhoXWZoSav+Q726eIbN3qprA==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.3.tgz", + "integrity": "sha512-keuSRwO02c7PBV3JMWuctIfdeJrVFI7RpzouehvBWL4/GGUB3PBNg/9ZKPZAgJphzmS2v2+7vr7BGDQw1CAulw==" + }, "node_modules/@types/d3-color": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz", "integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==" }, + "node_modules/@types/d3-contour": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.3.tgz", + "integrity": "sha512-x7G/tdDZt4m09XZnG2SutbIuQqmkNYqR9uhDMdPlpJbcwepkEjEWG29euFcgVA1k6cn92CHdDL9Z+fOnxnbVQw==", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.1.tgz", + "integrity": "sha512-tLxQ2sfT0p6sxdG75c6f/ekqxjyYR0+LwPrsO1mbC9YDBzPJhs2HbJJRrn8Ez1DBoHRo2yx7YEATI+8V1nGMnQ==" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.3.tgz", + "integrity": "sha512-Df7KW3Re7G6cIpIhQtqHin8yUxUHYAqiE41ffopbmU5+FifYUNV7RVyTg8rQdkEagg83m14QtS8InvNb95Zqug==" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.3.tgz", + "integrity": "sha512-82AuQMpBQjuXeIX4tjCYfWjpm3g7aGCfx6dFlxX2JlRaiME/QWcHzBsINl7gbHCODA2anPYlL31/Trj/UnjK9A==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.2.tgz", + "integrity": "sha512-DooW5AOkj4AGmseVvbwHvwM/Ltu0Ks0WrhG6r5FG9riHT5oUUTHz6xHsHqJSVU8ZmPkOqlUEY2obS5C9oCIi2g==" + }, "node_modules/@types/d3-ease": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.0.tgz", "integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==" }, + "node_modules/@types/d3-fetch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.3.tgz", + "integrity": "sha512-/EsDKRiQkby3Z/8/AiZq8bsuLDo/tYHnNIZkUpSeEHWV7fHUl6QFBjvMPbhkKGk9jZutzfOkGygCV7eR/MkcXA==", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-1.2.4.tgz", + "integrity": "sha512-fkorLTKvt6AQbFBQwn4aq7h9rJ4c7ZVcPMGB8X6eFFveAyMZcv7t7m6wgF4Eg93rkPgPORU7sAho1QSHNcZu6w==" + }, + "node_modules/@types/d3-format": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.1.tgz", + "integrity": "sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==" + }, + "node_modules/@types/d3-geo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.0.4.tgz", + "integrity": "sha512-kmUK8rVVIBPKJ1/v36bk2aSgwRj2N/ZkjDT+FkMT5pgedZoPlyhaG62J+9EgNIgUXE6IIL0b7bkLxCzhE6U4VQ==", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.3.tgz", + "integrity": "sha512-GpSK308Xj+HeLvogfEc7QsCOcIxkDwLhFYnOoohosEzOqv7/agxwvJER1v/kTC+CY1nfazR0F7gnHo7GE41/fw==" + }, "node_modules/@types/d3-interpolate": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz", @@ -4092,6 +4255,21 @@ "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz", "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==" }, + "node_modules/@types/d3-polygon": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.0.tgz", + "integrity": "sha512-D49z4DyzTKXM0sGKVqiTDTYr+DHg/uxsiWDAkNrwXYuiZVd9o9wXZIo+YsHkifOiyBkmSWlEngHCQme54/hnHw==" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.2.tgz", + "integrity": "sha512-QNcK8Jguvc8lU+4OfeNx+qnVy7c0VrDJ+CCVFS9srBo2GL9Y18CnIxBdTF3v38flrGy5s1YggcoAiu6s4fLQIw==" + }, + "node_modules/@types/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-IIE6YTekGczpLYo/HehAy3JGF1ty7+usI97LqraNa8IiDur+L44d0VOjAvFQWJVdZOJHukUJw+ZdZBlgeUsHOQ==" + }, "node_modules/@types/d3-scale": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.4.tgz", @@ -4100,6 +4278,16 @@ "@types/d3-time": "*" } }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.6.tgz", + "integrity": "sha512-2ACr96USZVjXR9KMD9IWi1Epo4rSDKnUtYn6q2SPhYxykvXTw9vR77lkFNruXVg4i1tzQtBxeDMx0oNvJWbF1w==" + }, "node_modules/@types/d3-shape": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.2.tgz", @@ -4113,11 +4301,33 @@ "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz", "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==" }, + "node_modules/@types/d3-time-format": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.0.tgz", + "integrity": "sha512-yjfBUe6DJBsDin2BMIulhSHmr5qNR5Pxs17+oW4DoVPyVIXZ+m6bs7j1UVKP08Emv6jRmYrYqxYzO63mQxy1rw==" + }, "node_modules/@types/d3-timer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.0.tgz", "integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==" }, + "node_modules/@types/d3-transition": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.4.tgz", + "integrity": "sha512-512a4uCOjUzsebydItSXsHrPeQblCVk8IKjqCUmrlvBWkkVh3donTTxmURDo1YPwIVDh5YVwCAO6gR4sgimCPQ==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.4.tgz", + "integrity": "sha512-cqkuY1ah9ZQre2POqjSLcM8g40UVya/qwEUrNYP2/rCVljbmqKCVcv+ebvwhlI5azIbSEL7m+os6n+WlYA43aA==", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, "node_modules/@types/dagre": { "version": "0.7.49", "resolved": "https://registry.npmjs.org/@types/dagre/-/dagre-0.7.49.tgz", @@ -4180,6 +4390,11 @@ "integrity": "sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ==", "dev": true }, + "node_modules/@types/geojson": { + "version": "7946.0.10", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", + "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==" + }, "node_modules/@types/graceful-fs": { "version": "4.1.6", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", @@ -4277,8 +4492,7 @@ "node_modules/@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "devOptional": true + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "node_modules/@types/qs": { "version": "6.9.8", @@ -4296,7 +4510,6 @@ "version": "18.2.21", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz", "integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==", - "devOptional": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -4312,6 +4525,14 @@ "@types/react": "*" } }, + "node_modules/@types/react-measure": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@types/react-measure/-/react-measure-2.0.8.tgz", + "integrity": "sha512-Pu4/hQ/1AKVN6efoawtcM+l376WYOI8e1fiM6ir4pdLkHilDCkJLjUGvAm0mWKJ0GE6hzu55yCrcJ/xNyEdFwA==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -4330,8 +4551,7 @@ "node_modules/@types/scheduler": { "version": "0.16.3", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", - "devOptional": true + "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" }, "node_modules/@types/semver": { "version": "7.5.1", @@ -6925,8 +7145,47 @@ "node_modules/csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "devOptional": true + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + }, + "node_modules/d3": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.5.tgz", + "integrity": "sha512-JgoahDG51ncUfJu6wX/1vWQEqOflgXyl4MaHqlcSruTez7yhaRKR9i8VjjcQGeS2en/jnFivXuaIMnseMMt0XA==", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } }, "node_modules/d3-array": { "version": "3.2.4", @@ -6939,6 +7198,40 @@ "node": ">=12" } }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/d3-color": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", @@ -6947,6 +7240,88 @@ "node": ">=12" } }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay/node_modules/delaunator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", + "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "dependencies": { + "robust-predicates": "^3.0.0" + } + }, + "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-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, "node_modules/d3-ease": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", @@ -6955,6 +7330,30 @@ "node": ">=12" } }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/d3-format": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", @@ -6963,6 +7362,25 @@ "node": ">=12" } }, + "node_modules/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "engines": { + "node": ">=12" + } + }, "node_modules/d3-interpolate": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", @@ -6982,6 +7400,30 @@ "node": ">=12" } }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "engines": { + "node": ">=12" + } + }, "node_modules/d3-scale": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", @@ -6997,6 +7439,26 @@ "node": ">=12" } }, + "node_modules/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "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-shape": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", @@ -7038,6 +7500,39 @@ "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", @@ -9222,6 +9717,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-node-dimensions": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-node-dimensions/-/get-node-dimensions-1.2.1.tgz", + "integrity": "sha512-2MSPMu7S1iOTL+BOa6K1S62hB2zUAYNF/lV0gSVlOaacd087lc6nR1H1r0e3B1CerTo+RceOmi1iJW+vp21xcQ==" + }, "node_modules/get-own-enumerable-property-symbols": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", @@ -9816,7 +10316,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -13396,6 +13895,60 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mobx": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.10.2.tgz", + "integrity": "sha512-B1UGC3ieK3boCjnMEcZSwxqRDMdzX65H/8zOHbuTY8ZhvrIjTUoLRR2TP2bPqIgYRfb3+dUigu8yMZufNjn0LQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + } + }, + "node_modules/mobx-react": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-7.6.0.tgz", + "integrity": "sha512-+HQUNuh7AoQ9ZnU6c4rvbiVVl+wEkb9WqYsVDzGLng+Dqj1XntHu79PvEWKtSMoMj67vFp/ZPXcElosuJO8ckA==", + "dependencies": { + "mobx-react-lite": "^3.4.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.1.0", + "react": "^16.8.0 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/mobx-react-lite": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-3.4.3.tgz", + "integrity": "sha512-NkJREyFTSUXR772Qaai51BnE1voWx56LOL80xG7qkZr6vo8vEaLF3sz1JNUVh+rxmUzxYaqOhfuxTfqUh0FXUg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.1.0", + "react": "^16.8.0 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/monaco-editor": { "version": "0.41.0", "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.41.0.tgz", @@ -14122,6 +14675,24 @@ "node": ">=4" } }, + "node_modules/point-in-svg-path": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/point-in-svg-path/-/point-in-svg-path-1.0.2.tgz", + "integrity": "sha512-+Smsf7B9e7eRFHIwpN+4rE8inF2APbFWeywPfUgbeh02xdJSkbTz6Pqdt7A36wVCR+CnLbaNkRnBjgOpF5RMVQ==", + "engines": { + "node": ">=8.x.x" + } + }, + "node_modules/popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", + "deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/postcss": { "version": "8.4.29", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz", @@ -15890,6 +16461,21 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-measure": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/react-measure/-/react-measure-2.5.2.tgz", + "integrity": "sha512-M+rpbTLWJ3FD6FXvYV6YEGvQ5tMayQ3fGrZhRPHrE9bVlBYfDCLuDcgNttYfk8IqfOI03jz6cbpqMRTUclQnaA==", + "dependencies": { + "@babel/runtime": "^7.2.0", + "get-node-dimensions": "^1.2.1", + "prop-types": "^15.6.2", + "resize-observer-polyfill": "^1.5.0" + }, + "peerDependencies": { + "react": ">0.13.0", + "react-dom": ">0.13.0" + } + }, "node_modules/react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", @@ -16123,8 +16709,7 @@ "node_modules/regenerator-runtime": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", - "dev": true + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "node_modules/regenerator-transform": { "version": "0.15.2", @@ -16242,6 +16827,11 @@ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, "node_modules/resolve": { "version": "1.22.4", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", @@ -16392,6 +16982,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + }, "node_modules/rollup": { "version": "2.79.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", @@ -16490,6 +17085,11 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, "node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -16553,8 +17153,7 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sanitize.css": { "version": "13.0.0", @@ -18548,6 +19147,54 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/webcola": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/webcola/-/webcola-3.4.0.tgz", + "integrity": "sha512-4BiLXjXw3SJHo3Xd+rF+7fyClT6n7I+AR6TkBqyQ4kTsePSAMDLRCXY1f3B/kXJeP9tYn4G1TblxTO+jAt0gaw==", + "dependencies": { + "d3-dispatch": "^1.0.3", + "d3-drag": "^1.0.4", + "d3-shape": "^1.3.5", + "d3-timer": "^1.0.5" + } + }, + "node_modules/webcola/node_modules/d3-dispatch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", + "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==" + }, + "node_modules/webcola/node_modules/d3-drag": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.5.tgz", + "integrity": "sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==", + "dependencies": { + "d3-dispatch": "1", + "d3-selection": "1" + } + }, + "node_modules/webcola/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" + }, + "node_modules/webcola/node_modules/d3-selection": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz", + "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==" + }, + "node_modules/webcola/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/webcola/node_modules/d3-timer": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", + "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==" + }, "node_modules/webidl-conversions": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", diff --git a/karavan-web/karavan-app/src/main/webui/package.json b/karavan-web/karavan-app/src/main/webui/package.json index d6d968cc..54e823a3 100644 --- a/karavan-web/karavan-app/src/main/webui/package.json +++ b/karavan-web/karavan-app/src/main/webui/package.json @@ -33,6 +33,7 @@ "@patternfly/react-core": "^5.0.0", "@patternfly/react-log-viewer": "^5.0.0", "@patternfly/react-table": "^5.0.0", + "@patternfly/react-topology": "^5.0.0", "@types/js-yaml": "4.0.5", "@types/node": "18.16.3", "@types/uuid": "9.0.1", @@ -67,5 +68,8 @@ "overrides": { "@svgr/webpack": "$@svgr/webpack", "core-js": "^3.30.1" + }, + "resolutions": { + "@types/react": "^18" } } diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/KaravanDesigner.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/KaravanDesigner.tsx index cb58a377..00c8b966 100644 --- a/karavan-web/karavan-app/src/main/webui/src/designer/KaravanDesigner.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/designer/KaravanDesigner.tsx @@ -24,8 +24,6 @@ import { Tabs, TabTitleIcon, TabTitleText, - Tooltip, - TooltipPosition, } from '@patternfly/react-core'; import './karavan.css'; import {RouteDesigner} from "./route/RouteDesigner"; diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/route/DslConnections.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/route/DslConnections.tsx index c9d85ccb..d217104a 100644 --- a/karavan-web/karavan-app/src/main/webui/src/designer/route/DslConnections.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/designer/route/DslConnections.tsx @@ -23,9 +23,9 @@ import {SagaDefinition} from "karavan-core/lib/model/CamelDefinition"; import {useConnectionsStore, useDesignerStore, useIntegrationStore} from "../KaravanStore"; import {shallow} from "zustand/shallow"; import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt"; +import {TopologyUtils} from "karavan-core/lib/api/TopologyUtils"; const overlapGap: number = 40; -const outgoingDefinitions: string[] = ['ToDefinition', 'KameletDefinition', 'ToDynamicDefinition', "PollEnrichDefinition", "EnrichDefinition", "WireTapDefinition", "SagaDefinition"]; export function DslConnections() { @@ -61,7 +61,7 @@ export function DslConnections() { function getIncomings() { let outs: [string, number][] = Array.from(steps.values()) .filter(pos => ["FromDefinition"].includes(pos.step.dslName)) - .filter(pos => !CamelUi.isElementInternalComponent(pos.step)) + .filter(pos => !TopologyUtils.isElementInternalComponent(pos.step)) .filter(pos => !(pos.step.dslName === 'FromDefinition' && CamelUi.hasInternalUri(pos.step))) .sort((pos1: DslPosition, pos2: DslPosition) => { const y1 = pos1.headerRect.y + pos1.headerRect.height / 2; @@ -135,10 +135,11 @@ export function DslConnections() { function getOutgoings(): [string, number][] { + const outgoingDefinitions = TopologyUtils.getOutgoingDefinitions(); let outs: [string, number][] = Array.from(steps.values()) .filter(pos => outgoingDefinitions.includes(pos.step.dslName)) .filter(pos => pos.step.dslName !== 'KameletDefinition' || (pos.step.dslName === 'KameletDefinition' && !CamelUi.isActionKamelet(pos.step))) - .filter(pos => pos.step.dslName === 'ToDefinition' && !CamelUi.isActionKamelet(pos.step) && !CamelUi.isElementInternalComponent(pos.step)) + .filter(pos => pos.step.dslName === 'ToDefinition' && !CamelUi.isActionKamelet(pos.step) && !TopologyUtils.isElementInternalComponent(pos.step)) .filter(pos => !(outgoingDefinitions.includes(pos.step.dslName) && CamelUi.hasInternalUri(pos.step))) .filter(pos => pos.step.dslName !== 'SagaDefinition') .sort((pos1: DslPosition, pos2: DslPosition) => { @@ -203,6 +204,7 @@ export function DslConnections() { } function getInternals(): [string, number, boolean][] { + const outgoingDefinitions = TopologyUtils.getOutgoingDefinitions(); let outs: [string, number, boolean][] = Array.from(steps.values()) .filter(pos => outgoingDefinitions.includes(pos.step.dslName) && CamelUi.hasInternalUri(pos.step)) .sort((pos1: DslPosition, pos2: DslPosition) => { diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/utils/CamelUi.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/utils/CamelUi.tsx index c5d63801..1ca65fae 100644 --- a/karavan-web/karavan-app/src/main/webui/src/designer/utils/CamelUi.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/designer/utils/CamelUi.tsx @@ -88,6 +88,8 @@ import { WorkflowIcon } from "./KaravanIcons"; import React from "react"; +import {TopologyUtils} from "karavan-core/lib/api/TopologyUtils"; +import {renderToStaticMarkup} from "react-dom/server"; const StepElements: string[] = [ "AggregateDefinition", @@ -669,48 +671,23 @@ export class CamelUi { } } - static isElementInternalComponent = (element: CamelElement): boolean => { - const uri = (element as any).uri; - const component = ComponentApi.findByName(uri); - return component !== undefined && CamelUi.isComponentInternal(component.component.label); - } - - static isComponentInternal = (label: string): boolean => { - const labels = label.split(","); - if (labels.includes('core') && ( - labels.includes('transformation') - || labels.includes('testing') - || labels.includes('scheduling') - || labels.includes('monitoring') - || labels.includes('transformation') - || labels.includes('java') - || labels.includes('endpoint') - || labels.includes('script') - || labels.includes('validation') - )) { - return true; - } else if (label === 'transformation') { - return true; - } - return false; - } - static getIconForElement = (element: CamelElement): JSX.Element => { const uri = (element as any).uri; const component = ComponentApi.findByName(uri); const k: KameletModel | undefined = CamelUtil.getKamelet(element); if (["FromDefinition", "KameletDefinition"].includes(element.dslName) && k !== undefined) { return k ? this.getIconFromSource(k.icon()) : CamelUi.getIconForDslName(element.dslName); - } else if ("FromDefinition" === element.dslName && component !== undefined && CamelUi.isComponentInternal(component.component.label)) { + } else if ("FromDefinition" === element.dslName && component !== undefined && TopologyUtils.isComponentInternal(component.component.label)) { return this.getIconForComponent(component?.component.title, component?.component.label); } else if (element.dslName === "ToDefinition" && (element as ToDefinition).uri?.startsWith("kamelet:")) { return k ? this.getIconFromSource(k.icon()) : CamelUi.getIconForDslName(element.dslName); - } else if (element.dslName === "ToDefinition" && component && CamelUi.isComponentInternal(component.component.label)) { + } else if (element.dslName === "ToDefinition" && component && TopologyUtils.isComponentInternal(component.component.label)) { return this.getIconForComponent(component?.component.title, component?.component.label); } else { return this.getIconForDslName(element.dslName); } } + static getIconForDslName = (dslName: string): JSX.Element => { switch (dslName) { case 'AggregateDefinition': @@ -761,15 +738,33 @@ export class CamelUi { const uri = (element as any).uri; const component = ComponentApi.findByName(uri); if (component) { - return CamelUi.getIconForComponent(component.component.title, component.component.label); + const reactElement = CamelUi.getIconForComponent(component.component.title, component.component.label); + const icon = 'data:image/svg+xml,' + encodeURI(renderToStaticMarkup((reactElement))) + return ( + <svg className="icon"> + <image href={icon} className="icon"/> + </svg> + ) } else if (["FromDefinition", "KameletDefinition"].includes(element.dslName)) { const icon = k ? k.icon() : externalIcon; - return <img src={icon} className="icon"/> + return ( + <svg className="icon"> + <image href={icon} className="icon"/> + </svg> + ) } else if (element.dslName === "ToDefinition" && (element as ToDefinition).uri?.startsWith("kamelet:")) { const icon = k ? k.icon() : CamelUi.getIconSrcForName(element.dslName); - return <img src={icon} className="icon"/> + return ( + <svg className="icon"> + <image href={icon} className="icon"/> + </svg> + ) } else { - return <img src={externalIcon} className="icon"/>; + return ( + <svg className="icon"> + <image href={externalIcon} className="icon"/> + </svg> + ) } } diff --git a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx index c207900a..1f2a623b 100644 --- a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx @@ -60,6 +60,7 @@ export function ProjectPage() { <FlexItem className="project-tabs"> {showTabs() && <Tabs activeKey={tab} onSelect={(event, tabIndex) => setTab(tabIndex)}> <Tab eventKey="files" title="Files"/> + <Tab eventKey="topology" title="Topology"/> <Tab eventKey="dashboard" title="Dashboard"/> <Tab eventKey="trace" title="Trace"/> <Tab eventKey="build" title="Build"/> diff --git a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPanel.tsx b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPanel.tsx index 512530b1..402cf7d1 100644 --- a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPanel.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPanel.tsx @@ -16,6 +16,7 @@ import {ContainerButtons} from "./container/ContainerButtons"; import {ProjectContainerTab} from "./container/ProjectContainerTab"; import {KameletModal} from "../knowledgebase/kamelets/KameletModal"; import {KameletCard} from "../knowledgebase/kamelets/KameletCard"; +import {TopologyTab} from "./topology/TopologyTab"; export function ProjectPanel() { @@ -38,21 +39,22 @@ export function ProjectPanel() { } const buildIn = isBuildIn(); - return ( - <PageSection padding={{default: 'noPadding'}} className="scrollable-out"> + const isTopology = tab === 'topology'; + return isTopology + ? (<TopologyTab/>) + : (<PageSection padding={{default: 'noPadding'}} className="scrollable-out"> <PageSection isFilled padding={{default: 'noPadding'}} className="scrollable-in"> <Flex direction={{default: "column"}} spaceItems={{default: "spaceItemsNone"}}> {tab === 'files' && <FlexItem><FilesTab/></FlexItem>} {!buildIn && tab === 'dashboard' && project && <FlexItem><DashboardTab/></FlexItem>} {!buildIn && tab === 'trace' && project && <FlexItem><TraceTab/></FlexItem>} {!buildIn && tab === 'build' && <FlexItem><ProjectBuildTab/></FlexItem>} - {!buildIn && tab === 'build' && config.infrastructure !== 'kubernetes' && <FlexItem><ImagesPanel/></FlexItem>} + {!buildIn && tab === 'build' && config.infrastructure !== 'kubernetes' && + <FlexItem><ImagesPanel/></FlexItem>} {!buildIn && tab === 'container' && <FlexItem><ProjectContainerTab/></FlexItem>} - {!buildIn && tab === 'container' && config.infrastructure !== 'kubernetes' && <FlexItem><ImagesPanel/></FlexItem>} + {!buildIn && tab === 'container' && config.infrastructure !== 'kubernetes' && + <FlexItem><ImagesPanel/></FlexItem>} </Flex> </PageSection> - </PageSection> - - - ) + </PageSection>) } diff --git a/karavan-web/karavan-app/src/main/webui/src/project/topology/CustomNode.tsx b/karavan-web/karavan-app/src/main/webui/src/project/topology/CustomNode.tsx new file mode 100644 index 00000000..40a5995d --- /dev/null +++ b/karavan-web/karavan-app/src/main/webui/src/project/topology/CustomNode.tsx @@ -0,0 +1,42 @@ +import * as React from 'react'; +import { RegionsIcon } from '@patternfly/react-icons'; + +import { DefaultNode, observer} from '@patternfly/react-topology'; +import {getDesignerIcon} from "../../designer/utils/KaravanIcons"; +import {CamelUi} from "../../designer/utils/CamelUi"; +import './topology.css'; + +function getIcon(data: any) { + if (data.icon === 'route') { + return ( + <g transform={`translate(14, 14)`}> + {getDesignerIcon('routes')} + </g> + ) + } else if (data.icon === 'element') { + return ( + <g transform={`translate(14, 14)`}> + {CamelUi.getConnectionIcon(data.step)} + </g> + ) + } + return <RegionsIcon/>; +} + +const CustomNode: React.FC<any> = observer(({ element, ...rest }) => { + const data = element.getData(); + + return ( + <DefaultNode + className="common-node" + element={element} {...rest} + // badge={data.badge} + // badgeColor={} + // badgeTextColor={badgeColors?.badgeTextColor} + // badgeBorderColor={badgeColors?.badgeBorderColor} + > + {getIcon(data)} + </DefaultNode> + ) +}) +export default CustomNode; \ No newline at end of file diff --git a/karavan-web/karavan-app/src/main/webui/src/project/topology/TopologyApi.tsx b/karavan-web/karavan-app/src/main/webui/src/project/topology/TopologyApi.tsx new file mode 100644 index 00000000..3695825e --- /dev/null +++ b/karavan-web/karavan-app/src/main/webui/src/project/topology/TopologyApi.tsx @@ -0,0 +1,168 @@ +import { + ComponentFactory, + DefaultEdge, + DefaultGroup, + EdgeModel, + GraphComponent, + Model, + ModelKind, + NodeModel, + NodeShape, + NodeStatus, + withDragNode, + withPanZoom +} from '@patternfly/react-topology'; +import CustomNode from "./CustomNode"; +import {ProjectFile} from "../../api/ProjectModels"; +import {Integration} from "karavan-core/lib/model/IntegrationDefinition"; +import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml"; +import {TopologyUtils} from "karavan-core/lib/api/TopologyUtils"; +import {TopologyIncomingNode, TopologyOutgoingNode, TopologyRouteNode} from "karavan-core/lib/model/TopologyDefinition"; + +const NODE_DIAMETER = 60; + +export function getIntegrations(files: ProjectFile[]): Integration[] { + return files.filter((file) => file.name.endsWith(".camel.yaml")).map((file) => { + return CamelDefinitionYaml.yamlToIntegration(file.name, file.code); + }) +} + +export function getIncomings(tins: TopologyIncomingNode[]): NodeModel[] { + return tins.map(tin => { + return { + id: tin.id, + type: 'node', + label: tin.title, + width: NODE_DIAMETER, + height: NODE_DIAMETER, + shape: NodeShape.ellipse, + status: NodeStatus.default, + data: { + isAlternate: false, + badge: tin.type, + icon: 'element', + step: tin.from, + } + } + }); +} + +export function getRoutes(tins: TopologyRouteNode[]): NodeModel[] { + return tins.map(tin => { + const node: NodeModel = { + id: tin.id, + type: 'node', + label: tin.title, + width: NODE_DIAMETER, + height: NODE_DIAMETER, + shape: NodeShape.rect, + status: NodeStatus.default, + data: { + isAlternate: false, + icon: 'route' + } + } + return node; + }); +} + +export function getOutgoings(tons: TopologyOutgoingNode[]): NodeModel[] { + return tons.map(tin => { + const node: NodeModel = { + id: tin.id, + type: 'node', + label: tin.title, + width: NODE_DIAMETER, + height: NODE_DIAMETER, + shape: NodeShape.ellipse, + status: NodeStatus.default, + data: { + isAlternate: false, + icon: 'element', + step: tin.step, + badge: tin.type + } + } + return node; + }); +} + +export function getIncomingEdges(tins: TopologyIncomingNode[]): EdgeModel[] { + return tins.map(tin => { + const node: EdgeModel = { + id: 'edge-incoming-' + tin.routeId, + type: 'edge', + source: tin.id, + target: 'route-' + tin.routeId + } + return node; + }); +} + +export function getOutgoingEdges(tons: TopologyOutgoingNode[]): EdgeModel[] { + return tons.map(tin => { + const node: EdgeModel = { + id: 'edge-outgoing-' + tin.routeId + '-' + (tin.step as any).id, + type: 'edge', + source: 'route-' + tin.routeId, + target: tin.id + } + return node; + }); +} + +export function getModel(files: ProjectFile[]): Model { + const integrations = getIntegrations(files); + const tins = TopologyUtils.findTopologyIncomingNodes(integrations); + const troutes = TopologyUtils.findTopologyRouteNodes(integrations); + const tons = TopologyUtils.findTopologyOutgoingNodes(integrations); + const trestns = TopologyUtils.findTopologyRestNodes(integrations); + + const nodes: NodeModel[] = []; + const groups: NodeModel[] = troutes.map(r => { + const children = [r.id] + children.push(... tins.filter(i => i.routeId === r.routeId).map(i => i.id)); + children.push(... tons.filter(i => i.routeId === r.routeId).map(i => i.id)); + return { + id: 'group-' + r.routeId, + children: children, + type: 'group', + group: true, + label: r.title, + style: { + padding: 40 + } + } + }) + + nodes.push(...getIncomings(tins)) + nodes.push(...getRoutes(troutes)) + nodes.push(...getOutgoings(tons)) + nodes.push(...groups) + // nodes.push(...groups2) + + const edges: EdgeModel[] = []; + edges.push(...getIncomingEdges(tins)); + edges.push(...getOutgoingEdges(tons)); + + return {nodes: nodes, edges: edges, graph: {id: 'g1', type: 'graph', layout: 'Dagre'}}; +} + +export const customComponentFactory: ComponentFactory = (kind: ModelKind, type: string) => { + switch (type) { + case 'group': + return DefaultGroup; + default: + switch (kind) { + case ModelKind.graph: + return withPanZoom()(GraphComponent); + case ModelKind.node: + return withDragNode()(CustomNode); + // return CustomNode; + case ModelKind.edge: + return DefaultEdge; + default: + return undefined; + } + } +} \ No newline at end of file diff --git a/karavan-web/karavan-app/src/main/webui/src/project/topology/TopologyTab.tsx b/karavan-web/karavan-app/src/main/webui/src/project/topology/TopologyTab.tsx new file mode 100644 index 00000000..dea2f52a --- /dev/null +++ b/karavan-web/karavan-app/src/main/webui/src/project/topology/TopologyTab.tsx @@ -0,0 +1,74 @@ +import * as React from 'react'; +import { + ToolbarItem +} from '@patternfly/react-core'; +import { + action, + createTopologyControlButtons, + defaultControlButtonsOptions, + GRAPH_LAYOUT_END_EVENT, + TopologyView, + TopologyControlBar, + Visualization, + VisualizationProvider, + VisualizationSurface, DagreLayout, ColaLayout, ForceLayout, ColaGroupsLayout, GridLayout, +} from '@patternfly/react-topology'; +import {customComponentFactory, getModel} from "./TopologyApi"; +import {useFilesStore, useProjectStore} from "../../api/ProjectStore"; +import {shallow} from "zustand/shallow"; + +export const TopologyTab: React.FC = () => { + + const [files] = useFilesStore((s) => [s.files], shallow); + const [project] = useProjectStore((s) => [s.project], shallow); + + const controller = React.useMemo(() => { + const model = getModel(files); + const newController = new Visualization(); + newController.registerLayoutFactory((_, graph) => new DagreLayout(graph)); + newController.registerComponentFactory(customComponentFactory); + + newController.addEventListener(GRAPH_LAYOUT_END_EVENT, () => { + newController.getGraph().fit(80); + }); + + newController.fromModel(model, false); + return newController; + }, []); + + React.useEffect(() => { + const model = getModel(files); + controller.fromModel(model, false); + }, []); + + return ( + <TopologyView + viewToolbar={<ToolbarItem>{}</ToolbarItem>} + controlBar={ + <TopologyControlBar + controlButtons={createTopologyControlButtons({ + ...defaultControlButtonsOptions, + zoomInCallback: action(() => { + controller.getGraph().scaleBy(4 / 3); + }), + zoomOutCallback: action(() => { + controller.getGraph().scaleBy(0.75); + }), + fitToScreenCallback: action(() => { + controller.getGraph().fit(80); + }), + resetViewCallback: action(() => { + controller.getGraph().reset(); + controller.getGraph().layout(); + }), + legend: false + })} + /> + } + > + <VisualizationProvider controller={controller}> + <VisualizationSurface /> + </VisualizationProvider> + </TopologyView> + ); +}; \ No newline at end of file diff --git a/karavan-web/karavan-app/src/main/webui/src/project/topology/TopologyToolbar.tsx b/karavan-web/karavan-app/src/main/webui/src/project/topology/TopologyToolbar.tsx new file mode 100644 index 00000000..3036c5bb --- /dev/null +++ b/karavan-web/karavan-app/src/main/webui/src/project/topology/TopologyToolbar.tsx @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React, {useEffect, useState} from 'react'; +import { + Button, + Flex, + FlexItem, Form, FormGroup, FormHelperText, Label, Modal, ModalVariant, TextInput, Tooltip, TooltipPosition, +} from '@patternfly/react-core'; +import '../../designer/karavan.css'; +import UploadIcon from "@patternfly/react-icons/dist/esm/icons/upload-icon"; +import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon"; +import {useFilesStore, useFileStore, useProjectStore} from "../../api/ProjectStore"; +import {shallow} from "zustand/shallow"; +import {ProjectService} from "../../api/ProjectService"; +import PushIcon from "@patternfly/react-icons/dist/esm/icons/code-branch-icon"; + +export function TopologyToolbar () { + + const [project, isPushing] = useProjectStore((state) => [state.project, state.isPushing], shallow ) + const {files} = useFilesStore(); + const [file, editAdvancedProperties, setEditAdvancedProperties, setAddProperty] = useFileStore((state) => + [state.file, state.editAdvancedProperties, state.setEditAdvancedProperties, state.setAddProperty], shallow ) + + + useEffect(() => { + }, [project, file]); + + function canAddFiles(): boolean { + return !['templates', 'services'].includes(project.projectId); + } + + return <Flex className="toolbar" direction={{default: "row"}} justifyContent={{default: "justifyContentFlexEnd"}}> + + </Flex> +} diff --git a/karavan-web/karavan-app/src/main/webui/src/project/topology/topology.css b/karavan-web/karavan-app/src/main/webui/src/project/topology/topology.css new file mode 100644 index 00000000..f39a1941 --- /dev/null +++ b/karavan-web/karavan-app/src/main/webui/src/project/topology/topology.css @@ -0,0 +1,4 @@ +.karavan .common-node .icon { + height: 32px; + width: 32px; +} \ No newline at end of file