chore (litmus-portal): Added argo workflow representation using dagre d3 graph (#1975)
- Argo workflow representation using dagre d3 - Subscription fixes - removed unnecessary re-rendering - refactoring of few components - renaming to appropriate names for few components Signed-off-by: arkajyotiMukherjee <arkajyoti.mukherjee@mayadata.io>
This commit is contained in:
parent
85a0fede89
commit
7f7cb65980
|
@ -18,6 +18,15 @@
|
|||
}
|
||||
},
|
||||
"rules": {
|
||||
"new-cap": 0,
|
||||
"no-underscore-dangle": 0,
|
||||
"react/static-property-placement": [
|
||||
"warn",
|
||||
"property assignment",
|
||||
{ "defaultProps": "static public field" }
|
||||
],
|
||||
"lines-between-class-members": 0,
|
||||
"no-restricted-syntax": 0,
|
||||
"no-nested-ternary": 0,
|
||||
"no-plusplus": 0,
|
||||
"dot-notation": 0,
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
/// <reference types="Cypress" />
|
||||
import React from 'react';
|
||||
import { mount } from 'cypress-react-unit-test';
|
||||
|
||||
import CustomSlider from '../../src/components/Sections/Workflow/WeightSlider';
|
||||
import React from 'react';
|
||||
import CustomSlider from '../../src/components/Sections/CreateWorkflow/WeightSlider';
|
||||
|
||||
describe('Testing Custom Slider with different values', () => {
|
||||
[10, 5, 2].map((i) => {
|
||||
|
|
|
@ -2612,9 +2612,142 @@
|
|||
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
|
||||
},
|
||||
"@types/d3": {
|
||||
"version": "3.5.43",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3/-/d3-3.5.43.tgz",
|
||||
"integrity": "sha512-t9ZmXOcpVxywRw86YtIC54g7M9puRh8hFedRvVfHKf5YyOP6pSxA0TvpXpfseXSCInoW4P7bggTrSDiUOs4g5w==",
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3/-/d3-5.7.2.tgz",
|
||||
"integrity": "sha512-7/wClB8ycneWGy3jdvLfXKTd5SoTg9hji7IdJ0RuO9xTY54YpJ8zlcFADcXhY1J3kCBwxp+/1jeN6a5OMwgYOw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/d3-array": "^1",
|
||||
"@types/d3-axis": "*",
|
||||
"@types/d3-brush": "*",
|
||||
"@types/d3-chord": "*",
|
||||
"@types/d3-collection": "*",
|
||||
"@types/d3-color": "*",
|
||||
"@types/d3-contour": "*",
|
||||
"@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-voronoi": "*",
|
||||
"@types/d3-zoom": "*"
|
||||
}
|
||||
},
|
||||
"@types/d3-array": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-1.2.7.tgz",
|
||||
"integrity": "sha512-51vHWuUyDOi+8XuwPrTw3cFqyh2Slg9y8COYkRfjCPG9TfYqY0hoNPzv/8BrcAy0FeQBzqEo/D/8Nk2caOQJnA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-axis": {
|
||||
"version": "1.0.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-1.0.12.tgz",
|
||||
"integrity": "sha512-BZISgSD5M8TgURyNtcPAmUB9sk490CO1Thb6/gIn0WZTt3Y50IssX+2Z0vTccoqZksUDTep0b+o4ofXslvNbqg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/d3-selection": "*"
|
||||
}
|
||||
},
|
||||
"@types/d3-brush": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-1.1.1.tgz",
|
||||
"integrity": "sha512-Exx14trm/q2cskHyMjCrdDllOQ35r1/pmZXaOIt8bBHwYNk722vWY3VxHvN0jdFFX7p2iL3+gD+cGny/aEmhlw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/d3-selection": "*"
|
||||
}
|
||||
},
|
||||
"@types/d3-chord": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-1.0.9.tgz",
|
||||
"integrity": "sha512-UA6lI9CVW5cT5Ku/RV4hxoFn4mKySHm7HEgodtfRthAj1lt9rKZEPon58vyYfk+HIAm33DtJJgZwMXy2QgyPXw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-collection": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-collection/-/d3-collection-1.0.8.tgz",
|
||||
"integrity": "sha512-y5lGlazdc0HNO0F3UUX2DPE7OmYvd9Kcym4hXwrJcNUkDaypR5pX+apuMikl9LfTxKItJsY9KYvzBulpCKyvuQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-color": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-1.2.2.tgz",
|
||||
"integrity": "sha512-6pBxzJ8ZP3dYEQ4YjQ+NVbQaOflfgXq/JbDiS99oLobM2o72uAST4q6yPxHv6FOTCRC/n35ktuo8pvw/S4M7sw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-contour": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-1.3.0.tgz",
|
||||
"integrity": "sha512-AUCUIjEnC5lCGBM9hS+MryRaFLIrPls4Rbv6ktqbd+TK/RXZPwOy9rtBWmGpbeXcSOYCJTUDwNJuEnmYPJRxHQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/d3-array": "*",
|
||||
"@types/geojson": "*"
|
||||
}
|
||||
},
|
||||
"@types/d3-dispatch": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-1.0.8.tgz",
|
||||
"integrity": "sha512-lCDtqoYez0TgFN3FljBXrz2icqeSzD0gufGook6DPBia+NOh2TBfogjHIsmNa/a+ZOewlHtq4cgLY80O1uLymw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-drag": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-1.2.3.tgz",
|
||||
"integrity": "sha512-rWB5SPvkYVxW3sqUxHOJUZwifD0KqvKwvt1bhNqcLpW6Azsd0BJgRNcyVW8GAferaAk5r8dzeZnf9zKlg9+xMQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/d3-selection": "*"
|
||||
}
|
||||
},
|
||||
"@types/d3-dsv": {
|
||||
"version": "1.0.36",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-1.0.36.tgz",
|
||||
"integrity": "sha512-jbIWQ27QJcBNMZbQv0NSQMHnBDCmxghAxePxgyiPH1XPCRkOsTBei7jcdi3fDrUCGpCV3lKrSZFSlOkhUQVClA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-ease": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-1.0.9.tgz",
|
||||
"integrity": "sha512-U5ADevQ+W6fy32FVZZC9EXallcV/Mi12A5Tkd0My5MrC7T8soMQEhlDAg88XUWm0zoCQlB4XV0en/24LvuDB4Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-fetch": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-1.1.5.tgz",
|
||||
"integrity": "sha512-o9c0ItT5/Gl3wbNuVpzRnYX1t3RghzeWAjHUVLuyZJudiTxC4f/fC0ZPFWLQ2lVY8pAMmxpV8TJ6ETYCgPeI3A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/d3-dsv": "*"
|
||||
}
|
||||
},
|
||||
"@types/d3-force": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-1.2.1.tgz",
|
||||
"integrity": "sha512-jqK+I36uz4kTBjyk39meed5y31Ab+tXYN/x1dn3nZEus9yOHCLc+VrcIYLc/aSQ0Y7tMPRlIhLetulME76EiiA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-format": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-1.3.1.tgz",
|
||||
"integrity": "sha512-KAWvReOKMDreaAwOjdfQMm0HjcUMlQG47GwqdVKgmm20vTd2pucj0a70c3gUSHrnsmo6H2AMrkBsZU2UhJLq8A==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-geo": {
|
||||
|
@ -2626,6 +2759,142 @@
|
|||
"@types/geojson": "*"
|
||||
}
|
||||
},
|
||||
"@types/d3-hierarchy": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-1.1.6.tgz",
|
||||
"integrity": "sha512-vvSaIDf/Ov0o3KwMT+1M8+WbnnlRiGjlGD5uvk83a1mPCTd/E5x12bUJ/oP55+wUY/4Kb5kc67rVpVGJ2KUHxg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-interpolate": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-1.3.1.tgz",
|
||||
"integrity": "sha512-z8Zmi08XVwe8e62vP6wcA+CNuRhpuUU5XPEfqpG0hRypDE5BWNthQHB1UNWWDB7ojCbGaN4qBdsWp5kWxhT1IQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/d3-color": "*"
|
||||
}
|
||||
},
|
||||
"@types/d3-path": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.8.tgz",
|
||||
"integrity": "sha512-AZGHWslq/oApTAHu9+yH/Bnk63y9oFOMROtqPAtxl5uB6qm1x2lueWdVEjsjjV3Qc2+QfuzKIwIR5MvVBakfzA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-polygon": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-1.0.7.tgz",
|
||||
"integrity": "sha512-Xuw0eSjQQKs8jTiNbntWH0S+Xp+JyhqxmQ0YAQ3rDu6c3kKMFfgsaGN7Jv5u3zG6yVX/AsLP/Xs/QRjmi9g43Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-quadtree": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-1.0.7.tgz",
|
||||
"integrity": "sha512-0ajFawWicfjsaCLh6NzxOyVDYhQAmMFbsiI3MPGLInorauHFEh9/Cl6UHNf+kt/J1jfoxKY/ZJaKAoDpbvde5Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-random": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-1.1.2.tgz",
|
||||
"integrity": "sha512-Jui+Zn28pQw/3EayPKaN4c/PqTvqNbIPjHkgIIFnxne1FdwNjfHtAIsZIBMKlquQNrrMjFzCrlF2gPs3xckqaA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-scale": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-2.2.0.tgz",
|
||||
"integrity": "sha512-oQFanN0/PiR2oySHfj+zAAkK1/p4LD32Nt1TMVmzk+bYHk7vgIg/iTXQWitp1cIkDw4LMdcgvO63wL+mNs47YA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/d3-time": "*"
|
||||
}
|
||||
},
|
||||
"@types/d3-scale-chromatic": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz",
|
||||
"integrity": "sha512-9/D7cOBKdZdTCPc6re0HeSUFBM0aFzdNdmYggUWT9SRRiYSOa6Ys2xdTwHKgc1WS3gGfwTMatBOdWCS863REsg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-selection": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-1.4.2.tgz",
|
||||
"integrity": "sha512-ksY8UxvTXpzD91Dy3D9zZg98yF2ZEPMKJd8ZQJlZt1QH3Xxr08s6fESEdC2l0Kbe6Xd9VhaoJX06cRaMR1lEnA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-shape": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.3.2.tgz",
|
||||
"integrity": "sha512-LtD8EaNYCaBRzHzaAiIPrfcL3DdIysc81dkGlQvv7WQP3+YXV7b0JJTtR1U3bzeRieS603KF4wUo+ZkJVenh8w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/d3-path": "*"
|
||||
}
|
||||
},
|
||||
"@types/d3-time": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-1.0.10.tgz",
|
||||
"integrity": "sha512-aKf62rRQafDQmSiv1NylKhIMmznsjRN+MnXRXTqHoqm0U/UZzVpdrtRnSIfdiLS616OuC1soYeX1dBg2n1u8Xw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-time-format": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.1.1.tgz",
|
||||
"integrity": "sha512-tJSyXta8ZyJ52wDDHA96JEsvkbL6jl7wowGmuf45+fAkj5Y+SQOnz0N7/H68OWmPshPsAaWMQh+GAws44IzH3g==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-timer": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-1.0.9.tgz",
|
||||
"integrity": "sha512-WvfJ3LFxBbWjqRGz9n7GJt08RrTHPJDVsIwwoCMROlqF+iDacYiAFjf9oqnq0mXpb2juA2N/qjKP+MKdal3YNQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-transition": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-1.1.6.tgz",
|
||||
"integrity": "sha512-/F+O2r4oz4G9ATIH3cuSCMGphAnl7VDx7SbENEK0NlI/FE8Jx2oiIrv0uTrpg7yF/AmuWbqp7AGdEHAPIh24Gg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/d3-selection": "*"
|
||||
}
|
||||
},
|
||||
"@types/d3-voronoi": {
|
||||
"version": "1.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-voronoi/-/d3-voronoi-1.1.9.tgz",
|
||||
"integrity": "sha512-DExNQkaHd1F3dFPvGA/Aw2NGyjMln6E9QzsiqOcBgnE+VInYnFBHBBySbZQts6z6xD+5jTfKCP7M4OqMyVjdwQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-zoom": {
|
||||
"version": "1.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-1.7.4.tgz",
|
||||
"integrity": "sha512-5jnFo/itYhJeB2khO/lKe730kW/h2EbKMOvY0uNp3+7NdPm4w63DwPEMxifQZ7n902xGYK5DdU67FmToSoy4VA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/d3-interpolate": "*",
|
||||
"@types/d3-selection": "*"
|
||||
}
|
||||
},
|
||||
"@types/dagre": {
|
||||
"version": "0.7.44",
|
||||
"resolved": "https://registry.npmjs.org/@types/dagre/-/dagre-0.7.44.tgz",
|
||||
"integrity": "sha512-N6HD+79w77ZVAaVO7JJDW5yJ9LAxM62FpgNGO9xEde+KVYjDRyhIMzfiErXpr1g0JPon9kwlBzoBK6s4fOww9Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/dagre-d3": {
|
||||
"version": "0.4.39",
|
||||
"resolved": "https://registry.npmjs.org/@types/dagre-d3/-/dagre-d3-0.4.39.tgz",
|
||||
"integrity": "sha512-JZySpfIQPRSTx38B4P5pPGeV4Pqgb0qE/aIiS60qD+j0c3mYP/AHiiwlsrrLCVZWY7OJdvD3dp+aD1HvpjPBzA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/d3": "^3",
|
||||
"@types/dagre": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/d3": {
|
||||
"version": "3.5.43",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3/-/d3-3.5.43.tgz",
|
||||
"integrity": "sha512-t9ZmXOcpVxywRw86YtIC54g7M9puRh8hFedRvVfHKf5YyOP6pSxA0TvpXpfseXSCInoW4P7bggTrSDiUOs4g5w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/eslint-visitor-keys": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
|
||||
|
@ -2732,6 +3001,14 @@
|
|||
"dev": true,
|
||||
"requires": {
|
||||
"@types/d3": "^3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/d3": {
|
||||
"version": "3.5.43",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3/-/d3-3.5.43.tgz",
|
||||
"integrity": "sha512-t9ZmXOcpVxywRw86YtIC54g7M9puRh8hFedRvVfHKf5YyOP6pSxA0TvpXpfseXSCInoW4P7bggTrSDiUOs4g5w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/prop-types": {
|
||||
|
@ -6766,15 +7043,74 @@
|
|||
}
|
||||
},
|
||||
"d3": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz",
|
||||
"integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g="
|
||||
"version": "5.16.0",
|
||||
"resolved": "https://registry.npmjs.org/d3/-/d3-5.16.0.tgz",
|
||||
"integrity": "sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw==",
|
||||
"requires": {
|
||||
"d3-array": "1",
|
||||
"d3-axis": "1",
|
||||
"d3-brush": "1",
|
||||
"d3-chord": "1",
|
||||
"d3-collection": "1",
|
||||
"d3-color": "1",
|
||||
"d3-contour": "1",
|
||||
"d3-dispatch": "1",
|
||||
"d3-drag": "1",
|
||||
"d3-dsv": "1",
|
||||
"d3-ease": "1",
|
||||
"d3-fetch": "1",
|
||||
"d3-force": "1",
|
||||
"d3-format": "1",
|
||||
"d3-geo": "1",
|
||||
"d3-hierarchy": "1",
|
||||
"d3-interpolate": "1",
|
||||
"d3-path": "1",
|
||||
"d3-polygon": "1",
|
||||
"d3-quadtree": "1",
|
||||
"d3-random": "1",
|
||||
"d3-scale": "2",
|
||||
"d3-scale-chromatic": "1",
|
||||
"d3-selection": "1",
|
||||
"d3-shape": "1",
|
||||
"d3-time": "1",
|
||||
"d3-time-format": "2",
|
||||
"d3-timer": "1",
|
||||
"d3-transition": "1",
|
||||
"d3-voronoi": "1",
|
||||
"d3-zoom": "1"
|
||||
}
|
||||
},
|
||||
"d3-array": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
|
||||
"integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
|
||||
},
|
||||
"d3-axis": {
|
||||
"version": "1.0.12",
|
||||
"resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.12.tgz",
|
||||
"integrity": "sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ=="
|
||||
},
|
||||
"d3-brush": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.1.6.tgz",
|
||||
"integrity": "sha512-7RW+w7HfMCPyZLifTz/UnJmI5kdkXtpCbombUSs8xniAyo0vIbrDzDwUJB6eJOgl9u5DQOt2TQlYumxzD1SvYA==",
|
||||
"requires": {
|
||||
"d3-dispatch": "1",
|
||||
"d3-drag": "1",
|
||||
"d3-interpolate": "1",
|
||||
"d3-selection": "1",
|
||||
"d3-transition": "1"
|
||||
}
|
||||
},
|
||||
"d3-chord": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.6.tgz",
|
||||
"integrity": "sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA==",
|
||||
"requires": {
|
||||
"d3-array": "1",
|
||||
"d3-path": "1"
|
||||
}
|
||||
},
|
||||
"d3-collection": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz",
|
||||
|
@ -6785,6 +7121,14 @@
|
|||
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz",
|
||||
"integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q=="
|
||||
},
|
||||
"d3-contour": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-1.3.2.tgz",
|
||||
"integrity": "sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==",
|
||||
"requires": {
|
||||
"d3-array": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"d3-dispatch": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz",
|
||||
|
@ -6799,11 +7143,29 @@
|
|||
"d3-selection": "1"
|
||||
}
|
||||
},
|
||||
"d3-dsv": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.2.0.tgz",
|
||||
"integrity": "sha512-9yVlqvZcSOMhCYzniHE7EVUws7Fa1zgw+/EAV2BxJoG3ME19V6BQFBwI855XQDsxyOuG7NibqRMTtiF/Qup46g==",
|
||||
"requires": {
|
||||
"commander": "2",
|
||||
"iconv-lite": "0.4",
|
||||
"rw": "1"
|
||||
}
|
||||
},
|
||||
"d3-ease": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.6.tgz",
|
||||
"integrity": "sha512-SZ/lVU7LRXafqp7XtIcBdxnWl8yyLpgOmzAk0mWBI9gXNzLDx5ybZgnRbH9dN/yY5tzVBqCQ9avltSnqVwessQ=="
|
||||
},
|
||||
"d3-fetch": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.2.0.tgz",
|
||||
"integrity": "sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==",
|
||||
"requires": {
|
||||
"d3-dsv": "1"
|
||||
}
|
||||
},
|
||||
"d3-force": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz",
|
||||
|
@ -6815,6 +7177,11 @@
|
|||
"d3-timer": "1"
|
||||
}
|
||||
},
|
||||
"d3-format": {
|
||||
"version": "1.4.5",
|
||||
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz",
|
||||
"integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ=="
|
||||
},
|
||||
"d3-geo": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz",
|
||||
|
@ -6841,11 +7208,43 @@
|
|||
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz",
|
||||
"integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="
|
||||
},
|
||||
"d3-polygon": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.6.tgz",
|
||||
"integrity": "sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ=="
|
||||
},
|
||||
"d3-quadtree": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.7.tgz",
|
||||
"integrity": "sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA=="
|
||||
},
|
||||
"d3-random": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.2.tgz",
|
||||
"integrity": "sha512-6AK5BNpIFqP+cx/sreKzNjWbwZQCSUatxq+pPRmFIQaWuoD+NrbVWw7YWpHiXpCQ/NanKdtGDuB+VQcZDaEmYQ=="
|
||||
},
|
||||
"d3-scale": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz",
|
||||
"integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==",
|
||||
"requires": {
|
||||
"d3-array": "^1.2.0",
|
||||
"d3-collection": "1",
|
||||
"d3-format": "1",
|
||||
"d3-interpolate": "1",
|
||||
"d3-time": "1",
|
||||
"d3-time-format": "2"
|
||||
}
|
||||
},
|
||||
"d3-scale-chromatic": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz",
|
||||
"integrity": "sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg==",
|
||||
"requires": {
|
||||
"d3-color": "1",
|
||||
"d3-interpolate": "1"
|
||||
}
|
||||
},
|
||||
"d3-selection": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.1.tgz",
|
||||
|
@ -6859,6 +7258,19 @@
|
|||
"d3-path": "1"
|
||||
}
|
||||
},
|
||||
"d3-time": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz",
|
||||
"integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA=="
|
||||
},
|
||||
"d3-time-format": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz",
|
||||
"integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==",
|
||||
"requires": {
|
||||
"d3-time": "1"
|
||||
}
|
||||
},
|
||||
"d3-timer": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz",
|
||||
|
@ -6877,6 +7289,11 @@
|
|||
"d3-timer": "1"
|
||||
}
|
||||
},
|
||||
"d3-voronoi": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz",
|
||||
"integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg=="
|
||||
},
|
||||
"d3-zoom": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.8.3.tgz",
|
||||
|
@ -6889,6 +7306,168 @@
|
|||
"d3-transition": "1"
|
||||
}
|
||||
},
|
||||
"dagre": {
|
||||
"version": "0.8.5",
|
||||
"resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz",
|
||||
"integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==",
|
||||
"requires": {
|
||||
"graphlib": "^2.1.8",
|
||||
"lodash": "^4.17.15"
|
||||
}
|
||||
},
|
||||
"dagre-d3": {
|
||||
"version": "0.6.4",
|
||||
"resolved": "https://registry.npmjs.org/dagre-d3/-/dagre-d3-0.6.4.tgz",
|
||||
"integrity": "sha512-e/6jXeCP7/ptlAM48clmX4xTZc5Ek6T6kagS7Oz2HrYSdqcLZFLqpAfh7ldbZRFfxCZVyh61NEPR08UQRVxJzQ==",
|
||||
"requires": {
|
||||
"d3": "^5.14",
|
||||
"dagre": "^0.8.5",
|
||||
"graphlib": "^2.1.8",
|
||||
"lodash": "^4.17.15"
|
||||
},
|
||||
"dependencies": {
|
||||
"d3": {
|
||||
"version": "5.16.0",
|
||||
"resolved": "https://registry.npmjs.org/d3/-/d3-5.16.0.tgz",
|
||||
"integrity": "sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw==",
|
||||
"requires": {
|
||||
"d3-array": "1",
|
||||
"d3-axis": "1",
|
||||
"d3-brush": "1",
|
||||
"d3-chord": "1",
|
||||
"d3-collection": "1",
|
||||
"d3-color": "1",
|
||||
"d3-contour": "1",
|
||||
"d3-dispatch": "1",
|
||||
"d3-drag": "1",
|
||||
"d3-dsv": "1",
|
||||
"d3-ease": "1",
|
||||
"d3-fetch": "1",
|
||||
"d3-force": "1",
|
||||
"d3-format": "1",
|
||||
"d3-geo": "1",
|
||||
"d3-hierarchy": "1",
|
||||
"d3-interpolate": "1",
|
||||
"d3-path": "1",
|
||||
"d3-polygon": "1",
|
||||
"d3-quadtree": "1",
|
||||
"d3-random": "1",
|
||||
"d3-scale": "2",
|
||||
"d3-scale-chromatic": "1",
|
||||
"d3-selection": "1",
|
||||
"d3-shape": "1",
|
||||
"d3-time": "1",
|
||||
"d3-time-format": "2",
|
||||
"d3-timer": "1",
|
||||
"d3-transition": "1",
|
||||
"d3-voronoi": "1",
|
||||
"d3-zoom": "1"
|
||||
}
|
||||
},
|
||||
"d3-axis": {
|
||||
"version": "1.0.12",
|
||||
"resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.12.tgz",
|
||||
"integrity": "sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ=="
|
||||
},
|
||||
"d3-brush": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.1.6.tgz",
|
||||
"integrity": "sha512-7RW+w7HfMCPyZLifTz/UnJmI5kdkXtpCbombUSs8xniAyo0vIbrDzDwUJB6eJOgl9u5DQOt2TQlYumxzD1SvYA==",
|
||||
"requires": {
|
||||
"d3-dispatch": "1",
|
||||
"d3-drag": "1",
|
||||
"d3-interpolate": "1",
|
||||
"d3-selection": "1",
|
||||
"d3-transition": "1"
|
||||
}
|
||||
},
|
||||
"d3-chord": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.6.tgz",
|
||||
"integrity": "sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA==",
|
||||
"requires": {
|
||||
"d3-array": "1",
|
||||
"d3-path": "1"
|
||||
}
|
||||
},
|
||||
"d3-contour": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-1.3.2.tgz",
|
||||
"integrity": "sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==",
|
||||
"requires": {
|
||||
"d3-array": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"d3-dsv": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.2.0.tgz",
|
||||
"integrity": "sha512-9yVlqvZcSOMhCYzniHE7EVUws7Fa1zgw+/EAV2BxJoG3ME19V6BQFBwI855XQDsxyOuG7NibqRMTtiF/Qup46g==",
|
||||
"requires": {
|
||||
"commander": "2",
|
||||
"iconv-lite": "0.4",
|
||||
"rw": "1"
|
||||
}
|
||||
},
|
||||
"d3-fetch": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.2.0.tgz",
|
||||
"integrity": "sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==",
|
||||
"requires": {
|
||||
"d3-dsv": "1"
|
||||
}
|
||||
},
|
||||
"d3-format": {
|
||||
"version": "1.4.5",
|
||||
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz",
|
||||
"integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ=="
|
||||
},
|
||||
"d3-polygon": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.6.tgz",
|
||||
"integrity": "sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ=="
|
||||
},
|
||||
"d3-random": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.2.tgz",
|
||||
"integrity": "sha512-6AK5BNpIFqP+cx/sreKzNjWbwZQCSUatxq+pPRmFIQaWuoD+NrbVWw7YWpHiXpCQ/NanKdtGDuB+VQcZDaEmYQ=="
|
||||
},
|
||||
"d3-scale": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz",
|
||||
"integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==",
|
||||
"requires": {
|
||||
"d3-array": "^1.2.0",
|
||||
"d3-collection": "1",
|
||||
"d3-format": "1",
|
||||
"d3-interpolate": "1",
|
||||
"d3-time": "1",
|
||||
"d3-time-format": "2"
|
||||
}
|
||||
},
|
||||
"d3-scale-chromatic": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz",
|
||||
"integrity": "sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg==",
|
||||
"requires": {
|
||||
"d3-color": "1",
|
||||
"d3-interpolate": "1"
|
||||
}
|
||||
},
|
||||
"d3-time": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz",
|
||||
"integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA=="
|
||||
},
|
||||
"d3-time-format": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz",
|
||||
"integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==",
|
||||
"requires": {
|
||||
"d3-time": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"damerau-levenshtein": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz",
|
||||
|
@ -10169,6 +10748,14 @@
|
|||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
|
||||
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw=="
|
||||
},
|
||||
"graphlib": {
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz",
|
||||
"integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==",
|
||||
"requires": {
|
||||
"lodash": "^4.17.15"
|
||||
}
|
||||
},
|
||||
"graphql": {
|
||||
"version": "15.3.0",
|
||||
"resolved": "https://registry.npmjs.org/graphql/-/graphql-15.3.0.tgz",
|
||||
|
@ -15700,6 +16287,13 @@
|
|||
"topojson-client": "^3.1.0",
|
||||
"webgl-context": "^2.2.0",
|
||||
"world-calendars": "^1.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"d3": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz",
|
||||
"integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g="
|
||||
}
|
||||
}
|
||||
},
|
||||
"pn": {
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
"@material-ui/pickers": "^3.2.10",
|
||||
"ace-builds": "^1.4.12",
|
||||
"brace": "^0.11.1",
|
||||
"d3": "^5.16.0",
|
||||
"dagre-d3": "^0.6.4",
|
||||
"date-fns": "^2.14.0",
|
||||
"graphql": "^15.3.0",
|
||||
"i18next": "^19.7.0",
|
||||
|
@ -74,6 +76,8 @@
|
|||
"not op_mini all"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/d3": "^5.7.2",
|
||||
"@types/dagre-d3": "^0.4.39",
|
||||
"@types/js-yaml": "^3.12.5",
|
||||
"@types/jsonwebtoken": "^8.5.0",
|
||||
"@types/plotly.js": "^1.50.15",
|
||||
|
|
|
@ -2,8 +2,8 @@ import Breadcrumbs from '@material-ui/core/Breadcrumbs';
|
|||
import * as React from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import useStyles from './styles';
|
||||
import { history } from '../../redux/configureStore';
|
||||
import useStyles from './styles';
|
||||
|
||||
interface CustomBreadcrumbsProps {
|
||||
location: string;
|
||||
|
@ -12,7 +12,7 @@ interface CustomBreadcrumbsProps {
|
|||
const CustomBreadcrumbs: React.FC<CustomBreadcrumbsProps> = ({ location }) => {
|
||||
const path: string[] = location.split('/');
|
||||
|
||||
let intermediatRoutes: string = '/';
|
||||
let intermediateRoutes: string = '/';
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
|
@ -22,11 +22,12 @@ const CustomBreadcrumbs: React.FC<CustomBreadcrumbsProps> = ({ location }) => {
|
|||
<Breadcrumbs aria-label="breadcrumb">
|
||||
{path.map((path: string) => {
|
||||
if (path) {
|
||||
intermediatRoutes += path;
|
||||
intermediateRoutes += path;
|
||||
|
||||
const link = (
|
||||
<Link
|
||||
to={intermediatRoutes}
|
||||
key={path}
|
||||
to={intermediateRoutes}
|
||||
className={classes.breadCrumb}
|
||||
onClick={() => {
|
||||
history.push(`/${path}`);
|
||||
|
@ -36,7 +37,7 @@ const CustomBreadcrumbs: React.FC<CustomBreadcrumbsProps> = ({ location }) => {
|
|||
</Link>
|
||||
);
|
||||
|
||||
intermediatRoutes += '/';
|
||||
intermediateRoutes += '/';
|
||||
|
||||
return link;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
import * as d3 from 'd3';
|
||||
import dagreD3, { GraphLabel, Node } from 'dagre-d3';
|
||||
import React, { Component, createRef } from 'react';
|
||||
|
||||
interface GraphProps {
|
||||
nodes: d3Node[];
|
||||
links: d3Link[];
|
||||
zoomable?: boolean;
|
||||
fitBoundaries?: boolean;
|
||||
height?: string;
|
||||
width?: string;
|
||||
config?: GraphLabel;
|
||||
animate?: number;
|
||||
className?: string;
|
||||
shape?: shapes;
|
||||
onNodeClick?: nodeClick;
|
||||
onRelationshipClick?: relationshipClick;
|
||||
}
|
||||
type shapes = 'rect' | 'circle' | 'ellipse';
|
||||
type labelType = 'html' | 'svg' | 'string';
|
||||
|
||||
type nodeClick = (nodeData: {
|
||||
d3node: Node;
|
||||
original: d3Node | undefined;
|
||||
}) => void;
|
||||
|
||||
type relationshipClick = (nodeData: {
|
||||
d3source: Node;
|
||||
source: d3Node | undefined;
|
||||
d3target: Node;
|
||||
target: d3Node | undefined;
|
||||
}) => void;
|
||||
|
||||
export type d3Node = {
|
||||
id: any;
|
||||
label: string;
|
||||
class?: string;
|
||||
labelType?: labelType;
|
||||
config?: object;
|
||||
};
|
||||
export type d3Link = {
|
||||
source: string;
|
||||
target: string;
|
||||
class?: string;
|
||||
label?: string;
|
||||
config?: object;
|
||||
};
|
||||
type Relationship = {
|
||||
v: any;
|
||||
w: any;
|
||||
};
|
||||
|
||||
class DagreGraph extends Component<GraphProps> {
|
||||
svg = createRef<SVGSVGElement>();
|
||||
innerG = createRef<SVGSVGElement>();
|
||||
|
||||
static defaultProps = {
|
||||
zoomable: false,
|
||||
fitBoundaries: false,
|
||||
className: 'dagre-d3-react',
|
||||
};
|
||||
componentDidMount() {
|
||||
this._drawChart();
|
||||
}
|
||||
componentDidUpdate() {
|
||||
this._drawChart();
|
||||
}
|
||||
|
||||
_drawChart = () => {
|
||||
const {
|
||||
nodes,
|
||||
links,
|
||||
zoomable,
|
||||
fitBoundaries,
|
||||
config,
|
||||
animate,
|
||||
shape,
|
||||
onNodeClick,
|
||||
onRelationshipClick,
|
||||
} = this.props;
|
||||
const g = new dagreD3.graphlib.Graph().setGraph(config || {});
|
||||
|
||||
nodes.forEach((node) =>
|
||||
g.setNode(node.id, {
|
||||
label: node.label,
|
||||
class: node.class || '',
|
||||
labelType: node.labelType || 'string',
|
||||
...node.config,
|
||||
})
|
||||
);
|
||||
|
||||
if (shape) {
|
||||
g.nodes().forEach((v) => {
|
||||
g.node(v).shape = shape;
|
||||
});
|
||||
}
|
||||
|
||||
links.forEach((link) => {
|
||||
g.setEdge(link.source, link.target, {
|
||||
label: link.label || '',
|
||||
class: link.class || '',
|
||||
...link.config,
|
||||
});
|
||||
});
|
||||
|
||||
const render = new dagreD3.render();
|
||||
const svg: any = d3.select(this.svg.current);
|
||||
const inner: any = d3.select(this.innerG.current);
|
||||
|
||||
const zoom = d3
|
||||
.zoom()
|
||||
.on('zoom', () => inner.attr('transform', d3.event.transform));
|
||||
|
||||
if (zoomable) {
|
||||
svg.call(zoom);
|
||||
}
|
||||
if (animate) {
|
||||
g.graph().transition = function transition(selection) {
|
||||
return selection.transition().duration(animate || 1000);
|
||||
};
|
||||
}
|
||||
|
||||
render(inner, g);
|
||||
|
||||
if (fitBoundaries) {
|
||||
// @BertCh recommendation for fitting boundaries
|
||||
const { width, height, x, y } = inner.node().getBBox();
|
||||
const parent = inner.node().parentElement || inner.node().parentNode;
|
||||
const fullWidth = parent.clientWidth || parent.parentNode.clientWidth;
|
||||
const fullHeight = parent.clientHeight || parent.parentNode.clientHeight;
|
||||
const midX = x + width / 2;
|
||||
const midY = y + height / 2;
|
||||
|
||||
if (width === 0 || height === 0) return; // nothing to fit
|
||||
const scale = 0.9 / Math.max(width / fullWidth, height / fullHeight);
|
||||
const translate = [
|
||||
fullWidth / 2 - scale * midX,
|
||||
fullHeight / 2 - scale * midY,
|
||||
];
|
||||
const transform = d3.zoomIdentity
|
||||
.translate(translate[0], translate[1])
|
||||
.scale(scale);
|
||||
|
||||
svg
|
||||
.transition()
|
||||
.duration(animate || 0) // milliseconds
|
||||
.call(zoom.transform, transform);
|
||||
}
|
||||
|
||||
if (onNodeClick) {
|
||||
svg.selectAll('g.node').on('click', (id: any) => {
|
||||
const _node: Node = g.node(id);
|
||||
const _original = this._getNodeData(id);
|
||||
onNodeClick({ d3node: _node, original: _original });
|
||||
});
|
||||
}
|
||||
if (onRelationshipClick) {
|
||||
svg
|
||||
.selectAll('g.edgeLabel, g.edgePath')
|
||||
.on('click', (id: Relationship) => {
|
||||
const _source = g.node(id.v);
|
||||
const _original_source = this._getNodeData(id.v);
|
||||
|
||||
const _target = g.node(id.w);
|
||||
const _original_target = this._getNodeData(id.w);
|
||||
onRelationshipClick({
|
||||
d3source: _source,
|
||||
source: _original_source,
|
||||
d3target: _target,
|
||||
target: _original_target,
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
_getNodeData(id: any) {
|
||||
const { nodes } = this.props;
|
||||
return nodes.find((node) => node.id === id);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { width, height, className } = this.props;
|
||||
return (
|
||||
<svg
|
||||
width={width}
|
||||
height={height}
|
||||
ref={this.svg}
|
||||
className={className || ''}
|
||||
>
|
||||
<g ref={this.innerG} />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DagreGraph;
|
|
@ -1,21 +1,21 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
Button,
|
||||
IconButton,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Popover,
|
||||
TableCell,
|
||||
Typography,
|
||||
IconButton,
|
||||
MenuItem,
|
||||
Menu,
|
||||
Popover,
|
||||
Button,
|
||||
} from '@material-ui/core';
|
||||
import MoreVertIcon from '@material-ui/icons/MoreVert';
|
||||
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
|
||||
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
|
||||
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
|
||||
import MoreVertIcon from '@material-ui/icons/MoreVert';
|
||||
import moment from 'moment';
|
||||
import useStyles from './styles';
|
||||
import LinearProgressBar from '../../ReturningHome/ProgressBar/LinearProgressBar';
|
||||
import { history } from '../../../../redux/configureStore';
|
||||
import React from 'react';
|
||||
import { WorkflowRun } from '../../../../models/workflowData';
|
||||
import { history } from '../../../../redux/configureStore';
|
||||
import LinearProgressBar from '../../ReturningHome/ProgressBar/LinearProgressBar';
|
||||
import useStyles from './styles';
|
||||
|
||||
interface TableDataProps {
|
||||
data: WorkflowRun;
|
||||
|
@ -170,10 +170,7 @@ const TableData: React.FC<TableDataProps> = ({ data, deleteRow }) => {
|
|||
<MenuItem
|
||||
value="Workflow"
|
||||
onClick={() =>
|
||||
history.push({
|
||||
pathname: '/schedule',
|
||||
state: data,
|
||||
})
|
||||
history.push(`/workflows/${data.workflow_name}/schedule`)
|
||||
}
|
||||
>
|
||||
<div className={classes.expDiv}>
|
|
@ -1,64 +1,62 @@
|
|||
import React, { useState } from 'react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import SearchIcon from '@material-ui/icons/Search';
|
||||
import {
|
||||
InputBase,
|
||||
InputAdornment,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Select,
|
||||
MenuItem,
|
||||
Typography,
|
||||
TableContainer,
|
||||
Table,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TableCell,
|
||||
TableBody,
|
||||
TablePagination,
|
||||
IconButton,
|
||||
InputAdornment,
|
||||
InputBase,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
Select,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TablePagination,
|
||||
TableRow,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import ExpandLessIcon from '@material-ui/icons/ExpandLess';
|
||||
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
||||
import SearchIcon from '@material-ui/icons/Search';
|
||||
import React, { useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import useStyles from './styles';
|
||||
import { WORKFLOW_DETAILS } from '../../../../graphql';
|
||||
import TableData from './TableData';
|
||||
import {
|
||||
ExecutionData,
|
||||
Workflow,
|
||||
WorkflowDataVars,
|
||||
WorkflowRun,
|
||||
ExecutionData,
|
||||
} from '../../../../models/workflowData';
|
||||
import Loader from '../../../Loader';
|
||||
import { RootState } from '../../../../redux/reducers';
|
||||
import {
|
||||
sortAlphaAsc,
|
||||
sortAlphaDesc,
|
||||
sortNumAsc,
|
||||
sortNumDesc,
|
||||
} from '../../../../utils/sort';
|
||||
import { UserData } from '../../../../models/user';
|
||||
import { RootState } from '../../../../redux/reducers';
|
||||
import Loader from '../../../Loader';
|
||||
import useStyles from './styles';
|
||||
import TableData from './TableData';
|
||||
|
||||
interface FilterOption {
|
||||
search: string;
|
||||
cluster: string;
|
||||
}
|
||||
|
||||
interface PaginationData {
|
||||
pageNo: number;
|
||||
rowsPerPage: number;
|
||||
}
|
||||
|
||||
interface SortData {
|
||||
startDate: { sort: boolean; ascending: boolean };
|
||||
name: { sort: boolean; ascending: boolean };
|
||||
}
|
||||
|
||||
const ScheduleWorkflow = () => {
|
||||
const BrowseSchedule = () => {
|
||||
const classes = useStyles();
|
||||
const userData: UserData = useSelector((state: RootState) => state.userData);
|
||||
const { selectedProjectID } = userData;
|
||||
const selectedProjectID = useSelector(
|
||||
(state: RootState) => state.userData.selectedProjectID
|
||||
);
|
||||
|
||||
// Apollo query to get the scheduled data
|
||||
const { data, loading, error } = useQuery<Workflow, WorkflowDataVars>(
|
||||
|
@ -329,4 +327,4 @@ const ScheduleWorkflow = () => {
|
|||
);
|
||||
};
|
||||
|
||||
export default ScheduleWorkflow;
|
||||
export default BrowseSchedule;
|
|
@ -1,15 +1,15 @@
|
|||
import { Divider, Typography } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { Typography, Divider } from '@material-ui/core';
|
||||
import useStyles from './styles';
|
||||
import { preDefinedWorkflowData } from '../../../../models';
|
||||
import Head from './Head';
|
||||
import ExperimentDetails from './ExperimentDetails';
|
||||
import Recommendation from './Recommendation';
|
||||
import Scaffold from '../../../../containers/layouts/Scaffold';
|
||||
import ButtonOutlined from '../../../Button/ButtonOutline';
|
||||
import { preDefinedWorkflowData } from '../../../../models/predefinedWorkflow';
|
||||
import { LocationState } from '../../../../models/routerModel';
|
||||
import { history } from '../../../../redux/configureStore';
|
||||
import ButtonFilled from '../../../Button/ButtonFilled';
|
||||
import { LocationState } from '../../../../models/routerModel';
|
||||
import ButtonOutlined from '../../../Button/ButtonOutline';
|
||||
import ExperimentDetails from './ExperimentDetails';
|
||||
import Head from './Head';
|
||||
import Recommendation from './Recommendation';
|
||||
import useStyles from './styles';
|
||||
|
||||
interface LocationObjectProps {
|
||||
workflowData: preDefinedWorkflowData;
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
IconButton,
|
||||
Menu,
|
||||
MenuItem,
|
||||
TableCell,
|
||||
Typography,
|
||||
IconButton,
|
||||
MenuItem,
|
||||
Menu,
|
||||
} from '@material-ui/core';
|
||||
import MoreVertIcon from '@material-ui/icons/MoreVert';
|
||||
import CustomStatus from '../CustomStatus/Status';
|
||||
import LinearProgressBar from '../../ReturningHome/ProgressBar/LinearProgressBar';
|
||||
import useStyles from './styles';
|
||||
import timeDifferenceForDate from '../../../../utils/datesModifier';
|
||||
import React from 'react';
|
||||
import { ExecutionData, WorkflowRun } from '../../../../models/workflowData';
|
||||
import { history } from '../../../../redux/configureStore';
|
||||
import { WorkflowRun, ExecutionData } from '../../../../models/workflowData';
|
||||
import timeDifferenceForDate from '../../../../utils/datesModifier';
|
||||
import LinearProgressBar from '../../ReturningHome/ProgressBar/LinearProgressBar';
|
||||
import CustomStatus from '../CustomStatus/Status';
|
||||
import useStyles from './styles';
|
||||
|
||||
interface TableDataProps {
|
||||
data: WorkflowRun;
|
||||
|
@ -99,10 +99,7 @@ const TableData: React.FC<TableDataProps> = ({ data, exeData }) => {
|
|||
<MenuItem
|
||||
value="Workflow"
|
||||
onClick={() =>
|
||||
history.push({
|
||||
pathname: '/workflows/workflow-underground',
|
||||
state: data,
|
||||
})
|
||||
history.push(`/workflows/${data.workflow_name}/details`)
|
||||
}
|
||||
>
|
||||
Show the workflow
|
||||
|
|
|
@ -10,13 +10,12 @@ import {
|
|||
TableRow,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import moment from 'moment';
|
||||
import ExpandLessIcon from '@material-ui/icons/ExpandLess';
|
||||
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
||||
import moment from 'moment';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { WORKFLOW_DETAILS, WORKFLOW_EVENTS } from '../../../../graphql';
|
||||
import { UserData } from '../../../../models/user';
|
||||
import {
|
||||
ExecutionData,
|
||||
Workflow,
|
||||
|
@ -25,16 +24,15 @@ import {
|
|||
WorkflowSubscription,
|
||||
} from '../../../../models/workflowData';
|
||||
import { RootState } from '../../../../redux/reducers';
|
||||
|
||||
import {
|
||||
sortAlphaAsc,
|
||||
sortAlphaDesc,
|
||||
sortNumAsc,
|
||||
sortNumDesc,
|
||||
} from '../../../../utils/sort';
|
||||
import HeaderSection from './HeaderSection';
|
||||
import useStyles from './styles';
|
||||
import TableData from './TableData';
|
||||
import HeaderSection from './headerSection';
|
||||
|
||||
interface FilterOptions {
|
||||
search: string;
|
||||
|
@ -61,8 +59,9 @@ interface DateData {
|
|||
|
||||
const BrowseWorkflow = () => {
|
||||
const classes = useStyles();
|
||||
const userData: UserData = useSelector((state: RootState) => state.userData);
|
||||
const { selectedProjectID } = userData;
|
||||
const selectedProjectID = useSelector(
|
||||
(state: RootState) => state.userData.selectedProjectID
|
||||
);
|
||||
|
||||
// Query to get workflows
|
||||
const { subscribeToMore, data, error } = useQuery<Workflow, WorkflowDataVars>(
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React from 'react';
|
||||
import PredifinedWorkflows from '../../../PredifinedWorkflows';
|
||||
import workflowData from '../../../PredifinedWorkflows/data';
|
||||
import { history } from '../../../../redux/configureStore';
|
||||
import parsed from '../../../../utils/yamlUtils';
|
||||
import PredifinedWorkflows from '../../../PredifinedWorkflows';
|
||||
import workflowData from '../../../PredifinedWorkflows/data';
|
||||
import useStyles from './styles';
|
||||
|
||||
const Templates = () => {
|
||||
|
@ -24,7 +24,7 @@ const Templates = () => {
|
|||
testWeights.push(10);
|
||||
});
|
||||
history.push({
|
||||
pathname: `/workflows/${workflowData[index].title}`,
|
||||
pathname: `/workflows/${workflowData[index].title}/template`,
|
||||
state: {
|
||||
workflowData: workflowData[index],
|
||||
testNames,
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
import { AppBar, Box, Typography } from '@material-ui/core';
|
||||
import { createStyles, withStyles } from '@material-ui/core/styles';
|
||||
import Tab from '@material-ui/core/Tab';
|
||||
import Tabs from '@material-ui/core/Tabs';
|
||||
import React from 'react';
|
||||
import { history } from '../../../../redux/configureStore';
|
||||
import ButtonFilled from '../../../Button/ButtonFilled';
|
||||
import BrowseWorkflow from '../BrowseWorkflow';
|
||||
import useStyles from './styles';
|
||||
import ScheduleWorkflow from '../ScheduleWorkflow';
|
||||
import Templates from '../Templates';
|
||||
|
||||
interface TabPanelProps {
|
||||
children?: React.ReactNode;
|
||||
index: number;
|
||||
value: number;
|
||||
}
|
||||
const TabPanel: React.FC<TabPanelProps> = ({ children, index, value }) => {
|
||||
return (
|
||||
<div role="tabpanel" hidden={value !== index}>
|
||||
{value === index && (
|
||||
<Box p={3}>
|
||||
<>{children}</>
|
||||
</Box>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
interface StyledTabProps {
|
||||
label: string;
|
||||
}
|
||||
const StyledTab = withStyles((theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
textTransform: 'none',
|
||||
color: 'rgba(0,0,0,0.5)',
|
||||
fontSize: '0.95rem',
|
||||
paddingTop: theme.spacing(1.875),
|
||||
paddingBottom: theme.spacing(1.875),
|
||||
width: '15.9375rem',
|
||||
'&:focus': {
|
||||
opacity: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
)((props: StyledTabProps) => <Tab {...props} />);
|
||||
|
||||
const CenteredTabs = () => {
|
||||
const classes = useStyles();
|
||||
const [value, setValue] = React.useState(0);
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
|
||||
setValue(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className="Header section">
|
||||
<div className={classes.header}>
|
||||
<Typography variant="h4">Chaos Workflows</Typography>
|
||||
<div className={classes.scheduleBtn}>
|
||||
<ButtonFilled
|
||||
isPrimary={false}
|
||||
handleClick={() => history.push('/create-workflow')}
|
||||
>
|
||||
<>Schedule a workflow</>
|
||||
</ButtonFilled>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<AppBar position="static" color="default" className={classes.appBar}>
|
||||
<Tabs
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
indicatorColor="secondary"
|
||||
textColor="secondary"
|
||||
variant="fullWidth"
|
||||
>
|
||||
<StyledTab label="Browse workflows" />
|
||||
<StyledTab label="Schedules" />
|
||||
<StyledTab label="Templates" />
|
||||
<StyledTab label="Analytics" />
|
||||
</Tabs>
|
||||
</AppBar>
|
||||
<TabPanel value={value} index={0}>
|
||||
<BrowseWorkflow />
|
||||
</TabPanel>
|
||||
<TabPanel value={value} index={1}>
|
||||
<ScheduleWorkflow />
|
||||
</TabPanel>
|
||||
<TabPanel value={value} index={2}>
|
||||
<Templates />
|
||||
</TabPanel>
|
||||
<TabPanel value={value} index={3}>
|
||||
Item Four
|
||||
</TabPanel>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default CenteredTabs;
|
|
@ -1,20 +0,0 @@
|
|||
import { makeStyles } from '@material-ui/core';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
header: {
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
marginTop: theme.spacing(2.5),
|
||||
marginBottom: theme.spacing(2.5),
|
||||
},
|
||||
scheduleBtn: {
|
||||
marginLeft: 'auto',
|
||||
},
|
||||
appBar: {
|
||||
background: 'transparent',
|
||||
boxShadow: 'none',
|
||||
},
|
||||
}));
|
||||
|
||||
export default useStyles;
|
|
@ -1,3 +1,4 @@
|
|||
import { useLazyQuery } from '@apollo/client';
|
||||
import {
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
|
@ -6,16 +7,14 @@ import {
|
|||
} from '@material-ui/core';
|
||||
import Radio from '@material-ui/core/Radio';
|
||||
import * as React from 'react';
|
||||
import { useLazyQuery } from '@apollo/client';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { GET_CLUSTER } from '../../../../graphql';
|
||||
import useActions from '../../../../redux/actions';
|
||||
import * as WorkflowActions from '../../../../redux/actions/workflow';
|
||||
import { RootState } from '../../../../redux/reducers';
|
||||
import ButtonFilled from '../../../Button/ButtonFilled';
|
||||
import ButtonOutLine from '../../../Button/ButtonOutline';
|
||||
import useStyles from './styles';
|
||||
import { GET_CLUSTER } from '../../../../graphql';
|
||||
import { RootState } from '../../../../redux/reducers';
|
||||
import { UserData } from '../../../../models/user';
|
||||
import useActions from '../../../../redux/actions';
|
||||
import * as WorkflowActions from '../../../../redux/actions/workflow';
|
||||
|
||||
/*
|
||||
Check is image which is used as
|
||||
|
@ -41,7 +40,9 @@ const WorkflowCluster: React.FC<WorkflowClusterProps> = ({ gotoStep }) => {
|
|||
const workflow = useActions(WorkflowActions);
|
||||
const [isTragetSelected, setTarget] = React.useState(true);
|
||||
const [isRegistered, setRegistration] = React.useState(true);
|
||||
const userData: UserData = useSelector((state: RootState) => state.userData);
|
||||
const selectedProjectID = useSelector(
|
||||
(state: RootState) => state.userData.selectedProjectID
|
||||
);
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setValue((event.target as HTMLInputElement).value);
|
||||
};
|
||||
|
@ -51,7 +52,7 @@ const WorkflowCluster: React.FC<WorkflowClusterProps> = ({ gotoStep }) => {
|
|||
if (data && data.getCluster.length !== 0) {
|
||||
workflow.setWorkflowDetails({
|
||||
clusterid: data.getCluster[0].cluster_id,
|
||||
project_id: userData.selectedProjectID,
|
||||
project_id: selectedProjectID,
|
||||
});
|
||||
gotoStep(1);
|
||||
} else {
|
||||
|
@ -63,7 +64,7 @@ const WorkflowCluster: React.FC<WorkflowClusterProps> = ({ gotoStep }) => {
|
|||
const handleClick = () => {
|
||||
getCluster({
|
||||
variables: {
|
||||
project_id: userData.selectedProjectID,
|
||||
project_id: selectedProjectID,
|
||||
cluster_type: 'internal',
|
||||
},
|
||||
});
|
|
@ -0,0 +1,85 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Nodes } from '../../../../models/workflowData';
|
||||
import useActions from '../../../../redux/actions';
|
||||
import * as NodeSelectionActions from '../../../../redux/actions/nodeSelection';
|
||||
import DagreGraph, { d3Link, d3Node } from '../../../DagreGraph';
|
||||
import useStyles from './styles';
|
||||
|
||||
interface GraphData {
|
||||
nodes: d3Node[];
|
||||
links: d3Link[];
|
||||
}
|
||||
interface ArgoWorkflowProps {
|
||||
nodes: Nodes;
|
||||
}
|
||||
|
||||
const ArgoWorkflow: React.FC<ArgoWorkflowProps> = ({ nodes }) => {
|
||||
const classes = useStyles();
|
||||
// Redux action call for updating selected node
|
||||
const nodeSelection = useActions(NodeSelectionActions);
|
||||
|
||||
const [graphData, setGraphData] = useState<GraphData>({
|
||||
nodes: [],
|
||||
links: [],
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const data: GraphData = {
|
||||
nodes: [],
|
||||
links: [],
|
||||
};
|
||||
|
||||
for (const key of Object.keys(nodes)) {
|
||||
const node = nodes[key];
|
||||
|
||||
data.nodes.push({
|
||||
id: key,
|
||||
class: `${node.phase} ${node.type}`,
|
||||
label: node.type !== 'StepGroup' ? node.name : '',
|
||||
labelType: 'html',
|
||||
});
|
||||
|
||||
if (node.children) {
|
||||
node.children.map((child) =>
|
||||
data.links.push({
|
||||
source: key,
|
||||
target: child,
|
||||
config: {
|
||||
arrowheadStyle: 'display: arrowhead',
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
setGraphData({
|
||||
nodes: [...data.nodes],
|
||||
links: [...data.links],
|
||||
});
|
||||
}, [nodes]);
|
||||
|
||||
return graphData.nodes.length ? (
|
||||
<DagreGraph
|
||||
className={classes.dagreGraph}
|
||||
nodes={graphData.nodes}
|
||||
links={graphData.links}
|
||||
config={{
|
||||
ranker: 'tight-tree',
|
||||
}}
|
||||
animate={1000}
|
||||
shape="rect"
|
||||
fitBoundaries
|
||||
zoomable
|
||||
onNodeClick={({ original }) => {
|
||||
const nodeID = Object.keys(nodes).filter(
|
||||
(key) => key === original?.id
|
||||
)[0];
|
||||
nodeSelection.selectNode(nodes[nodeID]);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<div>Loading Graph...</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ArgoWorkflow;
|
|
@ -0,0 +1,48 @@
|
|||
import { makeStyles, Theme } from '@material-ui/core/styles';
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
dagreGraph: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
|
||||
// Styles for nodes
|
||||
'& g g.nodes': {
|
||||
'& g.node': {
|
||||
cursor: 'pointer',
|
||||
color: theme.palette.common.white,
|
||||
'& rect': {
|
||||
rx: '0.2rem',
|
||||
ry: '0.2rem',
|
||||
},
|
||||
},
|
||||
'& g.Succeeded': {
|
||||
fill: theme.palette.primary.dark,
|
||||
},
|
||||
'& g.Running': {
|
||||
fill: theme.palette.warning.main,
|
||||
},
|
||||
'& g.Pending': {
|
||||
fill: theme.palette.customColors.gray,
|
||||
},
|
||||
'& g.Failed': {
|
||||
fill: theme.palette.error.dark,
|
||||
},
|
||||
'& g.StepGroup': {
|
||||
fill: theme.palette.customColors.gray,
|
||||
cursor: 'default',
|
||||
'& rect': {
|
||||
rx: '0.625rem !important',
|
||||
ry: '0.625rem !important',
|
||||
transform: 'scale(0.5)',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// Styles for edges
|
||||
'& g g.edgePaths': {
|
||||
stroke: theme.palette.customColors.gray,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
export default useStyles;
|
|
@ -0,0 +1,164 @@
|
|||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
// TODO: remove this after creating UI for node details sidebar
|
||||
import { Typography } from '@material-ui/core';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { ExecutionData } from '../../../../models/workflowData';
|
||||
import { RootState } from '../../../../redux/reducers';
|
||||
import timeDifference from '../../../../utils/datesModifier';
|
||||
import useStyles from './styles';
|
||||
|
||||
interface WorkflowInfoProps {
|
||||
workflow_name: string;
|
||||
execution_data: ExecutionData;
|
||||
cluster_name: string;
|
||||
}
|
||||
|
||||
interface SidebarState {
|
||||
currentRunningNodes: string[];
|
||||
executedNodes: string[];
|
||||
}
|
||||
|
||||
const WorkflowInfo: React.FC<WorkflowInfoProps> = ({
|
||||
workflow_name,
|
||||
execution_data,
|
||||
cluster_name,
|
||||
}) => {
|
||||
const classes = useStyles();
|
||||
// Get selected node data from redux
|
||||
const selectedNode = useSelector((state: RootState) => state.selectedNode);
|
||||
|
||||
const [duration, setDuration] = useState<number>(0);
|
||||
const [data, setData] = useState<SidebarState>({
|
||||
currentRunningNodes: [],
|
||||
executedNodes: [],
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setDuration(
|
||||
(parseInt(execution_data.finishedAt, 10) -
|
||||
parseInt(execution_data.startedAt, 10)) /
|
||||
60
|
||||
);
|
||||
|
||||
// If the Workflow is Running [Data is being received through Subscription]
|
||||
// Set the currently executed node in a local state
|
||||
const executedNodes: string[] = [];
|
||||
const currentRunningNodes: string[] = [];
|
||||
|
||||
for (const val of Object.values(execution_data.nodes))
|
||||
if (val.type !== 'StepGroup' && val.phase === 'Running')
|
||||
currentRunningNodes.push(val.name);
|
||||
else if (val.type !== 'StepGroup' && val.phase === 'Succeeded')
|
||||
executedNodes.push(val.name);
|
||||
|
||||
setData({
|
||||
...data,
|
||||
currentRunningNodes,
|
||||
executedNodes,
|
||||
});
|
||||
}, [execution_data.nodes, execution_data.phase]);
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
{/* Workflow Information */}
|
||||
<Typography className={classes.header} variant="h6">
|
||||
<span className={classes.bold}>Workflow Information</span>
|
||||
</Typography>
|
||||
<hr className={classes.divider} />
|
||||
<div className={classes.heightMaintainer}>
|
||||
<Typography className={classes.workflowSpacing}>
|
||||
<span className={classes.bold}>Workflow name:</span>
|
||||
<br />
|
||||
{workflow_name}
|
||||
</Typography>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
{/* Workflow Details
|
||||
@param State
|
||||
@param Start Time
|
||||
@param End Time
|
||||
@param Duration
|
||||
@param Namespace */}
|
||||
|
||||
<div className={classes.workflowSpacing}>
|
||||
<div className={classes.heightMaintainer}>
|
||||
<Typography>
|
||||
<span className={classes.bold}>State:</span> {execution_data.phase}
|
||||
</Typography>
|
||||
<Typography>
|
||||
<span className={classes.bold}>Start time:</span>{' '}
|
||||
{timeDifference(execution_data.startedAt)}
|
||||
</Typography>
|
||||
{execution_data.phase !== 'Running' ? (
|
||||
<>
|
||||
<Typography>
|
||||
<span className={classes.bold}>End time:</span>{' '}
|
||||
{timeDifference(execution_data.finishedAt)}
|
||||
</Typography>
|
||||
<Typography>
|
||||
<span className={classes.bold}>Duration:</span>{' '}
|
||||
{`${duration.toFixed(1)} minutes`}
|
||||
</Typography>
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<Typography>
|
||||
<span className={classes.bold}>Namespace:</span>{' '}
|
||||
{execution_data.namespace}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
{/* Workflow Node Details
|
||||
@param Currently Running Node
|
||||
@param Executed Nodes */}
|
||||
|
||||
<div className={classes.workflowSpacing}>
|
||||
<div className={classes.heightMaintainer}>
|
||||
{execution_data.phase === 'Running' ? (
|
||||
<Typography>
|
||||
<span className={classes.bold}>Currently Running Nodes:</span>{' '}
|
||||
<ul>
|
||||
{data.currentRunningNodes.map((node) => (
|
||||
<li key={node}>{node}</li>
|
||||
))}
|
||||
</ul>
|
||||
</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<Typography>
|
||||
<span className={classes.bold}>Executed Nodes:</span>{' '}
|
||||
{data.executedNodes.length ? (
|
||||
<ul>
|
||||
{data.executedNodes.map((node) => (
|
||||
<li key={node}>{node}</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<Typography>No executed nodes</Typography>
|
||||
)}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
{/* Cluster Details
|
||||
@param Cluster Name */}
|
||||
|
||||
<div className={classes.workflowSpacing}>
|
||||
<div className={classes.heightMaintainer}>
|
||||
<Typography>
|
||||
<span className={classes.bold}>Cluster:</span> {cluster_name}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default WorkflowInfo;
|
|
@ -1,199 +0,0 @@
|
|||
/* eslint-disable */
|
||||
|
||||
import { Typography } from '@material-ui/core';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { ExecutionData, Node } from '../../../../models/workflowData';
|
||||
import timeDifference from '../../../../utils/datesModifier';
|
||||
import useStyles from './styles';
|
||||
|
||||
interface WorkflowRepresentationProps {
|
||||
workflow_name: string;
|
||||
execution_data: string;
|
||||
cluster_name: string;
|
||||
}
|
||||
|
||||
interface SidebarProps extends ExecutionData {
|
||||
current_running_node: string[];
|
||||
executed_nodes: string[];
|
||||
}
|
||||
|
||||
const SideBar: React.FC<WorkflowRepresentationProps> = ({
|
||||
workflow_name,
|
||||
execution_data,
|
||||
cluster_name,
|
||||
}) => {
|
||||
const classes = useStyles();
|
||||
|
||||
const [duration, setDuration] = useState<number>(0);
|
||||
const [data, setData] = useState<SidebarProps>({
|
||||
creationTimestamp: '',
|
||||
event_type: '',
|
||||
finishedAt: '',
|
||||
name: '',
|
||||
namespace: '',
|
||||
nodes: {},
|
||||
current_running_node: [],
|
||||
executed_nodes: [],
|
||||
phase: '',
|
||||
startedAt: '',
|
||||
uid: '',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (execution_data !== undefined) {
|
||||
const execData = JSON.parse(execution_data) as ExecutionData;
|
||||
|
||||
// Setting initial data to the data received from query/subscription
|
||||
setData({
|
||||
...data,
|
||||
...execData,
|
||||
});
|
||||
}
|
||||
}, [(JSON.parse(execution_data) as ExecutionData).phase]);
|
||||
|
||||
useEffect(() => {
|
||||
setDuration(
|
||||
(parseInt(data.finishedAt, 10) - parseInt(data.startedAt, 10)) / 60
|
||||
);
|
||||
|
||||
// If the Workflow is Running [Data is being received through Subscription]
|
||||
// Set the currently executed node in a local state
|
||||
|
||||
if (data.phase === 'Running' && data.nodes !== undefined) {
|
||||
const dataObj: Node[] = Object.values(data.nodes as Node);
|
||||
|
||||
const currentlyRunningNodes: string[] = [];
|
||||
|
||||
dataObj.map((val) => {
|
||||
if (val.type !== 'StepGroup' && val.phase === 'Running') {
|
||||
currentlyRunningNodes.push(val.name);
|
||||
}
|
||||
setData({
|
||||
...data,
|
||||
current_running_node: [
|
||||
...data.executed_nodes,
|
||||
...currentlyRunningNodes,
|
||||
],
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// If the Workflow has Succeeded or Failed
|
||||
// Store all the executed nodes in an array
|
||||
|
||||
const dataObj: Node[] = Object.values(data.nodes as Node);
|
||||
|
||||
const executedNodes: string[] = [];
|
||||
dataObj.map((val) => {
|
||||
if (val.name.charAt(0) === '[') {
|
||||
val.name = 'Step Group ' + val.name.substring(1, val.name.length - 1);
|
||||
}
|
||||
executedNodes.push(val.name);
|
||||
setData({
|
||||
...data,
|
||||
executed_nodes: [...data.executed_nodes, ...executedNodes],
|
||||
});
|
||||
});
|
||||
}
|
||||
}, [data.nodes]);
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
{/* Workflow Information */}
|
||||
<Typography className={classes.header} variant="h6">
|
||||
<span className={classes.bold}>Workflow Information</span>
|
||||
</Typography>
|
||||
<hr className={classes.divider} />
|
||||
<div className={classes.heightMaintainer}>
|
||||
<Typography className={classes.workflowSpacing}>
|
||||
<span className={classes.bold}>Workflow name:</span>
|
||||
<br />
|
||||
{workflow_name}
|
||||
</Typography>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
{/* Workflow Details
|
||||
@param State
|
||||
@param Start Time
|
||||
@param End Time
|
||||
@param Duration
|
||||
@param Namespace */}
|
||||
|
||||
<div className={classes.workflowSpacing}>
|
||||
<div className={classes.heightMaintainer}>
|
||||
<Typography>
|
||||
<span className={classes.bold}>State:</span> {data.phase}
|
||||
</Typography>
|
||||
<Typography>
|
||||
<span className={classes.bold}>Start time:</span>{' '}
|
||||
{timeDifference(data.startedAt)}
|
||||
</Typography>
|
||||
{data.phase !== 'Running' ? (
|
||||
<>
|
||||
<Typography>
|
||||
<span className={classes.bold}>End time:</span>{' '}
|
||||
{timeDifference(data.finishedAt)}
|
||||
</Typography>
|
||||
<Typography>
|
||||
<span className={classes.bold}>Duration:</span>{' '}
|
||||
{`${duration.toFixed(1)} minutes`}
|
||||
</Typography>
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<Typography>
|
||||
<span className={classes.bold}>Namespace:</span> {data.namespace}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
{/* Workflow Node Details
|
||||
@param Currently Running Node
|
||||
@param Executed Nodes */}
|
||||
|
||||
<div className={classes.workflowSpacing}>
|
||||
<div className={classes.heightMaintainer}>
|
||||
{data.phase === 'Running' ? (
|
||||
<Typography>
|
||||
<span className={classes.bold}>Currently Running Nodes:</span>{' '}
|
||||
{
|
||||
<ul>
|
||||
{data.current_running_node.map((node) => {
|
||||
return <li>{node}</li>;
|
||||
})}
|
||||
</ul>
|
||||
}
|
||||
</Typography>
|
||||
) : (
|
||||
<Typography>
|
||||
<span className={classes.bold}>Executed Nodes:</span>{' '}
|
||||
{
|
||||
<ul>
|
||||
{data.executed_nodes.map((node) => {
|
||||
return <li>{node}</li>;
|
||||
})}
|
||||
</ul>
|
||||
}
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
{/* Cluster Details
|
||||
@param Cluster Name */}
|
||||
|
||||
<div className={classes.workflowSpacing}>
|
||||
<div className={classes.heightMaintainer}>
|
||||
<Typography>
|
||||
<span className={classes.bold}>Cluster:</span> {cluster_name}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SideBar;
|
|
@ -0,0 +1,39 @@
|
|||
import { Box, createStyles, Tab, withStyles } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
|
||||
interface TabPanelProps {
|
||||
children?: React.ReactNode;
|
||||
index: number;
|
||||
value: number;
|
||||
}
|
||||
const TabPanel: React.FC<TabPanelProps> = ({ children, index, value }) => {
|
||||
return (
|
||||
<div role="tabpanel" hidden={value !== index}>
|
||||
{value === index && (
|
||||
<Box p={3}>
|
||||
<>{children}</>
|
||||
</Box>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
interface StyledTabProps {
|
||||
label: string;
|
||||
}
|
||||
const StyledTab = withStyles((theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
textTransform: 'none',
|
||||
color: 'rgba(0,0,0,0.5)',
|
||||
fontSize: '0.95rem',
|
||||
paddingTop: theme.spacing(1.875),
|
||||
paddingBottom: theme.spacing(1.875),
|
||||
width: '15.9375rem',
|
||||
'&:focus': {
|
||||
opacity: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
)((props: StyledTabProps) => <Tab {...props} />);
|
||||
|
||||
export { TabPanel, StyledTab };
|
|
@ -1,32 +1,31 @@
|
|||
import React from 'react';
|
||||
import { useMutation } from '@apollo/client';
|
||||
import Step from '@material-ui/core/Step';
|
||||
import { StepIconProps } from '@material-ui/core/StepIcon';
|
||||
import StepLabel from '@material-ui/core/StepLabel';
|
||||
import Stepper from '@material-ui/core/Stepper';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useMutation } from '@apollo/client';
|
||||
import YAML from 'yaml';
|
||||
import Unimodal from '../../containers/layouts/Unimodal';
|
||||
import { CREATE_WORKFLOW } from '../../graphql';
|
||||
import { experimentMap, WorkflowData } from '../../models/workflow';
|
||||
import useActions from '../../redux/actions';
|
||||
import * as WorkflowActions from '../../redux/actions/workflow';
|
||||
import { history } from '../../redux/configureStore';
|
||||
import { RootState } from '../../redux/reducers';
|
||||
import parsed from '../../utils/yamlUtils';
|
||||
import ButtonFilled from '../Button/ButtonFilled';
|
||||
import ButtonOutline from '../Button/ButtonOutline';
|
||||
import ReliablityScore from '../Sections/Workflow/ReliabilityScore';
|
||||
import ScheduleWorkflow from '../Sections/Workflow/ScheduleWorkflow';
|
||||
import VerifyCommit from '../Sections/Workflow/VerifyCommit';
|
||||
import ChooseAWorkflowCluster from '../Sections/Workflow/WorkflowCluster';
|
||||
import ChooseWorkflow from '../Sections/CreateWorkflow/ChooseWorkflow/index';
|
||||
import ReliablityScore from '../Sections/CreateWorkflow/ReliabilityScore';
|
||||
import ScheduleWorkflow from '../Sections/CreateWorkflow/ScheduleWorkflow';
|
||||
import TuneWorkflow from '../Sections/CreateWorkflow/TuneWorkflow/index';
|
||||
import VerifyCommit from '../Sections/CreateWorkflow/VerifyCommit';
|
||||
import ChooseAWorkflowCluster from '../Sections/CreateWorkflow/WorkflowCluster';
|
||||
import QontoConnector from './quontoConnector';
|
||||
import useStyles from './styles';
|
||||
import useQontoStepIconStyles from './useQontoStepIconStyles';
|
||||
import TuneWorkflow from '../Sections/Workflow/TuneWorkflow/index';
|
||||
import ChooseWorkflow from '../Sections/Workflow/ChooseWorkflow/index';
|
||||
import { WorkflowData, experimentMap } from '../../models/workflow';
|
||||
import { UserData } from '../../models/user';
|
||||
import { RootState } from '../../redux/reducers';
|
||||
import useActions from '../../redux/actions';
|
||||
import * as WorkflowActions from '../../redux/actions/workflow';
|
||||
import parsed from '../../utils/yamlUtils';
|
||||
import { CREATE_WORKFLOW } from '../../graphql';
|
||||
import Unimodal from '../../containers/layouts/Unimodal';
|
||||
import { history } from '../../redux/configureStore';
|
||||
|
||||
function getSteps(): string[] {
|
||||
return [
|
||||
|
@ -127,12 +126,10 @@ const CustomStepper = () => {
|
|||
clusterid,
|
||||
} = workflowData;
|
||||
|
||||
const userData: UserData = useSelector((state: RootState) => state.userData);
|
||||
|
||||
const { selectedProjectID } = userData;
|
||||
|
||||
const selectedProjectID = useSelector(
|
||||
(state: RootState) => state.userData.selectedProjectID
|
||||
);
|
||||
const workflow = useActions(WorkflowActions);
|
||||
|
||||
const steps = getSteps();
|
||||
|
||||
const handleNext = () => {
|
||||
|
|
|
@ -14,9 +14,7 @@ const ErrorPage = lazy(() => import('../../pages/ErrorPage'));
|
|||
const Workflows = lazy(() => import('../../pages/Workflows'));
|
||||
const CreateWorkflow = lazy(() => import('../../pages/CreateWorkflow'));
|
||||
const LoginPage = lazy(() => import('../../pages/LoginPage'));
|
||||
const WorkflowUnderground = lazy(() =>
|
||||
import('../../pages/WorkflowUnderground')
|
||||
);
|
||||
const WorkflowDetails = lazy(() => import('../../pages/WorkflowDetails'));
|
||||
const BrowseTemplate = lazy(() =>
|
||||
import('../../components/Sections/ChaosWorkflows/BrowseTemplate')
|
||||
);
|
||||
|
@ -60,18 +58,27 @@ const Routes: React.FC<RoutesProps> = ({ userData, isProjectAvailable }) => {
|
|||
<Route exact path="/login" component={LoginPage} />
|
||||
<Route exact path="/workflows" component={Workflows} />
|
||||
<Route exact path="/create-workflow" component={CreateWorkflow} />
|
||||
<Route exact path="/schedule" component={SchedulePage} />
|
||||
<Route
|
||||
exact
|
||||
path="/workflows/workflow-underground"
|
||||
component={WorkflowUnderground}
|
||||
/>
|
||||
<Route exact path="/community" component={Community} />
|
||||
<Route
|
||||
exact
|
||||
path="/workflows/:workflowName"
|
||||
component={WorkflowDetails}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/workflows/:workflowName/details"
|
||||
component={WorkflowDetails}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/workflows/:scheduleId/schedule"
|
||||
component={SchedulePage}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/workflows/:templateName/template"
|
||||
component={BrowseTemplate}
|
||||
/>
|
||||
<Route exact path="/community" component={Community} />
|
||||
<Route exact path="/settings" component={Settings} />
|
||||
<Route exact path="/404" component={ErrorPage} />
|
||||
<Redirect to="/404" />
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
import { useQuery } from '@apollo/client';
|
||||
import { Box, Divider } from '@material-ui/core';
|
||||
import AppBar from '@material-ui/core/AppBar';
|
||||
import Toolbar from '@material-ui/core/Toolbar';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import CustomBreadCrumbs from '../../../components/BreadCrumbs';
|
||||
import { GET_USER } from '../../../graphql';
|
||||
import { Message, NotificationIds, Project } from '../../../models/header';
|
||||
import {
|
||||
UserData,
|
||||
CurrentUserDetails,
|
||||
CurrentUserDedtailsVars,
|
||||
CurrentUserDetails,
|
||||
UserData,
|
||||
} from '../../../models/user';
|
||||
import { RootState } from '../../../redux/reducers';
|
||||
import CustomBreadCrumbs from '../../../components/BreadCrumbs';
|
||||
import NotificationsDropdown from './NotificationDropdown';
|
||||
import ProfileDropdownSection from './ProfileDropdownSection';
|
||||
import useStyles from './styles';
|
||||
import { GET_USER } from '../../../graphql';
|
||||
|
||||
const Header: React.FC = () => {
|
||||
const classes = useStyles();
|
||||
|
@ -44,7 +44,6 @@ const Header: React.FC = () => {
|
|||
setSelectedProject(selectedProjectID);
|
||||
// send POST request with #selectedProjectID to update active
|
||||
// project on db or persist it in redux or cookie.
|
||||
// window.location.reload(false);
|
||||
};
|
||||
|
||||
const fetchRandomProjects = useCallback(() => {
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import { AnalyticsAction } from './analytics';
|
||||
import { NodeSelectionAction } from './nodeSelection';
|
||||
import { UserAction } from './user';
|
||||
import { WorkflowAction } from './workflow';
|
||||
|
||||
export * from './predefinedWorkflow';
|
||||
|
||||
export type Action = UserAction | AnalyticsAction | WorkflowAction;
|
||||
export type Action =
|
||||
| UserAction
|
||||
| AnalyticsAction
|
||||
| WorkflowAction
|
||||
| NodeSelectionAction;
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import { Node } from './workflowData';
|
||||
|
||||
export enum NodeSelectionActions {
|
||||
SELECT_NODE = 'SELECT_NODE',
|
||||
}
|
||||
|
||||
interface NodeSelectionActionType<T, P> {
|
||||
type: T;
|
||||
payload: P;
|
||||
}
|
||||
|
||||
export type NodeSelectionAction = NodeSelectionActionType<
|
||||
typeof NodeSelectionActions.SELECT_NODE,
|
||||
Node
|
||||
>;
|
|
@ -23,6 +23,6 @@ export interface workflowDetails {
|
|||
description: string;
|
||||
}
|
||||
|
||||
export interface SelectWorkflowCallBackType {
|
||||
interface SelectWorkflowCallBackType {
|
||||
(selectedWorkflow: workflowDetails): void;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,10 @@ export interface Node {
|
|||
type: string;
|
||||
}
|
||||
|
||||
export interface Nodes {
|
||||
[index: string]: Node;
|
||||
}
|
||||
|
||||
export interface ExecutionData {
|
||||
event_type: string;
|
||||
uid: string;
|
||||
|
@ -16,7 +20,7 @@ export interface ExecutionData {
|
|||
phase: string;
|
||||
startedAt: string;
|
||||
finishedAt: string;
|
||||
nodes: object;
|
||||
nodes: Nodes;
|
||||
}
|
||||
|
||||
export interface WorkflowRun {
|
||||
|
|
|
@ -9,20 +9,15 @@ import {
|
|||
} from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import CustomDate from '../../components/DateTime/CustomDate/index';
|
||||
import CustomTime from '../../components/DateTime/CustomTime/index';
|
||||
import SetTime from './SetTime/index';
|
||||
import useStyles from './styles';
|
||||
import Scaffold from '../../containers/layouts/Scaffold';
|
||||
import ButtonFilled from '../../components/Button/ButtonFilled';
|
||||
import ButtonOutline from '../../components/Button/ButtonOutline';
|
||||
import CustomDate from '../../components/DateTime/CustomDate/index';
|
||||
import CustomTime from '../../components/DateTime/CustomTime/index';
|
||||
import Scaffold from '../../containers/layouts/Scaffold';
|
||||
import SetTime from './SetTime/index';
|
||||
import useStyles from './styles';
|
||||
|
||||
// To be changed to a Location Generic
|
||||
interface WorkflowScheduleProps {
|
||||
location: any;
|
||||
}
|
||||
|
||||
const SchedulePage: React.FC<WorkflowScheduleProps> = () => {
|
||||
const SchedulePage: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const start = 0;
|
||||
const end = 10;
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
import { useQuery } from '@apollo/client';
|
||||
import { Typography } from '@material-ui/core';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import Loader from '../../components/Loader';
|
||||
import ArgoWorkflow from '../../components/Sections/WorkflowDetails/ArgoWorkflow';
|
||||
import WorkflowInfo from '../../components/Sections/WorkflowDetails/WorkflowInfo';
|
||||
import Scaffold from '../../containers/layouts/Scaffold';
|
||||
import { WORKFLOW_DETAILS, WORKFLOW_EVENTS } from '../../graphql';
|
||||
import {
|
||||
ExecutionData,
|
||||
Workflow,
|
||||
WorkflowDataVars,
|
||||
WorkflowSubscription,
|
||||
} from '../../models/workflowData';
|
||||
import { RootState } from '../../redux/reducers';
|
||||
import useStyles from './styles';
|
||||
|
||||
const WorkflowDetails: React.FC = () => {
|
||||
const classes = useStyles();
|
||||
const { pathname } = useLocation();
|
||||
// Getting the workflow nome from the pathname
|
||||
const workflowName = pathname.split('/')[2];
|
||||
|
||||
// get ProjectID
|
||||
const selectedProjectID = useSelector(
|
||||
(state: RootState) => state.userData.selectedProjectID
|
||||
);
|
||||
|
||||
// Query to get workflows
|
||||
const { subscribeToMore, data, error } = useQuery<Workflow, WorkflowDataVars>(
|
||||
WORKFLOW_DETAILS,
|
||||
{ variables: { projectID: selectedProjectID } }
|
||||
);
|
||||
|
||||
const workflow = data?.getWorkFlowRuns.filter(
|
||||
(w) => w.workflow_name === workflowName
|
||||
)[0];
|
||||
|
||||
// Using subscription to get realtime data
|
||||
useEffect(() => {
|
||||
if (
|
||||
workflow?.execution_data &&
|
||||
(JSON.parse(workflow?.execution_data) as ExecutionData).phase ===
|
||||
'Running'
|
||||
) {
|
||||
subscribeToMore<WorkflowSubscription>({
|
||||
document: WORKFLOW_EVENTS,
|
||||
variables: { projectID: selectedProjectID },
|
||||
updateQuery: (prev, { subscriptionData }) => {
|
||||
if (!subscriptionData.data) return prev;
|
||||
const modifiedWorkflows = prev.getWorkFlowRuns.slice();
|
||||
const newWorkflow = subscriptionData.data.workflowEventListener;
|
||||
|
||||
// Updating the query data
|
||||
let i = 0;
|
||||
for (; i < modifiedWorkflows.length; i++) {
|
||||
if (
|
||||
modifiedWorkflows[i].workflow_run_id ===
|
||||
newWorkflow.workflow_run_id
|
||||
) {
|
||||
modifiedWorkflows[i] = newWorkflow;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i === modifiedWorkflows.length)
|
||||
modifiedWorkflows.unshift(newWorkflow);
|
||||
|
||||
return { ...prev, getWorkFlowRuns: modifiedWorkflows };
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<Scaffold>
|
||||
{workflow ? (
|
||||
<div className={classes.root}>
|
||||
<div className={classes.workflowGraph}>
|
||||
<Typography className={classes.heading}>
|
||||
{workflow.workflow_name}
|
||||
</Typography>
|
||||
<Typography>
|
||||
Click on test to see detailed log of your workflow
|
||||
</Typography>
|
||||
|
||||
{/* Argo Workflow DAG Graph */}
|
||||
<ArgoWorkflow
|
||||
nodes={
|
||||
(JSON.parse(workflow.execution_data) as ExecutionData).nodes
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<WorkflowInfo
|
||||
workflow_name={workflow.workflow_name}
|
||||
execution_data={
|
||||
JSON.parse(workflow?.execution_data) as ExecutionData
|
||||
}
|
||||
cluster_name={workflow.cluster_name}
|
||||
/>
|
||||
</div>
|
||||
) : error ? (
|
||||
<Typography>An error has occurred while fetching the data</Typography>
|
||||
) : (
|
||||
<Loader />
|
||||
)}
|
||||
</Scaffold>
|
||||
);
|
||||
};
|
||||
|
||||
export default WorkflowDetails;
|
|
@ -3,8 +3,8 @@ import { makeStyles, Theme } from '@material-ui/core/styles';
|
|||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
root: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
marginTop: theme.spacing(3),
|
||||
height: '75vh',
|
||||
},
|
||||
heading: {
|
||||
fontSize: '2rem',
|
|
@ -1,67 +0,0 @@
|
|||
import { useSubscription } from '@apollo/client';
|
||||
import { Typography } from '@material-ui/core';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSelector } from 'react-redux';
|
||||
import SideBar from '../../components/Sections/WorkflowUnderground/WorkflowRepresentation';
|
||||
import Scaffold from '../../containers/layouts/Scaffold';
|
||||
import { WORKFLOW_EVENTS } from '../../graphql';
|
||||
import { LocationState } from '../../models/routerModel';
|
||||
import {
|
||||
ExecutionData,
|
||||
WorkflowRun,
|
||||
WorkflowSubscription,
|
||||
} from '../../models/workflowData';
|
||||
import capitalize from '../../utils/capitalize';
|
||||
import useStyles from './styles';
|
||||
import { UserData } from '../../models/user';
|
||||
import { RootState } from '../../redux/reducers';
|
||||
|
||||
interface WorkflowUndergroundProps {
|
||||
location: LocationState<WorkflowRun>;
|
||||
}
|
||||
|
||||
const WorkflowUnderground: React.FC<WorkflowUndergroundProps> = ({
|
||||
location,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const classes = useStyles();
|
||||
const userData: UserData = useSelector((state: RootState) => state.userData);
|
||||
const { selectedProjectID } = userData;
|
||||
const [data, setData] = useState<WorkflowRun>(location.state);
|
||||
const dataSub = useSubscription<WorkflowSubscription>(WORKFLOW_EVENTS, {
|
||||
variables: { projectID: selectedProjectID },
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const workflowCompleted: boolean =
|
||||
(JSON.parse(location.state.execution_data) as ExecutionData).phase ===
|
||||
'Succeeded';
|
||||
|
||||
if (workflowCompleted && location.state.execution_data !== undefined)
|
||||
setData(location.state);
|
||||
else setData(dataSub.data?.workflowEventListener ?? location.state);
|
||||
}, [location.state, dataSub.data, data.execution_data]);
|
||||
|
||||
return (
|
||||
<Scaffold>
|
||||
<div className={classes.root}>
|
||||
<div className={classes.workflowGraph}>
|
||||
<Typography className={classes.heading}>
|
||||
{data.workflow_name
|
||||
.split('-')
|
||||
.map((text) => `${capitalize(text)} `)}
|
||||
</Typography>
|
||||
<Typography>{t('workflowUnderground.heading')}</Typography>
|
||||
</div>
|
||||
<SideBar
|
||||
workflow_name={data.workflow_name}
|
||||
execution_data={data.execution_data}
|
||||
cluster_name={data.cluster_name}
|
||||
/>
|
||||
</div>
|
||||
</Scaffold>
|
||||
);
|
||||
};
|
||||
|
||||
export default WorkflowUnderground;
|
|
@ -1,11 +1,64 @@
|
|||
import { AppBar, Typography } from '@material-ui/core';
|
||||
import Tabs from '@material-ui/core/Tabs';
|
||||
import React from 'react';
|
||||
import WorkflowTabs from '../../components/Sections/ChaosWorkflows/WorkflowTabs';
|
||||
import ButtonFilled from '../../components/Button/ButtonFilled';
|
||||
import BrowseSchedule from '../../components/Sections/ChaosWorkflows/BrowseSchedule';
|
||||
import BrowseWorkflow from '../../components/Sections/ChaosWorkflows/BrowseWorkflow';
|
||||
import Templates from '../../components/Sections/ChaosWorkflows/Templates';
|
||||
import { StyledTab, TabPanel } from '../../components/Tabs';
|
||||
import Scaffold from '../../containers/layouts/Scaffold';
|
||||
import { history } from '../../redux/configureStore';
|
||||
import useStyles from './styles';
|
||||
|
||||
const Workflows = () => {
|
||||
const classes = useStyles();
|
||||
const [value, setValue] = React.useState(0);
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
|
||||
setValue(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<Scaffold>
|
||||
<WorkflowTabs />
|
||||
<section className="Header section">
|
||||
<div className={classes.header}>
|
||||
<Typography variant="h4">Chaos Workflows</Typography>
|
||||
<div className={classes.scheduleBtn}>
|
||||
<ButtonFilled
|
||||
isPrimary={false}
|
||||
handleClick={() => history.push('/create-workflow')}
|
||||
>
|
||||
<>Schedule a workflow</>
|
||||
</ButtonFilled>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<AppBar position="static" color="default" className={classes.appBar}>
|
||||
<Tabs
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
indicatorColor="secondary"
|
||||
textColor="secondary"
|
||||
variant="fullWidth"
|
||||
>
|
||||
<StyledTab label="Browse workflows" />
|
||||
<StyledTab label="Schedules" />
|
||||
<StyledTab label="Templates" />
|
||||
<StyledTab label="Analytics" />
|
||||
</Tabs>
|
||||
</AppBar>
|
||||
<TabPanel value={value} index={0}>
|
||||
<BrowseWorkflow />
|
||||
</TabPanel>
|
||||
<TabPanel value={value} index={1}>
|
||||
<BrowseSchedule />
|
||||
</TabPanel>
|
||||
<TabPanel value={value} index={2}>
|
||||
<Templates />
|
||||
</TabPanel>
|
||||
<TabPanel value={value} index={3}>
|
||||
Analytics comming soon
|
||||
</TabPanel>
|
||||
</Scaffold>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
heading: {
|
||||
header: {
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
marginTop: theme.spacing(2.5),
|
||||
marginLeft: theme.spacing(11),
|
||||
marginBottom: theme.spacing(0),
|
||||
fontFamily: 'Ubuntu',
|
||||
fontSize: '2.25rem',
|
||||
display: 'inline-block',
|
||||
marginBottom: theme.spacing(2.5),
|
||||
},
|
||||
scheduleBtn: {
|
||||
marginLeft: 'auto',
|
||||
},
|
||||
appBar: {
|
||||
background: 'transparent',
|
||||
boxShadow: 'none',
|
||||
},
|
||||
}));
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/* eslint-disable import/prefer-default-export */
|
||||
import {
|
||||
NodeSelectionAction,
|
||||
NodeSelectionActions,
|
||||
} from '../../models/nodeSelection';
|
||||
import { Node } from '../../models/workflowData';
|
||||
|
||||
export function selectNode(node: Node): NodeSelectionAction {
|
||||
return {
|
||||
type: NodeSelectionActions.SELECT_NODE,
|
||||
payload: node,
|
||||
};
|
||||
}
|
|
@ -25,7 +25,7 @@ if (dev) {
|
|||
middleware = composeWithDevTools(middleware);
|
||||
}
|
||||
|
||||
const persistedReducer = persistReducer(persistConfig, rootReducer(history));
|
||||
const persistedReducer = persistReducer(persistConfig, rootReducer());
|
||||
|
||||
export default () => {
|
||||
const store = createStore(persistedReducer, {}, middleware) as any;
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { History } from 'history'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
import { combineReducers } from 'redux';
|
||||
import { CommunityData } from '../../models/analytics';
|
||||
import { UserData } from '../../models/user';
|
||||
import { WorkflowData } from '../../models/workflow';
|
||||
import { Node } from '../../models/workflowData';
|
||||
import * as analyticsReducer from './analytics';
|
||||
import * as nodeSelectionReducer from './nodeSelection';
|
||||
import * as userReducer from './user';
|
||||
import * as workflowReducer from './workflow';
|
||||
|
||||
|
@ -11,13 +12,13 @@ export interface RootState {
|
|||
communityData: CommunityData;
|
||||
userData: UserData;
|
||||
workflowData: WorkflowData;
|
||||
selectedNode: Node;
|
||||
}
|
||||
|
||||
export default (
|
||||
history: History // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
) =>
|
||||
export default () =>
|
||||
combineReducers({
|
||||
...analyticsReducer,
|
||||
...userReducer,
|
||||
...workflowReducer,
|
||||
...nodeSelectionReducer,
|
||||
});
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import {
|
||||
NodeSelectionAction,
|
||||
NodeSelectionActions,
|
||||
} from '../../models/nodeSelection';
|
||||
import { Node } from '../../models/workflowData';
|
||||
import createReducer from './createReducer';
|
||||
|
||||
const initialState: Node = {
|
||||
children: null,
|
||||
finishedAt: '',
|
||||
name: '',
|
||||
phase: '',
|
||||
startedAt: '',
|
||||
type: '',
|
||||
};
|
||||
|
||||
export const selectedNode = createReducer<Node>(initialState, {
|
||||
[NodeSelectionActions.SELECT_NODE](state: Node, action: NodeSelectionAction) {
|
||||
return {
|
||||
...state,
|
||||
...action.payload,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default selectedNode;
|
|
@ -24,6 +24,7 @@ declare module '@material-ui/core/styles/createPalette' {
|
|||
customColors: {
|
||||
white: (opacity: number) => string;
|
||||
black: (opacity: number) => string;
|
||||
gray: string;
|
||||
};
|
||||
input: {
|
||||
disabled: string;
|
||||
|
@ -34,6 +35,7 @@ declare module '@material-ui/core/styles/createPalette' {
|
|||
customColors?: {
|
||||
white?: (opacity: number) => string;
|
||||
black?: (opacity: number) => string;
|
||||
gray?: string;
|
||||
};
|
||||
input?: {
|
||||
disabled?: string;
|
||||
|
@ -80,15 +82,16 @@ function customTheme(options: ThemeOptions) {
|
|||
white: (opacity: number): string => {
|
||||
let op = opacity;
|
||||
if (op < 0) op = 0;
|
||||
if (op > 100) op = 100;
|
||||
if (op > 1) op = 1;
|
||||
return `rgba(255, 255, 255, ${op})`;
|
||||
},
|
||||
black: (opacity: number): string => {
|
||||
let op = opacity;
|
||||
if (op < 0) op = 0;
|
||||
if (op > 100) op = 100;
|
||||
if (op > 1) op = 1;
|
||||
return `rgba(0, 0, 0, ${op})`;
|
||||
},
|
||||
gray: '#5D6173',
|
||||
},
|
||||
},
|
||||
typography: {
|
||||
|
|
Loading…
Reference in New Issue