diff --git a/package.json b/package.json index 72e8cf5..b7b85dd 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,6 @@ "@angular/compiler": "^17.0.7", "@angular/compiler-cli": "^17.0.7", "@angular/localize": "^17.0.7", - "@types/dagre": "0.7.48", "@types/jasmine": "~4.3.0", "@types/lodash": "^4.14.196", "@types/node": "18.11.9", @@ -58,7 +57,7 @@ "@angular/material": "^17.0.4", "@angular/platform-browser": "^17.0.7", "@angular/platform-browser-dynamic": "^17.0.7", - "dagre": "^0.8.5", + "@dagrejs/dagre": "1.1.3", "lodash": "^4.17.21", "rxjs": "7.5.7", "safevalues": "^1.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f4d0c83..a167c04 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,9 +35,9 @@ importers: '@angular/platform-browser-dynamic': specifier: ^17.0.7 version: 17.3.12(@angular/common@17.3.12(@angular/core@17.3.12(rxjs@7.5.7)(zone.js@0.14.10))(rxjs@7.5.7))(@angular/compiler@17.3.12(@angular/core@17.3.12(rxjs@7.5.7)(zone.js@0.14.10)))(@angular/core@17.3.12(rxjs@7.5.7)(zone.js@0.14.10))(@angular/platform-browser@17.3.12(@angular/animations@17.3.12(@angular/core@17.3.12(rxjs@7.5.7)(zone.js@0.14.10)))(@angular/common@17.3.12(@angular/core@17.3.12(rxjs@7.5.7)(zone.js@0.14.10))(rxjs@7.5.7))(@angular/core@17.3.12(rxjs@7.5.7)(zone.js@0.14.10))) - dagre: - specifier: ^0.8.5 - version: 0.8.5 + '@dagrejs/dagre': + specifier: 1.1.3 + version: 1.1.3 lodash: specifier: ^4.17.21 version: 4.17.21 @@ -45,8 +45,8 @@ importers: specifier: 7.5.7 version: 7.5.7 safevalues: - specifier: ^0.4.3 - version: 0.4.3 + specifier: ^1.0.1 + version: 1.2.0 systemjs: specifier: 6.1.2 version: 6.1.2 @@ -75,9 +75,6 @@ importers: '@angular/localize': specifier: ^17.0.7 version: 17.3.12(@angular/compiler-cli@17.3.12(@angular/compiler@17.3.12(@angular/core@17.3.12(rxjs@7.5.7)(zone.js@0.14.10)))(typescript@5.2.2))(@angular/compiler@17.3.12(@angular/core@17.3.12(rxjs@7.5.7)(zone.js@0.14.10))) - '@types/dagre': - specifier: 0.7.48 - version: 0.7.48 '@types/jasmine': specifier: ~4.3.0 version: 4.3.0 @@ -1031,6 +1028,13 @@ packages: resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} + '@dagrejs/dagre@1.1.3': + resolution: {integrity: sha512-umT7fBPECI4zgxxXW07H3vJN7W1WZcnBjk613eOEAKcwoFrYNyMZO+1SHmoC8zPZWR18DquK2wRUp9VHUE+94g==} + + '@dagrejs/graphlib@2.2.2': + resolution: {integrity: sha512-CbyGpCDKsiTg/wuk79S7Muoj8mghDGAESWGxcSyhHX5jD35vYMBZochYVFzlHxynpE9unpu6O+4ZuhrLxASsOg==} + engines: {node: '>17.0.0'} + '@discoveryjs/json-ext@0.5.7': resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} engines: {node: '>=10.0.0'} @@ -2096,9 +2100,6 @@ packages: '@types/cors@2.8.13': resolution: {integrity: sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==} - '@types/dagre@0.7.48': - resolution: {integrity: sha512-rF3yXSwHIrDxEkN6edCE4TXknb5YSEpiXfLaspw1I08grC49ZFuAVGOQCmZGIuLUGoFgcqGlUFBL/XrpgYpQgw==} - '@types/estree@1.0.0': resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==} @@ -2650,9 +2651,6 @@ packages: custom-event@1.0.1: resolution: {integrity: sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==} - dagre@0.8.5: - resolution: {integrity: sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==} - date-format@4.0.14: resolution: {integrity: sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==} engines: {node: '>=4.0'} @@ -3096,6 +3094,7 @@ packages: glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} @@ -3114,9 +3113,6 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - graphlib@2.1.8: - resolution: {integrity: sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==} - handle-thing@2.0.1: resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==} @@ -3256,6 +3252,7 @@ packages: inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. inherits@2.0.3: resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} @@ -4274,6 +4271,7 @@ packages: rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rollup@4.24.4: @@ -4306,8 +4304,8 @@ packages: safevalues@0.3.4: resolution: {integrity: sha512-LRneZZRXNgjzwG4bDQdOTSbze3fHm1EAKN/8bePxnlEZiBmkYEDggaHbuvHI9/hoqHbGfsEA7tWS9GhYHZBBsw==} - safevalues@0.4.3: - resolution: {integrity: sha512-pNCNTkx3xs7G5YJ/9CoeZZVUSPRjH0SEPM0QI5Z1FZRlLBviTFWlNKPs8PTvZvERV0gO7ie/t/Zc0S96JS4Xew==} + safevalues@1.2.0: + resolution: {integrity: sha512-zIsuhjYvJCjfsfjoim2ab6gLKFYAnTiDSJGh0cC3T44L/4kNLL90hBG2BzrXPrHA3f8Ms8FSJ1mljKH5dVR1cw==} sass-loader@14.1.1: resolution: {integrity: sha512-QX8AasDg75monlybel38BZ49JP5Z+uSKfKwF2rO7S74BywaRmGQMUBw9dtkS+ekyM/QnP+NOrRYq8ABMZ9G8jw==} @@ -6254,6 +6252,12 @@ snapshots: '@colors/colors@1.5.0': {} + '@dagrejs/dagre@1.1.3': + dependencies: + '@dagrejs/graphlib': 2.2.2 + + '@dagrejs/graphlib@2.2.2': {} + '@discoveryjs/json-ext@0.5.7': {} '@esbuild/aix-ppc64@0.19.12': @@ -7477,8 +7481,6 @@ snapshots: dependencies: '@types/node': 18.11.9 - '@types/dagre@0.7.48': {} - '@types/estree@1.0.0': {} '@types/estree@1.0.6': {} @@ -8104,11 +8106,6 @@ snapshots: custom-event@1.0.1: {} - dagre@0.8.5: - dependencies: - graphlib: 2.1.8 - lodash: 4.17.21 - date-format@4.0.14: {} debug@2.6.9: @@ -8644,10 +8641,6 @@ snapshots: graceful-fs@4.2.11: {} - graphlib@2.1.8: - dependencies: - lodash: 4.17.21 - handle-thing@2.0.1: {} has-flag@3.0.0: {} @@ -9913,7 +9906,7 @@ snapshots: safevalues@0.3.4: {} - safevalues@0.4.3: {} + safevalues@1.2.0: {} sass-loader@14.1.1(sass@1.71.1)(webpack@5.94.0(esbuild@0.20.1)): dependencies: diff --git a/src/app/data_types_internal.ts b/src/app/data_types_internal.ts index e6d7e98..1d4724a 100644 --- a/src/app/data_types_internal.ts +++ b/src/app/data_types_internal.ts @@ -489,6 +489,13 @@ export interface FeatureToggleOptions { * Custom themes can override the theme behavior. */ theme?: Theme; + + /** + * Whether the layout should respect the order of the nodes in the graph + * instead of optimizing for space according to the layout algorithm. + * Defaults to `false`. + */ + respectNodeOrder?: boolean; } /** * Default set of functionality to enable / disable in the DAG Component @@ -513,6 +520,7 @@ export const defaultFeatures: FeatureToggleOptions = { hideProgressCell: false, disableLoadingMaterialStyles: false, theme: 'light', + respectNodeOrder: false, }; /** diff --git a/src/app/directed_acyclic_graph.spec.ts b/src/app/directed_acyclic_graph.spec.ts index e7f2ad5..45fdf16 100644 --- a/src/app/directed_acyclic_graph.spec.ts +++ b/src/app/directed_acyclic_graph.spec.ts @@ -19,7 +19,6 @@ import {CdkDragMove} from '@angular/cdk/drag-drop'; import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed'; import {Component, EventEmitter, Input, ViewChild} from '@angular/core'; import {ComponentFixture, fakeAsync, flush, TestBed, tick, waitForAsync} from '@angular/core/testing'; -import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '@angular/platform-browser-dynamic/testing'; import {ScreenshotTest} from '../screenshot_test'; @@ -28,7 +27,6 @@ import {DagStateService} from './dag-state.service'; import {STATE_SERVICE_PROVIDER} from './dag-state.service.provider'; import {DirectedAcyclicGraph, DirectedAcyclicGraphModule, generateTheme} from './directed_acyclic_graph'; import {DagNode as Node, type GraphSpec, type NodeRef} from './node_spec'; -import {TEST_IMPORTS, TEST_PROVIDERS} from './test_providers'; import {DirectedAcyclicGraphHarness} from './test_resources/directed_acyclic_graph_harness'; import {createDagSkeletonWithCustomGroups, createDagSkeletonWithGroups, fakeGraph, fakeGraphWithEdgeOffsets} from './test_resources/fake_data'; import {initTestBed} from './test_resources/test_utils'; @@ -140,7 +138,7 @@ describe('Directed Acyclic Graph Renderer', () => { fixture.destroy(); })); - function setup( + async function setup( options: {hideControlNodeOnExpand?: boolean, expanded?: boolean} = {}) { const { @@ -153,16 +151,17 @@ describe('Directed Acyclic Graph Renderer', () => { Node.createFromSkeleton(skeleton.skeleton, skeleton.state); fixture.componentRef.setInput('graph', graphSpec); fixture.detectChanges(); + await fixture.whenStable(); } it('renders correctly', async () => { - setup(); + await setup(); await screenShot.expectMatch(`graph_custom_control_node`); }); it('renders correctly with group expanded and control hidden', async () => { - setup({expanded: true}); + await setup({expanded: true}); await screenShot.expectMatch( `graph_expanded_with_custom_control_node_hidden`); }); diff --git a/src/app/directed_acyclic_graph.ts b/src/app/directed_acyclic_graph.ts index 6f3752e..0e436ac 100644 --- a/src/app/directed_acyclic_graph.ts +++ b/src/app/directed_acyclic_graph.ts @@ -20,7 +20,7 @@ import {CdkDragEnd, CdkDragMove, CdkDragStart, DragDropModule} from '@angular/cd import {CommonModule} from '@angular/common'; import {ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ElementRef, EventEmitter, Input, NgModule, OnDestroy, OnInit, Optional, Output, TemplateRef, ViewChild} from '@angular/core'; import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; -import * as dagre from 'dagre'; // from //third_party/javascript/typings/dagre +import * as dagre from '@dagrejs/dagre'; import {Subject, Subscription} from 'rxjs'; import {takeUntil, throttleTime} from 'rxjs/operators'; diff --git a/src/app/directed_acyclic_graph_raw.ts b/src/app/directed_acyclic_graph_raw.ts index c4d3730..5630374 100644 --- a/src/app/directed_acyclic_graph_raw.ts +++ b/src/app/directed_acyclic_graph_raw.ts @@ -19,7 +19,7 @@ import {LiveAnnouncer} from '@angular/cdk/a11y'; import {CdkDrag, CdkDragMove, CdkDragStart, DragDropModule} from '@angular/cdk/drag-drop'; import {CommonModule} from '@angular/common'; import {ChangeDetectionStrategy, ChangeDetectorRef, Component, DoCheck, ElementRef, EventEmitter, Input, KeyValueDiffer, KeyValueDiffers, NgModule, OnDestroy, OnInit, Optional, Output, QueryList, TemplateRef, ViewChildren} from '@angular/core'; -import * as dagre from 'dagre'; // from //third_party/javascript/typings/dagre +import * as dagre from '@dagrejs/dagre'; import {Subscription} from 'rxjs'; import {DagStateService} from './dag-state.service'; @@ -637,7 +637,10 @@ export class DagRaw implements DoCheck, OnInit, OnDestroy { for (const node of this.nodes) { g.setNode(node.id, setNodeSizeProps(node, this.dims, this.collapsed)); } - dagre.layout(g); + + dagre.layout(g, { + disableOptimalOrderHeuristic: this.features.respectNodeOrder ?? false + }); this.positionAllElementsOnGraph(); @@ -697,7 +700,9 @@ export class DagRaw implements DoCheck, OnInit, OnDestroy { g.setEdge(e.from, e.to, e); } - dagre.layout(g); + dagre.layout(g, { + disableOptimalOrderHeuristic: this.features.respectNodeOrder ?? false + }); this.positionAllElementsOnGraph(); this.updateGraphSize(); diff --git a/src/app/scuba_goldens/directed_acyclic_graph/chrome-linux/graph_expanded_with_custom_control_node_hidden.png b/src/app/scuba_goldens/directed_acyclic_graph/chrome-linux/graph_expanded_with_custom_control_node_hidden.png index a28878f..0055ec2 100644 Binary files a/src/app/scuba_goldens/directed_acyclic_graph/chrome-linux/graph_expanded_with_custom_control_node_hidden.png and b/src/app/scuba_goldens/directed_acyclic_graph/chrome-linux/graph_expanded_with_custom_control_node_hidden.png differ